第4周 Day 1:智能体记忆系统——给 Agent 一个"大脑"

前面学了 Function Calling(让 Agent 会动手)和 RAG(让 Agent 会翻书),但还有个尴尬的问题:

你刚跟 Agent 聊完天,转头再问它"我刚才说了啥?"------它不记得了。

就像你跟朋友说"我喜欢吃辣的",下次吃饭他给你点了盆清汤------你啥心情?

Agent 没有记忆,就像一个金鱼的脑子

今天来解决这个问题。


一、为什么 Agent 需要记忆?

先想想人类是怎么聊天的:

人类聊天 Agent 聊天
"你好,我叫张三" Agent 记住你叫张三
"我喜欢打篮球" Agent 记住你的爱好
"你叫什么名字?" "我叫张三啊,你刚告诉我的"
聊完,第二天再见 "早啊张三,今天还聊篮球吗?"

没有记忆的 Agent 呢?

复制代码
你:你好,我叫张三
AI:你好!

你:我叫什么名字?
AI:我不知道啊,你没告诉过我。

气不气人?

记忆系统就是解决这个问题的。


二、两种记忆:短期 vs 长期

类比人类记忆:

短期记忆 长期记忆
像什么 便利贴 笔记本
存什么 刚才聊的话题 用户的重要信息
存多久 聊完就忘(或覆盖) 写到文件里,永久保存
怎么用 维持对话上下文 下次启动还能读
例子 "刚才说到哪了?" "我记得你叫张三"

2.1 短期记忆(ShortTermMemory)

就是记录当前对话的上下文。我实现了一个简单的:

python 复制代码
class ShortTermMemory:
    def __init__(self, max_turns=10):
        self.conversation = []  # 存对话记录
        self.max_turns = 10     # 最多记 10 轮

    def add(self, role, content):
        """记下一条对话"""
        self.conversation.append({
            "role": role,       # "user" 或 "assistant"
            "content": content, # 说了什么
            "time": "14:30:25"  # 什么时候说的
        })
        # 太长就忘掉最早的
        if len(self.conversation) > self.max_turns:
            self.conversation.pop(0)

关键:短期记忆有容量上限,满了就扔掉最旧的。就像你记不住一周前中午吃了什么一样。

2.2 长期记忆(LongTermMemory)

把重要信息存到文件里,下次启动还能读:

python 复制代码
class LongTermMemory:
    def __init__(self, storage_path="memory/long_term.json"):
        self.storage_path = storage_path
        self.memories = self._load()  # 启动时加载

    def remember(self, key, value):
        """记下一件事"""
        self.memories[key] = {"value": value, "time": "2026-04-19"}
        self._save()  # 立刻写到文件

    def recall(self, key):
        """回想一件事"""
        return self.memories.get(key, {}).get("value")

    def forget(self, key):
        """忘记一件事"""
        del self.memories[key]
        self._save()

存储的文件长这样

json 复制代码
{
    "user_name": {
        "value": "张三",
        "time": "2026-04-19 14:30:25"
    },
    "preferences": {
        "value": ["打篮球", "辣的食物"],
        "time": "2026-04-19 14:31:10"
    }
}

三、MemoryAgent:有记性的 Agent

把短期和长期记忆组合起来,就是有记忆的 Agent:

python 复制代码
class MemoryAgent:
    def __init__(self):
        self.short_term = ShortTermMemory()  # 便利贴
        self.long_term = LongTermMemory()    # 笔记本

    def reply(self, user_message):
        # 1. 记到短期记忆
        self.short_term.add("user", user_message)

        # 2. 查长期记忆,看看有没有相关信息
        user_info = self.long_term.recall_all()

        # 3. 根据消息 + 记忆,决定怎么回复
        reply = self._think_reply(user_message, user_info)

        # 4. 把回复也记到短期记忆
        self.short_term.add("assistant", reply)

        return reply

四、Token 优化------别让你的 prompt 变成"裹脚布"

上面说的短期记忆有个问题:对话越长,prompt 越长,花的 token 越多

聊 10 轮,几百 token。聊 100 轮,几千 token。聊 1000 轮......钱包受得了吗?

