Files
RAG/docs/01-data-and-evaluation.md
YoVinchen 75592af33a
Some checks failed
verify / verify (push) Has been cancelled
Isolate cloud model access before enabling product RAG workflows
The API and ingestion tools now use a fixed internal model gateway while
governed profiles, embedding cache assignments, traceable citations, and
stable API errors establish the boundaries required by later workflows.

Constraint: The current Alibaba Cloud workspace rejects all three live model calls with authentication failures
Rejected: Give the API or seed tools the Bailian key and direct egress | combines database access, cloud credentials, and public network access
Rejected: Mix offline and Bailian vectors in one demo namespace | makes profile activation and retrieval ambiguous
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep Bailian credentials and egress exclusive to model-gateway and create a new immutable profile hash for any embedding identity change
Tested: make verify; 121 backend tests; 14 frontend tests; fresh and populated Alembic upgrade-downgrade-upgrade; two idempotent offline seeds; Docker health and HTTP retrieval; isolated provider smoke
Not-tested: Successful live Bailian responses because the supplied workspace credential currently fails authentication
2026-07-13 04:09:06 +08:00

35 KiB
Raw Blame History

数据构建、向量入库与系统评测设计

项目 内容
文档版本 v1.0-design
更新日期 2026-07-11
默认切片 目标 512 Token最大 800重叠 64
默认向量 text-embedding-v41024 维Cosine
正式验证集 建议 300 题(构建/开发/盲测各 100500 题为扩展目标

1. 数据治理是入库前置条件

1.1 语料来源优先级

优先级 来源 适合内容 使用边界
A 学校、实验室、合作单位自有报告 勘查报告、钻孔描述、化验表 取得书面授权,确认不涉密且允许发送到云模型
A 明确 CC BY、CC0 等许可的数据 地层、地球化学、矿床描述 保存许可、DOI、版本和引用方式
A USGS 自制报告与数据 英文矿床模型、调查数据 多数自制内容属美国公共领域,但第三方图件例外,逐项检查版权说明
B 中国地质调查局“地质云”等公开服务 区域地质、资源环境产品 在线可看不等于允许批量下载、衍生入库或再分发,检查每项条款
B 国家科学数据中心 各类专题数据集 每个数据集许可独立,不用平台整体印象代替许可核验
C 开放获取论文 术语、矿床成因、方法综述 仅明确开放许可时保存全文,否则只保存合法题录/摘要
禁止默认纳入 商业数据库、付费标准、教材、来源不明扫描件 必须取得明确授权,不能因“下载得到”而入库

“公开访问”“研究可用”“允许批量下载”“允许建立衍生知识库”“允许公开发布”是五种不同授权。矿产地、钻孔、精确坐标和大比例尺图件还可能涉及受限地理信息或商业秘密。状态不明确时默认拒绝,而不是“先入库以后再处理”。

1.2 文档硬门禁

任何一个条件不满足,文档保持 QUARANTINED_LOCAL_REVIEW。授权人员必须在隔离、无外网、无模型调用的环境中完成完整解析/OCR、规范化、结构化切分和字段级脱敏生成待出域 bundle完成本地复核后进入 LOCAL_PARSED_PENDING_CLOUD_REVIEW。只有审核人批准这一个确切 bundle 后才能进入 CLOUD_APPROVED;在此之前严禁向量化、百炼调用、对普通用户展示或激活检索:

  • 来源 URL/交付人、权利人、许可或授权证据可追踪;
  • 保密/涉密等级已确认;
  • 允许本项目处理和建立索引;
  • 允许把选定字段发送到外部模型服务;
  • 页码、报告编号或版本足以支持引用;
  • 原始 SHA-256 与审核时一致;
  • 是否允许随论文、演示或仓库发布衍生样例已单独标记。

原始 raw_text 永久保留在许可允许的受控边界内;另行生成每个待发送块的 cloud_text。精确坐标、单位名称或项目编号需要脱敏时,只修改 cloud_text,不得破坏原件。审批对象必须绑定 raw_sha256 + parser_profile_hash + ocr_profile_hash + normalization_profile_hash + chunk_profile_hash + cloud_policy_id + outbound_manifest_sha256manifest 对所有可能发送的 cloud_text、允许附带的标题/章节元数据、顺序和各自哈希做承诺。上述任一输入、处理器、规则、文本或元数据变化,数据库约束自动撤销原审批并回到 LOCAL_PARSED_PENDING_CLOUD_REVIEW。Embedding、Rerank 和 LLM 只能读取与当前已批准 manifest 完全一致的 cloud_textWorker 在发请求前再次核对哈希。

1.3 文档清单格式

documents.jsonl 示例仅使用虚构数据:

{
  "doc_id": "doc_demo_001",
  "title": "某地区铜矿地质特征与找矿标志(演示)",
  "authors": ["示例作者"],
  "publisher": "示例机构",
  "report_no": "DEMO-2026-001",
  "doi": null,
  "source_url": "https://example.invalid/document",
  "retrieved_at": "2026-07-11",
  "published_at": "2026-01-01",
  "source_version": "v1",
  "raw_sha256": "<sha256>",
  "license_id": "INTERNAL-DEMO",
  "license_url": null,
  "rights_holder": "示例机构",
  "permission_evidence": "<private-evidence-reference>",
  "redistribution_allowed": false,
  "confidentiality": "internal",
  "security_review": "passed",
  "review_state": "CLOUD_APPROVED",
  "cloud_policy_id": "cloud-policy-v1",
  "cloud_text_sha256": "<sha256>",
  "outbound_manifest_sha256": "<sha256>",
  "parser_profile_hash": "<sha256>",
  "ocr_profile_hash": "<sha256-or-disabled>",
  "normalization_profile_hash": "<sha256>",
  "chunk_profile_hash": "<sha256>",
  "cloud_approved_at": "2026-07-11T00:00:00Z",
  "cloud_approved_by": "<reviewer-id>",
  "regions": ["示例地区"],
  "mineral_types": ["铜"],
  "deposit_types": ["斑岩型"],
  "geological_ages": ["侏罗纪"],
  "language": "zh-CN"
}

真实授权文件放在受控文档系统,不提交到 Git仓库只保存字段定义和脱敏后的许可类型。

2. 原始资料到切片的数据流水线

原始文件只读归档
  -> MIME/加密/大小检查
  -> 隔离环境完整解析/OCR/页码章节恢复/规范化/切分/脱敏
  -> 人工复核低置信页与最终待出域内容
  -> 生成 outbound manifest
  -> LOCAL_PARSED_PENDING_CLOUD_REVIEW
  -> CLOUD_APPROVED / REJECTED绑定 manifest
  -> 向量化
  -> 数据库校验
  -> 文档版本激活

每一层都保存:输入哈希、处理器名和版本、配置哈希、输出哈希、开始/结束时间、错误码。原始文件不得被规范化结果覆盖。

2.1 数字 PDF

建议用 PyMuPDF 提取页级文本块和坐标,用 pdfplumber 辅助表格:

  • 保存 page_nobbox、阅读顺序、字体/字号等可用信息;
  • 恢复多栏阅读顺序,不能直接按底层对象顺序拼接;
  • 跨页重复出现于多数页面的页眉/页脚作为噪声候选,但删除前保留规则和样例;
  • 不删除章节标题、图表编号、地层代号、钻孔号、元素符号、坐标、正负号和单位;
  • 页码同时保存 PDF 物理页和报告印刷页,回答引用统一展示可理解的页码;
  • 解析失败页单独标记,不能因整份文档大部分成功就静默跳过。

2.2 扫描 PDF 与 OCR

推荐流程:

  1. 页面以 300 DPI 渲染;
  2. 自动旋转、倾斜矫正、去噪和对比度增强;
  3. PaddleOCR/PP-Structure 输出文本、坐标和置信度;
  4. 地质词典用于提出纠错候选,不直接覆盖原始 OCR
  5. 同时保存 raw_textnormalized_text、置信度和修订人;
  6. 数值密集页、低置信页和表格页进入人工复核队列。

金标准页建议目标:

指标 目标
OCR 字符错误率 CER ≤ 3%
地质专业术语准确率 ≥ 95%
数字、符号和单位准确率 ≥ 98%
入库切片可追溯页码 100%

平均置信度低于 0.85、关键数值置信度低、阅读顺序异常或单位缺失时,不允许自动激活。

2.3 表格

表格至少保存四种表示:

  1. 原始页截图或坐标引用;
  2. 结构化 JSON
  3. 可展示 Markdown
  4. 面向检索的逐行语义文本。

虚构示例:

{
  "table_id": "table_demo_p34_02",
  "title": "ZK1203 钻孔样品分析结果(演示)",
  "page_no": 34,
  "columns": ["样品号", "起始深度_m", "终止深度_m", "Cu_pct"],
  "rows": [
    {
      "样品号": "H12",
      "起始深度_m": 125.4,
      "终止深度_m": 127.2,
      "Cu_pct": 0.86
    }
  ],
  "unit_notes": "Cu 品位单位为 %",
  "source_bbox": [88, 201, 512, 690]
}

对应检索文本:

在演示表“ZK1203 钻孔样品分析结果”中,样品 H12 位于 125.4127.2 m铜品位为 0.86%。

表格按 1020 行切片,每个切片重复表名、列名、单位和页码。跨页表、续表、合并单元格必须抽检。目标为行列对齐 ≥ 97%,数值和单位 ≥ 99%。

2.4 图件与地质图

纯文本模型可处理图名、图注、图例 OCR、邻近解释文字和人工复核摘要但不能因此宣称理解断层、矿体或蚀变带在整幅图中的几何关系。

第一版把以下问题放入挑战集:

  • 某断层位于矿体哪一侧;
  • 某地层与侵入体在图上的接触关系;
  • 剖面图中的空间延伸;
  • 只存在于图形、没有文字描述的测量值。

后续如引入多模态向量和重排,需要新增数据格式、模型 ADR 和独立指标。

3. 规范化、切分和去重

3.1 规范化规则

允许:

  • Unicode NFKC、全角/半角统一;
  • 连续空白压缩、OCR 断行和错误连字符修复;
  • 可逆的单位别名映射;
  • 页眉页脚规则化删除;
  • 在单独字段中保存术语同义词。

禁止:

  • 全部英文转小写而破坏元素符号;
  • 从受控原件删除数字、坐标、钻孔号、地层代号;云处理所需脱敏只作用于单独的 cloud_text
  • 无原文依据扩写缩写;
  • 把不同年代或不同报告的结论合并成“统一事实”;
  • 用 LLM 改写后的正文替代原文。

3.2 基线切分

参数 初始值
目标长度 约 512 Token
最小长度 120 Token
最大长度 800 Token
相邻重叠 64 Token
章节边界 不跨一级/二级标题
表格 1020 行,重复表头和单位

优先级为“章节 > 自然段 > 句子 > 长度兜底”。定义、枚举、完整成矿阶段和结论尽量保持在同一切片。若没有准确的百炼 tokenizer使用保守估算并让切片远小于 8192 Token而不是依赖服务端截断。

display_text = 权限允许时贴近原文,用于展示和引用
cloud_text = 经字段级策略批准、可发送到云端的文本
embedding_text = [允许发送的标题/地区/矿种/章节路径] + cloud_text

是否添加元数据前缀由消融实验决定,不能把经验判断写成既定收益。

3.3 去重和版本

  • 精确重复:规范化文本 SHA-256 相同;
  • 文档近重复MinHash/Jaccard 参考阈值 0.92,进入人工确认;
  • 切片近重复:参考阈值 0.95,保留主切片和来源别名;
  • 修订版、扫描版、OCR 版归入同一 duplicate_family_id
  • 有冲突的历史结论不去重,标记 supersedes/conflicts_with
  • 同一重复族必须进入同一数据划分,避免评测泄漏。

4. Ground-truth 验证集生成

4.1 规模与题型

阶段 文档 切片 问题
管线冒烟 510 100500 2030
试运行 50 2,00010,000 100
正式毕设 200500 10,00050,000 300500 为扩展)

