Files
smartmate/backend/memory/记忆模块实施计划.md
Losita 574d44c332 Version: 0.9.11.dev.260409
后端:
1. conv 并行迁移与切流接线(旧目录下沉到 newAgent/conv)
   - 新建 newAgent/conv/schedule_provider.go、schedule_state.go、schedule_preview.go、schedule_persist.go,保持原有排程转换/预览/持久化能力;
   - 删除旧目录 conv/schedule_provider.go、schedule_state.go、schedule_preview.go、schedule_persist.go;
   - 更新 cmd/start.go 与 service/agentsvc/agent_newagent.go,ScheduleProvider/SchedulePersistor 与 preview 转换统一切到 newAgent/conv;
   - 删除旧 conv/schedule_state_test.go(迁移期测试文件清理)。
2. execute 循环上下文收口增强(历史归档 + 当前轮清晰化)
   - 更新 node/chat.go:仅在 completed 收口时写 execute_loop_closed marker,供后续 prompt 分层归档;
   - 更新 prompt/execute_context.go:msg1/msg2 升级为 V3,按收口标记拆分“历史归档 loop / 当前活跃 loop”,并增加 msg1 长度预算裁剪;
   - 更新 node/execute.go:新增 execute 置顶上下文同步(execution_context/current_step),在轮次开始与 next_plan 后即时刷新;
   - 更新 prompt/execute.go + execute_context.go:补齐“当前计划步骤 + done_when”强约束,禁止未达成判定时提前 next_plan。
3. 图路由与执行策略微调
   - 更新 graph/common_graph.go:Plan/Confirm 分支允许直接进入 Deliver 收口;
   - 更新 node/plan.go:always_execute 链路下补发计划摘要并写入历史,保证自动执行与手动确认文案一致;
   - 更新 model/common_state.go:DefaultMaxRounds 从 30 提升到 60。
4. 复合工具规划器重构(去重实现,复用 logic 公共能力)
   - 更新 tools/compound_tools.go:min_context_switch / spread_even 改为调用 backend/logic 规划器(PlanMinContextSwitchMoves / PlanEvenSpreadMoves);
   - 新增 state_id↔logic_id 映射层,统一入参与回填,避免工具层与规划层 ID 语义耦合;
   - 删除 compound_tools 内部重复的规划/归一化/分组/打分实现,减少第三份复制逻辑。
5. 同步调试与文档
   - 更新 newAgent/Log.txt 调试日志;
   - 新增 memory/记忆模块实施计划.md(面试优先版到产品可用版的落地路线)。
前端:无
仓库:无
2026-04-09 22:20:30 +08:00

15 KiB
Raw Blame History

记忆模块实施计划(面试优先版 -> 产品可用版)

1. 文档目标

  1. 在 3 天内交付一个“可演示、可讲清楚、可继续演进”的记忆系统 MVP。
  2. 兼容当前单体工程,不引入高风险拆分,不破坏现有聊天主链路。
  3. 复用现有 Outbox 异步基础设施,避免重复造轮子。
  4. 形成可直接用于面试讲述的架构故事线、指标体系与演示脚本。

2. 背景与约束

  1. 当前系统是单体 Go 项目,已有稳定的 Outbox + Kafka + 消费事务 通路。
  2. 当前项目定位先是日程助手,长期演进为陪伴型助手。
  3. 短期目标是快速做出“真的可用”的记忆能力,不追求一次做成完整通用平台。
  4. 风险约束:
    • 不能让重型 LLM 处理阻塞聊天实时响应。
    • 不能在 Outbox 消费主循环里堆重计算,避免拖垮其他事件消费。
    • 不能牺牲数据一致性与可审计性。

3. 总体方案

3.1 核心思路

采用“同步快路径 + 异步慢路径”:

  1. 同步快路径:回复前快速读取可用记忆(以 MySQL 结构化事实为主),保证“下一轮能用”。
  2. 异步慢路径:通过 Outbox 触发记忆抽取任务,执行去重、冲突消解、打分、向量化等重操作。
  3. 读写解耦:写路径确保可靠入队,读路径优先稳定可控,再做语义增强。

3.2 存储职责分层

  1. MySQL事实主库偏好、约束、任务上下文、TTL、置信度、敏感级别、来源
  2. Milvus语义召回同义表达匹配、模糊语义联想
  3. Redis可选热数据缓存后续优化不作为 MVP 必选项)。

3.3 编排层职责

Memory Orchestrator 负责两条链路:

  1. 写入链路:候选抽取 -> 去重/冲突 -> 打分 -> 分流落库MySQL/Milvus
  2. 读取链路:硬约束优先 -> 语义召回补充 -> 重排 -> 门控 -> 注入上下文。

4. 3 天执行计划(可直接照着做)

