记忆系统:让 Agent 记住你是谁、上次聊到哪

📚 系列:《Agent 从入门到上手》· 30 天连载 · 第 8 篇(能力篇) 🎯 本篇目标:搞清楚 Agent 的两套记忆 (短期 / 长期)怎么分工、记忆该什么时候写、写什么 ,以及上下文塞爆之后怎么压缩、怎么遗忘------最后给你一个纯标准库、能直接跑的「记忆系统实验室」 ⏱️ 阅读时长:约 24 分钟


一、开场:你招了个"每天都是入职第一天"的员工

先说一个几乎所有人都会遇到的场景。

你跟一个 AI 助手聊了半小时,掏心掏肺地把背景交代清楚:

"我叫老张,在天津工作,做智能建造方向的研究。另外我对花生过敏,推荐餐厅记得避开。"

它答得又快又好。然后你第二天打开新会话,问它:

"帮我推荐一家天津的餐厅。"

它热情洋溢地回你:"推荐狗不理包子、煎饼馃子、罾蹦鲤鱼------都是本地名吃!"

然后你满怀期待地点开菜单,第三道菜是宫保鸡丁。

🤡 这时候你会深刻意识到一件事:它不是"记性不好",它是压根没有"记性"这个器官。

这就是 Day 03 里四大件之一「记忆」缺失的典型症状。前六篇我们搭出来的 Agent,本质上都是一个七秒记忆的金鱼------每一轮对话,它看到的都只是"这一轮发生了什么",外加你给它写的那份岗位说明书(Day 07)。至于你是谁、你上次说了什么、你讨厌什么,一概不知。

更魔幻的是,很多人的第一反应是:"那我把之前所有的聊天记录都贴给它不就行了?"

这个想法非常自然,也非常危险。为什么危险,第四节和第六节专门讲------先剧透一句:

🔑 把整个聊天记录塞进上下文,就像搬家时一件东西都不扔:房子是变满了,但你要找的那把钥匙,永远在最底下。

好,今天我们给这个数字员工装一个大脑里的海马体。


二、先分清两套记忆:桌上的便签 vs 楼下的档案柜

Agent 的记忆不是一个东西,是两套完全不同的系统。混为一谈是新手做记忆系统时最常见的翻车起点。

用人话讲:

🧾 短期记忆(Short-term / Working Memory) 🗄️ 长期记忆(Long-term Memory)
存什么 本轮对话的原文、工具返回的原始结果、刚做的每一步 用户画像(身份/偏好/禁忌)、历史结论、领域知识
存在哪 内存里,就是一个 list[messages] 硬盘 / 数据库 / 文件
多大 受上下文窗口限制,装满了必须腾位置 理论上无上限
多快 毫秒级,直接拼在提示词里,模型"抬眼就能看见" 要检索才能拿到,慢一点
多贵 每轮都重发一遍,长度 × 轮数 = 账单 只发检索出来的一小撮,长期看反而省钱
会丢吗 进程一关就没了,会话结束即清零 持久化,换个会话、换台机器都还在
对应什么 办公桌上摊开的便签本 楼下的档案柜

一个特别好用的判断口诀:

🔑 短期记忆负责"连贯",长期记忆负责"认识你"。

  • 只做短期记忆 → 一次会话里能接得上话,但每次都像第一次见面("请问怎么称呼您?");
  • 只做长期记忆 → 存了一堆,但检索不回来就等于没存(档案柜锁着,钥匙丢了)。

顺带讲清三个被说滥的词

术语 人话翻译 一句话解释
Context Window(上下文窗口) 办公桌的桌面大小 模型一次最多能"同时看见"多少字,超出的它真的看不见
Token(词元) 计费和占位的小格子 中文大约 1 个字 1 个 token;它是收费单位,也是桌面面积的度量单位
上下文工程(Context Engineering) 桌面收纳术 怎么在有限的桌面上,摆上对当前这一步最有用的东西(Day 13 专门展开)

三、短期记忆:那张越摊越乱的办公桌

先讲短期记忆,因为它是你不用做任何额外工作就已经在用的那一套------每次你调一次大模型,你都在用短期记忆。

3.1 它本质上就是一个列表

复制代码
messages = [
    {"role": "system",    "content": "你是「小张助理」......"},   # Day 07 的岗位说明书
    {"role": "user",      "content": "我叫老张......"},
    {"role": "assistant", "content": "好的老张!"},
    {"role": "user",      "content": "帮我推荐一家餐厅"},
]

