Skip to content

Context Engineering:上下文工程

摘要: Context Engineering 是 Prompt Engineering 的自然演进——关注点从'说什么'转向'让模型知道什么,以及怎么知道'。本文从范式演进的驱动力出发,分析了单次 Prompt 在复杂任务中的局限性如何催生上下文工程的需求。核心围绕三大支柱展开:RAG(检索增强生成)通过外部知识库突破模型训练数据的时效边界;记忆系统(短期、长期与工作记忆)赋予模型跨轮次的状态感知能力;工具调用(Function Calling)使模型从信息处理者升级为行动执行者。同时讨论了上下文窗口容量管理、信息密度优化与多轮对话中的注意力衰减等工程挑战,为企业级 LLM 应用的上下文架构设计提供方法论参考。

1. 引言

如果把 Prompt Engineering 比作"学会与 LLM 对话的语法",那么 Context Engineering 就是"学会为 LLM 准备一个认知环境"。

Context Engineering 是 Prompt Engineering 的自然演进——从关注"说什么",到关注"让模型知道什么,以及怎么知道"

2. 从 Prompt Engineering 到 Context Engineering 的演进

让我们先理解为什么会出现这个演进:

Prompt Engineering 时代(2022-2023):
  关注点:如何写好一段 Prompt
  典型工作:调教措辞、设计 Few-shot 示例、尝试 CoT
  假设:模型的能力是固定的,Prompt 是唯一的杠杆

Context Engineering 时代(2024-至今):
  关注点:模型在做出决策时"看到了什么"
  典型工作:上下文组装、信息检索增强、动态上下文管理
  假设:模型的能力 = 模型权重 × 上下文质量,两个都可以优化

演进的核心原因

  1. 上下文窗口急剧扩大:从 GPT-3 的 2K token 到 Gemini 的 2M token,可塞入的信息量增长了 1000 倍。"放什么进去"变成了关键决策。
  2. RAG 模式的成熟:模型不再只靠训练时记住的知识,而是从外部动态获取信息。上下文变成了一个"动态拼装的认知界面"。
  3. Agent 工作流的兴起:Agent 在执行任务过程中不断积累信息(工具返回、中间结果、错误反馈),这些信息如何组织直接影响 Agent 的表现。

一个形象的比喻

Prompt Engineering  = 写一封邮件(措辞、语气、结构)
Context Engineering = 布置一间会议室(谁在场、桌上有什么资料、墙上贴了什么便签、
                      窗户透进什么光、会议前发生了什么)

3. 上下文组装策略

上下文组装解决的核心问题是:在一次推理请求中,应当选择哪些信息放入上下文窗口,以及如何合理安排它们的顺序?

3.1 典型的上下文组装结构

┌────────────────────────────────────────────────┐
│ 1. System Prompt          (~500 tokens)        │
│    角色 + 规则 + 格式要求                       │
├────────────────────────────────────────────────┤
│ 2. 持久化上下文            (~200 tokens)        │
│    用户偏好 / 历史关键事实 / 对话目的            │
├────────────────────────────────────────────────┤
│ 3. 检索到的参考信息        (~2000 tokens)       │
│    文档片段 / FAQ / 知识库条目                  │
├────────────────────────────────────────────────┤
│ 4. 工具调用历史            (~500 tokens)        │
│    之前调用了什么工具,返回了什么结果            │
├────────────────────────────────────────────────┤
│ 5. 对话历史                (~2000 tokens)       │
│    最近 N 轮对话                             │
├────────────────────────────────────────────────┤
│ 6. 用户当前输入            (~200 tokens)        │
│    最新一条消息                               │
└────────────────────────────────────────────────┘

3.2 组装原则

原则一:相关性优先于完整性

不是把所有能找到的信息都塞进去。上下文窗口就像桌面的工作区——东西放得越多,越难集中注意力。

错误做法:找到 20 个相关的文档片段,全部放进去
正确做法:只放最相关的 3-5 个,其他作为备选

原因:1) 过多的不相关信息会稀释关键信号
     2) "Lost in the Middle" 现象证明,中间位置的信息最容易被模型忽略
     3) 每多一个 token,推理延迟和成本都在增加

原则二:重要信息放在两端

研究表明,LLM 对上下文中位置信息的注意力不是均匀分布的:

上下文窗口中的注意力分布示意:

  注意力强度

     │  ████                                    ████
     │  ████                                    ████
     │  ████                                    ████
     │  ████                                    ████
     │  ████     ██                             ████
     │  ████     ██                      ██     ████
     │  ████     ██            ██        ██     ████
     │  ████ ██  ██   ██   ██ ██    ██  ██  ██ ████
     └──┴───┴───┴────┴────┴───┴─────┴───┴───┴──┴─────→ 位置
       开头         中间区域(注意力最低)          结尾

→ "Lost in the Middle": 中间位置的信息最容易被模型忽视
→ 把关键指令放在开头(System Prompt)或结尾(近期对话)
→ 参考资料放在开头(紧接 System Prompt 后),比放在中间效果更好

原则三:结构化优于自然语言

同样的信息,用结构化的方式呈现比用自然语言描述更容易被模型准确理解:

自然语言(差):
"我们的产品有三种订阅计划,基础版每月 29 元包含 100 次调用和基本支持,
 专业版每月 99 元包含 1000 次调用和优先支持还有自定义模型,
 企业版需要联系销售包含无限调用和专属支持..."