推荐正式最少 300 题,构建/开发/盲测各 100有足够标注人力时扩展至 500 题。题型比例:

类型 比例
直接事实、术语定义 20%
数值、钻孔、表格 20%
地层—构造—矿化关系 15%
多证据、多跳推理 15%
区域或矿床比较 10%
找矿方法与工作流程 10%
无答案、歧义或冲突 10%

每题标注模态、矿种、地区、难度、单跳/多跳、是否可回答和证据组,保证结果可以分层分析。

4.2 人工 + 半自动流程

  1. 先按文档族完成数据划分。
  2. 在每个 split 内按来源、矿种、题型和模态分层抽样。
  3. LLM 只根据给定切片生成候选问题、短答案、证据原句和页码。
  4. 自动检查证据是否真实存在、数字/单位是否一致、页码是否有效。
  5. 标注员 A 修改或拒绝候选。
  6. 标注员 B 独立验证答案、证据和可回答性。
  7. 分歧交由地质专业教师或第三名标注员裁决。
  8. 将所有参评的 Dense、词法、Hybrid 和 Rerank 系统候选取 union 建池,记录系统版本与 pooling depth初始建议每系统 Top 20。
  9. 人工给池中候选 03 级相关性;新系统若在计分深度内返回未判定候选,必须补标,不能默认当作 0。
  10. 冻结测试集、源证据锚点、corpus manifest 和整个数据集哈希。