每一轮对话,你把这个列表整体再发一遍 。模型是无状态 的(stateless)------它不记得上一次你发过什么,它只知道"这次你发给我的这段文字"。所谓的"它记得",其实是你每次都把全文重发了一遍。

这一点极其重要,它带来三个直接后果:

🔑 ① 记忆的成本是"平方级"的。 第 1 轮发 1 轮内容,第 10 轮要发 10 轮内容,第 50 轮要发 50 轮内容。一轮 500 token,50 轮就是一万多 token------而这只是"让它看起来记得住"的代价。

🔑 ② 塞得越满,它越笨。 上下文越长,模型对中间部分的注意力越弱(Day 07 提过的 "lost in the middle")。你辛辛苦苦塞进去的第 7 轮的某个关键约定,可能在第 30 轮已经被它"视而不见"了。

🔑 ③ 塞爆了会直接报错。 超过窗口上限,API 会直接返回错误,你的 Agent 当场去世。

3.2 桌面经济学的三条账

账 怎么算 省钱的姿势
钱 每轮 token × 轮数 × 单价 只留必要的历史,其余压缩
速度 首字延迟 ≈ 输入长度的线性函数 输入越短,用户等得越短
质量 越长越容易"顾此失彼" 重要的放两头(开头和结尾最容易被遵守)

🤡 一个真实的吐槽:很多人优化 Agent 的第一反应是"换个更强的模型"。但一半的情况下,问题根本不是模型不够强,而是你往它桌上堆了 30 页材料,然后问它"第 12 页第三行写的啥"。换了爱因斯坦来,他也得先翻一阵。

3.3 一个反直觉的结论

短期记忆不是越多越好,是"刚好够用"最好。

一个常见的错误做法是:为了保证"什么都不丢",把每轮的原文、工具的完整返回、报错堆栈全部保留。三天后你的上下文是 4 万 token,Agent 变慢、变贵、变笨,而它真正需要的信息可能只有 300 字。

正确的思路是:让"流水账"留在短期记忆里(用完即焚),让"结论"沉淀到长期记忆里(永久保存)。 这就是下一节的事。


四、长期记忆:存什么、怎么存、怎么找回来

长期记忆才是"记住你是谁"的关键。它分三层,这三层对应三种完全不同的东西:

记忆类型 人话翻译 存什么 例子 什么时候用
情景记忆 Episodic 日记本 发生过的事、具体经历 "上次他让我改那份报告,改了三版才过" 用户说"上次那个......"
语义记忆 Semantic 百科知识卡片 提炼后的事实与知识 "他叫老张,在天津,研究智能建造" 每次都要用的画像
程序记忆 Procedural 肌肉记忆 做事的方法与流程 "他要求报告结论先行,别写流水账" 决定"怎么做"而不是"做什么"

🎯 一个非常好用的判据 :如果一条记忆会影响 Agent 怎么做 (风格、格式、禁忌),它是程序记忆;如果它影响 Agent 认为事实是什么 (你是谁、你要什么),它是语义记忆;如果它只是发生过 (历史流水),那是情景记忆------而这第三种,恰恰是最该被压缩掉的。

4.1 存:别存整段聊天,存"抽出来的事实"

新手最爱干的事:把整轮对话原文存进数据库。 三个月后你的数据库里躺着 20 万条"好的,我明白了""收到""嗯嗯",真正的用户信息埋在里面,检索十条有九条是噪音。

正确的做法是写入前先抽取 :从一轮对话里,只挑出"值得长期保存"的事实(fact),然后带类型、带重要度地存进去。

复制代码
# 值得存的:跨会话仍然成立、会影响未来决策、用户明确要求记
# 不值得存的:一次性计算、验证码、当时的天气股价、临时文件名
NOISE_PATTERNS = [
    r"算(?:一下|一算)?\s*[\d\s\+\-\*/x×]+",
    r"验证码",
    r"今天(?:天气|气温|几号|星期几)",
    r"现在几点",
]

🐟 一个真实的笑话 :我见过最离谱的一条"长期记忆"是 上次的临时文件名是 v3_final_真的最终版.docx。它在数据库里躺了 11 个月,每次用户问"帮我写个文档",它都被检索出来,然后 Agent 郑重其事地建议:"您可以命名为 v3_final_真的最终版.docx。"

