Agent Memory 深度解析:三层记忆系统,让 Agent 从一次性工具变成长期助手
这是「近五年 AI 技术演进」系列深挖的第十一篇。上一篇 AGENTS.md 解决的是「AI 怎么在你的仓库里少犯错」这一篇解决一个更根本的问题它凭什么记得昨天发生的事。一句话定位短期 / 工作 / 长期三层记忆管理。全文约 6500 字含一张三层对照表、三段可运行代码和六张原创信息图。一、一个让人恼火的瞬间周一上午你跟 AI 说「这个项目用 pnpm别用 npm装依赖的时候注意 workspace 软链。」它答应得很痛快。那天它表现很好pnpm add、pnpm -r build一次没错。周三下午你开了个新对话让它给新模块加个日期库。它敲下的第一条命令是npm install dayjs你盯着屏幕愣了两秒。不是生气是那种「原来你根本没记住」的荒谬感——明明两天前才说过明明它当时还复述了一遍「好的用 pnpm」。这不是模型不听话也不是你说得不够清楚。它压根就没有「记住」这个动作。二、先把残酷事实说清楚模型没有记忆2.1 它是一个无状态的函数把大模型的调用过程写成伪代码就一行next_tokens model(context_tokens) # 输入一坨 token输出下一坨 token没有隐藏的self.state没有磁盘上的memory.db也没有「上次那个用户」。函数执行完一切归零。你在界面上看到的「连续对话」是应用层每次把整段历史重新拼进context_tokens再发一遍的结果。换句话说对话的连续性是一种表演是靠每一轮重发全文伪造出来的。顺手澄清一个常见误解KV Cache 不是记忆。它缓存的是同一前缀的注意力中间结果作用只是让你重发那几千 token 时不必重算——它是加速手段不是存储机制。换个会话、换个前缀缓存立刻作废。2.2 上下文窗口就是它的全部世界而且这个世界很挤模型能「看见」的只有当前这次调用里的 token这就是它的全部世界。这个世界有三重物理约束长度有限。现在动辄 128K、200K甚至标称百万级。听起来很大换算成中文也就一本中等厚度的书。你让它读一个中型仓库的代码几轮工具调用就满了。按 token 计费而且每一轮都计。一个 3 万 token 的上下文跑 20 轮就是 60 万 token 的输入账单。记忆不免费遗忘才是。注意力会稀释。这是最容易忽略的一条。论文 Lost in the Middle 测出一条 U 形曲线放在上下文开头和结尾的信息召回准确率最高塞在中间那段的明显下滑。所以「窗口够大随便塞」是危险的幻觉——能装进去不等于能被用上。2.3 所以「记忆」是工程的职责既然模型自己不记就只能由外面替它记、替它在合适的时机把东西塞回去。这件事的雏形是 RAG——把外部知识检索出来拼进上下文。两者是同一个族谱上的东西本质都是「把外部信息喂给模型」。但 Memory 比 RAG 多走了关键的一步RAGAgent Memory信息来源静态文档库事先准备好运行过程中动态产生时间维度无文档没有「什么时候学的」有记忆带时间戳、会过期、会被覆盖写入方人灌数据Agent 自己写边干边记目标回答这一次的问题让下一次会话比这一次更聪明打个比方RAG 是图书馆书是别人写好的你只能借阅Memory 是你自己的笔记本你边干边写写错了还得划掉重写。从「一次性工具」变成「长期助手」分界线就在这里。三、三层记忆把「记不住」拆成三个不同的问题「让 Agent 有记忆」这句话太笼统落地的时候必须拆开。因为「记住」至少是三种完全不同的需求记住刚才说了什么、记住这件事干到哪了、记住这个人是谁。人的大脑其实也是这么分的工作记忆working memory容量只有 4±1 个组块几分钟就散长期记忆可以存几十年但提取靠线索。Agent 的三层架构几乎是照着这个抄的。3.1 短期记忆脑子里正在想的事存什么。当前这一轮对话的原始消息序列用户说了什么、模型回了什么、每一次工具调用和返回。就是那一坨messages数组。存在哪。就在上下文窗口里物理上存在于你下一次请求的messages字段里。没有别的地方。怎么管理。它是易失的——会话结束或messages被清空就没了。特征是三个字原、多、贵。原文保真度最高但体积最大、最贵而且随轮次线性增长。所以对它只有一个动作在它撑爆窗口之前处理掉。顺带记住短期记忆不是「模型记住了」而是「你还没删」——它的生命周期由你的代码决定不由模型决定。3.2 工作记忆桌上摊开的草稿纸这一层是三层里最容易被跳过、但工程价值最高的一层。存什么。当前任务的中间状态目标是什么、已经查到哪些事实、试过哪条路失败了、下一步打算干什么、产出物落在哪个路径。它是结构化的字段不是自然语言。存在哪。你的应用内存里、一个 dict 里、一个State对象里——或者被序列化到磁盘/数据库做检查点。关键是它在上下文窗口之外只是因为需要才被渲染进 prompt。怎么管理。必须显式读写。这是它和短期记忆最大的区别短期记忆是自动堆积的工作记忆是代码主动维护的。每次工具调用返回后你或者模型通过一个update_state工具要把「刚查到什么」写进state[findings]每次决定下一步要把它写进state[plan]。为什么非要多这一层三个理由它抗压缩。二十轮对话压成三百字摘要必然丢细节但state[files_created]压缩前后一模一样。它抗崩溃。进程挂了、超时了、用户关了页面只要状态被持久化下次从断点续跑。它抗跑偏。长任务里模型最容易犯的错是忘记最初目标。把目标钉在 state 里每轮渲染一次比在对话历史里翻找可靠得多。草稿纸的类比很贴切你不会把想的事都记在脑子里你会写下来摊在桌上抬眼就能看见。3.3 长期记忆笔记本和档案柜存什么。跨会话仍然有价值的东西大致三类用户偏好「用 pnpm 不用 npm」「回答别超过 300 字」「我不看 emoji」项目结论「订单服务的时间字段统一用 UTC 存、前端转本地时区」历史决策及其理由「2026 年 3 月放弃了 MongoDB因为运维成本改回 MySQL」——这条比结论本身更值钱因为它防止你在半年后重新讨论一遍。存在哪。一般是混合存储偏好和画像用关系库/键值库要精确命中、要能改语义类经验用向量库要模糊召回实体关系复杂的用知识图谱Zep 那类方案走的就是这条路。怎么管理。两个动作写入和召回。写入的关键不是「怎么存」而是「存什么」。绝大多数失败的记忆系统死在这一步——什么都记结果库里 90% 是废话。我的经验是三条准入标准被用户纠正过的说明模型默认行为错了、跨会话还会用到的一次性任务细节不入库、有明确结论的「试了 A 和 B最后选 B」而不是「讨论了 A 和 B」。召回的关键是别只看向量相似度。一个可用的打分公式来自 Generative Agents 那篇论文三个因子加权score α × 相关性(embedding 相似度) β × 时效性(越近越高指数衰减) γ × 重要性(写入时由模型打 1~10 分)只用相似度会出问题三个月前那条「这个项目用 npm」的相似度可能比上周那条「改用 pnpm 了」更高因为它出现次数多、表述更典型。加上时效性权重才能让新结论压过旧结论。3.4 三层对照表这张表建议存下来实现记忆系统时对着它填维度短期记忆工作记忆长期记忆存储位置上下文窗口messages数组应用内存中的结构化 State可持久化为检查点数据库 / 向量库 / 知识图谱生命周期单次会话会话结束即失单个任务任务结束可归档永久直到被显式覆盖或遗忘容量受窗口限制几十万 token 上限实际可用更少几 KB ~ 几十 KB字段数可控理论无上限实际受成本与检索精度约束读写方式自动追加代码裁剪代码显式读写state[plan] ...写入模型判断 规则过滤读取检索召回典型内容原始对话、工具返回全文任务目标、已查事实、失败路径、下一步、产物路径用户偏好、项目约定、历史决策与理由失效方式会话结束任务完成被新记忆覆盖 / 过期 / 主动遗忘主要风险撑爆窗口、注意力稀释状态字段设计不全模型无从判断进度记忆污染、召回不准、无限膨胀四、三层之间怎么流动架构图好看落地时真正难的是流动。哪一层的东西什么时候搬到另一层搬多少谁来搬。4.1 上行一短期 → 工作记忆摘要沉淀触发时机通常是两个每 N 轮或者上下文占用超过阈值比如 70%。动作是把最近一段对话交给模型让它输出结构化的增量合并进 state。请从以下对话中提取只输出 JSON { facts: [已确认的事实每条一句话], decisions: [已做出的决定], open: [还没解决的问题], artifacts: [产出的文件路径或 ID] } 没提到的字段返回空数组不要推测。注意「没提到就返回空数组不要推测」这句——不加这句模型会为了填满字段而编造。这是工作记忆被污染的头号来源。沉淀完之后那段原始对话就可以压缩甚至丢弃了。这就是短期记忆的出口。4.2 上行二工作 → 长期记忆任务结束归档任务完成后问三个问题这条结论在别的会话里还有用吗它是否纠正了某个默认行为半年后有人问「当初为什么这么定」这条能回答吗三个里命中一个才写。全不命中的留在工作记忆里随任务一起丢掉。归档时务必带上元数据时间、来源会话、置信度、作用域全局 / 某项目 / 某仓库。没有作用域的记忆是灾难——你在 A 项目里定的「用 pnpm」会被搬到 B 项目里去而 B 项目是 npm workspace。4.3 下行长期 → 上下文召回回填两个时机会话开始预取。拿到用户 ID 和作用域当前仓库路径直接按 key 查偏好类记忆。这部分不需要语义检索精确查询又快又准通常几百 token直接注入系统提示。任务进行中按需检索。遇到具体问题时用当前任务描述去向量库检索取 top-k加时间衰减重排再把命中项拼成一段「相关历史」注入。这部分要克制k 别超过 5宁缺毋滥。4.4 三个动作对应三种「遗忘」记忆系统里写什么和忘什么同等重要短期记忆的遗忘是压缩保住语义、丢掉原话工作记忆的遗忘是归档任务结束状态转成一条长期记忆或直接丢弃长期记忆的遗忘是失效新结论覆盖旧结论或按 TTL 过期。没有遗忘机制的系统三个月后一定变成一个又慢又贵又不准的垃圾场。五、一个例子走完三层pnpm回到开头那个场景。如果记忆系统是对的全过程应该长这样T0周一你第一次说。「这个项目用 pnpm」作为一条普通消息进入短期记忆。此时它没什么特殊就是对话历史里的第 7 条。T1同一会话内它被沉淀。上下文用到 60% 触发压缩模型抽取增量时把这条识别成偏好类事实「包管理器偏好 pnpm理由workspace 软链」写进工作记忆的facts字段。原始对话被压成摘要但这条事实完整保留——因为它是结构化的不依赖原文措辞。T2任务结束时它被归档。那天任务完成归档逻辑判断这条结论跨会话有用命中问题 1且纠正了默认行为命中问题 2。于是写入长期记忆作用域标记为repo: trip-miniapp置信度 0.9来源是用户明确指令。T3周三新会话它被召回。新会话启动代码先做精确预取scope repo:trip-miniapp的偏好类记忆有 3 条其中一条是 pnpm。这 3 条一共 120 token拼进系统提示【项目约定】 - 包管理器使用 pnpm用户明确要求勿用 npm/yarn - 时间字段统一 UTC 存储前端转本地时区 - 数据库为 MySQL 5.7注意不支持窗口函数于是周三它敲的是pnpm add dayjs。这就是全部魔法。模型依然没有记忆一行都没变。变的是有一层工程代码在它每次醒来之前替它把最该知道的三句话放在了枕头边。六、代码三层记忆到底怎么写6.1 一个最小可用的实现不用框架几十行就能跑通三层。核心就四个方法remember写短期、render_state把工作记忆渲染进上下文、consolidate上行沉淀、recall下行召回。import json, time from dataclasses import dataclass, field, asdict dataclass class MemoryItem: content: str scope: str # 作用域user:123 / repo:xxx kind: str # preference / decision / fact importance: int 5 # 1~10写入时打分 ts: float field(default_factorytime.time) confidence: float 1.0 id: str # 存储层生成 similarity: float 0.0 # 检索时回填不落库 class AgentMemory: def __init__(self, llm, store, scope): self.llm, self.store, self.scope llm, store, scope self.short_term [] # 短期messages self.state {goal: , facts: [], plan: [], artifacts: []} staticmethod def _tokens(messages): # 粗估即可不用精确分词 return sum(len(m[content]) for m in messages) // 2 # ---- 写短期 ---- def remember(self, role, content): self.short_term.append({role: role, content: content}) # ---- 读工作记忆渲染进上下文 ---- def render_state(self): s self.state return (f【任务目标】{s[goal]}\n f【已确认】{; .join(s[facts]) or 无}\n f【下一步】{; .join(s[plan]) or 无}) # ---- 上行短期 - 工作上下文超阈值时触发---- def consolidate(self, threshold_tokens80000): if self._tokens(self.short_term) threshold_tokens: return None prompt (从以下对话提取增量只输出 JSON {facts:[],decisions:[],open:[],artifacts:[]} 没提到的字段给空数组禁止推测。\n\n json.dumps(self.short_term[-40:], ensure_asciiFalse)) delta json.loads(self.llm(prompt)) self.state[facts] delta[facts] self.state[plan] delta[open] self.short_term [{role: system, content: 【早期对话摘要】 self.llm( 用 200 字概括以下对话保留数字和结论\n json.dumps(self.short_term[:-40], ensure_asciiFalse))}] return delta # ---- 上行工作 - 长期任务结束时调用---- def archive(self, conclusions): for c in conclusions: item MemoryItem(contentc[text], scopeself.scope, kindc[kind], importancec[importance]) self.store.upsert(item) # 同 scopekind主题则覆盖见 10.4召回那一侧是「精确查 语义查」两条路合并# ---- 下行长期 - 上下文会话开始时调用---- def recall(self, query, k5): pinned self.store.query(scopeself.scope, kindpreference) # 精确 hits self.store.search(query, scopeself.scope, kk) # 向量 now time.time() def score(it): recency 0.995 ** ((now - it.ts) / 3600) # 每小时衰减 return 0.5 * it.similarity 0.3 * recency 0.2 * it.importance / 10 merged {it.id: it for it in pinned hits}.values() top sorted(merged, keyscore, reverseTrue)[:k] return 【相关记忆】\n \n.join(f- {it.content} for it in top)两个细节值得注意pinned偏好类走精确查询并始终注入因为偏好不该靠相似度碰运气语义检索的结果要经过时间衰减重排否则老记忆会靠「表述更典型」压过新结论。6.2 用框架LangGraph Checkpointer如果任务本身就跑在图里工作记忆这一层可以直接交给框架。LangGraph 的持久化层 就是干这个的图里有一个State每次节点执行完框架自动存一个检查点checkpoint。from langgraph.graph import StateGraph, MessagesState from langgraph.checkpoint.sqlite import SqliteSaver builder StateGraph(MessagesState) builder.add_node(plan, plan_node) builder.add_node(research, research_node) builder.add_edge(__start__, plan) builder.add_edge(plan, research) builder.add_edge(research, plan) # 循环直到 plan 里没有待办 with SqliteSaver.from_conn_string(memory.sqlite) as saver: graph builder.compile(checkpointersaver) config {configurable: {thread_id: task-20261020-001}} graph.invoke({messages: [(user, 给订单模块加时区处理)]}, config)thread_id就是工作记忆的主键。只要它不变进程重启、服务重发、用户第二天回来都能graph.invoke(None, config)从断点继续——因为状态存在 sqlite 里不在内存里。更实用的是它支持时间旅行graph.get_state_history(config)拿到整条检查点链可以回滚到任意一步重跑。调试长任务时这功能价值极高——某一步走错了不用从头再来。但要清楚它的边界Checkpointer 只管工作记忆不管长期记忆。它回答的是「这个任务干到哪了」不回答「这个用户是谁、他偏好什么」。长期记忆还得自己搭或者用 LangMem、Mem0、Letta 这类专门方案。七、上下文窗口管理压缩、截断、淘汰短期记忆总会满。满了以后只有三种动作选错会很痛。7.1 三种策略各管什么策略做什么适合代价压缩Compaction让模型把一段历史概括成摘要替换原文长对话、探索型任务、结论比过程重要丢细节、多一次模型调用、可能引入摘要错误截断Truncation直接丢掉最早的若干条或把超长工具输出砍掉工具返回巨大但只用一次比如读了一个 3000 行文件丢上下文、模型可能重复已做过的操作淘汰Eviction按打分挑价值最低的丢不是按时间混合型历史早期有关键结论、近期有大量废话需要能算分实现复杂三者的选择有个简单判据这段内容「以后还会被引用」吗会就压缩不会就截断拿不准就淘汰。在工具输出这一侧截断几乎没有争议——一个 5000 行的日志读进来模型真正用的可能就那 3 行。更好的做法是在工具层就截断返回前 N 行 「共 N 行已截断需要更多请用 offset 分页」而不是让全文涌进上下文再想办法删。7.2 优先级原则谁最不该被丢窗口紧张时按这个顺序保系统指令与硬约束绝对不能动当前任务目标与状态工作记忆渲染块最近 3~5 轮对话原文不改写召回的长期记忆挑 top-3宁少勿滥中段历史摘要可再压早期工具输出原文最先丢这个顺序背后的逻辑是越靠前的东西越是「怎么做事」越靠后的越是「做过什么」。丢「做过什么」模型顶多重复劳动丢「怎么做事」它会立刻违反约束。还有个位置技巧因为 Lost in the Middle 那个 U 形曲线最关键的约束应该放在上下文的最前面或最后面别埋在中间。系统提示放最前是对的任务目标如果很长值得在最后再复述一遍——这不是浪费 token是买准确率。7.3 工程上的几个具体做法阈值设在 70%~80%别等 100%。一是留缓冲应对突发的巨型工具返回二是压缩本身也要消耗 token。压缩要保数字和路径。摘要 prompt 里明确要求「保留所有数字、文件路径、函数名、错误码」——这些是模型最容易在概括时弄丢、又最需要精确复现的东西。压缩后重新注入状态。摘要的可靠性不如结构化字段压缩触发后把render_state()的输出作为第一条 system 消息再插一次。留一个「不可压缩区」。用户的原话尤其纠正类尽量保留原文。说「别用 npm」被摘要成「用户对包管理器有偏好」语义就衰减了。小心压缩把 prompt cache 打掉。主流 API 的缓存按前缀命中而压缩替换的是上下文中间的内容——一旦替换后面所有 token 的前缀都变了缓存全废。于是会出现一个诡异现象为了省 token 做的压缩反而让那一轮账单变贵。对策是让压缩发生在边界上按轮次整段替换而不是从历史中间挖掉一段。八、Context Engineering为什么它比 Prompt Engineering 更关键前几年大家聊 Prompt Engineering怎么写角色、怎么给例子、怎么加「让我们一步步思考」。现在这个词正在被另一个词替换Context Engineering上下文工程。Anthropic 有篇专门的博客讲这件事Effective context engineering for AI agents核心论点一句话上下文是有限资源工程的任务是在这个预算里放最有价值的信息。这个视角的转换是必然的。Prompt Engineering 的隐含假设是「上下文够大把话说清楚就行」而 Agent 的实际情况是一个任务跑二十轮工具返回、检索结果、中间产出全在抢同一个窗口。写一句漂亮的 prompt 已经不是瓶颈争的是名额。一个真实的预算表大概长这样以 128K 窗口为例占用项典型大小能否压缩说明系统提示 硬约束2K ~ 5K否每次都要精确尽量精简工具定义50 个工具5K ~ 15K部分可按需动态加载只挂当前需要的长期记忆召回0.5K ~ 2K是top-k 可调工作记忆状态块0.3K ~ 1K否结构化性价比最高对话历史10K ~ 60K是压缩的主要对象工具返回结果10K ~ 80K是最先被截断输出预留4K ~ 8K否不留会截断回答看完这张表能得出一个反直觉的结论最划算的投入是工作记忆那一行。三百 token 的状态块能顶掉几万 token 的对话历史——因为它把「我干到哪了」压缩到了极致。这也是我第三节说工作记忆工程价值最高的原因它不是在存记忆它是在省上下文。九、实现方案怎么选9.1 四种路子手写状态管理。一个 dict、一张表、几百行代码。完全可控、调试直观但压缩逻辑、去重、作用域、并发全要自己写。适合任务形态固定、规则清晰的产品。框架内置LangGraph Checkpointer 等。白送工作记忆这一层自动检查点、断点续跑、时间旅行、按thread_id隔离。代价是接受它的状态模型且它不解决长期记忆。适合本来就用图编排的项目。向量数据库。把记忆当文档存靠 embedding 检索。实现快、天然支持模糊召回但把「记忆」降级成了「搜索」——没有覆盖语义、没有时间推理、没有冲突解决。很多项目的「记忆系统」其实就是这一层然后死在第十节那几个坑上。托管记忆服务Mem0 / Letta / Zep 等。直接调add(messages)/search(query)通常内置了抽取、去重、冲突消解。代价是记忆结构受制于人、数据要出境。Letta 的思路值得一提——它源自 MemGPT 论文把上下文当内存、外部存储当磁盘让模型自己通过工具调用「换页」这个类比至今仍是理解 Agent 记忆最好的框架。9.2 一个务实的组合别一上来就搭全套分三个阶段第一阶段只做工作记忆。一个结构化 state 一个检查点存储。这一步就能解决 60% 的「Agent 干到一半忘了自己在干嘛」。第二阶段加「偏好类」长期记忆只存用户明确纠正过的内容走精确查询注入。先别做语义检索把准的做对。第三阶段上下文真的经常满了再上压缩和语义召回。这时你已经有真实数据知道该压什么。什么时候才需要向量库记忆条目超过几千条、且查询意图确实模糊「上次那个部署失败的事」时。几百条记忆用 SQLLIKE加时间排序效果往往更好。十、四个真实的坑10.1 记忆污染错的东西一旦写进去会一直错这是最贵的坑因为它有复利效应一条错误记忆会被反复召回、反复强化最后变成「事实」。常见来源有三个摘要时推测补全「用户大概想要 A」、把一次性状态写成通用偏好「这次用 npm」→「偏好 npm」、以及把模型自己的话当成用户的话Agent 说「我建议用 yarn」归档成「用户要用 yarn」。三个对策标注信源每条记忆带source: user_explicit / user_implicit / agent_inferred只有前两类能进「硬约束」区写前确认高重要性记忆入库前问一次「我记下了这个项目用 pnpm对吗」可撤销记忆列表对用户可见、可删、可改——用户看不到的记忆系统等于把错误的黑盒装进了产品。10.2 召回不准该来的没来不该来的来了两种失败模式漏召回用户问「按我们之前的规范来」却没命中模型开始自由发挥——对策是关键词与向量双路召回再合并专有名词、项目代号这类东西 BM25 反而比 embedding 准误召回召回了别的项目、别的用户、或已失效的旧结论——对策是检索前先按scope过滤再算相似度而不是先算相似度再过滤。还有一种更隐蔽的召回得太多。top-10 塞进去模型反而抓不住重点。三个精准的胜过十个模糊的。10.3 无限膨胀记忆越多越慢越贵越不准记忆系统的成本是三重叠加的存储、检索、以及注入上下文的 token每次会话都要付。更麻烦的是精度——库里一万条记忆检索到相关条目的概率反而下降因为噪音变多了。必须显式设计淘汰TTL任务类 30 天过期偏好类长期有效、合并相似度 0.9 的同类归并保留最新表述与最高置信度、降权长期未被召回的记忆逐步降权低于阈值归档冷存储、总量上限每个 scope 设 500 条超了按「重要性 × 时效性」淘汰末尾。一句话记忆系统的质量不看存了多少看召回命中率。10.4 记忆冲突与越权冲突。用户上周说「用 pnpm」这周说「算了还是 npmpnpm 在 CI 上有问题」。两条记忆都成立但只有一条有效。解决靠三样东西时间戳、显式失效写入新记忆时把同 key 的旧记忆标记为superseded、召回时重排。绝不要靠「两条都召回让模型自己判断」——它很可能挑错。越权。多租户产品里记忆隔离做错一次就是数据事故。scope必须由服务端从会话身份推导绝不能由模型或前端传入。这条没有例外。十一、结语记忆是 Agent 变成同事的门槛回头看这一路Prompt 解决「怎么说」RAG 解决「知道什么」Function Calling 和 Tool 解决「能做什么」MCP 解决「怎么接」Skill 解决「怎么做」AGENTS.md 解决「在这个项目里怎么守规矩」——到了 Memory解决的是**「上次做到哪了这次接着来」**。前面那些能力做好一个就能做出一个漂亮的 demo。而记忆这件事做不好就永远只能做 demo。因为人对「助手」的期待里有一条是隐性的、但不可谈判的你应该记得我。技术上它一点都不玄。模型仍然是无状态的函数每次调用仍然从零开始。所谓记忆就是三层容器加上三条搬运规则短期记忆装原话快满了就压缩工作记忆装状态用代码显式读写抗压缩抗崩溃长期记忆装结论带作用域带时间戳按需召回然后用「沉淀、归档、召回」三个动作把它们连起来。真正难的不是写这几个函数是判断什么值得记。这件事没有标准答案只有一条经验法则记那些「如果忘了会重犯的错」和「如果忘了会重问的问题」。其余的让它忘掉——遗忘不是缺陷是设计。参考资料LangGraph 持久化与 Checkpointer 文档Anthropic: Effective context engineering for AI agentsMemGPT: Towards LLMs as Operating SystemsLost in the Middle: How Language Models Use Long ContextsZep: A Temporal Knowledge Graph Architecture for Agent MemoryMem0 / Letta / LangMem