大模型不能同时成为唯一出题者、唯一裁判和最终评分者。若团队资源有限,至少保证正式测试集双人审核,且 LLM 评分抽取 20% 以上由人复核。

4.3 评测问题格式

{
  "qid": "q_test_0042",
  "query": "演示钻孔 ZK1203 在 125.4 至 127.2 米的铜品位是多少?",
  "answerable": true,
  "reference_answer": "0.86%",
  "answer_aliases": ["0.86 %"],
  "numeric_tolerance": {"absolute": 0.001, "unit": "%"},
  "question_type": "table_numeric",
  "difficulty": "medium",
  "modality": "table",
  "gold_evidence_groups": [
    {
      "required": true,
      "doc_id": "doc_demo_001",
      "document_version_id": "docver_demo_001",
      "page_no": 34,
      "char_start": 1280,
      "char_end": 1348,
      "bbox": [88, 201, 512, 238],
      "evidence_sha256": "<sha256>"
    }
  ],
  "split": "test",
  "security_classification": "internal",
  "redistribution_allowed": false,
  "created_by": "llm_assisted",
  "review_status": "double_reviewed"
}

Gold 主锚点必须是跨切分配置稳定的源位置,不是 chunk_id。每次实验按 anchor_resolver_versiondoc/version/page/char offsets/bbox/evidence hash 映射到本次切片并生成 run-specific qrels跨边界或 OCR 变化的歧义映射进入人工复核。这样 256/512/800 Token 等消融才使用同一事实真值。evidence_text 只可存在于有权限的内部 benchmark公开版本只保留哈希、允许公开的短引文或完全脱敏锚点。

