Context Engineering 实战 01|Context Engineering ≠ Prompt Engineering 2.0:到底在“工程“什么

Context Engineering 实战 01|Context Engineering ≠ Prompt Engineering 2.0:到底在"工程"什么

AIReview 系统的 Code Review Agent 上线一个月,效果一般。eval 通过率 62%——能抓住明显 bug,但对业务逻辑问题基本无感。

团队开始优化 prompt。

第一周,改措辞。把"请检查代码质量"改成"按以下维度逐项检查:正确性、安全性、性能、可维护性"。加了 few-shot 示例,展示"好的 review 长什么样"。从 800 token 到 2400 token,通过率 62% → 71%。

第二周,继续加内容。团队的 review 规则库有 200 条规则——安全类 38 条、性能类 27 条、风格类 45 条、业务逻辑类 52 条、其他 38 条。“反正 context window 放得下,全塞进去让模型参考”。Prompt 从 2400 涨到 6200 token。

通过率跌到 55%。加了 200 条正确的规则,比不加还差。

优化手段              prompt 大小     eval 通过率
──────────────       ──────────    ──────────
初版                  800 tokens    62%
措辞优化(一周)       2400 tokens   71%
全量规则注入(两周)    6200 tokens   55%  ← 更多规则,反而更差

200 条规则都是对的——每条都是团队从真实 code review 里沉淀出来的。全塞进去为什么效果还退步了?


排查:问题不在"写了什么",在"模型看到了什么"

做了一件事:手动检查 AI 输出的 review 意见,逐条比对它实际"遵循了哪些规则"。

200 条规则注入后,AI 的行为分布:

规则遵循情况              数量    占比
──────────            ────    ────
正确遵循,且跟当前代码相关    23条    12%
正确遵循,但跟当前代码无关    31条    16%  ← 看到规则就乱套
完全忽略                   146条   73%

73% 的规则被完全忽略。16% 被强行套用到不相关的代码上。只有 12% 被正确使用。

“强行套用"是什么意思?比如一条规则是"数据库查询必须有超时设置”——AI 把它套用到一个纯前端组件的 review 上,硬说"这里应该加超时设置"。还有一条"并发操作需要加锁"——AI 在一个同步的配置解析函数里也建议加锁。

AI 不是不懂规则——它在 6000 token 的规则海洋里失去了判断力。该看的没看到,不该用的却用了。

当时团队有人说了一句话:“它不像是没读懂 prompt,更像是什么都看了但什么都没看仔细。”

这句话是突破口。


对照实验:同一个 prompt,不同的 context 组装

为了验证"问题在 context 组装而不是 prompt 措辞",做了一个对照实验。

两组用完全相同的 system prompt 措辞、角色定义、输出格式要求。唯一区别是规则注入方式:

  • A 组(静态全量注入): 200 条规则全部写进 context,每次 review 都看到同样的 200 条
  • B 组(动态选择注入): 先分析当前 diff 的文件类型和变更内容,从 200 条中选 10-15 条相关规则注入

100 条测试用例,结果:

指标                  A组(全量注入)   B组(动态选择)  差异
──────              ─────────      ─────────    ────
规则遵循率             45%            83%         +84%
误报率(套用不相关规则) 22%            4%          -82%
context token 消耗    6000           500          -92%
eval 综合通过率        55%            86%          +56%

Prompt 一个字没改。只改了"模型看到哪些规则",通过率 55% → 86%。

更值得注意的是误报率:22% → 4%。全量注入时那些"硬套规则"的行为几乎消失了——因为模型只看到了跟当前代码相关的规则,没有多余的规则可以乱套。

这就是 Prompt Engineering 和 Context Engineering 的分界线。Prompt Engineering 在优化"你怎么说",Context Engineering 在优化"模型看到什么"。 前者是语言问题,后者是信息工程问题。


为什么 200 条不如 15 条:注意力的零和博弈

Transformer 的 attention 不是无限的——它是零和博弈。

每个 token 生成时,模型要对 context 里的所有 token 做注意力分配。Softmax 归一化后总和是 1。context 越长,每条信息分到的注意力越少。

200 条规则(6000 tokens):
  每条规则的平均注意力 ≈ 1/200 = 0.5%

15 条规则(500 tokens):
  每条规则的平均注意力 ≈ 1/15 = 6.7%

差距:13 倍

而且实际的注意力分布不是均匀的——是 U 形的。开头和结尾的信息拿到更多注意力,中间大段信息落入"注意力凹陷区"。

注意力权重 ↑
          │ █                                      █
          │ █ █                                  █ █
          │ █ █ █                              █ █ █
          │ █ █ █ █                          █ █ █ █
          │ █ █ █ █ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ █ █ █ █
          │ █ █ █ █ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ █ █ █ █
          ├───────────────────────────────────────────
          context 开头        中段              结尾

200 条规则全量注入时,大部分规则挤在中间——注意力凹陷区。模型"看到了"这些规则,但没有给它们足够的注意力权重来真正遵循。

这解释了之前发现的 73% 忽略率:不是 prompt 没写清"要遵守规则",是这些规则在 context 里的物理位置决定了它们拿不到足够的注意力。

这也是为什么误报率会上升——中间凹陷区的规则被部分激活,模型"隐约记得有这么条规则"但不清楚具体适用条件,就粗暴地套用了。


三轮优化实录

理解了注意力机制后,优化方向从改措辞变成了改 context 的组装方式。三天做了三轮。

第一轮:按文件类型粗筛(200 → 60 条)

def filter_by_file_type(rules, file_path):
    ext = Path(file_path).suffix
    tag_map = {
        ".py": ["python", "general"],
        ".ts": ["typescript", "general"],
        ".sql": ["sql", "database", "general"],
    }
    tags = tag_map.get(ext, ["general"])
    return [r for r in rules if r.category in tags]

