Rahul (@sairahul1)
2026-06-17
D
原文
---
title: "面向 AI 智能体的上下文工程:完整攻略"
author: "Rahul (@sairahul1)"
source_url: "https://x.com/sairahul1/status/2067171101978071501"
published_at: "2026-06-17T09:02:51.000Z"
fetched_at: "2026-06-17T16:08:11Z"
updated_at: "2026-06-17T16:08:11Z"
language: "zh"
review_status: "draft"
---

# 面向 AI 智能体的上下文工程:完整攻略
你的 AI 智能体在前 10 步运行得很棒。
然后到了第 15 步左右,它开始变得潦草。
调错工具。忘掉你最初的指令。输出质量低下。
大多数人会怪模型。
可这几乎从来都不是模型的问题。
问题在于模型看到的是什么。
组织模型所看到的东西,这件事叫做**上下文工程(context engineering)**。
它正在迅速成为任何搭建 AI 智能体的人最重要的技能。
下面就是这份完整攻略。
---
### **提示词工程已死。如今真正要紧的是上下文工程。**

你听说过提示词工程(prompt engineering)。
写清晰的指令。好的示例。告诉模型该扮演什么角色。
对一个聊天机器人来说,这套办法完美奏效。
可一旦你搭建的是一个智能体,它就不再管用了。
原因如下。
聊天机器人回答一个问题,然后停下。
而智能体会采取行动——浏览网页、调用 API、写代码、运行命令——一步接一步又一步,有时多达几十步。
每一步都产生输出,被加进模型的上下文里。
而那个上下文是有限的。
Anthropic 的工程团队是这样定义的:
「上下文是你从一个 LLM 采样时所包含的那组 token。上下文工程,就是优化这些 token 的效用,从而稳定地达成期望的结果。」
简单说:确保你的智能体在正确的时间、以正确的格式,看到正确的信息。
提示词工程是上下文工程的一个子集。
上下文工程则是全部。
---
### **你智能体的上下文窗口就是内存(RAM)。而它正在被填满。**

LangChain 对此有个恰当的类比。
把一个 LLM 想象成一种新型的操作系统。
模型是 CPU——它负责思考。
上下文窗口是内存(RAM)——那块工作记忆,模型当前能看到、能推理的一切都住在那里。
就像你的电脑在内存被填满时会变慢一样,你智能体的推理能力也会在上下文窗口变得拥挤时退化。
这叫做**上下文腐烂(context rot)**。
Chroma 做过一项研究,评估了 18 个前沿模型——GPT-4.1、Claude 4、Gemini 2.5、Qwen3 以及其他。
每一个模型的表现,都随着输入长度的增加而退化。
不是在硬性上限处退化,而是远在那之前就开始了。
一个拥有 200K token 窗口的模型,可能在 50K token 时就显示出明显的退化。
这种下滑是连续的,不是一道断崖。
为什么?Transformer 的工作方式是让每个 token 都关注其他每一个 token——这制造出 n 的平方级别的关系。随着上下文增长,模型把所有这些关系都把握住的能力,就被稀释了。
然后还有「迷失在中间」(Lost in the Middle)的问题。
LLM 表现出一条 U 形的注意力曲线。
→ 上下文的开头:记得很牢
→ 上下文的结尾:记得很牢
→ 中间:基本被忽略
研究者测得,当相关信息从上下文的开头移到中间时,准确率下降超过 30 个百分点。
你那些最初的指令——被埋在 50,000 个 token 的工具输出之下——实际上就消失了。
Claude Code 的用户发现,输出质量在**上下文容量的 40%–60%** 处就开始退化。远在任何硬性上限之前。
---
### **究竟有哪些东西在争抢你智能体上下文里的空间**

