mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
5501 字
14 分钟
大模型记忆机制:从上下文窗口到长期记忆
2026-04-01

大模型本身没有传统意义上的”记忆”。它是一个无状态的函数:输入一段文本,输出一段文本,调用结束就什么都不剩。但用过大模型的人都有”它记得我”的体验:它记得上一轮说过的话、记得我几小时前提的偏好、甚至记得我昨天让它做的事。这种记忆感不是模型自带的,而是应用层在模型外面搭的一套机制。

理解大模型的记忆,关键要先分清两层:一层是上下文窗口,模型每轮能看到多少历史;另一层是长期记忆,窗口装不下时怎么把信息留住。Claude Code、ChatGPT、各类 Agent 框架的记忆系统,本质都在这两层上做文章。本文把这套机制拆开讲清楚,回答两个问题:Claude 的记忆机制是怎么样的,长期记忆又是怎么实现的。

一、上下文窗口:记忆的第一道边界#

大模型单次能处理的输入有长度上限,叫上下文窗口(Context Window)。这个窗口以 token 为单位计量,早期 GPT-3.5 为 4K(后续扩展至 16K),GPT-4 基础版为 8K/32K(Turbo 及 4o 系列达到 128K),Claude 3.5 为 200K,Gemini 2.0 率先突破 1M。到 2026 年,百万级上下文已成为旗舰模型的标配。窗口里的内容包括系统提示词、历史对话、当前用户输入、可能还有检索到的资料,全部塞进这一次推理。

窗口的作用是模型的”工作记忆”。所有想让模型这一轮参考的信息,必须落在这扇窗口里。不在窗口里的,模型这一轮就感知不到。这是理解一切记忆机制的前提:模型每轮推理都是一次性从头读窗口里的全部内容,没有什么跨轮的”内部状态”帮你记住。所谓”记得上文”,本质是应用层把上文拼进了这一轮的窗口。

这带出一个直接的问题:对话越长,历史越多,窗口迟早被塞满。满了之后要么砍掉早期对话,要么把早期对话压缩成摘要再放回去。这就是压缩(compaction)机制的由来。

二、对话历史:以什么形式留存#

应用层要让模型”记得上文”,做法是把历史对话作为输入的一部分拼进窗口。最朴素的形式是按轮次拼接的消息列表,每条消息带角色(user/assistant/system)和内容:

[
{"role": "system", "content": "你是一个助手"},
{"role": "user", "content": "我叫张三"},
{"role": "assistant", "content": "你好张三"},
{"role": "user", "content": "我叫什么"}
]

模型读到这个列表,“张三”在历史里,它就能回答。这就是无状态模型产生记忆感的全部秘密:不是模型记住了,是应用层每次都把历史喂给它。

对话历史的存储和管理因产品而异。Claude Code 的做法很有代表性:它把整个会话以 append-only 的 JSONL(每行一条 JSON 事件)形式落盘,每条消息有 uuidparentUuid,组成一条链表。这样做的好处是历史可回溯、可分支、可恢复,--resume 能从断点继续对话。这套存储机制是”对话历史”这一层在工程上的具体实现,详见 Claude Code 深度解析 的会话持久化章节。

三、压缩:窗口装不下怎么办#

对话一长,历史塞不进窗口,就得压缩。压缩的思路是:把早期对话交给模型做一次摘要,用摘要替换原始消息,腾出窗口空间,同时保留关键信息。

压缩不是简单截断。简单截断会丢掉早期信息,用户问起就来一句”我不记得了”。压缩是把长历史浓缩成一段摘要,仍然放进窗口,模型还能据此回答早期的事。压缩后的对话在 Claude Code 里用 compact_boundary 这类标记隔开,摘要之后是新一轮的完整对话。

压缩什么时候触发?一般是窗口用到一定程度(比如接近容量的某个比例)时自动触发,也允许手动触发。触发后,应用层把当前窗口里的历史读出来,调一次模型生成摘要,把摘要写回,后续轮次模型看到的就是”摘要 + 压缩后新对话”。这个过程要处理失败重试(生成摘要的调用可能失败)和熔断(连续失败就停止自动压缩,避免无限消耗)。