review 一个 .py 文件时,TypeScript 规则、SQL 规则自动排除。200 条 → 60 条。

结果:55% → 68%。有提升,但 60 条还是太多。

第二轮:按变更内容语义匹配(60 → 15 条)

def semantic_rank(rules, diff_text, top_k=15):
    diff_emb = embed(diff_text)
    scored = []
    for rule in rules:
        sim = cosine_similarity(diff_emb, rule.embedding)
        scored.append((rule, sim))
    scored.sort(key=lambda x: x[1], reverse=True)
    return [r for r, _ in scored[:top_k]]

对 diff 内容做 embedding,跟每条规则的 embedding 算相似度,选 top-15。

结果:68% → 82%。跃升 14 个点——这一轮贡献最大。

第三轮:利用 U 形曲线排列规则位置

高优先级规则放 context 开头(注意力高区),次优先级放结尾(第二高区),普通规则放中间。

def arrange_by_attention(rules):
    by_priority = sorted(rules, key=lambda r: r.priority, reverse=True)
    high = by_priority[:5]      # 最重要 → 开头
    low = by_priority[5:10]     # 次重要 → 结尾
    medium = by_priority[10:]   # 一般 → 中间
    return high + medium + low  # 注意力 U 形分布

结果:82% → 86%。提升幅度小了,但这 4 个点纯粹来自规则的物理排列,一行 prompt 都没改。

优化轮次      动作                  通过率    token 消耗
────────    ──────────           ──────    ─────────
基线         全量注入 200 条         55%      6000
第一轮       按文件类型筛选到 60 条    68%      1800
第二轮       语义匹配选 15 条        82%      500
第三轮       U 形排列               86%      500

三轮下来,token 消耗 6000 → 500(-92%),通过率 55% → 86%(+56%)。Prompt 措辞一字未改。


模型看到的"全部信息"比你以为的大

优化 context 时,大部分人只盯着自己写的 system prompt。但模型的 context window 里远不止这些。

一次 AIReview 的 review 请求,实际的 context 构成:

组成部分              token 占用        你的控制程度
────────            ─────────        ──────────
System Prompt        2400              完全控制
Review 规则(动态注入) 500              完全控制
待 review 的 diff     3000-15000        部分控制(可截取关键段)
工具定义(8 个工具)    900              容易忽视 ← 
对话历史              2000-8000         需要主动管理
──────────────────────────────────────────────
总计                  8800-26800

两个容易被忽视的开销:

工具定义占 900 token。 AIReview 有 8 个工具(search_code、read_file、run_test 等),每个工具的 description + parameter schema 大约 100-150 token。这 900 token 是隐性固定开销,每次请求都在,你的规则和 diff 要跟它们竞争注意力。

对话历史是会膨胀的。 如果不是第一轮 review——比如模型已经检查了 3 个文件——之前的对话可能积累了 5000-8000 token。你花力气把规则从 6000 压到 500,但对话历史悄悄加回来 5000,总体 context 又膨胀了,注意力又被稀释。

这就是 Context Engineering 的范畴:你要管理的不是自己写的那一段 prompt 文本,而是模型每次推理时实际看到的全部信息。 System prompt、动态注入的规则、检索到的外部知识、工具定义、对话历史——五个来源,任何一块膨胀,都会稀释其他部分的注意力。


什么时候 Prompt Engineering 就够了

不是所有场景都需要 Context Engineering。判断方法很简单:

如果你的系统只有一种输入模式,一个固定 prompt 能覆盖所有情况——Prompt Engineering 够用。

翻译、单次分类、简单文本处理——这些任务输入类型单一、不需要外部知识、不需要多轮对话、不用工具。一个写好的 prompt 就是最终答案。

一旦你的系统有以下任何一个特征,就进入了 Context Engineering 的领域:

特征                              为什么 PE 不够
─────────                       ──────────
输入类型多样(>3 种)               不同输入需要不同的规则和示例
需要外部知识(RAG / 规则库)        检索质量直接决定输出质量
多轮对话(>5 轮)                  对话历史的膨胀和遗忘需要主动管理
工具数量 > 3                      工具 description 吃 token,选择准确率受描述质量影响
输出要求随场景变化                  需要动态切换约束和格式

AIReview 全中——多种文件类型、200 条规则库、多轮 review 循环、8 个工具。在这种系统上继续打磨 prompt 措辞,就是在局部最优解上死磕。


PE 和 CE 的一个直觉区分

如果你做的事情只需要打开一个文本文件就能完成——那是 Prompt Engineering。

如果你需要写代码来决定模型看到什么——写检索逻辑、写过滤规则、写排序算法、写组装 pipeline——那就是 Context Engineering。

PE 的工程量在编辑器里,CE 的工程量在代码里。

AIReview 这个案例的具体对比:

Prompt Engineering 的工作量:
  打开 system_prompt.txt
  把"检查代码"改成"逐行检查以下维度:..."
  加 2 个 few-shot 示例
  跑 eval 看效果
  → 一周,通过率 +9%(62% → 71%)

Context Engineering 的工作量:
  写规则的 embedding 索引(embed_rules.py)
  写按文件类型过滤的逻辑(filter.py)
  写语义匹配的排序逻辑(ranker.py)
  写 context 组装 pipeline(assembler.py)
  跑 eval 看效果
  → 三天,通过率 +31%(55% → 86%)

一周 +9% vs 三天 +31%。不是 PE 没用——是在 AIReview 这类系统上,信息选择的杠杆远大于措辞优化。


Prompt 是你写的文本,Context 是模型做决策时看到的一切——后者才是工程的对象。别再优化措辞了,去优化信息供给。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值