7 个类别。全都在争夺同一个有限的窗口。
**1. 系统提示词(System Prompt)**
智能体的身份。行为规则。控制流逻辑。针对不同任务类型的指令。在一个智能体里,这不只是「乐于助人」那么简单。它可以定义整个架构。
**2. 工具定义(Tool Definitions)**
智能体可能调用的每一个工具,都需要一份 schema 来描述它做什么、接受哪些参数、什么时候该用它。
**3. 工具调用结果(Tool Call Results)**
每一次工具调用都会把它的输出加进上下文。一次网页抓取:5,000–10,000 个 token。一次文件读取:差不多。这些累积得很快。
**4. 检索到的知识(RAG)**
从向量数据库拉取的文档、搜索结果、API 响应——任何为给智能体的决策提供信息而检索来的东西。
**5. 对话历史(Conversation History)**
所发生一切的完整记录。用户消息、智能体回复、推理、先前的决定。每一轮都让它线性增长。
**6. 记忆(Memory)**
来自当前会话的短期记忆。来自先前会话的长期记忆——用户偏好、过往结果、学到的模式。
**7. 智能体状态(Agent State)**
当前的计划、待办清单、进度标记、草稿笔记。那些追踪智能体在一个多步任务里走到哪一步的元信息。
7 项全都在争夺同一个窗口。
上下文工程,就是决定谁胜出。
---
### **4 个核心策略**
LangChain 发布了一套框架,把每一种上下文工程技术都归进 4 个桶里。
你将来会学到的每一种技术,都能装进其中之一。
**写入。选择。压缩。隔离。**

---
### **策略 1 —— 写入(Write)** *(智能体会遗忘。给它一个记住的办法。)*

当一个智能体的上下文被填满、随后被压紧(compacted)时,它会丢失信息。
如果在那之前智能体什么都没记下来——那条信息就永远没了。
**写入**意味着给智能体一些办法,把信息持久化到上下文窗口之外。
三种形式:
**草稿区(Scratchpads)**
给智能体一个工具,让它在执行任务的过程中记笔记。中间发现。做出的决定。它知道自己稍后会需要的信息。
Anthropic 造了一个「think」工具——一块让 Claude 把问题想透的专用空间。
在 tau-bench 基准测试上,这在某些任务上把表现提升了高达 54%。
**规则文件(Rules Files)**
持久化的流程记忆。
如果你用过 Claude Code,就见过 CLAUDE.md。
每次会话开始时加载的指令——项目架构、约定、怎么跑测试、要当心什么。
智能体每次启动都会读它。
它永远不会忘掉那些根本性的东西。
**记忆提取(Memory Extraction)**
智能体把事实、用户偏好和学到的模式保存下来,以便跨会话检索它们。
完全活在上下文窗口之外。
智能体明天需要的信息,等明天来临时就在那里等着。
---
### **策略 2 —— 选择(Select)** *(别把所有东西都给智能体。给它此刻需要的那些。)*

一个拥有 40 个工具、一个庞大知识库,以及好几个会话历史的智能体,没法一次性把这些全都加载进来。
总得有什么来决定,对这一步来说什么才是相关的。
**传统 RAG:** 由系统来决定。
用户提问 → 检索文档 → 塞进提示词 → 完事。
静态。一次性。模型没有发言权。
**智能体式 RAG(Agentic RAG):** 由智能体来决定。它搜索自己需要的东西,精炼查询,挑选工具,判断自己什么时候信息已经够了。
把检索当成一个迭代的过程,而不是一条一次性的流水线。
这之所以要紧,是因为「什么才相关」在每一步都在变——而只有智能体知道自己下一步需要什么。
**工具选择问题,是最让人栽跟头的那一个。**
如果你的智能体有 40 多个工具,那就可能是 10,000 个 token 的工具定义,在任何工作开始之前就坐在上下文里。
解法:**对工具描述做 RAG。**
不要在每次调用时都把所有工具定义一股脑倒进去,而是用语义搜索,只把与当前这一步相关的工具浮现出来。
一篇叫 RAG-MCP 的论文测试了这个做法。
工具选择准确率:14% → 43%(提升 3 倍)。token 用量:大致砍掉一半。
Anthropic 称之为一种**混合策略**:把核心上下文(比如 CLAUDE.md)预先加载好,让智能体对其余一切做即时(just-in-time)检索。
把基础的东西前置加载。其余的按需检索。
---
### **策略 3 —— 压缩(Compress)** *(上下文会累积。留住含义,砍掉 token。)*

