AI Agent 记忆写入控制器设计:别把临时指令写成长期偏好
1. 问题:长期记忆不能从对话摘要直接生成
很多 AI Agent 在实现长期记忆时,会采用一种看似自然的做法:每轮对话结束后,让大模型总结“值得记住的信息”,然后写入数据库或向量库。
这种方式实现简单,但很容易造成记忆污染。
例如,用户只是说了一句:
这次周报写短一点,只保留本周进展、当前风险和下周计划。如果系统没有写入控制,就可能把它记成:
用户喜欢简短回答,只保留核心内容。这就是典型错误。
用户要求的是“这次周报”更短,而不是以后所有回答都要短。如果系统把它写成长期偏好,后续用户让 Agent 写技术方案、需求文档或论文分析时,系统可能仍然强行压缩内容,导致回答深度不足。
所以,长期记忆的核心问题不是“怎么存”,而是:
什么信息有资格被写入长期记忆?
存储层解决“能不能记”,写入控制器解决“该不该记”。
2. 写入控制器不是摘要器
记忆写入控制器位于用户交互和长期记忆库之间。它不负责回答生成,也不负责记忆检索,而是在一轮交互结束后判断:哪些信息可以写入长期记忆,哪些信息只能用于当前任务,哪些信息应该直接跳过。
它的输入包括:
user_input:用户本轮输入agent_response:Agent 本轮回复session_state:当前任务状态existing_memories:已有长期记忆
它的输出不是一段自然语言摘要,而是一组结构化写入决策:
{”action”: ”WRITE”,”memory_type”: ”constraint”,”scope”: ”current_task”,”content”: ”当前项目周报需要压缩篇幅,只保留本周进展、当前风险和下周计划。”,”evidence”: ”用户明确要求“这次周报写短一点”。”,”confidence”: 0.96,”importance”: 5,”expires_at”: ”task_finished”}
一个可用的写入控制器至少要判断四件事:
1. 这条信息来自用户明确表达,还是系统推断?2. 它是临时指令、任务约束,还是长期偏好?3. 它应该影响当前任务、同类任务,还是所有后续对话?4. 它在什么时候失效?
其中最关键的不是生成 content,而是确定 scope、evidence、confidence 和 expires_at。
content 说明系统记住什么;scope 说明这条记忆影响多大范围;evidence 说明系统凭什么这样记;confidence 说明系统有多确定;expires_at 说明这条记忆什么时候失效。
3. 一句话如何拆成两条候选记忆
仍然看这个输入:
这次周报写短一点,只保留本周进展、当前风险和下周计划。这句话不能直接被总结成“用户喜欢简短回答”。更合理的做法是先拆成候选记忆。
[{”content”: ”当前项目周报需要压缩篇幅,只保留本周进展、当前风险和下周计划。”,”memory_type”: ”constraint”,”scope”: ”current_task”,”evidence”: ”用户明确说“这次周报写短一点”。”,”confidence”: 0.96},{”content”: ”用户在工作汇报类写作中可能偏好先突出进展、风险和下一步计划。”,”memory_type”: ”preference”,”scope”: ”writing_tasks”,”evidence”: ”由一次周报任务要求推断得到,不是用户直接声明。”,”confidence”: 0.70}]
这两条候选记忆的性质不同。
第一条是当前任务约束。它来自用户明确表达,置信度高,但只应该影响当前周报。
第二条是弱偏好推断。它可能对以后写工作汇报有参考价值,但并不是用户明确说出的长期偏好,所以不能写成高置信度全局记忆。
如果系统把这两条混在一起,就会出现过度泛化。
错误写法是:
{”content”: ”用户喜欢简短回答。”,”memory_type”: ”preference”,”scope”: ”global”,”confidence”: 0.92}
正确写法是:
{”content”: ”当前项目周报需要压缩篇幅,只保留本周进展、当前风险和下周计划。”,”memory_type”: ”constraint”,”scope”: ”current_task”,”evidence”: ”用户明确限定了这次周报的篇幅和结构。”,”confidence”: 0.96,”expires_at”: ”task_finished”}
也可以保留一条弱偏好,但必须限制范围并降低置信度:
{”content”: ”用户在工作汇报类写作中可能偏好先突出进展、风险和下一步计划。”,”memory_type”: ”preference”,”scope”: ”writing_tasks”,”evidence”: ”由一次周报任务要求推断得到。”,”confidence”: 0.70}
4. 单次写入决策链
为了让写入过程可解释,可以把一次用户输入拆成完整决策链。
global | |
current_task | |
current_task | |
这条链路的重点是:写入控制器不是把一句话摘要成一条记忆,而是把用户输入拆成不同层级的信息,并分别决定是否写入、写到哪里、以多大权重写入、什么时候失效。
5. 四个关键字段:scope、evidence、confidence、expires_at
记忆写入质量主要由四个字段控制。
5.1 scope:控制作用范围
scope 是最重要的字段。很多记忆污染不是内容完全错误,而是作用范围写得太大。
可以先设计四类作用域:
current_task:只影响当前任务project:影响当前项目writing_tasks:影响写作类任务global:影响所有后续对话
例如:
这次周报写短一点。应该优先写成:
{”scope”: ”current_task”}
而不是:
{”scope”: ”global”}
只有用户明确说:
以后所有回答都尽量简洁。才可能写入 global。
作用域判定可以遵循一个保守原则:
没有长期信号,默认 current_task;没有同类任务信号,不提升到 writing_tasks;没有明确全局信号,不提升到 global。
5.2 evidence:保存记忆来源
evidence 用来说明这条记忆从哪里来。
记忆内容回答“系统记住了什么”,证据字段回答“系统凭什么这样记”。
没有 evidence 的记忆,在后续冲突处理时很难判断可信度。例如:
{”content”: ”用户喜欢简短回答。”}
这条记忆本身缺少上下文,系统无法知道它是用户明确声明,还是模型从一次任务中推断出来的。
更合理的是:
{”content”: ”用户在当前周报任务中要求压缩篇幅。”,”evidence”: ”用户说“这次周报写短一点”。”}
这样后续如果出现冲突,系统可以根据证据判断这条记忆是否应该继续生效。
5.3 confidence:区分用户事实和系统推断
confidence 决定一条记忆在后续系统中的话语权。
可以采用简单分级:
因此,下面这种写法风险很高:
{”content”: ”用户喜欢简短回答。”,”scope”: ”global”,”confidence”: 0.92}
它把一次任务要求变成了高置信度全局偏好。
更合理的是:
{”content”: ”用户在工作汇报类写作中可能偏好突出进展、风险和下一步计划。”,”scope”: ”writing_tasks”,”confidence”: 0.70}
低置信度记忆可以保留,但在后续检索和上下文注入时应降低权重,不能覆盖用户明确表达的高置信度记忆。
5.4 expires_at:让任务约束及时失效
不是所有记忆都应该永久有效。
例如:
当前项目周报需要压缩篇幅。这条记忆只对当前周报任务有效。任务完成后,它应该过期。
{”scope”: ”current_task”,”expires_at”: ”task_finished”}
如果不设置过期条件,当前任务中的临时约束会继续影响后续任务。
因此,只要 scope 是 current_task,就应该考虑 expires_at。这能防止阶段性上下文长期污染 Agent 的行为。
6. 写入控制器的最小实现
最小可用版本不需要复杂模型,但必须保留可解释的判断流程。
用户交互↓候选记忆抽取↓证据绑定↓准入判断↓作用域判定↓置信度设置↓相似记忆检查↓执行 WRITE / SKIP / MERGE / UPDATE
关键伪代码如下:
def memory_write_controller(user_input, agent_response, session_state, user_id):candidates = extract_candidates(user_input, agent_response)decisions = []for candidate in candidates:candidate.evidence = attach_evidence(candidate, user_input)if is_temporary_instruction(candidate):decisions.append(skip(candidate, reason=”current_turn_instruction”))continuecandidate.scope = assign_scope(candidate, user_input)candidate.confidence = assign_confidence(candidate)if candidate.scope == ”current_task”:candidate.expires_at = ”task_finished”similar = search_similar_memories(user_id, candidate)decision = resolve_memory_relation(candidate, similar)decisions.append(decision)apply_decisions(decisions)return decisions
其中 assign_scope 是核心判断函数:
def assign_scope(candidate, text):current_task_words = [”这次”, ”当前”, ”本次”, ”先”, ”暂时”]task_family_words = [”以后写”, ”写周报时”, ”写汇报时”, ”做这类任务时”]global_words = [”以后所有回答”, ”每次回答”, ”一直保持”]if contains_any(text, current_task_words):return ”current_task”if contains_any(text, task_family_words):return ”writing_tasks”if contains_any(text, global_words):return ”global”return ”current_task”
assign_confidence 可以先按证据来源实现:
def assign_confidence(candidate):if candidate.source == ”explicit_user_statement”:return 0.92if candidate.source == ”repeated_behavior”:return 0.82if candidate.source == ”single_task_inference”:return 0.65return 0.50
这不是完整算法,但足以体现一个关键原则:默认收窄作用域,默认降低推断型记忆的置信度。
7. 数据结构:字段是风险控制手段
记忆表不需要一开始设计得很复杂,但必须支持作用域、证据、置信度和过期控制。
CREATE TABLE agent_memory (id BIGINT PRIMARY KEY AUTO_INCREMENT,user_id VARCHAR(64) NOT NULL,agent_id VARCHAR(64) NOT NULL,memory_type VARCHAR(32) NOT NULL,scope VARCHAR(32) NOT NULL,content TEXT NOT NULL,evidence TEXT,confidence DECIMAL(4,3) DEFAULT 0.800,importance INT DEFAULT 3,source_session_id VARCHAR(64),source_message_id VARCHAR(64),created_at DATETIME DEFAULT CURRENT_TIMESTAMP,updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,expires_at DATETIME NULL,status VARCHAR(16) DEFAULT 'active',version INT DEFAULT 1);
这些字段不是为了让表结构更复杂,而是为了控制具体风险。
scopeexpires_at | |
scope | |
evidenceconfidence | |
versionstatus, confidence | |
importanceconfidence |
字段设计必须服务风险治理。否则,记忆表只是保存文本的容器,无法支撑长期协作。
8. 如何测试写入控制器
记忆写入控制器不能只测试“数据是否成功写入数据库”,更要测试判断质量。
可以设计四类指标:
current_task 写成 global | |
典型测试用例:
8.1 临时指令
输入:
这次回答短一点。期望:
{”action”: ”SKIP”,”reason”: ”current_turn_instruction”}
8.2 当前任务约束
输入:
这次周报写短一点,只保留本周进展、当前风险和下周计划。期望:
{”action”: ”WRITE”,”memory_type”: ”constraint”,”scope”: ”current_task”,”expires_at”: ”task_finished”}
8.3 明确长期偏好
输入:
以后写项目周报时,尽量先写进展、风险和下一步计划。期望:
{”action”: ”WRITE”,”memory_type”: ”preference”,”scope”: ”writing_tasks”}
8.4 偏好覆盖风险
已有记忆:
用户偏好详细、系统化的技术解释。新输入:
这次简单说。期望:
{”action”: ”SKIP”,”reason”: ”temporary_instruction_cannot_override_existing_preference”}
这些测试验证的是写入控制器的判断能力,而不是数据库写入能力。只有能稳定通过这类测试,长期记忆才不会在真实使用中逐渐失控。
9. 总结
AI Agent 的长期记忆不是聊天记录摘要,而是经过准入判断后的结构化上下文。
记忆写入控制器的核心价值,是在信息进入长期记忆前判断:是否该写入、写成什么类型、作用范围多大、证据是否充分、置信度是多少、什么时候过期。
在最小可用实现中,重点不在于复杂算法,而在于四个关键控制点:
scope:防止当前任务约束变成全局规则evidence:防止记忆来源不可追踪confidence:防止系统推断被当成用户事实expires_at:防止阶段性任务状态长期污染后续对话
真正可靠的长期记忆,不是记得越多越好,而是写入越克制、证据越清楚、作用域越准确、生命周期越可控越好。
夜雨聆风