简易版的ChatGPT核心逻辑实现,包括长期记忆及短期记忆的管理复用,提供了本地Json文件存储及Postgres存储两种示例,仅供学习。
这个仓库包含两个“带记忆的 ChatGPT”最小示例,各自独立,可分开运行:
-
mini-chatgpt通过本地 JSON 文件保存长期记忆,短期记忆保存在 Python 进程里的history列表中。 -
mini-chatgpt-langgraph通过 LangGraph 管理对话流程,短期记忆交给checkpointer,长期记忆交给PostgresStore。
这两个示例非常适合教学,因为它们展示了同一个核心问题的两种实现路径:
- 不依赖框架时,我们如何自己拼出一个“像 ChatGPT 一样”的记忆型助手
- 依赖 LangGraph 时,我们如何把记忆、线程、状态管理交给框架
读完并跑通这两个示例后,建议至少要搞懂下面三件事:
- 什么是短期记忆,什么是长期记忆
- ChatGPT 一轮对话的核心逻辑到底是什么
- 为什么“记忆”本质上不是模型参数,而是运行时上下文的一部分
可以把这两个项目理解为:
mini-chatgpt:手写版原理教学mini-chatgpt-langgraph:工程化版原理教学
很多同学第一次接触大模型应用时,会误以为“模型像人脑一样一直记得之前的内容”。
实际上,在应用层里,一个聊天助手更接近下面这个过程:
用户输入
-> 检索相关长期记忆
-> 拼接系统提示词 + 短期对话历史 + 当前问题
-> 调用大模型
-> 如果模型要用工具,就先执行工具
-> 再把工具结果喂回模型
-> 得到最终回答
也就是说,一个极简版 ChatGPT 往往由下面几层构成:
- 大模型:负责生成语言、理解上下文、决定是否调用工具
- 系统提示词:规定助手的角色、边界和行为规则
- 短期记忆:保存当前会话里最近几轮消息
- 长期记忆:保存跨会话仍然有价值的信息
- 工具系统:让模型可以“做事”,比如写入记忆
- 对话循环:模型回答一次,如果调用了工具,就继续循环直到产出最终文本
短期记忆可以理解为“当前会话上下文”。
它的特点是:
- 生命周期短,通常只在一个会话线程里有效
- 直接参与当前轮次的提示词拼接
- 更像“聊天记录”而不是“用户档案”
例如下面这些通常属于短期记忆:
- 用户刚刚问了什么
- 助手上一轮怎么回答的
- 当前这个任务的上下文
- 本轮工具执行完返回了什么
在本仓库里:
mini-chatgpt中,短期记忆就是mini-chatgpt/src/cli.py里的historymini-chatgpt-langgraph中,短期记忆由 LangGraph 的checkpointer按thread_id自动管理
长期记忆可以理解为“跨会话仍有价值的信息”。
它的特点是:
- 不只服务当前一轮对话
- 下一次打开新会话时仍然可能被检索出来
- 通常是用户画像、偏好、长期目标、持续项目、稳定事实
例如下面这些通常适合长期保存:
- 用户正在学习 Python
- 用户偏好中文回答
- 用户长期在做 LangGraph 相关项目
- 用户希望回答时先给结论再展开
而下面这些一般不适合写入长期记忆:
- “帮我把这一行代码改一下”
- “今天下午 3 点提醒我”
- “刚刚那条报错先忽略”
- 当前会话里的临时上下文
在这个仓库中,长期记忆被分成三类:
episodic:情景记忆,记录发生过的事件或经历semantic:语义记忆,记录稳定事实、偏好、身份、目标procedural:程序性记忆,记录用户希望助手长期遵循的协作方式
这部分规则主要写在两个项目的 prompts.py 和 mini-chatgpt-langgraph/src/prompts.py 中。
如果只保留最关键的主干逻辑,可以把这个仓库理解成下面这套流程:
这其实就是一个很典型的 Agent 最小闭环:
- 输入用户问题
- 找出和当前问题相关的长期记忆
- 把长期记忆和短期记忆一起塞进上下文
- 让模型决定是直接回答,还是先调用工具
- 如果模型调用
upsert_memory,就把新记忆保存下来 - 再让模型基于“工具执行后的结果”继续回答
这也是为什么很多人会说:
一个能工作的 ChatGPT 应用,不只是“调用一次模型 API”,而是“模型 + 上下文 + 工具 + 状态管理”。
| 维度 | mini-chatgpt |
mini-chatgpt-langgraph |
|---|---|---|
| 短期记忆 | 手动维护 history 列表 |
LangGraph checkpointer 按 thread_id 管理 |
| 长期记忆 | 本地 JSON 文件 | PostgresStore |
| 检索方式 | 本地 embedding + 相似度排序 | PostgresStore + 可选 pgvector |
| 对话流程 | 自己写循环 | 用 LangGraph Graph 承载 |
| 工程复杂度 | 更低,适合入门 | 更高,适合理解工程化 Agent |
| 教学重点 | 原理拆解最直观 | 状态管理和多会话更清晰 |
如果你是第一次学,建议阅读顺序是:
- 先看
mini-chatgpt - 再看
mini-chatgpt-langgraph - 最后对比两者“哪些代码是业务逻辑,哪些代码是框架接管的”
目录:
mini-chatgpt/main.pymini-chatgpt/src/cli.pymini-chatgpt/src/agent.pymini-chatgpt/src/store.pymini-chatgpt/src/tools.py
这个版本最适合拿来解释“记忆型 ChatGPT 的最小实现”。
核心思路是:
- 短期记忆:CLI 中维护
history - 长期记忆:每个用户对应一个本地 JSON 文件
- 每轮问答前:先用当前问题搜索相关长期记忆
- 每轮问答中:模型可以调用
upsert_memory写入新记忆 - 每轮结束后:把本轮用户消息和模型回复追加回
history
- 看入口
mini-chatgpt/main.py - 看交互循环
mini-chatgpt/src/cli.py - 看主逻辑
mini-chatgpt/src/agent.py - 看长期记忆存储
mini-chatgpt/src/store.py - 看模型如何调用记忆工具
mini-chatgpt/src/tools.py
MemoryAgent.respond():整轮对话的核心闭环JsonMemoryStore.search():如何把“记忆检索”接到回答前JsonMemoryStore.upsert():如何新增或更新长期记忆_format_memories():为什么要把检索结果格式化后注入系统提示词
- 好处:代码直白,最容易看懂原理
- 局限:短期记忆在进程内,程序退出后就没了;多会话管理也要自己做
目录:
mini-chatgpt-langgraph/main.pymini-chatgpt-langgraph/src/agent.pymini-chatgpt-langgraph/src/store.pymini-chatgpt-langgraph/src/cli.pymini-chatgpt-langgraph/src/tools.py
这个版本把“状态管理”进一步工程化了。
核心思路是:
- 短期记忆不再由我们手写
history - LangGraph 用
thread_id把每个会话线程隔离开 PostgresSaver保存短期对话快照PostgresStore保存长期记忆- Agent 逻辑仍然是“检索长期记忆 -> 调模型 -> 工具调用 -> 继续调模型”
- 看入口
mini-chatgpt-langgraph/main.py - 看 Graph 定义和
chat()节点mini-chatgpt-langgraph/src/agent.py - 看长期记忆存储
mini-chatgpt-langgraph/src/store.py - 看命令行如何切换会话
mini-chatgpt-langgraph/src/cli.py - 看记忆工具
mini-chatgpt-langgraph/src/tools.py
get_agent():LangGraph 图是怎么组装出来的invoke_agent():为什么同时需要thread_id和业务Contextchat():和 JSON 版相比,哪些逻辑没变,哪些被框架接管了clear_short()/clear_long():短期记忆和长期记忆为什么要分开清理
- 好处:更贴近真实项目,天然支持多线程、多会话、持久化短期状态
- 局限:抽象更多,初学者一开始可能不如 JSON 版直观
这是记忆系统里非常重要的一点。
user_id:表示“这个人是谁”thread_id:表示“当前这次会话是哪一条线程”
一个用户可以有很多会话线程,所以通常是:
- 长期记忆挂在
user_id上 - 短期记忆挂在
thread_id上
这也是 LangGraph 版更适合教学的一点,因为它把这两个概念分得很清楚。
因为模型不会天然知道什么值得长期保存。
如果你不给规则,它可能会:
- 把临时问题也存起来
- 把噪声信息当作长期偏好
- 重复保存相似记忆
- 把当前会话里的瞬时上下文错误地当成用户画像
所以在这类应用里,prompt 其实是在做一件很重要的事情:
它不是单纯让模型“说话更像助手”,而是在教模型如何做记忆决策。
因为模型的上下文窗口有限,不可能每次都把所有记忆全部塞进去。
一个常见模式就是:
- 用户发来新问题
- 用这个问题去搜最相关的几条长期记忆
- 只把最相关的记忆放进本轮系统提示词
- 模型基于“当前问题 + 相关记忆”回答
这就是检索增强的一种非常轻量的形式。
所以长期记忆系统并不是“模型永远记住了什么”,而是“应用在每一轮把有用信息重新拿给模型看”。
如果你是拿这个仓库做教学或自学练习,建议按下面顺序动手:
- 修改系统提示词,观察模型保存记忆的积极程度会怎么变化
- 故意输入一些“短期信息”,看模型是否会错误保存
- 为 JSON 版增加“只保留最近 N 轮短期消息”的逻辑
- 为 LangGraph 版增加“按 memory_type 分类查看记忆”的命令
- 尝试给长期记忆增加“重要度”字段
- 观察“有记忆”和“无记忆”时回答风格的差异
这些练习会帮助你真正理解:
- Prompt 会改变工具决策
- 记忆是应用层状态,而不是模型参数
- 框架并不会改变原理,只是帮你管理复杂度
如果是教学场景,我推荐按下面顺序讲:
- 先讲“普通聊天机器人为什么不是真正有记忆”
- 再讲短期记忆和长期记忆的区别
- 先带学生读 JSON 版
- 让学生自己画出
respond()的调用流程 - 再切到 LangGraph 版,看哪些代码被框架替代了
- 最后讨论工程化问题:多用户、多线程、数据库、检索、清理策略
这两个示例都依赖 DashScope 的兼容接口调用 Qwen,因此运行前至少需要准备:
DASHSCOPE_API_KEY
可以放到环境变量里,也可以写入 .env。
进入目录后执行:
cd mini-chatgpt
python main.py
用户ID = demo-user
模型 = qwen-plus
记忆目录 = .memory
已存储记忆数量 = 2
Commands: /help: 查看帮助 /memories: 查看当前用户所有长期记忆 /clear: 清楚当前用户所有长期记忆 /exit: 退出
[You]: 从当前提示可以看到,本地已经储存有两条记忆信息,并且可以通过命令 /memories 查看:
[You]: /memories
已保存记忆:
1. [semantic / 语义记忆] 用户籍贯为四川,当前常居地为上海 | 用户的地理背景信息,可能影响后续对地域相关话题(如饮食、方言、政策等)的交流
2. [episodic / 情景记忆] 用户曾用5天完成聊天机器人搭建,流程包括:梳理逻辑→绘制结构图→编码实现→调试/注释/修bug→发布 | 体现用户的项目执行能力、结构化思维和工程实践习惯,属于具体的一次性项目经历
[You]: 进一步,可直接输入相关内容与其进行交互,如果识别到新的记忆内容,也会进行保存:
[You]: 我有一个朋友叫张三,他是北京人,我们是大学同学。对了,今天北京天气怎么样?
有 1 条记忆插入
[Assistant]:
已为你保存这条语义记忆:
✅ 朋友张三,北京人,与你是大学同学。
这有助于我未来更自然地理解你们之间的关系背景(比如聊到母校、北京生活、学生时代等话题时)😊
至于**今天北京的天气**——虽然我无法实时联网查询......
欢迎告诉我你的偏好~ 🌤️
----------------------------------------------------------------------
[You]: 根据上述内容可以看出,用户的输入包含有记忆相关内容,智能体对其进行了保存,同时也输出了与北京天气相关的内容。此时,可以再次查看当前保存的记忆内容:
[You]: /memories
已保存记忆:
1. [semantic / 语义记忆] 用户籍贯为四川,当前常居地为上海 | 用户的地理背景信息,可能影响后续对地域相关话题(如饮食、方言、政策等)的交流
2. [episodic / 情景记忆] 用户曾用5天完成聊天机器人搭建,流程包括:梳理逻辑→绘制结构图→编码实现→调试/注释/修bug→发布 | 体现用户的项目执行能力、结构化思维和工程实践习惯,属于具体的一次性项目经历
3. [semantic / 语义记忆] 朋友张三,北京人,与用户是大学同学 | 属于用户长期人际关系信息,可能影响后续对话中对共同经历、地域背景或社交场景的理解常用命令:
/help/memories/clear/exit
这个版本除了模型 API Key,还需要 PostgreSQL。
环境变量:
DASHSCOPE_API_KEYPOSTGRES_URI
命令行模式:
cd mini-chatgpt-langgraph
python main.py --cli常用命令:
/new/thread <id>/memories/clear/clearall/id/exit
如果环境里装了 Streamlit,也可以直接运行页面版:
cd mini-chatgpt-langgraph
streamlit run main.py
You can now view your Streamlit app in your browser.
Local URL: http://localhost:8501
Network URL: http://192.168.0.109:8501此时可在浏览器中通过上面的链接打开。
首先,我们在会话 7c45cf2e-35…… 中告诉了智能体一些基本信息,智能体提取后作为记忆进行了保存,如图所示。
接着,新建对话并提问以验证长期记忆的有效性,如图所示。
长期记忆验证示意图从图中可以看出,智能体在回答问题以前的确加入了之前保存的长期记忆。作为验证,各位可以再次新建会话,同时点击左侧”删除长期记忆“按钮,此时再问智能体同样的问题便不会得到类似的答案。
如果只用一句话概括:
mini-chatgpt教你看懂“ChatGPT + 记忆”的原理骨架mini-chatgpt-langgraph教你理解“同样的原理如何走向工程化”
而这两个项目共同想说明的核心是:
大模型应用中的“记忆”,本质上是应用层对上下文和状态的组织,而不是模型自己永久记住了一切。
mini-chatgpt/src/agent.pymini-chatgpt/src/store.pymini-chatgpt-langgraph/src/agent.pymini-chatgpt-langgraph/src/store.py
如果你要做一次分享或授课,这四个文件基本就是整场内容的主线。