哪怕做了好的选择,上下文还是会累积。
每一次工具调用、检索来的文档、做出的决定,都留在窗口里。
设想你的智能体已经做了 20 次工具调用。
上下文:80,000 个 token 的累积工具输出、对话历史、推理痕迹。
其中大部分已经不再相关了。智能体早就基于它们采取过行动。
但它还在那里,占着空间、拖累注意力、推高成本和延迟。
**你可以在 3 个点上做压缩。**
**在信息进入上下文之前:**
→ 在检索之前,把大文档切成连贯的小块
→ 重排序(rerank),让只有最有用的块才进得来
→ 在工具输出进入主上下文之前,即时地把它们摘要掉
**在智能体工作的过程中:**
→ 对话历史的滚动摘要——持续更新
→ 流行的混合做法:保留最近 10 条消息的原文 + 把更早的全部摘要
→ 硬性裁剪:一旦上下文达到某个尺寸阈值,就移除较早的消息
→ Claude Code 的自动压紧:在 95% 容量处触发,自动摘要整条轨迹
**在智能体已经基于某样东西采取过行动之后:**
→ 工具结果清除:某个工具结果在 15 步之前用过了,就丢掉它
→ 用一行摘要替换,或者干脆移除
→ 智能体并不需要它 20 步之前抓取的某个网页的全文
目标是:减少 token 数量。保留真正要紧的东西。
---
### **策略 4 —— 隔离(Isolate)** *(最强大的策略。它让多智能体系统成为可能。)*

这里有一个关于长时间智能体运行的、更深层的问题。
它不只是空间问题,而是污染问题。
来自研究阶段的那些详尽的文件搜索,在智能体转去写代码时,仍然坐在上下文里。
那段陈旧的研究上下文,现在成了噪声。在一个本该专注于干净实现的阶段里,它正分散着模型的注意力。
**隔离意味着给工作的不同部分各自独立的上下文窗口。**
**子智能体(Sub-agents)**
一个父智能体把一个聚焦的子任务——「在代码库里搜索所有与认证相关的文件」——委派给一个子智能体。
子智能体在它自己干净的上下文窗口里工作。
当它回报时,只返回一份浓缩的摘要。
所有杂乱的搜索操作,都隔离在子智能体的上下文里,永远不会污染父智能体。
**状态 schema 隔离**(LangGraph 的做法)
把智能体的状态设计成:不同的字段存储不同类型的上下文。
LLM 只看到与当前这一步相关的那些字段。
工具结果坐在一个「后台」字段里——在被显式浮现出来之前,对模型不可见。
无需开出独立的子智能体,就能对智能体在每一步看到什么进行细粒度的控制。
正是隔离,让复杂的多步工作流真正变得可靠。
不同的活儿。不同的上下文窗口。没有污染。
---
### **智能体失败的 4 种方式** *(给失败命名。然后修好它。)*
Drew Breunig 辨认出了随着智能体上下文增长而出现的四种截然不同的失败模式。
你见过的每一个出故障的智能体,都落在其中之一里。

**失败 1:上下文投毒(Context Poisoning)**
一个幻觉或一个错误进入了上下文。
智能体在随后的步骤里一次又一次地引用它。
第 5 步的坏数据,会复利式地累积进之后的每一步。
**修法:** 在工具输出进入上下文之前先验证它们。从一个错误中恢复之后,把失败尝试的历史压缩掉。当只有最终解法才要紧时,别把 10 步死胡同里的调试过程留着可见。
━━━
**失败 2:上下文分心(Context Distraction)**
上下文变得太长,模型开始过度依赖近期的历史。
它不再综合出一个新颖的计划,而是只把自己最近做过的事重新炒一遍。
它停止了思考。它开始了重复。
**修法:** 积极地摘要和修剪。哪怕你手头有一个很大的上下文窗口可用。窗口大,不意味着就要把它填满。
━━━
**失败 3:上下文混淆(Context Confusion)**
多余的内容把模型引向低质量的决策。
经典例子:一个模型在给它 46 个工具时在某基准测试上失败——尽管上下文远在限度之内——但只给 19 个工具时却运行良好。
工具的数量,对上下文来说并不算多到装不下。
而是对模型来说,多到没法把它们想清楚。
**修法:** 动态工具管理。用 RAG-MCP 只把与当前这一步相关的工具浮现出来。让工具集与当前阶段相匹配。
━━━
**失败 4:上下文冲突(Context Clash)**
新信息与上下文里已有的某样东西相矛盾。
系统提示词说一套。一份检索来的文档说的是另一套。
智能体没法调和这个矛盾。于是产生前后不一致的行为。
**修法:** 确立一个清晰的权威排序。系统提示词 > 检索来的事实 > 对话历史。在注入新信息之前,拿它对照已有的上下文做验证。用 XML 标签和清晰的标题,让模型知道该信任哪个来源。
---
### **怎样为智能体写系统提示词** *(不是为聊天机器人。是为智能体。)*

