【学习笔记】上下文工程深度解析 —— 越跑越蠢的 Agent-04/15
上一篇我们用 Fowler 的 2×2 矩阵把 Harness 的各种组件分了类。末尾我提了一句:下一篇聊上下文工程,因为它是 Harness 里最容易卡住整体性能的那一块。
今天就来兑现这个承诺。
先说一个让我印象深刻的现象。
我用 Claude Code 处理过一个比较长的任务——给一个老项目做类型迁移,涉及大概 80 个文件。前半段跑得很顺,Agent 思路清晰,每改完一批文件就记录下来,方向感很强。
但大概到了 40 个文件之后,它开始走样。开始重复检查已经改完的文件,开始把之前定好的类型命名规则搞混,甚至有一次给我改了一个它自己十分钟前刚改完的文件——改的方向还跟之前相反。
我当时以为是模型的问题。换了个更大的模型,同样的现象,只是推迟了一点出现的时间。
后来才明白:问题不在模型,在上下文。
一、上下文的瓶颈
O(n²):数学上写死的瓶颈
Transformer 架构有一个逃不掉的特性:Attention 的计算复杂度是 O(n²)。上下文长度翻倍,计算量变成四倍。
上下文长度翻倍,计算量四倍——Agent 跑了 30 分钟,积累了大量工具调用输出、中间推理、修改历史,上下文窗口已经撑得接近上限,此时每一步推理的成本,远比刚开始时贵得多,质量还在下滑。
Anthropic 的工程团队记录了一个具体的「35分钟墙」:Agent 连续运行超过 35 分钟后,性能开始明显退化。不是模型能力变弱,是上下文太长、信息密度太高,模型的注意力开始稀释,重要的早期信息被淹没在大量后续输出里。
我当时踩的坑,就是这个。
上下文管理决定 Agent 能跑多远、跑多稳、跑多便宜。这才是 Harness 里真正的核心——不是最花哨的那块,是最容易被忽视、出问题最安静的那块。
二、四板斧:把上下文管好
Anthropic 和 OpenAI 在他们的工程实践里,都反复提到四个具体技术。我按照「出手时机」来排:先是防止上下文膨胀的两招,再是降低成本的两招。
2.1 第一招:Compaction(压缩)
上下文快满了怎么办?暴力截断?不行,早期的关键信息会丢失。
Compaction 的思路是智能摘要:在接近上下文限制之前,把当前窗口里的内容压缩成一个结构化摘要,然后用这个摘要替换掉原始内容,继续往前跑。
Anthropic 已经把这个做成了 API 级别的能力——你不需要自己实现压缩逻辑,只需要告诉系统「在 80% Token 占用时触发压缩」,框架自动处理。
其中有一项更精细的技术叫 ACON(Anchored Context Optimization Network)——锚定式迭代摘要。
普通的摘要是把全文压缩成一段话,问题是细节大量丢失。ACON 的做法是:先识别「锚点」——任务列表、已完成项、关键约定、已知约束这些必须保留的信息——然后围绕锚点做有选择的压缩,舍弃的是冗余的中间步骤,保留的是影响后续决策的核心状态。
效果是 26-54% 的峰值 Token 降低。换算成成本:一个原本需要 100 万 Token 完成的任务,用 ACON 可能只需要 50-70 万。
但 Compaction 有它的代价:压缩必然有信息损失。压缩越激进,信息损失越多。好的 Compaction 策略需要在「压缩比」和「信息保留」之间找平衡——这本身就是一个需要精心设计的 Harness 组件。
我自己的经验是:任务早期的关键约定(命名规范、架构决策、禁止事项)必须标记为「锚点」不可压缩,中间的工具执行细节可以大胆压缩。
2.2 第二招:Tool Call Offloading(工具输出卸载)
Agent 运行时有一类特别危险的上下文污染源:大体量工具输出。
想象 Agent 调用了 grep 搜索整个代码库,返回了 500 行匹配结果。这 500 行会直接进上下文窗口,吃掉大量空间,而真正有用的可能只有其中 5 行。
Tool Call Offloading 的解法很直接:保留头尾,全量卸载到文件系统。
具体逻辑:工具返回大体量输出时,Harness 自动截取前 50 行和后 50 行放入上下文(让模型知道输出的大致结构),完整内容写到临时文件(比如 .agent-workspace/tool-output-123.txt)。需要深查时,Agent 显式读文件;不需要时,这 500 行不占上下文一个 Token。
这个技术听起来简单,效果却相当显著——特别是在涉及大量文件读取、搜索、日志分析的 Agent 任务里,上下文膨胀速度可以降低 60% 以上。
Claude Code 就是这么设计的。你在用它的时候,注意观察它处理大文件时的行为——它不会把整个文件塞进上下文,而是把文件「记在外面」,按需拉取。
2.3 第三招:Progressive Disclosure(渐进式披露)
这一招不是在任务执行过程中起作用,而是在任务开始时起作用。
很多人建 Harness 的时候,会把所有东西塞进系统提示:所有工具的完整文档、所有规则、所有示例、所有注意事项……结果系统提示动不动就几千甚至上万 Token。任务还没开始,上下文窗口已经用掉了相当一部分。
Progressive Disclosure 的思路是:系统提示只是地图,不是百科全书。
入口文件保持短小(大约 100 行左右):核心角色定义、关键约束、可用工具的简短列表、以及「如何获取更多信息」的指引。
工具文档、详细规则、示例代码——全部外链,按需加载。Agent 需要用某个工具时,去读那个工具的文档文件;遇到特定场景需要更多指引时,去读对应的规则文件。
Claude Code 的 Skills 系统就是这个思路。每个 Skill 是一个独立的文件,系统提示里只有 Skill 的名字和一句话描述。Agent 决定要用某个 Skill 时,才把那个文件加载进来——不用的 Skill 一个 Token 都不占。
效果:同样功能完备的 Harness,用 Progressive Disclosure 设计,系统提示的初始大小可以从 8000 Token 压到 500 Token 以内。
2.4 第四招:Prompt Caching(提示缓存)
这一招直接冲着成本去的。
大多数 Agent 任务有一个特点:系统提示(角色定义、规则、工具描述)在整个会话期间是不变的。每次 Agent 调用都带着这一大段相同的内容,每次都要重新计算——浪费。
Prompt Caching 让模型对「不变的前缀」做一次计算,结果缓存下来,后续调用直接复用缓存。
Anthropic API 支持显式标记缓存断点(cache_control: ephemeral)。在恰当位置打上标记之后:
-
输入成本降低约 90%(缓存命中的 Token 不重新计费)
-
延迟降低约 75%(缓存命中不重新计算)
对于有大量工具描述或长系统提示的 Harness,这几乎是免费的优化——代码改动不超过十行,收益立竿见影。
有一个坑要注意:Prompt Cache 的 TTL(生存时间)是 5 分钟。如果 Agent 两次调用之间间隔超过 5 分钟,缓存失效,下次重新计算。设计 Agent 的执行节奏时要考虑这一点——如果有频繁的长间隔,缓存收益会打折扣。
三、把四板斧拼在一起
光讲四个技术还不够,关键是它们怎么组合。
一个完整的上下文管理策略是这样的:
任务开始
│
▼
系统提示(Progressive Disclosure)
│ 只有核心入口,~100 行
│ 按需加载工具文档 / 规则文件
│
▼
执行过程
│
├── 工具输出大? → Tool Call Offloading
│ 头尾入上下文,全量写文件系统
│
├── 上下文到 80%?→ Compaction
│ 保留锚点,压缩冗余
│ 干净上下文继续跑
│
└── 每次 LLM 调用 → Prompt Caching
系统提示缓存命中
90% 成本直接省掉
四招不是并列关系,是分工:
-
Progressive Disclosure 控制起点,让上下文从一开始就精简
-
Tool Call Offloading 控制增速,防止执行过程中的膨胀
-
Compaction 控制上限,临近满载时及时清理
-
Prompt Caching 控制成本,把重复计算变成零边际成本
缺任何一招,都会有对应的漏洞。