4.2 找:检索不是"翻箱倒柜",是"按需取一小撮"

存进去只是第一步,能检索回来才算数。检索的核心动作是:

  1. 用户说了新的话 → 拿它当查询词;
  2. 在长期记忆里找出最相关的 k 条(通常 3-8 条);
  3. 把这 k 条拼进提示词的固定位置(通常是 System Prompt 之后、用户消息之前)。

这里的"相关"怎么算?真实系统里用 Embedding(向量化) 做语义相似度------简单说就是"给每段话发一个气味标签,问哪几段味道最像"。这块 Day 10 会专门讲透,今天先记住结论:

🔑 检索的最大陷阱是"贪多"。 你检索 20 条塞进去,等于把档案柜倒在了办公桌上------又回到第三节的问题了。k 取 3-8,宁少勿多;不相关的一律不要。

4.3 合并:同一件事别存成十个版本

用户第 1 轮说"我叫老张",第 30 轮又说"我叫老张"。如果你的实现是 INSERT,你会有两条一样的记忆;如果他说"我改名叫老李了",你会有两条自相矛盾的记忆------然后你的 Agent 会开始精神分裂,今天叫你老张明天叫你老李。

所以写入必须是 upsert(有就更新,没有才插入):

  • 同类型 + 内容高度重合 → 更新 ,刷新时间戳、抬高重要度、version += 1;
  • 同类型 + 内容冲突 → 覆盖,并保留一条变更记录(谁在什么时候改的,方便追溯);
  • 不同类型 → 各自独立。

五、写入策略:不是所有对话都值得记住

这是记忆系统里最容易被跳过、代价却最高的一节。

5.1 四条判据

判据 ✅ 该记 ❌ 不该记
跨会话仍然成立吗? "我对花生过敏"(下个月还是真的) "帮我算下 17×25"(算完就完了)
会影响未来的决策吗? 预算上限、常用地址、禁忌、权限范围 今天的心情、随口一句吐槽
是用户明确要求记的吗? "记住:以后都这么叫我" (用户没提,你自作主张)
是会变的吗? --- 验证码、实时股价、库存数量、临时文件名

🎯 一句话:记忆的是"人"和"规则",不是"事"和"数据"。 事和数据会变,人和规则相对稳定。

5.2 谁来决定"记不记"?三种做法

做法 怎么实现 优点 缺点
① 规则/正则 写一堆模式,命中就抽 便宜、快、可预测 覆盖不全,容易漏
② 让模型抽 每轮结束后让小模型输出"值得记的事实"JSON 覆盖全、能理解语义 要花钱、要延迟、可能抽歪
③ 混合(推荐) 高频类型走规则,兜底交给模型 性价比最高 两套代码要维护

工程上的现实选择:先上规则,跑两周看日志,把规则漏掉的高频场景挑出来,再考虑加模型。 一上来就"每轮都调一次模型抽记忆",你的账单会先于你的产品成熟。

5.3 什么时候写?别阻塞用户

写入动作的时机也有讲究:

  • 轮末异步写 :用户这条已经拿到回复了,后台再慢慢抽、慢慢存 → 用户无感,推荐;
  • 轮首同步写:下一轮开始前先写 → 会拖慢首字延迟;
  • 定时批量写:攒一批一起写 → 最省,但会话中途断了会丢。

🧯 提醒:写入一定要幂等。网络重试导致同一条事实写了两次,不该产生两条记忆------这就是 4.3 节 upsert 的用处。


六、压缩与遗忘:聊到第 50 轮,上下文爆炸了怎么办

现在终于可以回答开头那个问题了:"把整个聊天记录都塞进去"为什么是个坏主意?

三个理由:会爆 (超过窗口直接报错)、会贵 (平方级成本)、会笨(中间被忽略)。

那怎么办?业界主流是三条路,各有各的适用位:

6.1 三条压缩路线

策略 做法 省 代价 适用
① 截断 只保留最近 N 轮 最省 丢开头的关键信息(名字、偏好全没了) 只在"历史真的不重要"时用
② 摘要压缩 把旧对话压成一段事实摘要,保留最近 N 轮原文 很省 要一次摘要调用;摘要本身可能丢细节 默认推荐
③ 外置检索 旧对话存进长期记忆,按需检索回来 中等 需要检索链路 长会话 + 需要"翻旧账"

