Skip to content
文章目录
GitHub Star

知识检索:一段文档怎样成为可引用、可撤权的研究证据? ​

一个投研 Agent 被问到:“某基金 2023 年的一份申购赎回清单更新公告,到底改了什么?后来的招募说明书能不能证明当时的变更范围?”

它可能命中三份材料:早年的说明书、当年的公告、后来的说明书。三者都有相近的字段名,但真正能直接回答“当时改了什么”的,往往是特定日期、特定版本的原始公告。如果模型只拿到排序最高的几个片段,容易把“后来也出现过这个字段”误认为“当时就是这样修改的”。

这正是知识检索比一个向量搜索接口复杂得多的原因:**一份资料需要先被允许进入语料,再被可靠切分、索引、检索、送达模型,最后还要通过引用与披露资格的检查。**其中任何一步失真,答案都可能显得有理有据,却无法复核。

本文沿 ETF Agent 的 A20 知识检索展开。它的核心职责是:从已经准入的知识集合中,为一次获准查询寻找候选片段,并保留真实来源、检索状态和可追溯身份。资料准入、PDF 解析、模型是否相信某项论证,以及答案发布/历史回放各有原本的职责;本文讲完整交接链路,但不把它们收编成一个万能 RAG 模块。

一、先分清四件容易混淆的事 ​

概念它代表什么不代表什么
Knowledge Source有来源、用途和许可的知识材料当前持仓、NAV 或投资交易事实
Research Asset一份获准取得、带身份和版本的研究文件已解析、已入库或已被模型阅读
Indexed Chunk索引中可检索的某份材料的有限片段全文完整、适用条件齐全
Knowledge Evidence经本次查询实际交付、保留来源身份的读得材料排名高就足以支持最终结论

这几个对象不能相互升级。PDF 阅读可以提供文本和页码,但不负责决定哪段最相关;A20 可以找到候选,但不替模型判断哪句主张被证实;Host 可以证明片段的来源身份,却不能借一次成功检索授予投资写入权。

把 RAG 看作“数据管线 + 证据交付”更接近工程现实。资料生命周期和查询生命周期相交,但不是同一条流水线。

二、离线链路:为什么要先审材料,再建立索引? ​

1. 来源准入先于文本提取 ​

取得一份公开网页或研究报告,并不自动意味着能把其全文复制进本地向量库。来源可能只允许保存元数据,或仅允许人工整理摘要;个人材料还涉及账户作用域与本地处理资格。

ETF Agent 早期知识建设为不同来源保留过原文、经整理摘要和仅元数据等形态。重要的是不能让“资料目录里有这本报告”在检索工具描述中变成“原始全文可供引用”。

示例中,机构报告只有被许可的整理卡片,而监管公开资料有可检索正文,两者同样可能回答问题,却应在结果里明确表示类型。摘要里的观点不能伪装成机构原文引语。

2. 解析、切块要保住限定条件 ​

一段从 PDF 提取的费用表,只留下“管理费 0.5%”,却丢掉了“适用份额类别”和脚注,检索越准确,误导反而越稳定。

合理的索引单元至少应保留逻辑来源、文档版本、内容哈希、片段序号与章节/页位置。Markdown 可按章节切块,长章节再做有限重叠;PDF 则还要保留物理页的关联。块尺寸是取舍:短块便于命中精确条款,长块保留更多限定,但消耗更多上下文。

在核对过的本地知识导入路径中,不会把只提取到前几页的 PDF伪装成可全文检索的完整文档。提取不完整时应记录不支持或待补,而不是悄悄把缺失页解释成“内容不存在”。表格结构、扫描页 OCR 与视觉解释还属于另外的提取能力和资格问题。

按起点分组阅读关系与条件;完整图保留在下方。

登记来源用途、许可与版本
  • → 准许保留何种内容? (判断)
准许保留何种内容? (判断)
  • 仅元数据 → 建立目录记录,不冒称原文
  • 有界正文 → 解析并检查提取覆盖
  • 不允许 → 拒绝入库
解析并检查提取覆盖
  • → 原件范围可确认? (判断)
原件范围可确认? (判断)
  • 否 → 标记不完整并待复核
  • 是 → 分章节或页面切块
分章节或页面切块
  • → 保存来源身份、哈希及检索表示
保存来源身份、哈希及检索表示
  • → 检查实际索引健康