五、一个实战数字对比
说个数字,我自己跑过的一个项目。
任务背景:让 Agent 分析一个中型代码仓库(约 200 个文件),找出所有违反某一架构规则的调用点,生成改造方案,逐文件修改。
5.1 没有上下文管理(原始跑法):
-
任务到 60% 左右开始出现重复操作
-
到 75% 上下文已经接近上限,Agent 开始频繁输出「我需要先确认一下之前的进度」
-
任务最终没有跑完,需要人工接管
5.2 加入四板斧之后:
-
全程无需人工介入,任务一次跑完
-
总 Token 消耗减少约 45%(Compaction + Offloading)
-
API 调用成本减少约 62%(Prompt Caching + Token 减少叠加)
-
任务执行时间反而缩短了 30%(缓存命中降低延迟)
不是玄学,是工程。

六、上下文是稀缺资源,要像内存一样管
我最近在和一个做 AI Infra 的朋友聊,他说了一句很准确的话:
「上下文窗口就是 Agent 的内存,但大多数人用它的方式像是从不释放内存的程序员。」
传统软件里,程序员知道内存是有限的,会主动分配、使用、释放。但在 Agent 开发里,很多人把上下文当成无限大的草稿纸——往里塞,塞满了换一个,然后抱怨模型不够聪明。
上下文管理不是 Harness 的「高级选项」,是基础设施——就像你的程序必须管好内存,你的 Harness 必须管好上下文。
四板斧用熟了,你会开始有自己的感觉:哪些信息绝不能压缩,哪些工具输出从来不需要看全量,哪段系统提示可以抽出来做缓存。这种感觉是 Harness 工程师的直觉,练出来之后干活会快很多。
但有一句话可以先记住:每一个进上下文的 Token,都应该值得占那个位置。
下一篇讲工具设计。上下文管好了,Agent 还是得靠工具跟世界打交道——工具设计得好,它的「手」就精准;设计得差,它就是一头力气很大但到处打翻东西的熊。
参考文献:
更多推荐
所有评论(0)