大模型通识 / 大模型理论基础
8. 上下文窗口、缓存与记忆:模型这一次到底看到了什么
原文备份 · 第 9 / 20 篇 · 查看极客时间原知识库 ↗
本篇目录 · 12 节
来源:大模型理论基础
上一轮,复习助手帮你安排了今晚的学习时间。你明确说过:连续学习不能超过 45 分钟,任务 B 必须在任务 A 后面。
聊了许多轮以后,你让它“按刚才的条件再排一版”,它却把 A、B 连在一起,安排了 60 分钟。界面上明明还能翻到原来的要求,模型为什么像忘了一样?
原因可能有几种:要求没有进入这一次模型调用;历史被压缩时漏掉了条件;要求虽然还在,模型却没有正确使用。仅凭一次错误,不能判断是哪一种。
本篇要建立一个具体的判断方法:先检查这一次有效输入里有哪些信息,再区分容量限制、计算缓存与应用保存的记忆。 全文使用教学构造,不测量任何真实模型的容量、速度或记忆表现,也不要求调用 API。
一、聊天记录,不等于本次模型上下文
上下文,Context,是模型本次生成时可利用的输入信息,以及生成过程中已经形成的相关序列状态。它不只包括你刚刚输入的那句话。
在聊天应用中,组成一次调用的材料可能有:
| 材料 | 在复习助手中的例子 |
|---|---|
| 应用指令 | 只依据提供的笔记,不擅自添加日程 |
| 被保留的对话 | 之前的要求、回答和用户纠正 |
| 当前问题 | 按刚才的条件重新排一版 |
| 参考资料 | 本周计划、章节笔记 |
| 工具相关信息 | 可用工具说明、读取日历后返回的结果 |
| 应用取出的记忆 | 用户确认过的学习偏好 |
普通模型调用不会自动扫描你电脑上的所有文件,也不会天然拥有聊天界面里存着的全部内容。应用要选择、组织并提供相关信息。
有些接口要求应用重新提交消息历史;有些服务支持引用已经保存的会话状态。接口形式不同,但都需要明确恢复出本次有效上下文。“应用或服务保存过”,不等于“这次一定全部提供给模型”。
因此,出现“忘记条件”时,第一步不应只是把提示写得更凶,而是检查最终送入或恢复给模型的内容。开发时可以记录本轮用了哪些消息、资料版本和摘要;无须把所有敏感原文都随意写入日志。
二、上下文窗口:要给输入与后续生成共同留位置
上下文窗口,Context Window,描述模型一次处理序列时的容量边界,通常以 Token 计量。它不是聊天可以持续多少天,也不是模型能保存多少份永久文件。
对常见自回归聊天模型,输入历史与后续生成共同影响窗口占用。不同服务还可能分别规定输入上限、输出上限,以及思考内容怎样计入。Claude 的官方上下文说明就区分了这些组成与模式规则;实际开发不能只看一个宣传容量数字。Claude:Context windows
下面构造一个简单服务:总窗口是 8000 Token,暂不考虑特殊架构;所有必要格式开销已单独计入。这里的数字不是任何厂商当前规格。
| 本轮组成 | 教学 Token 数 |
|---|---|
| 应用指令 | 400 |
| 历史消息 | 1800 |
| 当前参考笔记 | 3600 |
| 当前问题 | 200 |
| 消息边界等格式开销 | 200 |
| 输入合计 | 6200 |
| 为本次生成预留 | 1200 |
| 计划占用 | 7400 |
剩余余量是 8000-7400=600。如果在下一次调用中又带入 1000 Token 的工具结果,并保持其他项不变,计划占用变成 8400,超过预算 400。
不能因为“输入 7200 还不到 8000”,就忘记原本想为生成留下的 1200。也不能把最大输出长度理解为保证一定输出这么多;它是上限或预算控制的一部分,模型可能提前结束。
这是一种保守的容量规划,不表示所有 API 都会按“输入+请求输出上限”提前拒绝请求。有的服务会报错,有的允许生成到窗口边界,有的应用会先删减或压缩材料。要区分你自己规划的余量与服务实际的校验规则。
对于推理模型,还要核对思考 Token 与最终文本的计数方式。用户只看到几百字,不代表本轮只产生了这几百字对应的 Token。
三、材料放不下时,删掉、总结和找回来有什么区别
长对话不能靠无限累加处理。可以比较三种方式:
| 处理方式 | 留下什么 | 可能失去什么 |
|---|---|---|
| 截断或裁剪 | 选中的原始消息、片段 | 被删除部分的细节与约束 |
| 摘要压缩 | 对原文的简短表示 | 原句、例外、歧义、来源细节 |
| 外部保存并按需取回 | 文件或数据库中的完整材料,输入中只放当前相关部分 | 如果取回失败,本轮仍得不到所需信息 |
这些都是应用或服务的设计选择,不是模型到了第某轮就必然采取的统一行为。
一份看似通顺、却不够用的摘要
原始要求是:
今晚 19:00—20:30 有空。
A 25 分钟,B 35 分钟,C 20 分钟,都不能拆开。
B 必须在 A 后面;C 顺序不限。
中间恰好休息一次、10 分钟;连续学习不超过 45 分钟。
如果压缩成:
用户今晚要完成 A、B、C,并适当休息。
读起来没有语病,却丢失了解题所需的几乎全部约束。后续模型即使严格依据摘要,也无法恢复“45 分钟”和“B 在 A 之后”。它偶然猜对,不算可靠记忆。
更有用的工作摘要可以按任务保留:
目标:在今晚 19:00—20:30 内完成 A/B/C。
时长:A25、B35、C20 分钟;各任务不可拆分。
顺序:A 先于 B;C 无顺序限制。
休息:恰好一次10分钟;每段连续学习≤45分钟。
已验证候选:A-C-休息-B;C-A-休息-B。
来源:本次会话的日程要求;只对今晚生效。
这不是原文的无损压缩。它只是针对当前任务保留了必要信息;如果以后要查用户的精确措辞,仍需回到原始消息。尤其不要把模型自己提出、尚未核对的方案,摘要成“用户已经确认的事实”。
在前面的容量算例中,若把 1800 Token 历史压缩成 600,节省 1200;再加入 1000 Token 工具结果,计划占用就是 7400-1200+1000=7200,剩余 800。但节省空间只是第一项检查,还要核对关键条件是否保留。
四、放得下,也不等于每条信息都用得好
上下文容量允许你提交一定长度的序列,不保证模型对其中所有细节有同等稳定的利用能力。
《Lost in the Middle》在所测的多文档问答与键值检索任务中发现,相关信息处于不同位置时,模型表现会变化;某些长输入中,中间位置的信息更难被有效利用。原始论文
这是特定研究设置的结果,不是“所有模型永远读不懂中间内容”的定律。它提示我们把两个问题分开:
- 输入是否在容量范围内,并且实际送入了模型?
- 模型是否在你的任务中正确定位、组合和使用了这些信息?
复习助手可以用一个小检查区分二者:把明确的“连续学习≤45分钟”放入当前输入,再要求生成方案,独立核对每段时长。如果新输入仍违规,就不能只归因于历史被截断;还应检查模型理解、其他冲突指令和任务难度。
堆入更多旧对话也可能把过期计划一起带回来。整理来源、时间和当前约束,往往比把所有材料原样拼接更容易定位问题。不过,具体怎样组织效果最好,仍需用自己的案例比较。
五、KV cache:省去重复计算,不是保存一份永久笔记
第二篇介绍过注意力中的 Key 和 Value。对常见的因果 Transformer,已处理位置在相同前缀、相同模型计算条件下的 K/V,可以保留下来,供后续位置使用。这就是 KV cache,键值缓存。Hugging Face:How caching works
它保存的是注意力计算的中间张量,不是一份人类可读的事实清单,也不是模型参数的新版本。
为什么已有 K/V 可以复用
因果注意力不让较早位置读取未来 Token。当前缀不变,只在后面追加内容时,早先位置不需要因新增的未来文字而重新编码。新位置仍计算自己的表示,并利用已有缓存参与注意力。
考虑一个只有 4 个输入 Token 的示意。首次处理输入,再继续两步,每步追加一个待处理 Token:
| 阶段 | 每次重算整个前缀时处理的位置数 | 使用缓存时新增处理的位置数 |
|---|---|---|
| 首次处理 4 Token | 4 | 4 |
| 追加一个 Token | 5 | 1 |
| 再追加一个 Token | 6 | 1 |
| 合计 | 15 | 6 |
表格只对比为这些位置重新计算 K/V 的工作,没有计算完整模型的全部运算。它不表示速度一定提高到 2.5 倍。新位置仍要与可用缓存进行注意力计算,读取缓存本身也有开销。
处理整段提示并建立相应状态,常称为 Prefill,预填充;后续逐步生成,常称为 Decode,解码。这两个阶段的计算特点不同,所以“提示很长”和“答案很长”对耗时的影响也不同。
用存储换计算,要付出空间成本
做一个常规、完整保存 K/V 的简化估算。假设只有一个序列,2 层,每层 2 个用于保存 Key/Value 的头(KV 头),每个头的向量维数为 4,缓存 1000 个位置,每个数用 2 字节。
K/V 存储字节数
= 2(K与V两份)×层数×KV头数×位置数×头维数×每个数的字节数
= 2×2×2×1000×4×2
= 64000 字节,即 62.5 KiB
1 KiB=1024字节。在相同假设下,缓存 2000 个位置就是 125 KiB。这里没有计算模型权重、临时张量、内存分配开销和其他序列。
真实模型可能共享 KV 头、压缩缓存、使用滑动窗口,或把缓存移到其他存储层,不能直接套这组玩具数字。官方缓存文档也区分动态、静态、量化和滑动等策略。Hugging Face:Cache strategies
缓存缓解重复计算,并不自动扩大模型可用的逻辑上下文窗口。把张量存到硬盘,也不会把 8000 的窗口变成无限。
六、前缀缓存:不同请求也可能复用已有计算
KV cache 常用于一次生成中的连续步骤;服务系统还可以把它用于具有相同开头的后续请求,这通常叫 前缀缓存,Prefix Caching。
例如,复习助手多次使用同一份课程笔记:
请求1:固定指令 + 同一份笔记 + 问题甲
请求2:固定指令 + 同一份笔记 + 问题乙
如果模型及相关计算条件一致,公共前缀的状态仍可用,而且符合缓存匹配规则,第二次请求就可能跳过部分重复的预填充计算。vLLM 的自动前缀缓存文档说明了这种复用,也指出它主要节省输入处理阶段,不会因此省掉新答案的逐 Token 生成。vLLM:Automatic Prefix Caching
这里有三个容易误解的地方。
第一,相同意思不等于相同前缀。 改变前面的文字、消息格式或顺序,可能改变 Token 序列及其上下文状态。不是把同一段文字搬到任何地方都能直接复用。最低长度、分块、保存时机和淘汰规则也由实现决定。
第二,命中缓存不表示少占窗口。 6200 Token 的有效输入即使有 3600 命中缓存,规划窗口时仍按有效输入 6200 计算;节省的是部分计算或服务计费,不是把这 3600 从上下文长度里抹掉。
第三,前缀缓存不会替应用补全未提交的笔记。 在要求提交完整消息的接口中,你只发“问题乙”,服务不会仅凭之前出现过笔记,就自动猜出应接续哪份前缀。支持会话引用或显式缓存引用的接口,则要按其协议恢复上下文,不能与普通缓存命中混为一谈。
以观察基准日核查到的 DeepSeek 文档为例,其上下文缓存要求匹配已持久化的前缀单元,并提供输入命中/未命中统计;缓存采用尽力而为机制,不保证每次命中。因此不能许诺“同样笔记第二次问就必然命中全部公共部分”。DeepSeek:Context Caching
不要为了追求命中而继续发送已经失效的计划。正确材料优先于缓存复用。
七、应用记忆:把信息保存下来,再在需要时取用
如果希望复习助手下周仍知道你的偏好,仅依赖一次计算的缓存并不够。应用需要有明确的保存与读取机制。
例如,用户进一步确认“45分钟上限也是我平时的偏好”后,可以保存:
内容:一般情况下,每段连续学习不超过45分钟。
范围:用户长期学习偏好。
来源:用户确认。
更新时间:2026-10-03。
而“今晚只有19:00—20:30有空”应作为当日计划条件保存,不能顺手升级成每天固定的空闲时间。当前任务有临时例外时,还应区分例外与长期偏好,避免互相覆盖。
flowchart LR
A[用户说明或确认] --> B[提取待保存的信息与适用范围]
B --> C[存入文件或数据库]
D[新的任务] --> E[读取或检索相关记录]
C --> E
E --> F[连同来源 时间和当前任务组织上下文]
F --> G[模型生成并检查结果]
LangGraph 的文档区分会话范围的短期状态与跨会话的长期存储。这是应用保存和恢复信息的机制,并不要求通过训练把每条个人事实写进模型参数。LangChain/LangGraph:Memory overview
即便数据库保存了所有笔记,每次调用仍只能使用本轮实际取出的内容。记忆不可靠,可能是保存时提取错了、旧记录没更新、检索没找到,或读到了却没有正确使用。错误发生在不同环节,修复方法也不同。
对于个人项目,可以先从少量明确字段和可读文件开始:学习偏好、当前任务、已确认决定、尚待解决的问题。让用户能修改或删除过期记录;让每条记录能追溯到来源。后面的语义检索与 RAG 篇会再讲材料多起来以后怎样查找。
八、遇到“忘了”,按信息经过的顺序检查
把本篇概念放在一张表里:
| 概念 | 主要保存或约束什么 | 不能据此断言什么 |
|---|---|---|
| 模型参数 | 训练形成的数值与能力 | 已永久记住本次上传的笔记 |
| 本次上下文 | 当前提供、恢复并可用的信息 | 窗口内每条信息都会被正确使用 |
| KV cache | 已处理位置的计算状态 | 有一份可任意查询的长期用户档案 |
| 前缀缓存 | 符合条件的公共前缀计算状态 | 能补回省略的历史,或扩大窗口 |
| 应用记忆 | 持久保存、可读取的信息记录 | 每一轮都已取出全部记录 |
针对开篇的 60 分钟违规日程,可以依次检查:
- 原始要求是否保存,保存的是哪一版?
- 摘要或记忆里是否仍保留“45分钟”及适用范围?
- 本轮有效输入是否真的包含该条件,容量是否足够?
- 若确实包含,生成结果为什么未通过独立时长检查?
这些检查比笼统地说“模型记性差”更有助于修复问题。缓存命中率可以帮助诊断效率,却不能代替上述信息与结果检查。
九、理解检查
1. 界面能翻到十天前的聊天,是否证明模型本轮看到了那条消息?
不能。界面存储、应用选择历史、服务恢复状态与本轮模型输入是不同环节。应检查实际有效上下文。
2. 教学窗口8000,输入6200,希望预留1200,剩多少余量?再加1000工具结果后超出多少?
余量600;计划占用变成8400,超出400。这里是容量规划,不代表所有服务一定采用同一种请求拒绝规则。
3. 输入6200中有3600命中前缀缓存,能按2600输入来规划窗口吗?
不能。有效上下文仍有6200 Token。缓存复用计算,不是删除这些位置。
4. 教学KV缓存1000位置占62.5 KiB,在其他假设不变时,2000位置占多少?等于整个模型的内存吗?
125 KiB。不等于整个模型内存;它只计入所设两层、两个KV头的K/V数值存储。
5. 摘要保留“适当休息”,删除“连续学习≤45分钟”,模型以后还能可靠恢复45这个数字吗?
不能仅凭该摘要恢复。需要保留精确条件,或从原始记录取回。偶然生成45不证明已经保留信息。
6. 应用数据库里存着用户偏好,但本轮没取出,模型却没遵守。首先该改训练还是检查信息流程?
先检查读取、检索与上下文组装。保存到数据库不会自动改变模型参数,也不会自动让每次调用都包含该记录。
上下文决定本轮可用的信息,缓存减少部分重复计算,应用记忆负责跨轮次保存与取用。把三者分清,才能判断应当扩大容量、整理材料、修复记忆流程,还是提高任务验证能力。
下一篇《提示词为什么有效:指令遵循与上下文学习》,我们继续讨论:信息已经送进来以后,怎样组织任务、示例与约束,让模型更容易按要求使用它们。
上一篇:推理模型与计算预算 · 返回第二部分大纲