我在动手环节里实测了三种策略在同一段 24 轮对话上的表现(预算 800 token):

策略 tokens 预算 关键事实保留率
A 全量塞入 897 ❌ 溢出 5/5(100%)
B 截断保留最近 6 轮 137 ✅ 正常 0/5(0%)
C 摘要压缩 + 最近 6 轮 178 ✅ 正常 5/5(100%)

看清楚 B 那一列 :它最省钱,但把"老张 / 天津 / 智能建造 / 花生过敏 / 结论先行"全丢了。而 C 只比 B 多花 41 个 token,关键事实 100% 存活。

🔑 这 41 个 token,是整个记忆系统里性价比最高的一笔投资。

6.2 摘要怎么做才不丢关键事实

"摘要"不是让模型"总结一下",那是让它自由发挥。要写成有结构的抽取:

复制代码
请把以下对话压缩成不超过 200 字的摘要,必须包含:
1. 用户的身份信息(姓名/城市/职业/研究方向)------没有就写"未提供"
2. 用户明确提出的所有偏好与禁忌(逐条列出)
3. 已达成的结论与待办事项(带状态)
4. 未完成、被中断或失败的操作
不要包含:寒暄、重复的确认、工具返回的原始数据。

🎯 要点:摘要要用"清单 + 字段",不要用"一段话"。 一段话的自由度太高,模型今天漏掉"花生过敏"你根本发现不了;清单漏了一项,一眼就看得出来。

另一个实战技巧:分层摘要。每 10 轮压一次小摘要,每 5 个小摘要再压一次大摘要。比"一次性压 50 轮"稳得多,也便宜得多(每次输入都短)。

6.3 遗忘:该忘的必须忘得掉

最后讲一个几乎所有教程都不讲、但几乎每个生产系统都会遇到的东西:记忆库会腐烂。

一个只增不减的长期记忆库,最后会变成一屋子过期传单:

  • 用户三年前说"我在用 Windows 10"------现在还在里面;
  • 用户说过一次"帮我看看 Python 2 的写法"------被当成长期兴趣;
  • 检索的时候,这些陈年老账会挤占 k 个名额,把真正重要的挤出去。

解法是给每条记忆算一个强度分数,定期淘汰低于阈值的:

复制代码
强度 = 重要度 × 0.5 ^ (距上次被唤起的天数 / 有效半衰期)
有效半衰期 = 基础半衰期 × (1 + 被唤起次数 × 0.5)     # 越常被想起,忘得越慢

这个公式有两处刻意的设计,值得单独说:

  1. 衰减看的是"上次被唤起",不是"创建时间"。 一条被反复用到的老记忆不该衰减------就像你天天骑的自行车,不会因为买了三年就变难骑。这就是艾宾浩斯遗忘曲线里"复习重置"的机制。
  2. 用户画像类(姓名、过敏、核心偏好)应该"钉住",永不衰减。 你不会因为用户 200 天没提"花生过敏"就认为他痊愈了------这条要是被忘掉,是会出医疗事故的。

实测一张表(基础半衰期 30 天,阈值 1.0):

记忆内容 重要度 上次唤起 唤起次数 有效半衰期 强度 判定
对花生过敏 10 3 天前 25 钉住 10.00 ✅ 保留
我叫老张 9 5 天前 30 钉住 9.00 ✅ 保留
报告要结论先行 8 20 天前 12 210 天 7.49 ✅ 保留
不喜欢香菜 7 200 天前 1 45 天 0.32 🗑️ 淘汰
回信用三段式 3 260 天前 0 30 天 0.01 🗑️ 淘汰
临时文件名 v3_final_真的最终版 2 330 天前 0 30 天 0.00 🗑️ 淘汰

🐟 注意看第四行 :「不喜欢香菜」是真的 ,但它 200 天没被提起,慢慢淡了。这是遗忘机制的代价 ,也是它的本意------记忆系统的资源是有限的,你不可能什么都留着。如果你觉得某条绝不能忘,就在写入时把它标成"钉住",而不是去调阈值。

🔑 最后一句,也是本篇我最想让你记住的:记忆系统的上限,不是"能存多少",而是"该忘的能不能忘掉"。


七、动手环节:搭一个「记忆系统实验室」