4.1 记忆压缩(Memory Compression)

原理很简单:把旧对话"浓缩"成摘要,扔掉细节,只留关键信息

就像你写日记不会写"8:00 起床,8:01 刷牙,8:03 洗脸......",而是写"今天去了医院"。

我实现了一个 CompressedShortTermMemory

python 复制代码
class CompressedShortTermMemory:
    def __init__(self, keep_recent=4, compress_after=8):
        self.summaries = []             # 历史摘要列表
        self.recent = []                # 最近几轮原始对话
        self.keep_recent = 4            # 保留最近 4 轮原文
        self.compress_after = 8         # 超过 8 轮就压缩

    def add(self, role, content):
        # 添加对话
        self.recent.append(f"{role}:{content}")
        # 满了?触发压缩
        if len(self.recent) >= self.compress_after:
            self._compress()

    def _compress(self):
        # 把要压缩的对话提取关键信息
        to_compress = self.recent[:-4]  # 保留最近 4 轮
        summary = self._summarize(to_compress)
        self.summaries.append(summary)
        self.recent = self.recent[-4:]  # 只保留最近 4 轮

    def build_context(self):
        # 输出:历史摘要 + 最近对话
        # 体积小多了!
        return self.summaries + self.recent

4.2 压缩效果对比

跑一下测试,看看省了多少:

指标 普通记忆 压缩记忆 效果
存储方式 全部原文 摘要 + 最近几轮 ---
20 轮对话 ~340 tokens ~280 tokens 省 ~18%
100 轮对话 ~1700 tokens ~400 tokens 省 ~76%
对话越长 线性增长 趋于稳定 省更多!
关键信息 全保留 摘要提取 够用

对话越长,压缩效果越明显。如果你和 Agent 能聊几百轮,压缩能帮你省 70-80% 的 token 费用

4.3 摘要怎么生成?

生产环境一般调 LLM 来总结:

erlang 复制代码
原始对话:
  用户:我叫张三
  助手:你好张三!
  用户:我喜欢打篮球
  ...

LLM 摘要 → "用户叫张三,喜欢打篮球"

但我代码里用的是规则提取------找"我叫""喜欢""学了"等关键词来提取。好处是不用调 API 也能演示原理。

4.4 token 估算方法

代码里我写了个 estimate_tokens() 函数,不用 API 也能估算:

python 复制代码
def estimate_tokens(text):
    """粗略估算 token 数"""
    chinese = sum(1 for c in text if '一' <= c <= '鿿')
    english = len(text) - chinese
    return int(chinese * 1.5 + english * 0.3)

规则:中文 1.5 个字 / token,英文 3 个字母 / token。不完全准确,但够用来对比效果。

4.5 更多省 token 技巧

技巧 做法 效果
滑动窗口 只保留最近 N 轮对话 最简单,但会丢掉旧信息
摘要压缩 把旧对话总结成几句话 省 token,保留关键信息
重要性打分 重要的永远保留,不重要的先丢 精准控制
去重 去掉重复的信息 特别是长期记忆里
结构化存储 用 JSON 而不是自然语言存 减少冗余描述

运行效果演示

代码写好了,跑起来看看:

测试 1:短期记忆------记得刚才聊了什么

css 复制代码
[用户] 你好!
[AI] 我知道了,这个话题我记下了。

[用户] 我想学英语单词
[AI] 我知道了,这个话题我记下了。

[用户] 我叫小明
[AI] 你好,小明!已经记住你啦!

[用户] 我叫什么名字?
[AI] 你叫小明呀,我记性可好了!
→ 短期记忆已记录 10 条对话

测试 2:长期记忆------跨会话还记得你

css 复制代码
第一轮对话:
[用户] 你好,我叫小红
[AI] 你好,小红!已经记住你啦!

[用户] 我喜欢猫和音乐
[AI] 好嘞,我记住了!

[用户] 我学了 cat 和 dog 单词
[AI] 收到!

------ 模拟重新启动 ------

第二轮对话(Agent 加载了长期记忆文件):
[用户] 我叫什么名字?
[AI] 你叫小红呀,我记性可好了!

