Skip to content

Reading Model 与 harness_py 工具

Reading Model 是产品长期保存的论文结构。它回答页面、章节、表格、图片、公式和来源身份怎样被稳定 表达。产品请求进入 harness_py 后,JavaCorpusGatewayReader 通过 Java Corpus API 使用 Qdrant 检索候选、用 MySQL 精确读取;ReadingCorpusTools 继续向 Agents SDK 暴露不变的 Function Tool。 Golden Fixture 才使用内存 GoldenDataset 和 BM25 Adapter。

完整 Reading Model 比 Harness 的模型编排面更丰富,因此词法检索、未来的实验性 Retriever 和 Model Provider 可以独立变化,论文与历史引用仍保留长期身份。

Reading Model 的构成

1. Model Version 与 Readiness

paper_reading_models 保存 model_versionmodel_statusis_current、Parser Identity、Page / Character Count、Failure Reason 与 Diagnostics。

Ready 是显式产品状态。Live Corpus 只选择 Current READING_MODEL_READY,不会根据某个派生文件或 Index Document 是否存在来推断论文能不能读。

2. Physical Page

paper_pages 保存 PDF Page Number、Page Text、Text Status、Text Hash、Character Count、Source Span 与 Parser Provenance。Textless 或 Parser Missing 的页仍然留在论文模型中,产品可以明确知道这一页 存在但当前没有可靠文本。

3. Section

paper_sections 保存 Section Title、Level、Page Range、Reading-order Range、Display Order、Section Text 与 Source Span。章节结构独立于后续的 Chunk 或 Ranker 策略。

4. Canonical Reading Element

paper_reading_elements 是当前检索索引和准确读取的主要内容来源。Java 会按正式 Location 聚合 Reading Element,生成 Qdrant 候选 Point;原始内容继续保存在 MySQL。

维度典型字段或类型
内容类型Heading、Paragraph、List、Table、Image、Figure、Chart、Formula、Footnote、Aside、Code
顺序与结构Page Number、Reading Order、Section Title、Content-list Index
可读内容Caption Text、Body Text、Searchable Text
来源Parser Element、Source Object、BBox、Source Span、Parser Name / Version
结构化信息Structured Payload、Raw Attributes
关系Parent Reading Element、Attachment Role、Association Status
导航Location Ref、Location Type、Location-not-created Reason

body_textcaption_text 保存可读来源,searchable_text 是给 Retriever 使用的 Projection。搜索文本 可以合并 Caption 和 Body,但不会取代原文,也不会成为历史 Citation 的唯一身份。

5. Location

paper_locations 为 Page、Section、Table 与合适的 Figure 建立正式 Navigation Identity。当前一部分 Text 或 Deferred Formula 会使用 reading_element_id 作为 Live Harness 的 Location Fallback。

当前实现先保证 Retained Content 能被准确读取,再逐步提高高层 Location Coverage。没有可靠位置的 Parser Element 会留下明确缺口,不会获得猜测生成的 Location。

6. Visual Asset

paper_visual_assets 保存 Page Screenshot、Table Crop、Figure Crop、Chart Crop 与 Parser Image 的 Availability / Failure、Owner Element、Page、Source Object、BBox、Object Key、Size 与 Checksum。

Live Harness 当前只加载 Availability。Binary Asset 仍由 Java 代码从 MinIO 打开。

Builder 做了哪些建模判断

PaperReadingModelBuilder 会处理 Parser 语义到产品语义的转换:

  • 保留 Physical Page 与 Reading Order;
  • 将 Parser Type 映射成 Product Type,同时保留 Raw Attribute;
  • 把 Table Caption Fragment 和 Figure Panel Label 关联到 Parent Element;
  • 区分 Full Caption 与 Panel-only Caption;
  • 记录 Parent、Attachment Role 与 Association Status;
  • 对 Ambiguous / Unattached Relationship 明确标记,不猜 Ownership;
  • 建立 Page、Section、Table 和适合的 Figure Location;
  • 保存 BBox、Source Span、Parser Provenance 与 Structured Payload;
  • 输出 Retention、Association、Location 与 Visual Gap Diagnostics。

