AI也有健忘症:为什么要聊上下文工程?
第一章:AI也有健忘症——为什么要聊上下文工程?
那个让 GPT-4 "忘了题目"的夜晚
2023 年的某个深夜,我的朋友老王(一位计算机系博士)正在赶一篇 deadline 是第二天上午 10 点的会议论文。他决定"机智地"用 GPT-4 来协助撰写,于是兴冲冲地打开 ChatGPT,在对话框里输入了一段长达 800 字、包含 5 个具体子要求的 prompt:
> 请你帮我撰写一篇关于「联邦学习在医疗影像隐私保护中的应用」的会议论文初稿,要求:① 包含 300 字摘要(中英文);② 列出 3 个相关工作对比;③ 给出基于 FedAvg 改进的算法伪代码;④ 包含一段实验设置的描述;⑤ 最后给出 5 句话的结论与未来工作。
接下来的 40 分钟里,老王和 GPT-4 进行了一场看似流畅的对话——AI 礼貌地回应了每一轮,输出了摘要、生成了对比表格、还真的写了一段伪代码。但当他把第五个子要求的结果收齐,准备通读一遍时,他愣住了。
结论部分写的是:「本文提出了基于差分隐私的联邦学习框架」——但老王的需求里从头到尾根本没有提到差分隐私。
更糟糕的是,对比三个相关工作那一节,AI 给出的两篇论文都来自 2019 年,而那篇和 FedAvg 算法最近密切相关的 2022 年顶会论文,连名字都没出现——它就是"忘记"了。
此时老王看了一眼自己左下角的对话历史,长度显示:对话已经进行了 12 轮,累计 6,400 tokens。他突然意识到发生了什么——GPT-4 那扇号称"32K 上下文窗口"的玻璃窗,不知道在第几轮悄悄合上了一点;而他写在最开头那段 800 字的精细 prompt,已经有一半被推到了窗外。
这就是上下文遗忘(context loss)最经典的、最日常的、最让人崩溃的样子。
它不是 AI "智力不够",不是 "提示词写得不好",也不是 "模型变笨了"——它是工程问题。而这本书要解决的,就是这一类工程问题。
我们把这门研究"如何让 AI 在对话中不丢三落四"的学问,叫做 Context Engineering(上下文工程)。
在接下来的 15 章里,我们将一起:
- 弄懂 AI 的"记忆"到底是怎么回事;
- 拆解五大主流解决方案——长上下文(Long Context)、压缩(Compression)、摘要(Summarization)、检索增强(RAG)、状态管理(State Management);
- 看懂为什么同样的需求,"上下文工程做得好"和"做得差"的 AI 表现会差出一个量级;
- 最终掌握一套可以迁移到任何 LLM 应用中的工程思维。
而现在,让我们先从一个最基本、却最容易被误解的问题聊起——人类和 AI,"遗忘"的方式有什么本质不同?
---
人类的遗忘 vs AI 的截断:两种 "忘记" 的本质差异
你以为你在同一件事
"AI 怎么又忘了?"——这是过去两年我听到的最频繁的抱怨之一。
但每次我想认真解释这个问题,发现第一步就卡住了:因为大多数人的大脑里,"AI 遗忘"和"人类遗忘"是被当成同一件事来理解的。
事实上,它们根本不是一回事。
人类会忘记,是因为我们的大脑有一套主动的、有目的的遗忘机制——海马体(hippocampus)会在睡眠时重播当天的经历,决定哪些值得保留进长期记忆,哪些扔进回收站。这套机制让我们不会因为 10 岁生日派对的细节而阻塞工作记忆。
而 AI 会"忘记",是因为它的硬件资源有限——具体来说,是上下文窗口(context window)这个滑窗是有上限的。当新文本进来,老的就会被无情地挤掉。这是一种被动的、物理性的截断(truncation)。
也就是说:
> 人类遗忘 = 选择;AI 遗忘 = 截止。
下面这张图希望能帮你建立直觉:
```mermaid flowchart LR subgraph Human["人类记忆系统"] H1["感觉记忆<br/>Sensory Memory<br/>(几毫秒~几秒)"] H2["短期记忆<br/>Working Memory<br/>(15~30秒, 7±2项)"] H3["长期记忆<br/>Long-term Memory<br/>(几乎无限, 但需检索)"] H1 --> H2 H2 --> H3 H4["遗忘曲线<br/>Ebbinghaus Forgetting Curve<br/>主动衰减"] H4 -.控制.-> H2 H5["睡眠巩固<br/>Sleep Consolidation"] H5 -.强化.-> H3 end
subgraph AI["AI 上下文窗口"] A1["输入 Token 流<br/>Token Stream"] A2["上下文窗口<br/>Context Window<br/>(固定大小, e.g. 128K tokens)"] A3["输出 Token<br/>Response"] A4["被截断<br/>Truncated<br/>(物理丢弃)"] A1 --> A2 A2 --> A3 A2 --> A4 A2 -.一旦超出.-> A4 end ```
(图:左边是人类记忆的三级模型——感觉记忆、短期记忆、长期记忆;右边是 AI 的上下文窗口——所有输入挤进一个固定容量的"水箱",溢出部分直接被丢弃。)
三层记忆 vs 单层滑窗
第一层:感觉记忆(Sensory Memory)
人类视觉、听觉、触觉等感官信号会在脑中短暂停留——大概几百毫秒到几秒。这部分信息绝大部分会被丢弃,只有一小部分"被注意到"的进入下一层。
AI 没有这一层。但有一个类比物——System Prompt 里的环境设定(比如 "你是一个有用的助手" 这种永远在线的 instruction),它通常会被放在对话的最前面,作为一个"始终可见的常量"。
第二层:短期记忆 / 工作记忆(Working Memory)
这是人类大脑当下"正在想"的内容。容量极其有限——经典的"7 加减 2"理论认为,我们一次只能在工作记忆里同时处理约 5 到 9 个信息项。而且这段记忆会主动衰减(这就是为什么你刚查到的一个电话号码,几分钟后就忘了)。
AI 的"短期记忆"就是上下文窗口。但它与人类工作记忆有一个关键区别:AI 不会自动衰减——只要 token 不被挤出去,它对所有历史信息的"重视程度"理论上是一样的(虽然在注意力分布上仍会有侧重)。但有一个致命弱点——它有上限。
老的对话只要还在窗口里,理论上 AI 就能看到;但是窗口装不下了,AI 自己也不会主动告诉你——它会"假装"还在继续回答。
第三层:长期记忆(Long-term Memory)
人类拥有可以存储几年、甚至几十年记忆的长期记忆系统。它的容量几乎无限——但有个前提:信息要被检索(retrieved)出来才能用。如果你想不起高中同桌的名字,那段记忆就是"未被激活",而不是"丢失了"。
AI 在通用模型层面没有长期记忆——所有知识都在训练时被"烧"进了参数(这就是所谓 parametric memory)。但一旦部署到一个应用里(比如 ChatGPT 的 Memory 功能、Notion AI、或者你自己写的 Agent),它可以通过外挂存储(向量数据库、外部文件)来模拟长期记忆——这就是我们后面要详细讲的检索增强生成(Retrieval-Augmented Generation, RAG)。
主动遗忘 vs 被动截断
让我们用一个具体例子来体会这个差异:
假设你告诉一个朋友:"明天是我妈妈的生日",然后聊了 5 分钟后问:"我妈的生日是几号?"
- **人类朋友**的常见反应:「等等……你刚才是不是说过?嗯……我想想……」他需要从短期记忆中检索,而且很可能检索失败,需要你提醒。
这里发生的是主动遗忘——信息衰退了、被覆盖了、或者单纯就是没被编码进长期记忆。
- **ChatGPT** 的常见反应:会立刻准确回答"明天"。
只要这句话还在上下文窗口里,模型就是"知道"的。它不会主动遗忘——除非你继续聊了 8,000 字,把这段对话挤出了窗外。
但如果那 8,001 个字中真的有这一句,AI 会出现一种诡异情况:它会非常自信地乱回答。它不会说"我忘了",而是用流畅的语言编造一个看起来很像那么回事的答案——因为你看到的是一个永远自信的语言模型。
这就是 AI 和人类遗忘最大的差别之一:
> 人类会知道自己忘了;AI 通常不知道自己"看不见"。
这是这本书要反复强调的一个核心洞察:AI 没有"遗忘感",它的截断对用户和对自己都是不可见的——这就是为什么"上下文工程"这么重要。
一个简短的认知偏差测试
做个小实验:现在闭上眼睛 5 秒钟,在心里默念 "banana, umbrella, 42, blue, piano",然后过 30 秒告诉我这五个词是什么?
如果你是正常人类,大概率会丢一两个。这就是主动遗忘在工作。
但如果我把这五个词写进一个 prompt 发给 GPT-4,然后你追问"我说过哪些词"——AI 会一字不差地复述出来(只要 prompt 还在窗口内)。
这就是工程差异。你不需要写更好的 prompt 来 "让 AI 更聪明",你需要的是一套机制,能让关键信息在对话的任意时刻都"还在 AI 能看到的地方"。
这就是我们整本书要做的事。
---
上下文的定义:AI 眼中世界的"全部可见范围"
一个看似简单的词
"上下文"这个词,是这本书里出现频率最高的概念,没有之一。但讽刺的是,它的定义恰恰是最容易被搞混的。
很多人随口会说:"上下文就是 prompt"——这是错的。也有人说:"上下文就是历史消息"——这也是错的。还有人说:"上下文就是 system message 加上 user message"——接近了,但还是不完整。
让我用一个更精确的方式来讲:
> Context(上下文)= 在某一个生成时刻,模型在计算下一个 token 时,所能"看到"的全部文本输入。
这个定义里有三个关键词:
1. "某一个生成时刻" —— 上下文是动态的,不是静态的。每生成一个新的 token,整个上下文都重新被计算一遍。 2. "能看到" —— 这是技术上的"可见性(visibility)",而不是"逻辑上能用到"。哪怕一句话在 prompt 里,但被位置编码过滤、被注意力屏蔽了,等于"看不见"。 3. "全部文本输入" —— 包括系统提示、用户消息、助手历史回复、外挂检索回来的文档、工具调用结果,甚至——这是很多人忽略的——模型自己刚刚生成的内容。
一次解构:ChatGPT 里到底有什么"上下文"?
我们以你打开 ChatGPT 网页版,开启一个全新的对话为例。在你按下回车键的那一刻,模型看到的"上下文"实际上是这样一个拼接起来的超长字符串(顺序不固定,但大致如此):
```python context_string = """ <|system|> You are ChatGPT, a large language model trained by OpenAI. Follow the user's instructions carefully. Respond helpfully... [系统提示·约几百 tokens]
<|system|> [用户自定义的 Custom Instructions, 约几百 tokens]
<|user|> [历史对话中的第 1 轮 user 消息]
<|assistant|> [历史对话中的第 1 轮 assistant 回复]
<|user|> [历史对话中的第 2 轮 user 消息]
<|assistant|> [历史对话中的第 2 轮 assistant 回复]
... [一直堆到对话的最新位置]
<|user|> [用户刚刚发送的当前消息] """ ```
注意几点:
- **顺序(position)是有讲究的**——几乎所有 LLM 都对"靠近当前"的内容更敏感。放在对话最前的内容,会随着对话变长逐步"被加权降低关注"。
- **每一段都不能凭空消失**——但也有"软移除"的机制,比如 Anthropic 的 Claude 有一个 prompt caching 机制,而 OpenAI 在 GPT-4 Turbo 引入了"自动摘要超过 50% 容量的旧消息"功能。
- **总长度不能超**——一旦超过模型的最大上下文长度,要么报错、要么被静默截断。
一个隐喻:水箱、聚光灯,还是剧场?
关于"上下文"是什么,业内有三种常见的隐喻。我个人最喜欢第三种,但你都该了解:
隐喻 1:上下文是一个 "水箱"(Container)
最早的隐喻,把上下文想成一个大水箱。你的所有输入就是水,水满了就溢出。这种隐喻强调"容量(capacity)"——能装多少 token 就是多大容量。今天大部分 LLM 厂商在他们的技术博客里用的就是这种隐喻。
隐喻 2:上下文是一束 "聚光灯"(Attention Spotlight)
随着 Transformer 架构被理解,人们意识到——模型并不是平等地"看"上下文里的所有内容,而是通过 attention mechanism(注意力机制) 决定给每个 token 多少"光"。聚光灯虽然照亮了整个房间,但每个字的亮度是不同的。
这种隐喻解释了为什么"重要的内容要放后面、或者用 Markdown 标题强调"——这是在借助 prompt 的"视觉化锚点"来抓住注意力。
隐喻 3:上下文是一场 "独幕剧"(One-Act Play)
我个人最喜欢的隐喻。把一次 LLM 调用想成一次剧场演出:
- **System Prompt** = 导演写在剧本书脊上的"舞台设定"(时代背景、角色身份、风格基调)
- **User Message** = 编剧写的新一幕剧本
- **Assistant Response** = 演员正在即兴表演
- **Tool/Function Call** = 演员跑下台去道具间拿东西(外部世界的数据流入)
- **Context Window** = 舞台的物理大小——超出舞台的部分,无论戏多好,观众(模型)都看不见
这种隐喻的好处是,它把"上下文"从一个干巴巴的技术概念,变成了一个有戏剧张力的空间——而你作为"上下文工程师"(是的,这就是这本书的主题),就是那个导演。
你的工作不是去"纠正 AI 的输出",而是"布置舞台"——让模型在它能看见的空间里,正好有它需要的所有道具和剧本。
上下文的"边界效应"
一个值得记住的工程经验:
> 靠近上下文末尾的信息,对模型输出的影响最大;上下文开头和中间的内容,往往会被"边缘化"。
这个现象叫做positional bias(位置偏差)或者更口语化的"lost in the middle"——也就是说,AI 一旦上下文变得很长,它对中间段落的"理解精度"会显著下降。
研究数据来自 Liu 等人 2023 年发表在 arXiv 上的论文 *"Lost in the Middle: How Language Models Use Long Contexts"*。他们做了一个简单但有力实验:
把一篇文档的关键信息(答案)藏在 4 种不同位置:
- 最开头
- 文档 25% 处
- 文档 50% 处(正中间)
- 文档 75% 处
- 最末尾
然后让模型找答案。结果发现:
- **末尾位置的精度**:通常 80%-95%
- **开头位置的精度**:通常 60%-85%
- **中间位置(约 50%)的精度**:可能骤降到 40%-60%
不同模型表现不一样,但 U 型曲线几乎是普遍的——AI 对开头和结尾记得清楚,对中间一片模糊。
这意味着什么?意味着你不能简单地把所有信息"丢"进 prompt 就完事——你需要 有策略地安排信息位置。
这就是为什么"上下文工程"不等同于"提示词工程(prompt engineering)"——后者关心的是"怎么写一句话让模型做某件事",而前者关心的是"在一个有限、动态、有位置偏差的空间里,怎么组织信息让模型持续做对事"。
---
为什么 ChatGPT 会"答非所问"?三个真实翻车场景
理论听够了,下面我们来看几个真实的(经过匿名处理但骨架保真)翻车案例。它们代表了我在工作中、和朋友交流中、以及阅读大量公开 issue 时,总结出来的三大典型症状。
翻车案例 1:长会议纪要总结
场景:某产品经理小张把一段 90 分钟的客户访谈录音转写稿(22,000 字)贴进 ChatGPT,让它生成会议纪要。
Prompt:"请基于以上访谈内容,生成一份结构化的会议纪要,包含:参会人员、主要讨论议题、各方观点、行动项 (Action Items)。"
AI 输出:一份看似很专业的纪要,结构整齐。但仔细看——里面有两个参会人员的发言被张冠李戴。访谈中 A 客户强烈反对的某功能,在纪要里变成了"参会人员一致认可"。
为什么会翻车?
问题出在 "Lost in the Middle" 上。当输入长达 22K 字、超过 16K token 时,最关键的那段话(参会人员 B 在 30 分钟处对核心功能的尖锐反对)恰恰落在了模型的"中场盲区"——模型对它看得不够清楚,于是开始"自由发挥"。
> 症状诊断:上下文中间部分的信息丢失(Context Truncation in the Middle)
翻车案例 2:长对话中插入早期指令
场景:某开发者小陈在调试一个复杂的 Agent。他和 GPT-4 已经对话了 18 轮,每轮都很长。任务目标是:「用 Python 写一个能在 PostgreSQL 上查询近 30 天活跃用户的 SQL,并封装成 FastAPI 接口。」
在第 12 轮时,他让 AI 加了一个小需求:"记得加上日志记录中间步骤。"
到第 18 轮,AI 输出的最终代码确实有日志,但**对原始需求 "PostgreSQL + Fas