压缩还有一个关键细节:哪些东西要重新放进窗口。压缩会丢掉早期对话的细节,但有些信息不能丢,比如最近读过的文件、当前执行的计划、正在跑的子任务状态。所以压缩后会有一轮”重新注入”,把这些关键上下文补回窗口,防止压缩之后模型失忆。

Note

压缩是上下文窗口这一层的核心机制,它解决的是”单轮窗口装不下”的问题,不是真正的长期记忆。压缩摘要本身也还在窗口里,对话继续变长,摘要还会被再次压缩。要跨会话记住信息(关掉程序明天再开还记得),靠的是下一节讲的长期记忆。

四、记忆文件与召回:跨会话的记忆#

压缩解决单次会话内的容量问题,跨会话的记忆要靠外部存储。Claude Code 的 memory 目录就是这种机制的实例:它维护一个 memory/ 目录,每条记忆是一个带 frontmatter 的 markdown 文件,再加一个 MEMORY.md 索引文件。

这套设计的逻辑是这样的:

  1. 写入:模型在对话中发现某条信息值得长期记住(用户偏好、项目约束、反馈纠正),就写一个独立的 markdown 文件,文件头部用 frontmatter 标注这条记忆的类型、一句话描述。
  2. 索引:所有记忆文件在 MEMORY.md 里登记一行,类似目录。
  3. 召回:每次会话开始,先加载 MEMORY.md 索引,根据当前任务描述判断哪些记忆可能相关,再按需读取具体的记忆文件内容放进窗口。

召回这一步很关键,因为记忆文件可能很多,全塞进窗口不现实。Claude Code 的做法是用一个轻量模型(不是主模型)扫一遍所有记忆文件的描述,挑出与当前任务最相关的几条,再加载全文。这本质是一种”先看摘要再读全文”的检索,只不过检索器是个小模型。

与 memory 文件并列的还有 CLAUDE.md 这种项目级行为指令。两者的分工是:CLAUDE.md 管”你应该怎么干活”(项目规范、工作流约定),memory 管”上次干活学到了什么”(跨会话经验)。两者都在会话启动时加载,共同构成模型的”启动状态”。

这里有个容易从 Claude Code 实现里得出的误解:以为长期记忆就是不断往里追加。Claude Code 的 memory 文件确实是 append-only 写入,但工业级的记忆系统不能止步于此,新事实进来还得和已有记忆对账。Mem0 这个开源框架把这件事做成了”提取、对比、决策”两阶段流水线:每段对话结束先提取候选记忆,再对每条候选做向量检索找语义相近的已有记忆,由模型判断两者关系,做出四种决策之一。这四种决策不是拍脑袋分类,而是对应记忆该往哪走的四条路:ADD 是全新信息直接入库,UPDATE 是新信息补充或修正了旧记忆,DELETE 是新信息否定了旧记忆,NOOP 是重复不操作。用户说”我搬到了上海”,系统检索到已有记忆”用户住在北京”,判为 UPDATE 把旧记忆改成上海,而不是同时留着两条互相矛盾的记录。这一步对账是长期记忆区别于流水账的关键,没它记忆库会越攒越乱、矛盾越积越多。

五、记忆好不好:三层次框架#

讲了这么多方案,怎么判断一个记忆系统算好?光说”记得住”不够。记忆能力可拆成递进的三层,从低到高。

第一层是基础回忆,最根本的能力:能准确存储和检索用户直接说的、结构化的、无歧义的信息。“我的会员号是 12345”,后面要用时精确返回。这层确保基本可靠性,是更复杂能力的基础。连这层都做不稳,后面都白搭。

第二层是多会话检索:面对来自不同对象、不同时期的会话,能检索出所有相关信息并推理判断。真实交互往往不是一次完成的,而是分渠道、分时间完成的。用户有两辆车问”为我的车预约保养”,得找出全部两辆车并主动问要哪辆,而不是随便猜一辆;取消”洛杉矶之旅”要理解这是复合事件,主动关联机票和酒店两笔预订。

第三层是主动服务,衡量是否到助理级的试金石:综合跨越多个甚至很久以前的会话,提供有预见性的主动帮助,从看似无关的记忆里发现深层联系。预订国际航班时主动关联数月前存的护照信息,发现快过期就预警;报税季主动从过去一年记录里搜出所有税务文件,呈现完整待办清单。这层要求系统在没有明确指令时,主动规避潜在问题、整合复杂信息。