[用户] 我喜欢什么?
[AI] 我记得你喜欢:猫、音乐

测试 3:记忆管理------回顾和遗忘

css 复制代码
[用户] 查看我的记忆
[AI] 我的记忆状态:
  [短期记忆] 1 条对话
  [长期记忆] 3 条信息

执行:让 Agent 忘记偏好设置
→ 还剩 2 条记忆:user_name, learned_words

[用户] 清空所有记忆
→ 长期记忆剩余:0 条
→ 短期记忆剩余:0 条

测试 4:记忆一致性------短期和长期配合

css 复制代码
[用户] 我叫张三
[AI] 你好,张三!已经记住你啦!

[用户] 我喜欢打篮球
[AI] 好嘞,我记住了!

[用户] 我学了 rabbit 单词
[AI] 收到!

[用户] 我叫什么?
[AI] 你叫张三呀,我记性可好了!

[用户] 我有什么爱好?
[AI] 我记得你喜欢:打篮球

最终状态:
  - 短期记忆:10 条对话记录
  - 长期记忆:3 条持久化信息
  - 两者协同工作,互不冲突

测试 5:记忆压缩------省 token 还能记住关键信息

css 复制代码
[对比] 普通记忆 vs 压缩记忆
  对话总轮数:20 轮
  普通记忆:~340 tokens
  压缩记忆:~280 tokens
  省了约 18% 的 token!

状态:轮次:40 | 摘要:9条 | 近期:4轮 | 预估:284 tokens | 节省:~449 tokens

关键信息还在:
  - 记住了"我叫张三"
  - 记住了"喜欢打篮球"
  - 记住了"学了 cat 和 dog"

五、什么时候用什么记忆

场景 用哪个 为什么
用户说"刚才我们聊到哪了?" 短期记忆 找最近的对话上下文
用户说"你还记得我叫什么吗?" 长期记忆 跨会话的信息
用户说"帮我总结今天的学习" 短期 + 长期 短期看今天聊了啥,长期看用户信息
用户说"忘掉我的偏好设置" 长期记忆.forget() 精确删除指定内容
用户说"重置所有" 两个都清空 彻底重新开始

六、短期记忆 vs 长期记忆 对比

加上压缩记忆,就是三种记忆了。可以理解成:

  • 短期记忆:便利贴(方便,但贴满了就扔旧的)
  • 压缩记忆:笔记本摘要(定期整理,把旧内容浓缩)
  • 长期记忆:保险箱(重要信息永久保存)
维度 短期记忆 长期记忆
存哪 内存(列表) 磁盘(JSON 文件)
速度 极快 慢一点(要读写文件)
容量 有限(默认 10 轮) 几乎无限
持久性 程序退出就丢 下次启动还在
适合 对话上下文 用户画像、偏好、关键信息

七、生产环境的内存设计思路

真实项目里,记忆系统不能只是 demo 级别,要考虑这几个问题:

7.1 三层记忆架构

7.2 Token 预算管理

python 复制代码
# 设定 token 预算,防止 prompt 无限膨胀
MAX_CONTEXT_TOKENS = 4000