聊天机器人的系统提示词定的是一种基调。
「你是一个乐于助人的助手。要简洁、友好。」
智能体的系统提示词定的是架构。
它规定控制流——怎么应对各种任务类型、什么时候用哪些工具、出错时怎么办、要遵守哪些护栏。
它更接近于给一名自主的员工写一份岗位说明书,而不是写一段人格提示词。
Anthropic 称之为在「正确的海拔高度」上写作。
**太过规定死:**「如果用户提到账单,并且提到退款,并且金额超过 100 美元,就调用工具 X。」脆弱。在每一个你没预料到的边界情形上都会崩。
**太过含糊:**「乐于助人,并使用恰当的工具。」这等于什么都没给智能体。没有具体的信号,它做不出好的自主决策。
**那个甜蜜点:**具体到足以引导自主行为。又灵活到足以让模型在新情形里运用判断。强有力的启发式经验法则。而不是僵硬的死规矩。
**实用建议:**
→ 用 XML 标签或 markdown 标题来组织——背景、指令、工具指引
→ 从最小开始,在失败中迭代——别想着一上来就预料到每一个边界情形
→ 最小不等于短——一个复杂智能体的系统提示词可以有好几千个 token,这没问题,只要每个 token 都对得起它占的位置
→ 用少样本(few-shot)示例——给智能体看看好的行为是什么样,而不是试图用文字描述每一条规则
---
### **KV 缓存:你该在意上下文顺序的那个「$$$」理由**

大多数搭建智能体的人都不知道这东西的存在。
当你把 token 发给一个 LLM 时,模型会为每个 token 计算键值(key-value)表示。
计算开销很大。
所以推理服务商会把这些表示缓存起来。
如果你上下文的开头——那个前缀——在多次 API 调用之间保持不变,服务商就会复用缓存下来的计算,只处理结尾处那些新的 token。
快。便宜。
但如果你在两次调用之间重排或改动了上下文的早期部分——你就让缓存失效了。服务商会从头把一切重新算一遍。
在 Claude Sonnet 上的成本差异:
→ 缓存命中的输入 token:**每百万 0.30 美元**
→ 未缓存的输入 token:**每百万 3.00 美元**
**10 倍的差异。**
对一个每个任务要做 30–40 次 API 调用的智能体来说,这积累得很快。
**KV 缓存效率的实用规则:**
→ 稳定的内容放在上下文的最**顶部**——系统提示词、工具定义,以及任何在轮次之间不变的东西
→ 动态的内容放在最**底部**——对话历史、当前步骤、智能体状态 → 不要在对话进行到一半时动态地增删工具——那会让缓存失效
→ 用**工具屏蔽(tool masking)**而不是工具移除——让所有工具定义在前缀里保持稳定(被缓存),只是把不相关的那些标记为在当前阶段不可用
---
### **那套在 7 小时里交付 35,000 行代码的工作流**

