阅读前须知-点我下拉
本篇文章为ReAct智能体架构系列的第二篇——记忆篇。在入门篇基础上,为你的小智能体装上"海马体",让它不再金鱼记忆。
前置要求:已完成入门篇的代码搭建,或至少理解了 agent.py 的基本结构。
所需工具及版本:
Python 3.10
OpenAI 2.32.0
任意大模型API
引言
上一篇文章我们搭好了ReAct智能体的骨架——它能查天气、能调工具,像模像样。但如果你真的跑起 main.py 和它聊上几轮,会发现一个尴尬的场面:
1 | 你:你好,我叫柏青 |
刚说完就忘,翻脸不认人——这不就是金鱼记忆吗?
入门篇末尾我也提了一句:“缺点:缺乏记忆功能(Memory)”。本篇就来填这个坑。我们会把messages从一个用完即弃的"便签纸",升级成智能体随身携带的"记忆本",让它真正具备多轮对话的能力。
记忆篇是入门篇的直接延续。如果你还没读过入门篇,建议先移步 ReAct智能体架构-入门篇 打好基础。
先诊断:为什么智能体会"失忆"?
让我们回到入门篇最终版的 agent.py,仔细看看 run() 方法的第一行:
1 | def run(self, user_input): |
发现问题了吗?每次调用 run(),messages 都被重新创建。就像你每次跟朋友聊天之前,先把聊天记录整本撕掉,只留下一句刚说的话——对方不懵才怪。
用一张图来感受:
1 | 第一次 run("你好,我叫柏青") |
每一轮对话之间是断裂的。模型只看到当前这一句话,完全没有上下文。这就是失忆的根源。
解决方案:给 messages 升个级
升级思路如下:
把
messages从run()里的局部变量,升级为Agent类的实例属性self.messages。
局部变量 = 一次性便签纸,函数结束就扔。
实例属性 = 绑定在对象身上的笔记本,只要智能体还活着,本子就在。
对比一下改动:
| 改造前(金鱼版🐟) | 改造后(记忆版🧠) | |
|---|---|---|
| messages 在哪 | run() 方法内(局部变量) |
__init__() 中初始化(实例属性) |
| 生命周期 | 每次调用 run() 重建 | 和 Agent 实例同生共死 |
| 多轮对话 | ❌ 每次失忆 | ✅ 完整保留上下文 |
| 引用方式 | messages |
self.messages |
逐步改造
1. 在 __init__() 中初始化记忆本
1 | class Agent: |
self.messages = [] 这行就是智能体的"出厂记忆"——刚出生时一片空白,等着被写入。
2. 给记忆本加一条"出厂设定"——System Prompt
光有空本子还不够,我们最好给智能体定个人设。就像新员工入职培训,告诉它"你是谁、你要做什么、你有什么能力"。
在OpenAI的消息体系中,role 有四种身份:
| role | 身份 | 谁说的 | 例子 |
|---|---|---|---|
system |
系统指令 | 开发者预设的规则 | “你是一个友好的天气助手” |
user |
用户 | 正在和你聊天的人 | “北京天气怎么样?” |
assistant |
助手 | 智能体自己 | “北京今天是晴天,25度” |
tool |
工具 | 函数执行的结果 | “北京今天是晴天,25度” |
一个形象的类比:如果把对话比作一场戏——
- system = 导演给演员的剧本大纲(幕后,观众看不见)
- user = 观众对演员说的话
- assistant = 演员的表演
- tool = 演员从后台拿到的道具
我们在初始化时就把 system prompt 塞进记忆本:
1 | class Agent: |
这条 system 消息会一直待在记忆本的最前面,每轮对话都会带上——模型每次看聊天记录时,第一眼就能看到自己的"人设",不会跑偏。
3. 改造 run() 方法:追加而非覆盖
关键改动:把原来的 messages = [...](新建)改成 self.messages.append(...)(追加)。
1 | def run(self, user_input): |
关键细节:注意代码末尾,当不需要工具调用时,我们也执行了 self.messages.append(message)。这一步很多初学者会漏掉——漏掉的后果是:智能体的回复没有被记入记忆本,下一轮对话时模型会"看到用户说了两句话,但自己一句都没回过",上下文就乱了。
4. 数据流对比:改造前 vs 改造后
理解一个概念最好的方式是看它怎么流动。下面用同一个对话场景对比:
场景:用户先自我介绍,再问名字。
改造前(金鱼版🐟):
1 | 第1轮 run("我叫柏青") |
改造后(记忆版🧠):
1 | 第1轮 run("我叫柏青") |
看到区别了吗?记忆版的多轮对话就像一个不断滚动的剧本,每一句话都被记录下来,模型每次都能"回顾前情提要"。
上下文窗口:记忆本也有页数限制
现实总是残酷的——记忆本不是无限大的。大模型都有一个叫做 上下文窗口(Context Window) 的概念,也就是它一次最多能"看到"多少内容。
用一本书来类比:
| 概念 | 类比 | 说明 |
|---|---|---|
| Context Window | 书的"可见页数上限" | 模型一次最多读 N 页 |
| Token | 一个字/词 | 中英文混合约 1 个 token ≈ 0.75 个汉字 |
| self.messages | 你写过的所有笔记 | 越写越厚 |
| 超出窗口 | 笔记太厚,最早的几页自动被遮住 | 模型看不到最早的内容 |
常见模型的上下文窗口:
| 模型 | 上下文窗口 | 大约能记住 |
|---|---|---|
| DeepSeek-V4-Pro | 1M tokens | 150万~250万汉字 |
| Gemini 3.1 Pro | 1M tokens | 150万~250万汉字 |
| ChatGPT 5.5 | 128K tokens | 20万~30万汉字 |
| Qwen3.7 Max | 256K~1M tokens | 40万~250万汉字 |
| 豆包等模型 | 128K~256K tokens | 20万~60万汉字 |
对于我们的教程场景,聊几百轮都超不了——所以暂时不用担心。但如果你以后要拿记忆版智能体去做更复杂的项目,知道这个概念很重要。
进阶:简单的记忆管理策略
当对话实在太长时,有几种简单的"瘦身"策略:
- 保留 system + 最近 N 轮:始终保留 system prompt,只保留最近 20 轮对话,旧的扔掉。
- 摘要压缩:每隔一段对话,让模型自己把历史总结成一段摘要,用摘要替代原文。
- 滑动窗口:始终只保留最近的 N 条消息,像一扇在聊天记录上滑动的窗。
这些属于进阶内容,本篇不展开——先跑通基础版,后面自然会遇到这些需求。
完整代码示例
基础ReAct架构(记忆版)的树形项目目录结构:
1 | ReactAgentAI/ |
config.py 代码示例(不变):
1 | BASE_URL = "https://api.xxxxx/v1" |
agent.py 完整代码示例:
1 | from openai import OpenAI |
tools/__init__.py 代码示例(不变):
1 | from .get_weather import get_weather |
tools/get_weather.py 代码示例(不变):
1 | def get_weather(city): |
main.py 代码示例(不变):
1 | from agent import Agent |
改造前后核心差异一览
| 对比维度 | 入门篇(金鱼版🐟) | 记忆篇(记忆版🧠) |
|---|---|---|
| messages 存储位置 | run() 内局部变量 |
self.messages 实例属性 |
| 每次 run() 调用 | 新建空列表 | 追加到已有列表 |
| System Prompt | 无 | 有(出厂人设) |
| 多轮对话 | ❌ 每次失忆 | ✅ 完整上下文 |
| 能不能记住你的名字 | 不能 | 能(直到上下文窗口满) |
| 代码改动量 | — | 核心只改 3 处 |
测试一下
跑起 main.py,试试这些对话:
1 | 你:你好,我叫柏青 |
第一轮自我介绍 → 第二轮验证记忆 → 第三轮调用工具 → 第四轮验证上下文追溯。四个维度全部通过,你的智能体正式告别金鱼记忆!🎉
本篇小结
我们做的事情本质上就是一次"记忆搬家":
1 | 改造前:messages 是便签纸,用完就扔 |
这个改动只有几行代码,但意义重大——它让智能体从一个"无状态的工具调用器"变成了一个"有上下文的对话伙伴"。入门篇我们搭好了骨架,记忆篇我们给它注入了连续性。
当然,这还只是"短期记忆"——对话关掉就没了。如果你想让智能体在下次启动时还记得你叫柏青,那就需要长期记忆(持久化存储),那是后续篇章的内容了。
你已经学会了:
✅ 为什么入门篇的智能体会"翻脸不认人"
✅ 如何把 messages 升级为实例属性 self.messages
✅ System Prompt 的作用和写法
✅ 四种消息角色的含义(system / user / assistant / tool)
✅ 多轮对话的数据流
✅ 上下文窗口的基本概念
✅ 如何在不需要工具时也正确 append 消息
下一篇文章,我们将在记忆版的基础上继续扩展——让智能体具备更丰富的工具能力和更强的自主决策能力。敬请期待!
AI总结
本篇为ReAct智能体架构系列第二篇——记忆篇。
核心问题:入门篇的智能体每次调用 run() 都会重建 messages 列表,导致"金鱼记忆"——说完就忘。
解决方案:将 messages 从 run() 内的局部变量升级为 Agent 类的实例属性 self.messages,同时在初始化时写入 system prompt 作为"出厂人设"。
关键改动:
__init__()中初始化self.messages并写入 system promptrun()中用self.messages.append()替代messages = [...]- 明确四种消息角色:system(系统指令)、user(用户)、assistant(助手)、tool(工具结果)
额外科普:上下文窗口(Context Window)的概念——记忆本有"页数上限",短期对话不用管,长期项目需要管理策略。
成果:智能体从"无状态工具调用器"升级为"有上下文连续性的对话伙伴",能够记住用户的名字和历史对话内容。