Day 1把“可写入”打通可靠入队 + 可追踪)

目标

  1. 记忆任务能稳定从聊天主链路发出。
  2. 能看到任务从 pendingsuccess/failed 的状态流转。
  3. 保证失败可重试、可追踪、可补偿。

任务清单

  1. 新增文档与目录占位:
    • backend/memory/README.md(模块说明)
    • backend/memory/service/(门面)
    • backend/memory/model/DTO 与状态)
    • backend/memory/repo/(数据访问)
    • backend/memory/orchestrator/(编排)
    • backend/memory/worker/(异步执行)
  2. 新增 MySQL 表(建议先手写 SQL + DAO
    • memory_items
    • memory_jobs
    • memory_audit_logs
    • memory_user_settings
  3. 新增 Outbox 事件:
    • memory.extract.requestedv1
  4. 在聊天后置持久化环节发布事件:
    • 仅传轻量字段,避免超大 payload。
  5. 新增消费处理器:
    • 只做任务入库,不做重型 LLM 调用。
  6. 启动期接线:
    • backend/cmd/start.go 注册记忆事件处理器。

Day 1 验收标准

  1. 一次聊天后Outbox 中能看到 memory.extract.requested 事件。
  2. 事件消费后,memory_jobs 生成记录。
  3. 人工触发 worker 可完成一次任务状态推进(哪怕先是 mock 抽取)。

Day 2把“可读取可注入”打通先 MySQL 后向量)

目标

  1. 记忆可在回复前被检索并注入上下文。
  2. 能避免明显的“尬提”与无关提及。
  3. 提供最小用户可控能力(查看/删除/关闭)。

任务清单

  1. 实现 MemoryReadService
    • 按用户与会话上下文读取记忆。
    • 优先结构化硬约束(时间偏好、排程禁忌、显式偏好)。
  2. 实现 MemoryInjector
    • Top-K 记忆选择。
    • token 预算截断。
    • 注入模板统一化。
  3. 实现门控逻辑:
    • 相关性阈值。
    • 置信度阈值。
    • 时间衰减权重。
    • 敏感级别检查。
  4. 新增最小管理接口:
    • GET /api/v1/memory/items
    • DELETE /api/v1/memory/items/:id
    • POST /api/v1/memory/settings(开关)
  5. 完成首版日志埋点:
    • 检索命中数、注入条数、门控丢弃原因。

Day 2 验收标准

  1. 给出偏好后,下一轮排程请求能利用该偏好。
  2. 无关话题不会频繁硬提旧记忆。
  3. 用户可删除指定记忆,删除后不再注入。

Day 3把“可讲清楚”与“可评估”补齐面试可答

目标

  1. 输出完整可讲架构,说明设计取舍。
  2. 增加可量化指标,证明记忆“有用”而不是“看起来有”。
  3. 可选接入 Milvus若环境未就绪先保留接口 + mock

任务清单

  1. 实现/预留向量接口:
    • VectorStore.Upsert()
    • VectorStore.Search()
    • VectorStore.Delete()
  2. 对接 Milvus可选
    • collection 初始化。
    • 向量 + 元数据过滤检索。
  3. 指标体系落地:
    • 记忆命中率retrieved/useful
    • 错误提及率wrong mention
    • 用户纠正率user correction
    • 回复延迟影响P50/P95
  4. 准备演示脚本与面试问答稿:
    • 5 分钟架构说明。
    • 3 个典型失败案例及兜底策略。
    • 未来迭代路线。

Day 3 验收标准

  1. 能现场演示“记住偏好 -> 下轮生效 -> 删除后失效”。
  2. 能答清楚“为什么不是纯同步/纯异步”。
  3. 能答清楚“为什么 MySQL + Milvus 双存储”。

5. 数据模型设计(首版)

5.1 memory_items(长期事实记忆)

用途:保存对业务有约束价值的可注入记忆。

关键字段建议:

  1. id bigint PK
  2. user_id bigint必填
  3. conversation_id varchar(64)(可空,表示全局用户记忆)
  4. memory_type varchar(32)
    • preference(偏好)
    • constraint(硬约束)
    • fact(事实)
    • todo_hint(近期提醒线索)
  5. title varchar(128)
  6. content text
  7. normalized_content text去噪后
  8. confidence decimal(5,4)0~1
  9. importance decimal(5,4)0~1
  10. sensitivity_level tinyint
    • 0 普通
    • 1 中敏
    • 2 高敏
  11. source_message_id bigint
  12. source_event_id varchar(64)
  13. is_explicit tinyint(1)(是否用户明确要求记住)
  14. status varchar(16)
    • active
    • archived
    • deleted
  15. ttl_at datetime到期时间
  16. last_access_at datetime
  17. created_at datetime
  18. updated_at datetime

