从零开始理解大模型(八):上下文窗口——大模型的"工作记忆"到底有多大?

举报
AGENT魔方 发表于 2026/04/24 17:02:25 2026/04/24
【摘要】 本文是「从零开始理解大模型」系列第八篇,全套共十篇,循序渐进搭建完整大模型心智模型,每篇均附带可运行代码。本篇聚焦上下文窗口,深度解读大模型的工作记忆原理、容量边界与实际应用限制,透彻理解长上下文能力的底层逻辑。

专栏1.png

欢迎阅读「从零开始理解大模型」系列 —— 十篇文章,从"下一个词预测"到完整的大模型心智模型。每篇配可运行代码。

* 本系列配套运行代码,可在公众号后台回复“大模型”完整获取。

作者:十一

你有没有过这种经历——和 AI 聊得正起劲,它突然对前面说过的事一脸茫然。或者你把一份 3 万字的行业报告丢进去,它礼貌地回你:"抱歉,内容太长,我处理不了。"

它不是失忆了。它只是"工作台"满了

今天我们来扒一扒大模型的"工作记忆"——上下文窗口到底有多大、为什么不能无限大,以及为什么 128K 听起来很多,用起来却很容易见底。

 一、先说结论

模型 真相
模型能"记住"所有对话历史  模型只能看到窗口内的内容,窗口外的等于不存在
28K 很大,肯定够用了 128K token ≈ 10 万字中文。处理长文档或多轮 Agent 调用时,瞬间见底
窗口大小可以随意设置 受限于计算量(n²)显存(KV Cache)的物理极限
只要能"装下"就能"读懂" 存在 Lost in the Middle 现象,中间的信息最容易被漏掉

核心定义:上下文窗口 = 输入 token 数 + 输出 token 数 ≤ 窗口上限
它就像模型的一次性"工作台"——台子越大,能同时摆放的参考资料越多,但台子不是无限大的。

口大小一览

以下为各模型发布时的代表性规格,部分模型后续版本已扩展:

