Version: 0.9.22.dev.260416
后端: 1. 品牌文案与聊天定位统一切到 SmartMate,并放宽非排程问答能力 - 系统人设、路由、排程、查询、交付提示统一从 SmartFlow 改为 SmartMate - 明确普通问答/生活建议/开放讨论可正常回答,deep_answer 不再输出“让我想想”等占位话术 - thinkingMode=auto 时,deep_answer 默认开启 thinking,execute 继续跟随路由决策,其余路由默认关闭 2. Memory 读取链路升级为“结构化强约束 + 语义候选”hybrid 模式,并补齐注入渲染 / Execute 消费 - 新增 read.mode、四类记忆预算、inject.renderMode 等配置及默认值 - 落地 HybridRetrieve,统一 MySQL/RAG 读侧作用域、三级去重(ID/hash/text)、统一重排与按类型预算裁剪 - 新增 FindPinnedByUser、content_hash DTO/兜底补算、legacy/RAG 共用读侧查询口径与 fallback 逻辑 - 记忆注入支持 flat/typed_v2 两种渲染,execute msg3 正式消费 memory_context,主链路注入 MemoryReader 时同步透传 memory 配置 3. Memory 第二步/第三步 handoff 与治理文档补齐 - HANDOFF_Memory向Mem0靠拢三步冲刺计划.md 从 newAgent 迁到 memory 目录,并补充“我的记忆”增删改查与最小留痕口径 - 新增 backend/memory/记忆模块第二步计划.md、backend/memory/第三步治理与观测落地计划.md,分别拆解 hybrid 读取注入闭环与治理/观测/清理路线 - 同步更新 backend/memory/Log.txt 调试日志 前端: 1. 助手输入区新增“智能编排”任务类选择器,并把 task_class_ids 作为请求 extra 透传 - 新建 frontend/src/components/assistant/TaskClassPlanningPicker.vue,支持拉取任务类列表、临时勾选、已选标签回显与清空 - 更新 frontend/src/components/dashboard/AssistantPanel.vue、frontend/src/types/dashboard.ts:Chat extra 正式建模 task_class_ids / retry 字段;当本轮带编排任务类时强制新起会话,避免把现有会话历史误混入新编排 2. 会话上下文窗口统计接入前端展示 - 更新 frontend/src/api/agent.ts、新建 frontend/src/components/assistant/ContextWindowMeter.vue、更新 frontend/src/components/dashboard/AssistantPanel.vue、frontend/src/types/dashboard.ts:接入 /agent/context-stats,兼容 object/string/null 三种返回;在输入工具栏展示 msg0~msg3 占比与预算使用率 3. 助手面板交互细节优化 - 更新 frontend/src/components/dashboard/AssistantPanel.vue:thinking 开关改为 auto/true/false 三态选择;切会话与重试后同步刷新 context stats;历史列表首屏不足时自动继续分页直到形成滚动区 仓库:无
This commit is contained in:
521
backend/memory/第三步治理与观测落地计划.md
Normal file
521
backend/memory/第三步治理与观测落地计划.md
Normal file
@@ -0,0 +1,521 @@
|
||||
# Memory 第三步治理与观测落地计划
|
||||
|
||||
## 1. 这份文档解决什么问题
|
||||
|
||||
这份文档只回答第三步要做什么,不再重复前两步已经完成的抽取、决策、召回细节。
|
||||
|
||||
第三步的目标很简单:
|
||||
|
||||
1. 把 memory 从“能跑”升级成“敢灰度、敢排障、敢清理、敢回滚”。
|
||||
2. 把“日志打在哪里、我怎么看、会不会给接口”说清楚。
|
||||
3. 把改动范围收敛在治理层,不再继续扩算法和能力边界。
|
||||
|
||||
一句人话总结:
|
||||
|
||||
前两步解决的是“有没有能力”,第三步解决的是“出了问题怎么查、怎么收、怎么退”。
|
||||
|
||||
---
|
||||
|
||||
## 2. 先说结论
|
||||
|
||||
第三步我会分成两块做:
|
||||
|
||||
1. 观测与切流
|
||||
2. 用户管理与清理
|
||||
|
||||
为什么这么拆:
|
||||
|
||||
1. 现在第二步最小闭环已经通了,最怕的不是“能力不够多”,而是“出了问题不知道卡在哪一层”。
|
||||
2. 如果没有统一日志、指标和开关,后面再继续加功能,只会让 memory 变成一个越来越难维护的黑箱。
|
||||
3. 历史重复脏数据不先治理,后面读链路和注入链路的数据噪音会越来越重。
|
||||
|
||||
第三步不追求“更聪明”,追求“更稳、更可控”。
|
||||
|
||||
---
|
||||
|
||||
## 3. 你最关心的三个问题
|
||||
|
||||
## 3.1 日志会打在哪里
|
||||
|
||||
第三步不会把所有信息都塞进一个地方,而是分三层:
|
||||
|
||||
### A. 运行日志
|
||||
|
||||
运行日志打到后端服务本身的标准日志,也就是当前 `backend` 进程控制台 / 容器 stdout。
|
||||
|
||||
这层主要看实时链路,适合排查:
|
||||
|
||||
1. 这次写入为什么是 `ADD / UPDATE / DELETE / NONE`
|
||||
2. 这次召回为什么没命中
|
||||
3. 这次注入为什么降级到 `flat` 或 `legacy`
|
||||
4. 这次 worker 为什么走了 fallback
|
||||
|
||||
这层的形态参考当前 RAG 轻量 Observer 的做法,不单独造一套散装日志方案。
|
||||
|
||||
参考文件:
|
||||
|
||||
1. `backend/cmd/start.go`
|
||||
2. `backend/infra/rag/core/observer.go`
|
||||
|
||||
### B. 变更留痕
|
||||
|
||||
变更留痕继续落库,不只打终端。
|
||||
|
||||
当前已经有:
|
||||
|
||||
1. `memory_audit_logs` 表
|
||||
2. `backend/model/memory.go`
|
||||
3. `backend/memory/repo/audit_repo.go`
|
||||
|
||||
这层主要看“已经发生过的变更事实”,适合研发排查和后端自查:
|
||||
|
||||
1. 哪条记忆被删了
|
||||
2. 删之前和删之后内容是什么
|
||||
3. 这次 dedup 清理保留了哪条,归档了哪条
|
||||
4. 某次 update / delete / restore 是谁触发的,原因是什么
|
||||
|
||||
### C. 汇总指标
|
||||
|
||||
第一版不先上完整 Prometheus / Grafana 平台,而是先把关键指标打稳,再视需要接统一观测平台。
|
||||
|
||||
这层主要看趋势和健康度,适合回答:
|
||||
|
||||
1. 最近写入成功率怎么样
|
||||
2. hybrid 召回到底有没有提升
|
||||
3. 去重到底丢了多少垃圾数据
|
||||
4. 是否频繁回滚到 legacy
|
||||
|
||||
---
|
||||
|
||||
## 3.2 我会怎么看
|
||||
|
||||
开发和联调阶段,推荐分两种看法:
|
||||
|
||||
### 看实时问题
|
||||
|
||||
直接看后端运行日志。
|
||||
|
||||
适合看:
|
||||
|
||||
1. 单次请求链路
|
||||
2. 单次 worker 执行过程
|
||||
3. fallback / 降级 / 回滚是否发生
|
||||
|
||||
### 看历史问题
|
||||
|
||||
直接查数据库留痕表和主表。
|
||||
|
||||
适合看:
|
||||
|
||||
1. 某条 memory 历史上被怎么改过
|
||||
2. 某次清理动作具体处理了哪些记录
|
||||
3. 当前 active / archived / deleted 分布
|
||||
|
||||
建议排查时优先查这几张表:
|
||||
|
||||
1. `memory_jobs`
|
||||
2. `memory_items`
|
||||
3. `memory_audit_logs`
|
||||
|
||||
第一版就够用了,不强依赖前端页面才能排查。
|
||||
|
||||
---
|
||||
|
||||
## 3.3 会不会提供接口
|
||||
|
||||
会,但原则上只补“面向当前用户管理自己记忆”的接口,不补“原始运行日志接口”,也不把 `memory` 先做成全项目唯一完整的审计后台。
|
||||
|
||||
原因很直接:
|
||||
|
||||
1. 原始日志噪音很大,不适合直接给前端看。
|
||||
2. 原始日志字段会迭代,直接对外暴露会把内部实现绑死。
|
||||
3. 原始日志可能带内部 trace、错误细节,不适合直接外露。
|
||||
|
||||
所以第三步对外提供的是“用户管理自己记忆”的接口,不是“把 stdout 原样吐给前端”,也不是“先给 memory 单独造一套管理后台接口”。
|
||||
|
||||
第三步建议优先补这几类用户接口:
|
||||
|
||||
### 第一组:当前用户查看自己的记忆
|
||||
|
||||
1. `GET /api/v1/memory/items`
|
||||
- 分页查看“我自己的记忆”
|
||||
2. `GET /api/v1/memory/items/:id`
|
||||
- 查看“我自己的某条记忆”详情
|
||||
|
||||
### 第二组:当前用户主动维护自己的记忆
|
||||
|
||||
1. `POST /api/v1/memory/items`
|
||||
- 手动新增一条记忆
|
||||
2. `PATCH /api/v1/memory/items/:id`
|
||||
- 修改自己的一条记忆
|
||||
3. `DELETE /api/v1/memory/items/:id`
|
||||
- 删除自己的一条记忆
|
||||
|
||||
### 第三组:当前用户恢复误删内容
|
||||
|
||||
1. `POST /api/v1/memory/items/:id/restore`
|
||||
- 若底层采用软删或归档,可补恢复动作
|
||||
|
||||
这些接口都默认只允许操作“当前登录用户自己的记忆”,不支持跨用户查询和跨用户修改。
|
||||
|
||||
原则:
|
||||
|
||||
1. 原始日志看后端 stdout
|
||||
2. 内部变更留痕优先给后端查表和排障使用,不急着做成前端正式能力
|
||||
3. 对外先开放用户真正会用到的“我的记忆”增删改查
|
||||
|
||||
---
|
||||
|
||||
## 4. 第三步到底要做什么
|
||||
|
||||
## 4.1 观测与切流
|
||||
|
||||
这是第三步的第一优先级。
|
||||
|
||||
### 要做的事
|
||||
|
||||
1. 给写入决策链路补统一结构化日志
|
||||
2. 给读侧召回链路补统一结构化日志
|
||||
3. 给注入渲染链路补统一结构化日志
|
||||
4. 给上述三条链路补关键计数指标
|
||||
5. 把现有配置字段整理成清晰的切流顺序和回滚手册
|
||||
|
||||
### 为什么先做这个
|
||||
|
||||
因为第三步如果先做 dedup 清理,但没有日志和切流能力,一旦清错了,排查成本会很高。
|
||||
|
||||
---
|
||||
|
||||
## 4.2 用户管理与清理
|
||||
|
||||
这是第三步的第二优先级。
|
||||
|
||||
### 要做的事
|
||||
|
||||
1. 给“我的记忆”补完整增删改查语义
|
||||
2. 给历史重复数据补离线 dedup 工具
|
||||
3. 给关键变更动作补最小留痕
|
||||
4. 把 dedup 保持在后端内部治理流程,不急着做成前端接口
|
||||
|
||||
### 为什么不一上来绑主 worker
|
||||
|
||||
因为第一版 dedup 的目标是“可留痕、可回滚”,不是“全自动”,也不是先给 `memory` 单独造一个很重的治理后台。
|
||||
|
||||
离线或手动触发更安全,出问题也更容易止血。
|
||||
|
||||
---
|
||||
|
||||
## 5. 具体改动计划
|
||||
|
||||
## 5.1 第一轮:先把观测底座补起来
|
||||
|
||||
### 目标
|
||||
|
||||
先让系统“可看见”。
|
||||
|
||||
### 预计改动
|
||||
|
||||
新增:
|
||||
|
||||
1. `backend/memory/observe/log_fields.go`
|
||||
|
||||
修改:
|
||||
|
||||
1. `backend/memory/worker/decision_flow.go`
|
||||
2. `backend/memory/worker/apply_actions.go`
|
||||
3. `backend/memory/service/read_service.go`
|
||||
4. `backend/memory/service/retrieve_merge.go`
|
||||
5. `backend/service/agentsvc/agent_memory.go`
|
||||
6. `backend/service/agentsvc/agent_memory_render.go`
|
||||
|
||||
### 这一轮会补什么日志
|
||||
|
||||
#### 写入决策日志
|
||||
|
||||
至少记录这些字段:
|
||||
|
||||
1. `trace_id`
|
||||
2. `user_id`
|
||||
3. `conversation_id`
|
||||
4. `job_id`
|
||||
5. `fact_type`
|
||||
6. `candidate_count`
|
||||
7. `final_action`
|
||||
8. `fallback_mode`
|
||||
9. `success`
|
||||
|
||||
#### 读侧召回日志
|
||||
|
||||
至少记录这些字段:
|
||||
|
||||
1. `trace_id`
|
||||
2. `user_id`
|
||||
3. `read_mode`
|
||||
4. `query_len`
|
||||
5. `legacy_hit_count`
|
||||
6. `semantic_hit_count`
|
||||
7. `dedup_drop_count`
|
||||
8. `final_count`
|
||||
9. `degraded`
|
||||
|
||||
#### 注入渲染日志
|
||||
|
||||
至少记录这些字段:
|
||||
|
||||
1. `trace_id`
|
||||
2. `user_id`
|
||||
3. `inject_mode`
|
||||
4. `input_count`
|
||||
5. `rendered_count`
|
||||
6. `token_budget`
|
||||
7. `fallback`
|
||||
|
||||
---
|
||||
|
||||
## 5.2 第二轮:补指标,不急着开 overview 接口
|
||||
|
||||
### 目标
|
||||
|
||||
先让系统“可量化”。
|
||||
|
||||
### 第一版建议补的指标
|
||||
|
||||
优先补这 8 个:
|
||||
|
||||
1. `memory_job_success_rate`
|
||||
2. `memory_job_retry_rate`
|
||||
3. `memory_decision_distribution`
|
||||
4. `memory_decision_fallback_rate`
|
||||
5. `memory_retrieve_hit_count`
|
||||
6. `memory_retrieve_dedup_drop_count`
|
||||
7. `memory_inject_item_count`
|
||||
8. `memory_rag_fallback_rate`
|
||||
|
||||
暂不强求第一版就补:
|
||||
|
||||
1. `memory_wrong_mention_rate`
|
||||
2. `memory_user_correction_rate`
|
||||
|
||||
因为这两个更依赖后续“用户纠错入口”。
|
||||
|
||||
### 这一轮先不做什么
|
||||
|
||||
这一轮先不单独新增 `GET /api/v1/memory/overview`。
|
||||
|
||||
原因不是这个接口没价值,而是现在别的模块还没有统一的观测面板和汇总接口规范。`memory` 这一轮先把指标打稳,后续如果全项目一起做观测面板,再统一收口更对称。
|
||||
|
||||
也就是说,这一轮优先把“数据先有”做出来,不急着把“看板接口先长出来”。
|
||||
|
||||
---
|
||||
|
||||
## 5.3 第三轮:补用户管理动作
|
||||
|
||||
### 目标
|
||||
|
||||
先让用户“能管理自己的记忆”。
|
||||
|
||||
### 预计改动
|
||||
|
||||
修改:
|
||||
|
||||
1. `backend/memory/service/manage_service.go`
|
||||
2. `backend/memory/repo/item_repo.go`
|
||||
3. `backend/memory/utils/audit.go`
|
||||
4. `backend/memory/module.go`
|
||||
|
||||
新增:
|
||||
|
||||
1. `backend/api/memory.go`
|
||||
2. 路由注册文件中的 memory 接线
|
||||
|
||||
### 要补的动作
|
||||
|
||||
1. `list`
|
||||
2. `detail`
|
||||
3. `create`
|
||||
4. `update`
|
||||
5. `delete`
|
||||
6. 若底层保留软删语义,再补 `restore`
|
||||
|
||||
### 接口建议
|
||||
|
||||
新增:
|
||||
|
||||
1. `GET /api/v1/memory/items`
|
||||
2. `GET /api/v1/memory/items/:id`
|
||||
3. `POST /api/v1/memory/items`
|
||||
4. `PATCH /api/v1/memory/items/:id`
|
||||
5. `DELETE /api/v1/memory/items/:id`
|
||||
6. `POST /api/v1/memory/items/:id/restore`
|
||||
- 仅在底层采用软删或归档方案时开放
|
||||
|
||||
### 设计要求
|
||||
|
||||
1. 所有接口默认只作用于“当前登录用户自己的记忆”
|
||||
2. 后端仍保留最小变更留痕,但不把它包装成用户侧“审计接口”
|
||||
3. 接口返回给前端的是“人能看懂的记忆内容和操作结果”,不是底层日志
|
||||
|
||||
---
|
||||
|
||||
## 5.4 第四轮:做离线 dedup 治理
|
||||
|
||||
### 目标
|
||||
|
||||
先让系统“可清理”。
|
||||
|
||||
### 预计新增
|
||||
|
||||
1. `backend/memory/cleanup/dedup_runner.go`
|
||||
2. `backend/memory/cleanup/dedup_policy.go`
|
||||
|
||||
### 第一版治理规则
|
||||
|
||||
按以下维度扫描重复组:
|
||||
|
||||
1. `user_id`
|
||||
2. `memory_type`
|
||||
3. `content_hash`
|
||||
4. `status = active`
|
||||
|
||||
每组处理规则:
|
||||
|
||||
1. 选一条主记录保留
|
||||
2. 优先保留最近更新的
|
||||
3. 若最近更新时间接近,则优先保留置信度更高的
|
||||
4. 其余记录改为 `archived`
|
||||
5. 每次治理动作都写最小变更留痕
|
||||
|
||||
### 接口建议
|
||||
|
||||
这一轮不对外新增 dedup 接口。
|
||||
|
||||
dedup 先保留为后端内部治理能力,必要时通过离线任务、后台命令或内部 job 触发,避免 `memory` 先演化成一个比其他模块更重的专用治理后台。
|
||||
|
||||
### 明确限制
|
||||
|
||||
第一版不做:
|
||||
|
||||
1. 直接危险 SQL 清表
|
||||
2. 自动定时常驻清理
|
||||
3. 无留痕的批量删除
|
||||
|
||||
---
|
||||
|
||||
## 6. 日志、留痕、接口分别给谁看
|
||||
|
||||
这个地方一定要分清,不然第三步会越做越乱。
|
||||
|
||||
### 运行日志
|
||||
|
||||
给研发和排障看。
|
||||
|
||||
特点:
|
||||
|
||||
1. 实时
|
||||
2. 噪音大
|
||||
3. 字段多
|
||||
4. 不直接给前端
|
||||
|
||||
### 变更留痕
|
||||
|
||||
先给研发和后端排障使用。
|
||||
|
||||
特点:
|
||||
|
||||
1. 是持久化结果
|
||||
2. 适合看历史
|
||||
3. 这一轮不急着做成正式用户接口
|
||||
|
||||
### 用户接口
|
||||
|
||||
给用户和前端页面看。
|
||||
|
||||
特点:
|
||||
|
||||
1. 只暴露“我的记忆”内容和操作结果
|
||||
2. 不暴露内部 raw log
|
||||
3. 不承载平台级观测职责
|
||||
|
||||
---
|
||||
|
||||
## 7. 切流顺序
|
||||
|
||||
第三步不允许一刀切。
|
||||
|
||||
建议严格按下面顺序灰度:
|
||||
|
||||
1. 阶段 A:决策层 shadow
|
||||
- 真正写库仍然走 `legacy`
|
||||
- 新决策层只记日志,不生效
|
||||
2. 阶段 B:决策层仅对显式记忆生效
|
||||
3. 阶段 C:决策层对全部写入生效
|
||||
4. 阶段 D:读侧切到 `hybrid`
|
||||
5. 阶段 E:注入切到 `typed_v2`
|
||||
6. 阶段 F:历史清理跑完,再考虑关闭 `legacy` 默认路径
|
||||
|
||||
这里的配置基础已经存在,关键是把切流顺序写清、用清、能回退。
|
||||
|
||||
参考文件:
|
||||
|
||||
1. `backend/memory/model/config.go`
|
||||
2. `backend/memory/service/config_loader.go`
|
||||
|
||||
---
|
||||
|
||||
## 8. 回滚方案
|
||||
|
||||
第三步的回滚不应影响前两步代码保留,只回切开关。
|
||||
|
||||
### 最小回滚动作
|
||||
|
||||
1. 写侧回到 `legacy`
|
||||
2. 读侧回到 `legacy`
|
||||
3. 注入回到 `flat`
|
||||
4. 停掉 dedup 清理任务
|
||||
|
||||
### 回滚原则
|
||||
|
||||
1. 先停治理动作,再回切主路径
|
||||
2. 不做破坏性 schema 回滚
|
||||
3. 不依赖人工热修逻辑判断
|
||||
|
||||
---
|
||||
|
||||
## 9. 第三步明确不做什么
|
||||
|
||||
为了防止范围失控,这一轮明确不做:
|
||||
|
||||
1. 不做图记忆
|
||||
2. 不做多 Provider 工厂化
|
||||
3. 不拆独立 memory 服务
|
||||
4. 不在这一轮给 `memory` 先单独做完整审计后台
|
||||
5. 不把 WebSearch 和 Memory 强行合并成一轮上线
|
||||
6. 不再扩新的召回算法分支
|
||||
|
||||
---
|
||||
|
||||
## 10. 完成标准
|
||||
|
||||
满足以下条件,算第三步完成:
|
||||
|
||||
1. 能从日志看清某条记忆为什么被判成 `ADD / UPDATE / DELETE / NONE`
|
||||
2. 能从指标看清召回命中、去重、降级、回滚情况
|
||||
3. 用户能通过接口管理自己的记忆
|
||||
4. 能对历史重复数据做可留痕清理
|
||||
5. 出异常时能通过开关在分钟级切回 `legacy`
|
||||
6. 文档和代码现状一致,不再靠口头传递
|
||||
|
||||
---
|
||||
|
||||
## 11. 如果只看一页,请看这个执行顺序
|
||||
|
||||
第三步不要散着做,建议按这个顺序推进:
|
||||
|
||||
1. 先补统一日志字段和结构化日志
|
||||
2. 再补指标,把观测数据打稳
|
||||
3. 再补“我的记忆”增删改查能力
|
||||
4. 最后做离线 dedup 和内部清理能力
|
||||
|
||||
一句人话总结:
|
||||
|
||||
先让系统“看得见”,再让系统“能管理”,最后再让系统“敢清理”。
|
||||
Reference in New Issue
Block a user