上下文窗口与 KV Cache:为什么 LLM 会「忘事」,长文本还越用越贵
每个用过 ChatGPT 的人都经历过:聊着聊着,模型"忘了"我们一小时前说过的话。它不是失忆,是它的"视野"有物理边界。
上下文窗口(Context Window)是 LLM 最核心、也最容易被误解的概念之一。它决定了模型能"记住"多少、能"看见"多少,也直接决定了长文本场景的成本与质量。
但窗口大小只是表象。真正决定一切的是窗口背后的两样东西:**注意力机制(Attention)**和 KV Cache。
一、上下文窗口:模型的"视野"有物理边界
想象模型在生成每一个字时,都只能"翻阅"一个固定长度的纸带。这个纸带,就是上下文窗口。
- 窗口里的内容 = 系统提示 + 历史对话 + 工具返回 + 你的最新输入。
- 窗口大小以 token 计:8k、32k、128k、甚至 1M。
- 一旦内容超过窗口,早期的内容会被截断——模型就"忘"了。
为什么窗口不能无限大?因为它的背后是一个平方级的算力代价,这正是注意力机制的代价。
二、注意力机制:每个 token 都要"看"所有 token
大模型的核心是 Transformer,Transformer 的核心是自注意力(Self-Attention)。
直觉上,注意力在做一件事:当一个 token 在生成时,它要计算"我应该关注前面的哪些 token"。
以句子 "The cat sat on the mat because it was tired" 为例,当模型处理到 it 时,它需要判断 it 指的是 cat 还是 mat。注意力机制就是让 it 这个 token 去"回顾"前面所有 token,并为每个 token 分配一个权重(注意力分数)。
技术细节(可以跳过,但要记住结论):
- 每个 token 被投影出三个向量:Query(Q,我想找什么)、Key(K,我是什么)、Value(V,我携带什么信息)。
- token 之间两两计算注意力:用 Q 去匹配所有 K,得到分数,再加权求和所有 V。
- 这个"两两计算"意味着:N 个 token 需要 O(N²) 的算力和显存。
这就是窗口不能无限大的根本原因。128k 窗口的注意力矩阵,规模是 8k 窗口的 256 倍。
三、KV Cache:为什么生成第二个字,也要算第一个字?
理解了注意力,再看一个反直觉的问题:模型生成文本是逐 token 进行的,但为什么越往后生成越慢、越贵?
答案:因为注意力是"两两相关"的。生成第 1000 个 token 时,它依然要"回顾"前面 999 个 token。如果每次都重新计算前面所有 token 的 K 和 V,那生成 N 个 token 的总计算量是 O(N²)。
KV Cache 就是用来避免这种重复计算的关键优化:
- 生成第 1 个 token 时,把前面所有 token 的 K 和 V 向量存进缓存。
- 生成第 2 个 token 时,只需计算新 token 的 Q,去匹配缓存里的 K 和 V,再把这个新 token 的 K、V 追加进缓存。
- 依此类推。
这样,每生成一个新 token,只需要算"新 token 和旧 token 之间的关系",总计算量降为 O(N)。
但 KV Cache 不是免费的:它要占用显存,而且随着对话变长,缓存线性增长。这就是为什么:
- 长对话越聊越慢(缓存越来越大,每步都要扫更大的缓存);
- 长对话越聊越贵(历史越长,每轮输入 token 越多)。
KV Cache 是理解"为什么长文本贵"的钥匙。贵的不是"读",而是"反复回顾"。
四、位置编码:模型怎么知道"先后顺序"
注意力机制本身是无序的——它只算两两关系,不知道谁是第一个、谁是最后一个。为了让模型理解顺序,需要额外注入位置信息,这就是位置编码(Positional Encoding)。
不同模型用不同方案:早期的正弦位置编码、后来的可学习位置嵌入,以及现代的 RoPE(旋转位置编码)——它让模型能更好地外推到训练时没见过的更长位置。
位置编码直接决定了模型能"外推"到多长的上下文,是长上下文能力的重要一环。
五、为什么长上下文会"退化":Lost in the Middle
很多人以为"窗口越大越好",但研究表明,即使内容都在窗口内,模型的表现也会不均匀。
最著名的发现是 "Lost in the Middle"(迷失在中间):
- 模型对开头和结尾的信息记得最好;
- 对中间部分的信息,抓取能力显著下降。
原因在于注意力机制:中间 token 的信息会被两端"稀释",而开头和结尾天然是注意力的焦点。
工程含义:
- 把最重要的信息放在开头(system prompt 末尾)或结尾(最新对话)。
- 长文档问答时,不要把关键段落埋在中间。
- 必要时用 RAG 把相关片段"提"到注意力焦点位置,而不是一股脑塞进窗口。
六、工程实践:窗口不是越大越好
面对上下文窗口,成熟开发者的做法不是盲目追求更大的窗口,而是管理好窗口预算。
1. 先估算,再设计
用 tokenizer 精确估算 system prompt + 历史 + 输入各占多少 token,并预留输出空间(比如给模型留 25% 窗口用于回答)。
2. 用策略替代"硬塞"
- 截断(Truncation):超长时,保留开头(重要背景)+ 结尾(最新内容),丢弃中间。
- 滑动窗口(Sliding Window):只保留最近 N 轮对话。
- 摘要压缩(Summarization):把旧对话总结成一段摘要,替代原文。
- RAG:把知识放外部,按需检索,只把"相关的少量片段"塞进窗口。
3. 长上下文 vs RAG:怎么选?
- 长上下文适合:需要模型"通读"整份文档、全局推理、跨段落关联的场景。
- RAG 适合:海量知识库、成本敏感、需要可溯源、需要频繁更新的场景。
- 实践趋势是两者结合:用 RAG 粗筛,用长上下文精读。
结语:窗口是预算,不是口号
上下文窗口、注意力机制、KV Cache——这三个概念共同决定了 LLM 应用的记忆边界、成本曲线和质量上限。
不要被"128k 超大窗口"的宣传迷惑。真正重要的,是你是否理解:每一次生成,模型都要重新"回顾"整个历史;而这份回顾,是要用显存和真金白银买单的。
把上下文当作一笔需要精打细算的预算,而不是一个可以无限挥霍的空间——这是每一个大模型开发者都必须建立的第一性认知。