214 lines
4.7 KiB
Markdown
214 lines
4.7 KiB
Markdown
# Thread Memory 手动测试清单
|
||
|
||
日期:`2026-05-08`
|
||
测试人:`__________`
|
||
|
||
---
|
||
|
||
## 0. 前置检查
|
||
|
||
- [ ] 已拉取包含以下修复的最新代码并重启后端进程
|
||
- `memory.enabled=false` 时仍允许 `thread_memory` 更新
|
||
- `thread_prompt` 的 JSON 模板转义修复(避免 `KeyError: "profile"`)
|
||
- `thread_updater` 使用非流式安全参数(避免 `stream_options` 400)
|
||
- [ ] `config.yaml` 中已启用 `thread_memory.enabled: true`
|
||
- [ ] 确认使用的是预期配置文件(当前项目根目录 `config.yaml`)
|
||
|
||
---
|
||
|
||
## 1. 基础写入与读取
|
||
|
||
前置条件:
|
||
- 选择一个新的 `thread_id`(例:`1f571481-e3ae-42b5-a513-945bf8f1cbef`)
|
||
|
||
步骤:
|
||
1. 在该线程发送 2-3 轮消息,包含姓名、角色、偏好语气等信息
|
||
2. 等待 `debounce_seconds`(默认 30 秒)
|
||
3. 查询 `thread_memory` 表
|
||
|
||
期望:
|
||
- 出现该 `thread_id` 记录
|
||
- `profile/preferences/facts` 有对应内容
|
||
|
||
结果:
|
||
- [1] 通过
|
||
- [ ] 失败(备注:`________________`)
|
||
|
||
---
|
||
|
||
## 2. Per-Thread 隔离
|
||
|
||
前置条件:
|
||
- 准备两个线程 `thread_A`、`thread_B`
|
||
|
||
步骤:
|
||
1. 在 A 中输入“前端背景”信息
|
||
2. 在 B 中输入“后端背景”信息
|
||
3. 分别等待写入完成后查看两条记录
|
||
|
||
期望:
|
||
- A 仅保存 A 的画像,B 仅保存 B 的画像
|
||
- 两个线程不串数据
|
||
|
||
结果:
|
||
- [1] 通过
|
||
- [ ] 失败(备注:`________________`)
|
||
|
||
---
|
||
|
||
## 3. 全局记忆 Fallback
|
||
|
||
前置条件:
|
||
- 全局 memory 有内容
|
||
- 新建一个尚无 per-thread 记录的线程
|
||
|
||
步骤:
|
||
1. 先在该新线程发一轮普通消息
|
||
2. 观察回复是否体现全局记忆
|
||
3. 再继续对话触发 per-thread 写入后观察注入变化
|
||
|
||
期望:
|
||
- 无 per-thread 时可 fallback 到全局
|
||
- 有 per-thread 后优先使用 per-thread
|
||
|
||
结果:
|
||
- [ ] 通过
|
||
- [ ] 失败(备注:`未执行(N/A):当前环境 memory.enabled=false,全局记忆关闭,本用例不适用`)
|
||
|
||
---
|
||
|
||
## 4. 注入裁剪优先级(Profile > Preferences > Facts)
|
||
|
||
前置条件:
|
||
- 某线程已有大量 facts
|
||
|
||
步骤:
|
||
1. 人为积累 facts 到接近/超过注入预算
|
||
2. 保持 profile/preferences 有值
|
||
3. 观察注入后的表现
|
||
|
||
期望:
|
||
- 超预算时保留 profile + preferences
|
||
- 优先裁剪 facts
|
||
|
||
结果:
|
||
- [1 ] 通过
|
||
- [ ] 失败(备注:`________________`)
|
||
|
||
---
|
||
|
||
## 5. 敏感信息过滤
|
||
|
||
步骤:
|
||
1. 在对话中输入邮箱、手机号、token/password 等敏感样例
|
||
2. 等待写入后查库
|
||
|
||
期望:
|
||
- 敏感信息不应落入 `profile/preferences/facts`
|
||
|
||
结果:
|
||
- [1] 通过
|
||
- [ ] 失败(备注:`________________`)
|
||
|
||
---
|
||
|
||
## 6. 并发覆盖保护(CAS + version)
|
||
|
||
步骤:
|
||
1. 同一 `thread_id` 短时间内触发两次更新(尽量并发)
|
||
2. 观察最终数据与日志
|
||
|
||
期望:
|
||
- 不出现明显“旧数据覆盖新数据”
|
||
- 冲突时可见重试行为(日志)
|
||
|
||
结果:
|
||
- [1] 通过
|
||
- [ ] 失败(备注:`________________`)
|
||
|
||
---
|
||
|
||
## 7. Debounce 生效
|
||
|
||
步骤:
|
||
1. 在 30 秒内连续发送多条消息
|
||
2. 观察写库频率
|
||
|
||
期望:
|
||
- 多条输入被合并处理,不是每条都立即写库
|
||
|
||
结果:
|
||
- [1] 通过
|
||
- [ ] 失败(备注:`________________`)
|
||
|
||
---
|
||
|
||
## 8. 线程删除联动清理
|
||
|
||
步骤:
|
||
1. 对已有 per-thread 记录的线程调用 `DELETE /api/threads/{thread_id}`
|
||
2. 查询 `thread_memory` 表
|
||
|
||
期望:
|
||
- 对应 `thread_id` 记录被删除
|
||
|
||
结果:
|
||
- [ ] 通过
|
||
- [ ] 失败(备注:`未执行:当前产品决策不接受“删线程即删记忆”,需改为用户显式触发清除后再复测`)
|
||
|
||
---
|
||
|
||
## 9. SQLite 自动建表与路径
|
||
|
||
步骤:
|
||
1. 删除现有 `thread_memory.db`(测试环境)
|
||
2. 重启服务并触发一轮写入
|
||
3. 检查 DB 文件和表结构
|
||
|
||
期望:
|
||
- 自动创建 DB 文件与 `thread_memory` 表
|
||
- 索引 `idx_thread_memory_owner_id` 存在
|
||
|
||
结果:
|
||
- [1] 通过
|
||
- [ ] 失败(备注:`________________`)
|
||
|
||
---
|
||
|
||
## 10. 配置开关验证
|
||
|
||
步骤:
|
||
1. 关闭 `thread_memory.enabled`,重启并测试写入
|
||
2. 开启 `thread_memory.enabled`,关闭 `thread_memory.injection_enabled`,重启并测试注入
|
||
|
||
期望:
|
||
- `enabled=false`:不更新 per-thread
|
||
- `injection_enabled=false`:不注入 per-thread(可 fallback)
|
||
|
||
结果:
|
||
- [1] 通过
|
||
- [ ] 失败(备注:`________________`)
|
||
|
||
---
|
||
|
||
## 11. 已知错误回归验证
|
||
|
||
### 11.1 `KeyError: "profile"` 回归
|
||
- [ 1] 未再出现 `thread_prompt.py` 的 `KeyError` 报错
|
||
|
||
### 11.2 `stream_options` 400 回归
|
||
- [ 1] 未再出现 `"'stream_options' only set this when you set stream: true"` 报错
|
||
|
||
备注:`________________`
|
||
|
||
---
|
||
|
||
## 测试总结
|
||
|
||
- 总用例数:`11`
|
||
- 通过数:`____`
|
||
- 失败数:`____`
|
||
- 结论:
|
||
- [ ] 可上线
|
||
- [ ] 需修复后复测
|