上下文工程导论:当提示工程不够用了
第 1 章:上下文工程导论——当提示工程不够用了
为什么 2024 年发布的 GPT-4o 已经支持 128K 上下文窗口(context window),Claude 3.5 Sonnet 做到了 200K,Gemini 1.5 Pro 直接把上限推到 1M——可你公司的"智能客服"在第八轮对话之后依然开始胡说八道?为什么你精心写好的 500 字 System Prompt 加上 10 段对话历史喂给模型,它却答非所问,甚至连你 30 秒前刚告诉它的客户名字都忘了?
这些不是模型问题。这些是上下文问题(context problem)。
过去三年,"提示工程"(Prompt Engineering)这个词几乎统治了所有关于如何"用好大模型"的讨论。但 2024 年之后,越来越多一线工程师开始发现一个尴尬的事实:单轮提示写得再漂亮,也救不了一个会"失忆"、会"走神"、会"抓错重点"的多轮应用。提示工程解决的是"一句话怎么说"的问题,而真正难的是"一百句话怎么组织、怎么记住、怎么用对"。这正是上下文工程(Context Engineering)登场的理由。
本章是全书的第一站。我们不会立刻抛给你一堆术语和框架,而是先回答三个朴素的问题:
1. 提示工程到底是怎么"不够用"的? 2. 上下文到底由哪些东西组成? 3. 为什么"上下文窗口变大"不等于"上下文变好"?
回答完这三个问题之后,你会得到本书的第一个核心框架——上下文工程的四大设计原则:相关性(Relevance)、压缩性(Compressibility)、可观测性(Observability)、可恢复性(Recoverability)。最后,我们会用一个真实的对比实验,让你亲手看到"加一层上下文包装"能带来多大的差别。
读完之后,你应该能完成一件具体的事:为任意一个 AI 应用画出一张"上下文来源清单",并用四大原则对它做一次初评。
---
1.1 从提示工程到上下文工程:一次安静的范式跃迁
1.1.1 提示工程的辉煌与边界
把时间拨回 2022 年 11 月。ChatGPT 上线两个月,全世界的开发者都在做同一件事:研究"这句话怎么问,模型才答得好"。于是诞生了一整套后来被称为"提示工程"的技术——
- **零样本提示(Zero-shot Prompting)**:直接问"请把下面这段话翻译成法语"。
- **少样本提示(Few-shot Prompting)**:在问之前先给两三组"输入-输出"示例,让模型"模仿"风格。
- **思维链提示(Chain-of-Thought, CoT)**:在问题后面加一句"让我们一步一步思考"(Let's think step by step)。
- **ReAct**:让模型在"思考"和"调用工具"之间反复切换。
- **角色提示(Role Prompting)**:告诉模型"你是一位资深律师"。
到 2023 年中,这些技巧已经被写进了无数篇博客、几本电子书、若干门 Coursera 课程。提示工程几乎成了"会用大模型"的代名词。
但如果我们冷静下来回顾,会发现提示工程默认了一个隐含前提:每次调用模型,都是一次"独立的、从零开始的问答"。它优化的是"这一轮"的质量,不关心"上一轮说了什么"、"文档库里有什么"、"用户到底是谁"。
这个前提在以下三种场景里会迅速失效——
场景 A:多轮对话(Multi-turn Conversation) 用户第一轮说"我叫张伟,在北京做律师"。第二轮问"我下周要去上海出差,该带什么?" 模型本来应该回答"带身份证、注意天气"之类的常识问题。但当对话进行到第十五轮,模型可能已经把"张伟在北京做律师"这条信息推出窗口之外,回答变得像个陌生人。
场景 B:跨任务工作流(Cross-task Workflow) 一个 RAG(Retrieval-Augmented Generation,检索增强生成)客服系统,需要先调用知识库检索订单,再调用 CRM 查客户等级,再调用工具查物流——每一步的"输入"不仅包含用户的原始问题,还包含上一步工具返回的几千 token 结果。提示工程教的"一句好指令"在这里几乎没有着力点。
场景 C:长时段任务(Long-horizon Task) 让 AI 帮你"阅读一本 500 页的财报并写摘要",或者"分析一周的客服日志并给出改进建议"——这本质上是一个多步骤、多文件、可能跨越数小时的工程。提示词再长,也装不下整个任务的中间状态。
这三种场景有一个共同特征:问题的难度不在"怎么说",而在"给什么"。
1.1.2 上下文工程:换一个提问角度
"上下文工程"这个术语在 2024 年中开始被频繁讨论。Tobi Lütke(Shopify CEO)在 2024 年的一次演讲中说过一句话被广泛引用:"Context engineering is the delicate art and science of filling the context window with just the right information for the next step."(上下文工程是一门精细的艺术与科学——把恰到好处的信息装进上下文窗口,为下一步服务。)而 Andrej Karpathy 在 2025 年初的多次访谈中,则把上下文工程称作"最被低估的技能"(the most under-rated skill)。
那么,上下文工程和提示工程到底什么关系?
我的回答是:提示工程是上下文工程的一个子集。
- 提示工程关心的是"在已经确定的上下文里,这一轮的指令如何措辞"。
- 上下文工程关心的是"进入模型之前,整个输入窗口里应该放什么、不放什么、以什么顺序放、用什么格式组织"。
换句话说,提示工程是"遣词造句",上下文工程是"备菜上桌"。你当然可以遣词造句很精彩,但如果端上桌的菜本来就是错的、凉的、或者和客人点的菜无关,再精彩的措辞也救不回来。
下面这张表总结了二者的主要差异——
| 维度 | 提示工程(Prompt Engineering) | 上下文工程(Context Engineering) | |------|------------------------------|-----------------------------------| | 优化对象 | 单轮指令的措辞与结构 | 进入模型前整个上下文窗口的内容与组织 | | 典型技术 | 少样本、CoT、角色提示 | 信息筛选、压缩、分层、记忆、检索 | | 关心的时间尺度 | 一轮对话 | 整个会话、整个任务、甚至整个用户生命周期 | | 默认前提 | 模型是"无状态"的 | 模型是"有上下文依赖"的 | | 失败模式 | 答非所问、风格跑偏 | 失忆、走神、抓不住重点、用错信息 | | 典型使用者 | 写提示词的"词匠" | 设计 AI 系统的工程师与架构师 |
判断题:以下三种情况,哪些属于提示工程的范畴,哪些属于上下文工程的范畴?
1. 把"请帮我写一封请假邮件"改成"请帮我写一封请假邮件,语气要正式、不超过 150 字、包含病假说明"——提示工程。 2. 在模型回答之前,先从公司 HR 系统里查到这个员工过去三个月已经请过两次假,把这条信息塞进上下文——上下文工程。 3. 把对话历史里超过 20 轮的旧内容压缩成一段 200 字的摘要,腾出空间放新检索到的文档——上下文工程。
你会发现,真正的分水岭不在"写什么文字",而在"管理什么信息"。
1.1.3 为什么"上下文工程"在 2024 年才成为话题
一个合理的疑问是:既然 RAG、记忆管理这些技术 2023 年就存在,为什么"上下文工程"作为统一术语到 2024 年才被广泛接受?
三个原因——
第一,上下文窗口(Context Window)变长了,但"有效上下文"没有同步变长。 2023 年初,大多数主流模型的窗口是 4K–8K。2024 年底,已经有 1M 级别的模型上线。窗口变大暴露了一个尴尬的事实:模型并不能真正"用满"这个窗口。研究(Liu et al., 2023, "Lost in the Middle")发现,当关键信息被放在超长上下文的中间位置时,模型的召回率会显著下降——1.3. 节我们会详细讨论这个现象。
第二,Agentic Workflow(智能体工作流)成为主流。 2024 年是"AI Agent 元年"。当模型不再只是"答题",而是"规划—调用工具—观察结果—再规划"地循环,它面对的"上下文"就变成了一个动态变化的、由多源信息拼接而成的复杂结构。这远超"写好一句提示词"所能解决的范围。
第三,开发者意识到成本和延迟。 长上下文的推理成本是短上下文的几十倍。把 100K token 塞给模型,不仅贵,而且慢。如果能用 8K 的精挑细选的内容,达到 100K 灌入差不多的效果,那是真金白银的节省。
所以,上下文工程的崛起不是因为模型变弱了,而是因为应用变复杂了。
---
1.2 上下文的工程化定义:五源输入与一张全景图
1.2.1 一个朴素但有力的类比:厨房备菜
在我们进入正式定义之前,先用一个生活中的比喻来建立直觉——
想象你是一位厨师,明天中午要为 8 个人做一桌菜。在你拿起锅铲之前,你需要在厨房里做一系列备菜工作:
- **菜谱(System Prompt)**:客人是广东人,喜欢清淡,那你今天走粤菜路线,少放辣椒。这是"任务的总规则"。
- **昨天剩的半锅老火汤(Conversation History)**:昨天的客人说"汤有点咸",今天的你就会记得少放半勺盐。这是"过去的对话"。
- **冰箱里的食材(External Knowledge)**:你打开冰箱,看到有鸡、有豆腐、有西红柿——这些是你"可调用但默认不在场"的原材料。这就是 RAG 要检索的知识库。
- **刚切好的配菜(Tool Results)**:你让助手去市场买的香菜到了,这是"刚才工具调用得到的结果",是新鲜的。
- **客人的忌口清单(User State)**:客人 A 吃素,客人 B 过敏花生,这些是"用户长期状态"。
菜谱、老汤、食材、配菜、忌口清单——这就是上下文。你端给客人的每一道菜,都是从这五样东西里挑出来、组合、烹饪、上桌的。
提示工程只关心"菜谱怎么写"。上下文工程关心的是:每一道菜端出去之前,五样东西各自的版本、配比、顺序、新鲜度是什么。
1.2.2 上下文 = 系统提示 + 对话历史 + 外部知识 + 工具结果 + 用户状态
现在我们把这五样东西翻译成工程语言——
1. 系统提示(System Prompt / System Message) 模型在本次会话中扮演的"角色说明 + 总规则"。例如: > "你是一位耐心的银行客服,回答必须基于提供的政策文档,不确定时要明确说不知道。"
这一段通常在每次调用时位置固定(最前面),且往往具有最高优先级。
2. 对话历史(Conversation History) 用户与模型之间已经发生的多轮问答。它是"短期记忆"。但要注意:对话历史不会自动全保留——超出窗口的部分会被截断,或者被压缩、摘要。
3. 外部知识(External Knowledge / Retrieved Context) 从知识库、向量数据库(Vector Database)、搜索引擎、文档库中按需检索得到的内容。它的特点是"按相关性取用",不是"全量灌入"。
4. 工具结果(Tool Results / Function Outputs) 模型调用外部工具后返回的数据,比如查到的订单详情、执行的 SQL 结果、调用的 API 响应。这部分内容往往格式高度结构化、体积可能很大,需要特别处理。
5. 用户状态(User State / User Profile) 跨越多个会话、甚至跨越整个产品生命周期的用户信息。例如:用户的语言偏好、历史购买记录、会员等级、长期目标。这部分通常来自数据库,而不是用户当前说的话。
把这五个来源合在一起,就是本书采用的上下文的工程化定义:
> 上下文(Context)= 系统提示(System Prompt)+ 对话历史(Conversation History)+ 外部知识(External Knowledge)+ 工具结果(Tool Results)+ 用户状态(User State)
它既不是"提示词"那么简单,也不是"提示词 + 历史"那么直白。它是一个五源异构、动态变化、有强优先级结构的输入集合。
1.2.3 全景图:上下文工程的心智模型
让我们用一张图把上面这五源与下游处理模块的关系画出来——
```mermaid flowchart TD A[系统提示<br/>System Prompt] --> X[上下文组装器<br/>Context Assembler] B[对话历史<br/>Conversation History] --> X C[外部知识 RAG<br/>Retrieved Docs] --> X D[工具结果<br/>Tool Results] --> X E[用户状态<br/>User Profile] --> X X --> F[压缩 / 摘要<br/>Compression] F --> G[LLM 调用<br/>Model Inference] G --> H[用户可见回复<br/>Visible Reply] G --> I[可观测日志<br/>Observability Logs] H --> B I --> J[反馈与再训练<br/>Feedback Loop] ```
这张图请你在脑子里默背一遍。它不是某一本书的专利图,而是几乎所有现代 LLM 应用都遵循的"骨架"——无论你是在做一个客服机器人、一个代码助手、还是一个多智能体协作系统,输入都从这五源流进,经过组装、压缩、推理,再产出回复与日志。
几个值得注意的点:
- **"上下文组装器(Context Assembler)"是上下文工程的核心战场**。它决定哪些信息进、哪些信息出、以什么顺序进。
- **压缩(Compression)几乎不可避免**。一旦总 token 数超过窗口,就必须做摘要、裁剪或者重新排序。
- **可观测日志(Observability Logs)**:每次推理不仅要产出回复,还要记录"喂了什么、怎么喂的、模型关注了什么"——这是后续调优的依据。
- **反馈闭环(Feedback Loop)**:用户对回复的评价(点赞、点踩、改写)最终应该回流到上下文组装策略里。
接下来的章节,我们会反复回到这张图。它是我们的"总地图"。
1.2.4 一个反直觉的判断:上下文不是越多越好
第一次接触上下文工程的人,常常会陷入一个误区:"窗口变大了,那就尽量多塞点东西进去,反正模型看得完。"
这个直觉是错的。三个理由——
1. 成本与延迟:长上下文的推理成本近似线性甚至超线性增长。把 100K token 喂给模型,可能比 10K 慢 20 倍、贵 30 倍,效果却未必好 10 倍。 2. 注意力稀释(Attention Dilution):Transformer 的注意力机制(attention mechanism)在面对超长输入时,会出现"看起来都看了一遍,但其实没真注意关键信息"的现象。这在 1.3 节会展开。 3. 噪音放大(Noise Amplification):无关信息越多,模型越容易被无关信息误导。例如在 RAG 里,如果检索到的 10 个文档里有 2 个与问题无关,这 2 个无关文档就可能把答案带偏。
所以,上下文工程的第一性原理不是"装满",而是"刚好"。
---
1.3 上下文是新瓶颈:声明上下文 vs. 有效上下文
1.3.1 Transformer 的"有效上下文"难题
我们已经知道,2024 年的旗舰模型动辄支持 128K、200K、乃至 1M token 的上下文窗口。但请注意一个细节:窗口大小(Context Window Size)≠ 模型能有效利用的上下文长度(Effective Context Length)。
为了理解这个差距,我们需要简要回顾 Transformer 的工作原理——
Transformer 的核心是自注意力机制(Self-Attention Mechanism)。对于输入序列中的每一个 token,它都会和序列中的所有其他 token 计算一个"注意力分数",来决定"我在生成下一个 token 时应该多看谁一眼"。
数学上,对于长度为 $L$ 的序列,自注意力的计算复杂度是 $O(L^2)$。也就是说,序列长度翻一倍,计算量翻四倍。这是为什么"长上下文"对硬件和推理成本都是巨大的挑战。
但比成本更麻烦的是另一个问题:注意力的有效范围(Effective Attention Span)。
研究发现(Xiao et al., 2024; Press et al., 2022),虽然理论上每个 token 都能和任意距离的 token 建立注意力连接,但实际训练和推理中,模型对"远处"信息的注意力强度会显著衰减。这种现象被非正式地称为 "Lost in the Middle"——关键信息放在中间位置,比放在开头或结尾,更容易被模型"忽略"。
1.3.2 Lost-in-the-Middle:一个值得记住的研究
2023 年,Liu 等人在论文 *"Lost in the Middle: How Language Models Use Long Contexts"* 中做了一个简洁而有力的实验——
他们准备了一组问题,每个问题都附带一段很长的文档,文档里包含了回答问题所需的关键事实。然后他们改变关键事实在文档中的位置:在开头、在中间、在结尾,观察模型的回答准确率。
结果令人警醒——
- 当关键信息在**开头**或**结尾**时,模型表现良好,准确率较高。
- 当关键信息在**中间**时,准确率显著下降,部分任务甚至跌到接近"瞎猜"的水平。
- 这个问题**不是某一个模型的特例**,而是 GPT-3.5、Claude、LLaMA 等多个模型普遍存在的现象。
这个研究的工程含义是巨大的:你以为模型"读完了整篇文档",但它可能只认真读了开头和结尾。