这三层不是可选项,是选型时的标尺。做客服 Agent,第一二层就够;做个人助理,必须冲第三层。方案选错,再复杂的工程也补不回能力层级的差距。

六、长期记忆的通用方案#

Claude Code 的记忆文件是一种具体的长期记忆实现,思路是”把要记的写成文件,启动时读回来”。这是长期记忆的一种范式,但不是唯一范式。通用地看,AI 系统的长期记忆有几种主流方案,对应不同的工程取舍。

6.1 滑动窗口与摘要压缩#

最简单的长期记忆其实不是”长期”,而是”尽量延长短期记忆”。滑动窗口保留最近 N 轮原文,更早的对话压缩成摘要。这是大多数聊天产品的默认做法,实现简单,但本质仍是上下文窗口的延伸,关掉会话就没了。

6.2 RAG:向量检索召回#

RAG(Retrieval-Augmented Generation)是工业界最主流的长期记忆方案。思路是把要记的内容切成块、向量化、存进向量数据库,每轮对话开始时把当前输入也向量化,去库里找最相关的几块,拼进窗口。

flowchart LR W["用户输入"] --> E["Embedding 向量化"] V[("向量数据库<br/>历史记忆/知识")] E --> Q["相似度检索 Top-K"] V --> Q Q --> P["拼进上下文窗口"] W --> P P --> M["模型生成回答"]

RAG 的好处是记忆容量不受窗口限制(库里可以放几亿条),按相关性召回,不相关的不会挤占窗口。代价是要维护向量化和检索这一套基础设施,而且召回靠的是语义相似度,不是”模型主动想起”,召回不到的就算模型知道也用不上。RAG 的完整工作流程(分块、向量化、向量库选型、混合检索、重排序)是一个独立的大话题。

6.3 MemGPT:操作系统式的内存管理#

MemGPT 把长期记忆做成了操作系统管理内存的样子。它的灵感来自虚拟内存:主内存(上下文窗口)有限,但可以在外部存大量数据(外部上下文),靠一个”内存管理”层在两者之间搬数据。

在 MemGPT 里,模型不仅回答用户,还能主动调用”把某条记忆放进主上下文”或”把某段对话存到外部”的操作,像操作系统触发缺页中断一样按需把外部记忆调入窗口。这让模型对”记什么、什么时候召回”有了一定自主权,比 RAG 的被动检索更接近人脑的主动回忆。代价是复杂度和 token 消耗都更高。

6.4 持久化记忆文件#

Claude Code 的 memory 目录属于这一类:把记忆结构化写成文件持久化,会话启动时按需读回。它的特点是记忆是”人机可读的文本”,可解释、可编辑、可版本管理,适合存”规则、偏好、经验”这类需要稳定和可审计的内容。缺点是不适合存海量对话历史(文件一多召回就是问题,所以要用索引加轻量检索来缓解)。

6.5 结构化存储#

也有系统把记忆存进关系数据库或知识图谱:用户画像存结构化表,对话历史存时序表,实体关系存图。好处是查询灵活、可做复杂关联,缺点是结构化要先设计好 schema,且语义检索不如向量库自然。生产系统常把几种存储混着用:向量库存语义记忆,关系库存结构化画像,文件存可读经验。

6.6 从文本到可执行代码:User as Code#

前面五种方案有个共同点:记忆的载体都是文本,于是”存”和”用”始终是分开的两步,先把相关文本捞回来,再交给容易出错的模型去读、去算。文本记忆擅长召回单条事实,却很难在众多记录上做聚合统计、发现相互矛盾的事实、或强制执行逻辑规则,因为这些操作都得靠模型心算,记录一多就出错。

User as Code 这条路把记忆的介质从文本换成了可执行代码:把对用户的模型本身做成一个活的软件工程,用带类型的 Python 对象保存用户状态,用普通函数编码约束规则,让”表示用户”和”推理用户”发生在同一个能被解释器运行的介质里。它的更新分两阶段:记忆阶段在每次会话后把对话里的事实逐条抽出来追加到只增不删的事实日志,结构化阶段周期性地从完整日志重新生成整份带类型的 Python。这套两阶段设计对应数据库里”预写日志加周期检查点”的经典思路,第一次被搬到了大模型记忆上。