索引建议:

  1. (user_id, status, memory_type, updated_at desc)
  2. (user_id, conversation_id, status, updated_at desc)
  3. (source_message_id)(排查链路)
  4. (ttl_at)(过期清理)

5.2 memory_jobs(异步任务队列表)

用途:承接 Outbox 消费后的待处理任务,解耦重计算。

关键字段建议:

  1. id bigint PK
  2. user_id bigint
  3. conversation_id varchar(64)
  4. source_message_id bigint
  5. source_event_id varchar(64)
  6. job_type varchar(32)
    • extract
    • embed
    • reconcile
  7. payload_json longtext
  8. status varchar(16)
    • pending
    • processing
    • success
    • failed
    • dead
  9. retry_count int
  10. max_retry int
  11. next_retry_at datetime
  12. last_error varchar(2000)
  13. created_at datetime
  14. updated_at datetime

索引建议:

  1. (status, next_retry_at, id)
  2. (user_id, created_at desc)
  3. (source_event_id)(幂等与追踪)

5.3 memory_audit_logs(审计日志)

用途:回答“这条记忆是谁在什么条件下写的/改的/删的”。

关键字段建议:

  1. id bigint PK
  2. memory_id bigint
  3. user_id bigint
  4. operation varchar(32)
    • create
    • update
    • archive
    • delete
    • restore
  5. operator_type varchar(16)
    • system
    • user
  6. reason varchar(255)
  7. before_json longtext
  8. after_json longtext
  9. created_at datetime

5.4 memory_user_settings(用户记忆开关)

用途:实现用户可控能力。

关键字段建议:

  1. user_id bigint PK
  2. memory_enabled tinyint(1)
  3. implicit_memory_enabled tinyint(1)
  4. sensitive_memory_enabled tinyint(1)
  5. updated_at datetime

6. 事件与协议设计

6.1 事件类型

  1. memory.extract.requestedv1
  2. 预留:
    • memory.embed.requested
    • memory.cleanup.requested

6.2 载荷字段v1

  1. user_id
  2. conversation_id
  3. source_message_id
  4. source_role
  5. source_text
  6. occurred_at
  7. trace_id

设计约束:

  1. Payload 只放执行需要的最小字段。
  2. 大文本允许截断并保留摘要,防止消息膨胀。
  3. 必须包含幂等标识(如 source_message_id + user_id)。

7. 写入流程详细设计

7.1 主流程

  1. 聊天主链路完成并落历史消息。
  2. 发布 memory.extract.requested 到 Outbox。
  3. Outbox 消费处理器验证 payload。
  4. 处理器创建或幂等更新 memory_jobs(仅任务入库)。
  5. memory/worker 扫描 pending 任务并抢占为 processing
  6. Worker 调用 LLM 执行“候选记忆抽取”。
  7. 执行标准化(时间归一化、实体归一化、噪声去除)。
  8. 执行冲突消解(同类偏好最新优先、互斥约束降权)。
  9. 计算分值(置信度、重要度、时效度)。
  10. 写入 memory_items 与审计日志。
  11. 触发向量化(同步或异步二选一)。
  12. 成功后任务标记 success,失败按重试策略推进。

7.2 失败处理策略

  1. Payload 非法:直接标记 dead不重试。
  2. LLM 短时失败:指数退避重试。
  3. DB 写失败:重试,超过上限 dead。
  4. 向量写失败:
    • MVP 策略:不阻塞事实写入,记录 vector_pending 状态。
    • 后续策略:补偿任务重建向量索引。

7.3 幂等策略

  1. 幂等键:user_id + source_message_id + memory_type + normalized_content_hash
  2. 同幂等键重复写入:更新 updated_at、提升访问热度,不新增重复条目。
  3. 由 Outbox 重试导致的重复消费必须无副作用。

8. 读取流程详细设计

8.1 主流程

  1. 接收用户新问题,先做意图分类(排程/闲聊/混合)。
  2. memory_items 拉取硬约束记忆(高优先级)。
  3. 若 Milvus 可用,执行语义召回补充记忆候选。
  4. 对候选执行重排:
    • 相关性分
    • 置信度分
    • 时间衰减分
    • 显式记忆加权
  5. 执行门控:
    • 低相关丢弃
    • 高敏过滤
    • 过期过滤
  6. 按 token budget 选择最终注入条目。
  7. 组装统一注入上下文,传给主模型生成回复。

8.2 重排评分(建议公式)

final_score = 0.45 * relevance + 0.25 * confidence + 0.20 * recency + 0.10 * explicit_bonus

说明:

  1. 排程类场景可增加硬约束权重。
  2. 闲聊类场景可提高语义相关权重。
  3. 该公式为 MVP 默认值,后续可通过线上数据调参。

