73 lines
4.4 KiB
Markdown
73 lines
4.4 KiB
Markdown
# Memory V2 候选表与生命周期灰度守卫
|
|
|
|
## 已知故障
|
|
|
|
生产曾出现 `h5_memory_v2_candidates` 不存在:候选记忆写入和后台查询报错,
|
|
但 Agent 召回仍在 shadow 模式执行,因此表现为“有召回事件、回答未注入、个人记忆状态降级”。
|
|
|
|
同时,生命周期 worker 只检查了 worker 开关;`expire()` 没有检查 rollout
|
|
作用域。若忘却开关开启,即使 `MEMORY_LIFECYCLE_ROLLOUT_MODE=off`,定时器也可能
|
|
归档全量用户的过期记忆。
|
|
|
|
灰度还曾出现 MySQL 已成功保存新记忆,但 pgvector 仍只包含旧数据:runtime 从全局
|
|
`updated_at=0` 游标开始做有限批次 backfill,新写入行可能长期排在批次之外。结果是
|
|
`agent_memory_resolved` 显示已注入,但回答只拿到旧的无关记忆。
|
|
|
|
首次修复同步后,灰度又发现 `remember-recent` 读取的是 Agent 编排后的会话文本,其中
|
|
包含已注入的 `[Memory Context]`。提取器因此可能把旧记忆再次沉淀,而忽略用户本轮明确
|
|
要求保存的内容,形成旧记忆自我复制。
|
|
|
|
提取器返回 `{"memories":[]}` 时,旧逻辑仍会触发规则回退,可能把“……是什么”一类
|
|
问句误存为事实。空数组必须视为成功的“无需保存”判断;只有提取不可用并返回 `null`
|
|
时才允许规则回退。
|
|
|
|
当前生产使用的本地 hash embedding 只有 3 维,且连续中文可能被视为单个 token。即使正确
|
|
记忆已进入 pgvector,它也可能排在向量 Top-K 之外。因此 pgvector 读取必须合并有界的
|
|
向量候选与最近候选,再以中文字符 n-gram 查询覆盖率重排;无词法重合时保持向量排序。
|
|
|
|
## 必须保留的行为
|
|
|
|
1. `MEMORY_CANDIDATE_PERSISTENCE_ENABLED=1` 且 MySQL 可用时,Portal 必须先执行
|
|
`ensurePersonalMemoryCandidateSchema()`,再创建候选记忆 store。
|
|
2. 候选表 DDL 失败不能阻塞 Portal 聊天启动;Portal 应记录告警并退回 bounded-memory。
|
|
3. memind_adm 必须在创建候选 store 前完成同一幂等建表;初始化失败时后台启动失败,
|
|
不允许以“页面可用但候选接口持续报错”的半初始化状态运行。
|
|
4. 生命周期 rollout 语义必须严格一致:
|
|
- `off`:不得执行任何写操作,也不得启动 worker 定时器。
|
|
- `canary`:只允许 `MEMORY_LIFECYCLE_ROLLOUT_USER_IDS` 中的用户。
|
|
- `active`:才允许无 user scope 的全局任务。
|
|
5. `forgetMemory()` 和 `expire()` 都必须同时满足功能开关与 rollout 作用域。
|
|
6. 用户记忆 `write/compact` 成功后,必须在返回前按 `userId + sessionId` 将本次活跃记忆
|
|
幂等 upsert 到 pgvector;候选晋升成功后也必须按实际晋升用户同步。不得依赖从零开始
|
|
的全局有限批次 backfill 来保证新记忆可立即召回。
|
|
7. 显式记忆提取必须优先使用同一用户、同一会话中已成功 `h5_agent_runs.user_message_json`
|
|
保存的原始用户消息。不得把 Agent 编排提示或 `[Memory Context]` 当作用户的新记忆;
|
|
原始消息查询失败时必须 fail-open 到现有可见会话,不能阻塞保存接口。
|
|
8. pgvector 召回必须同时覆盖有界向量候选和有界最近候选,去重后只返回请求的 limit;
|
|
中文词法重排用于弥补低维本地 hash 的排序缺陷,且候选池上限不得超过 100。
|
|
9. LLM 提取明确返回空数组时不得再走规则回退;提取提示必须明确排除没有提供答案的
|
|
问题、请求、指令和待办,避免把问句本身沉淀为长期记忆。
|
|
|
|
## 回归检查
|
|
|
|
```bash
|
|
node --test conversation-memory.test.mjs conversation-repair.test.mjs memory-v2-personal-store.test.mjs memory-v2-lifecycle.test.mjs \
|
|
memory-v2-pgvector-backfill.test.mjs memory-v2-runtime.test.mjs
|
|
npm test
|
|
```
|
|
|
|
memind_adm 同时执行:
|
|
|
|
```bash
|
|
node --test server/personal-memory-candidate-store.test.mjs
|
|
npm test
|
|
```
|
|
|
|
灰度上线后还必须验证:候选表存在、候选写入成功、后台可查询,以及一个测试用户完成
|
|
“保存 → 候选 → 晋升 → 新会话召回 → 回答注入”的闭环。未通过前不得切换全量 active。
|
|
|
|
## 回滚
|
|
|
|
代码可以按标准 runtime/release 回滚;候选表是加法结构,回滚时保留空表或已有数据,
|
|
不得为了代码回滚直接删除表。先把候选、生命周期和 Agent 注入模式切回 shadow/off。
|