Pool 中所有等级 1/2/3 的人工 judgment 也必须保存候选的源位置锚点、证据哈希、等级和判定理由,不能只有 Gold 使用稳定锚点。等级 0 保存候选来源锚点与“不相关/实体冲突”等理由。重新切片时解析全部 anchored judgments无法可靠映射的候选重新建池和补标否则该 run 不计算 nDCG。

4.4 无答案与困难负例

无答案题应覆盖:

  • 语料完全没有的矿种或地区;
  • 将真实问题的地区、矿床或年份替换形成的错误前提;
  • 同矿种不同矿区、同地区不同矿种;
  • 相邻但不能回答问题的切片;
  • 新旧资料冲突且问题未限定时间;
  • 缺少关键条件的歧义问题。

判定“无答案”前至少用关键词、向量和人工三种方式确认没有支持证据。随机无关句不够难,不能代表真实拒答能力。

4.5 构建、开发与测试隔离

RAG 不训练基础模型,这里的 train 更准确地说是“构建/校准集”:

  • corpus 按文档族做 60/20/20而不是按切片随机划分问题集建议构建/开发/盲测各 100 题;
  • 相同 DOI、报告号、扫描版、修订版和近重复文档必须在同一 split
  • 构建集用于开发解析器、词典、Prompt 和初始参数;
  • 开发集用于选择维度、切片、Top K、重排数量和拒答阈值
  • 测试问题和答案在调参期间不可查看;
  • Gold 问答、参考答案、qrels 绝不能写进 RAG 知识库;
  • 主指标始终在冻结的全量 train + dev + test 文档索引上检索,并把 corpus_manifest_sha256 写入 run只检索 test 文档子库仅作诊断,不能与主指标混报;
  • 盲测问题、答案和标签由独立保管人或受控凭据管理,开发者在参数冻结前不可访问;
  • 同一次论文结论只运行一次冻结盲测。若盲测结果被用于修改参数,该测试集立即退役并转为开发数据,最终结论必须使用新的未见盲测集;更换 run_id 不能恢复盲测有效性。

标注一致性目标:相关/不相关二分类 Cohen's kappa ≥ 0.75,证据定位 F1 ≥ 0.85。数值、冲突和多跳问题全部双人审核。

4.6 评测数据的安全边界

问题、参考答案和证据锚点可能复制或推断受限原文,因此评测项继承源文档的许可、保密级别和销毁策略:

  • 内部完整 benchmark 使用独立存储和独立访问凭据,不进入 Git
  • 公开 benchmark 只包含获得再分发许可或充分脱敏的内容;
  • 通用知识库导入器以 allowlist 指定语料目录,自动测试保证 eval/runs/ 和私有标注目录永不被扫描入库;
  • 导出论文附件前再次执行版权、坐标和商业秘密检查;
  • 评测备份、保留和删除与源资料策略一致。

5. 向量化 API 与写库测试

5.1 基线配置

model: text-embedding-v4
dimension: 1024
encoding_format: float
distance: cosine
synchronous_batch_items: 8
chunk_target_tokens: 512
chunk_max_tokens: 800

百炼官方说明 text-embedding-v4 支持 642048 维、单次最多 10 条、单条最多 8192 Token北京单请求总计最多 33000 Token并推荐 1024 维作为通用平衡点,见Embedding 规格。同步接口适合首版OpenAI Batch 适合数十万切片以上的离线任务,可降低调用价格,但需要提交、轮询、下载和失败行重试,因此不进入最小运行链路。

生产表固定 vector(1024)。512/1536 维消融每个维度使用独立 schema/table/HNSW index或一次性独立评测数据库通过相同不可变证据锚点生成各自 qrels不同维度绝不共用同一普通 HNSW 索引。

5.2 三层验证数据

第一层是 API 契约样例,验证字段、下标和维度;第二层是 100 组语义三元组;第三层是正式 qrels 验证集。

语义三元组格式:

{
  "id": "triplet_demo_001",
  "query": "斑岩铜矿常见哪些蚀变找矿标志?",
  "positive": "斑岩铜矿常见钾化、绢英岩化和青磐岩化分带。",
  "hard_negative": "矽卡岩矿床常见于侵入岩与碳酸盐岩接触带。",
  "tags": ["synonym", "deposit_type", "hard_negative"]
}