Dex Horthy(HumanLayer 的 CEO)在 AI Engineer Code Summit 上展示了这套方法。
据称,他的团队用它在一次 7 小时的会话里,向一个庞大的 Rust 代码库交付了大约 35,000 行代码。
方法是:**频繁的、刻意的压紧(Frequent Intentional Compaction)。**
把智能体的工作组织成一个个阶段。每个阶段产出一份压紧后的产物。每个新阶段都从一个全新的上下文窗口开始,里面只装着那份产物。
始终刻意地待在上下文窗口的 40%–60% 以下。
**阶段 1 —— 研究**
子智能体探索代码库。读文件。追踪数据流。绘制架构图。
所有杂乱的 grep 结果和文件内容都留在子智能体的上下文里。从不碰到父智能体。*(隔离)*
产出:一份紧凑的 research.md——文件路径、函数签名、模式、坑点。*(写入)*
上下文重置:原始研究用掉了窗口的 60–80%。研究产物把它压缩到了 15–20%。*(压缩)*
**阶段 2 —— 规划**
全新的上下文窗口。只包含:研究文档 + 问题定义。
智能体产出一份详尽的实现计划。
**这是最重要的一处人工审查检查点。**
在这里抓出逻辑错误,此时修正它们既容易又免费。到了后面,那要花上好几个小时。
**阶段 3 —— 实现**
又一个全新的上下文窗口。只包含:那份计划。
智能体一步一步地照着做。
对于复杂的任务:用一份 progress.md 追踪什么已经完成、什么还剩下。*(写入)*
结果:在每个阶段都是一个干净、专注的智能体。没有污染。没有上下文腐烂。没有「潦草的第 20 步」。
---
### **最优秀的平台是如何以不同方式处理这件事的**
**Claude Code**
混合检索。CLAUDE.md 在前面加载。glob 和 grep 这类工具负责对代码库做即时导航。
在 95% 处自动压紧——保留架构决策,以及最近访问的 5 个文件。
可以为复杂的子任务开出子智能体,每一个都有自己干净的上下文。
理念:「做能奏效的最简单的事。」让模型自己聪明地判断它需要什么,并给它工具去把那东西找到。
**Manus**
KV 缓存感知的上下文排序:稳定的前缀,动态的后缀。工具屏蔽,而非移除。
观测结果压缩流水线——每一份工具输出在进入智能体上下文之前都经过处理。
用一份持久的待办清单来追踪状态。
把文件系统当作被驱逐出去的上下文的溢出记忆。
为规模而生。服务着数十万用户,在那里效率是一个关乎经营成本的问题。
**ChatGPT Agent**
视觉优先的路子。智能体与一个 GUI 浏览器交互。
截图作为视觉快照被加进上下文。模型基于它所看到的进行推理。
视觉 token 很贵,所以智能体对截图数量很挑剔。
用强化学习(RL)在成千上万台虚拟机上学习最优的工具使用策略,而不是把它们显式地编程进去。
**Google ADK**
最讲原则的架构路子。
三条设计原则:
1. 把存储与呈现分开——持久的状态,和每次 API 调用里出现的东西,不是一回事
2. 显式的变换——具名的、有序的处理器,以可测试、可组合的步骤来变换上下文
3. 默认就给上下文划定范围——每一次模型调用都只看到所需的最少信息
工程纪律,重于提示词雕琢。
---
### **通用的智能体回合流水线**
每一个严肃的平台,在每个智能体回合里都收敛到同样的 5 步循环:
→ **收集(Collect)**——用户输入、对话历史、工具结果、检索来的文档、智能体状态
→ **选择(Select)**——在剩余的 token 预算之内,挑出对这一步相关的东西
→ **压缩(Compress)**——摘要、截断或重构,以塞进上下文 → **排列(Arrange)**——稳定的内容在前(缓存),动态的内容在后
→ **组装 + 调用(Assemble + call)**——最终的上下文 → API 调用 → 拿到输出 → 循环
这就是那个在你用过的每一个生产级智能体内部运行着的循环。
理解它,正是把那些交付出可靠智能体的搭建者,与那些纳闷自己的智能体为何在第 15 步变潦草的搭建者,区分开来的东西。
---
**总结**
上下文腐烂是真实存在的,而且远在你的上下文上限之前就开始了。
修好它的 4 个策略:
→ **写入**——把信息持久化到上下文之外,这样智能体就不会遗忘
→ **选择**——只拉进这一步所需要的东西
→ **压缩**——砍掉 token,留住含义,要主动而非被动
→ **隔离**——为不同的活儿用不同的上下文,互不污染
要提防的 4 种失败模式:
→ **投毒**——坏数据复利式地贯穿每一步
→ **分心**——冗长的历史让智能体只会炒冷饭而不思考
→ **混淆**——太多工具拉低决策质量
→ **冲突**——矛盾产生前后不一致的行为
KV 缓存值得你为之省下 10 倍的成本。把稳定的内容放在最前面。
最好的工作流:研究 → 压紧 → 规划 → 压紧 → 实现。在每个阶段都用全新的上下文。
对于严肃的智能体工作,上下文工程不是可选项。
它就是工作本身。
---
如果这篇对你有用:
→ 转发,把它分享给你认识的每一个搭建智能体的人
→ 关注 @sairahul1,获取更多在你睡觉时也照样运转的系统
→ 收藏这篇——你会回头来看那套 4 策略框架的
我写的是关于 AI、做产品,以及真正奏效的系统。