同一个模型,换一种上下文组织方式,表现可以差一个档次
"上下文工程"(Context Engineering)这个词 2024 年后才流行,但它讨论的问题自 LLM 诞生以来就是核心:有限的输入窗口,怎么放最能让模型发挥的信息。
Andrej Karpathy 在 2025 年有句话被广泛引用:Prompt Engineering 是给模型一次性问题的技巧;Context Engineering 是在 Agent 运行过程中持续管理信息结构的工程学。两者的区别是后者有状态——一个 Agent 跑到第 10 步时,该看到什么、不该看到什么、该以什么顺序看,都是设计问题。
这一篇把 Agent 上下文工程的几个核心话题串起来。
上下文不是"尽可能多塞"
第一个反直觉的事实:上下文窗口不是越大越好。
200K 窗口的 Claude、1M 窗口的 Gemini 给人一种错觉——"反正够大,不用裁"。但两个原因让这个想法不成立:
Lost in the Middle。模型对长上下文的"中部"关注显著低于头部和尾部。如果关键信息放在 50K~150K 的位置,模型经常视而不见。研究显示,信息在 token 位置的第 20%~80% 区间,召回率最多能掉到头尾的一半。
注意力稀释。每个 token 都在争抢模型的注意力。上下文越长,每个 token 分到的注意力越少,相关的信号更容易被无关的噪音淹没。
所以优秀的 Agent 不是"把窗口填满",而是让每个 token 都尽量有用。这件事上越节制,模型表现越好。
上下文预算:像 CPU 管理内存那样管 token
一个生产级 Agent 会把自己的上下文分成几个区,每个区有预算:
System Prompt (固定,不变): ~1K tokens
Long-term Memory (检索注入): ~2K
Task Description: ~500
Tool Schemas: ~2K (随工具数变)
Working Memory (最近对话): ~8K (sliding window)
Tool Results (最近几次调用): ~4K
Space for Model Reply: ~2K
----------------------------------------
总预算: 约 20K (远小于 200K)
每个区有自己的上限。超出时各自有压缩策略:记忆区重新检索 top-K、工作记忆滚动窗口、工具结果只保留最近的。这套"预算 + 压缩"的做法比"等窗口满了再处理"稳得多。
一个常见错误是让工具结果无限累积。你的 Agent 调用了一个返回 20KB JSON 的工具,这 20KB 现在在 messages 里。下一轮又调用了类似的工具,又是 20KB。跑 10 轮,200KB 全是工具结果,你的 Agent 还没真正开始工作。
解法:工具结果也要做摘要和滚动。最近 1~2 次的工具结果保留原文,更早的让模型总结成一段话。或者在 tool 返回时就做精简——不返回整个 JSON,只返回任务需要的字段。
信息分层:什么该常驻,什么该动态注入
这是上下文工程最值得想清楚的一个设计决定:哪些信息永远在 prompt 里,哪些只在需要时注入。
常驻(每一轮都在):
- System Prompt(角色、规则、约束)
- Tool schemas(至少是正在用的那组)
- 核心 user profile(身份、偏好)
动态注入(按需):
- 从向量库检索的相关事实
- 从工具返回的长文档(只在讨论这个文档时加载)
- 历史对话中相关片段(而不是全部历史)
常驻信息放在 system prompt 或 messages 最前面。动态注入的部分每轮重新计算——上一轮检索到的 5 条事实,这一轮话题变了,重新检索不同的 5 条。
这种设计的精髓在于:不为"可能用得上"的信息占位。大部分信息大部分时间都用不上,只在特定话题出现时才相关。只在那个时候注入。
上下文污染:Agent 最隐蔽的病
这是一个真实存在但很少被讨论的问题:历史工具调用里的错误输出,会污染后续推理。
场景:第 3 步 Agent 调用 search_web,返回的结果里有一段是错误信息("根据某某研究,X 的事实是 Y")。第 5 步 Agent 在总结时,把这段错误内容当作事实引用,因为它已经在上下文里,模型没有怀疑它的动机。
这就是上下文污染。和幻觉不一样——幻觉是模型编出来的,污染是真的进来了错的。应对策略:
工具返回打标签。让工具的返回明确标出"这是 X 工具查到的结果,未经验证",模型在使用时就会谨慎一些:
return {
"source": "web_search",
"confidence": "unverified",
"results": [...]
}
关键结论要求引用。system prompt 里写"任何最终结论,必须指出它基于哪次工具调用的哪个结果"。这种 grounding 迫使模型不能"凭印象"总结。
定期清理可疑内容。长任务可以在中途"重启上下文"——把当前已确认的事实重新组织成一个干净的摘要,把原始工具结果丢掉,带着干净摘要继续。
上下文缓存:生产 Agent 的救命稻草
OpenAI 的 Prompt Caching、Anthropic 的 Prompt Caching、Gemini 的 Context Caching——三家都有类似功能,核心一句话:前缀相同的上下文在几分钟内重复用,按极低单价计费。
对 Agent 的意义特别大。一个跑 20 轮的任务:
- 不用缓存:每轮从头算整个上下文,20 次 × 完整 token
- 用缓存:第一轮建立缓存,后续 19 轮只付增量 token,整体成本降低 70~80%
但缓存只对前缀完全一致的部分生效。所以生产 Agent 的 messages 结构会刻意做这种设计:
[0] System prompt (不变) → 缓存命中
[1] User profile (罕见变) → 缓存命中
[2] Tool schemas (不变) → 缓存命中
[3] 任务描述 → 缓存命中
[4] 动态信息 (每轮变) → 不命中
[5..n] 对话历史 (追加) → 部分命中
把"不变的"放前面、"变的"放后面,是上下文工程的黄金结构。很多人不知道这个,把动态信息放在 system prompt 里,导致缓存永不命中。
工具结果的裁剪:一个实战技巧
工具经常返回远超所需的信息。一个文件读工具返回整个文件,但 Agent 只关心前 30 行。一个 API 返回 50 个字段,但 Agent 只看 3 个。
两种应对:
在工具内部限制——read_file(path, start=0, end=50),让 Agent 指定范围。好处:Agent 能学会只要它需要的部分。坏处:给 Agent 增加认知负担。
在工具外部裁剪——工具返回完整数据,但系统在把结果加到 messages 前用规则或 LLM 截取相关部分。好处:Agent 不用关心。坏处:可能裁错。
生产上两者结合:常用字段由 Agent 在调用时指定,巨大返回(文件、日志)由系统自动截取并用 [truncated: 显示 100/10000 行] 标注。
动态 Prompt:让 prompt 随上下文变化
Agent 跑到不同阶段,system prompt 其实应该不一样。
任务刚开始时:"你是一个规划型助手,优先思考任务拆解" 任务执行中:"你是一个执行型助手,专注完成下一步" 任务快结束时:"你是一个总结型助手,把已完成的工作组织成报告"
这种"阶段化 prompt"能显著提升 Agent 的专注度。代价是破坏 Prompt Cache(每阶段 prompt 变了就要重新算)。权衡的办法:阶段变化少(全任务 2~3 个阶段)且每阶段持续多轮,收益大于缓存损失。
Tool Result Inlining 和 Out-of-band 的权衡
工具返回结果有两种放法:
Inline(放进 tool message)——标准做法。模型能看到,能引用。 Out-of-band(放到外部存储,只给 Agent 一个 ID)——模型看到的是 "已存入 artifact_123",要用时通过另一个工具调取。
第二种做法对大结果有用——读完一个 100MB 的 PDF,直接塞进上下文不可能。把它存到外部,模型后续通过 search_artifact(id=123, query=...) 或 get_artifact_section(id=123, page=5) 按需查看片段。
Claude Code 的 file 读取就是这种思路——它不把整个文件塞给模型,而是用 Read 工具按行号分块取。这让 Agent 能处理远超窗口的代码库。
经验法则
做 Agent 上下文工程时,几条我反复用的经验:
把"每轮重算"和"只算一次"分开。system prompt、tool schemas 放前面,打缓存;动态信息放后面。 显式预算,预算超了强制压缩。不要靠"窗口够大"做借口。 工具返回永远想"这 20KB 里有多少我真正要用"。多的就裁。 污染是真的。给工具结果打 confidence 标签,让模型有质疑的借口。 阶段化 prompt 提升专注度。但只用 2~3 个阶段,别搞 10 个。
下一篇开始讲 Hermes 和工具调用协议——三家大厂各自的 tools 格式有什么差别、为什么开源世界集体押宝 Hermes 的 XML 协议、这些协议差异对你写 Agent 到底有没有影响。
相关阅读
- Context Engineering (Karpathy) — Context Engineering 这个词的出处之一
- Lost in the Middle (2023)
- Anthropic: Prompt Caching Docs
- OpenAI: Prompt Caching
版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。
(采用 CC BY-NC-SA 4.0 许可协议进行授权)
本文标题:08. 上下文工程:Agent 最难的不是推理,是喂什么进去
本文链接:https://www.sshipanoo.com/blog/ai/ai-agent/08-上下文工程/
本文最后一次更新为 天前,文章中的某些内容可能已过时!