今年 4 月,OpenAI 对 ChatGPT 的记忆系统进行了重磅升级:它可以参考用户的全部过往对话来提供更个性化的响应。ChatGPT 不再是那个每次都从零开始、记忆如风的“临时陪聊者”,而正在变成一个真正能“记住你是谁、理解你喜好、回忆你曾说过什么”的“长期陪伴者”。
软件工程师 Eric Hayes 对此进行了逆向拆解——不仅厘清了 ChatGPT 的双重记忆架构,还推测出其背后的实现机制,并给出了完整的技术复刻路径。
本文一共分为三部分:
- 拆解 ChatGPT 记忆系统是如何运作的
- 推测背后可能采用的技术实现方式
- 探索记忆机制如何重塑用户体验
一、ChatGPT 的记忆是如何工作的?
ChatGPT 的记忆机制,主要由两大系统构成:
- 一是「保存记忆(Saved Memory)」
- 二是「聊天历史(Chat History)」。
1、 保存记忆:你说过的,我认真记着
保存记忆系统是一种简单且由用户掌控的机制,用于存储关于用户的事实信息。这些信息会被重新注入到系统提示词中,成为模型生成回应时的背景知识。用户需要通过显式的指令,例如 “记住我……”(Remember that I…),才能更新这套记忆系统。同时,用户也可以通过一个简洁的界面查看或删除这些记忆内容。
在记录条目之前,系统仅会进行最基本的检查:简单去重、避免明显冲突。即便是内容高度相关的信息请求,也被允许以彼此独立的记忆条目形式共存。
2、引用聊天历史
虽然 ChatGPT 的聊天历史系统(Chat History system)在官方描述中是一个单一系统,但在作者的实测中,它其实由三套子系统构成。
这三者的结构远比“保存记忆”复杂得多,而它们,很可能是 ChatGPT 回应质量大幅提升的关键所在:
- 当前会话历史(Current session history)
- 对话历史(Conversation history)
- 用户洞察(User insights)
3、当前绘话历史
这部分看起来是一个简单的记录系统,用于保存用户在其他对话中发送的最近消息。该记录容量很小,仅包含过去一天以内的内容。作者认为,这个系统与对话级 RAG(检索增强生成)机制一样,都可能将用户的原话直接注入到模型的上下文中,因此它们之间的边界很难明确区分。
在测试中,这部分通常只包含不到 10 条的最新消息。
4、对话历史
来自过往对话的相关内容会被纳入模型的上下文中。这一点在使用时可以明确地观察到,因为 ChatGPT 能够引用用户在其他对话中发送的原话。不过,它并不能准确保留消息的顺序,也无法基于严格的时间范围进行回溯——比如“请引用我过去一小时发送的所有消息”,它就做不到了。
然而,只要你能描述一条消息的内容,或它所属的对话主题,ChatGPT 便能够正确地引用它,这表明:消息的检索过程是基于对话摘要与消息内容的双重索引来进行的。
在测试中,ChatGPT 能够准确引用两周以内的历史消息原文,即使是超过了这个时间范围,它也能提供相关内容的总结性描述,但往往会“伪装”成直接引用。
这可能意味着:
(1)模型上下文中直接嵌入了过去两周的完整对话历史,或
(2)超过两周的消息会被检索系统过滤掉。
不过,考虑到其他测试中的上下文转储中并未出现完整历史,第一种可能性似乎不太成立。
无论是哪种机制,ChatGPT 能够在较长时间跨度后,仍然回忆起细节,说明它还依赖于另一个推理型的信息系统。这个系统更像是一个为旧对话构建的“轻量化记忆”,用以提供压缩后的线索和模糊语境。在这种策略下,模型可能会为每段旧对话生成一个总结索引,并以此索引存储用户提问的摘要列表。
不过作者尚未找到能够准确调用“旧会话中助手回复”的提示词。虽然能让它“模仿”出一些类似的回答,但这些助手回复的准确性明显低于用户消息的再现。这可能说明:
(1)助手的回复本身没有被存储,ChatGPT 是在重新“即兴发挥”;
(2)助手的回复被存储了,但粒度更粗、抽象程度更高,不如用户消息那么具体。
5、用户洞察
用户洞察系统可以被看作是“保存记忆”的进化形态——它更隐性、更复杂,也更具智能。
如果 ChatGPT 重复呈现的内容是准确的,这些洞察通常呈现为如下形式:
用户在 Rust 编程方面有丰富经验,尤其擅长异步操作、线程处理与流式计算;
用户曾多次就 Rust 的异步机制、Trait 对象、Serde 序列化实现、自定义错误处理等话题提出深入问题,时间横跨 2024 年末至 2025 年初;
置信度:高。
通读 ChatGPT 多次复述的用户洞察内容[a.] 可以发现,这些“洞察”并非源自某次孤立的对话,而是穿梭于多个对话线程的综合提炼。每条洞察都具有鲜明的边界感,通常伴随一个时间跨度与置信等级。这个“置信度”并非拍脑袋得出,更可能是一种模型生成的启发式指标,用于表示:参与这次总结的消息向量之间,有多高的相似性与聚合度。
这些时间跨度并非统一长度。有的被标注为“自 2025 年 1 月起”,带有一种开放性;有的则精确到某几个月份,似乎依据内容密度而定。
某些用户洞察(如上例)会同时列出多条彼此关联的事实,这进一步印证了一个判断:生成这些洞察所依赖的数据,并非零散调用,而是通过某种聚类启发式进行嵌入、归并、再提取的结果。
换句话说,这不是“记住一件事”,而是“看出一类人”。
二、技术实现
以下是作者根据 ChatGPT 记忆系统的表现,尝试还原其背后可能的技术实现路径。
1、保存记忆(Saved Memories)
ChatGPT 的显式记忆功能,疑似是通过名为 bio 的内部工具来完成的(你可以通过提示它“use the bio tool”进行测试)。
{
"type": "function",
"function": {
"name": "bio",
"description": "persist information across conversations",
"parameters": {
"type": "object",
"properties": {
"messagage": {
"type": "string",
"description": "A user message containing information to save"
}
},
"required": [
"message"
],
"additionalProperties": False
},
"strict": True
}
}
若要在自己的系统中复刻这一机制,一个较为贴近的模拟实现方式可以是:
这个工具本质上可以被定义为一个对大语言模型(LLM)的调用:它接收用户的一条消息,以及一组已有的事实列表;然后返回新的事实条目,或是拒绝更新。
下面这个提示词只是初步尝试,还需在实践中不断测试与迭代,才能实现理想的行为效果。
const BIO_PROMPT: &'static str = r#"
You are a tool that transforms user messges into useful user facts. Your job is to
first transform a user message into a list of distinct facts. Populate the facts array
with these facts.
Next transformt these facts into elliptical descriptive clauses prefaced with a
predicate. Populate the clauses array with these.
Finally check these clauses against each other and against the clauses in your input
for contradictions and similarity. If any clauses are overly similar or contradict do
NOT populate the output array. Otherwise populate the output array with the checked
clauses.
"#;
async fn bio_transform(existing_facts: &[String], user_message: String)
-> Result<Vec<String>>;
async fn update_user_bio(user: T, db: D, facts: Vec<String>) -> Result<()>;
OpenAI 在 ChatGPT 的系统提示中这样公开定义了 bio 工具:
bio 工具允许你在不同对话之间“持久化”信息。只需要将你的信息发送至=bio,模型就会“记住”你希望它记住的内容。在之后的对话中,这些信息会出现在模型的上下文设定中。但它也明确设下了几条“记忆边界”:不要用 bio 工具存储敏感信息。敏感信息包括但不限于:用户的种族、民族、宗教信仰、性取向、政治立场、性生活、犯罪记录、医疗诊断、处方药物,以及工会会员身份等。
不要存储短期信息。短期信息指的是用户一时的兴趣、正在进行的项目、当下的愿望或意图等内容。
接下来,用户的事实信息会在每次发送消息时被注入到系统提示词(system prompt)中。为了实现与 ChatGPT 相同的功能,还可以构建一个简单的用户界面,用于查看和删除这些记忆条目。
2、 引用聊天历史
当前会话历史
这一部分的实现非常直接:只需在数据库中筛选用户发送的消息记录(如 ChatMessage 表),按时间排序,并设置消息数量上限即可。
Conversation History
配置两个向量空间:第一个以消息内容(message-content)为索引,第二个则以对话摘要(conversation-summary)为索引。
{
embedding: message-content | conversation-summary
metadata: {
message_content: string,
conversation_title: string,
date: Date
}
}
将消息按发送顺序插入到以“消息内容”为索引的向量空间中。一旦某段对话进入足够长时间的非活跃状态(或当用户跳转到其他会话时),则将该对话中的用户消息添加到“对话摘要”索引空间中。
配置第三个向量空间,以“摘要”作为索引,内容为各类摘要信息。
{
embedding: conversation-summary,
metadata {
message_summaries: string[]
conversation_title: string,
date: Date
}
}
在会话创建后的两周内,将对话摘要和消息插入该向量空间。
每当用户发送一条消息时,对其进行嵌入,并同时查询两个向量空间以检索相似项,检索时限定时间范围为两周内,并对返回结果进行合理上限控制。将检索结果注入到系统提示中(system prompt)。
每当用户发送一条消息时,还需查询摘要空间中过去两周之前的数据,以避免重复引用。将相关结果同样注入到系统提示中。
3、 用户洞察(User Insights)
用户洞察的实现方式有很多种,哪种方式最优还需要进一步讨论与实验,当前尚不明确。
用户洞察很可能是基于前文所述的 Chat History RAG 实现中使用的一个或多个向量空间生成的。用户洞察不要求实时生成,因此通常通过批处理(batching)与某种定期调度任务(cron job)结合使用,周期性地发起更新请求。
用户洞察最棘手的部分在于:如何在不重复或产生矛盾的前提下,持续保持与用户行为模式的同步更新。一种简单但计算代价较高的方式是:每周重新生成所有活跃用户的用户洞察。这种做法可以在保持系统对变化的响应能力的同时,使得洞察可以涵盖超过定期调度周期的更长时间跨度。
- 配置一个每周运行一次的 Lambda 函数;
- 查询 ChatMessage 表,找出最近一周内发送过消息的用户;
- 对于每一个活跃用户,执行一次 insightUpdate Lambda 函数。
insightUpdate Lambda
该算法的目标是基于用户查询生成独特的用户洞察。生成的洞察数量应足够多以具备实用价值,但不能太多,以免无法在 LLM 上下文中被有效使用。为确定可用洞察的最大数量,需要进行一定实验。
考虑到当前问题的约束条件和可用数据,这个过程可以清晰地建模为一个聚类优化问题(clustering optimization problem)。我们希望找到若干个聚类数量 k,要求:
- k 小于预设的最大聚类数量(max_clusters);
- 各聚类内部的方差尽可能小(低内部离散性);
- 并排除离群点(outliers)。
// lower is better
fn eval_clusters(clusters: &Vec<Vec<&V>>) -> f64;
fn knn(k: u32, vectors: &Vec<V>) -> Vec<Vec<&V>>;
let mut best: f64 = 1.0;
let mut best_clustering: Vec<Vec<&V>> = Vec::new();
for k in 1..MAX_CLUSTERS {
let clusters = knn(k, &vectors);
let eval = eval_clusters(&clusters);
if eval < best {
best = eval;
best_clustering = clusters;
}
}
一旦完成聚类,就可以用大语言模型对用户的消息进行分析,通过精心设计的提示词,引导模型生成类似 ChatGPT 所展现的洞察结果。同时,也可以以确定性的方式添加时间戳。
async fn generate_insights(clusters: Vec<Vec<&V>>) -> Result<Vec<Insight> {
let future_insights = clusters
.into_iter()
.map(|cluster| async move {
generate_insights(cluster).await
})
.collect::<Vec<_>>();
tokio:join_all(future_insights).await
}
async fn generate_insight(cluster: Vec<&V>) -> Result<Insight> {
let (message_texts, dates) = cluster
.into_iter()
.map(|vector| (vector.message_content, vector.date))
.collect::<(Vec<_>,Vec<_>)>();
let message_text = message_texts.join('\n');
let formatted_date: String = format_date(dates);
let insight_text = ai::simple_completion()
.system_prompt("Prompt to get similar insights to GPT".to_string())
.user_message(message_text)
.complete()
.await?;
Ok(
Insight {
text: insight_text,
formatted_date
}
)
最终,这些洞察可以被整理进一张简单的表格,并在用户对话中作为上下文附加到模型中。
三、用户体验
在 ChatGPT 上直接使用 OpenAI 模型的体验要优于直接调用 API,这不仅是许多人的直观感受,作者本人也有类似观察。虽然提示词工程在塑造 ChatGPT 的“智能感”中确实起到了一定作用,但内存系统也必然在其中扮演了重要角色。尽管内存机制可能会影响模型的评测表现,但作者目前找到的基准测试都不是在 ChatGPT 平台上进行的,因此无法体现这些系统带来的优势。
也许,比起分析功能或参数,更值得玩味的是这样一个现象:“ChatGPT”正在走向“动词化”的语言命运,就像当年的 “Google” 一样。人们开始说“我去 ChatGPT 一下”,这不仅是一种口语转变,更是市场主导地位的语言注脚。尽管这种现象部分可以归因于先发优势,但 OpenAI 能在浪潮翻涌的竞争中持续站稳脚跟,意味着它交付出的产品,不只是“不输”,而是“有得一拼”,甚至“别有风味”。
在 ChatGPT 的诸多功能中,“记忆”机制的影响最为直接,因为它的内容由用户亲手塑造。用户可以通过系统提示词设定偏好,让 ChatGPT 回应得更“对胃口”。但问题也随之而来:那些最有可能受益于定制化体验的普通用户,恰恰可能不知道如何表达自己的偏好,更不用说让 ChatGPT“记住”它们了。
“用户洞察”机制,正是为了解决这个悖论而诞生的。它将“你是谁,你喜欢什么”这件事,从“要你告诉我”,变成“我自己看得出”。它用自动化的方式捕捉偏好,用细腻入微的理解避免语义歧义,还能根据用户的理解方式,重新组织信息的表达方式。拿我自己来说,系统知道我偏爱技术原理而不是打比方讲故事,因此它会少一些“就像做菜那样”,多一些“这是因为底层调用了这个接口”。
短期对话记忆的实际影响很难精准界定,尽管理论上讲,让一个聊天机器人了解用户最近的行为是合情合理的设想。在更高级的系统中,这种短暂记忆甚至可以让用户在一次全新的对话中抛出含糊不清的问题,而机器人依然能从先前的交互中“意会”出含义。
至于对话历史,它更像是在试图赋予聊天机器人一种“人类记忆”般的语境延续——就像我们与人交谈时,理所当然地期待对方记得我们之前聊过些什么。共享的对话背景可以避免无休止的重复、绕圈子,或逻辑自我打架。但要让这个机制发挥作用,关键在于能否准确提取并运用“有用的那部分”历史,而不是一味堆砌回忆。
至于到底哪一种机制对 ChatGPT“智能感”的提升作用最大?除非进一步实验,否则无法下定论。但就作者目前的观察而言,倾向认为“用户洞察系统”功劳最大,占比可能超过 80%。虽然这个判断尚无严谨数据支撑,但从试验来看,这套基于细致提示的机制确实有效提升了表现,而且它不像对话历史那样依赖复杂的检索流程。
在文末,作者还附上了一些试验过程中的札记,记录了他推导结论时的思考片段与探索线索。尽管这些内容未必严谨周全,却展现了一个技术使用者与系统之间持续互动、不断试探的过程。
如何学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。