今天不装任何库 ,纯 Python 标准库,也没有随机数(结果可复现)。完整脚本在 temp/day08_memory_lab.py。

我们要做五件事:给短期记忆装上预算 → 抽取值得存的事实 → 建一个会检索的档案柜 → 对比"有记忆 / 没记忆"的跨会话表现 → 看压缩和遗忘。

第 1 步:给短期记忆装一个预算

复制代码
def approx_tokens(text: str) -> int:
    """粗估 token 数:中文 1 字 1 token,英文单词 1.3 token/词。"""
    zh = len(re.findall(r"[\u4e00-\u9fff]", text))
    en = len(re.findall(r"[A-Za-z]+", text))
    return int(zh * 1.0 + en * 1.3) + 1

class ShortTermMemory:
    def __init__(self, budget=800):
        self.budget = budget
        self.turns = []          # 短期记忆:就是一个 list
        self.system = ""
        self.summary = ""        # 被压缩掉的历史留下的摘要

    def tokens(self):
        total = approx_tokens(self.system) + approx_tokens(self.summary)
        for t in self.turns:
            total += approx_tokens(t["content"]) + 4   # 4 ≈ 角色标记开销
        return total

    def overflow(self):
        return self.tokens() > self.budget

关键就是那句 overflow()------没有预算检查的记忆系统,等于没有刹车。绝大多数"Agent 跑着跑着突然报错"的事故,根因都是没人盯着这个数字。

第 2 步:抽取值得存的事实(含噪音过滤)

复制代码
EXTRACTORS = [
    ("identity", r"我叫([\u4e00-\u9fffA-Za-z]{1,8})", 9, "我叫{}"),
    ("allergy",  r"我对([\u4e00-\u9fff]{1,6})过敏", 10, "对{}过敏"),
    ("location", r"在([\u4e00-\u9fff]{2,4})(?:做|搞|从事|工作|上班|生活|读书)", 8, "在{}"),
    ("domain",   r"研究(?:方向是|的是)?([\u4e00-\u9fff]{2,8})", 7, "研究方向:{}"),
    ("prefer",   r"记住[::]?\s*(.{2,28}?)(?:[,。!]|$)", 8, "{}"),
]

NOISE_PATTERNS = [r"算(?:一下|一算)?\s*[\d\s\+\-\*/x×]+", r"验证码", r"现在几点"]

def extract_facts(text):
    if is_noise(text):        # 一次性信息直接拦在门外
        return []
    facts = []
    for ftype, pattern, imp, tpl in EXTRACTORS:
        for m in re.finditer(pattern, text):
            facts.append((ftype, tpl.format(m.group(1).strip()), imp))
    return facts

🧯 踩坑提示:正则写宽了会误抓。我第一版写了 以后(.+),结果「以后推荐餐厅帮我避开」被当成"长期偏好"存了进去------这就是 4.1 节说的噪音。规则要收紧,收紧不了就加校验。

第 3 步:会合并、会检索、会遗忘的档案柜

复制代码
class LongTermMemory:
    def upsert(self, ftype, content, importance, ts=None, hits=0, last_seen=None):
        for it in self.items:                      # 同类型 + 内容重合 → 合并而不是新增
            if it["type"] == ftype and (content in it["content"] or it["content"] in content):
                it["content"] = content
                it["importance"] = max(it["importance"], importance)
                it["version"] += 1
                return it, False
        self.items.append({...}); return item, True

    def search(self, query, k=2):
        ranked = sorted(self.items, key=lambda it: -self.score(it, query))
        picked = [it for it in ranked if self.score(it, query) > 3][:k]
        for it in picked:
            it["hits"] += 1
            it["last_seen"] = NOW        # 被唤起 = 复习一次,遗忘曲线重置
        return picked

    def strength(self, it):
        if it["type"] in PINNED_TYPES:             # 用户画像,钉住,永不衰减
            return it["importance"]
        eff_half = self.half_life * (1 + it["hits"] * 0.5)
        return it["importance"] * math.pow(0.5, (NOW - it["last_seen"]) / eff_half)

打分函数 score() 里除了关键词重合,还加了一项意图提示 (TYPE_HINTS):用户问"名字/谁"就往 identity 类加权,问"餐厅/吃"就往 allergy 类加权。

