干货:从零构建一个超越ChatGPT和Claude客户端的长期记忆能力系统!逆向剖析记忆功能的工程实现
- 内容介绍
- 文章标签
- 相关推荐
引言
佬们如果曾经深入使用过ChatGPT或Claude,一定会注意他们的记忆功能:他们似乎记得你,能够在新的对话中回忆起你的偏好、背景信息,甚至几周前讨论过的话题细节。这种跨会话的记忆能力,远远超出了单次对话中的上下文窗口管理,背后是一套精心设计的长期记忆系统。
本文基于多篇逆向工程博客,结合我长期使用ChatGPT和Claude的实践经验,对两者的长期记忆实现方式进行了系统性的梳理和分析。需要说明的是,这篇文章更侧重于从产品和工程实现的角度进行剖析,而非底层代码实现。即使你没有深厚的理工背景,也能够理解这些系统的设计思路和工程实践价值。
由于CLoseAI在system prompt中包含了明确的防injection指令,并且专门训练防止被套取内部实现细节,因此不同于Claude在博客上公开分享的诸多技术细节,OpenAI的记忆系统大多依赖逆向工程推测。本文将综合这些研究成果,揭示这两个主流AI助手在长期记忆上的异同。
从API到客户端的上下文管理
在深入讨论长期记忆系统之前,我们需要先理清一些基础但容易混淆的概念,懂的佬麻烦直接跳过。Session、thread、prompt、chat等术语在不同的上下文中往往有不同的含义,业界并没有统一的定义标准。我们在这里将session和thread看作你开的一个对话窗口里所有消息的集合。prompt和chat则对应你发的每一条消息或模型的回复。
从API层面来看,OpenAI和Anthropic采用了不同的数据格式。OpenAI使用JSON格式的chat completion API,将每条消息分为system、user和assistant三种角色;而Anthropic则采用XML风格的格式,将user消息称为human消息。这些是我们在调用API时直接面对的接口层。
然而,真正的复杂性在于客户端实现。当你在ChatGPT或Claude的Web界面中进行对话时,发送给后端的并不是简单的消息数组,而是经过精心设计的上下文管理结果,也就是我们常说的context engineering。这个工程化的过程决定了哪些信息会被注入到实际的API请求中,以及如何组织这些信息以达到最佳效果。
以ChatGPT为例,每次API调用时,上下文的结构大致如下:
[0] System Instructions
[1] Developer Instructions
[2] Session Metadata (ephemeral)
[3] User Memory (long-term facts)
[4] Recent Conversations Summary (past chats, titles + snippets)
[5] Current Session Messages (this session)
[6] Your latest message
其中,层级0和1包含了系统级别的配置,如佬友们发现的juice参数、防injection指令、工具定义等就在这里;层级2则包含临时的会话元信息,如用户当前时间、IP所在地区等。这些内容在许多技术博客中都有详细分析,本文不再赘述。我们将重点聚焦于层级3、4、5,也就是记忆系统的核心实现部分。
理解这个分层结构非常重要,这告诉我们,所谓的"长期记忆"并不是模型本身的能力,而是通过巧妙的prompt engineering和数据管理实现的。每次对话时,相关的历史信息会被检索出来,动态注入到上下文中,让模型看起来记得你。
ChatGPT的长期记忆架构
整体设计概览
ChatGPT的长期记忆系统采用了三层设计:一个显性维护的记忆列表(memory)、一个最近会话摘要系统(recent conversations summary),以及一个隐性的用户洞察系统(user insight)。
从上下文结构来看,显性记忆列表对应层级3的user memory,最近会话摘要对应层级4,而用户洞察系统则可能位于层级0或1中。这三个组件协同工作,共同构成了ChatGPT的记忆能力。虽然关于ChatGPT具体的prompt框架细节无需过多深究,但这套记忆系统中的诸多设计思路,非常值得我们在实际工程中借鉴。
上下文窗口的滚动管理
在讨论长期记忆之前,我们需要先理解当前会话(current session)的上下文管理机制。用传统的prompt角色概念来理解,current session messages就是assistant prompt和user prompt的交替序列。
这里的一个关键点是:模型的回复与用户的提问并不是全部无限制地保留在上下文中,而是通过滚动窗口机制进行管理。
我们知道,模型的输入长度存在物理上限。例如GPT-5.2的文档标注为40万token,但实际可用约为272k;DeepSeek V3为128k;Gemini 3flash则达到了1M(Opus4.6好像也是,不过长上下文要加钱)。然而,更长的上下文并不总是更好——随着上下文长度增加,模型的召回率会下降,这在学术界被称为"lost in the middle"现象。过长的上下文会导致模型"降智",这是不可避免的。
image1768×512 88.5 KB
ChatGPT采用的策略相对简单粗暴:当消息序列的token总和超过上下文上限时,直接从最早的消息开始裁剪。
举个具体的例子:假设某个模型的输入上限是60 token,system prompt占10 token,每个user prompt和assistant prompt也各占10 token。你与AI进行了三轮对话,产生了user prompt 1、assistant prompt 1、user prompt 2、assistant prompt 2、user prompt 3、assistant prompt 3。此时你发送第四条消息user prompt 4,总上下文变为:system prompt (10) + 三轮对话 (60) + 当前消息 (10) = 80 token,超出了20 token的限制。
此时ChatGPT会将最早的一轮对话——也就是user prompt 1和assistant prompt 1——完全移除,使剩余内容刚好满足60 token的限制。
这种机制的含义很明确:被裁剪掉的信息会永久从当前会话中消失。ChatGPT并没有采用上下文压缩或摘要技术来保留这些信息,这意味着如果某条重要信息没有被提取到层级3或4的记忆系统中,它就会随着对话的进行而丢失。
从信息论角度理解上下文管理
要理解为什么上下文管理如此重要,我们可以从信息论的角度来思考。
在信息论中,信息量与不确定性的减少程度相关。一个消息传递的信息越多,它能够排除的可能性就越多。这个概念看起来抽象,但在日常沟通中我们无时无刻不在应用。
想象这样一个场景:你和佬友约定周末线下面基,已经确定了在上海碰头。这时候,如果你说"我在人民广场星巴克等你",这句话传递的有效信息是"人民广场"和"星巴克";而如果你说"我在中国上海市黄浦区人民广场某号某栋星巴克咖啡厅等你",前面的"中国上海市"其实是冗余信息——你们都已经知道在上海见面了。
同样的道理,在与AI的对话中,如果system prompt已经注入了"今天是2026年2月6日星期五",那么你在user prompt中再次说"今天是星期五"就是信息冗余,浪费了宝贵的token空间。
信息密度的另一个维度是具体性。"我老婆昨晚没回家"这句话留下了很多不确定性——可能是加班、可能是和朋友聚会、可能是出差;而"我老婆出轨了"则是一个高信息密度的陈述,它大幅减少了可能性空间。在AI对话中,提供高信息密度的上下文,能够让模型更准确地理解你的意图,减少无关回复的可能性。
在当今的大语言模型时代,动辄数百k甚至上M的上下文窗口,对于绝大多数对话来说都是足够的。真正的挑战不在于空间大小,而在于如何在有限的空间中放入最有价值的信息。这就是为什么我们需要精心设计的记忆系统——它的作用是从海量的历史交互中,检索出与当前对话最相关的信息,而不是一股脑地把所有历史都塞进上下文。
User Memory的实现机制
现在让我们回到ChatGPT的上下文结构,其中的user memory(层级3)和recent conversations summary(层级4)构成了所谓的长期记忆。
image1200×449 86.3 KB
User memory是一个相对稳定的、对用户特征进行结构化存储的系统。根据Mathan的逆向工程博客,ChatGPT在system prompt中注入了一个名为bio的工具定义。当模型检测到user prompt中包含与用户档案相关的信息时,它会主动调用这个工具来存储记忆。这些存储的记忆条目可以在设置界面中查看和管理,形成了一个用户可见、可编辑的记忆列表。
image1946×418 78.7 KB
然而,实际的实现比文档中描述的更加复杂。根据我的测试,ChatGPT并不是每次都将所有的user memory全部注入上下文,而是使用RAG进行检索匹配。也就是说,系统会根据当前的user prompt,从记忆库中检索出最相关的若干条bio记录,然后注入到上下文中。
有趣的是,ChatGPT似乎并没有提供显性的工具让模型在推理过程中主动搜索记忆(也就是所谓的agentic RAG)。RAG检索发生在上下文构建阶段,而不是在模型的工作流中。这种设计更加简单可靠,但灵活性稍弱。
image1910×1476 177 KB
Conversation History的复杂系统
相比于user memory的相对简单,conversation history是一个设计更为精巧的系统。
从表面上看,recent conversation summary的实现逻辑类似于一个简单的SQL查询:SELECT * FROM chat_message WHERE user_id = ? ORDER BY created_at DESC LIMIT N,即提取最近N个会话的摘要并注入上下文。根据Mathan的测试,ChatGPT大约会保留15条最近会话的摘要,格式类似:
- <Timestamp>:<Chat Title>
|||| user message snippet ||||
|||| user message snippet ||||
然而,Macro的另一篇博文提出了不同的观点。他认为ChatGPT使用了RAG,在一个两周的时间窗口内,根据当前query检索相关的若干条session,并且模型能够逐字复述其中的信息。这与Mathan的"保存user prompt摘要"的观点在数据层面是一致的——无论是通过摘要内容索引还是通过原始user prompt索引,RAG的效果本质上并无太大区别。
但我倾向于认为,ChatGPT在这一层并没有直接使用RAG,而是采用了更巧妙的两阶段检索策略。原因在于:长期记忆的核心功能已经通过user memory和user insight(稍后讨论)完全覆盖,conversation history的主要作用是提供短期记忆的连贯性,让跨会话的对话更加自然。如果在此处再引入一次RAG检索,会与user memory的RAG产生功能重叠,显得冗余。
在实际测试中,我验证了ChatGPT确实使用了一种两阶段RAG策略。如下图所示,通过询问历史对话的细节,ChatGPT不仅回答了相关问题,还提到了一些在设置中不可见的时间标记信息。这说明存在一个更高层次的检索逻辑:
-
首先通过RAG匹配相关的bio记录,这些bio带有时间区间标记
-
然后在这些时间区间内,再次使用RAG检索top-k个相关的conversation摘要
-
同时,无论是否匹配到相关bio,都会加入固定数量的最近session摘要
这种设计非常巧妙。它既保证了时间局部性(最近的对话总是可见),又通过bio作为"索引"实现了对历史深处相关信息的精准检索。这避免了单纯按时间顺序检索导致的信息丢失,也避免了全局RAG可能带来的性能开销和不稳定性。
image966×818 135 KB
User Insight隐性系统
除了上述两个显性的记忆系统,Macro的博文还揭示了一个更加隐蔽的组件:user insight系统。
这是一个用户不可见、不可编辑的隐性系统,据推测是通过定时任务或特定触发条件来更新的。User insight与bio的最大区别在于,它不是简单的事实性记忆列表,而是对用户偏好、交流风格、思维特点的高层次总结。
在我的测试中,ChatGPT的反应颇为有趣。当我询问是否存在user insight系统时,它先是含糊其辞,随后在追问下间接承认了这个系统的存在,并且明确告诉我:它被禁止向用户透露user insight的存在。这可以说是此地无银三百两。
image722×662 100 KBimage858×1378 148 KB
从工程角度来看,user insight的设计是合理的。Bio记录是连续的用户记忆,如"他写了一个博客文章"、”他今天吃了碗炸酱面";而user insight则是整体性的画像,如"这个用户倾向于直奔主题,不喜欢冗长的铺垫,在技术讨论中偏好深度而非广度"。这种高层次的总结可以更好地指导模型的回复风格,而不仅仅是提供事实性信息。
Claude的记忆系统分析
相比ChatGPT,Claude的记忆系统采用了截然不同的设计哲学。由于我个人对Claude客户端使用较少(GPT Teams的agent mode实在太好用了),这部分的分析主要基于Mathan的博客总结。这位作者的逆向工程工作相当透彻,感兴趣的读者可以查阅原文获取更多细节。
Claude的最大特点是完全放弃了传统的RAG自动注入方式,转而采用agentic RAG——也就是将会话搜索和记忆搜索作为工具直接暴露给模型,由模型自主决定何时、如何检索记忆。
这种设计与Claude的整体产品策略是一致的。如果你使用过Claude Code,你会发现它也是通过工具调用的方式,让模型主动进行关键词搜索。这种agentic的实现方式显然更加灵活,模型可以根据对话的上下文动态决定是否需要查阅历史记忆,甚至可以进行多轮检索来找到所需信息。
然而,这种设计也有其代价。首先,它高度依赖模型的能力——模型需要准确判断何时需要检索、使用什么关键词检索、如何整合检索结果。如果模型能力不足,或者在本地部署时使用较弱的模型,效果可能会大打折扣。其次,由于没有自动注入相关的会话摘要,完全依赖模型主动检索,可能会存在信息遗漏的风险。毕竟RAG的语义搜索能力是经过验证的,而模型的主动检索更多依赖prompt理解和关键词提取。
从工程实践的角度,我个人更倾向于ChatGPT的多层设计。特别是通过bio的时间戳索引来检索相关会话摘要的方式,在保证灵活性的同时,也提供了稳定性保障。
两种方案的选择,本质上是在模型依赖度和系统可控性之间做权衡。ChatGPT的方案更加工程化,适合需要稳定可靠表现的生产环境;Claude的方案更加前沿,适合追求极致体验并且不介意偶尔出现意外的场景。
开源客户端的实现方案
在开源领域,Cherry Studio和Open-Web-UI代表了两种不同的技术路线,它们的设计思路与ChatGPT和Claude颇为相似。
Cherry Studio采用的是直接RAG方式。每次对话结束后,系统会自动提取并存储一条记忆。经过一段时间的使用,我的记忆库已经积累了近200条记录。值得称赞的是,Cherry并不是简单粗暴地堆砌记忆,而是在存储过程中进行了去重和去矛盾处理。根据官方文档,系统会检测新记忆是否与已有记忆重复或冲突,如果存在冲突则会进行合并或更新。这种设计虽然简单,但在实践中效果不错。
Open-Web-UI则选择了agentic RAG路线,让模型自主选择何时搜索、更新或添加记忆。这种方式更加灵活,但对模型能力的要求也更高。使用较弱的模型时,可能会出现该搜索时不搜索、不该搜索时频繁搜索的情况。
两者的共同优势在于开源和透明——所有记忆都在设置中清晰呈现,支持完整的CRUD操作。用户可以随时查看、编辑、删除任何一条记忆,不存在像ChatGPT的user insight那样的"黑箱"组件。
然而,这两个客户端明显缺乏更复杂的多层架构设计。它们都只有单一的记忆列表,没有区分稳定的用户画像(bio)和动态的会话摘要,也没有类似user insight的高层次总结。对于短期使用或记忆量较少的场景,这样的设计完全够用;但对于长期使用的重度用户,或者对记忆管理有更高要求的技术爱好者来说,仍然存在改进空间。
复现与改进方案:融合最优设计
基于对ChatGPT、Claude以及开源客户端的分析,我设计了一个融合各家优势的记忆系统架构。这个方案试图在稳定性和灵活性之间找到平衡点,既保留自动化记忆管理的可靠性,又提供agentic检索的灵活性。
系统架构设计
整个系统分为三个核心组件:原子记忆(atomic memory)、用户画像(user profile)和文件夹记忆(folder memory)。
原子记忆是整个系统的基础单元。每条原子记忆包含以下字段:
-
ID:唯一标识符
-
Timestamp:创建时间戳
-
Content:记忆内容,控制在三到四句话的长度,形成一个完整的语义段落
-
Tags:若干个标签,用于分类和快速检索
原子记忆的设计借鉴了ChatGPT的bio,但存储粒度更细、频率更高。这样做的好处是能够捕捉更多的交互细节,同时每条记忆的长度适中,既不会太长导致RAG匹配不精准,也不会太短丢失上下文信息。
用户画像对应ChatGPT的user insight,是一个动态维护的结构化文档。它包含用户的回答风格偏好、语言习惯、主要的个人背景信息等。与user insight不同的是,这个画像是用户可见、可编辑的,增加了系统的透明度。
文件夹记忆是一个创新性的设计。考虑到许多用户会按照项目、主题来组织对话,文件夹级别的记忆可以捕捉特定主题下的上下文信息。例如,你可能有一个"工作项目A"的文件夹和一个"学习笔记"的文件夹,两者的记忆应该是隔离的。
在这个设计中,我舍弃了独立的会话级别摘要。原因是原子记忆的存储频率已经足够高,特别是设置了"每个新会话的首条消息必须存储记忆"的规则后,原子记忆本身就能提供足够的会话连续性。这样做的好处是减少了系统复杂度,同时降低了embedding的计算成本。
记忆检索与存储机制
在运行时,系统采用双通道检索策略:
被动RAG:每次用户发送消息时,系统自动通过RAG检索top-N条相关的原子记忆,注入到上下文中。同时,用户画像和当前文件夹的记忆文档会被自动加载。这个通道保证了基本的记忆功能,无需模型主动干预。
主动RAG(agenticRAG):将记忆搜索作为一个工具暴露给模型。模型可以使用关键词主动搜索记忆库,这在某些边缘场景下非常有用。例如,当用户的提问本身不够准确,或者自动RAG没有检索到关键信息时,模型可以通过工具调用进行补充检索。
记忆的存储采用异步机制。当用户发送消息后,系统会立即进行被动检索并生成回复,不阻塞用户体验。同时,启动一个异步的记忆处理流程:
-
分析user prompt的内容
-
如果包含值得记录的新信息,存入原子记忆
-
如果包含偏好或风格相关的信息,更新用户画像
-
如果在特定文件夹中,更新文件夹记忆
这个异步流程由单独的LLM调用完成,不会影响主对话的响应速度。
时间区间检索功能
ChatGPT通过bio时间戳索引相关会话的设计非常巧妙,但它是一个自动的、用户不可见的过程。在我的方案中,我将这个功能显性化为一个工具。
原子记忆除了文本内容外,还包含时间戳信息。当模型暴露给用户的搜索工具定义中,包含一个可选的时间范围参数。在工具的说明中,明确提示模型:如果用户询问的是某个时间段的经历或信息,需要添加时间参数进行过滤。
这个设计既保留了灵活性,又不会增加系统复杂度。对于大多数不涉及时间的查询,模型使用普通的语义检索即可;只有在明确需要时间过滤的场景下,才会使用时间参数。
可配置性与透明度
最后,所有的记忆功能都应该是用户可配置的。包括:
-
原子记忆的存储频率和长度限制
-
RAG检索时的top-N参数
-
是否启用主动检索工具
-
用户画像和文件夹记忆的开关
同时,所有记忆都支持完整的CRUD操作,用户可以随时查看、编辑、删除任何一条记忆。这种透明度是开源项目的优势,也是对用户隐私的尊重。
可视化上下文管理
记忆系统的最终目标是让上下文工程变得可视化和可控。在我设计的客户端Prompt-Tree中,所有被调用的记忆都会实时显示在一个context box中。用户可以清楚地看到哪些记忆被注入了上下文,并且可以自由编辑、移除或压缩这些内容。
这种设计完美解决了ChatGPT和Claude中滚动窗口的痛点。在传统的设计中,当上下文超出限制时,早期的消息会被无声地丢弃,用户完全无法干预。而在可视化的上下文管理中,用户可以主动删除不重要的消息,或者将长消息压缩为摘要,从而为真正重要的信息腾出空间。
image2932×1660 192 KBimage2938×1664 175 KBimage1920×1100 99.7 KBimage1920×1088 184 KB
此外,我还将每次对话建模为一个树节点,形成类似Git的对话树结构。用户可以在不同的对话分支间自由切换,可以从历史的某个节点开始新的分支,也可以对比多个模型在同一问题上的不同回复。这种设计极大地增强了对话的灵活性和可探索性。
GitHub - yxp934/Prompt-Tree: A local AI client with Git‑style tree context....
A local AI client with Git‑style tree context. Branch conversations, compress long chats, and visually assemble per‑request context to avoid LLM “long-chat degradation.
总结与展望
本文系统梳理了ChatGPT和Claude的长期记忆实现机制,并基于开源客户端的实践,提出了一个融合各家优势的改进方案。
从技术角度看,长期记忆系统本质上是prompt engineering和数据管理的结合。通过RAG检索、多层架构设计、异步处理等工程手段,我们可以在有限的上下文窗口内,为模型提供最相关的历史信息,从而实现跨会话的连续体验。
ChatGPT的方案更加工程化,通过多层记忆和巧妙的检索策略保证了稳定性;Claude的方案更加前沿,将更多的控制权交给模型本身。两者各有优劣,选择哪种方案取决于具体的应用场景和对模型能力的预期。
对于开发者而言,理解这些设计思路有助于我们构建更智能的AI应用。无论是开发客户端、设计AI agent,还是优化产品的用户体验,记忆管理都是一个不可忽视的环节。随着模型能力的不断提升,我相信会有更多创新的记忆系统设计涌现出来。
我的目标是打造一个集成所有优秀设计理念的开源客户端。上下文管理问题已经有了清晰的解决方案,接下来的重点是进一步增强agentic能力,让AI助手能够更加主动、智能地利用工具和记忆。欢迎佬友们下载、fork、issue、讨论,共同构建更强大的开源AI客户端。
参考资料
I Reverse Engineered Claude's Memory System, and Here's What I Found! - Manthan
When I reverse-engineered ChatGPT’s memory system, I found it uses pre-computed summaries injected into every prompt. But Claude’s approach is different. Through extensive experimentation, I discovered Claude uses on-demand tools and selective...
逆向工程:ChatGPT 的记忆是如何工作的 前沿快讯首先声明:本文章部分是搬运AI寒武纪。(不知是否符合站内规则) 因为我也在尝试复刻ChatGPT的一些功能,所以比较关注。 我也在用魔法打败魔法: 一张图片 这篇文章是名为eric 工程师对ChatGPT记忆系统的深度逆向工程和技术实现推测。它详细拆解了“可保存记忆”和包含“当前会话历史”、“对话历史”、“用户洞察”三个子系统的“聊天历史”,分析了它们的工作原理、可能的实现方案(如向…
I Reverse Engineered ChatGPT's Memory System, and Here's What I Found! - Manthan
When I asked ChatGPT what it remembered about me, it listed 33 facts from my name and career goals to my current fitness routine. But how does it actually store and retrieve this information? And why does it feel so seamless? After extensive...
网友解答:--【壹】--:
学习一下
--【贰】--:
爱了爱了
佬,想问问是每一条用户消息都会触发异步的user_memery是否存储的检测吗?
如何定义哪些信息有被存储的价值,如果有信息冲突是直接将过时记忆合并还是做增量的记忆更新说明呢
--【叁】--:
谢谢支持
--【肆】--:
千问点杯奶茶喝着看就不疼了
--【伍】--:
复现的bio功能中把时间戳暴露给模型,同时模型可以根据时间检索记忆,所以模型是有时间的概念的。但是我没有做被动的最近记忆的直接注入,一会去加个功能
--【陆】--:
纯干活
--【柒】--:
深度好文,爱了
--【捌】--:
好干的干货,支持一下
--【玖】--:
感谢佬的分享
--【拾】--:
不赖,支持一下
--【拾壹】--:
好文章,学习了
--【拾贰】--:
佬们记得给个star,欢迎fork提issue
--【拾叁】--:
感谢干货 mark
--【拾肆】--:
考不考虑时间衰减的问题?越新的记忆分数越高
--【拾伍】--:
收藏后看
--【拾陆】--:
好东西,感觉对项目有用,支持一下
--【拾柒】--:
妈呀,天天看技术贴,脑袋好疼啊
--【拾捌】--:
深度好文,来支持了!
--【拾玖】--:
难得看到如此干货,赞!!
引言
佬们如果曾经深入使用过ChatGPT或Claude,一定会注意他们的记忆功能:他们似乎记得你,能够在新的对话中回忆起你的偏好、背景信息,甚至几周前讨论过的话题细节。这种跨会话的记忆能力,远远超出了单次对话中的上下文窗口管理,背后是一套精心设计的长期记忆系统。
本文基于多篇逆向工程博客,结合我长期使用ChatGPT和Claude的实践经验,对两者的长期记忆实现方式进行了系统性的梳理和分析。需要说明的是,这篇文章更侧重于从产品和工程实现的角度进行剖析,而非底层代码实现。即使你没有深厚的理工背景,也能够理解这些系统的设计思路和工程实践价值。
由于CLoseAI在system prompt中包含了明确的防injection指令,并且专门训练防止被套取内部实现细节,因此不同于Claude在博客上公开分享的诸多技术细节,OpenAI的记忆系统大多依赖逆向工程推测。本文将综合这些研究成果,揭示这两个主流AI助手在长期记忆上的异同。
从API到客户端的上下文管理
在深入讨论长期记忆系统之前,我们需要先理清一些基础但容易混淆的概念,懂的佬麻烦直接跳过。Session、thread、prompt、chat等术语在不同的上下文中往往有不同的含义,业界并没有统一的定义标准。我们在这里将session和thread看作你开的一个对话窗口里所有消息的集合。prompt和chat则对应你发的每一条消息或模型的回复。
从API层面来看,OpenAI和Anthropic采用了不同的数据格式。OpenAI使用JSON格式的chat completion API,将每条消息分为system、user和assistant三种角色;而Anthropic则采用XML风格的格式,将user消息称为human消息。这些是我们在调用API时直接面对的接口层。
然而,真正的复杂性在于客户端实现。当你在ChatGPT或Claude的Web界面中进行对话时,发送给后端的并不是简单的消息数组,而是经过精心设计的上下文管理结果,也就是我们常说的context engineering。这个工程化的过程决定了哪些信息会被注入到实际的API请求中,以及如何组织这些信息以达到最佳效果。
以ChatGPT为例,每次API调用时,上下文的结构大致如下:
[0] System Instructions
[1] Developer Instructions
[2] Session Metadata (ephemeral)
[3] User Memory (long-term facts)
[4] Recent Conversations Summary (past chats, titles + snippets)
[5] Current Session Messages (this session)
[6] Your latest message
其中,层级0和1包含了系统级别的配置,如佬友们发现的juice参数、防injection指令、工具定义等就在这里;层级2则包含临时的会话元信息,如用户当前时间、IP所在地区等。这些内容在许多技术博客中都有详细分析,本文不再赘述。我们将重点聚焦于层级3、4、5,也就是记忆系统的核心实现部分。
理解这个分层结构非常重要,这告诉我们,所谓的"长期记忆"并不是模型本身的能力,而是通过巧妙的prompt engineering和数据管理实现的。每次对话时,相关的历史信息会被检索出来,动态注入到上下文中,让模型看起来记得你。
ChatGPT的长期记忆架构
整体设计概览
ChatGPT的长期记忆系统采用了三层设计:一个显性维护的记忆列表(memory)、一个最近会话摘要系统(recent conversations summary),以及一个隐性的用户洞察系统(user insight)。
从上下文结构来看,显性记忆列表对应层级3的user memory,最近会话摘要对应层级4,而用户洞察系统则可能位于层级0或1中。这三个组件协同工作,共同构成了ChatGPT的记忆能力。虽然关于ChatGPT具体的prompt框架细节无需过多深究,但这套记忆系统中的诸多设计思路,非常值得我们在实际工程中借鉴。
上下文窗口的滚动管理
在讨论长期记忆之前,我们需要先理解当前会话(current session)的上下文管理机制。用传统的prompt角色概念来理解,current session messages就是assistant prompt和user prompt的交替序列。
这里的一个关键点是:模型的回复与用户的提问并不是全部无限制地保留在上下文中,而是通过滚动窗口机制进行管理。
我们知道,模型的输入长度存在物理上限。例如GPT-5.2的文档标注为40万token,但实际可用约为272k;DeepSeek V3为128k;Gemini 3flash则达到了1M(Opus4.6好像也是,不过长上下文要加钱)。然而,更长的上下文并不总是更好——随着上下文长度增加,模型的召回率会下降,这在学术界被称为"lost in the middle"现象。过长的上下文会导致模型"降智",这是不可避免的。
image1768×512 88.5 KB
ChatGPT采用的策略相对简单粗暴:当消息序列的token总和超过上下文上限时,直接从最早的消息开始裁剪。
举个具体的例子:假设某个模型的输入上限是60 token,system prompt占10 token,每个user prompt和assistant prompt也各占10 token。你与AI进行了三轮对话,产生了user prompt 1、assistant prompt 1、user prompt 2、assistant prompt 2、user prompt 3、assistant prompt 3。此时你发送第四条消息user prompt 4,总上下文变为:system prompt (10) + 三轮对话 (60) + 当前消息 (10) = 80 token,超出了20 token的限制。
此时ChatGPT会将最早的一轮对话——也就是user prompt 1和assistant prompt 1——完全移除,使剩余内容刚好满足60 token的限制。
这种机制的含义很明确:被裁剪掉的信息会永久从当前会话中消失。ChatGPT并没有采用上下文压缩或摘要技术来保留这些信息,这意味着如果某条重要信息没有被提取到层级3或4的记忆系统中,它就会随着对话的进行而丢失。
从信息论角度理解上下文管理
要理解为什么上下文管理如此重要,我们可以从信息论的角度来思考。
在信息论中,信息量与不确定性的减少程度相关。一个消息传递的信息越多,它能够排除的可能性就越多。这个概念看起来抽象,但在日常沟通中我们无时无刻不在应用。
想象这样一个场景:你和佬友约定周末线下面基,已经确定了在上海碰头。这时候,如果你说"我在人民广场星巴克等你",这句话传递的有效信息是"人民广场"和"星巴克";而如果你说"我在中国上海市黄浦区人民广场某号某栋星巴克咖啡厅等你",前面的"中国上海市"其实是冗余信息——你们都已经知道在上海见面了。
同样的道理,在与AI的对话中,如果system prompt已经注入了"今天是2026年2月6日星期五",那么你在user prompt中再次说"今天是星期五"就是信息冗余,浪费了宝贵的token空间。
信息密度的另一个维度是具体性。"我老婆昨晚没回家"这句话留下了很多不确定性——可能是加班、可能是和朋友聚会、可能是出差;而"我老婆出轨了"则是一个高信息密度的陈述,它大幅减少了可能性空间。在AI对话中,提供高信息密度的上下文,能够让模型更准确地理解你的意图,减少无关回复的可能性。
在当今的大语言模型时代,动辄数百k甚至上M的上下文窗口,对于绝大多数对话来说都是足够的。真正的挑战不在于空间大小,而在于如何在有限的空间中放入最有价值的信息。这就是为什么我们需要精心设计的记忆系统——它的作用是从海量的历史交互中,检索出与当前对话最相关的信息,而不是一股脑地把所有历史都塞进上下文。
User Memory的实现机制
现在让我们回到ChatGPT的上下文结构,其中的user memory(层级3)和recent conversations summary(层级4)构成了所谓的长期记忆。
image1200×449 86.3 KB
User memory是一个相对稳定的、对用户特征进行结构化存储的系统。根据Mathan的逆向工程博客,ChatGPT在system prompt中注入了一个名为bio的工具定义。当模型检测到user prompt中包含与用户档案相关的信息时,它会主动调用这个工具来存储记忆。这些存储的记忆条目可以在设置界面中查看和管理,形成了一个用户可见、可编辑的记忆列表。
image1946×418 78.7 KB
然而,实际的实现比文档中描述的更加复杂。根据我的测试,ChatGPT并不是每次都将所有的user memory全部注入上下文,而是使用RAG进行检索匹配。也就是说,系统会根据当前的user prompt,从记忆库中检索出最相关的若干条bio记录,然后注入到上下文中。
有趣的是,ChatGPT似乎并没有提供显性的工具让模型在推理过程中主动搜索记忆(也就是所谓的agentic RAG)。RAG检索发生在上下文构建阶段,而不是在模型的工作流中。这种设计更加简单可靠,但灵活性稍弱。
image1910×1476 177 KB
Conversation History的复杂系统
相比于user memory的相对简单,conversation history是一个设计更为精巧的系统。
从表面上看,recent conversation summary的实现逻辑类似于一个简单的SQL查询:SELECT * FROM chat_message WHERE user_id = ? ORDER BY created_at DESC LIMIT N,即提取最近N个会话的摘要并注入上下文。根据Mathan的测试,ChatGPT大约会保留15条最近会话的摘要,格式类似:
- <Timestamp>:<Chat Title>
|||| user message snippet ||||
|||| user message snippet ||||
然而,Macro的另一篇博文提出了不同的观点。他认为ChatGPT使用了RAG,在一个两周的时间窗口内,根据当前query检索相关的若干条session,并且模型能够逐字复述其中的信息。这与Mathan的"保存user prompt摘要"的观点在数据层面是一致的——无论是通过摘要内容索引还是通过原始user prompt索引,RAG的效果本质上并无太大区别。
但我倾向于认为,ChatGPT在这一层并没有直接使用RAG,而是采用了更巧妙的两阶段检索策略。原因在于:长期记忆的核心功能已经通过user memory和user insight(稍后讨论)完全覆盖,conversation history的主要作用是提供短期记忆的连贯性,让跨会话的对话更加自然。如果在此处再引入一次RAG检索,会与user memory的RAG产生功能重叠,显得冗余。
在实际测试中,我验证了ChatGPT确实使用了一种两阶段RAG策略。如下图所示,通过询问历史对话的细节,ChatGPT不仅回答了相关问题,还提到了一些在设置中不可见的时间标记信息。这说明存在一个更高层次的检索逻辑:
-
首先通过RAG匹配相关的bio记录,这些bio带有时间区间标记
-
然后在这些时间区间内,再次使用RAG检索top-k个相关的conversation摘要
-
同时,无论是否匹配到相关bio,都会加入固定数量的最近session摘要
这种设计非常巧妙。它既保证了时间局部性(最近的对话总是可见),又通过bio作为"索引"实现了对历史深处相关信息的精准检索。这避免了单纯按时间顺序检索导致的信息丢失,也避免了全局RAG可能带来的性能开销和不稳定性。
image966×818 135 KB
User Insight隐性系统
除了上述两个显性的记忆系统,Macro的博文还揭示了一个更加隐蔽的组件:user insight系统。
这是一个用户不可见、不可编辑的隐性系统,据推测是通过定时任务或特定触发条件来更新的。User insight与bio的最大区别在于,它不是简单的事实性记忆列表,而是对用户偏好、交流风格、思维特点的高层次总结。
在我的测试中,ChatGPT的反应颇为有趣。当我询问是否存在user insight系统时,它先是含糊其辞,随后在追问下间接承认了这个系统的存在,并且明确告诉我:它被禁止向用户透露user insight的存在。这可以说是此地无银三百两。
image722×662 100 KBimage858×1378 148 KB
从工程角度来看,user insight的设计是合理的。Bio记录是连续的用户记忆,如"他写了一个博客文章"、”他今天吃了碗炸酱面";而user insight则是整体性的画像,如"这个用户倾向于直奔主题,不喜欢冗长的铺垫,在技术讨论中偏好深度而非广度"。这种高层次的总结可以更好地指导模型的回复风格,而不仅仅是提供事实性信息。
Claude的记忆系统分析
相比ChatGPT,Claude的记忆系统采用了截然不同的设计哲学。由于我个人对Claude客户端使用较少(GPT Teams的agent mode实在太好用了),这部分的分析主要基于Mathan的博客总结。这位作者的逆向工程工作相当透彻,感兴趣的读者可以查阅原文获取更多细节。
Claude的最大特点是完全放弃了传统的RAG自动注入方式,转而采用agentic RAG——也就是将会话搜索和记忆搜索作为工具直接暴露给模型,由模型自主决定何时、如何检索记忆。
这种设计与Claude的整体产品策略是一致的。如果你使用过Claude Code,你会发现它也是通过工具调用的方式,让模型主动进行关键词搜索。这种agentic的实现方式显然更加灵活,模型可以根据对话的上下文动态决定是否需要查阅历史记忆,甚至可以进行多轮检索来找到所需信息。
然而,这种设计也有其代价。首先,它高度依赖模型的能力——模型需要准确判断何时需要检索、使用什么关键词检索、如何整合检索结果。如果模型能力不足,或者在本地部署时使用较弱的模型,效果可能会大打折扣。其次,由于没有自动注入相关的会话摘要,完全依赖模型主动检索,可能会存在信息遗漏的风险。毕竟RAG的语义搜索能力是经过验证的,而模型的主动检索更多依赖prompt理解和关键词提取。
从工程实践的角度,我个人更倾向于ChatGPT的多层设计。特别是通过bio的时间戳索引来检索相关会话摘要的方式,在保证灵活性的同时,也提供了稳定性保障。
两种方案的选择,本质上是在模型依赖度和系统可控性之间做权衡。ChatGPT的方案更加工程化,适合需要稳定可靠表现的生产环境;Claude的方案更加前沿,适合追求极致体验并且不介意偶尔出现意外的场景。
开源客户端的实现方案
在开源领域,Cherry Studio和Open-Web-UI代表了两种不同的技术路线,它们的设计思路与ChatGPT和Claude颇为相似。
Cherry Studio采用的是直接RAG方式。每次对话结束后,系统会自动提取并存储一条记忆。经过一段时间的使用,我的记忆库已经积累了近200条记录。值得称赞的是,Cherry并不是简单粗暴地堆砌记忆,而是在存储过程中进行了去重和去矛盾处理。根据官方文档,系统会检测新记忆是否与已有记忆重复或冲突,如果存在冲突则会进行合并或更新。这种设计虽然简单,但在实践中效果不错。
Open-Web-UI则选择了agentic RAG路线,让模型自主选择何时搜索、更新或添加记忆。这种方式更加灵活,但对模型能力的要求也更高。使用较弱的模型时,可能会出现该搜索时不搜索、不该搜索时频繁搜索的情况。
两者的共同优势在于开源和透明——所有记忆都在设置中清晰呈现,支持完整的CRUD操作。用户可以随时查看、编辑、删除任何一条记忆,不存在像ChatGPT的user insight那样的"黑箱"组件。
然而,这两个客户端明显缺乏更复杂的多层架构设计。它们都只有单一的记忆列表,没有区分稳定的用户画像(bio)和动态的会话摘要,也没有类似user insight的高层次总结。对于短期使用或记忆量较少的场景,这样的设计完全够用;但对于长期使用的重度用户,或者对记忆管理有更高要求的技术爱好者来说,仍然存在改进空间。
复现与改进方案:融合最优设计
基于对ChatGPT、Claude以及开源客户端的分析,我设计了一个融合各家优势的记忆系统架构。这个方案试图在稳定性和灵活性之间找到平衡点,既保留自动化记忆管理的可靠性,又提供agentic检索的灵活性。
系统架构设计
整个系统分为三个核心组件:原子记忆(atomic memory)、用户画像(user profile)和文件夹记忆(folder memory)。
原子记忆是整个系统的基础单元。每条原子记忆包含以下字段:
-
ID:唯一标识符
-
Timestamp:创建时间戳
-
Content:记忆内容,控制在三到四句话的长度,形成一个完整的语义段落
-
Tags:若干个标签,用于分类和快速检索
原子记忆的设计借鉴了ChatGPT的bio,但存储粒度更细、频率更高。这样做的好处是能够捕捉更多的交互细节,同时每条记忆的长度适中,既不会太长导致RAG匹配不精准,也不会太短丢失上下文信息。
用户画像对应ChatGPT的user insight,是一个动态维护的结构化文档。它包含用户的回答风格偏好、语言习惯、主要的个人背景信息等。与user insight不同的是,这个画像是用户可见、可编辑的,增加了系统的透明度。
文件夹记忆是一个创新性的设计。考虑到许多用户会按照项目、主题来组织对话,文件夹级别的记忆可以捕捉特定主题下的上下文信息。例如,你可能有一个"工作项目A"的文件夹和一个"学习笔记"的文件夹,两者的记忆应该是隔离的。
在这个设计中,我舍弃了独立的会话级别摘要。原因是原子记忆的存储频率已经足够高,特别是设置了"每个新会话的首条消息必须存储记忆"的规则后,原子记忆本身就能提供足够的会话连续性。这样做的好处是减少了系统复杂度,同时降低了embedding的计算成本。
记忆检索与存储机制
在运行时,系统采用双通道检索策略:
被动RAG:每次用户发送消息时,系统自动通过RAG检索top-N条相关的原子记忆,注入到上下文中。同时,用户画像和当前文件夹的记忆文档会被自动加载。这个通道保证了基本的记忆功能,无需模型主动干预。
主动RAG(agenticRAG):将记忆搜索作为一个工具暴露给模型。模型可以使用关键词主动搜索记忆库,这在某些边缘场景下非常有用。例如,当用户的提问本身不够准确,或者自动RAG没有检索到关键信息时,模型可以通过工具调用进行补充检索。
记忆的存储采用异步机制。当用户发送消息后,系统会立即进行被动检索并生成回复,不阻塞用户体验。同时,启动一个异步的记忆处理流程:
-
分析user prompt的内容
-
如果包含值得记录的新信息,存入原子记忆
-
如果包含偏好或风格相关的信息,更新用户画像
-
如果在特定文件夹中,更新文件夹记忆
这个异步流程由单独的LLM调用完成,不会影响主对话的响应速度。
时间区间检索功能
ChatGPT通过bio时间戳索引相关会话的设计非常巧妙,但它是一个自动的、用户不可见的过程。在我的方案中,我将这个功能显性化为一个工具。
原子记忆除了文本内容外,还包含时间戳信息。当模型暴露给用户的搜索工具定义中,包含一个可选的时间范围参数。在工具的说明中,明确提示模型:如果用户询问的是某个时间段的经历或信息,需要添加时间参数进行过滤。
这个设计既保留了灵活性,又不会增加系统复杂度。对于大多数不涉及时间的查询,模型使用普通的语义检索即可;只有在明确需要时间过滤的场景下,才会使用时间参数。
可配置性与透明度
最后,所有的记忆功能都应该是用户可配置的。包括:
-
原子记忆的存储频率和长度限制
-
RAG检索时的top-N参数
-
是否启用主动检索工具
-
用户画像和文件夹记忆的开关
同时,所有记忆都支持完整的CRUD操作,用户可以随时查看、编辑、删除任何一条记忆。这种透明度是开源项目的优势,也是对用户隐私的尊重。
可视化上下文管理
记忆系统的最终目标是让上下文工程变得可视化和可控。在我设计的客户端Prompt-Tree中,所有被调用的记忆都会实时显示在一个context box中。用户可以清楚地看到哪些记忆被注入了上下文,并且可以自由编辑、移除或压缩这些内容。
这种设计完美解决了ChatGPT和Claude中滚动窗口的痛点。在传统的设计中,当上下文超出限制时,早期的消息会被无声地丢弃,用户完全无法干预。而在可视化的上下文管理中,用户可以主动删除不重要的消息,或者将长消息压缩为摘要,从而为真正重要的信息腾出空间。
image2932×1660 192 KBimage2938×1664 175 KBimage1920×1100 99.7 KBimage1920×1088 184 KB
此外,我还将每次对话建模为一个树节点,形成类似Git的对话树结构。用户可以在不同的对话分支间自由切换,可以从历史的某个节点开始新的分支,也可以对比多个模型在同一问题上的不同回复。这种设计极大地增强了对话的灵活性和可探索性。
GitHub - yxp934/Prompt-Tree: A local AI client with Git‑style tree context....
A local AI client with Git‑style tree context. Branch conversations, compress long chats, and visually assemble per‑request context to avoid LLM “long-chat degradation.
总结与展望
本文系统梳理了ChatGPT和Claude的长期记忆实现机制,并基于开源客户端的实践,提出了一个融合各家优势的改进方案。
从技术角度看,长期记忆系统本质上是prompt engineering和数据管理的结合。通过RAG检索、多层架构设计、异步处理等工程手段,我们可以在有限的上下文窗口内,为模型提供最相关的历史信息,从而实现跨会话的连续体验。
ChatGPT的方案更加工程化,通过多层记忆和巧妙的检索策略保证了稳定性;Claude的方案更加前沿,将更多的控制权交给模型本身。两者各有优劣,选择哪种方案取决于具体的应用场景和对模型能力的预期。
对于开发者而言,理解这些设计思路有助于我们构建更智能的AI应用。无论是开发客户端、设计AI agent,还是优化产品的用户体验,记忆管理都是一个不可忽视的环节。随着模型能力的不断提升,我相信会有更多创新的记忆系统设计涌现出来。
我的目标是打造一个集成所有优秀设计理念的开源客户端。上下文管理问题已经有了清晰的解决方案,接下来的重点是进一步增强agentic能力,让AI助手能够更加主动、智能地利用工具和记忆。欢迎佬友们下载、fork、issue、讨论,共同构建更强大的开源AI客户端。
参考资料
I Reverse Engineered Claude's Memory System, and Here's What I Found! - Manthan
When I reverse-engineered ChatGPT’s memory system, I found it uses pre-computed summaries injected into every prompt. But Claude’s approach is different. Through extensive experimentation, I discovered Claude uses on-demand tools and selective...
逆向工程:ChatGPT 的记忆是如何工作的 前沿快讯首先声明:本文章部分是搬运AI寒武纪。(不知是否符合站内规则) 因为我也在尝试复刻ChatGPT的一些功能,所以比较关注。 我也在用魔法打败魔法: 一张图片 这篇文章是名为eric 工程师对ChatGPT记忆系统的深度逆向工程和技术实现推测。它详细拆解了“可保存记忆”和包含“当前会话历史”、“对话历史”、“用户洞察”三个子系统的“聊天历史”,分析了它们的工作原理、可能的实现方案(如向…
I Reverse Engineered ChatGPT's Memory System, and Here's What I Found! - Manthan
When I asked ChatGPT what it remembered about me, it listed 33 facts from my name and career goals to my current fitness routine. But how does it actually store and retrieve this information? And why does it feel so seamless? After extensive...
网友解答:--【壹】--:
学习一下
--【贰】--:
爱了爱了
佬,想问问是每一条用户消息都会触发异步的user_memery是否存储的检测吗?
如何定义哪些信息有被存储的价值,如果有信息冲突是直接将过时记忆合并还是做增量的记忆更新说明呢
--【叁】--:
谢谢支持
--【肆】--:
千问点杯奶茶喝着看就不疼了
--【伍】--:
复现的bio功能中把时间戳暴露给模型,同时模型可以根据时间检索记忆,所以模型是有时间的概念的。但是我没有做被动的最近记忆的直接注入,一会去加个功能
--【陆】--:
纯干活
--【柒】--:
深度好文,爱了
--【捌】--:
好干的干货,支持一下
--【玖】--:
感谢佬的分享
--【拾】--:
不赖,支持一下
--【拾壹】--:
好文章,学习了
--【拾贰】--:
佬们记得给个star,欢迎fork提issue
--【拾叁】--:
感谢干货 mark
--【拾肆】--:
考不考虑时间衰减的问题?越新的记忆分数越高
--【拾伍】--:
收藏后看
--【拾陆】--:
好东西,感觉对项目有用,支持一下
--【拾柒】--:
妈呀,天天看技术贴,脑袋好疼啊
--【拾捌】--:
深度好文,来支持了!
--【拾玖】--:
难得看到如此干货,赞!!