完整关系图 · 可放大查看细节
在核对过的本地知识导入路径中,不会把只提取到前几页的 PDF伪装成可全文检索的完整文档。提取不完整时应记录不支持或待补,而不是悄悄把缺失页解释成“内容不存在”。表格结构、扫描页 OCR 与视觉解释还属于另外的提取能力和资格问题。
Agent architecture diagram 放大查看完整图 / Open full-size SVG

图 1|入库资格与文本完整性是索引前的条件;拒绝入库不影响其他获准来源。

3. 更新不是“把旧行覆盖掉” ​

同名报告可能被修订,网页也会变。索引需要区分逻辑来源和物理内容版本:先准备新版本及其片段,再按获准的生命周期切换可用版本。旧引用如果需要审计回读,仍须指向原版本,不能在用户打开历史报告时偷偷解析为新正文。

在来源维护上,检查是否变更与实际同步、重新嵌入和更新索引也应分离。历史实现曾采用只读检查与经过审核的同步操作,变更仅更新相关的生成材料,不顺手改动手工知识、账户持仓或投资执行账本。

由此引出第一个故障判断:数据库能连通、Embedding 模型能返回、检索测试全绿,都不能证明现在的可用索引里有获准片段。一个历史诊断曾发现本机文档与 chunk 都为零;它是当时的运行状态,不是当前生产语料情况。

三、在线链路:从用户问题到候选片段,谁决定什么? ​

A20 接收的不是“一个字符串”这么简单。除了原始查询,还要面对 Host 已绑定的用户作用域、集合、来源限制,以及可选的领域、时间和文档版本条件。

例如下列示例请求是为了说明输入语义,而非现成的公开 API:

json
{
  "query": "这份旧版公告具体改变了哪个字段?",
  "collection": "reference",
  "domains": ["fund-documents"],
  "domainMode": "prefer",
  "sourceIds": ["approved-document-v2023"]
}

其中 sourceIds 应理解为实际返回过的逻辑文档身份;上面的字符串只是教学占位符,不是系统真实可传的领域 ID 或来源 ID。模型提出的来源范围只能缩小 Host 的许可,不能因为猜到某个 ID 就获得读取权。

1. Host 允许查询,不等于模型一定调用 ​

模型可以直接回答通用问题,也可以选择调用 search_financial_knowledge。系统没有必要为了“让 RAG 出现”对所有问题偷偷预检索。真正需要观察的是:工具是否进入这轮模型请求、模型是否提出调用、Host 是否执行,以及检索结果是否进入后续实际模型输入。

一次研究即使 Host 事先准备好了知识授权,模型请求里也可能未包含工具定义。这时没有检索,不应错误归因为向量召回差。工具可用、工具可见、工具被调用是三个不同事实。

2. 硬过滤必须发生在 Top-K 之前 ​

对一个有私人材料、公开参考材料和历史版本的知识库,先全库搜索 Top-K、最后才剔除越权候选,不只是信息泄露风险,也会使结果失真:最相关的获准片段可能早就被未授权候选挤出榜单。

当前 PostgreSQL 知识路径在候选检索阶段按集合、scope、来源、用途、状态以及适用的领域/版本等字段收窄范围。reference 与 personal 分开检索,默认不会悄悄搜个人笔记。

一个领域偏好不足时,Retriever 可以在同一集合与硬约束内做一次受限扩展;明确的 domainMode=only 以及 Host 来源、scope、版本约束不能被这次扩展取消。扩展触发的依据是候选数量不足,不是语义上“已经证据充分”的判定。

3. 为什么需要两路召回与 RRF? ​

词法检索擅长精确基金代码、字段名和术语;向量检索更有机会找到表达不同但含义接近的段落。这两路候选的分数刻度通常不一致,不能简单把原始分数相加。

实际系统保留独立的向量与词法候选上限,使用版本化 RRF(Reciprocal Rank Fusion,倒数排名融合),按各路名次合并,同一片段只计算一次身份。RRF 贡献描述排序,不是“证据正确的概率”。

词法通道还存在真实运行差异:

环境和状态词法路径可以得到的结论
PostgreSQL 已具备获准的 pg_search 与 BM25 索引,且配置允许可选 BM25该次查询确实需要观察算法诊断,不能只看配置
不具备扩展或索引,或已关闭 BM25PostgreSQL FTS(tsvector 路径)仍可能返回有效候选,不可声称 BM25 已启用
词法通道失败,向量仍有合格候选使用幸存通道并标记部分状态不是“两个通道都成功”,也不是全库无资料

