2026/03/05
推理检索与证据定位机制:可追溯输出的工程实现
作者: 瀚铄智擎技术团队
本文面向企业级知识问答、制度检索、合规审查等高要求场景,目标不是“回答得像”,而是“回答可证明”。文中给出一套可直接实施的工程路径:以 ToC(Table of Contents)树为主索引,以树搜索驱动推理检索,以证据回传和审计日志保障可追溯输出。本文所述机制、流程与指标口径均基于瀚铄智擎技术团队的项目交付实践沉淀。全文按“输入、处理、输出、日志、验收”五个维度展开,便于团队按模块落地与联调。
一、问题定义与设计原则
在长文档检索中,仅依赖“固定 chunk + 向量相似度”通常会出现三类问题:
- 结构失真:chunk 与原始章节边界错位,导致模型拿到片段但失去上下文层级,容易出现“局部正确、整体错误”。
- 证据不可定位:向量召回返回的是切片编号,不天然对应文档章节、页码区间或父子路径,审计与复核成本高。
- 过程不可复盘:很难回答“为什么选到这个 chunk、为什么没选另一个”,无法形成稳定的检索责任链。
因此,工程目标应明确为四项:
- 相关性优先:优先命中正确章节,再进入段落级细化。
- 证据可定位:任何结论都能回到
node_id + 页码/索引区间 + 原文片段。 - 过程可审计:每一步节点选择、扩展、放弃都写入日志。
- 结果可复盘:同一
query_id可重放检索路径并复现结论。
对应设计原则如下:结构先行、推理驱动、证据闭环、无证据降级、指标验收。
二、索引构建:ToC 树结构(核心)
2.1 节点模型与字段定义
索引树是后续检索与审计的唯一结构锚点,节点字段建议固定如下。
| 字段 | 类型/示例 | 作用 | 验收口径 |
|---|---|---|---|
node_id | "2.3.1" 或 UUID | 节点唯一标识,用于检索命中、证据引用、日志关联 | 全树唯一;可逆定位到原文 |
title | "3.2 风险控制" | 章节语义入口,供 LLM 与规则检索共同使用 | 与原文标题匹配率 ≥ 99% |
start_index | 12(页码或段落索引) | 节点起始位置,定义证据边界 | start_index ≤ end_index |
end_index | 19 | 节点结束位置,约束回传范围 | 不越界、不交叉 |
summary | "本节定义审批时限与例外条件" | 低成本语义摘要,用于树上快速筛选 | 与原文主题一致,无反向含义 |
sub_nodes/nodes | 子节点数组 | 形成层级路径,支持由粗到细搜索 | 无孤儿节点、无环 |
2.2 node_id -> 原文内容 映射机制
推荐建立独立的 node_content_map,避免树结构与内容载荷耦合:
- 文本:
node_id -> [{page, paragraph_id, text_span}] - 图像:
node_id -> [{page, image_bbox, ocr_text, image_hash}] - 表格:
node_id -> [{page, table_bbox, csv_snapshot, header_map}]
处理流程:
- 输入:解析后的文档页对象(含文本块、图像块、表格块)。
- 处理:按
start_index/end_index汇总对象并生成内容引用。 - 输出:
node_content_map(仅引用,不复制全文)。 - 日志:记录每个节点绑定的对象数、空节点率、异常对象率。
- 验收:随机抽样节点,人工核验“树节点与原文对象一致”。
2.3 三类入口流程
索引入口必须覆盖三种现实文档状态:
-
原文含目录且带页码。 处理:提取目录行后直接构建节点区间,再进行页码有效性与标题落点校验。 输出:高置信初始树。
-
原文含目录但不带页码。 处理:先抽取目录层级,再在正文中做标题定位;定位冲突时并发二次检索。 输出:带推断页码的树,并标记
inferred=true。 -
原文无目录。 处理:启动自动结构抽取(标题模式 + 版式特征 + LLM 归并)。 输出:候选树并附结构置信度,低于阈值进入人工复核池。
2.4 索引质量控制与修复
质量控制建议在构建阶段一次做完,避免把错误传入检索层:
- 物理页码有效性校验与截断:页码超出文档总页数时先截断,再触发修复流程。
- 标题出现位置校验(并发检查):针对每个标题并发扫描正文,核对首次出现页与目录页是否一致。
- 错误页码修复与重试:对错位节点执行“标题重定位 -> 区间重算 -> 子树联动修正”,失败则回退上层节点范围并记
needs_review。
2.5 大节点递归细化(双阈值)
对过大的节点执行再切分,触发条件建议采用“页数阈值 + token 阈值”双阈值:
- 条件:
(end_index - start_index + 1) > PAGE_THRESHOLD或tokens(node_text) > TOKEN_THRESHOLD - 动作:调用结构化再切分模型生成子节点,并继承父路径。
- 终止:达到最小粒度或连续两次切分收益不足。
function build_or_repair_index(document):
toc_info = detect_toc(document)
if toc_info.has_toc and toc_info.has_page_num:
tree = build_tree_from_toc_with_pages(toc_info)
else if toc_info.has_toc and not toc_info.has_page_num:
tree = build_tree_from_toc_without_pages(toc_info, document)
else:
tree = build_tree_from_auto_structure(document)
tree = validate_physical_page_range(tree, total_pages=document.page_count)
# 并发做标题定位校验
mismatches = concurrent_title_location_check(tree, document)
for node in mismatches:
repaired = repair_node_page_range_by_title(node, document)
if not repaired:
mark(node, "needs_review")
queue = [tree.root]
while queue not empty:
node = queue.pop()
page_span = node.end_index - node.start_index + 1
token_span = estimate_tokens(fetch_text(document, node))
if page_span > PAGE_THRESHOLD or token_span > TOKEN_THRESHOLD:
node.sub_nodes = split_large_node(node, document)
queue.extend(node.sub_nodes)
node_content_map = build_node_content_map(tree, document)
qc_report = generate_index_qc_report(tree, mismatches)
return tree, node_content_map, qc_report
三、推理检索:树搜索而非向量召回(核心)
3.1 LLM Tree Search 标准 I/O
建议统一接口,避免模型调用与检索编排耦合:
- 输入:
query + current_tree_view - 输出:
thinking + node_list
其中 thinking 记录模型对当前树的判断理由(供审计,不直接展示给终端用户),node_list 为下一步待取证节点集合。该接口的核心价值在于“先选结构,再取原文”。
3.2 迭代检索闭环
标准闭环可固定为五步:
- 读树:读取当前可见层级与历史访问状态。
- 选节点:模型输出
node_list,并进行去重与合法性检查。 - 取原文:按
node_id从node_content_map拉取正文证据。 - 判充分:执行证据充分性判定。
- 不充分则继续:扩展相邻节点、父子节点或文内引用节点,再次迭代。
3.3 证据充分性判定标准
建议以结构化判定结果替代“主观觉得够了”:
- 覆盖度(Coverage):问题中的关键约束是否被证据逐项覆盖。
- 一致性(Consistency):多条证据是否互相支持、是否同一版本口径。
- 冲突情况(Conflict):是否出现相互矛盾条款,是否已标注优先级规则。
- 缺失项(Missing):仍缺哪些关键信息,缺失是否影响结论有效性。
判定输出至少包含 is_sufficient、missing_info、conflict_notes 三类字段。
四、混合树搜索(Hybrid)工程化
纯 LLM 路径在复杂问题上准确性高,但成本与时延受上下文影响;纯打分路径成本可控,但容易只命中局部。工程上建议并行执行两条分支:
- LLM 树搜索分支:负责路径规划、跨层跳转、歧义消解。
- value-based 分支:以 chunk 为中间单元计算节点分数,仅用于节点优先级排序,不直接把 chunk 当最终证据返回。
4.1 队列与消费者机制
frontier_queue:候选节点队列,按综合分数排序。visited_set:节点去重,防止循环访问。consumer_pool:并发拉取节点原文,降低长文 I/O 时间。
4.2 提前终止(Early Stop)
当满足以下任一条件即可提前结束:
is_sufficient=true且冲突已解释。- 新增节点连续 N 轮未提升覆盖度。
- 达到
max_steps或预算阈值(token、时延、成本)。
4.3 节点打分示例公式
设节点下 chunk 集合为 C(node),chunk 相关度为 s_i,chunk token 为 t_i,可采用:
raw(node) = Σ( s_i )
norm(node) = sqrt( Σ(t_i) / 100 )
score(node) = raw(node) / max(norm(node), 1)
该做法可抑制“长节点因文本多而天然高分”的偏置,便于与 LLM 分支结果融合。
function retrieve_with_trace(query, tree, node_content_map):
frontier = init_frontier(tree.root)
visited = set()
evidence_refs = []
retrieval_steps = []
for step in range(1, MAX_STEPS + 1):
llm_out = llm_select_nodes(query, view_tree(frontier))
# llm_out: {thinking, node_list}
value_rank = value_score_nodes(query, frontier) # chunk->node 聚合打分
candidates = merge_and_rerank(llm_out.node_list, value_rank)
candidates = deduplicate(candidates, visited)
node_batch = consume_nodes(candidates, TOP_K_PER_STEP)
for node in node_batch:
visited.add(node.node_id)
refs = fetch_evidence(node_content_map, node.node_id)
evidence_refs.extend(refs)
suff = judge_evidence_sufficiency(query, evidence_refs)
retrieval_steps.append({
"step": step,
"thinking": llm_out.thinking,
"selected_nodes": [n.node_id for n in node_batch],
"sufficient": suff.is_sufficient,
"missing": suff.missing_info
})
if suff.is_sufficient:
break # early stop
frontier = expand_neighbors_and_references(node_batch, tree)
final_answer = generate_answer_or_decline(query, evidence_refs)
audit_log = build_audit_log(query, retrieval_steps, evidence_refs, final_answer)
return final_answer, evidence_refs, audit_log
五、证据定位与可追溯输出(核心)
5.1 证据输出格式规范
最终响应必须返回“答案 + 证据对象数组”,单条证据对象最少包含:
node_idstart_index/end_index(或页码区间)snippet(证据片段)source_path(父子节点路径,如1 > 1.2 > 1.2.3)confidence_note(置信说明与限制条件)
5.2 审计日志字段规范
审计日志最少字段:
query_idretrieval_stepsselected_nodesevidence_refsfinal_answertimestamp
建议补充:model_version、index_version、latency_ms、cost_tokens、degrade_reason,以支持线上问题回放。
5.3 JSON 输出示例
{
"query_id": "Q-20260305-00017",
"timestamp": "2026-03-05T14:38:21+08:00",
"query": "采购审批超时后的责任划分与升级路径是什么?",
"selected_nodes": ["3", "3.2", "3.2.1", "7.4"],
"retrieval_steps": [
{
"step": 1,
"thinking": "问题包含规则定义与例外条款,优先进入第3章制度条款。",
"node_list": ["3", "3.2"],
"sufficient": false,
"missing": ["升级链路触发条件"]
},
{
"step": 2,
"thinking": "在3.2下找到超时责任描述,同时需补充跨章节升级流程。",
"node_list": ["3.2.1", "7.4"],
"sufficient": true,
"missing": []
}
],
"evidence_refs": [
{
"node_id": "3.2.1",
"start_index": 42,
"end_index": 45,
"snippet": "审批节点超出SLA 24小时,由节点责任人提交延迟说明并报部门负责人确认。",
"source_path": "3 > 3.2 > 3.2.1",
"confidence_note": "条款定义清晰,适用于常规采购流程。"
},
{
"node_id": "7.4",
"start_index": 103,
"end_index": 105,
"snippet": "连续两次超时或单次超时超过72小时,触发跨级升级至运营治理委员会。",
"source_path": "7 > 7.4",
"confidence_note": "与3.2.1互补,无冲突。"
}
],
"final_answer": "常规超时先由节点责任人说明并经部门负责人确认;出现连续两次超时或单次超过72小时时,按第7.4条升级至运营治理委员会处理。"
}
5.4 降级与人工复核
必须执行“无证据不下结论”:
- 当
evidence_refs为空或覆盖度不足时,返回“证据不足”状态,不输出确定性结论。 - 当冲突无法消解时,输出冲突条款并触发人工复核。
- 当命中节点均为低置信(如结构抽取节点)时,进入人工确认队列。
人工复核触发条件建议量化:coverage < 0.8、conflict_count > 0 且无优先级规则、retry_count ≥ 2。
六、验收口径与评测指标
上线前建议按查询集(不少于 500 条)进行离线评测,并在灰度期持续采集线上指标。以下口径可直接执行。
| 指标 | 定义 | 计算口径 | 采集方式 | 目标示例 |
|---|---|---|---|---|
| 节点召回率(Node Recall) | 应命中节点中被检索命中的比例 | 命中真值节点数 / 真值节点总数 | 离线标注集对比 selected_nodes | ≥ 0.92 |
| 证据覆盖率 | 答案关键点被证据覆盖的比例 | 被证据支持的关键点数 / 关键点总数 | 规则抽取关键点 + 人工抽检 | ≥ 0.90 |
| 引用准确率 | 返回证据与答案断言一致的比例 | 正确引用条目数 / 总引用条目数 | 逐条校验 snippet 与断言映射 | ≥ 0.95 |
| 无证据断言率 | 无证据仍输出确定性结论的比例 | 无证据确定性回答数 / 总回答数 | 线上审计日志扫描 evidence_refs | ≤ 0.5% |
| P95 检索时延 | 检索阶段 95 分位耗时 | P95(retrieval_latency_ms) | APM/日志平台按 query_id 聚合 | ≤ 1200ms |
| 端到端响应时延 | 从请求到最终响应总耗时 | response_ts - request_ts 的 P95 | 网关日志 + 应用日志对齐 | ≤ 2500ms |
指标解释要求:所有延迟指标必须带样本量、时间窗和查询类型分层(短问、复杂问、跨章节问),避免平均值掩盖长尾。
七、风险与边界
7.1 树结构错误导致漏检
风险:目录抽取或层级归并错误会直接影响召回上限。 对策:构建期执行校验重试;检索期提供“相邻节点扩展 + 父节点回退”;低置信节点进入人工兜底。
7.2 摘要偏差导致误选节点
风险:summary 与原文不一致时,LLM 会沿错误路径深入。
对策:摘要生成后做语义一致性校验;命中前二次取样原文;发现偏差即重算摘要并回写版本。
7.3 文内跳转引用遗漏
风险:制度文档常有“见第X章”跳转,若不跟踪引用边将漏掉关键约束。
对策:在索引中显式构建 reference_edges;检索不充分时优先扩展引用节点;日志记录“引用扩展命中率”。
7.4 长文多轮检索导致时延抬升
风险:复杂问题下迭代轮次增加,P95 时延显著上升。 对策:使用并发消费者、节点缓存、结果缓存;设置 early stop 与预算上限;超过预算自动降级到“证据不足 + 人工复核”。
实施建议与交付件清单
为便于项目制交付,建议最小交付件包含:
index_builder:完成三类入口、校验修复、双阈值细化。retrieval_engine:完成 LLM 树搜索与 Hybrid 并行、去重队列、early stop。evidence_formatter:统一证据结构与答案输出协议。audit_logger:按query_id记录全链路检索与生成过程。evaluation_suite:离线指标计算脚本与线上看板口径。
上述五项全部可映射到“输入/处理/输出/日志/验收”闭环。达到指标后再扩展多模态(图像、表格)与跨文档检索,可显著降低一次性改造风险。