三元组至少覆盖:

  • 地质术语同义表达;
  • 同矿种不同地区;
  • 同地区不同矿种;
  • 数值和单位差异;
  • 地层代号、钻孔号、图幅号;
  • 中文简称与全称;
  • OCR 轻微错误;
  • 标题前缀有无。

建议门槛:sim(query, positive) > sim(query, hard_negative) ≥ 90%;原文式查询目标切片 Top 1合理改写 Top 3。不要使用未校准的固定余弦分数判断所有问题。

5.3 API 契约断言

用已轮换的新 Key、从 Secret 注入后执行:

  1. 空字符串在客户端拒绝。
  2. 批次数量超过 10 在客户端拒绝。
  3. 单条超长文本由切分器拒绝或重新切分,不依赖服务静默截断。
  4. 批次估算总 Token 超过 33000 时客户端重新分批。
  5. HTTP 200 且返回模型可识别。
  6. len(data) == len(input)
  7. data[].index 恢复原输入顺序。
  8. 每个向量长度严格为 1024。
  9. 每个元素为有限浮点数,无 NaN/Inf。
  10. L2 norm 大于 0。
  11. 同一文本重复请求的余弦相似度接近 1。
  12. 保存 request ID、Token 和耗时,不保存鉴权头。
  13. 401/403/404 不自动重试429/5xx 有上限退避。

5.4 入库算法

外部请求和数据库事务分离:

解析并持久化 chunks(status=PENDING)
  -> 选取未向量化批次并建立幂等键
  -> 调用 Embedding事务外
  -> 验证返回数量、下标、维度和数值
  -> 短事务批量 UPDATE/UPSERT embedding
  -> 提交检查点
  -> 全部完成后执行文档级一致性校验
  -> 单事务更新 documents.active_version_id 和 searchable chunks 投影

Embedding profile 与缓存键分离:

embedding_profile_hash = SHA256(
  provider + endpoint_region + endpoint_identity_hash + api_mode + requested_model
  + resolved_model_revision_or_cache_epoch
  + dimension + output_type + text_type + instruct_hash
  + normalization_version
)

embedding_cache_key = SHA256(
  embedding_text_sha256 + embedding_profile_hash
)

chunk_embedding_assignment = UNIQUE(chunk_id, embedding_profile_hash)

相同文本可以安全复用向量缓存,但每个 chunk 都必须建立独立 assignment不能用缓存键替代任务/行唯一键。模型别名无法解析到稳定 revision 时,每次冻结实验显式设置 cache_epoch,并把它纳入不可变的 embedding_profile_hashepoch 变化必须创建新 profile禁止原地修改 profile 后继续复用旧缓存。激活前再次核对当前 embedding_text_sha256、完整 profile 与 assignment任何一项变化都生成新索引版本。

endpoint_identity_hash 由规范化后的工作空间/部署端点身份计算,仅保存哈希而不在实验导出中暴露真实工作空间。这样同地域、同模型别名但不同 MaaS 工作空间的向量不会错误共用缓存。

5.5 数据库完整性查询(示意)

-- 1. 待激活且当前未删除版本中必须没有空向量
SELECT count(*) AS missing_vectors
FROM chunks
WHERE document_version_id = :version_id
  AND approval_status = 'APPROVED'
  AND deleted_at IS NULL
  AND (
    embedding IS NULL
    OR index_status <> 'READY'
    OR embedded_text_sha256 <> embedding_text_sha256
    OR embedding_profile_hash <> :expected_profile_hash
  );

-- 2. 所有向量维度必须一致
SELECT vector_dims(embedding) AS dims, count(*)
FROM chunks
WHERE document_version_id = :version_id
  AND approval_status = 'APPROVED'
  AND deleted_at IS NULL
GROUP BY vector_dims(embedding);

-- 3. 预期切片数、实际向量数应相等
SELECT
  count(*) AS chunk_count,
  count(embedding) AS vector_count
FROM chunks
WHERE document_version_id = :version_id
  AND approval_status = 'APPROVED'
  AND deleted_at IS NULL;

-- 4. Cosine 检索
SELECT id, document_version_id,
       1 - (embedding <=> :query_vector) AS cosine_similarity
FROM chunks
WHERE searchable = true
  AND deleted_at IS NULL
  AND knowledge_base_id = ANY(:allowed_kb_ids)
  AND access_scope_id = ANY(:allowed_scope_ids)
ORDER BY embedding <=> :query_vector
LIMIT 50;

documents.active_version_id 是唯一权威激活状态;chunks.searchable 只是为了 filtered HNSW 的事务性派生投影。激活事务先验证新版本全部 READY/哈希/profile 一致,再将同文档旧切片设为不可检索、新版本切片设为可检索,并更新 documents.active_version_id 后一次提交。约束触发器和 reconciliation 检查保证每份文档只有一个 active version且所有 searchable chunk 都属于该版本。权限过滤在候选生成时生效,而不是检索后才删除未授权结果。

