Files
natural-memory-agent-lab/PRODUCTION_TEST_REPORT.md
T

189 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NM2 模型 + Agent 生产级测试报告
> 测试对象:`H:\Memory\V2_dpskw\qwen3_5_4b_natural_memory_v2`(**NM2.0**)
> 测试方式:**真任务**,不是合成场景;每条结论都配一台机器上可复现的客观基准
> 测试期:2026-09-15(Agent 侧来自本次会话的多轮实测)
> 被测设施:`agent_lab/model_server/server.py`(控制面)+ `agent_lab/agent`(Pi Agent,11 个工具)
---
## 0. 一句话结论
**记忆这层已经站住了;挡在"每天都要用"前面的是模型侧的行为,不是记忆检索。**
七个测试族里 **六个可判定通过**(各带基准),**长时间稳定性因显卡被占用未测完**。
过程中修掉 1 个模型包真 bug(属性抽取把盘符冒号当分隔符)、1 个沿用已久的结构性缺陷(更正无法版本化 Agent 写入的记录),
以及若干 harness 缺陷;并**记录了我自己三次方法错误**,供复核。
---
## 1. 测试方法(以及两次差点误判的地方)
1. **先量基准,再判模型**。所有数字(文件数、磁盘可用、文件首行)都在跑之前用 PowerShell 独立量出,
绝不用模型的输出去验证模型。
2. **跨会话必须换进程**。同一进程内的追问可能靠对话上下文答对,**不能证明是记忆在起作用**——
凡是声称"记忆有效"的结论,都用**全新进程、上下文为空**复现过。
3. **测延迟前必须查显卡**。我的设施和用户的评测共用一块 RTX 5070。
第十一轮长跑里,每轮生成从 12.7 秒"涨到"137.6 秒,而 prompt 词元只涨 1.7 倍——
比例不对,去查显卡才发现是**用户自己的 `locomo_nm21_e2e` 评测占满 100%**。
**那是争用,不是会话退化。** 差点当成性能衰减报出去。
4. **测量 setup 必须复现真实时序**。写入路径上"本轮的事实"在生成前**还没进库**,
我一度把两条记录都写进库再测,量到的是另一个问题。
---
## 2. 逐族结论
| # | 测试族 | 判定 | 客观基准 | 实测结果 |
|---|---|---|---|---|
| 1 | 真实文件理解 | ✅ 通过 | `WRITE_PATH_FIX.md`(4023 字符) | 读完正确概括根因(`confirmed_update` 依赖学习打分 0.95、缺 `(entity,attribute)` 结构校验 → 误删) |
| 2 | 真实命令与数据统计 | ✅ 通过(修 harness 后) | `artifacts` 顶层 46 个;`V2_dpskw` 递归 `.py` 133 个;C 盘可用 34.47 GB | `list_files`→46 ✓、`list_files{recursive}`→133 ✓、`disk_space`→34.52 GB ✓ |
| 3 | 跨会话记忆支撑真活 | ✅ 通过 | 新进程、上下文为空 | 召回命中(`用记忆=要 · 命中 2 条 · 205 词元`)→ 调工具 → 答对目录 |
| 4 | 更正必须生效 | ✅ 通过(经三轮修复) | 旧值应退位 | `改了:…` → 旧记录 `superseded`、新进程答新路径;**回归场景无污染** |
| 5 | 不知道时拒答 | ✅ 通过 | 无 | 股票 →「我没有你购买的股票信息」;模型参数量 →「我不知道。没有证据表明…」 |
| 6 | 多步工具链 | ✅ 通过(修 harness 后) | 9 个 `client-*.txt`;首个 `client-api-check.txt` 首行 `PASS /api/send 返回成功` | 两步全对,17.7 秒 |
| 7 | 长时间日用稳定性 | ⚠️ **未测完** | —— | 24 轮只跑完 11 轮;**已完成轮次全部答对**,但耗时数据因显卡争用作废 |
---
## 3. 修掉的缺陷
### 3.1 模型包:属性抽取把盘符冒号当分隔符(真 bug)
`infer_memory_metadata` 的操作符列表含**裸冒号**:`(?:…|是|为|叫|:|:|=)`。
句子「我的评测报告**放在** `E:`\deepseek\artifacts」用的是「放在」而非「是」,正则于是抓到**盘符那个冒号**:
```
属性='评测报告放在 E' 取值='\deepseek\artifacts'
```
后果:同一件事被归档在**永远无法与 Agent 写的 `评测报告路径` 匹配**的键下,**旧值永远无法被取代**。
**修法**:冒号前是单个 ASCII 字母时不作分隔符(`(?<![A-Za-z])[::]`)。CJK 后的冒号仍是正常分隔符。
修复后路径句返回 `episode`(**宁可不给属性,也不给错属性**)。
### 3.2 模型包:更正无法版本化「经接口写入」的记录(结构缺陷)
「措辞变了也要版本化」的补救路径**按 `slot_index` 匹配继承对象**;
而 Agent 经接口写入的记录 `slot_index = -1`(独立分页项,不占遗留槽位)。
**凡是 Agent 自己写进记忆的事实,自动层永远无法把它版本化。**
该段的注释本身写着它的来历(realistic 语料上 25/25 更新失败)——**同一个 bug 类被修过一次,但修法绑死在槽位上**。
**修法**:新增一条继承路径,但必须同时满足**两道门**:
| 门 | 理由 |
|---|---|
| `not candidate_conflict_key` | 解析器给出结构时**一律不猜**(原有代码就有这道门) |
| 有身份记录自己的**绝对分数** ≥ 5.0 | 实测两簇:真更新 8.591/8.6325/8.64,无关 ≤0.682/0.7421 |
**为什么不用 `score_margin`(我第一版的做法)**:`margin = top − second`,
而**自动层每一轮都会插一条近似重复的记录**,把 margin 从 8.591 砸到 0.1523——
**那道门正好卡在它本该放行的那一类上。**
### 3.3 我自己的三次方法错误(如实记录)
| # | 错误 | 后果 | 纠正 |
|---|---|---|---|
| 1 | 继承块漏了 `not candidate_conflict_key` 这道门 | 用读取器的"最近邻猜测"**覆盖了解析器给出的正确结构**,把 `默认语言=日语` 污染成 `蓝鲸-47` | 已回退并补门;用仪表复现确认机理 |
| 2 | 标定正类用了「我的A**改成** v2」 | `改成` **本身会被结构解析**,那批样本**永远走不到继承块**——**population 标错了** | 按正确 population 重测,两簇间隔 0.74 vs 8.63 |
| 3 | 测延迟时未查显卡 | 把**争用**当成"会话退化"(12.7s→137.6s) | 已作废该数据并记录纪律 |
### 3.4 harness 缺陷(Agent 侧)
| 缺陷 | 实测 | 修法 |
|---|---|---|
| 模型手写 PowerShell 必翻车 | `-eq 'C:'` 比字符 → **成功但零输出** → 同一命令重发 10+ 次 → 会话被污染 | 新增窄接口工具 `disk_space` / `list_files` / `peek_files`,**模型只填路径** |
| 工具输出只给裸文件名,逼模型自己拼路径 | 它拿到 9 个正确文件名后**编了个 `client-0001.txt`** | `list_files` 每项返回**完整路径** |
| 静默零输出无法与"还没查到"区分 | 模型陷入重试 | 零输出时明确解释"多半是过滤条件没匹配、不要再发同一条" |
| 编造:问数量却跳过工具直接给数字 | 磁盘答 **100 GB**(真值 34.62);文件数答 **0**(真值 46) | 编造检测 + **强制重问**(问题问数量、零工具调用、回答含数字 → 追加一轮要求先调工具) |
| 一次坏回合污染整段会话 | 失败命令的污染带进下一轮(99 秒) | 熔断改同步 `abort()`;**会话卫生仍待查实**(替换 `agent.state.messages` 实测未生效) |
| 关掉记忆并不等于对照组 | `memory_mode=off` 只关自动路径,**显式工具调用照样能读写记忆** | 所有写入端点在该模式下 409 拒绝 |
---
## 4. 一个反直觉的结论
**修好"编造"的不是检测器,而是窄接口工具。**
加了 `disk_space`/`list_files` 之后,同一个跨会话场景(目录只存在于记忆里)它**自己调了工具并答对 46**
(此前答 `0`,一次工具没调)。合理解释:**以前要么手写命令(易错)要么干脆不查;有了省事的正路,它就走正路。**
检测/强制重问至今**没在实战中触发过**,属兜底。
**推论**:面对小模型,**先把正确路径铺平,比教它不要犯错更有效**。
---
## 5. 日用可用性判定
| 能力 | 判定 |
|---|---|
| 单步 + 窄接口工具 | ✅ 可用(5–6 秒,答对) |
| 多步链路(工具给完整路径) | ✅ 可用(17.7 秒,两步都对) |
| 跨会话记忆召回 | ✅ 可用 |
| 拿不到就说拿不到 | ✅ 可用 |
| 自然措辞的更正(「改了…」) | ✅ **可用**(经三轮修复后) |
| **长时间(数十轮)稳定** | ⚠️ **未验证**(需独占显卡) |
| 口语化、过短的更新(「我换到 X 了」) | ❌ 路由弃权,自动层不版本化(路由自身的门) |
| 自己拼路径 / 手写 PowerShell | ❌ 不可用(已用完整路径与窄接口工具规避) |
---
## 6. 按用户方针做的收敛
用户方针:「**我希望更多配置由模型决定,外部不要传入那么多参数(必要的保留)**」。
据此删掉了 Agent 面上一批**覆盖模型已学判断**的参数:`nm2_write` 的 `importance`/`confidence`
(检查点本就有学到的 importance 头)、`config_set` 的 `read_threshold`/`min_read_margin`/`auto_*_threshold`/
`max_hops`/`coverage_*`/`top_k_*` 等。**保留**机器硬约束(KV 预算、缓存、分块)。
HTTP 的 `/v1/nm2/config` 仍保留全部旋钮——那是研究脚本在用的,收敛的是 **Agent 能看到、能传的参数**。
---
## 7. 未完成与复现
### 未完成
1. **长时间稳定性**:24 轮只跑完 11 轮,因用户评测占满显卡而中止;**重跑前先查显卡**。
2. **更正修复的生产形态复跑**(上轮同样被显卡占用打断)。
3. **会话卫生**:`agent.state.messages` 替换实测未生效(下一轮仍复读旧对话),需换一条能真正清尾的路子。
4. **两代模型对照**:全程只用 NM2.0,NM2.1 未做同一套生产测试(代码共用,但权重不同)。
### 复现
```powershell
# 控制面(占卡;先确认显卡空闲!)
$env:PYTHONPATH='H:\Memory'
& C:\Users\Administrator\miniconda3\envs\LLM\python.exe H:\Memory\agent_lab\model_server\server.py `
--model-path H:\Memory\V2_dpskw\qwen3_5_4b_natural_memory_v2 --port 8766 --no-auto-persist
# 控制面自检
& C:\Users\Administrator\miniconda3\envs\LLM\python.exe H:\Memory\agent_lab\model_server\selftest.py
# Agent 终端(真任务)
cd H:\Memory\agent_lab\agent
$env:NATURAL_MEMORY_API_KEY='local'
$env:NATURAL_MEMORY_BASE_URL='http://127.0.0.1:8766/v1'
bun run tui
# 脚本化多轮:bun run tui --session x --say '…' --say '…'
# CPU 测试(不占卡):92 项
cd H:\Memory
& C:\Users\Administrator\miniconda3\envs\LLM\python.exe -m unittest discover -s V2_dpskw\tests -t . -p 'test_*.py'
# margin / 分数判别力测量
& C:\Users\Administrator\miniconda3\envs\LLM\python.exe H:\Memory\agent_lab\measure_inherit_margin.py --rounds 3
```
### 逐轮原始记录
`H:\Memory\agent_lab\RESULTS.md` §6.10(第一轮到第十一轮),含每次的基准、命令、原始输出与当时的判断。
---
## 8. 结论
- **记忆层可以用了**:跨会话召回、更正生效、拒答、遗忘,都在真任务上验证过,且带了防误伤的回归检查。
- **模型本身仍是瓶颈**:它不会自己拼路径、写不对 PowerShell、会给没出处的数字。
这三条目前都是**用工具设计绕过去**的,不是修好了。
- **一个可推广的经验**:给小模型铺一条"正确且省事"的路(窄接口工具 + 可直接照抄的输出),
比反复叮嘱它别犯错有效得多——编造就是这么消失的。