🧯 说明:真实系统里这一步由 Embedding 语义相似度 完成,不需要人工写关键词表。这里用关键词近似,是为了让脚本零依赖可运行------Day 10 讲向量之后,你可以把 score() 换成余弦相似度,其他代码一行不用改。

第 4 步:实测------有记忆 vs 没记忆

会话 1(交代背景):

复制代码
我叫老张,在天津工作,研究方向是智能建造
我对花生过敏,以后推荐餐厅帮我避开
帮我算一下 17 乘以 25 是多少        -> 被判定为一次性信息,不进档案柜
记住:以后给我写报告都用结论先行的结构,别写流水账

抽取结果(5 条记忆,去重后):

复制代码
[identity] 我叫老张                          重要度=9
[location] 在天津                            重要度=8
[domain]   研究方向:智能建造                  重要度=7
[allergy]  对花生过敏                        重要度=10
[prefer]   以后给我写报告都用结论先行的结构       重要度=8
再写一次「我叫老张」-> 条数 5 -> 5(合并,不产生副本)

会话 2(新会话,短期记忆清零)问同一批问题:

问题 无记忆 Agent 有记忆 Agent
我叫什么名字? ❌ "请问怎么称呼您?" ✅ "您叫老张"
我在哪个城市、做什么方向? ❌ "这个我不太清楚" ✅ "您的研究方向:智能建造;您在天津"
推荐天津餐厅有啥注意的? ❌ 直接推了本地名吃(含花生做法) ✅ "您对花生过敏,已帮您避开相关菜品"
上次说的报告结构是什么? ❌ "请问您指的是哪份报告?" ✅ "按您的要求:结论先行"
复制代码
📊 命中率:无记忆 0/4    有记忆 4/4

第三行值得单独看一眼 :无记忆 Agent 不是"答不出来",而是给了一个看起来很专业、实际有风险的答案。这正是没有记忆的 Agent 最危险的失败方式------它不会说"我不知道",它会热情地瞎推荐。

第 5 步:实测------压缩与遗忘

压缩策略对比(24 轮对话,预算 800 token)与遗忘曲线的结果,就是第六节那两张表------它们都是这个脚本真跑出来的,不是我编的。

你可以这样玩

  1. 把 EXTRACTORS 换成你自己业务的字段(比如"会员等级""常用收货地址""预算上限");
  2. 把 SESSION_1 换成你真实的一段对话,看看抽取器漏了什么;
  3. 把 k 从 2 调到 8,观察"召回变多但噪音也变多"的临界点;
  4. 把 half_life_days 从 30 改成 7,看看哪些记忆会突然活不下来。

八、本篇小结(建议截图保存)

  1. 🧠 记忆分两套:短期记忆是桌上的便签(管"连贯",每轮重发,受窗口限制),长期记忆是楼下的档案柜(管"认识你",持久化,靠检索取回)。
  2. 💸 短期记忆的成本是平方级的:第 N 轮要发 N 轮内容。而且塞得越满,模型对中间部分越迟钝,塞爆了直接报错。
  3. 📇 长期记忆分三层 :情景(日记本)/ 语义(百科卡片)/ 程序(肌肉记忆)。最该被压缩掉的是第一种。
  4. ✍️ 写入要抽取,不要照抄:存"事实"不存"聊天记录"。一次性信息(验证码、临时文件名、实时数据)必须拦在门外。
  5. 🔁 写入必须 upsert:同类型 + 内容重合就合并,冲突就覆盖并留痕------否则 Agent 会精神分裂。
  6. 🔍 检索宁少勿多:k 取 3-8。检索 20 条塞进去,等于把档案柜倒在桌子上。
  7. 🗜️ 压缩选"摘要 + 最近 N 轮" :实测在 24 轮对话上,截断只花 137 token 但关键事实保留 0/5;摘要压缩花 178 token,保留 5/5。多花 41 个 token 换 100% 存活。
  8. 🐟 遗忘是特性不是 bug :强度 = 重要度 × 时间衰减,衰减看"上次被唤起"而不是创建时间 ,越常用忘得越慢;姓名、过敏这类用户画像要钉住。
  9. ⚠️ 记忆系统的上限,不是"能存多少",而是"该忘的能不能忘掉"。
  10. 🧯 埋个伏笔 :本文的检索用关键词近似,真实系统用 Embedding 向量相似度------明天讲 RAG,后天(Day 10)讲向量数据库,到时候把 score() 换掉即可。

