📑 本页目录(点开跳转)
04 · 上下文工程
⏱ 24 分钟 | ⭐⭐ 理解后面一切的钥匙
🎯 一句话
上下文窗口不是硬盘,是有限的注意力预算。整个 Agent 工程的核心命题只有一句: 找到能达成目标的最小高信号 token 集合。
🧠 一、上下文腐烂(Context Rot)
现象:上下文里的 token 越多,模型准确回忆和使用其中信息的能力越差。 不是到了上限才出问题——是渐进式劣化,从很早就开始了。
三个架构性原因(短期内不会消失)
① 注意力是 n² 的
每个 token 要和所有 token 算关系
token 翻倍 → 每个 token 分到的"注意力份额"被稀释
→ 不是容量问题,是【分配】问题
② 训练数据里长序列本来就少
互联网上 100 万字的连贯文档极少
→ 模型在超长上下文上"练得少",能力天然弱
③ 位置编码在长距离上要外推
训练时见过的最长序列有限
→ 超出部分靠插值/外推,定位精度下降
💡 人话类比:
模型像人一样有工作记忆。你把 300 页资料拍在同事桌上说「都看看」, 和把关键 3 页划好重点递过去——得到的工作质量完全不同,哪怕他都"读"了。
⚠️ 一个必须破除的误解
❌ 「窗口 200K,所以我可以塞 200K」
✅ 「窗口 200K 是容量上限,有效工作区远小于它」
厂商宣传的"大海捞针"测试(在长文里藏一句话让模型找)
↑ 这只测【检索】,不测【推理】
真实任务需要:同时用上散落在多处的信息 + 做多步推理
→ 这个能力衰减得比"捞针"快得多
🧰 二、对抗腐烂的四件武器
武器一:压缩(Compaction)
接近上限时,把历史对话总结成摘要,用摘要 + 最近几轮重新开始。
[90K token 的对话历史]
↓ 总结
[2K 摘要] + [最近 3 轮原文]
↓
继续工作,注意力恢复清爽
⚠️ 压缩最容易做砸的地方:摘要提示词写得太笼统,导致丢关键细节。
# ❌ 会丢东西的写法
"总结上面的对话"
# ✅ 必须显式列出要保留什么
"""总结以下 Agent 工作历史。必须逐条保留:
1. 已完成的事(做了什么,结果如何)
2. 当前状态(正在做什么,卡在哪)
3. 下一步计划
4. 所有关键事实:文件路径、做过的决策及理由、报错原文、数字
不要省略任何路径或报错 —— 省略会导致重复犯已经犯过的错。
"""
🔑 判断压缩做得好不好的方法:压缩后问模型「我们刚才为什么放弃了方案 A?」 答不上来 = 摘要丢了决策理由 = 它会重新尝试方案 A。
武器二:结构化笔记(外置记忆)
把重要状态写到上下文之外的文件里,需要时再读回来:
progress.md ← 做到哪了(人可读,方便你介入)
decisions.md ← 为什么这么选(防止反复推翻)
todo.json ← 还剩什么 ⭐ 用 JSON 不用 Markdown
💡 为什么状态文件推荐 JSON:模型更不容易随手改坏或覆盖结构化格式。 Markdown 太"软",模型编辑时容易顺手重写整个文件。格式的刚性提供了保护。
这是第 12 章长时任务 harness 的地基。
🗃️ 注意这里只是记忆的一种实现:把状态写进文件,是为了「这一轮少塞点东西进去」。 但跨会话该留下什么、什么时候该写、旧的记忆过期了怎么办、两条记忆打架听谁的—— 这些问题这一章不管。它们在 04b · Agent 记忆。 ⭐ 一句话分工:上下文工程管「这一轮塞什么进去」,记忆管「跨轮次留下什么」。
武器三:子 Agent(上下文隔离)
把「大量阅读、少量结论」的任务派给一个独立上下文的子 Agent:
主 Agent(上下文珍贵)
│ "去调查这个报错的根因"
▼
子 Agent:翻 50 个文件、读 8000 行日志
(脏活在【自己的】上下文里干)
│
▼ 只返回 200 字结论
主 Agent 继续,完全没被污染 ✅
什么任务适合派给子 Agent:
| 特征 | 例子 |
|---|---|
| 输入大、输出小 | 日志分析、代码库搜索、文档调研 |
| 探索性强、可能白跑 | 「看看有没有类似实现」 |
| 需要完全不同的上下文 | 用另一套规则审查 |
| 不适合 | 需要主 Agent 全程上下文才能判断的任务 |
武器四:⭐ 渐进式披露(Just-in-Time)—— 全领域最重要的模式
不要预加载所有可能用到的信息,让 Agent 在需要时自己去取。
这个思想在整个体系里反复出现:
| 应用 | 机制 | 在哪讲 |
|---|---|---|
| Skills | 元数据(100 token)常驻 → 正文按需 → 附件更按需 | 第 10 章 |
| Tool Search | 工具定义延迟加载,先只给一个搜索工具 | 第 8 章 |
| 文件系统 | 给 ls/grep/read,让模型自己探索,而不是把仓库塞进去 | Claude Code 的做法 |
| 即时检索 | 用时才查,而不是全库入上下文 | 第 11 章 |
🔑 一句话:把"可能有用"的东西变成"可以取到"的东西,而不是"已经在这"的东西。
📉 三、Claude 5 时代的新规则:少即是多
模型变强后,上下文工程的方向从「教它做事」转向「别挡它的路」:
| 旧习惯 | 新规则 | 为什么变了 |
|---|---|---|
| 系统提示词写几千行流程指导 | 砍掉 80% | 模型已经知道怎么做,冗长指导变成噪声 |
| 为旧模型缺陷打的补丁提示 | 每次换代重新审视,删掉过时的变通 | 补丁编码了会过期的假设 |
| 手工编排每一步 | 给目标和验证手段,让模型自己规划 | 模型的规划能力超过了你的预设流程 |
| 写大量示例教它用工具 | 好的工具描述 + 一个示例通常够了 | 见第 7 章 |
🔑 这和第 12 章 harness的核心命题同源: 「你为模型缺陷写的每一段提示词,都编码了一个会过时的假设。」
所以要定期问:我可以停止做什么?
💰 四、上下文与成本:两个立刻能省钱的动作
① Prefix Caching(前缀缓存)
Agent 每轮都重发完整历史(第 1 章)
→ 前缀完全相同 → 可以被缓存复用 → 只为新增部分付费
⭐ 命中缓存的前提:前缀【逐字节相同】
所以要遵守一条布局铁律:
- 工具定义(稳定)
⚠️ 一个真实的常见事故:在系统提示词里塞「当前时间:2026-08-01 14:23:05」 → 每次请求前缀都不同 → 缓存 100% 失效 → 成本翻好几倍。 要放时间就放在最后。
② 控制工具返回的体积
工具返回的内容会永久占据上下文(除非压缩)。
read_logs() 返回 5000 行 → 这 5000 行会一直待在上下文里
search_logs(pattern) 返回 20 行 → 只占 20 行
⭐ 一次贪心的全量读取,会拖累后面所有轮次
第 7 章会展开工具设计。
🔨 五、动手:给你的长会话做尸检
- 找一次你觉得「AI 后来变笨了」的长对话
- 定位它开始出错的那一轮
- 数一下当时上下文里的构成:
真正相关的信息 ____%
失败的尝试 ____%
过时的文件版本 ____%
跑偏的讨论 ____%
- 在那个节点新开会话,只带 3 句话的状态摘要重试
大概率立刻变聪明。这个体验会让你永远记住:清空重来 > 长会话里拉扯。
🕳️ 六、五个常见坑
| 坑 | 症状 | 修 |
|---|---|---|
| 把窗口当硬盘 | 塞满了却效果变差 | 主动筛选,不是能塞就塞 |
| 压缩丢关键事实 | 压缩后重复犯已犯过的错 | 摘要提示词显式列出要保留什么 |
| 该派子 Agent 却在主线干 | 主上下文被日志/搜索结果淹没 | 大输入小输出的任务派出去 |
| 时间戳放前面 | 成本莫名其妙很高 | 动态内容一律放最后 |
| 工具一次返回太多 | 前几轮就把预算烧光 | 工具要支持过滤/分页(第 7 章) |
📚 延伸阅读
✅ 检查点
- 什么是上下文腐烂?三个架构性原因?
- 为什么说"大海捞针测试通过"不代表长上下文真的好用?
- 四件武器分别是什么?各解决什么问题?
- 压缩最容易做砸的地方是什么?怎么检验压缩质量?
- 为什么外置状态文件推荐 JSON 而不是 Markdown?
- 什么样的任务适合派给子 Agent?
- 为什么时间戳不能放在系统提示词开头?
- Claude 5 时代的新规则一句话是什么?
👀 答案
- token 越多,模型使用其中信息的能力越差,且是渐进式的。原因:①注意力 n² 导致份额被稀释 ②训练数据里长序列少 ③位置编码长距离要外推。
- 大海捞针只测检索(找一句藏起来的话),不测推理(同时用上散落多处的信息做多步推理)。后者衰减快得多。
- 压缩(历史→摘要)、外置笔记(状态写文件)、子 Agent(脏活隔离只回摘要)、渐进式披露(按需取用不预载)。
- 摘要提示词太笼统导致丢关键细节。检验方法:压缩后问「我们为什么放弃了方案 A」——答不上来说明丢了决策理由,它会重新尝试 A。
- JSON 格式刚性更强,模型不容易随手改坏或整体重写;Markdown 太"软",编辑时容易被覆盖。
- 输入大输出小(日志分析、代码搜索)、探索性可能白跑、需要完全不同的上下文。不适合:需要主 Agent 全程上下文才能判断的任务。
- 会让每次请求的前缀都不同,Prefix Caching 100% 失效,成本翻倍。动态内容一律放最后。
- 少即是多——砍掉教模型做事的冗长指导,删掉为旧模型打的补丁,给目标和验证手段而非手把手编排。
🛑 可以停在这里
⚡ 走神救援
上下文=有限注意力预算不是硬盘,核心命题只有一句:找到能达成目标的最小高信号 token 集合。腐烂三因:注意力n²稀释份额(是分配问题不是容量问题)、长序列训练少、位置编码外推;⚠️它不是到上限才出问题,是从很早就开始的渐进式劣化。⚠️大海捞针只测检索不测推理,所以「窗口 200K 就能塞 200K」是错的。四武器:①压缩(90K 历史→2K 摘要 + 最近 3 轮原文;摘要提示词必须显式列出要保留什么——做过什么、卡在哪、下一步,以及文件路径、决策理由、报错原文、数字,否则会重复犯错;⭐检验方法是压缩后问它「我们刚才为什么放弃了方案 A」,答不上来它就会重新去试 A)②外置笔记(progress/decisions/todo 三件套,用JSON不用MD,格式刚性防改坏,MD 太软容易被整体重写)③子Agent隔离(大输入小输出的任务派出去:翻 50 个文件、读 8000 行日志都在它自己的上下文里干,只返回 200 字结论)④渐进式披露(最重要,贯穿Skills/ToolSearch/检索——Skills 只让 100 token 的元数据常驻、正文按需;把"可能有用"变成"可以取到",而不是"已经在这")。Claude5新规则:少即是多——系统提示词砍掉 80%,删掉给旧模型打的补丁,定期问"我可以停止做什么"。省钱两招:Prefix Caching(命中前提是前缀逐字节相同,所以动态内容必须放最后,💀时间戳放前面会毁掉全部缓存,100% 失效、成本翻好几倍)、控制工具返回体积(read_logs 的 5000 行会永久占着上下文,search_logs 只占 20 行)。
下一节 👉 04b-Agent记忆.md
🧭 为什么紧接着是记忆:这一章讲的「压缩、外置笔记、子 Agent 隔离」全是在管当前这一轮的上下文。 一旦 Agent 要跨会话记住用户偏好、记住上次踩过的坑,就是另一套问题了。 只想先把 Claude Code 用起来的话,可以直接去 05-ClaudeCode实操-指令该放哪.md。