AI Agent 的记忆系统应该如何设计?
简化版
Agent 记忆不是一个统一数据库,而是按生命周期拆分的分层状态:工作记忆保存当前任务,长期记忆(情景/语义/程序性)保存可复用的事实或经历,检索层按需把相关内容放回上下文。核心认知——记忆不会自动改变模型权重(把记录放进向量库 ≠ 微调),写入、检索、更新、过期、隔离、删除都要由应用显式管理。
详细版
常见分层:
- 工作记忆:当前目标、计划、工具观察、未完成步骤;
- 情景记忆:过去任务、动作、结果、反馈;
- 语义记忆:用户偏好、业务事实、提炼后的知识;
- 程序性知识:稳定规则、工具说明、操作流程(版本化配置维护)。
写入前判断价值、来源、权限、有效期;读取时结合语义相关性、时间、新鲜度、访问控制;用后处理冲突和反馈。不能把整段对话无限追加,也不能把模型总结未经验证当事实。
完整版教学
一、记忆 vs 上下文(先分清)
这是最容易混淆的概念:
上下文(context):本次模型调用【可见】的信息(有窗口/成本/注意力限制)
记忆(memory): 应用在【调用之间】保存、按需取回的信息(容量可扩展,但有成本与保留边界)
流程:长期记忆(大)── 检索/压缩/排序 ──> 只把相关部分放进上下文(小)
关键认知:把一条记录放进向量库,不会让模型”永久学会”它,也不等于微调——它只是「下次可能被检索回上下文」。记忆是外部存储 + 检索,不是模型能力。
二、四种记忆分层(各管什么)
| 类型 | 存什么 | 例子 | 存储 |
|---|---|---|---|
| 工作记忆 | 当前任务状态 | 当前步骤、已完成清单、错误计数 | 结构化状态 |
| 情景记忆 | 过去经历 | 上次这个任务怎么做的、结果如何 | 向量库 + 元数据 |
| 语义记忆 | 提炼的事实/偏好 | 用户偏好中文、公司政策 | 键值 + 向量 |
| 程序性知识 | 稳定规则/流程 | 工具说明、SOP | 版本化配置 |
三、工作记忆:优先结构化,别只存对话
工作记忆是高频出错点。很多实现只把「对话历史」一路追加,导致模型从冗长历史里猜当前状态。正解是结构化状态:
✓ 结构化:{ task_id, current_step: 3, done: [1,2], key_facts: {...},
error_count: 1, budget_left: 0.5 }
✗ 只存对话:把 20 轮原始对话全塞进去 → 模型猜"现在到哪一步了"
好处:可恢复执行、可校验前置条件、不用从历史猜状态。原始工具结果外部保存,上下文只传必要字段和引用。
四、长期记忆:不是所有对话都该存
写入要有策略,别无脑存:综合显式用户要求、重复使用价值、置信度、保留期限。用户偏好保留来源和时间;业务事实尽量来自权威系统而非模型推断。
Reflexion 一类方法把任务反馈提炼成文字反思供后续尝试用——注意这是上下文层面的经验复用,不是更新模型参数。
五、检索、冲突与安全(三个红线)
检索:结合关键词 + 向量 + 时间衰减 + 元数据过滤。
冲突:新旧记录冲突时优先权威来源和较新版本,并向用户暴露不确定性。关键——召回相关 ≠ 内容正确,尤其不能让过期地址/权限/价格直接驱动写操作。
安全与隐私:
长期记忆按【用户/租户/任务】隔离,敏感字段加密或不落库,提供查看/更正/删除
⚠️ 记忆污染:外部文档/工具结果可能含 Prompt Injection,
未经筛选写入长期记忆 → 会在【未来会话】持续影响行为(持久化污染)
写入和读取都要执行访问控制,不能依赖模型自行判断
记忆钩子:相关性只决定“要不要取回”,来源、权限和新鲜度才决定“能不能相信并使用”;涉及写操作时,还必须回源权威系统确认。
六、写入、更新和删除必须形成生命周期
长期记录至少应包含 memory_id、主体/租户、内容、来源、置信度、创建时间、有效期、权限标签和版本。相同事实再次出现时不能简单追加一份副本:应按稳定主键更新、保留版本历史,并把冲突标记为待确认;用户要求删除时,还要同步清理原文、向量索引、缓存和派生摘要。
检索排序可以综合语义、时间和来源,但权限过滤必须在排序前由应用执行。例如候选库有 10,000 条记录,权限过滤后当前用户只能访问 320 条,再从中取 Top-20;若先在全库向量检索再让模型删除越权结果,Top-20 的内容和相似度本身就可能泄露其他租户信息。
score = 0.6 * semantic_similarity
+ 0.25 * source_authority
+ 0.15 * freshness
permission_filter -> ranking -> top_k -> 回源验证 -> 注入上下文
离线评测除 Recall@K 外,还要测错误写入率、过期记忆使用率、跨租户泄漏数、冲突解决正确率和删除完成率。假设 200 个需要历史偏好的任务中召回 180 个,但有 9 个使用了已过期地址,则召回率虽为 90%,危险使用率仍为 9/200=4.5%;两个指标必须分别报告。
七、常见误区与追问
- 误区:把记录放进向量库=模型学会了。 那只是外部存储,下次可能被检索回上下文,不改权重、不等于微调。
- 误区:工作记忆就是保留全部对话历史。 应优先结构化状态,否则模型从冗长历史猜当前步骤。
- 误区:召回的记忆内容一定正确。 召回只代表相关,过期/错误记忆不能直接驱动写操作。
- 误区:所有对话都值得长期保存。 要按价值/来源/权限/有效期筛选,无脑存会污染和涨成本。
- 误区:记忆写入读取靠模型判断权限。 必须应用层做访问控制和租户隔离。
- 追问:记忆和上下文什么区别? 上下文是本次调用可见信息(有限),记忆是调用之间的外部存储(按需检索回上下文)。
- 追问:工作记忆为什么要结构化? 可恢复执行、校验前置条件、不用从历史猜状态。
- 追问:什么是记忆污染? 含注入的外部内容写进长期记忆,会在未来会话持续影响行为,要筛选+隔离+访问控制。
八、加强记忆
Agent 记忆记「结构化状态 + 受控长期存储 + 按需检索」:工作记忆(当前任务,优先结构化状态而非全对话)、情景/语义/程序性长期记忆(可复用经历/事实/规则)。核心认知钉死:记录放向量库≠模型学会(是外部存储+检索,不改权重)、召回相关≠内容正确(过期记忆别驱动写操作)、记忆污染是大坑(含注入的内容写进长期记忆会持久影响未来会话)。关键不只是记得住,更要保证来源、新鲜度、权限、可删除、不被污染。
项目实战落地
项目里怎么做的
《AI Agent旅游行程智能规划平台》的行程编排 Agent 用到三种记忆,写入方、存放位置和寿命各不相同:
| 记忆 | 存什么 | 谁写入 | 寿命 |
|---|---|---|---|
| 工作记忆 | 一次调用的执行上下文:运行 ID、轮次、候选池、城市、规则阈值、步骤序号 | 编排代码在每次调用模型前绑定到 ThreadLocal | 一次调用结束就清掉 |
| 语义记忆 | 用户偏好画像:预算档位、节奏、兴趣标签等 | 用户在页面维护,新建行程单时拍成快照 | 画像长期保存,快照跟着行程单 |
| 情景记忆 | 每一版行程判出的问题和改进要求 | 硬校验没过时由代码写入 agent_reflection | 同一次执行的各版之间 |
情景记忆的生命周期是这样的:
- 写入:一版排完跑 14 条硬校验,没过就把每条问题写成一行
agent_reflection,带轮次、规则编码、严重度、原样的问题描述、关联明细和一列fix_instruction(给模型的改进要求);通过的那一版补一条ROUND_PASSED记录; - 读取:下一版把上一版的教训拼进 Prompt;落库之后同一批教训直接作为返回值交给下一版,不再查库;
- 清理:每一版都按轮次号留在库里,前面的版本不删不改;只有这张行程单下一次重新规划、前置校验全部通过之后,才清掉上一次的明细、校验和教训。
为什么这样取舍
- 教训要落库:不落库的话问题只在一次对话的上下文里,对话结束就没了,页面看不到第 1 版为什么被打回;落库后多版本对比页能逐版列出「这一版被判出了什么、给了什么改进要求」。
- 记忆都由代码或用户写入:问题来自代码判定,偏好来自用户填写,模型不负责决定记住什么。
面试官还会追问
- 预算超支时,改进要求里会点名几条明细?为什么不把所有明细都列出来?
- 编排时引用了候选池外的资源、被写入工具整条丢弃的明细,也会变成下一版的教训吗?
学完《AI Agent旅游行程智能规划平台》,上面这些追问你都会迎刃而解。