模型 上下文窗口  大约能装多少中文
GPT-2(2019 1,024  约 500 字
LLaMA 2(2023  4,096  约 2,000 字
GPT-4o(2024) 128,000 约 10 万字
Claude Opus 4.7 1,000,000 约 70 万字
Gemini 3.1 Pro(2026) 1,000,000 约 70 万字

从 GPT-2 的 1K 到 2026 年旗舰模型的 1M,窗口大了 1000 倍。进步巨大,但代价也巨大。

注意:输入 + 输出一起算。你塞进去的内容越多,留给模型回答的空间就越少。别以为 128K 窗口就能随便聊一整天——聊着聊着它就"断片"了。


二、为什么不能无限大?(三个致命瓶颈)

2.1 Attention 的 n² 问题

第四篇讲过,Attention 让每个词和**所有词**算相关度。5 个词之间需要 25 条连线,10,000 个词之间就需要 1 亿条。

Attention 计算量 ∝ n²

  1K tokens:      1K × 1K =        1M 次计算
  4K tokens:      4K × 4K =       16M 次计算    ← 长度×4,计算量×16
128K tokens:   128K × 128K = 16,384M 次计算    ← 长度×128,计算量×16384

长度翻 4 倍,计算量翻 16 倍。 这是上下文窗口最硬的天花板。

2.2 KV Cache 把显存撑爆

第七篇算过的账——为了推理快,模型会把之前算过的 K 和 V 缓存起来。问题是缓存大小和上下文长度成正比:

KV Cache = n × 层数 × 头数 × 每头维度 × 2(K和V) × 2字节

LLaMA 7B, 128K tokens:
  128,000 × 32 × 32 × 128 × 2 × 2 = 64 GB

模型参数本身只有 14 GB,KV Cache 却要 64 GB——比模型本身还大。一张 80 GB 的 A100 很快就装不下了。

2.3 位置编码的硬上限

第三篇提过,Embedding 不包含位置信息——"狗咬人"和"人咬狗"的向量是一样的。模型靠**位置编码**来区分先后顺序。

GPT-2 的做法最简单:准备一张只有 1024 行的表,每个位置存一个向量。

python
position_embedding = model.transformer.wpe.weight
print(position_embedding.shape)   # [1024, 768]  ← 只有 1024 个位置

超过 1024?表里没有对应的向量,模型直接傻眼。上下文窗口被位置编码硬性锁死


三、RoPE——让位置编码"旋转"起来

为了打破位置编码的页数限制,新一代模型(LLaMA、Qwen、DeepSeek)引入了 RoPE(Rotary Position Embedding,旋转位置编码)

3.1 核心思路

GPT-2 是"给每个位置发一张身份证"——身份证只印了 1024 张,用完就没了。

RoPE 完全不同:不发身份证,而是让每个 token 根据自己的位置旋转一个角度

位置 0: 不旋转
位置 1: 旋转一个小角度 θ
位置 2: 旋转 2θ
...
位置 n: 旋转 nθ

两个 token 相遇时,只看旋转角度差多少,就知道"你在我前面几个词"。就像时钟的指针——第 3 秒和第 5 秒的距离永远是 2 秒,不管现在是几点。

公式:RoPE(x, pos) = x · cos(pos · θ) + rotate(x) · sin(pos · θ)

不同维度用不同的旋转频率(θ),就像秒针、分针、时针——转速不同,组合起来能编码极其精细的位置信息。

3.2 为什么 RoPE 能支持更长的上下文

可无限外推:RoPE 是公式,不是表格。位置 1024 和位置 100,000 用同一个公式算,不需要提前"学过"。

只关心相对距离:第 3 个词和第 5 个词距离 2,第 100003 个词和第 100005 个词也距离 2——在 RoPE 看来完全一样。

一键拉伸:通过调整旋转频率参数(NTK-aware scaling),可以像拉皮筋一样把 4K 窗口直接拉到 128K——不需要重新训练。

RoPE 出现后,上下文窗口终于不再被位置编码卡死。真正的瓶颈只剩计算量和显存了。

完整的位置编码对比实验见附件 [context_window.py](./context_window.py)。


四、长上下文的真实雷区:不只是"能不能装下"

就算模型标称 128K 甚至 1M,也不代表里面的内容都能被好好利用。

4.1 "Lost in the Middle"——中间的内容直接被忽略

研究发现:上下文越长,模型对**开头和结尾**关注度最高,**中间**关注度最低,形成经典 U 形曲线:

关注度分布(示意):

开头 ████████████████████
...  ███████
中间 ████               ← 这里直接"失忆"
...  ██████
结尾 ████████████████████████

你把关键信息埋在第 50,000 个 token 的位置,模型可能直接当没看见。

 避坑指南如果你有重要的关键指令(比如"请基于以上内容给出结论"),一定要放在开头或结尾**,千万别埋在中间。

4.2 窗口标称值 ≠ 有效推理长度

处理 1,000 字时的逻辑能力,通常远高于处理 100 万字时。

就像你同时处理 3 件事和 300 件事——脑子够大全装得下,但注意力被彻底稀释了,推理质量直线下降。


五、扩展上下文的常见方案

上下文不够用?几种常见的解决思路:

5.1 上下文压缩

让 LLM 定期对长历史做摘要,把几千 token 压缩成几百 token。牺牲细节,但能装更多轮对话。

Agent 系列第六篇讲过——Agent 执行很多步之后,上下文塞满了历史消息和工具返回结果,用一次摘要把 10,000 字压成 500 字精华。

5.2 滑动窗口注意力

每个 token 不和所有历史 token 做 Attention,只和最近的 W 个 token 做:

标准 Attention: 每个 token 看所有 token  → O(n²)
滑动窗口:      每个 token 只看最近 W 个  → O(n × W)

W 通常设为 4096 或 8192。远距离信息看不到,但大部分语言理解其实只需要局部上下文。

5.3 稀疏注意力

每隔几十个 token 设一个"锚点",锚点之间全连接,普通 token 只看附近。远近兼顾。


六、代码实验:亲手感受"记忆"的边界

配套代码 [context_window.py](./context_window.py) 包含三组实验:

实验一:位置编码的"距离感"

python
pos_embed = model.transformer.wpe.weight.detach()

for dist in [1, 10, 100, 1023]:
    sim = cosine_similarity(pos_embed[0], pos_embed[dist])
    print(f"  位置 0 vs 位置 {dist:>4}: 相似度 {sim:.3f}")
```

```
  位置 0 vs 位置    1: 相似度 0.862    ← 紧挨着,很相似
  位置 0 vs 位置   10: 相似度 0.651
  位置 0 vs 位置  100: 相似度 0.312
  位置 0 vs 位置 1023: 相似度 0.095    ← 最远,差异最大

实验二:越界崩溃

python
too_long = tokenizer.encode("hello " * 1200, return_tensors="pt")
model(too_long)  # → IndexError! 位置编码表只有 1024 行,直接炸了

实验三:RoPE 模拟

验证"相对位置"特性——同样距离 1 的两个 token,不管绝对位置是 0-1 还是 100000-100001,RoPE 算出的相关度几乎相同。

完整代码见附件 [context_window.py](./context_window.py)。


七、上下文窗口和你的实际使用

为什么和 ChatGPT 聊久了它会"忘事"?不是忘了,是窗口满了。最早的消息被截掉——模型根本看不见了。

几个实用建议:

算好 token 预算。中文大约 1 个汉字 ≈ 1-2 个 token(第二篇讲过)。128K 看着大,一篇万字长文就吃掉 15K-20K token。

重要信息放两头。避开 U 形曲线的底部——开头和结尾关注度最高。

主动压缩。 在构建长对话系统或 Agent 时,学会让模型定期做摘要,把冗长的历史压缩成精华。

Agent 场景最危险。 Agent 每调一次工具,上下文就暴涨一截——工具返回的 JSON 日志 token 密度极高(第二篇提到过),几轮循环下来窗口很容易爆满。


八、结语

上下文窗口是大模型最硬的"硬指标"之一。它决定了你和模型能一起处理多大的任务。

RoPE 解放了位置编码,但 Attention 的 n² 计算量和 KV Cache 的线性显存增长仍然是铁律。窗口不是想多大就多大——你得学会挑最重要的资料放上工作台。

上下文窗口是模型与现实世界连接的"咽喉"。了解它的边界,你才能在这片有限的战场上,指挥它打出最漂亮的仗。

下一篇,我们讲更宏观的问题:参数量、数据量、算力到底是什么关系?为什么模型越大越强?"大力出奇迹"有没有尽头?


容器模仿.png

扫码回复“大模型

获取本系列文章完整配套代码

「从零开始理解大模型」是「从零开始理解 Agent」的姊妹系列。Agent 系列讲"四肢",本系列讲"大脑"。建议对照阅读 专栏入口

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。