导学阶段-上下文工程为什么必须管
本文整理自 CNB 上的开源课程 《Vibe Agent:从零搭建 Coding Agent》。课程讲义、示例代码与练习仓库均在 CNB 上公开,文中示例出自该仓库对应章节。
第 2 章的最小 Agent Loop 每轮把 messages 全量发一遍。三五轮对话里看不出问题,任务一长,这段历史就成了主要的成本和风险来源。
二十轮,259 倍
课程 demo_13_context_explosion.py 让一个旅行助手反复执行同一句追问:总结之前讨论过的要点,再补充 3 条新建议。每轮回复全量塞回 messages,连跑 20 轮,记录 usage 里的 prompt_tokens。
| 轮次 | prompt tokens | total tokens |
|---|---|---|
| 1 | 32 | 432 |
| 5 | 1771 | 2171 |
| 10 | 3946 | 4346 |
| 15 | 6121 | 6521 |
| 20 | 8296 | 8696 |
20 轮,prompt 从 32 涨到 8296,259 倍。增长几乎是匀速的:从第 2 轮起,每轮比上一轮多 435 个 token 左右,因为每轮追加的追问与回复长度基本固定。单轮是线性增长,但每一轮都要把前面全部历史重新发一次,累计开销随轮次平方级上升。20 轮的 prompt 合计约 8.3 万 token,total 合计约 9.1 万。
三类消息,三种膨胀速度
| 信息类型 | 来源 | 单条规模 | 累计速度 |
|---|---|---|---|
| system | 角色提示 | 几百 token | 不增长 |
| user、assistant | 对话历史 | 100 到 500 token | 线性增长 |
| tool | 工具返回 | 几百到几万 token | 可能爆炸 |
最贵的是 tool 消息。read 把整个文件原样塞回上下文,bash 跑一次 npm test 返回几千行 STDOUT,grep 命中几百行也一条不落。一次 read 带回 5000 token 并不稀奇,30 轮就顶到 128K 的天花板。没有上下文管理的 Coding Agent,跑过几轮就可能崩。
tool 消息的写法可以改。同样是查文件,只返回命中的几行和行号,与把整个文件丢回去,token 差一个数量级。工具返回值是上下文的一部分,返回格式在设计工具时就要考虑,不能等到窗口快满了再裁。
三个后果同时出现
撞窗口只是第一层。第二层是成本:每轮重发整段历史,同一段内容被反复计费,到第 10 轮,第 1 条消息已经按 10 次计过价。第三层是模型变笨。Lost in the Middle 的测试把同一段信息放在开头、中间、结尾三种位置,放在中间时模型用上它的比例明显更低;上下文越长,早期约束越容易落进这段被忽略的区间。窗口还有余量,答案质量已经开始下滑。
成本量级可以直接看课程给出的价格表:
| 模型 | 上下文窗口 | 输入价格 | 30 轮预估成本 |
|---|---|---|---|
| GPT-4o | 128K | 约 18 元 / 百万 token | 约 0.36 元 |
| Claude 3.5 Sonnet | 200K | 约 22 元 / 百万 token | 约 0.55 元 |
| DeepSeek-V3 | 128K | 约 1 元 / 百万 token | 约 0.025 元 |
成本还有一层容易被忽略:输入按 token 计费,每一轮都要为新旧全部内容付一次钱。30 轮下来,实际输入量接近把历史逐轮累加,而 messages 的最终长度只反映末尾一轮。
这些是课程讲义给出的量级。换成容量看,128K 大约是一本中篇小说或几万行代码,200K 能装半部《三体》。数字看着宽裕,但前面的实验里 20 轮对话已经吃掉 8.3k token,真实任务往往不止 20 轮。窗口大和可以不管,是两件事:Lost in the Middle 在便宜的模型上同样成立。按 128K 算,二十轮的 8296 token 连上限的十分之一都不到,问题不在装不下,在于每一轮都要重新装一遍。
对应的工程解法各管一头:设 token 阈值,触发后主动压缩消息,管撞窗口;让重复信息只算一次,缓存命中或者用摘要替代原文,管成本;重要事实前置、无关历史后移,管注意力。
上下文工程管什么
2024 年 Andrej Karpathy 说 Context engineering is the new prompt engineering。放到 Agent 上,意思是在正确的时机把正确的信息放进 messages。课程把它拆成四个维度:ContextManager 管本轮 messages 怎么压,Memory 管跨会话的事实怎么存和取,工具输出格式管 tool 消息怎么短而有用,Skills 管领域规范怎么按需加载。第 4 章覆盖前两个。这四个维度对应四类不同的失效:本轮 messages 太长、跨会话记忆丢失、工具输出污染上下文、领域知识塞不进 system prompt。分开处理比在一个地方加压缩逻辑更可控。这一章排在工具与范式之后,因为此前的循环都默认历史可以无限增长。
写 prompt 是基本功,上下文工程决定这套循环能跑多长。两者的区别在于,前者关心一句话怎么说,后者关心每一轮该看到什么。
这对搭 Agent 意味着什么
上下文管理属于前提条件。判断一个 Agent 能不能跑完长任务,先看它怎么组织历史:有没有阈值,tool 消息要不要裁,早期约束放在哪一层。窗口从 128K 涨到 200K,改变的是上限,不改变增长方式。只要每轮全量重发,任何窗口都会被填满。
下一节给出四种具体的压缩策略,从十行代码的截断到工程级的 GSSC 流水线。