这层模型把 Evidence 从某一次 Chunk Policy 中解耦出来。Parser 可以升级,Retriever 可以换,已经保存 的论文结构和来源身份仍然有稳定落点。

完整模型与当前产品路径的差异

能力完整 Reading Model当前产品怎样使用
Model Metadata / ReadinessMySQL 长期保存Java Corpus API 返回本轮需要的 Metadata
Physical PageMySQL 长期保存参与 Page Location 与准确读取,不整表复制到 Python
SectionMySQL 长期保存作为候选和原文的章节信息,不整表复制到 Python
Typed Reading ElementMySQL 长期保存聚合成 Qdrant Point,读取时从 MySQL 返回准确内容
Formal LocationMySQL 长期保存作为 Qdrant 候选、权限校验和 Evidence 的稳定身份
Visual AssetMinIO 与 MySQL 长期保存准确读取时返回 Availability,二进制仍由 Java 打开
Sparse Projection可重建派生数据Qdrant 保存 BM25 Sparse Vector 与最小路由字段

Python 维护 Agent 能看到哪些 Paper、Location 和 Evidence,不持有整份论文索引。Qdrant 只保存可重建 候选,MySQL Reading Model 仍是准确内容来源。

harness_py 怎样读取 Reading Model

harness_py 工具与状态变化图

build_agent_tools 会把 ResearchSkillRegistryReadingCorpusTools.definitions()submit_research_answer 组装成 SDK FunctionTool。每个工具只推进一种状态,下一步能做什么由 ResearchRunContextReadingCorpusTools 中已经记录的集合决定。

Paper、Location、Evidence 是三种不同权限

Java 先把 Dataset 限定在当前用户可访问的 Paper ID 内。进入 Python 后,模型仍要通过 Candidate Search 或唯一身份解析看到某篇论文,才能检索它的位置;Location 必须先被检索结果公开,才能被准确读取; 只有读取结果会得到 Evidence ID。

text
Java-authorized Dataset
-> disclosed Paper
-> disclosed Location
-> exact Read
-> Evidence Ledger
-> accepted Submission

Candidate Preview 只负责导航。把 Preview 和 Evidence 分开,可以阻止模型看到一段摘要后就把它当成 论文方法、结果或性能的引用依据。

状态保存在 Context,不交给模型自报

每个 ResearchRunContext 都创建独立的 ReadingCorpusTools,其中维护:

  • authorized_paper_ids:在 Java Scope 内已经向模型公开、允许继续阅读的 Paper;
  • disclosed_location_refsfind_reading_locations 已经返回过的 Location;
  • observations_by_evidence_idread_locations 创建的 Evidence Ledger;
  • trace:模型调用过什么工具,以及模型实际看到了什么结果。

模型无法通过参数声明“我已经看过这个位置”。每次 Tool Call 都由业务代码检查集合成员关系,并在 调用前后保存状态快照。

工具结果有 Internal 与 Model-visible 两个版本

Corpus Tool 先产生 Internal Result,再经过 model_facing_payload 过滤后返回模型。Golden Anchor 等 评估字段不会出现在模型可见结果里。Eval Capture 可以同时保存两个版本,离线分析因而知道系统内部 发生了什么,也能复原模型当时实际获得了哪些信息。

工具错误是可修复反馈

无效 JSON、未公开 Paper、未公开 Location、未知 Evidence 和 Coverage 缺口都会返回结构化错误。同一个 Runner 会继续执行,模型可以改参数、补搜索、补读取,或删掉没有证据的声明。非预期业务异常才会上升 为技术失败。

最终答案也通过 Function Tool 提交