8.3 门控规则MVP

  1. final_score < 0.55 不注入。
  2. sensitivity_level >= 2 且用户未开启敏感记忆时不注入。
  3. ttl_at < now 不注入。
  4. 同主题最多注入 1~2 条,防止重复轰炸。

9. 对外接口MVP

9.1 用户接口

  1. GET /api/v1/memory/items
    • 支持按类型、时间、状态过滤。
  2. DELETE /api/v1/memory/items/:id
    • 软删除并写审计日志。
  3. POST /api/v1/memory/settings
    • 修改记忆总开关、隐式记忆开关。

9.2 内部接口

  1. MemoryService.EnqueueExtractJob(ctx, payload)
  2. MemoryService.RetrieveForPrompt(ctx, req)
  3. MemoryService.UpsertMemoryItems(ctx, items)
  4. MemoryService.DeleteMemory(ctx, userID, memoryID)

10. 可观测性与指标

10.1 指标定义

  1. memory_job_success_rate
  2. memory_job_retry_rate
  3. memory_retrieval_hit_rate
  4. memory_injection_count_avg
  5. memory_wrong_mention_rate
  6. memory_user_correction_rate
  7. chat_p95_latency_delta_with_memory

10.2 日志与追踪

  1. 每个任务写 trace_id,贯穿聊天请求 -> outbox -> memory_job -> memory_item。
  2. 对门控丢弃记录原因码:
    • LOW_SCORE
    • EXPIRED
    • SENSITIVE_BLOCKED
    • DUP_TOPIC
  3. 保证可以反查“为什么这次没有提某条记忆”。

11. 安全与隐私约束

  1. 敏感信息默认不做隐式记忆(如健康、财务、证件等)。
  2. 用户必须可删除历史记忆,删除后不再用于注入。
  3. 记忆开关关闭后,仅保留必要系统数据,不再新增记忆条目。
  4. 审计日志保留系统写入行为,便于风控与合规排查。

12. 测试策略

12.1 单元测试范围(实现阶段)

  1. 候选抽取结果解析函数。
  2. 冲突消解函数。
  3. 重排评分函数。
  4. 门控函数。
  5. 幂等去重函数。

12.2 集成测试范围(实现阶段)

  1. 聊天后事件成功入 outbox。
  2. Outbox 消费后任务成功入 memory_jobs
  3. Worker 成功写 memory_items
  4. 读取链路能在回复中注入预期记忆。

12.3 注意事项(遵循项目约束)

  1. 若编写 Go 测试文件(*_test.go)做验证,任务完成后按项目约定移除测试文件。
  2. 每次执行本地 go test 后清理项目根目录 .gocache

13. 风险与回滚

13.1 主要风险

  1. 记忆误提影响体验。
  2. LLM 抽取不稳定导致脏记忆。
  3. 向量检索误召回导致不相关注入。
  4. 任务积压影响时效。

13.2 应对策略

  1. 先严门控,宁可少提,不要乱提。
  2. 保留“用户纠正”入口,纠正后提高冲突更新优先级。
  3. 对召回做 metadata 过滤(近 30 天、类型限定)。
  4. 监控任务积压长度,超阈值降级(停向量,仅结构化记忆)。

13.3 回滚方案

  1. 配置开关 memory.enabled=false 可一键关闭记忆注入。
  2. 保留写入链路但停读取链路,避免历史数据丢失。
  3. 极端情况下停 worker仅保留主链路聊天功能。

14. 面试表达模板(可直接复述)

  1. “我们做的是同步快路径 + 异步慢路径。同步保证下轮可用,异步负责治理和质量。”
  2. “结构化事实放 MySQL 保证可控可审计,语义联想放 Milvus 提高召回覆盖。”
  3. “Outbox 保证事件可靠入队Worker 解耦重计算,避免阻塞主链路。”
  4. “我们用命中率、误提率、纠正率三项核心指标验证记忆是否真的有价值。”

15. DoD完成定义

  1. 代码层:
    • 记忆事件可发布、可消费、可重试。
    • 记忆可检索、可注入、可删除、可关闭。
  2. 质量层:
    • 有基础指标与日志,支持问题排查。
    • 有失败兜底与降级路径。
  3. 叙事层:
    • 3 分钟能讲清架构。
    • 5 分钟能演示端到端效果。
    • 能回答核心取舍与后续演进。

16. 本轮执行顺序建议

  1. 先做 Day 1 的表结构与事件接线,不进入复杂抽取细节。
  2. 再做 Day 2 的读取注入,优先 MySQL 结构化记忆。
  3. 最后补 Day 3 的 Milvus 与指标,确保面试讲述闭环。

本文件定位为“落地执行蓝图”。后续每完成一块能力,建议在本文件追加“已落地清单 + 待办差距”,持续收敛为真实实施记录。