上下文工程导论:从 Prompt 到 Context Engineering 的范式跃迁 / Introduction to Context Engineering
第 1 章:上下文工程导论:从 Prompt 到 Context Engineering 的范式跃迁
Introduction to Context Engineering
一个客服机器人在生产环境的第 47 天出了问题:用户在第 23 轮对话中明确表达了"我对青霉素过敏,请推荐替代抗生素",但机器人在第 24 轮依旧推荐了阿莫西林。复盘日志显示,用户的过敏信息其实一直保存在会话历史里——它就在第 12 轮和第 19 轮出现过两次。问题不在 prompt 写得不够好,而在于这段关键信息被淹没在 8000 多个 token 的对话上下文中,模型根本没能稳定地"看见"它。
这不是孤立事件。把 2023 年到 2025 年的 LLM 应用案例汇总起来看,绝大多数生产事故——遗忘用户偏好、违背已声明的约束、跨工具状态丢失、引用错误的历史结论——都可以归因到同一个根因:模型没有拿到它真正需要的上下文,或者拿到了但无法有效利用。这正是 Context Engineering(上下文工程)作为独立工程范式登场的根本原因。
本章要回答三个层层递进的问题:第一,Prompt Engineering 究竟在哪个维度上"够用",又在哪个维度上"失灵"?第二,当我们把视角从"如何写好一句话的 prompt"提升到"如何管理整段运行时的状态"时,需要引入哪些新的概念骨架——Context Budget、Context Rot、Context Lifecycle?第三,这些骨架如何在真实项目中落地?我们会以一个客服对话系统的重构为案例,把抽象概念对应到具体的代码、指标和工程决策上。
---
1.1 范式跃迁:为什么 Prompt Engineering 不再足够
1.1.1 Prompt 的隐含假设
Prompt Engineering(提示工程)的成功,建立在一个被长期默认但很少被显式讨论的假设之上:每一次模型调用都是相对独立的单轮任务,调用方只关心"这一次我输入什么、模型输出什么"。在这个假设下,工程优化的对象被压缩为一段静态文本——系统提示 + 用户问题 + 少量示例。围绕它诞生的整套方法论,few-shot prompting、chain-of-thought、ReAct、self-consistency,本质上都是在优化"输入文本的质量"。
这套方法在三类场景里表现优异:第一类是单轮问答与文本改写,第二类是结构化生成(JSON 抽取、分类),第三类是推理增强(COT、Tree-of-Thought)。共同点是:上下文长度短、状态简单、一次调用即终态。当上下文只有几十到几百个 token、对话只有 1–3 轮时,精心雕琢的 prompt 是性价比最高的杠杆。
1.1.2 工业级 LLM 应用的真实形态
然而从 2024 年开始,企业级 LLM 应用的形态发生了质变。一个典型的生产系统不再是一次调用,而是一条多步骤、多角色、跨工具的调用链(call chain):
- **Multi-turn Conversation(多轮对话)**:会话可能持续几十到几百轮,单条 prompt 不可能容纳全部历史;
- **RAG(Retrieval-Augmented Generation)**:上下文由检索系统在运行时动态拼装;
- **Tool Use / Function Calling(工具调用)**:模型输出会触发外部动作,外部结果又会回流到上下文;
- **Agent Loop(智能体循环)**:模型在循环中持续观察、决策、行动,单轮 prompt 的边界消失;
- **Long-running State(长时状态)**:用户偏好、任务进度、累计事实需要跨会话持久化。
在这些形态下,模型看到的输入已经不再是"一句精心撰写的 prompt",而是一个运行时被多个子系统共同拼装出来的结构化状态包。Prompt 只是这个状态包中的一个组件,而且往往不是最重要的组件。
1.1.3 范式差异的三维对比
我们可以从三个维度刻画这次范式跃迁:
| 维度 Dimension | Prompt Engineering | Context Engineering | |---|---|---| | 优化对象 Optimization Target | 一段静态文本(the prompt text) | 一整套运行时状态(runtime state package) | | 关注焦点 Primary Concern | 让模型在这一次调用中给出好答案 | 让模型在整个会话生命周期中保持一致、可控、可观测 | | 工程方法 Engineering Method | 措辞调优、示例编排、推理结构设计 | 压缩、检索、记忆、状态管理、生命周期编排 |
一句话总结:Prompt Engineering 关心"怎么说",Context Engineering 关心"模型看见什么、什么时候看见、看见多少"。前者是写作问题,后者是系统问题。
---
1.2 什么是上下文:超越 Prompt 的运行时状态
1.2.1 上下文的工程定义
我们给出一个可操作的工程定义:
> Context(上下文) 是模型在一次推理调用中所能"看见"的全部输入信息及其结构化组织方式,它由系统、用户、工具和外部存储在运行时共同拼装而成。
这个定义有两个关键点需要展开:
第一,上下文是一个集合,而不是一段字符串。它至少包括:
- **System Instructions(系统指令)**:角色、约束、安全规则;
- **Conversation History(对话历史)**:所有 prior turns 的消息记录;
- **Retrieved Knowledge(检索知识)**:来自向量库、知识图谱、搜索引擎的外部证据;
- **Tool Observations(工具观察)**:Function Calling 之后外部世界的返回结果;
- **Working Memory(工作记忆)**:任务执行过程中的中间状态、计划、待办项;
- **User State(用户状态)**:偏好、历史行为、长期画像。
这些组件拥有不同的来源、不同的更新频率、不同的可信度。把它们当作一锅粥混在一起塞给模型,就是绝大多数上下文失效的起点。
第二,上下文是有结构的。现代 LLM 应用普遍使用结构化消息格式(OpenAI 的 `messages`、Anthropic 的 `system/user/assistant/tools`、Gemini 的 `parts`)。这种结构本身携带信息——哪条是系统级不可覆盖的约束、哪条是工具返回的不可信结果、哪条是用户当前的真实意图。Context Engineering 的一个核心职责,就是维护这种结构在拼装过程中的语义保真。
1.2.2 静态上下文 vs 动态上下文
在工程实践中,我们需要进一步区分两类上下文:
Static Context(静态上下文) 指在会话开始前就确定、整个会话生命周期内基本不变的输入。它包括系统提示、角色设定、长期用户偏好、领域基础知识。静态上下文适合预编译、缓存与版本化。
Dynamic Context(动态上下文) 指每次调用前都必须重新计算或检索的输入。它包括当前对话窗口、即时检索结果、工具最新返回值、任务当前进度。动态上下文的工程难点在于:它既要新鲜(fresh),又要精炼(relevant),还要经济(cheap)。
一个常见的设计误区是把动态上下文当成静态上下文来处理——把所有可能用到的信息一次性塞进系统提示,让模型自己"挑着用"。这种做法的成本是灾难性的:在 100K 上下文中塞满冗余信息,会同时拉高延迟、费用和 Context Rot 风险。
---
1.3 Context Budget:硬约束与软约束的双重经济学
1.3.1 硬约束的物理来源
任何 LLM 调用都受限于一个硬约束(Hard Constraint):模型上下文窗口(Context Window)。这是一个不可逾越的物理上限。但更隐蔽、也更致命的是第二个硬约束:注意力复杂度。
Transformer 自注意力机制的计算复杂度与序列长度 $n$ 的关系为:
$$O(n^2 \cdot d)$$
其中 $d$ 是注意力头的维度。这意味着上下文长度翻倍,计算量(以及显存占用、推理延迟)会增长为原来的四倍。即便你的模型支持 1M token 的窗口,把 1M token 真的塞进去,在生产环境几乎总是不可接受的。
1.3.2 Context Budget 的形式化
我们把 Context Budget(上下文预算) 定义为一个会话或调用链中可用于上下文的"有效 token 数",它受四类因素共同约束:
$$B_{\text{effective}} = \min\left(B_{\text{window}},\ \frac{B_{\text{latency}}}{t_{\text{per-token}}},\ B_{\text{cost}},\ B_{\text{quality}}\right)$$
其中:
- $B_{\text{window}}$:模型上下文窗口上限;
- $B_{\text{latency}}$:由 SLA 决定的延迟预算;
- $B_{\text{cost}}$:由单次调用成本上限决定的预算;
- $B_{\text{quality}}$:由 Context Rot 阈值决定的"质量预算"。
最后一项是软约束,但它在长上下文中常常最先触顶。
1.3.3 预算分配的工程实践
在工程上,Context Budget 需要像内存预算一样被显式管理。一个常见的分配框架:
| 组件 Component | 推荐占比 Suggested Share | 说明 | |---|---|---| | System Prompt | 5–10% | 稳定且可缓存 | | Recent Turns(最近 K 轮) | 15–25% | 短期对话记忆 | | Retrieved Evidence(检索证据) | 30–50% | RAG 核心 | | Tool Observations(工具结果) | 10–20% | 视任务而定 | | Working Memory(工作记忆) | 5–15% | Agent 任务进度 | | Reserved Buffer(保留缓冲) | 5–10% | 留给模型输出与意外 |
预算利用率指标(Context Utilization) 是衡量 Context Engineering 健康度的关键 KPI:
$$U = \frac{\sum_i \text{tokens}(c_i)}{B_{\text{effective}}}$$
当 $U < 0.4$ 时,往往意味着上下文未被充分利用(信息不足);当 $U > 0.85$ 时,意味着 Context Rot 风险显著上升。健康区间通常在 0.5–0.8 之间。
---
1.4 Context Rot 与 Lost-in-the-Middle:当长上下文不再是银弹
1.4.1 Lost-in-the-Middle 的实证发现
2023 年 Liu 等人在《Lost in the Middle》论文中给出了一个后来被反复验证的发现:当相关信息被放置在长上下文的中间位置时,LLM 检索和利用它的能力会显著下降,而放在开头或结尾时表现最好。这与人类的"首因效应—近因效应"惊人相似。
具体的实验设定是:给定一段包含若干段落的上下文,其中只有一段包含答案,让模型回答问题。改变答案段落的位置,测量准确率。结论是:U 形曲线——首尾高、中间低,且这个效应在 7B、13B、70B 模型上普遍存在。
1.4.2 Context Rot:更广义的现象
我们把 Context Rot(上下文腐烂) 作为一个更广义的概念:随着上下文中 token 总数的增长,模型对其中任意一段信息的忠实度、可追溯性和推理准确性都会系统性下降。这是一种统计意义上的退化,不是 bug,而是当前 Transformer 架构的内在属性。
Context Rot 的成因是多重的:
1. 注意力稀释(Attention Dilution):上下文越长,单个 token 平均获得的注意力权重越低; 2. 位置编码退化(Positional Encoding Degradation):RoPE、ALiBi 等位置编码在超长序列上的相对位置分辨率下降; 3. 干扰项密度(Distractor Density):无关 token 越多,模型越容易"分心"; 4. 推理链断裂(Chain-of-Reasoning Breakage):长上下文中插入的信息片段可能切断模型原本连贯的推理路径。
1.4.3 工程含义
Context Rot 告诉我们一个反直觉的结论:给模型更多上下文,未必是好事。在 Context Engineering 中,"少即是多"常常成立。这意味着工程上的默认选项应该是"按需提供最小可用上下文",而不是"塞满整个窗口"。
实际工程中对抗 Context Rot 的常用手段包括:
- **关键信息锚定(Anchor)**:把最重要的约束、事实、用户偏好放在上下文的开头和结尾;
- **结构化标注(Structural Markup)**:用 XML/Markdown 标签明确区分不同来源的信息,让模型能够基于结构做注意力分配;
- **相关性剪枝(Relevance Pruning)**:在注入前过滤掉低相关性内容,宁缺毋滥;
- **分而治之(Divide and Conquer)**:把一个长任务拆成多个短上下文调用,而不是一个大上下文。
---
1.5 上下文工程的四大支柱
上下文工程不是一项技术,而是一组协同工作的子能力。我们把它归纳为四大支柱:Compression(压缩)、Summarization(摘要)、Retrieval(检索)、State(状态管理)。
1.5.1 Compression:上下文压缩
Compression 关注如何在不丢失关键信息的前提下,用更少的 token 表示同样的内容。常见技术:
- **Token-level Compression(token 级压缩)**:去除冗余停用词、合并同义短语、规范化数值表达;
- **Embedding-level Compression(嵌入级压缩)**:用向量量化、稀疏化、子空间投影等方式压缩表征;
- **Prompt-level Compression(prompt 级压缩)**:用 LLMLingua、Selective Context 等工具做语义感知的剪枝。
LLMLingua 系列工作给出了一个有代表性的方法:通过一个小型 BERT 模型评估每个 token 的困惑度贡献,移除低贡献 token,可以在保留 80% 以上语义的情况下压缩 5–20 倍。
1.5.2 Summarization:分层摘要
Summarization 把累积的对话历史压缩为不同粒度的摘要,以支持"长期记忆 + 短期细节"的双层需求。一个常见的分层设计:
``` Layer 0: 最近 K 轮原文(verbatim) ~2K tokens Layer 1: 当前话题摘要(topic summary) ~500 tokens Layer 2: 会话级摘要(session summary) ~300 tokens Layer 3: 用户级长期记忆(user memory) ~200 tokens ```
每一层都是对下层的抽象,越往上信息越稳定、越个性化、越值得缓存。
1.5.3 Retrieval:检索增强
Retrieval 是动态上下文的主要来源。一个工业级 RAG 流水线包含:
1. Query Rewriting(查询改写):把多轮对话压缩为单轮检索查询; 2. Hybrid Search(混合检索):向量检索 + 关键词检索 + 结构化过滤; 3. Reranking(重排序):用 cross-encoder 对初检结果精排; 4. Contextual Compression(上下文压缩):只返回与查询相关的段落而非整篇文档; 5. Citation-Aware Slicing(引用感知切片):确保每个片段都携带可追溯的来源元数据。
1.5.4 State:状态管理
State 是被低估但最关键的一根支柱。它负责管理跨越多轮、多工具、多会话的持久化状态:
- **Session State(会话状态)**:当前任务进度、待办、临时决策;
- **User State(用户状态)**:偏好、长期事实、画像;
- **Tool State(工具状态)**:外部 API 调用结果、缓存、副作用追踪;
- **World State(世界状态)**:与外部世界的同步点(如数据库、文件系统)。
State 的工程难点在于:一致性(consistency)、可追溯性(traceability)、过期(expiration)。任何一个状态没有标注过期时间,都会成为日后 Context Rot 与事实幻觉的温床。
四大支柱不是替代关系,而是组合关系——一个成熟的 Context Engineering 系统会同时使用这四种能力,并根据任务类型动态调整它们的权重。
---
1.6 Context Lifecycle:上下文的生命周期模型
为了把以上概念串成可执行的工程流程,我们提出 Context Lifecycle(上下文生命周期) 模型。一次完整的上下文生命周期包含六个阶段:
```mermaid flowchart LR A[Acquire 获取] --> B[Filter 过滤] B --> C[Compress 压缩] C --> D[Assemble 装配] D --> E[Inject 注入] E --> F[Track 追踪] F --> G{Context Rot?} G -- 是 --> H[Re-Plan 重规划] H --> A G -- 否 --> A ```
1. Acquire(获取):从对话历史、用户档案、检索系统、工具返回值中采集候选信息。
2. Filter(过滤):基于相