对于精排,现有 Retriever 可以选择本地 TEI 适配器,在已合格的融合候选内调整顺序。它不应该加入新来源、不应该绕过候选权限,也不应该让精排得分变成引用权。服务不可用或超时时,保留既有 RRF 顺序并暴露降级状态。配置已加载、受控合成样本精排成功,不等于真实投研 Run 已证实答案质量改善。

4. 取相邻上下文不是扩大引用范围的许可证 ​

当一个 chunk 命中了费用条款,前后片段可能包含标题、例外或脚注。Retriever 的相邻片段回读受到同文档、同版本和原始作用域限制;但扩大阅读窗口并不会自动扩大之前那个引用所覆盖的原始文字。

尤其在 Native Knowledge 工具路径中,实际交付的是经过来源有效性复核的锚点片段;不为便利而把未独立取得引用身份的相邻正文冒称已经被证实。对需要脚注、表格或更长上下文的主张,后续仍应取得可对应的实际原文范围。

四、候选进入模型,怎样才算变成证据? ​

按起点分组阅读关系与条件;完整图保留在下方。

模型提出 Knowledge 查询
  • → Host 来源与集合许可? (判断)
Host 来源与集合许可? (判断)
  • 否 → 拒绝受保护的查询
  • 是 → 同约束下词法与向量召回
同约束下词法与向量召回
  • → RRF 去重融合与可选精排
RRF 去重融合与可选精排
  • → 候选来源当前仍有效? (判断)
候选来源当前仍有效? (判断)
  • 否 → 排除失效片段并标明缺口
  • 是 → 绑定实际交付片段与来源
绑定实际交付片段与来源
  • → 模型阅读并形成具体主张
模型阅读并形成具体主张
  • → 提交或回放仍可披露? (判断)
提交或回放仍可披露? (判断)
  • 否 → 阻止受保护内容显示
  • 是 → 交付带可核对来源的回答
完整关系图 · 可放大查看细节
四、候选进入模型,怎样才算变成证据?
Agent architecture diagram 放大查看完整图 / Open full-size SVG

图 2|排名不能越过授权,读到不能直接越过发布。每个判定都有独立的失败结果。

A20 返回的片段带有逻辑来源、文档与 chunk 身份、版本/哈希、文本表示类型、相关时间,以及可诊断的检索状态。Host 再把本次确实交付的读得材料映射成当前 Run 的引用绑定;模型自己写出的任意 citationId,不能因此获得真实出处。

这里必须拆开四层观察:

关口有什么证据才算跨过?
候选召回当前授权语料范围里返回了哪些 chunk,以及各通道实际状态
Host / 模型交付工具调用成功,且下一轮真实模型输入包含了哪些受许可的正文或外置读取引用
主张支持答案中的特定一句话,是否可由对应原文位置、版本和限定条件直接支持
受控披露答案提交时与历史再次显示时,该来源是否仍可对当前查看者披露

不要把“模型搜索到 24 个位置”写成“模型读了 24 段全文”。外置结果的字面搜索可能完整列出命中位置,但未取回周围论证。也不要把“回答引用了来源 A”写成“来源 A 支持了所有句子”。一条回答应按主张核对来源,必要时继续阅读原文。

RAG 撤权的真实工程教训就在最后一关:**检索时允许,无法证明首次 SSE 发出、回答提交或历史回放时仍允许。**旧许可或旧快照不能替代当前的批准索引资格。撤权可能需要阻止后续显示;明确的保留撤销还可能触发副本清理,但普通不可达与暂时拒绝不应被推导为永久删除。

这部分由相关的授权、Publication 和历史读取机制实现,A20 不另建一套发布系统。要深入并发撤权的提交次序,可以接着读文档撤权与历史回放。

五、没有答案时,先找到“最早丢失证据”的阶段 ​

把所有失败都转成“没搜到”,会诱导模型重复查询;把所有失败都转成“系统不可用”,则会丢掉独立有效的资料。