模型不能用一段自由文本直接结束研究。Model Settings 保持 tool_choice=required,供应商若返回纯文本, Model Adapter 会把它归一化成内部 Continue Tool,提醒模型继续调用 submit_research_answer

最终提交必须独占一次 Model Step。tools_to_final_output 只接受 accepted=true 的 Draft,其他工具即使 成功也不会结束 Runner。

模型可调用的工具

Tool设计目的前置状态返回给模型状态变化可否直接引用
get_research_skill按需加载研究范式,保持一个连续 Runner Loop方法步骤、Evidence Standard、Answer Guidance记录 skills_used
search_paper_candidates主题发现、Corpus Inventory、Metadata FilterJava-authorized DatasetPaper Cards、数量、分页状态公开返回的 PaperMetadata 可回答;论文内容不可引用
find_papers_by_identity用结构化线索消歧特定论文Java-authorized DatasetResolved / Ambiguous / Not Found只有唯一 Match 公开 Paper
find_reading_locations在已公开论文中找下一步阅读位置Paper 已公开location_ref、Section、Page、Element Type、Preview公开返回的 Location
read_locations读取准确来源并建立 Evidence 身份Location 已公开Exact Span、Provenance、Visual Availability、Evidence ID写入 Evidence Ledger是,唯一入口
submit_research_answer提交用户可见结果并请求结束 Run已知 Evidence 或明确的非完整 OutcomeAccepted / Validation ErrorAccepted 后形成 Final Output只能引用 Known Evidence

每个工具为什么存在

get_research_skill

Harness 当前提供 22 种研究范式,包括精确事实提取、方法复现、深度比较、研究谱系、多跳推理、知识 边界、矛盾处理、结构化信息读取和复杂约束组合。

Skill 返回 when_to_useinstructionsevidence_standardanswer_guidance。它只影响研究策略, 无权公开 Paper、Location 或 Evidence。这样可以给模型方法指导,又不会重新引入固定 Stage Runtime。

search_paper_candidates

这个工具同时服务两类问题。

  • 对 Corpus 数量、论文列表、作者、年份、Venue 和 Identifier 问题,Paper Card 是权威 Metadata 来源;
  • 对论文内容问题,它负责发现候选,并把返回的 Paper 加入可继续阅读的集合。

它支持 Query、Paper ID、Author、Venue、Year Range、Offset 和 Limit。空 Query 配合足够大的 Limit 可以 枚举当前固定 Corpus。返回 Card 仍不能支撑 Method、Finding、Performance 或 Limitation Claim。

find_papers_by_identity

这个工具处理“用户指的是哪一篇”这类身份问题,接受 Title、Filename、DOI、arXiv ID、Author、Year 和 Paper ID。只有一个 Match 时才公开论文;多个 Match 返回 ambiguous,不会任意挑一篇继续研究。

它不承担主题搜索和推荐。把 Identity Resolution 从 Topical Discovery 中拆出来,是为了让歧义能够 明确暴露给 Agent 和用户。

find_reading_locations

这个工具只接受已经公开的 Paper ID。它可以使用 query_textsection_query、Element Type Hint、 Page Range 和 top_k。产品请求会交给 JavaCorpusGatewayReader,再调用 Java Corpus API。

当前产品排序经过:

  • Java 用固定 Analyzer 和 Term ID 生成 BM25 Sparse Query;
  • Qdrant 在 lexical_bm25_v1 上执行一次全局检索;
  • Element Type Hint 只用于确定性的同分排序;
  • Java 在同一候选池中补足论文与 canonical Lead Coverage;
  • Current Reading Model 与 Index Contract 校验后,从 MySQL 补全 Preview。

产品 Qdrant 失败时会明确报错,不会静默切回内存检索。没有 JavaCorpusGatewayReader 的 Golden Fixture 和离线工具仍可使用内存 BM25 Adapter,两条路径不会在生产请求中混用。

返回值包含不可引用 Preview 与 location_ref。所有返回 Location 会进入 disclosed_location_refs,为下一步 Exact Read 建立前置状态。

