上下文工程:生产级 AI 智能体的隐形架构
大多数 AI Agent 的 Bug 并不是模型本身的 Bug。模型只是在执行它被告知的操作——出问题的是你放入上下文(context)的内容。在 Agent 执行到一定阶段后,问题不在于能力,而在于熵:噪声、冗余和注意力错位的缓慢积累,这会降低模型生成的每一项输出的质量。研究人员称之为“上下文腐烂”(context rot),而且所有主流模型——GPT-4.1、Claude Opus 4、Gemini 2.5——在任何输入长度增加的情况下,无一例外都会表现出这种现象。
上下文工程是专门管理这一问题的学科。它比提示词工程(prompt engineering)更广泛,后者主要关注静态的系统提示词。上下文工程涵盖了模型在推理时看到的一切:你包含什么、排除什么、压缩什么、将内容放在哪里,以及如何在长期运行的任务中保持缓存状态。
为什么 Agent 不同于聊天机器人
聊天会话 以线性方式积累 Token。用户发送消息,模型进行响应,下一轮对话追加到末尾。输入与输出的比例大致平衡,且会话通常足够短,上下文管理并不那么重要。
Agent 打破了所有这些假设。一个执行多步任务的 Agent 会生成工具调用、工具响应、中间观察结果和规划轨迹。每一步的输出都很简洁——可能只是一个简短的工具调用。但积累的输入会随着每一步的进行而增长。实际生产中的 Agent 通常会达到 100:1 甚至更糟的输入输出比。一个需要 50 步才能完成的任务可能会消耗 50,000 个 Token 的上下文,而只产生 500 个 Token 的有意义输出。
这不仅仅是成本问题。Transformer 的注意力机制呈二次方缩放:在 10 万个 Token 时,每个注意力头需要处理 100 亿个成对关系。模型的有效召回能力在你达到上下文窗口限制之前就已经退化了。斯坦福大学的研究发现,支持 20 万 Token 窗口的模型在达到 5 万 Token 时就会出现显著的质量下降。Chroma 的 2025 年基准测试显示,一旦输入超过某个阈值,某些模型的准确率会从 95% 骤降至 60%——这远未达到限制,而是远在限制之前。
常见的失效模式包括:
- 上下文污染(Context poisoning):幻觉进入上下文,并在后续环节被反复引用
- 上下文干扰(Context distraction):模型过度关注积累的历史记录,而非当前任务
- 迷失在中间(Lost in the middle):模型能很好地处理上下文的开头和结尾,但对中间部分的处理较差——埋在中间的相关信息被忽略的概率比边缘信息高出 30% 以上
- 干扰项干预(Distractor interference):语义相似但无关的内容会主动误导模型的注意力
所有的这些问题都不会出现在你的系统提示词测试中。它们是在 Agent 运行 15 分钟后的生产环境中浮现出来的。
KV 缓存优化是必选项
在生产环境中,KV 缓存(KV-cache)优化是你拥有的最具影响力的杠杆。在 Claude 等服务上,缓存的 Token 成本可能比未缓存的 Token 低 10 倍。但只有在你的提示词前缀在请求之间保持稳定时,缓存才会生效。
大多数团队会在无意中通过一些初衷良好但微小的改动破坏缓存命中:
- 在系统提示词中注入时间戳或会话 ID
- 根据推断的相关性动态重新排序工具定义
- 在头几百个 Token 中插入用户特定的数据
这些操作都会导致每次请求的前缀缓存失效。解决方法很简单:将所有动态内容推向上下文的末尾,而不是开头。你的系统提示词、工具定义和静态指令应该被固定并置于首位。用户特定的上下文、对话历史和当前任务状态应放在最后。在需要重复调用模型的任务负载中,这一简单的改变通常能使推理成本减半。
仅追加(Append-only)上下文增强了这一点。与其为了节省 Token 而选择性地删除工具结果或观察结果,不如追加新信息并让缓存自然构建。删除操作导致的缓存失效损失远超你节省的成本。
将文件系统视为无限的上下文
上下文窗口是有限的,但任务不是。实际的解决方案是停止将上下文窗口视为主要存储介质,而是开始将文件系统(或任何外部持久化存储)视为内存的延伸。
这种模式是这样的:与其保留 Agent 访问的每个网页或处理的每个文档的全部内容,不如只保留指针(pointer)——一个 URL、文件路径或唯一标识符。当你需要从上下文中压缩掉观察结果时,删除内容但保留引用。当你再次需要该内容时,由 Agent 重新获取。
这是可逆压缩。不可逆压缩——总结内容并丢弃原文——会永久丢失信息。可逆压缩则不会丢失任何内容。Agent 随时可以重新读取文件。代价是一次工具调用;收益则是任意大的可寻址工作集。
这也重新定义了 Agent “即时加载”的含义。与其预先在上下文中填充 Agent 可能需要的一切,不如给 Agent 提供在实际需要时调取信息的工具。上下文起步很小,然后有条理地增长,由 Agent 为特定步骤拉取特定数据,而不是在一开始就堆砌大量可能无关的内容,从而从第一个 Token 开始就消耗注意力预算。
通过复述维持注意力
LLM 没有独立于上下文的工作记忆。它们通过在 token 中看到任务来“记住”任务。随着上下文的增长,原始任务描述退到长序列的中间,模型对其的注意力就会减弱。
解决方法是刻意的复述:设计你的智能体(Agent)来维护一个工件——待办事项列表、计划或结构化的状态文档——它们在每一步都会更新,并且始终出现在当前上下文的 末尾 附近。模型 会以更高的权重持续关注最近的 token。通过在上下文末尾附近附加一份简洁、最新的任务说明和进度,你可以在长的执行序列中保持模型的目标导向。
这并不是提示词堆砌(prompt padding)。如果做得好,复述工件是真正有用的状态——它结构化地展示了已完成的工作、正在进行的任务以及到目前为止的失败模式。模型既可以将其作为上下文锚点,也可以将其作为规划工具,从中受益。
保留错误痕迹
在构建智能体时,一种本能是清理上下文——移除失败的尝试、修剪工具错误、向模型展示一个整洁的成功操作序列。这种本能是错误的。
将失败的尝试留在上下文中可以提供一些极其宝贵的东西:隐式错误恢复。当模型看到某个特定操作导致了失败时,它对随后类似操作的注意力会发生转移。它不需要明确的指令来告诉它不要重复错误。上下文中的失败模式改变了先验概率。
删除错误痕迹并不会让上下文更整洁。它会让模型变得“健忘”。一个无法看到自己尝试过什么的智能体,会再次尝试。保留错误痕迹的性能成本是客观存在的——你正在为那些不能直接推动任务进展的 token 付费。但在生产环境中,可靠性带来的收益通常超过了这个成本。
实践准则:保留错误痕迹,直到智能体成功绕过失败点。到那时,可以对它们进行压缩。但不要为了节省 token 而主动删除它们。