def build_prompt(user_input, short_term, long_term):
    """动态构建 prompt,确保不超预算"""
    prompt_parts = []

    # 1. 系统指令(固定,最优先)
    system = "你是一个有帮助的 AI 助手。"
    prompt_parts.append(system)
    budget = MAX_CONTEXT_TOKENS - estimate_tokens(system)

    # 2. 长期记忆(重要信息,优先放)
    user_info = long_term.recall_all()
    if user_info:
        info_text = f"用户信息:{json.dumps(user_info, ensure_ascii=False)}"
        if estimate_tokens(info_text) < budget:
            prompt_parts.append(info_text)
            budget -= estimate_tokens(info_text)

    # 3. 短期记忆(尽量放,但要控制)
    context = short_term.build_context()
    if estimate_tokens(context) > budget:
        # 超预算了,只放最近几轮
        context = short_term.build_context(max(3, budget // 50))
    prompt_parts.append(context)

    # 4. 当前问题
    prompt_parts.append(f"用户问题:{user_input}")

    return "\n\n".join(prompt_parts)

7.3 重要信息优先级

不是所有记忆都同等重要。可以给信息打分,重要的优先保留:

优先级 信息类型 例子 处理方式
🔴 高 身份信息 名字、年龄、职业 永远保留,存长期记忆
🟡 中 偏好信息 喜欢什么、讨厌什么 尽量保留,可压缩
🟢 低 日常对话 "今天天气不错" 随意压缩或丢弃

7.4 实际项目中用什么存

存储方案 适合 不适合
JSON 文件 个人项目、小规模 并发读写、大量数据
SQLite 单机应用、轻量级 高并发、分布式
Redis 高频读写、短期记忆 长期持久化(要配合其他方案)
PostgreSQL 生产环境、结构化存储 简单项目太重了

八、记忆 + RAG + Function Calling 的完整拼图

现在你已经学了三个核心能力:

javascript 复制代码
Function Calling → Agent 会"动手"(调用工具、发消息、查天气)
         +
       RAG → Agent 会"翻书"(检索文档、查知识库)
         +
     记忆系统 → Agent 有"记性"(记住你是谁、喜欢什么)
         =
   一个像样的智能体!

举个综合例子:

markdown 复制代码
用户:"帮我查一下昨天我学了哪些单词,然后发个总结到我邮箱"

Agent 的处理:
  1. 记忆系统 → 查用户信息:叫小明,邮箱是 xxx@xx.com
  2. RAG → 检索学习记录:找到昨天学的单词
  3. Function Calling → 调用发邮件接口

最终:"小明,你昨天学了 cat、dog、bird 三个单词,
       总结已发送到你的邮箱 xxx@xx.com"

九、今日总结

今天干了啥:

  • 理解了 Agent 为什么需要记忆(不然像个金鱼脑子)
  • 学会了短期记忆(便利贴,记对话上下文)
  • 学会了长期记忆(笔记本,跨会话持久化)
  • 学会了记忆压缩(省 token 还能记住关键信息)
  • 理解了生产环境的内存设计(三层架构 + token 预算)
  • 实现了完整的记忆 Agent,跑了 5 个测试用例

三种记忆对比

短期记忆 压缩记忆 长期记忆
存啥 最近几轮对话原文 旧对话的摘要 用户关键信息
存哪 内存 内存 磁盘文件
持久性 重启丢 重启丢 重启还在
Token 最费 极少
适合 上下文理解 长对话场景 跨会话信息

省 token 核心口诀

能扔的扔,能缩的缩,重要的存保险箱。

代码位置week4/01_agent_memory/app.py

可以运行的命令

  • python app.py ------ 跑 5 个测试用例
  • python app.py --chat ------ 交互模式,自己试试

试试说这些话

  • "我叫小明"
  • "我喜欢看电影"
  • "我学了 apple 单词"
  • "我的记忆怎么样?"
  • "清空记忆"

明天预告:多步推理 Agent------让 Agent 学会"拆解问题,一步步解决"。


写于 2026-05-08,智能体记忆系统------给 Agent 一个"大脑"

相关推荐
DavidTaozhe1 小时前
一文搞懂外汇接口怎么实时更新美元汇率
大数据·python
_风满楼1 小时前
TDD实战-会议室冲突检测的红绿重构循环
前端·javascript·算法
是你的小橘呀1 小时前
coze工作流打造 来喽!!
人工智能
Rkgua1 小时前
JS中的惰性函数基本介绍
前端·javascript
用户78937733908531 小时前
Docker 部署踩坑记录:从“构建失败”到“服务跑通”,以及为什么数据被清空了
python·docker
客场消音器1 小时前
我用两周半 Vibe Coding 做了一个前额叶训练的微信小程序
前端·javascript·后端
再玩一会儿看代码1 小时前
如何理解神经网络中的权重参数?从一张图看懂模型参数量计算
人工智能·经验分享·python·深度学习·神经网络·机器学习
2301_779622412 小时前
mysql如何通过主从备份实现读写分离_配置mysql架构模式
jvm·数据库·python
炜宏资料库2 小时前
【专家观点】河钢数字:工业AI质检助力生产制造企业持续提质降本增效
人工智能·制造