我把检索召回从 16/32 修到 29/32,却只多通过 1 个问题
- 背景
- 新增 9 篇论文和 15 个测试问题后,目标证据进入候选列表的次数从 21/32 降到 16/32,新增问题的通过数从 5/15 降到 1/15。
- 问题
- 一次严格评分会同时受到论文数据、候选检索、原文读取、最终引用和评分规则影响,需要确认下降最早发生在哪一层。
- 做法
- 固定并重放检索查询,让测试论文与产品论文共用正式 Parser 和 Reading Model 构建流程,再分别统计找到、读取、引用和严格评分。
- 结果
- 目标证据进入候选列表恢复到 29/32,新增问题只从原来的 5/15 提高到 6/15;检索问题已经缩小,后续工作转向证据选择、引用覆盖和研究成本。
1. 背景、冲突、问题与结论
背景。 PaperLoom 新增了 9 篇 Agent Evaluation 论文和 15 个测试问题。扩展后,新增问题通过数从 5/15 降到 1/15,指定证据进入候选列表的次数从 21/32 降到 16/32。
冲突。 严格评分位于回答链路末端。论文数据、候选检索、原文读取、最终引用和评分规则中的任何 一层出错,都会表现为同一个 Fail。只看最终分数,无法判断应该修改哪一层。
问题。 分数下降最早发生在哪里?候选召回恢复后,最终回答能否同步恢复?
结论。 召回下降来自测试论文的数据结构与产品论文不一致。统一 Parser 和 Reading Model 构建流程 后,候选召回恢复到 29/32。新增问题最终为 6/15,只比扩展前多通过 1 个。后续限制位于候选之后的 读取、证据选择、引用和成本。
2. 先固定五个概念
| 概念 | 含义 |
|---|---|
| Reading Model | Parser 产出的论文结构,包含章节、页码、内容类型和阅读顺序 |
| Golden Data | 固定问题、指定论文和指定证据位置组成的离线测试数据 |
| Candidate | find_reading_locations 返回的候选位置 |
| Read / Cited | 模型已经读取该位置 / 最终答案已经引用该位置 |
| Hard Pass | 回答类型、指定位置和引用全部通过固定规则 |
Hard Pass 只表示答案满足当前固定规则。它不能直接代替自然语言回答的完整性或语义准确性。后续人工 审核也验证了这个边界。
3. 论证所依据的回答链路
Java 负责论文权限、会话和接口,Python Research Harness 负责 Agent 的研究过程:
用户问题
-> 搜索论文
-> 查找阅读位置
-> 读取准确原文
-> 组织引用
-> 提交答案
-> 离线严格评分一次回答被拆成四个可独立观察的阶段:
找到:候选结果出现指定位置
读取:模型读取指定位置的原文
引用:最终答案引用指定位置
严格评分:回答类型、指定位置和引用全部通过这个顺序存在明确依赖。候选中没有指定位置,模型无法读取它;没有读取,答案不能形成对应 Evidence; 没有引用,严格评分不会通过。
3.1 先只保留一条 Agent 运行路径
早期 Harness 把研究拆成 Intent、Retrieval Plan、Evidence Ledger、Claim Graph 和 Verification Pass。 连续的模型工具循环已经完成主要工作,后续阶段经常重复处理相同内容。
同一批 12 个固定问题得到下面的结果:
| 运行方式 | Hard Pass |
|---|---|
| 多阶段版本 | 3/12 |
| 多阶段版本加证据约束 | 4/12 |
| 连续的 Agent 工具循环 | 10/12 |
论点。 检索排查应建立在单一运行路径上。
论据。 连续工具循环通过数更高,多阶段版本还出现重复澄清、状态丢失和阶段切换错误。
论证。 同一问题同时经过多套控制流时,分数变化可能来自阶段切换,也可能来自检索。删除重复路径 可以减少干扰变量。
决定。 删除 4,000 多行自建控制流,把通用模型与工具循环交给 OpenAI Agents SDK。Harness 只保留 论文授权、位置公开、Evidence ID、引用检查和最终提交规则。
4. 决策一:先定位失败层,再修改算法
论点。 排查必须分别记录 Candidate、Read、Cited 和 Hard Pass,不能只比较最终分数。
论据。 检索返回正确位置后,模型仍可能不读取;读取后仍可能不引用;答案也可能因为 Outcome 或 格式规则失败。
论证。 如果 Candidate 已经命中,继续调 BM25 不会修复读取和引用。若 Candidate 没有命中,修改 提交检查也无法让模型看到目标位置。四层记录可以把修改指向最早失败的位置。
为了排除模型每次更换检索词的随机性,运行记录保存 find_reading_locations 的参数,再用完全相同的 参数离线重放 BM25。
决定。 检索变化使用固定查询重放;模型行为使用完整运行;最终评分在线下计算。三类结果分别保存, 不再用一个总分解释整条链路。
5. 决策二:先统一论文数据,再判断 BM25
论点。 这次召回下降应该修复测试论文的数据构建流程,不应该先增加 BM25 特殊规则。
论据。 原来的 5 篇测试论文来自正式 MinerU 流程。新增 9 篇论文使用了简化流程:
PDF
-> pdftotext
-> 按空行分段
-> 按句号切句
-> 全部标成普通段落
-> 不保存章节标题简化流程生成了 8,225 个句子片段,没有有效章节、标题、表格、图片或公式。文件格式符合接口,内容 结构却与产品 Reading Model 不同。
论证。 BM25 根据词频排序。按句号切碎后,后文反复出现技术词的片段更容易排在首页摘要之前。 如果此时增加“第一页优先”,规则只会补偿测试数据缺失,无法证明产品检索需要同样修改。
测试论文随后改为共用产品构建流程:
PDF
-> MinerU
-> MinerUOutputMapper
-> PaperReadingModelBuilder
-> paperloom-reading-model-export/v1
-> Golden Harness重建前后的结构差异如下:
| 指标 | 简化数据 | 正式数据 |
|---|---|---|
| Reading Model 元素 | 8,225 | 3,278 |
| 带有效章节的元素 | 0 | 2,626,约 80.1% |
| Heading | 0 | 437 |
| Table | 0 | 108 |
| Image + Chart | 0 | 139 |
| Formula | 0 | 16 |
| 可用物理页 | 弱页码近似 | 336 |
元素减少来自句子片段重新合并为段落、标题、表格和公式。正文没有丢失,章节、类型、阅读顺序和解析 来源恢复到产品使用的结构。
决定。 Golden Data 论文与产品论文共用正式 Parser 和 Reading Model 构建流程。没有增加“第一页 优先”或测试专用召回规则。
6. 论点:召回恢复不会自动提高最终通过数
论据。 统一构建流程后的结果为:
指定证据进入候选列表:21/32 -> 16/32 -> 29/32
新增 15 个问题: 5/15 -> 1/15 -> 6/15
全量 MiniMax: 13/30 -> 18/30
指定位置审计: 29/29论证。 Candidate 从 16/32 恢复到 29/32,证明数据结构修复改善了检索。新增问题只从原来的 5/15 提高到 6/15,表明剩余失败大多发生在 Candidate 之后。
实际运行中出现了三类情况:模型没有继续读取候选;读取多篇论文后只引用其中一篇;第二次提交被截断, 答案只剩一半,旧检查仍然接受。
结论。 检索修复解决了上游召回问题,没有解决模型如何读取、选择和引用候选。检索指标与最终回答 指标需要继续分开报告。
7. 决策三:提交前检查论文级证据覆盖(已下线)
论点。 当答案讨论多篇论文时,每篇被讨论的论文都需要已有原文证据。
论据。 原来的提交检查只确认引用编号存在,并要求至少一条本轮 Evidence。它无法发现答案讨论四篇 论文,却只为一篇论文提供证据。
论证。 论文卡片、标题和摘要元数据只能帮助导航。方法、数值和实验结论需要来自 read_locations 读取的准确原文。检查论文级覆盖可以拦住“找到但没读”和“读了但没引”的答案。
当时在 submit_research_answer 前增加了论文级覆盖检查:
模型提交答案
-> 检查回答类型、格式和引用编号
-> 检查答案中提到的每篇论文是否已有原文证据
-> 完整:结束运行
-> 不完整:返回具体错误,允许同一轮继续处理这层在线检查后来移除;现在覆盖链路由离线 Scorer/Judge 分析。
该检查只使用产品运行时已有信息,不读取测试问题编号、指定证据位置、预期事实或人工标签。
4 个引用问题最明显的测试复跑后得到:
| 问题 | 结果 | 变化 |
|---|---|---|
| GAIA 与 WebArena 对比 | Fail | 两篇论文都有引用,但没引用 WebArena 指定位置 |
| 四类 Agent Benchmark 推荐 | Fail | 四篇论文都有引用,只命中一个指定位置 |
| ReAct 到后续 Agent Evaluation | Pass | 三个指定位置都被找到、读取和引用 |
| Topic Change 到 GitHub Issue Agent | Fail | 不再无引用回答,但没引用指定位置 |
严格评分从 0/4 变成 1/4。论文覆盖改善,指定证据位置选择仍未解决。
决定。 保留论文级证据覆盖检查,但不把它描述为检索质量提升,也不让它读取 Golden Data 答案。
8. 决策四:错误信息也属于 Agent 行为设计
论点。 提交拒绝信息需要明确告诉模型删除无关内容或补充必要证据。
论据。 Topic Change 第一次复跑时,错误信息先写“继续搜索”。模型随后搜索三篇无关论文,并把旧 话题的 GAIA 证据带入新答案。
错误信息改为优先删除与当前问题无关的内容,确有必要时再搜索。再次运行后,模型删除旁支比较,只保留 SWE-bench 和两条正文引用。
论证。 工具描述、拒绝原因和错误信息都会进入模型上下文。模型会把错误文字当作下一步行动条件, 开发日志式的措辞也会改变工具调用。
决定。 提交错误使用可执行、范围明确的反馈。先要求收窄无关内容,再要求新增搜索,避免拒绝规则 推动模型扩大问题范围。
9. 决策五:正确性检查必须同时计算成本
论点。 通过数增加不足以证明提交检查适合默认运行,还要比较模型调用、工具调用、Token 和耗时。
论据。 4 个重点问题合计使用:
模型调用:45
普通工具调用:48
供应商报告 Token:约 608,855
耗时:约 6.2 分钟ReAct 相关问题经历 7 次提交拒绝,最终使用 19 次模型调用、26 次工具调用和约 36.4 万 Token。
论证。 提交检查可以推动模型补证,也会在答案范围过宽时触发更多搜索。严格评分只增加 1 个问题, 每个答案却可能多运行十几轮。成本变化必须与通过数一起评估。
决定。 Eval 记录同时保存模型调用、工具调用、拒绝次数、Token 和耗时。后续优化先减少无效搜索, 再讨论提高调用上限。
10. 工程结果
本轮保留四项做法:
- 测试论文与产品论文共用正式 Parser 和 Reading Model 构建流程;
- 检索排查使用固定查询离线重放;
- 运行时分别记录 Candidate、Read 和 Cited,Hard Pass 在线下计算;
- 提交检查只约束论文级证据覆盖,不读取测试答案。
同时停止三条路线:
- 不用“第一页优先”补偿上游数据缺失;
- 不继续增加自建 Agent 阶段;
- 没有人工审核时,不把指定位置失败直接归因于检索。
当前验证结果为:
Python tests: 76/76
固定测试数据: 30/30
指定位置审计: 29/29
固定查询的候选召回: 29/32
全量 MiniMax 历史参考: 18/30
提交检查重点问题: 1/4,改造前为 0/4向量检索没有进入本轮修复。多数剩余目标证据与查询已有明显词语重合,当前限制集中在模型如何选择、读取 和引用已有候选。
11. 保存的评估数据及用途
EvalRecorder 保存两类原始文件:
<run_id>/events.jsonl
<run_id>/result.json事件包含模型响应、工具调用、候选位置、读取证据、最终引用、错误、耗时和 Token。候选召回、读取率、 引用率、成本和模型对比由离线脚本计算。运行时不保存在线奖励,也不用评分控制回答。
论点。 原始轨迹比单个总分更适合定位回归和积累训练数据。
论据。 同一条轨迹可以重新计算 Candidate、Read、Cited、Hard Pass、成本和错误分布,也能比较模型 版本与常见工具路径。
论证。 保存原始事件后,评分规则变化不需要重新调用模型。经过人工审核的高质量轨迹还可以整理成 监督数据,用于研究本地小模型训练或从强模型 API 蒸馏工具使用方式。
训练前仍需处理隐私、数据授权、错误轨迹和人工标签质量。当前记录提供材料,不直接等同于可用训练集。
12. 证据边界
能够支持的结论。 正式 Reading Model 修复了大部分候选召回;固定查询重放可以区分检索变化和模型 随机性;论文级覆盖检查能减少无引用或漏论文回答。
尚不能支持的结论。 29/32 不能证明最终回答已经解决;18/30 不能代表自然语言准确率;1/4 也不足以证明更严格的提交循环值得承担当前成本。
后续引入向量检索时,仍需分别报告 Candidate、Read、Cited 和最终评分,避免把排序变化解释成完整回答 能力变化。
13. 复现资料
.venv-harness/bin/python -m unittest discover -s harness_py/tests
.venv-harness/bin/python -m harness_py \
--manifest research/golden-data/manifest-expanded.yaml \
validate
.venv-harness/bin/python -m harness_py agent-run \
--product-corpus-map research/golden-data/product-corpus-map.local.yaml \
--case-id transformer_adam_params_001相关资料:
harness_py/ONBOARDING.mdresearch/golden-data/README.mddocs/adr/0011-use-evidence-first-golden-cases-for-harness-eval.mddocs/adr/0012-build-golden-schema-runtime-as-offline-eval-first.mdBest-of-2 Agent 编排实验