5.6 写库验收清单

  • approved chunks == vector rows
  • chunk_id 唯一,重复任务行数不增长;
  • 文本未变时不产生新模型费用;
  • 文本改变时旧版本退出检索,新版本完整激活;
  • documents.active_version_id、searchable 投影、当前文本哈希和 embedding profile 完全一致;
  • 删除文档后立即无法检索,后台完成物理清理;
  • 中断后从检查点恢复,不重复已提交批次;
  • Docker 重启后数据库和文件仍存在;
  • 备份恢复后行数、哈希和随机抽样向量一致;
  • 每个向量可回溯模型、维度、文本哈希和请求 ID。

5.7 HNSW 质量测试

首个 schema 版本即建立 HNSW在专用评测事务中关闭 index/bitmap scan并使用完全相同的知识库和 access-scope 过滤得到 exact 真值。对至少 200 个查询比较 ANN Top 10 与 exact Top 10

ANN Recall@10 = |ANN Top10 ∩ Exact Top10| / 10

Exact 基线在隔离连接中使用 SET LOCAL enable_indexscan = offSET LOCAL enable_bitmapscan = off,查询仍保留相同的 allowed_kb_ids/allowed_scope_ids;不能拿无权限过滤的全库 exact 结果与过滤后的 ANN 比较。

建议目标 ≥ 0.98,同时记录索引构建时间、索引大小、查询 p50/p95、ef_search、iterative scan 和 over-fetch。数据很小时仍保留 exact 指标,不把 HNSW 的存在当作质量结论。

6. Rerank 与端到端验证

6.1 Rerank 契约

基线Dense Top 50 -> qwen3-rerank 保存 Top 10 供 MRR/nDCG@10 评测 -> 前 8 条进入生成上下文。

断言:

  • 请求文档数和总 Token 未超限;
  • 总 Token 按 Query Tokens × Document 数量 + Document Tokens 总和 计算,断言 Query 被按候选数重复计入;
  • 候选在本地保留,响应 index 必须映射到正确候选;
  • results 数量不超过 top_n
  • 分数为有限数值且结果按降序;
  • 记录是否发生客户端裁剪;
  • 用同一 qrels 比较重排前后的 MRR/nDCG
  • 初召回没有 Gold 时,错误归为 RETRIEVAL_MISS,不能归因给 Rerank。

6.2 生成验证

端到端结果保存:

{
  "qid": "q_test_0042",
  "retrieved_chunk_ids": ["..."],
  "vector_scores": [0.0],
  "reranked_chunk_ids": ["..."],
  "rerank_scores": [0.0],
  "answer": "...",
  "citations": [{"label": "S1", "chunk_id": "..."}],
  "latency_ms": {"embedding": 0, "retrieve": 0, "rerank": 0, "generate": 0},
  "usage": {"embedding_tokens": 0, "rerank_tokens": 0, "llm_input_tokens": 0, "llm_output_tokens": 0}
}

模型生成的引用编号必须由后端映射到真实切片。引用存在不等于支持该声明,还需人工或经过验证的 claim-evidence 评审。

7. 指标与建议目标

这些是项目目标而不是预先宣称的结果。试运行后、正式盲测前冻结。

层级 指标 建议目标
数据 searchable 切片可追溯当前文档版本/页码 100%
OCR 金标准页 CER ≤ 3%
表格 数值及单位准确率 ≥ 99%
初召回 Hit@20 ≥ 0.85
初召回 Hit@50 ≥ 0.93
多跳初召回 CompleteHit@20 ≥ 0.70
多跳初召回 EvidenceGroupRecall@20 ≥ 0.85
初召回 MRR@10 ≥ 0.60
初召回 nDCG@10 ≥ 0.65
重排 Hit@5 ≥ 0.80
重排 MRR@10 ≥ 0.70
重排 nDCG@10 ≥ 0.75
重排收益 nDCG@10 绝对提升 ≥ 0.05
生成 专家答案通过率03 级中 ≥ 2 ≥ 0.80
生成 事实忠实度 ≥ 0.95
引用 Citation Precision ≥ 0.90
引用 Citation Recall ≥ 0.85
数值题 数值及单位正确率 ≥ 0.95
无答案 拒答 F1 ≥ 0.85
风险 无证据事实占比 ≤ 5%
端到端 完整成功率 ≥ 0.75
多跳困难集 完整成功率 ≥ 0.60
系统 稳态错误率 < 1%
系统 端到端 p95 建议 ≤ 10 秒

qrels 相关等级:

等级 定义
3 直接回答问题或属于必要 Gold 证据组
2 明确支持关键子结论,但单独不足以完整回答
1 主题相关或提供背景,不能支持关键答案
0 无关、实体混淆或与问题条件不匹配

