Agent 上下文工程
概述
上下文工程(Context Engineering)是为 LLM 任务筛选最优 token 集合的学科。核心目标:在最小化 token 消耗的同时,最大化推理质量。
这不是简单的"给模型更多信息",而是精确控制模型在每个推理步骤中看到什么、看不到什么、以什么顺序看到。Token 方差可解释约 80% 的 Agent 性能差异——上下文质量是 Agent 成败的第一因素。
何时使用
- 设计或调试 Agent 系统
- 上下文窗口限制影响输出质量
- 优化 Agent 的成本和延迟
- 构建多 Agent 协调架构
- 实现跨会话记忆系统
- 排查 Agent 输出"退化"或"幻觉"问题
上下文的五大组成部分
Agent 的上下文窗口由五类信息构成,每类对推理质量的影响不同:
| 组成部分 | 说明 | 影响权重 | 可控性 |
|---|---|---|---|
| 系统提示(System Prompt) | Agent 的角色、规则、流程定义 | 最高 | 完全可控 |
| 工具定义(Tool Definitions) | 可用工具的名称、参数、描述 | 高 | 完全可控 |
| 检索文档(Retrieved Documents) | 通过 RAG 或搜索获取的外部知识 | 中-高 | 部分可控 |
| 消息历史(Message History) | 用户与 Agent 的对话记录 | 中 | 被动积累 |
| 工具输出(Tool Outputs) | 工具调用返回的结果数据 | 中 | 间接可控 |
关键洞察: 系统提示和工具定义位于注意力的"黄金位置"(开头),而消息历史和工具输出不断增长,容易稀释核心指令的影响力。
注意力预算约束
注意力的 n² 关系
Transformer 的自注意力机制计算复杂度为 O(n²),其中 n 是 token 数量。这意味着:
- 上下文翻倍,计算成本翻 4 倍
- 更多 token 不仅更贵,还会降低对每个 token 的关注度
- 存在一个有效注意力预算:超过阈值后,增加信息反而降低质量
注意力 U 形曲线
研究发现,模型对上下文中不同位置的信息关注度呈 U 形分布:
关注度
↑
高 █ █
█ █ █ █
█ █ █ █
█ █ █ █
█ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █
低 ─────────────────────────────────────────────→
开头 中间("Lost-in-Middle") 结尾
实用指导:
- 关键指令和约束放在系统提示的开头和结尾
- 中间位置放参考资料和背景信息
- 最重要的一条规则,同时放在开头和结尾(冗余强化)
渐进式披露原则
渐进式披露(Progressive Disclosure)是上下文工程的核心设计理念:
不要在启动时加载全部信息,而是在需要时才注入相关上下文。
三层披露策略
| 层级 | 加载时机 | 内容类型 | 示例 |
|---|---|---|---|
| L0 - 始终存在 | Agent 启动时 | 核心角色、基本规则 | 系统提示的角色声明和核心纪律 |
| L1 - 按需加载 | 识别到特定任务时 | 任务相关的详细指导 | 检测到用户要做 TDD 时加载完整 TDD 流程 |
| L2 - 工具获取 | 需要外部知识时 | 检索结果、文件内容 | 通过 Read 工具读取相关代码文件 |
实施方式
## 基础指导(L0 - 始终存在)
你是一位代码质量专家。永远遵循以下原则:[核心原则]
## 深入指导(L1 - 当用户请求代码评审时加载)
### 评审清单
[详细的评审维度和标准...]
## 参考资料(L2 - 按需通过工具获取)
使用 Read 工具查看目标文件内容
使用 Grep 工具搜索相关模式
上下文质量 vs 数量
核心原则:信息密度优于详尽性
质量公式:Context Quality = Signal / Total Tokens
目标:用最少的 token 传递最高密度的决策相关信息
实验数据
| 场景 | Token 数量 | 任务完成率 | 说明 |
|---|---|---|---|
| 精简高质量上下文 | 2,000 | 92% | 只包含决策必需的信息 |
| 完整但冗余的上下文 | 8,000 | 78% | 包含大量"可能有用"的背景 |
| 过载上下文 | 20,000 | 61% | 堆砌所有可获取的信息 |
结论: 4 倍的 token 量反而导致 14% 的质量下降。多即是少。
退化模式
上下文工程最重要的实践之一是理解和预防退化。以下是五种核心退化模式:
1. Lost-in-Middle(中部信息丢失)
症状: 放在上下文中间的关键信息被忽略。
机理: 注意力 U 形曲线导致中间位置的信息获得最少的注意力权重。
缓解策略:
- 关键信息放在开头或结尾
- 重要规则在不同位置重复(冗余强化)
- 使用醒目的格式标记(粗体、大写、分隔线)
2. 上下文中毒(Context Poisoning)
症状: 上下文中的一条错误信息导致整个推理链偏离。
机理: 模型对上下文中的信息默认信任。一条错误的工具输出或过时的文档可以覆盖(override)模型的正确知识。
反直觉发现: 研究表明,单个干扰项(distractor)的负面影响远大于预期——即使在 100 条正确信息中混入 1 条错误信息,也可能导致输出质量大幅下降。
缓解策略:
- 对工具输出和检索结果做质量过滤
- 在系统提示中加入"如果工具输出与已知事实矛盾,优先信任已知事实"
- 对关键决策要求模型交叉验证多个信息源
3. 上下文分心(Context Distraction)
症状: Agent 输出中包含大量与任务无关的内容,或在不重要的细节上花费过多推理。
机理: 上下文中的无关信息激活了模型的关联推理,导致注意力被分散。
缓解策略:
- 严格过滤注入上下文的信息,只保留与当前任务直接相关的内容
- 在系统提示中明确"忽略与当前任务无关的上下文信息"
- 使用工具隔离:不同任务使用不同的工具集
4. 上下文混淆(Context Confusion)
症状: Agent 将不同来源或不同时间点的信息混为一谈。
机理: 多轮对话中,早期的讨论内容与当前任务的上下文混合,模型无法区分时效性。
缓解策略:
- 消息历史中添加时间戳和任务边界标记
- 长对话定期做上下文摘要,清理过时信息
- 新任务开始时明确声明"以下是新任务的上下文"
5. 上下文冲突(Context Conflict)
症状: Agent 输出自相矛盾,或在不同轮次给出不一致的建议。
机理: 上下文中存在相互矛盾的指令或信息(如系统提示说"保持简洁",但 Few-Shot 示例展示了详细输出)。
缓解策略:
- 审核系统提示中的所有规则,确保无逻辑矛盾
- 为冲突情况定义优先级(如"当简洁性与完整性冲突时,优先完整性")
- Few-Shot 示例必须与文字规则保持一致
四桶策略
上下文优化的核心框架——将所有优化手段归类为四个"桶":
1. Write(写入)— 将上下文持久化到外部
将不需要实时保持在上下文窗口中的信息写入外部存储:
- 草稿本(Scratchpad):将中间推理结果写入文件,释放上下文空间
- 记忆文件:将跨会话需要保持的知识写入 MEMORY.md
- 任务清单:将待办事项写入 Todo,而非保留在对话中
2. Select(选择)— 精确拉取相关上下文
只在需要时拉取与当前任务相关的信息:
- 语义检索:基于向量相似度获取相关文档片段
- 规则过滤:基于任务类型确定需要读取的文件列表
- 工具调用:用 Grep/Glob 定向搜索,而非将整个代码库加载到上下文
3. Compress(压缩)— 降低 token 密度
在不损失关键信息的前提下减少 token 数量:
- 摘要替代原文:用 3 句话摘要替代 100 行的工具输出
- 结构化提取:从长文档中提取关键字段,而非注入全文
- 压缩目标:50-70% 缩减,< 5% 质量损失
4. Isolate(隔离)— 在子 Agent 间分配上下文
通过多 Agent 架构实现上下文隔离:
- 任务分区:每个子 Agent 只接收其任务所需的上下文
- 结果汇总:子 Agent 的完整上下文不回传,只回传结构化结果
- 防污染:一个子 Agent 的错误不会通过上下文传播到其他子 Agent
优化技术详解
压缩(Compression)
长对话压缩流程:
1. 标记对话中的关键决策节点
2. 对非关键部分生成摘要
3. 用 [摘要] 替换原始消息
4. 保留最近 N 轮完整对话
压缩比参考:
- 事实性对话:可压缩 70%,质量损失 < 3%
- 推理密集型对话:可压缩 40%,质量损失 < 5%
- 代码讨论:可压缩 50%,质量损失 < 8%(代码块不宜压缩)
观察遮蔽(Observation Masking)
对工具输出进行选择性遮蔽,只保留任务相关的部分:
原始工具输出(500 tokens):
{
"file": "src/api/users.ts",
"content": "[完整文件内容]",
"metadata": { "size": 2048, "created": "...", "permissions": "..." }
}
遮蔽后(80 tokens):
{
"file": "src/api/users.ts",
"relevant_section": "[只保留与当前任务相关的函数]"
}
KV 缓存优化
利用 LLM 的 Key-Value 缓存机制降低延迟和成本:
- 缓存命中目标:稳定工作负载下 70%+
- 策略:保持系统提示和工具定义不变(缓存友好),只在消息末尾追加新内容
- 反模式:每次请求都重新组织上下文的顺序(破坏缓存)
分区(Partitioning)
将上下文窗口按功能分区,明确每个区域的用途:
┌─────────────────────────────────────┐
│ 区域 A:核心指令(系统提示) │ ← 高优先级,始终缓存
├─────────────────────────────────────┤
│ 区域 B:工具定义 │ ← 高优先级,始终缓存
├─────────────────────────────────────┤
│ 区域 C:任务上下文(检索/历史) │ ← 中优先级,按需更新
├─────────────────────────────────────┤
│ 区域 D:当前轮次输入 │ ← 最新信息,注意力最高
└─────────────────────────────────────┘
反直觉发现
基于大量实验的关键发现,这些结论可能与直觉相悖:
1. 乱序优于有序
在某些检索增强场景中,将文档片段随机打乱顺序后注入上下文,效果反而优于按相关性排序。
可能的解释: 有序排列可能让模型过度依赖位置信息而非内容本身,打乱后模型被迫更仔细地阅读每个片段。
2. 单个干扰项的巨大影响
在包含 10 个相关文档的上下文中,加入 1 个不相关但看起来权威的文档,可导致任务准确率下降 15-25%。
实用指导: 宁可少给信息,也不要给可能错误的信息。检索质量比检索数量重要得多。
3. 重复强化有效
将同一条关键指令在提示中重复 2-3 次(分布在不同位置),可以显著提高遵循率。但超过 3 次后边际收益递减。
4. 格式即信号
使用 Markdown 标题、粗体、表格等格式化手段,不仅提升可读性,还能实质性地影响模型的注意力分配。格式良好的提示比纯文本提示的指令遵循率高 10-20%。
关键指标参考
| 指标 | 说明 | 目标值 |
|---|---|---|
| Token 利用率 | 实际使用 / 窗口上限 | 70% 警告,80% 优化 |
| 信噪比 | 决策相关 token / 总 token | > 60% |
| 缓存命中率 | KV 缓存复用比例 | > 70%(稳定负载) |
| 压缩质量 | 压缩前后任务完成率差异 | < 5% 下降 |
| 多 Agent 开销 | 多 Agent 总成本 / 单 Agent 基线 | < 15x |
总结
上下文工程的核心心智模型:
- 上下文是有限资源 — 像管理内存一样管理上下文窗口
- 质量胜过数量 — 2000 个高质量 token 优于 20000 个低质量 token
- 位置决定影响力 — 开头和结尾是黄金位置
- 隔离防止退化 — 子 Agent 架构是处理复杂任务的必经之路
- 先度量再优化 — 建立基准线,用数据指导优化方向
- 防御性设计 — 假设每条注入的信息都可能是错误的