症状首先核对合适的后续动作
资料目录有文件,检索始终空源是否获准、索引是否建成、可搜索 chunk 数与版本区分 empty、not-indexed 与依赖不可用;先修入库/健康问题
精确代码可搜,同义问题搜不到向量通道、Embedding 版本、查询表达及候选限制在固定语料内比较两路候选;不要直接扩大权限
两路都命中,最终 Top-K 缺关键页融合去重、重排、Top-K 和上下文限制查看候选到选中片段在哪一步丢失
检索结果有正文,答案没用上工具表面、下一轮实际模型输入、外置结果是否回读修复交付/读取;不是盲目换 BM25
命中内容却不能引用或显示当前来源资格、版本、Host 绑定、发布与历史读取许可让受保护片段受控不可见,保留可独立交付内容
答案引用了正确公告,却扩大了结论原文适用日期、字段范围、后续版本和模型主张独立复核主张;不能靠提高召回数量修复

Retriever 的 grounded、partial、no-evidence、unavailable 是检索层结果语义。其中 grounded 说明取得了满足检索合同的材料,绝不是“投资结论已被证明”。索引健康又有 ready、partial、empty、not-indexed、unavailable 另一套诊断;两者不能混算。

最重要的工程指标不是单独一个 Recall@K,而是沿同一问题追踪哪个阶段第一次丢失可支持主张的原始材料。固定数据版本、候选粒度、人工标注范围与同一次任务资格,再讨论 BM25、RRF 或精排是否改善答案。

在 510500 公告的实际检索评测中,我们曾将同一范围内的 306 个 chunk 用于候选比较;但缺少完整人工相关性判断,因此没有资格从这次排序推导真实 Recall 或金融答案正确率。检索算法实验和端到端研究质量评测是两个不同命题。完整案例与证据边界见RAG 检索评测:找到相关文本,还不等于找到金融证据。

六、怎样从这篇文章走到一个可运行的最小实现? ​

公开教学仓库 Open ETF Agent 不是上述私有系统的完整 A20 实现。它提供一个适合学习“候选检索 → 原始页面回读 → 来源关联报告”的较小切面:在合成资料里做受限关键词页面检索,不提供这里讨论的完整 PostgreSQL/pgvector、BM25、RRF、TEI、个人知识权限和撤权发布联动。

可从已发布的 v0.15.0 固定源码中的简化词法检索 了解最小检索算法,再用 公开运行指南 查看原材料回读。按照 README 的 Node 版本安装并构建后,在新目录执行:

sh
npm run demo -- --case retrieve-reread --query "offline editing"

这个 CLI 示例以脚本化合成资料演示实际检索与结果回读;它不是一套可以用真实基金资料直接验收的 Knowledge 服务,也不会自动证明模型使用了所有候选。要观察完整私有 A20,仍须分别取得被批准的来源/索引状态、真实 Host 工具调用、模型输入投影和引用/发布证据;不能用公开小示例填补未验证的那几层。

七、最后一个架构判断:不要再造一个包办研究的 RAG Manager ​

RAG 很容易演化为“所有搜索、工具选择、知识状态、回答质量和发布审批”的巨型模块。看上去统一,实际会把多个领域的权威事实混到一个接口里:

  • 资料与版本由原始来源、文件/知识生命周期与权限 Owner 保持权威。
  • A20 Retriever负责受控候选、排序、状态与来源身份。
  • Model / Main负责研究问题如何继续、材料是否支持论证、是否需要补查;检索数量不决定研究完成。
  • Host 引用与 Publication / History负责实际送达、合法披露和可核查的回放,不能继承旧授权。

如果将来需要统一的是可观察的证据漏斗,就围绕原有输出关联各阶段,而不是新建一个能绕过它们的状态机。

完成一条可靠的知识检索链路,不是让每个问题都搜得更多,而是让维护者能回答:这段话究竟来自哪份原文的哪个版本、为什么这个 Run 当时能读、模型实际看见了什么、现在为何仍能展示,以及缺了哪段证据时应该诚实停止。


延伸阅读:A17 研究资料资产:来源与版本 · PDF 从文本到证据 · 引用与主张的独立复核 · RAG 撤权与历史回放 · RAG 检索评测

资料范围说明:本文的完整链路基于 ETF Agent 已核对的机制与历史证据组织;可选 BM25/本地重排的运行环境、真实模型消费和金融语义质量不能从代码或受控排序测试直接推断。公开教学实现的范围在上节另行划定。

与个人博客并行:这里按问题连续阅读,博客保留时间线。 · 联系邮箱:hpoenixf@foxmail.com · 微信:hpoenixf0510