指标定义与分母:

  • Hit@KTop K 至少包含一个等级 ≥ 2 的证据;
  • CompleteHit@K:多跳问题的所有必要证据组都在 Top K
  • EvidenceGroupRecall@KTop K 覆盖的必要证据组 / 全部必要证据组;
  • MRR@K:第一个等级 ≥ 2 结果排名倒数的均值;
  • nDCG@K:使用完整 03 等级衡量排序;
  • 忠实度:可被证据支持的原子事实声明 / 全部事实声明;
  • Citation Precision正确支持相关声明的引用 / 全部引用;
  • Citation Recall带正确引用的必要事实 / 全部必要事实;
  • 完整成功:答案正确、必要证据齐、引用正确且无关键无依据声明。

生成评分按以下冻结规约执行:

  1. 专家答案等级3 表示结论完整正确且无实质错误2 表示核心结论正确、仅有非关键遗漏1 表示只答对局部或有重大遗漏0 表示错误、矛盾、捏造,或应回答却拒答。answerable=true 的答案通过率以等级 ≥ 2 二值化;数值题还必须落在单位换算后的容差内。
  2. 原子事实:把答案拆为单一主语—谓语—宾语、单一数值+单位+对象、或单一时间/空间限定命题;“且/以及/分别”连接的可独立验证命题拆开,语义重复命题只计一次。纯格式、寒暄和引用标签不是事实。
  3. 证据边界:忠实度和 Citation Precision 的“证据”只指本次实际送入生成器的上下文切片;任意 Gold 原文不能事后补救未检索到的证据。专家正确性对照 reference answer 与稳定 Gold 锚点。一个声明的多个引用可按其并集判断是否充分蕴含。
  4. 空分母:正确拒答且没有事实声明时,忠实度和 Citation Precision 记为 N/A 并从宏平均分母排除;可回答题无引用时 Citation Recall 记 0Citation Precision 为 N/A有事实但无支持时这些事实全部计为无证据。无答案题交由拒答指标不用空答案抬高生成分数。
  5. 一致关系无证据事实占比 = 1 - 事实忠实度,两者使用同一原子事实分母,所以 ≥ 0.95 与 ≤ 5% 是同一验收约束,不重复计为两个独立成功条件。
  6. 裁决:冻结测试集的答案等级、原子事实边界和 claim-evidence 关系由两名评审独立标注;分歧由第三名地质专业评审裁决。报告原始一致率与 Cohen's kappa并保存脱敏后的裁决理由、rubric 版本和 reviewer blind 状态。

Hit/MRR/nDCG/CompleteHit 只在 answerable=true 上计算。无答案题单独计算拒答 Precision/Recall/F1正类定义为 should_refuse=true;不能把无答案题当作所有检索结果均错误后混进 MRR 分母。按问题类型、来源、模态、难度分别报告,并对查询做 1000 次 bootstrap 给出 95% 置信区间。RAGAS 可作为辅助自动评测,不能代替专家金标准;其方法将 RAG 拆为检索上下文、忠实使用和回答质量多个维度,见RAGAs 论文

Pooling 使用所有参评系统结果的 union。保存参与系统、模型/切片配置和 depth新系统若在指标计算深度内产生未判定候选先补标再计分。unjudged 不得默认等于 0否则指标会系统性偏向参与建池的系统。

8. 消融实验矩阵

为了避免组合爆炸,先在开发集逐项改变一个变量,再对最佳配置运行冻结测试集:

  1. Closed-book LLM 与完整 RAG
  2. 词法、Dense、Hybrid
  3. 512、1024、1536 维;
  4. 256、512、800 Token 切片;
  5. 0、64、128 Token 重叠;
  6. 原文与“标题/地区/矿种/章节”前缀;
  7. OpenAI 兼容 Embedding 与原生 query/document 模式;
  8. Top 20、50 候选重排;
  9. 无 Rerank 与 qwen3-rerank
  10. 上下文 Top 3、5、8
  11. 表格 Markdown 与逐行语义化;
  12. Query 改写开关;
  13. enable_thinking 开关(只用于复杂题子集);
  14. 数字 PDF 主集与 OCR/表格挑战集。

每个实验同时报告质量、p50/p95、Token、调用次数和每 1000 查询估算成本。不得只报告更高准确率而忽略费用和延迟。

9. 错误分类

代码 含义
SOURCE_LICENSE 许可或来源问题
CORPUS_MISSING 语料不存在答案
PARSE_LAYOUT 阅读顺序或版面错误
OCR_TERM / OCR_NUMBER 术语或数值 OCR 错误
TABLE_ALIGNMENT 表格行列错位
FIGURE_UNDERSTANDING 依赖图件空间关系
CHUNK_BOUNDARY 必要信息跨切片
DUPLICATE_CROWDING 重复切片占满候选
ENTITY_COLLISION 同名矿床/地区/地层混淆
RETRIEVAL_MISS 初召回未找到证据
RERANK_WRONG_ORDER 已召回但重排顺序错误
RERANK_TRUNCATION 候选被截断
GEN_HALLUCINATION 生成无依据内容
GEN_OMISSION 证据存在但答案遗漏
NUMERIC_UNIT 数值或单位错误
CONFLICT_VERSION 忽略资料版本冲突
CITATION_MISMATCH 引用不支持声明
REFUSAL_OVER/UNDER 过度拒答或应拒未拒
SYSTEM_TIMEOUT/RATE_LIMIT 外部超时或限流

