PageIndex:金融长文档RAG准确率98.7%的结构化索引策略

发布时间:2026/10/18 10:08:20
PageIndex:金融长文档RAG准确率98.7%的结构化索引策略 先放结论传统 RAG 的“召回再回答”流程遇到动辄几十页、满是表格和数值的金融文档时常常不是“回答错了”而是“根本不知道该看哪一页”。所谓 AI 的推理能力在这个场景里被压缩成了“片段拼接能力”——召回哪块算哪块模型再聪明也没法用不完整的上下文做判断。我最近在内部做完一轮针对金融长文档的技术验证核心方案就叫 PageIndex一种不再围绕“语义相似度”使劲而是把文档组织成可推理结构的索引策略。这套思路在仿真金融文档评测集上把准确率做到了 98.7%对比传统 RAG 跑同一批问题提升了将近 20 个百分点。这篇文章把里面的设计思路、切分逻辑、推理链实现和踩坑记录都摊开讲适合正在做 RAG 落地、长文档问答或者金融文本分析的同学参考。1. 传统 RAG 的瓶颈在哪里1.1 “召回正确片段”不等于“推理正确”先纠正一个常见的认知偏差。大家说到 RAG总是盯着召回率、命中率好像只要把包含答案的片段捞出来模型就能给出正确回答。实际跑过几轮长文档问答的人都知道答案片段正确只是第一步模型能不能基于这些片段完成推导是另一回事。举一个最简单的例子某财务说明里写“A 分部营收比上年增长 12%B 分部下降 8%公司整体营收增长 6%”。你要是把这三句话切成了三个独立 chunk模型检索时可能只召回“B 分部下降 8%”这一句于是它给出的结论就是“公司经营状况不好”完全忽略整体增长。这不是模型能力差是检索单元切碎了推理链条。我在传统 RAG 流程里调试过很多次这种问题加粗重排、改 embedding 模型、调 top-k效果都不理想。原因不在向量模型而在文档结构本身——很多关键推理依赖的上下文是分散在多个段落、多张表格里的单纯用“语义相似度排名”的方式把它们捞出来本质上是在赌赌模型恰好能补全缺失的信息这在严谨场景下根本不可靠。1.2 金融文档把这个问题放大了金融文档和普通文本最大的区别在于数字密集、表格密集、术语密集而且答案对准确性要求极高。技术报告里漏一句话可能只是理解偏差金融文档里漏一个数就是事故。实际解析这类文档时我发现有三个特点特别致命表格跨页非常普遍一个资产负债表经常横跨两到三页传统按页切分或按固定 chunk 切分都会把一张表的语义拦腰斩断。数值本身脱离单位、口径和上下文就毫无意义。一个纯数字“38.72”可能是一季度的营收也可能是环比增长率单独把它切进 chunk模型根本无从判断。问题的推理路径往往不是单点查找。“上季度毛利率为什么下降”需要同时关联收入明细、成本明细、费用率变化涉及多个来源的交叉验证。所以金融场景对 RAG 的要求从“找到最像答案的片段”变成了“找到所有和问题相关的结构化信息并按逻辑关系组织起来喂给模型”。这就是我最终转向 PageIndex 的根本原因。2. PageIndex 的核心设计思路2.1 把文档组织成“可推理结构”而不是“可检索碎片”传统 RAG 的流程是文档拆成碎片 → 碎片向量化 → 查询时按相似度检索 → 拼接后生成回答。PageIndex 走的是完全不同的路线先把文档解析成页面级对象再把页面内部的信息按“实体—属性—关系”的方式抽取出来建立索引最后把索引中的结构化信息作为推理上下文注入模型。打个比方传统 RAG 就像给你一本贴满便利贴的书问问题时把所有可能相关的便利贴撕下来丢给你你自己拼。PageIndex 则是提前把书里的关键信息做成一张大的关系图谱问问题时直接在图谱上做路径查找找到答案之后再回到原文对应位置核实。所以 PageIndex 的索引内容不是文档的原始文本块而是从文本块里抽出来的、经过结构化的“语义单元”。这些语义单元包含实体比如公司名、产品名、指标名属性比如数值、单位、时间、口径关系比如同比、环比、占比、增减查询“毛利率为什么下滑”不会去匹配“毛利率”这个词出现了多少次而是直接定位指标A与指标B之间的关联结构然后沿着关系链找回相关内容。2.2 “推理脑”是怎么运作的三步链路把 PageIndex 落地成实际系统最核心的部分是推理脑——一个负责把用户问题转成结构化查询指令的模块。整个链路分三步第一步是问题解析。把用户的口语化问题拆成语义成分例如“Q2 净利润环比变化的原因”会被拆成“指标净利润”、“周期Q2”、“变化环比”、“关注点原因”。第二步是索引导航。拿着这些语义成分去 PageIndex 里找对应的实体和关系。这一步不是向量近似匹配而是精确键值匹配所以不存在召回遗漏的问题。索引里记录了“净利润”出现在哪几页、关联哪些成本项、哪些费用科目和它存在逻辑关系。第三步是原文锚定。拿索引命中的结构化信息回到原始文档中把支撑这些信息的原文段落、表格行、页码一起打包作为模型生成回答的上下文。这样模型不仅能给出答案还能告诉你答案在文档里的准确出处。整个链路跑下来最直观的感受是模型不再是“凭检索结果猜答案”而是真的在沿着一条明确的路径做推理每一步都有据可查。2.3 为什么这种设计对金融文档特别有效我验证过很多类型的长文档PageIndex 在金融场景的增益最大原因和金融文档的信息组织方式高度匹配。金融文档结构化程度高大量信息天然是“主键—值”的结构便于抽取实体和关系。财务报告里每个科目都有稳定名称、固定口径、对应数值抽取难度比散文低得多。金融问题通常是“多跳推理”需要跨章节、跨表格串联信息正好是索引导航的强项。金融文档的错误容忍度低可追溯到原文的能力比传统 RAG 的“语义黑盒”靠谱得多。当然也不是说纯文本场景完全没用只是文本类问题对实体抽取的要求高纯度不够时结构化收益会打折。后面我会单独说这个问题。3. 金融文档分析实测98.7% 是怎么做出来的3.1 测试集与评测口径先说清楚我的评测方式避免读者把“在某几个样本上跑起来还行”当成“全场景无敌”。测试集用的是某机构脱敏后的仿真金融文档包括招股说明书风格的业务章节、财务报告风格的报表章节、以及审计说明风格的附注章节一共 120 份文档每份约 60 到 150 页。针对这批文档我们邀请了有金融背景的人设计了两类问题单点查找题和交叉推理题数量大约是 6:4。单点查找题定义为一个指标只依赖文档中一个信息源的题目交叉推理题定义为需要两个以上来源互相印证才能得到的结论。评测指标上我特别区分了召回准确率和推理准确率。召回准确率看指标数值是否从文档中正确取出推理准确率看针对“为什么”“怎么变化”“原因是什么”这类问题生成结论的方向是否正确。最后综合准确率按两种题型加权平均计算。3.2 对照组三种方案的实测表现同一套测试集我分别跑了三个方案方案A传统 RAG使用通用向量模型固定长度切分top-k5方案B传统 RAG 表格结构增强表格切成笛卡尔积格式并按页面边界做拼接方案CPageIndex实测结果如下指标方案A方案B方案C单点查找准确率85.3%91.6%98.4%交叉推理准确率51.2%68.5%99.1%综合准确率72.1%82.4%98.7%平均单题耗时2.1s2.8s3.4s方案A 的问题很简单跨页表格和跨章节推理基本靠运气。方案B 通过表格结构化已经挽回了一些单点查找的准确率但一到交叉推理还是力不从心。方案C 也就是 PageIndex在交叉推理上的准确率接近 99.1%是整套方案提升最大的部分。3.3 98.7% 有没有水分有人看到这个数字第一反应可能是“是不是问题出得简单”。说实话我一开始也怀疑后来看了十几条失败样本才放心。98.7% 含义是一个相对严格的混合评测结果同时包含了大量“需要跨三页找两个科目之差”的刁钻问题。交叉推理题准确率能做到 99.1% 的原因在于 PageIndex 的原文锚定阶段会把所有相关表格行完整返回模型不需要盲猜只需要根据给定信息做简单的数学判断。失败样本集中在两类一是文档本身数字印刷不清OCR 阶段就错属于源头污染二是问题含有多重限定条件比如“剔除某非经常性损益后”这种口径转换解析器没有正确识别查错了指标。这两类问题后续都有对应优化方向但不影响实验整体结论。4. 如何复现一个最小可用的 PageIndex 分析管线4.1 离线解析切分单位要用“版面结构”而非“固定长度”PageIndex 第一步是把 PDF 文档转成结构化页面对象。这一步的核心原则是以布局分析为主以文本长度为辅。我用的解析流程是先把每一页识别为若干区块区块类型包括标题、段落、表格、页眉页脚。然后进行块合并同页内的相邻段落若属于同一小节就合并成一个语义块跨页表格,则根据表头结构恢复出完整的表格对象而不是按页面边界硬切。我的经验是不要把表格的行简单拼接成文本序列这样会丢失列对齐信息。更好做法是保留表格的行列坐标把单元格内容转成类似键值对的形式。比如“营业收入 2023 年 1,230,456”在索引里存成 {科目: 营业收入, 年度: 2023, 值: 1230456, 单位: 万元}。这个阶段的产出是一个带版面坐标的解析中间文件。后续不管是做索引还是做检索都从这份中间文件出发不用反复解析 PDF能省下大量时间。4.2 建造索引实体、属性和关系表解析文件生成后下一步就是建 PageIndex。我建议用最朴素的关系型结构来做不要一上来就上图数据库除非你的文档规模真的很大。索引表大致设计成三张实体表存储公司、指标、科目名称每个实体关联一个全局 ID属性表存储实体的具体值、单位、时间、页码关系表存储实体之间的各类关联比如“同比”“占比”“原因提及”关系表的建立一部分靠布局规则自动推断比如同一个表格里的行天然存在“隶属于同一张表”的关系一部分靠模型抽取比如为回答“为什么下降”这类问题把文本中描述因果关系的句法结构抽成 “A 导致了 B”。建索引时有一个非常关键的细节一定要为每个属性保留“页码行号”级别的定位信息。原因很简单模型回答问题时需要引用出处如果没有行号定位后续人工核查成本会直线上升。4.3 推理链路把问题转成可执行查询推理链路是 PageIndex 里最像“AI 脑”的部分核心流程是把用户问题转成一条类似 SQL 的查询逻辑。我在验证中把它做成两个阶段。第一阶段用大模型对问题做成分拆解输出 JSON字段包括指标、期间、实体、限定条件。第二阶段把 JSON 映射成索引查询语言比如“查毛利率2023年报排除非经常性损益”就会翻译成“定位实体毛利率关联期间2023年报过滤条件排除非经常性损益”。这个设计有个好处中间 JSON 结构完全可解释。如果答案错了你可以一步步追查是拆解错了、映射错了、还是原文锚定错了而不是面对传统 RAG 的检索结果“黑盒”一筹莫展。以下是简化版的推理链伪代码我用 Python 风格写一下def parse_question(question: str) - dict: # 将问题解析为结构化成分 # 实际实现会交由大模型完成需要给足提示和示例 prompt f把以下问题解析为JSON 指标、期间、实体、限定条件、目标类型 问题{question} 示例输出 {{指标: 毛利率, 期间: 2023, 实体: 某公司, 限定条件: [排除非经常性损益], 目标类型: 原因}} return model_call(prompt) def navigate_index(structured_query: dict) - list: # 在实体表定位实体沿关系表查出相邻属性 entities find_entities(structured_query[指标]) attrs_by_entity [] for entity in entities: related_attrs find_attribute_by_relation( entity, relation_typestructured_query[目标类型] ) attrs_by_entity.extend(related_attrs) return attrs_by_entity def pin_to_source(attrs: list) - list: # 根据属性表里的页码、行号坐标回到解析中间文件抽取原文片段 return [extract_from_page(attr.page_no, attr.line_no) for attr in attrs] def ria_qa(question: str) - str: q parse_question(question) attrs navigate_index(q) contexts pin_to_source(attrs) answer model_call( 基于以下信息回答问题并标注引用页码, contextscontexts, questionquestion, ) return answer实际项目里我会把中间 JSON 记录下来供调试使用。这种日志对排查错误问题极有帮助任何一次错误回答都可以还原到中间状态判断是哪个环节出了问题。4.4 检索召回之后要不要保留向量链路做整个管线时我保留了一条传统向量检索链路作为兜底。原因是 PageIndex 无法覆盖开放型问题比如“这篇文档想传达什么信息”这类问题没有明确实体索引导航起不了作用。兜底策略是当结构化解析阶段置信度不足时比如解析器无法从问题中提取实体则自动降级到传统向量检索。这样既保持了 PageIndex 的高准确率也兼顾了泛化问题。5. 实操中遇到的问题与排查记录5.1 表格跨页导致实体断裂第一个踩到的坑是表格在 PDF 里分页后第二页的表头经常被省略直接就是数据行。按传统固定切分方式第二页的表格块会丢失表头信息索引里就会出现“科目None”这样的脏数据。解决办法是在版面解析阶段引入表头继承机制。如果当前页顶部区块看起来像是上一页表格的延续就尝试用上一页表头补全当前表格结构。这个启发式规则在大多数财务文档里都适用因为 PDF 排版软件通常会为了防止表头丢失而重复表头但对那些不重复表头的文档必须靠补全逻辑处理。5.2 数值单位不一致导致推理结果错乱有一次比率题准确率突然掉到 92%排查后发现问题出在单位上。某些附注里的数值以“万元”为单位而趋势图里展示的是“亿元”索引阶段没有统一口径模型把 1.2 亿当成 1.2 万结论自然全错。后来的修复方案是在属性抽取阶段增加单位归一化步骤所有数值先根据上下文识别单位再统一转成目标单位同时在属性表里保留原始值以便追溯。5.3 索引更新滞后导致新文档查不到PageIndex 是离线索引新文档进来后必须跑一次解析流程。我在项目早期吃过亏文档已经替换成新版本索引还停留在旧版问“最新一期营收”出来的数字是上一季度的。现在我的处理方式是给每个文档加版本号索引表里记录文档版本每次解析成功后同步更新。查询时如果发现文档版本和索引版本不一致立即触发增量重建。5.4 问题解析中的“限定条件”遗漏这是最后一个关键坑。问题里常有“剔除某非经常性损益后”这类口径修饰解析器如果没有识别出来索引导航会返回未剔除前的孤立指标答案自然不对。我的方案是给大模型解析环节加了两层防护一是明确要求模型输出否定性限定例如“不包含、剔除、排除”二是在索引导航时把限定条件作为过滤关键字强制应用到属性查询上做不到精确过滤时宁可报错也不返回未经过滤的结果。6. 我的一些实操心得整套方案从验证到落地我最深的体会是RAG 项目的复杂度不取决于用了多大的模型而取决于你对文档结构的理解程度。传统 RAG 是在用通用方法解决专用问题注定要在很多边界case上反复打补丁PageIndex 的思路是先理解文档再谈检索准确率的提升只是这个前置理解的必然结果。如果你也想在别的场景里尝试这套思路我的建议是从小处入手先拿 20 到 30 份有代表性的文档手动标注出实体、属性和关系建立一个小规模索引再用现成的大模型做问题解析把整条链路跑通后再扩大规模。直接一上来就搞全量索引很容易被各类脏数据拖进泥潭。还有一个值得留意的点PageIndex 对清洗后文档的依赖比传统 RAG 更高。传统 RAG 遇到脏文档顶多检索结果差一些PageIndex 遇到脏文档会把脏结构直接带进索引影响更深。所以预处理阶段多花一倍时间是完全值得的。后续我打算把重点放在两件事上一是用更大规模的数据验证索引自动构建的稳定性二是把限定条件解析做得更细让它能处理更复杂的口径转换。方向上这套思路还可以扩展到研报综述、尽调文档、合同条款比对等场景核心逻辑是一样的先把信息整理成可推理的形式再让模型沿着结构去思考而不是把一堆碎片丢给它碰运气。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询