翻译:Transwan
校对:Carl Cui

如果你经常使用 AI Agent,大概率碰到过这种情况:任务刚开始的时候,agent 表现得很好,能理解目标,也能选对工具,前几步推理看起来都在正轨上;但跑到第十几步、二十几步之后,质量开始变得不稳定,它可能忘了最初的要求,开始调用一些没必要的工具,或者输出明显变得粗糙。
很多人的第一反应是模型不够强,但在 Agent 场景里,问题往往不在模型本身,而在它在执行过程中看到了什么、忘掉了什么,以及被哪些无关信息干扰了。
这就是上下文工程要解决的问题,组织模型所看到的内容被称为上下文工程。过去我们谈提示词工程,关注的是如何写好一段初始指令;现在我们构建 Agent,要关心的是如何管理模型在每一步能看到的全部信息。一个可靠的 Agent,不只有一个好 prompt,而是有一套能够持续运转的工作记忆系统。
1. 什么是上下文工程,为什么 Agent 特别需要它
提示词工程解决的是“怎么把任务说清楚”。比如角色怎么设定,目标怎么描述,输出格式怎么约束,示例怎么给。这在普通聊天场景里很有效,因为聊天机器人通常只是在回答一个问题。但 Agent 不一样,它会连续执行动作,会浏览网页、调用 API、读取文件、写代码、运行命令,并根据中间结果继续做下一步决策。每一次工具调用、每一段检索结果、每一次对话历史,都会成为模型下一步推理时可能看到的上下文。
所以,上下文工程不是提示词工程的替代品,而是它在 Agent 时代的扩展。Anthropic 对这个概念的定义很直接:上下文是你从 LLM 中采样时包含进去的 token 集合;上下文工程,就是优化这些 token 的效用,让模型持续得到我们想要的结果。换句话说,关键不是把更多东西塞进窗口,而是在正确的时间、以正确的形式,让模型看到真正有用的信息。
可以把模型想象成 CPU,把上下文窗口想象成 RAM。CPU 再强,如果内存里塞满了无关内容,程序也会变慢、变乱。Agent 也是一样。上下文窗口一旦被大量工具输出、历史对话、过期信息和重复内容占满,模型的推理质量就会下降。这个过程通常不是到了上下文上限才突然发生,而是在窗口还远没有填满时就已经开始退化。
这类现象常被称为 context rot,也就是上下文腐烂。Chroma 的研究测试了多个前沿模型,发现随着输入长度增加,模型表现会变得越来越不稳定。另一个经典问题叫 Lost in the Middle:模型更容易使用上下文开头和结尾的信息,中间的信息反而容易被忽略。对 Agent 来说,这尤其危险,因为最初的任务目标、约束和关键背景,可能在几十步之后被大量工具输出埋到中间。模型虽然“看得到”,但实际上已经不怎么用它了。
一个 Agent 的上下文通常也远不止用户的一句话。它至少可能包含七类内容:系统提示、工具定义、工具调用结果、检索到的知识、对话历史、短期和长期记忆,以及 Agent 当前的状态。系统提示定义 Agent 的身份、边界、任务流程和工具使用原则;工具定义告诉模型每个工具能做什么、参数是什么、什么时候该用;工具调用结果可能是网页全文、文件内容、命令输出或 API 返回值;RAG 系统会把检索到的文档片段塞进来;对话历史记录之前发生过什么;记忆系统加入用户偏好和历史经验;Agent 状态里还有当前计划、待办事项、已完成步骤和草稿笔记。
这些内容都在争夺同一个上下文窗口。如果不加管理,窗口迟早会被填满,而且不一定是被有价值的信息填满。很多长任务 Agent 到后面变得敷衍,并不是它突然变笨了,而是它的工作记忆被污染了。
2. 四个核心策略:写入、选择、压缩、隔离
最有效的方式是把上下文工程拆成四个动作:写入、选择、压缩和隔离。这四个词看起来简单,但基本覆盖了 Agent 上下文管理的大多数问题。
写入解决的是 Agent 会遗忘的问题。长任务中,有些信息不应该只留在上下文窗口里,而应该被保存到外部存储中,比如重要发现、阶段性结论、项目规则、用户偏好。Claude Code 的 CLAUDE.md 就是一种典型的项目规则文件;在复杂任务里让 Agent 生成 research.md、plan.md、progress.md,也是同一类思路。写入的意义是不要指望模型一直记住所有细节,该落盘的就落盘,该结构化保存的就结构化保存。
选择解决的是另一个问题:不要把所有东西都塞给模型。传统 RAG 通常是系统先检索几段文档,然后塞进 prompt。但 Agent 场景更动态,每一步需要的信息都不一样,因此更好的方式是让 Agent 自己决定当前要查什么、用什么工具、什么时候信息已经足够。工具选择尤其重要。很多 Agent 一接入 MCP 或外部工具,就暴露几十个工具定义,看起来能力变强了,实际上模型更容易混乱。工具太多不仅浪费 token,还会干扰判断。更好的做法是只给当前步骤相关的工具,或者用语义检索先筛选工具定义。工具不是越多越好,能被正确选择和使用才有价值。
压缩解决的是上下文持续膨胀的问题。Agent 跑得越久,工具输出、历史消息和推理过程就越多。很多内容在当时有用,但几步之后已经不再需要原文。继续保留它们,只会增加成本、延迟和噪音。压缩可以发生在信息进入上下文之前,比如分块、重排、摘要;也可以发生在运行过程中,比如持续总结对话历史,只保留近期细节;还可以发生在工具结果被使用之后,用一段关键结论替代原始输出。压缩不是简单删内容,而是把原始材料变成当前任务还需要的有效信息。
隔离解决的是不同任务阶段互相污染的问题。一个 Agent 如果在同一个上下文里完成研究、规划、实现、测试和调试,窗口很快就会乱掉。研究阶段的大量搜索记录,到了实现阶段可能已经变成噪音。所以复杂任务应该拆成阶段,甚至拆给子 Agent。比如父 Agent 让子 Agent 去搜索代码库,子 Agent 在自己的上下文里读取大量文件,最后只把摘要交回父 Agent。这样搜索过程不会污染主上下文。隔离的本质是让不同任务使用不同工作区,最终只交换压缩后的结果。
这四个策略经常不是单独使用的。一个真正可靠的长任务流程,通常会同时用到它们:先把关键发现写入外部文件,再选择下一阶段真正需要的信息,把冗长历史压缩成摘要,并用新的上下文窗口隔离不同阶段的工作。
3. 上下文出问题时,Agent 会怎么失败
理解失败模式,是学习上下文工程最直接的方式。因为很多 Agent 问题表面上看像“模型乱来”,实际上都是上下文管理失控后的结果。
第一种失败是上下文投毒。错误信息一旦进入上下文,Agent 后续步骤就可能继续引用它,错误越滚越大。比如某个工具返回了错误数据,或者 Agent 早期做了一个错误判断,但这个判断一直留在上下文里。要预防这种问题,需要在工具输出进入上下文之前做验证,在新信息出现后主动剪枝过时或冲突的内容,并在 Agent 从错误中恢复后压缩失败尝试的历史。如果只有最终解决方案重要,就不要把十几步无效调试过程继续留在窗口里。
第二种失败是上下文干扰。上下文太长之后,模型会过度依赖近期历史,不再重新综合判断,只是在重复之前的模式。它看起来还在工作,但已经不太像是在独立思考。解决方法是主动摘要和剪枝,不要因为模型支持大窗口,就把所有历史都原样保留。大上下文窗口不是垃圾桶,它只是给你更多组织空间。
第三种失败是上下文混淆。无关内容太多,模型开始拿错信息、选错工具,尤其是在工具定义过多时更容易发生。很多团队给 Agent 接上几十个工具,以为能力更完整了,实际却增加了模型判断负担。解决方式是动态工具管理:保持工具集与当前阶段相关,或者用语义检索只呈现当前步骤需要的工具定义。
第四种失败是上下文冲突。系统提示、检索文档、历史记录之间互相矛盾,模型不知道该信谁,于是行为变得不稳定。这个问题需要通过结构化上下文和优先级规则来解决。比如明确系统提示高于检索事实,检索事实高于对话历史;用 Markdown 标题、XML 标签或其他结构化分区标明信息来源;新信息进入上下文之前,也应该检查它是否和已有信息冲突。
这四类问题分别对应了前面的四个核心动作。投毒需要验证、剪枝和压缩;干扰需要压缩;混淆需要选择;冲突需要结构化写入和优先级选择。上下文工程的价值就在这里:它让我们不再把 Agent 失败简单归因于“模型不行”,而是能定位到具体的信息管理问题。
4. 生产系统怎么处理上下文
到了生产环境,上下文工程首先体现在系统提示和工具定义上。给 Agent 写系统提示,和给聊天机器人写系统提示不是一回事。聊天机器人的系统提示可能只是“你是一个友好、简洁的助手”,但 Agent 的系统提示更像操作手册。它要说明 Agent 如何处理任务,什么时候使用工具,遇到错误如何恢复,哪些事情不能做,什么情况下需要停止并询问用户。
这里有一个平衡点。提示太细,会变得脆弱,遇到没覆盖的边界情况就失效;提示太虚,又无法指导 Agent 做决定。更好的写法是提供清晰的原则和启发式规则,而不是把所有情况写成死板的 if-else。用 Markdown 标题或 XML 标签组织结构,用少量高质量示例展示正确行为,通常比堆很多模糊规则更有效。
工具定义也是很多 Agent 系统里被低估的一部分。每个工具都需要 schema、参数说明、使用时机和容错说明,这些内容本身就会消耗大量 token。接入的 MCP Server 越多,工具定义越容易膨胀。处理大量工具主要有两种思路:一种是工具屏蔽,另一种是基于 RAG 的工具选择。Manus 的做法是尽量保持上下文前缀稳定,避免频繁增删工具定义破坏 KV-cache;工具定义可以留在固定位置,但通过状态告诉模型哪些工具当前不可用。如果工具数量特别多,则可以先检索当前步骤相关的工具定义,而不是每次加载全部工具。
这里背后的工程原则很朴素:稳定内容放在上下文顶部,动态内容放在底部。系统提示、基础规则、核心工具定义尽量保持稳定;对话历史、当前任务状态、工具结果则放在后面。这样既利于模型理解,也利于缓存复用,能降低成本和延迟。
对于复杂任务,这里推荐一种“频繁、有意压缩”的流程。第一步是研究,让 Agent 先探索代码库或资料,必要时用子 Agent 搜索文件、梳理架构、找相关函数;第二步是产出研究文档,不要把所有搜索过程留在上下文里,而是整理成 research.md,记录关键路径、函数、现有模式和风险点。接下来重置上下文,新窗口只带研究文档和任务目标,然后进入规划阶段。Agent 基于干净上下文生成实现计划,这个阶段很适合人工审查,因为逻辑错误在计划阶段最容易修;最后才是实现阶段,再开一个干净上下文,只带计划和必要规则。复杂任务可以用 progress.md 跟踪完成情况。
这套流程的关键,不是让 Agent 一口气从头跑到尾,而是让每个阶段都产出一个压缩后的中间产物,再用它开启下一阶段。这样既减少上下文污染,也让人类更容易在关键节点介入。
不同平台对上下文工程的实现方式不一样,但底层问题是相同的。Claude Code 的思路比较轻量:它会预加载 CLAUDE.md,然后用 grep、glob 等工具按需探索代码库。它不试图一开始索引所有东西,而是让模型自己决定下一步需要查什么,同时支持自动压缩、子 Agent 和记忆。
Manus 更偏基础设施。它关注 KV-cache、稳定前缀、工具屏蔽、观察压缩、待办列表,以及用文件系统作为外部记忆。它的重点是规模化运行时的成本和稳定性。ChatGPT Agent 更偏 GUI 场景,会处理截图、浏览器状态和操作历史,因此上下文工程的难点变成了如何管理高成本的视觉 token。Google ADK 则更工程化,强调存储和展示分离,用显式处理器转换上下文,并默认只给模型最小必要信息。
这些平台的具体实现不同,但流程大体接近:先收集候选信息,再选择相关内容,然后压缩、排序,最后组装成一次模型调用的上下文。
结语:Agent 的关键不是记得多,而是看得准
上下文工程真正要解决的,不是怎么把更多东西塞进模型,而是怎么让模型少看垃圾、多看信号。很多 Agent 失败,并不是因为模型不够强,而是因为它的上下文里充满了过期信息、重复信息、错误信息、冲突信息和无关工具。
所以,构建可靠 Agent 的核心能力正在从“会写 prompt”转向“会管理上下文”。你需要知道哪些信息应该写下来,哪些信息应该被选中,哪些信息应该被压缩,哪些任务应该被隔离。你还需要设计系统提示、工具定义、记忆、状态和压缩流程。
换句话说,上下文工程就是 Agent 时代的内存管理。模型负责推理,但你负责决定它在推理时看见什么。这个决定,往往比换一个更强的模型更重要。