📝 课后作业

  1. 动手题 :把 SESSION_1 换成你自己的一段真实对话,跑一遍脚本,看看 extract_facts() 漏抽了哪几条。漏的里面挑一条最重要的,给它补一条正则,再跑一次确认能抽到。
  2. 思考题 :你的 Agent 跑了三个月,长期记忆库里有 8000 条。用户投诉"它最近老提起一些过时的东西"。请用第六节的思路,写出你的三条整改措施,并说明哪些记忆应该被标成"钉住"。
  3. 进阶题 :把演示 4 的 strategy_summary() 改成"分层摘要"------每 10 轮压一次小摘要,小摘要再压成大摘要。对比单层摘要,看看在 50 轮对话下哪个 token 更省、关键事实保留率更高。

🔮 下集预告

Day 09|RAG 检索增强生成:给 Agent 外挂一个随身图书馆

今天我们让 Agent 记住了你 。但还有一类东西它依然不知道:你公司的产品手册、上周的会议纪要、那本 300 页的行业规范。

这些东西有几个共同点:量大(塞不进上下文)、会变(记死了就过时)、不是"关于用户"的(不该进用户画像)。硬塞进 System Prompt?Day 07 讲过,那是把 300 页文档每轮重发一遍。塞进长期记忆?检索准度又不够。

明天我们讲一个几乎所有生产级 Agent 都离不开的东西------RAG(Retrieval-Augmented Generation,检索增强生成):

  • 📚 为什么它是"外挂图书馆"而不是"背下来"
  • 🔪 切分怎么切才不把一段完整的意思劈成两半
  • 🔢 向量化 → 检索 → 重排 → 生成的完整链路,一步步拆
  • 🚑 以及最重要的:什么时候 RAG 也救不了你

剧透一句:RAG 的难点从来不在"检索",在"切分"和"检索不到时怎么办"。 明天 12:00 见。😉


🗺️ 系列导航

阶段 篇目 主题
认知篇 Day 01-06 Agent 是什么、四大件、ReAct、Function Calling、概念辨析(✅ 已完结)
能力篇 Day 07-14 提示词、记忆、RAG、向量库、规划、自愈、上下文工程、人设(📍 你在这里:Day 08)
框架篇 Day 15-21 LangChain / LangGraph / LlamaIndex / Dify / 手写 mini Agent
多智能体篇 Day 22-27 多智能体架构、MCP、A2A、人机协同
工程化篇 Day 28-33 评测、可观测、成本优化、安全护栏、生产落地、收官实战

已更新 :Day 01|Agent 到底是什么? · Day 02|LLM 和 Agent 的区别 · Day 03|解剖一只 Agent:四大件 · Day 04|ReAct 循环:想→做→看→再想 · Day 05|Function Calling 从零讲透 · Day 06|四个概念辨析与选型 · Day 07|提示词工程(Agent 版)

每天 12:00 更新一篇。 觉得有用的话,点个收藏,别到时候找不到路了 😄 有问题欢迎在评论区留言,每一条我都会看,典型问题会写进后续的加餐篇。

相关推荐
众链网络1 小时前
从一次近 5 小时的大模型中断,讲清 AI 应用的降级设计
人工智能·架构
yuanyxh1 小时前
我的工作流
agent·claude·deepseek
roman_日积跬步-终至千里1 小时前
【数据Agent论文·分析工作流|20】Data Interpreter:任务图怎样帮助复杂分析?
人工智能·数据分析
en.en..1 小时前
MRS/MSR 指令操作 xPSR 寄存器
linux·运维·服务器
buddyMe智能助手1 小时前
长任务拆给谁?把专门化智能体存成可复用、会增长的「选项」
人工智能·深度学习·安全·机器学习·aigc
原子延迟1 小时前
证件照压缩到20k,原图和电子版的3种方法(2026)
图像处理·人工智能·计算机视觉
badhope1 小时前
AI Agent安全治理实战:从API密钥泄露到沙箱隔离的完整防线
后端·llm·agent
Smoothcloud润云1 小时前
GPU算力平台推荐:新手租GPU时,镜像环境和显存应该怎么选?
大数据·人工智能·pytorch·分布式·深度学习·gpu算力
飞哥数智坊1 小时前
REA 支持 TRAE 了,我拿自己的开源软件做了一次逆向实测
人工智能·trae