上下文工程(Context Engineering) 是什么?和 Prompt Engineering 有什么区别?
同一个模型、同一条 Prompt,只因为”每轮看见的信息”不同,Agent 表现可以判若两人。这篇教程讲清上下文工程的对象与失效机制、压缩截断与按需加载策略、长上下文的注意力稀释问题,以及它与 RAG、Prompt 工程的协同边界。
它解决什么问题
上下文窗口是模型唯一的”工作记忆”,也是一块严格受限的稀缺资源:系统指令、历史消息、工具结果、检索片段全部挤在同一个窗口里按 Token 计费。窗口不够时,任务信息进不来;窗口塞满时,关键约束被噪声淹没。这两种失败都表现为 Agent”突然变笨”。
一个直观的售后例子:用户说”上周买的耳机右耳没声音了”。上下文贫乏的 Agent 只会反问订单号和故障现象;而在调用模型前先把订单记录、保修状态、历史工单查好、挂好退换工具的 Agent,可以直接给出”3 月 25 日购买、仍在退换期、仓库有货,是否帮您发起换货”的结论。模型没变,变的是上下文供给。上下文工程要回答的问题就是:每一轮调用,窗口里该放什么、怎么组织、什么时候换出。
核心原理
一次 LLM 调用实际携带的上下文,通常由几类内容组成,各自的角色与易错点不同:
- 系统提示:角色、约束、输出格式,优先级最高,必须防止被截断或被用户输入覆盖。
- 历史消息:会话的短期记忆,随轮次单调膨胀,是窗口溢出的主要来源。
- 工具结果(Observation):外部世界的反馈,原文往往冗长,需要摘要并保留可回查引用(traceId、错误码、位置)。
- 检索片段:RAG 捞回的证据,质量取决于召回与排序,噪声片段会直接误导判断。
- 工具描述与 Schema:也占用窗口,挂载几十个相似工具本身就是一种污染。
与 Prompt 工程的分界可以这样记:Prompt 工程管”指令怎么写”,一次写成、相对静态;上下文工程管”每轮调用实际带入哪些信息”,随任务动态变化、逐轮组装。只优化 Prompt 不管上下文,Agent 跑几轮就可能丢失目标——指令写得再漂亮,证据没进窗口也是白搭。
深入机制
注意力稀释:能放进去,不等于能用好
Transformer 通过注意力机制在上下文中筛选与当前生成最相关的内容。上下文越长,候选内容越多,干扰项也越多,模型定位关键证据的难度随之上升。两个已被反复观察到的现象:Lost in the Middle——模型对窗口开头与结尾的内容更敏感,夹在中间的关键信息容易被”看漏”;Context Rot——随着输入变长、噪声增多,模型对关键证据的利用不再稳定,标称 100K 的窗口不代表能稳定用好 100K。因此重要约束应靠近首尾放置,关键证据要显眼、去重、带编号,而不是淹没在日志洪流里。
压缩与截断:窗口快满时的取舍
长任务消息持续追加,接近上限时必须腾挪空间,常见三件套:
- Compaction(压缩):把早期历史摘要成一段,保留架构决策、未解决问题、关键结论,丢弃冗余工具结果,再以摘要衔接后续轮次。难点在取舍粒度——留太多失去压缩意义,留太少丢失约束与版本号。
- 结构化笔记(Note-taking):让 Agent 把进度、已知问题、下一步计划写到外部文件(如 NOTES.md),上下文重置后再读回恢复状态,相当于把记忆外挂到文件系统。
- Sub-agent 隔离:检索、代码阅读等探索性任务交给独立上下文的子 Agent,主 Agent 只接收一两千 Token 的证据摘要,探索过程不占用主窗口。
按需加载:Just-in-Time 取代一次性塞入
预检索在调用前一次性把片段塞进窗口,适合 FAQ 这类信息需求稳定的任务;但 Agent 任务的信息需求随执行变化,更合理的方式是只保留轻量引用(文件路径、URL、查询句柄),需要时再通过工具取回内容——Anthropic 称之为渐进式披露(Progressive Disclosure)。代码 Agent 是典型场景:先看目录结构和文件名收窄范围,再用 grep、head 按需读取,而非把整个仓库倒进窗口。
与 RAG 的协同
RAG 可以看作上下文工程的一个子系统,负责”检索什么、结果怎么进窗口”。协同要点有三:检索片段进入窗口前去重、重排并标注来源,避免模型混淆用户输入与外部资料;追问型对话中按轮次增量加载新证据,而不是每轮重复全量检索;低分无结果时降级到关键词检索或让 Agent 向用户澄清缺口,而非硬答。
工程实践
把组装逻辑收敛到一个 Context Assembler,在每次调用前统一完成装配:
def assemble(task, session, budget): |
两个关键决策点:rank 决定谁先谁后(重要约束靠近首尾),fit_token_budget 决定谁保留原文、谁压成摘要、谁只留引用。配套的做法是:按模块划分 Token 预算并设优先级;记录每轮实际进入窗口的完整消息,出问题时对比前后两轮的 context diff——“突然偏题”类故障,这是最高效的定位手段。评估策略优劣时,除任务成功率外,还要看平均输入 Token 与 P95 延迟,避免准确率上升但成本失控。
对比与权衡
| 策略 | 上下文干净度 | 延迟与调用次数 | 适合任务 |
|---|---|---|---|
| 预检索全量注入 | 差,易混入噪声 | 低,一次到位 | FAQ、固定知识库问答 |
| Just-in-Time 按需加载 | 好,证据按需进入 | 高,工具调用增多 | 代码库分析、故障排查、开放研究 |
| 混合策略 | 较好,静态预载 + 动态拉取 | 中 | 复杂业务 Agent、长任务 |
| 长任务手段 | 适用场景 |
|---|---|
| Compaction | 需保持连贯对话的长流程 |
| 结构化笔记 | 有清晰里程碑的迭代式任务 |
| Sub-agent | 可并行探索、最终汇总的研究型任务 |
面试视角
上下文工程和 Prompt 工程的区别? Prompt 工程管指令的写法,相对静态;上下文工程管每轮调用实际带入窗口的信息选择与组织,是逐轮动态决策。后者还覆盖工具结果、记忆、检索片段与 Token 预算。
为什么窗口越大效果不一定越好? 注意力稀释:候选内容增多使关键证据更难被定位,Lost in the Middle 与 Context Rot 让中间与噪声区域的信息利用率下降。准确说法是退化程度取决于模型、上下文结构与任务类型,但”放进去”与”用好”是两回事。
上下文快满时有哪些手段,怎么选? 保持对话连贯用 Compaction 压缩历史;有里程碑的长任务用结构化笔记外挂状态;可拆分的探索任务用 Sub-agent 隔离上下文。三者常组合,短任务没出现膨胀时不必提前引入。
如何评估上下文策略的改动是否有效? 固定任务集,只改一个变量(如检索 top-k、摘要方式),对比成功率、平均输入 Token 和 P95 延迟;用 Trace 回放每轮窗口内容,对比 context diff 定位偏题来源。
上下文工程与 RAG 是什么关系? RAG 是上下文工程的子系统,解决证据的检索与注入;上下文工程还要管检索结果进窗口后的去重、排序、预算分配,以及历史、工具结果、记忆的整体装配。
小结
- 上下文窗口是稀缺资源,上下文工程的对象是”每轮调用带入什么、何时换出”,与 Prompt 工程动静互补。
- 窗口由系统提示、历史、工具结果、检索片段、工具描述共同占用,需按优先级分配 Token 预算。
- 长上下文存在注意力稀释(Lost in the Middle、Context Rot),重要约束放首尾,关键证据去重显眼。
- 压缩三件套——Compaction、结构化笔记、Sub-agent——分别对应连贯对话、里程碑任务、并行探索。
- 落地从 Context Assembler 与逐轮 Trace 开始:先能回放,再谈优化;高信噪比永远比信息量重要。