read_locations

这个工具只读取已经公开的 Location Ref。每个读取结果保留:

  • Paper、Version、Section、Page 与 Element Type;
  • 准确 span_text
  • BBox、Parser Name / Version 与 Source Kind;
  • Table / Figure / Formula Identity;
  • Page、PDF、Table、Figure Screenshot Availability。

Evidence ID 由 Paper、Location、Element Type 和 Page 稳定生成。读取结果进入 observations_by_evidence_id,后面的 Citation Validator 只认可这个 Ledger 或上一轮已经接受的 Evidence。

submit_research_answer

提交结构包括 outcomemarkdown 和可选 fields。Outcome 只有四种:answeredneeds_clarificationpartialabstained

提交会依次检查:

  1. Outcome、Markdown 与 Fields 结构;
  2. 是否手写数字引用,或引用未知 / 不可引用的 Evidence ID;
  3. 本轮已经读过 Paper Content 时,Answered / Partial 是否实际引用 Evidence;
  4. submit_research_answer 是否独占最终 Tool Step。

在线提交不再做论文级覆盖推断。Candidate、Read、Cited 与逐 Block 语义支撑留给离线 Scorer/Judge。

一个多论文比较会怎样走工具

假设用户要求比较两篇已选论文的方法和结果,常见轨迹会是:

text
search_paper_candidates
-> 公开两篇 Paper
find_reading_locations(paper A, method query)
find_reading_locations(paper B, method query)
read_locations(method locations)
find_reading_locations(paper A + B, result query)
read_locations(result locations)
submit_research_answer
-> Accepted,或返回格式 / 引用错误继续同一个 Runner

模型可以改变 Query、重复搜索或先读某一篇。协议不会规定固定顺序,但会保证每个 Evidence 都经过 Paper Disclosure、Location Disclosure 和 Exact Read。

跨回合记忆怎样收敛

SDK Session 只在当前 Run 内合并文本历史。长期 Conversation State 由 Java 保存,下一轮 Python 收到 的是精简 History 与 Previous Evidence Card。

本轮只有进入已接受答案的 Evidence 会被提升为下一轮 Research Memory。搜索过的 Paper、看过的 Preview 和未引用 Evidence 不会自动回灌。这个规则让 Follow-up 可以继续引用已有证据,也避免一次 探索把后续会话永久污染。

模型和代码各自决定什么

模型决定:

  • 是否需要 Clarification;
  • 用什么 Query,搜索几次;
  • 阅读哪些 Location;
  • 是否调用一个或多个 Research Skill;
  • 怎样组织回答,何时 Partial 或 Abstain。

代码决定:

  • 当前 Dataset 包含哪些 Paper;
  • 哪些 Paper 和 Location 已经公开;
  • 哪次 Read 能创建 Evidence;
  • 哪些 Evidence ID 可以引用;
  • 多论文答案是否完成 Candidate / Read / Cited / Substantive Coverage;
  • 一个 Draft 是否有资格结束 Run。

当前实现把研究策略交给模型,证据资格和产品权限继续由代码判断。

当前词法检索的边界

Live Harness 当前只使用 Sparse-only Qdrant BM25。69 条固定查询和 48 个指定证据上,产品 Qdrant 命中 48/48,完整覆盖 24/24 Case,MRR 为 0.48019;同一批查询的内存 BM25 对照为 35/4815/240.37838

76 篇广查询的本地 p50 为 132.1 ms,也省掉了每个 Python Worker 的全文加载和索引构建。剩余边界 主要是未见论文上的泛化、模型查询质量、固定候选预算和 Agent 证据选择,而不是 Dense/Sparse 融合。 完整 MiniMax 运行中有 47/48 份所需证据进入 Candidate,模型只读取 29/48

阅读 Sparse Qdrant 切换与 MiniMax 证据缺口

继续阅读

PaperLoom · Evidence-bounded Agentic RAG