09 · 上下文 · 8 min

模型记住了什么

上下文窗口:完美但有界的记忆。为什么ChatGPT会遗忘以及这意味着什么。

完美的记忆,有限的边界

大语言模型拥有一种奇特的记忆——绝对清晰,却有边界

说绝对清晰,是因为落在上下文窗口内的一切,都被模型同等精准地"看见"。十轮对话之前你说的那句话,它仍能看得一字不差。说有边界,是因为这个窗口有最大容量。超出的部分,直接消失——不是渐渐模糊,而是彻底不在。

这就是为什么你和 ChatGPT 聊了一个小时后,新开一个对话窗口,它会"忘记"所有之前的上下文。这不是 bug,而是架构的根本性限制。

上下文窗口是什么

上下文窗口,就是模型在单次推理中能同时处理的 Token 总量。你的问题、对话历史、系统指令、粘贴进来的文档——这一切都被拼接成一个序列,在一次前向传播中被模型整体读取。

早期的 GPT-3 只有 2,048 个 Token 的窗口。今天,百万级 Token 在前沿模型中已经很常见,Llama 4 Scout 更是从 2025 年 4 月起宣称支持 1000 万——但这里有个重要的分寸:超过百万之后,模型真正的召回能力会明显下降。宣称的窗口不等于真正可用的窗口。 这是一个巨大的飞跃,但并未改变问题的本质:边界始终存在

注意力的代价

还记得注意力机制吗?每个 Token 都要关注窗口内的所有其他 Token,计算量与 Token 数的平方成正比。

窗口翻倍,计算量翻四倍

Token注意力运算量
1,000100 万次
8,0006,400 万次
128,000164 亿次

这解释了为什么模型提供商按 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、Mistral、Qwen 各自的变体。如果你自己跑这类模型,手写对话却没有按照正确的格式来,模型就会表现失常——它是被训练来看到这些标记并预期它们出现的。

而使用闭源 API(OpenAI、Anthropic、Google)时,你永远看不到这些标记。你发过去的是一组结构化的消息,每条带一个角色(systemuserassistant),格式化在服务端完成。机制完全一样,只是被藏了起来。

"迷失在中间"

一个出人意料的发现,由 Liu 等人在 2023 年发表:模型对上下文窗口不同位置的信息利用效率并不均等。

窗口开头窗口结尾的信息,比埋在中间的信息被更有效地利用。这个现象被称为 "lost in the middle"(迷失在中间)——模型倾向于忽视长上下文中间部分的段落。

2025—2026 年的长上下文模型已经把这个问题缓解了很多。要在一份超长文档中间找出某一句具体的话——也就是所谓的 needle in a haystack 测试——今天基本算是解决了。真正没解决的是推理:一旦需要把相距很远的几个段落串起来,位置就依然要紧。

实践含义:如果你在构建一个需要注入参考文档的助手,把最重要的信息放在提示词的开头或结尾,而不是夹在中间。

朝着更长的窗口走去

研究者正在探索几种不让成本爆炸就能延长窗口的思路:

  • Sparse attention(稀疏注意力):每个 Token 不再关注所有其他 Token,而只看一个子集(邻近的,或按重要性挑选的)。
  • Sliding window attention(滑动窗口注意力):一个滑动窗口——每个 Token 只关注距离它最近的 k 个邻居。
  • Flash Attention:不是减少计算量,而是对精确注意力的一种 GPU 效率高得多的实现。

但所有这些技术都要付出精度或实现复杂度的代价。目前还没有完美的方案。推理侧的细节——尤其是它们如何与 KV 缓存交互——会在第 18 章展开。

当上下文窗口不够用时

如果你需要让模型访问的信息量远超窗口容量——数千页文档、一个实时更新的数据库——上下文窗口本身就不是正确的解决方案。

这时,你需要的是另一种架构:不是把所有文本塞进上下文,而是在回答问题时检索最相关的片段,再注入窗口。

这正是下一章要讲的内容。

更新于