Day 36 / 共 68 天 · 阶段 6 Agent 核心
记忆 Memory
昨天(Day 35)你学会让 Agent 先规划再执行。但计划再好,如果它做完第 2 步就忘了第 1 步查到啥、这次告诉它的偏好下次全忘光,照样是个"金鱼脑"助理。今天补上 Agent 四大零件的最后一块——记忆(Memory):短期、长期、工作记忆各是什么,信息什么时候该"写进"记忆、什么时候别乱记。学完,阶段 6 的 Agent 核心概念就全齐了;明天(Day 37)讲怎么把记忆和进度存盘、支持"断点续跑"。
📍 你在阶段 6(Agent 核心 D33-38)的位置
D33 Agent 是什么→
D34 ReAct→
D35 规划→
D36 记忆→
D37 状态&断点→
D38 手写最小 Agent
💡 用一个类比兜住今天(今天全程沿用「新来的助理和他的记事本」的世界观)
大模型本身像个能力超强但一见面就"失忆"的临时工:每次调用它只看得到你当场递给它的那几页纸,过后一概不记得。要让这位助理靠谱,得给他配记事本:短期记忆=他手边这次谈话的便签(聊完这单就可能撕掉);长期记忆=他的档案柜(把"客户偏好""历史结论"归档,以后随时翻);工作记忆=他此刻摊在桌上、正在用的那几张纸(当前任务的关键中间结果)。今天的活儿,就是学会什么该写进便签、什么该归档、什么该马上扔——一个只会往档案柜里乱塞的助理,和金鱼脑一样没法用。
L01
转身就忘的助理:模型天生没记忆
🤔 痛点你和一个聊天 AI 说"我叫小明,对花生过敏",下一轮问"我能吃这道宫保鸡丁吗",它可能压根不记得你过敏——因为大模型每次调用都是"从头开始",不自带上一句的记忆。
💡 本质关键认知:LLM 是"无状态"的——它唯一"记得"的,就是你这一次调用时塞给它的那段文字(上下文)。它不会自己保存历史。所谓"AI 记得我们聊过啥",其实全是你的程序在背后帮它把该记的内容,每次重新塞进上下文。记忆不是模型的天赋,是你这个开发者给它外挂的能力。
👶 那我平时用的 ChatGPT 明明记得上文啊?那是因为对话界面/程序每次都把之前的对话记录一起发过去了——你看到的"它记得",是应用层帮它带上了历史,不是模型自己存的。理解这一点,你就抓住了做记忆的钥匙:记忆 = 决定"下次调用时,该把哪些旧信息重新塞进去"。
L02
三种记忆:便签 / 档案柜 / 桌面
🤔 痛点"记忆"听着是一坨,其实按"记多久、记什么"分成几类,分清了才知道各用什么技术存。
💡 本质三类,对应助理的三种"记东西的地方":
| 类型 | 助理类比 | 存什么 | 怎么实现 |
|---|---|---|---|
| 短期记忆 | 本次谈话的便签 | 当前对话/任务的历史消息 | 一个消息列表(Day 32 那个 messages) |
| 长期记忆 | 档案柜 | 跨会话要长久记住的:用户偏好、过往结论、知识 | 存进数据库/向量库,用时检索(RAG 的老本行) |
| 工作记忆 | 此刻摊在桌上的几张纸 | 当前这一步最相关的关键中间结果 | 从短/长期里挑出来、放进当前上下文的那部分 |
图注:短期/长期是"存在哪",工作记忆是"这次拿哪些出来用"。三者配合,决定模型每次到底"看到"什么。
L03
短期记忆:就是那个消息列表
🤔 痛点短期记忆听着高级,到底是个啥数据结构?
💡 本质朴素到你已经见过它了——就是 Day 32 一直在追加的那个
messages 列表!每轮把用户说的、模型回的、工具返回的都 append 进去,下次调用整个列表一起发。这个不断变长的列表,就是 Agent 的短期记忆(便签本)。它让模型"记得"这次任务里前面发生的一切。# 短期记忆 = 一个随对话增长的列表,每次调用都整个带上
memory = [{"role": "system", "content": "你是助理,记住用户告知的信息。"}]
def chat(user_text):
memory.append({"role": "user", "content": user_text}) # 把新话记进便签
reply = llm(memory) # 整本便签一起交给模型(它才"看得见"上文)
memory.append({"role": "assistant", "content": reply}) # 把回答也记进去
return reply
chat("我叫小明,对花生过敏") # 便签第1条
chat("我能吃宫保鸡丁吗?") # 此时模型看得到"过敏",会提醒有花生 → 有记忆了!
对照 L01:模型没变(还是无状态),变的是我们每次都把整本便签递给它。这就是"短期记忆"的全部魔法——没有黑科技,就是"带上历史"。
👶 小白:那对话越来越长,便签一直加下去不会爆吗?
👨🏫 老师:会!上下文窗口有上限(Day 10),而且越长越贵越慢(Day 13)。所以长对话要压缩短期记忆——常见招:①只保留最近 N 轮;②把更早的对话让模型总结成一段摘要再塞回去(这正是 Day 18 上下文工程讲的"历史压缩/摘要")。便签写满了,就撕掉细节、留个提要贴上。
L04
长期记忆:把该归档的塞进档案柜(向量库)
🤔 痛点短期记忆聊完就没了。可有些事要跨会话长久记住:上周小明说过他过敏、他偏好简洁回答、上个项目得出的结论……总不能每次都塞进便签(装不下也没必要)。
💡 本质把这些"要长久记、但不必时时都看"的信息,归档进档案柜——存成一条条记录,放进数据库或向量库。用的时候不是全搬出来,而是按当前需要"检索"出最相关的几条再塞进上下文。是不是很耳熟?——这就是阶段 4 学的 RAG!长期记忆 = 对"Agent 自己积累的经历/知识"做 RAG。
图注:所以你阶段 4 学的 embedding、向量库、检索(Day 21-28),在这里原封不动复用——课程是一张网,不是一堆孤岛。
📝 举个例子:有长期记忆的助理什么体验
第一次:你告诉客服 Agent"我用的是 Pro 版、上次那个导出 bug 还没解决"。它把这条归档。
两周后你再来问别的,它检索到档案:"了解,您是 Pro 版用户,上次的导出问题这边帮您确认下是否已修复……"——不用你重说一遍。这种"记得你"的体验,就是长期记忆带来的,也是产品粘性的来源。
两周后你再来问别的,它检索到档案:"了解,您是 Pro 版用户,上次的导出问题这边帮您确认下是否已修复……"——不用你重说一遍。这种"记得你"的体验,就是长期记忆带来的,也是产品粘性的来源。
L05
什么时候写入:不是啥都往档案柜塞
🤔 痛点短期记忆好说(每轮都追加)。可长期记忆——到底哪些该归档?总不能把每句闲聊都存进向量库吧?
💡 本质写入长期记忆要挑,判断标准:"以后大概率还用得上,且现在不记以后就丢了"。典型该记的:①用户明确的偏好/设定(过敏、喜欢简洁、时区);②稳定事实(账号信息、长期目标);③重要结论/成果(某任务最终得出的结果)。不该记的:一次性的闲聊、临时中间量、马上会过期的信息。
图注:谁来决定写不写?可以你的代码定规则,也可以让模型自己判断"这条值得记吗"再调一个"写记忆"工具(呼应 Day 29 的 Function Calling)。
👶 让模型自己决定记什么,靠谱吗?可以,但要给清规则、并复查。常见做法:给它一个
save_memory(内容) 工具,在提示里写明"仅当用户表达长期偏好或达成重要结论时才调用"。这样它会在合适时机主动归档。不过初学阶段,你先用简单规则(比如只存用户主动说的偏好)就够了,别一上来追求花哨。L06
别记太多:记忆也是把双刃剑
🤔 痛点既然记忆这么好,是不是记得越多越聪明?把一切都塞进上下文?
💡 本质恰恰相反,记太多会反噬:①上下文塞满无关信息,模型抓不住重点(Day 18 说的"lost in the middle"——中间信息被忽略);②又贵又慢(Day 13);③过时的旧记忆会误导当前判断(比如客户早换了套餐,旧档案还写着老套餐)。好的记忆不是"记得多",而是"每次只把此刻最相关的几条端上桌"——这正是"工作记忆"的活儿。
📝 举个例子:记太多的翻车
档案柜里存了小明三年前说"喜欢重口味"。但他去年备注改成了"最近清淡饮食"。若两条都无差别塞进去、且旧的排在前面,Agent 可能推荐一堆重辣菜——过时记忆盖过了新信息。对策:记忆要带时间戳、可更新/失效,检索时优先近期、冲突时以新为准。记忆管理本身就是一门手艺。
一句话收束:记忆的目标不是"什么都记住",而是"该记的记住、该忘的忘掉、每次只端出最相关的"。这和 Day 18 上下文工程、Day 35"别过度"是同一种克制。会取舍的记忆,才是好记忆。
L07
今日小结 + 动手 10 分钟
🧠 今天你应该能回答
- 为什么说"大模型本身没有记忆"?你平时看到的"它记得"是怎么来的?
- 短期 / 长期 / 工作记忆分别是什么?各用什么技术实现?
- 短期记忆本质就是哪个东西?(Day 32 的 messages 列表)长对话怎么压缩?
- 长期记忆和阶段 4 的 RAG 是什么关系?
- 什么信息该写进长期记忆?什么不该?为什么"记太多"反而有害?
✋ 动手 10 分钟:给"金鱼脑"装上短期记忆
把 L03 那段跑起来,亲眼见证"带不带历史"的天壤之别。存成 memory.py(用 input() 假装模型,聚焦记忆机制本身):
memory = [] # 短期记忆:一本空便签
def fake_llm(mem): # 假模型:只根据"便签里有没有过敏"来答
text = " ".join(m["content"] for m in mem) # 把便签所有内容拼一起看
if "过敏" in text and "鸡丁" in text:
return "宫保鸡丁含花生,你过敏,别吃!" # 它"记得"过敏了
return "好的,我记下了。"
while True:
u = input("你说(回车退出):")
if u == "": break
memory.append({"role": "user", "content": u}) # 记进便签(关键!)
reply = fake_llm(memory) # 把整本便签交给它
print("助理:", reply)
memory.append({"role": "assistant", "content": reply})
# 试:先输"我对花生过敏",再输"我能吃宫保鸡丁吗" → 它会拦住你
# 再把 memory.append(user) 那行注释掉重跑 → 它立刻"失忆",随便让你吃
# 这一行的差别,就是"有没有记忆"的全部秘密。
玩法:注释掉"记进便签"那行,对比前后——你会亲手证明:记忆不在模型里,在你有没有"带上历史"这个动作里。这个体感,比背十遍定义都深刻。
明日预告 · Day 37:恭喜——Agent 四大零件(大脑/手脚/记忆/岗位说明)到今天全齐了!但还有个现实问题:任务跑到一半程序崩了/要等人审批,记忆和进度怎么存盘、之后接着跑?明天进入阶段 6 收尾兼衔接框架:状态(state)共享黑板 + checkpointer 存档 + 中断等人,并首次深潜 LangGraph——你会看到工业框架怎么优雅地解决"断点续跑"。