错误记录包含 qid、运行配置、期望、实际、召回/重排列表、回答、引用、根因、严重性和修复建议。

10. 可复现实验目录与配置

data/
  raw_manifest.jsonl
  documents.jsonl
  pages.jsonl
  chunks.jsonl
  tables.jsonl
eval/
  questions.jsonl
  anchored_judgments.jsonl
  judgment_set_manifest.json
  evidence_groups.jsonl
runs/<run_id>/
  config.yaml
  qrels.tsv
  anchor_resolution.jsonl
  predictions.jsonl
  metrics.json
  errors.jsonl

真实受限数据位于 Git 之外;上面是运行时或受控数据区的逻辑结构,不代表可以提交原文。

anchored_judgments.jsonl 是全部 03 级 judgment 的权威快照;每行至少包含 schema 版本、qid、grade、理由、doc/version/page/char/bbox 锚点、evidence hash、标注人盲化 ID 和裁决状态。judgment_set_manifest.json 冻结 schema 版本、judgment set 版本、条目数、文件 SHA-256、问题集 SHA-256、创建时间和审批人。文件只追加新版本不原地覆盖。

每个 run 的 qrels.tsv 由同一版本的全部不可变、已判定源锚点(不仅是 Gold解析为切片级视图不是人工 judgment 的唯一存储:

qid    0    chunk_id    relevance_grade
q001   0    chk_a       3
q001   0    chk_b       1

补标或裁决变化会产生新的 judgment set 版本和哈希;同一比较表中的所有系统必须用该新版本重新生成 qrels 并重新计分。不同切片配置可以得到不同 chunk ID但必须来自同一 anchored judgment snapshot、resolver 版本和 corpus manifest禁止让不同系统偷偷使用不同真值集合。

config.yaml 至少冻结:

dataset_version: geo-rag-eval-v1.0
dataset_sha256: <sha256>
anchored_judgments_schema_version: 1
judgment_set_version: geo-rag-judgments-v1.0
judgment_set_sha256: <sha256>
corpus_manifest_sha256: <sha256>
git_commit: <commit>
docker_image_digest: <digest>
database_schema_version: <revision>
parser_version: <version>
parser_config_hash: <sha256>
anchor_resolver_version: <version>
anchor_resolution_sha256: <sha256>
qrels_sha256: <sha256>
ocr_model: <version-or-disabled>
chunk_size: 512
chunk_overlap: 64
chunk_profile_hash: <sha256>
embedding_model: text-embedding-v4
embedding_dimension: 1024
embedding_index_namespace: embedding_1024_v1
embedding_api_mode: openai-compatible
embedding_profile_hash: <sha256>
embedding_endpoint_region: cn-beijing
embedding_endpoint_identity_hash: <sha256>
embedding_requested_revision: <provider-model-alias>
embedding_resolved_revision: <provider-revision-or-unknown>
embedding_cache_epoch: <controlled-epoch>
vector_distance: cosine
retrieval_mode: dense
retrieval_top_k: 50
hnsw_ef_search: 100
hnsw_iterative_scan: strict_order
ann_overfetch_k: 200
lexical_analyzer_version: <disabled-or-version>
hybrid_fusion: disabled
hybrid_dense_weight: null
hybrid_lexical_weight: null
rrf_k: null
rerank_model: qwen3-rerank
rerank_api_mode: bailian-compatible-rerank
rerank_endpoint_identity_hash: <sha256>
rerank_resolved_revision: <provider-revision-or-unknown>
rerank_cache_epoch: <controlled-epoch>
rerank_top_n: 10
context_top_n: 8
max_context_tokens: 10000
rerank_instruct_hash: <sha256>
generator_model: deepseek-v4-flash
generator_api_mode: openai-compatible
generator_endpoint_identity_hash: <sha256>
generator_resolved_revision: <provider-revision-or-unknown>
generator_cache_epoch: <controlled-epoch>
provider_capability_fingerprint: <sha256>
prompt_hash: <sha256>
enable_thinking: false
enable_search: false
temperature: 0.0
top_p: 1.0
max_output_tokens: 1200
random_seed: 42

若供应商响应不暴露 resolved revision字段必须写 unknown,同时保存脱敏 endpoint identity、受控 cache epoch、能力探测指纹和响应中的 model 字段;观察到别名行为漂移时提升 epoch禁止继续复用旧缓存。只有配置、代码、数据集/判断集哈希和镜像均冻结,论文中“同一实验”才具有可复现含义。