结构化(好):
| 计划   | 月费   | API 调用数 | 支持级别 | 自定义模型 |
|--------|--------|-----------|---------|-----------|
| 基础版 | ¥29   | 100       | 基本    | 无        |
| 专业版 | ¥99   | 1,000     | 优先    | 有        |
| 企业版 | 联系销售 | 无限     | 专属    | 有        |

4. 上下文压缩与缓存

4.1 上下文压缩

随着对话进行,上下文持续增长。如果不加处理,最终会超出窗口限制或导致推理成本爆炸。上下文压缩解决的就是这个问题。

策略一:滑动窗口(Sliding Window)

最简单的方式:只保留最近的 N 轮对话,丢弃更早的。

完整对话历史: [R1, R2, R3, ..., R45, R46, R47, R48, R49, R50]
滑动窗口 N=10:                              [R41 ... R50]  ← 只保留最近 10 轮

缺点:丢失了用户早期表达的重要偏好和上下文线索。

策略二:摘要压缩(Summarization)

用 LLM 对早期对话进行渐进式摘要:

持久化摘要(随时间更新):

阶段 1:  [R1-R5 原始对话]
阶段 2:  [摘要(R1-R5)] + [R6-R10 原始对话]
阶段 3:  [摘要(摘要(R1-R5) + R6-R10)] + [R11-R15 原始对话]
...

最终上下文:
┌──────────────────────────────────────┐
│ 对话摘要(2-3 句,覆盖全部历史关键信息) │
├──────────────────────────────────────┤
│ 最近 10 轮原始对话                    │
├──────────────────────────────────────┤
│ 用户当前输入                         │
└──────────────────────────────────────┘

策略三:关键词提取(Keyword Extraction)

从历史对话中提取关键实体和偏好,存入一个精简的记忆字典:

记忆字典:
{
  "user_name": "小明",
  "preferred_language": "中文",
  "expertise_level": "高级 Python 开发者",
  "current_project": "构建 RAG 系统",
  "key_decisions": ["使用 ChromaDB", "嵌入模型选 BGE-large"],
  "open_questions": ["如何处理多轮对话的上下文压缩"]
}

这种方式的内存开销极小(通常 100-300 tokens),适合长期跨会话记忆。

4.2 上下文缓存

对于多轮对话或批量请求场景,上下文中有一部分是不变的(如 System Prompt):

请求 1: [System Prompt] + [User Msg 1]
请求 2: [System Prompt] + [User Msg 2]  ← System Prompt 的 KV Cache 可以复用!
请求 3: [System Prompt] + [User Msg 3]

优化:
  首次请求 → 计算 System Prompt 的 KV Cache 并缓存
  后续请求 → 直接从缓存读取,跳过 Prefill 阶段中的 System Prompt 部分
  → TTFT 降低 30-50%(取决于 System Prompt 在总输入中的占比)

Anthropic 的 Prompt CachingGoogle Gemini 的 Context Caching 都提供了这一功能的 API 支持。开发者可以标记上下文中的哪些部分是可缓存的,API 会自动处理缓存命中和失效。

5. 动态上下文管理

最先进的 Context Engineering 实践是动态上下文管理不是一次性地静态组装上下文,而是让 Agent 在执行过程中根据当前需求主动"拉取"所需上下文。

5.1 按需检索(Lazy Retrieval)

静态 RAG(传统):
  用户提问 → 一次性检索所有相关文档 → 全部放入上下文 → 生成回答
  问题:可能检索了 15 个文档片段,但回答只需要其中 3 个

动态 RAG(按需):
  用户提问 → 初步检索 3 个文档 → 生成初步回答
    → 发现需要更多细节 → 根据中间推理结果二次检索
    → 补充 2 个针对性文档 → 完善回答
  优势:上下文更精准,不被无关信息稀释

5.2 上下文窗口的"信息预算"管理

把上下文窗口视为一种有限资源(信息预算),需要做预算分配:

128K 上下文窗口的预算分配示例:

  知识检索:  ████████████████░░░░░░  60K (高优先级)
  对话历史:  ██████████░░░░░░░░░░░░  40K
  Agent 状态: ████░░░░░░░░░░░░░░░░░░ 16K
  工具历史:   ██░░░░░░░░░░░░░░░░░░░░  8K
  预留空间:   ░░░░░░░░░░░░░░░░░░░░░░  4K (应对突发需求)
             └───────────────────────┘
                    128K 总额

当预算紧张时:
  1. 先压缩对话历史(摘要代替原文)
  2. 降低检索结果数(只保留 Top 3 而非 Top 10)
  3. 精简工具调用历史(只保留最后一次调用的关键结果)

5.3 上下文污染防控

动态上下文管理还需要考虑上下文污染问题——错误或误导性信息一旦进入上下文,可能在整个 Agent 执行链条中传播:

污染传播示例:

  错误的工具返回 → 进入上下文
    → 模型基于错误信息做推理 → 生成错误结论
    → 错误结论保留在上下文中 → 影响后续所有决策

防控手段:
  - 对进入上下文的外部信息标注来源和置信度
  - 定期让模型"反思"当前上下文中的假设是否仍然成立
  - 对关键决策点,要求模型引用上下文中的具体证据

6. 总结

Context Engineering 的核心洞察是 LLM 的输出质量不止取决于模型本身有多强,还取决于它在做决策时"看到的世界"是什么样子。精心管理的上下文,可以让一个中等模型产生超越更大模型的效果;而混乱的上下文,可以让最强模型也犯低级错误。