# Normify 检索层评测结果(复制即跑 · n=3 × repeat=2) > **结论先行**:本评测只回答"检索层"(给定结构知识问题,三种手段的**正确率 / 延迟 / 输出 token** 对比)。 > **它不是 LLM A/B,也不代表端到端 agent 收益**。LLM 层协议见 [EVAL.md](EVAL.md)。 - 生成时间(UTC):2026-11-03T13:55:55.955Z - 复现命令:`node eval/harness.mjs` - Normify 版本:结构数据 spec `v2`;CLI = `node lib/cli/index.js`(full toolset 31 工具) - 环境:Node v24.21.0;k=3;每 arm 每任务 n=3 次独立进程,整轮重复 2 次 - fixture:131 模块 / 216 API / 88 依赖 / 6 planned / 4 deprecated / 3 棵树 / 任务 30 条 - 原始数据:`eval/results/raw-2026-11-03T13-55-55-955Z.json`(含每次运行明细:arm × task × rep × repeat) ## 方法 1. **fixture(确定性合成仓库)**:`eval/spec.mjs` 用固定 hash 生成模块/uid/API/依赖(同 spec 版本字节级可复现);`eval/fixture.mjs` 物化为 `repo/`(源码骨架 + git 提交)与 `structure/normify-eval-demo/`(结构数据),并用真实 CLI `build` 产出 `tree.json` / `structure-manifest.json`。drift 任务各用一个独立 git 仓库副本(只含一处工作区修改)。 2. **任务集(30 条,4 类)**:locate(哪个模块拥有某 API)/ impact-in(谁依赖我)/ impact-transitive(隔一跳间接依赖)/ impact-out(我依赖谁)/ list-leaves(子树叶子)/ list-planned(planned 模块)/ drift(某文件变更影响哪些模块)。**ground truth 全部由脚本从模块图推导**,无手写答案。 3. **三个 arm**(同任务、同 fixture): - A `grep`:递归扫描源码 + 模块 Markdown,字符串匹配后解析 id(模拟"没有结构工具、只能 grep/读文件"的 agent); - B `tree`:只读 `tree.json` 做 JSON 过滤(模拟"有编译产物但没有工具"); - C `normify`:只通过 `node lib/cli/index.js`(search / get / list / call deps_find / sync),走真实 core/toolset。 4. **指标**:hit@3(前 3 个返回 id 覆盖全部 ground truth 的比例)、recall@3、平均墙钟 ms、平均输出字节、token 代理 = 输出字节/4、CLI 调用次数;另记**本地扫描字节**与**上下文数据量估计**(见成本表)。 ## 结果总表(n=3) | arm | hit@3 | recall@3 | 平均墙钟 ms | 平均输出 B | token 代理 | 本地扫描 B | 上下文数据 B(估计) | CLI 调用 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | A. grep(文件扫描) | 100.0% | 100.0% | 130.76 | 20.6 | 5.15 | 186222 | 0 | 0 | | B. tree.json(JSON 过滤) | 100.0% | 100.0% | 104.45 | 20.6 | 5.15 | 188062 | 188062 | 0 | | C. normify CLI(真实引擎) | 100.0% | 100.0% | 426.19 | 916.93 | 229.23 | 0 | 0 | 1 | ### 成本:每次任务的数据搬运量(读取 + 输出) | arm | 输出 B | 本地扫描 B | 合计 B | 合计/4(token 量级) | | --- | --- | --- | --- | --- | | grep | 20.6 B | 186222 B | 186242.6 B | 46560.65 | | tree | 20.6 B | 188062 B | 188082.6 B | 47020.65 | | normify | 916.93 B | 0 B | 916.93 B | 229.23 | > 读法(三种成本分别定义): > - **token 代理** = 模型可见输出 / 4(本任务书指定口径); > - **本地扫描** = arm 为回答而在本地读了多少字节(A 的 grep 扫描、B 的 tree.json 读取;C 的读取在 CLI 进程内部); > - **上下文数据量(估计)** = 必须放进模型上下文的数据:B(有产物、无工具)需要整份 tree.json(≈ 47015.5 token/任务); > A 用 grep 工具时上下文只有匹配行(本表按 0 计,实际代价是多轮调用,见局限);C 的上下文只有工具输出(≈ 229.23 token/任务)。 ## 按任务类别(hit@3 / 平均输出字节) | 任务类别 | A. grep | B. tree.json | C. normify CLI | 输出字节 A / B / C | | --- | --- | --- | --- | --- | | locate | 100.0% | 100.0% | 100.0% | 13 B | 13 B | 191 B | | impact-in | 100.0% | 100.0% | 100.0% | 21 B | 21 B | 300.5 B | | impact-transitive | 100.0% | 100.0% | 100.0% | 33 B | 33 B | 2658.33 B | | impact-out | 100.0% | 100.0% | 100.0% | 16 B | 16 B | 1105 B | | list-leaves | 100.0% | 100.0% | 100.0% | 31 B | 31 B | 1000.5 B | | list-planned | 100.0% | 100.0% | 100.0% | 25 B | 25 B | 1114 B | | drift | 100.0% | 100.0% | 100.0% | 13 B | 13 B | 1205 B | ## 复跑稳定性(n=3 次独立进程 × 2 轮完整重复) | arm | hit@3 极差(跨整轮) | relSpread(跨整轮) | hit@3 极差(run 内) | 平均墙钟极差 | 各 rep 输出完全一致的任务 | | --- | --- | --- | --- | --- | --- | | grep | 1 – 1 | 0 | 1 – 1 | 129.62 – 131.9 ms | 30/30 | | tree | 1 – 1 | 0 | 1 – 1 | 103.33 – 105.58 ms | 30/30 | | normify | 1 – 1 | 0 | 1 – 1 | 424.89 – 427.49 ms | 30/30 | - 总耗时:26.7s(fixture 6.7s) - 验收口径:hit@3/recall@3 与输出字节在同版本下必须完全一致;墙钟相对极差 ≤10%(本次远低于)。 ## 观察(基于本次数据,自动生成) 1. **正确率天花板**:在确定性合成 fixture 上,三个 arm 的 hit@3 / recall@3 均为 100.0%(3 次独立进程重复一致)。 这说明"结构数据 + 任意检索手段"对**单跳事实型问题**都能答对;本评测因此主要在比**成本**(数据搬运量、延迟、工具调用),而不是比正确率。 真实差异会出现在多跳/歧义/大规模场景——见 EVAL.md 里的 LLM A/B 协议与后续扩展方向。 2. **上下文成本**:B(有产物、无工具)每任务需把整份 tree.json(188062 B ≈ 47015.5 token)放进上下文; C 的模型可见输出仅 916.93 B ≈ 229.23 token/任务(读取发生在 CLI 内部);A 的 grep 输出小,但需要多轮扫描(本 harness 未计轮次)。 3. **延迟**:C 单次 CLI 子进程约 426.19 ms(其中的 ~200ms 是进程启动;在 DSH 内工具调用无此开销),A/B 进程内 130.76/104.45 ms。 4. **调用次数**:C 每题恰好 1 次 CLI 调用(无多轮试探);A/B 为 0 次外部调用但有全量数据访问权。 ## 局限(必读) 1. **只测检索层**:没有 LLM 参与 → 不能推论"接入 Normify 后 agent 任务成功率提升";token 代理只算检索输出字节,不含模型思考/工具调用编排开销。 2. **fixture 是合成仓库**:结构规整、命名有规律,检索难度低于真实遗留仓库;grep arm 还能读到 `normify-*/modules/*.md`(这是有意为之:现实中"无工具 agent"也能 grep 文件,只是不知道结构语义)。 3. **arm 实现是"理想化检索器"**:A/B 直接在进程内解析,无模型选择成本;C 每次 CLI 调用有 ~200ms 进程启动成本(真实 DSH 内工具调用无此开销,但其结果仍需进入模型上下文)。 4. **单机单次**:n=3 只覆盖进程级噪声;跨机器/跨 load 未测;fixture 缓存复用(--fresh 可强制重建)会让构建耗时与生成路径不同。 5. **drift 语义**:每个 drift 任务用独立 git 副本(单文件改动),真实场景里一次改动常包含多文件 → C 的 sync 需要被调用一次即可返回全部 affected(本评测按单文件计费)。 6. **ground truth 来自生成 spec**:因此本评测检验"检索手段是否忠实反映结构数据",不检验"结构数据本身是否正确"(后者由 core-unit / e2e 测试保证)。