这么换介质图什么?看个最直接的对比。问”我去年出了几次国”,文本记忆要把所有行程召回再逐条数,记录一多就数错,论文实测这类聚合问题的正确率只有 6% 到 43%;在 User as Code 里这就是一行表达式,正确率接近 99%。差距大到反直觉,但道理很朴素:算术交给确定性的解释器,而不是让模型心算。代码形态还顺手解决了另外两件文本记忆最吃力的事:把”当前用药”和”过敏史”两份状态放一起,一个函数就能按药物类别交叉比对揪出冲突;护照有效期这类约束也能固化成检查函数,状态每次更新自动触发,出国行程出发日距护照到期不足 180 天就报警,不用用户开口也不用检索。

这条路的代价是要一套代码生成与执行的工程支撑,对结构化程度不高的杂项事实没有优势,所以它给文本留了位置,杂项塞进 notes 字段。顺着”表示介质”这条线还能往内再走一步:User as Engram 干脆把事实写进模型参数,但不是训练 LoRA(那样训出的 fact-LoRA 直接提问能复述,间接推理却失灵,因为冻结的骨干模型从没学过怎么去查阅这个临时挂上来的适配器),而是把事实精准写入 Engram 模型里空闲的哈希 N-gram 槽位,由一个感知上下文的门控决定何时调取,绕开了”存了却不会用”的困境。从纯文本、到可执行代码、再到局部参数,是用户记忆的表示由外及里的一条连续谱:外侧易更新可审查,内侧更紧凑更擅长即时推理。

方案容量召回方式记忆载体适用内容
滑动窗口+摘要受限全量装入窗口内摘要近期对话
RAG 向量检索语义相似度召回向量数据库海量知识、对话历史
MemGPT模型主动调入外部上下文 + 调度需要主动回忆的场景
持久化记忆文件索引+轻量检索结构化文件规则、偏好、经验
结构化存储SQL/图查询数据库/知识图谱用户画像、实体关系

七、把记忆装回窗口:殊途同归#

无论哪种长期记忆方案,最后都要解决一个问题:怎么把记忆装回模型的上下文窗口。因为模型只在窗口里”看得见”,所有长期记忆的归宿都是”在每一轮推理前,把相关记忆检索出来,拼进窗口”。区别只在检索方式和载体。

所以长期记忆的本质是:一个在模型外部的检索系统,每轮把相关历史喂进窗口。短期记忆(窗口、压缩)解决”这一轮能看多少”,长期记忆(RAG、记忆文件、外部存储)解决”跨轮跨会话怎么不丢”。两者在”拼进窗口”这一步汇合。

理解了这个汇合点,就能解释为什么不同产品的”记忆感”不一样:ChatGPT 的记忆偏 RAG,把偏好和事实存进向量库按需召回;Claude Code 的记忆偏持久化文件加索引召回;纯 Agent 框架可能用 MemGPT 式主动调度。选型要看要记什么(海量对话还是少量偏好)、要怎么召回(语义检索还是结构化查询)、可解释性要求多高。

小结#

大模型没有内置记忆,记忆是应用层在模型外面搭的。分两层看:上下文窗口是模型每轮能看多少历史,压缩负责在窗口快满时把旧历史浓缩成摘要;长期记忆负责跨会话留住信息,主流方案有滑动窗口加摘要、RAG 向量检索、MemGPT 主动调度、持久化记忆文件、结构化存储几种。所有长期记忆方案最终都要把相关记忆检索出来拼进窗口,模型才”看得见”。Claude 的记忆机制是这套框架的一个具体实例:JSONL 对话历史管单会话、压缩管窗口容量、memory 文件加 CLAUDE.md 管跨会话,召回靠索引加轻量模型筛选。把这几层对应清楚,遇到具体产品的记忆实现,就能拆出它用的是哪一层、为什么这么选。

参考资料#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

大模型记忆机制:从上下文窗口到长期记忆
https://blog.souloss.cn/posts/ai/agent/llm-memory-mechanism/
作者
Souloss
发布于
2026-04-01
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时