第 09 · 上下文 · 8 min
模型记住了什么
上下文窗口:完美但有界的记忆。为什么ChatGPT会遗忘以及这意味着什么。
完美的记忆,有限的边界
大语言模型拥有一种奇特的记忆——绝对清晰,却有边界。
说绝对清晰,是因为落在上下文窗口内的一切,都被模型同等精准地"看见"。十轮对话之前你说的那句话,它仍能看得一字不差。说有边界,是因为这个窗口有最大容量。超出的部分,直接消失——不是渐渐模糊,而是彻底不在。
这就是为什么你和 ChatGPT 聊了一个小时后,新开一个对话窗口,它会"忘记"所有之前的上下文。这不是 bug,而是架构的根本性限制。
上下文窗口是什么
上下文窗口,就是模型在单次推理中能同时处理的 Token 总量。你的问题、对话历史、系统指令、粘贴进来的文档——这一切都被拼接成一个序列,在一次前向传播中被模型整体读取。
早期的 GPT-3 只有 2,048 个 Token 的窗口。今天,部分模型已突破 100 万 Token。这是一个巨大的飞跃,但并未改变问题的本质:边界始终存在。
注意力的代价
还记得注意力机制吗?每个 Token 都要关注窗口内的所有其他 Token,计算量与 Token 数的平方成正比。
窗口翻倍,计算量翻四倍:
| Token 数 | 注意力运算量 |
|---|---|
| 1,000 | 100 万次 |
| 8,000 | 6,400 万次 |
| 128,000 | 164 亿次 |
这解释了为什么模型提供商按 Token 收费,也解释了为什么长对话的成本会随着上下文增长而急剧攀升。
亲自感受遗忘
发送几条消息,观察当早期对话轮次超出窗口后,模型就再也访问不到它们了——即使你明确提及它们。
调整窗口大小,看遗忘来得有多快或多慢。
拖动内容:超出窗口的部分会被彻底遗忘。Attention 的计算开销随上下文长度以 O(n²) 增长,这就解释了为什么各家都在追求 100 万 tokens 的窗口。
KV 缓存,简而言之
每生成一个新 Token 都对所有历史 Token 重新计算一次注意力,代价是灾难性的。拯救局面的优化叫作 KV 缓存:把已经算过的中间结果留在内存里,每一步只为新 Token 添加一行。
正是它让实时生成成为可能——也正是它让显存占用与上下文长度成正比地增长。我们在第 18 章会详细展开。
系统提示词与对话模板
当你向 ChatGPT 或 Claude 发一条消息时,模型实际收到的并不是你那条原始消息。而是一段经过精心格式化的序列,大致长这样:
<|im_start|>system
你是一个有用且简洁的助手。
<|im_end|>
<|im_start|>user
法国的首都是哪里?
<|im_end|>
<|im_start|>assistant
这种格式化方式——对话模板(chat template)——把一段对话变成一条线性的 Token 序列,并用特殊标记来区分不同角色(system、user、assistant)。模型在微调阶段就被训练去识别这些标记。
**系统提示词(system prompt)**是放在最开头的一条特殊消息。它设定模型的行为、语气、约束("用 JSON 回复"、"绝不回答关于某个话题的问题"、"你是一位专精知识产权的美国律师"……)。它和其他内容一样住在上下文窗口里,但因为位置在最前、角色又特殊,它的"分量"会比普通消息更重。
每一类模型都有自己专属的对话模板:OpenAI 用 ChatML,Llama 2 用 [INST]…[/INST],Llama 3 和 Claude 又有更新的变体。如果你手写对话却没有按照正确的格式来,模型就会表现失常——它是被训练来看到这些标记并预期它们出现的。
"迷失在中间"
研究发现,模型对上下文窗口不同位置的信息利用效率并不均等。
窗口开头和窗口结尾的信息,比埋在中间的信息被更有效地利用。这个现象被称为 "lost in the middle"(迷失在中间)——模型倾向于忽视长上下文中间部分的段落。
实践含义:如果你在构建一个需要注入参考文档的助手,把最重要的信息放在提示词的开头或结尾,而不是夹在中间。
朝着更长的窗口走去
研究者正在探索几种不让成本爆炸就能延长窗口的思路:
- Sparse attention(稀疏注意力):每个 Token 不再关注所有其他 Token,而只看一个子集(邻近的,或按重要性挑选的)。
- Sliding window attention(滑动窗口注意力):一个滑动窗口——每个 Token 只关注距离它最近的 k 个邻居。
- Flash Attention:不是减少计算量,而是对精确注意力的一种 GPU 效率高得多的实现。
但所有这些技术都要付出精度或实现复杂度的代价。目前还没有完美的方案。推理侧的细节——尤其是它们如何与 KV 缓存交互——会在第 18 章展开。
当上下文窗口不够用时
如果你需要让模型访问的信息量远超窗口容量——数千页文档、一个实时更新的数据库——上下文窗口本身就不是正确的解决方案。
这时,你需要的是另一种架构:不是把所有文本塞进上下文,而是在回答问题时检索最相关的片段,再注入窗口。
这正是下一章要讲的内容。
更新于