ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PageIndex没翻车,翻车的是我的解析器

PageIndex没翻车,翻车的是我的解析器 测试日期2026-10-02测试环境DockerPageIndex Cloud SDKFAISSPyMuPDF硅基流动API测试文档腾讯控股2024年度年报274页繁体PDF这篇原本要写PageIndex在国产模型环境下翻车了。写到一半我回头核对产出数据发现翻车的不是它是我自己。我在评测过程中踩了三个坑一个比一个基础也一个比一个难堪解析器一个汉字都没抽出来、我自己写的标准答案错了九道、以及把限流当成了兼容性问题。一、PageIndex是什么1.1 它做的事把翻目录这件事交给模型PageIndex是Vectify AI在2026年9月开源的项目主打无向量RAGvectorless RAG。它不做embedding也不算相似度流程是这样的建索引把整篇文档读一遍让LLM生成一棵树状目录类似书籍的章节结构每个节点带一段摘要查询问题进来后模型先读这棵树判断答案大概落在哪个分支下钻沿着分支走到叶子节点再调工具把对应页码的原文整页读出来回答基于原文给出答案这套动作在实测里能直接看到——它对外暴露的工具主要就是两个get_document_structure # 拿整篇文档的树结构 get_page_content # 按页码取原文后面第七节会把真实的调用记录整段贴出来。1.2 和普通RAG的区别在哪环节向量RAGPageIndex索引产物一堆chunk的向量一棵带摘要的目录树找答案的方式算语义相似度取top-k模型沿树推理选分支读原文只给命中的k个片段定位到具体页整页读效果取决于embedding对语义的区分度LLM的推理能力文档结构是否清晰像什么拿着问题跟每一段话比相似度像人翻目录找章节再翻到那页细读差别的核心就一句话**相似不等于相关。**向量检索优化的是语义距离最近而文档问答要的是事实正确。问总收入语义上最近的很可能是增值服务收入或者毛利——它们长得像但不是答案。PageIndex想用LLM的推理能力替代这一步相似度计算。这个方向本身成立也正是我想验证的。二、为什么值得动手测三个理由最后一个是国内团队最该关心的**官方数据太漂亮。**PageIndex公布在FinanceBench基准上的准确率是98.7%传统向量RAG大约50%。差距大到我需要自己看一眼——顺带说明这是厂商自测数字我没能复现也没能证伪第十节会再说一次**它瞄准的正是向量RAG最挣扎的场景。**财报、合同、技术手册这类长文档恰恰是我这几轮实测里基础向量RAG表现最差的地方**我想加一个国内开发者更关心的变量国产模型能不能跑。**生产环境里数据安全、成本、合规往往比效果最好更重要。如果它只能用GPT系列对国内团队的价值就得打折三、怎么测的方案与环境理由够了动手。3.1 测试文档腾讯控股2024年度年报PDF格式274页繁体。选它的理由很简单结构完整财务摘要、业务回顾、管理层讨论、公司治理都有、数据密集表格多、数字多、脚注多、公开披露没有版权问题。3.2 题目与评判标准15道题三个难度等级简单5道原文明确给出的单个数字或事实、中等7道需定位正确章节可能涉及计算或对比、困难3道需跨章节综合或归纳。评判标准完全正确核心事实和数字准确单位、范围、条件都对部分正确答到部分要点但有遗漏、单位不明确或数字有偏差错误答非所问或声称无法回答但答案其实在文档里方法说明这是15题小样本探索性实测单人人工评判可能有主观偏差。金标准逐条回溯到年报页码第4、8、28、123页等每道题都标了出处。3.3 三组方案方案配置作用A 基础向量RAGPyMuPDF解析、chunk_size500、overlap50、bge-m3、FAISS、top_k3对照组测裸奔版下限B PageIndex Cloud官方OCR树索引问答用DeepSeek-V3硅基流动实验组C 调优向量RAGABM25混合检索RRF融合召回5篇补齐调优后上限的对照方案C是立项时就定下的官方对比的往往是最差的向量RAG这对向量检索不公平真正有意义的对比应该跟调优后的版本比。3.4 运行环境Docker容器python:3.10-slim装pageindex、langchain系列、faiss-cpu、pymupdf。模型走硅基流动的OpenAI兼容接口。完整配置和可复现的脚本见第十一节。方案定了开始跑。后面几节讲的都是跑的过程中发生了什么。四、第一个坑274页的中文PDF抽出了0个汉字这一节是整篇里最有价值的部分因为它跟PageIndex、跟向量检索、跟大模型全都无关。4.1 现象对照组一开始用的就是标准写法fromlangchain_community.document_loadersimportPyPDFLoader loaderPyPDFLoader(pdf_path)documentsloader.load()# LangChain 默认后端是 pypdftext_splitterRecursiveCharacterTextSplitter(chunk_size500,chunk_overlap50)chunkstext_splitter.split_documents(documents)跑得很顺274页切成333个块5.3秒建完索引。15道题答下来13道回答根据文档内容无法回答剩下2道给了数字但答非所问。我当时给这个结果的解释是bge-m3对总收入和增值服务收入的语义区分度不够。这个解释是错的。我把vector_result.json里每题检索到的chunk内容打出来看一眼满屏是这样的ʮ̡ 262 ൗ ܓ 48 ྼ ᜗ ϓͭήᓃʿ ʊ೯БŊྼϗٙ Τ၈ሯ༉ઋ ᛆूˢԷ (%) ุਕʿ຾ᐄή这是典型的CID/ToUnicode CMap映射缺失——中文字形没有正确映射回Unicode被解成了希腊字母、西里尔字母、马来亚拉姆字母的大杂烩。4.2 量化证据我写了个脚本把两个解析器拉到同一个文档上对比importfitz,redefstats(text):totallen(text)cjklen(re.findall(r[\u4e00-\u9fff],text))weirdlen(re.findall(r[\u0370-\u03ff\u0400-\u04ff\u0d00-\u0d7f],text))returntotal,cjk,weird/total*100解析器抽取字符数中文字数乱码字符占比pypdfLangChain默认90,55806.0%PyMuPDF191,402128,0080.0%**0个汉字。**一份274页的中文年报喂给embedding模型的上下文里一个中文都没有。这个数字解释了一切为什么13道题都答无法回答——问题里的中文关键词在全是符号碎片的知识库里没有任何可匹配的东西为什么剩下2道题还能吐出数字——**数字和拉丁字符的编码没坏只有中文坏了。**纯靠数字形状还能蒙对一旦涉及语义就全线崩我当时把13道无法回答解释成语义相似度不等于事实相关性把一个解析层事故包装成了范式缺陷。这条归因链条错得离谱。4.3 修复一条命令的事pipinstallpymupdfimportfitzfromlangchain_core.documentsimportDocument docfitz.open(pdf_path)pages[Document(page_contentpage.get_text()or,metadata{page:i})fori,pageinenumerate(doc)ifpage.get_text().strip()]切块策略、bge-m3、FAISS、DeepSeek-V3一个都没动只换了解析器改完之后[basic] pages272 chars191402 chunks529 [basic] index_time35.11s [basic] q1 ok 2.93s :: 腾讯控股2024年的总收入为人民币6,603亿元。 [basic] q2 ok 3.17s :: 腾讯2024年净利润为人民币1,940.73亿元国际财务报告准则和人民币2,227.03亿元非国际财务报告准则。 [basic] q12 ok 3.17s :: 2024年腾讯回购了307,238,500股股份回购总金额为1,120亿港元。索引时间从5.3秒涨到35.11秒因为文本量翻了一倍多。这笔开销值。五、第二个坑9道标准答案是我自己写错的如果说第一个坑是技术问题第二个坑更难受——它说明我一开始就没有资格评判模型的答案。修好解析之后我把15道题的答案对着年报原文逐条核了一遍。核对的基础是三处公开数据第123页《综合收益表》、第8页《管理层讨论及分析》的分部收入表、第4页主席报告里的经营数据表。题我原来的标准答案年报真值出处q1总收入约7262亿元6,602.57亿元同比8%p123综合收益表q2净利润约2145亿元IFRS归母1,940.73亿元68%Non-IFRS2,227.03亿元41%p4/p123q3增值服务约3224亿元3,192亿元同比7%p8q4微信月活13.9亿2.5%1,385百万13.85亿同比3%p4经营数据表q6网络广告1126亿元24%营销服务1,213.74亿元同比20%2024年起由网络广告更名p8/p123q7金融科技及企业服务2277亿元13%2,119.56亿元同比4%p8/p123q10视频付费会员1.05亿1.13亿p5q12回购约1350亿港元约1,120亿港元共307,238,500股并注销p28q13音乐付费会员1.1亿1.21亿p515道题里9道对不上偏差都不小q1差了659亿元q6的同比差了4个百分点q12差了230亿港元。5.1 最打脸的一题旧版对照组的q4输出是这样的微信及WeChat月活1,385单位未明确同比增长3%我当时判部分正确理由是单位不明确数字有偏差。翻到第4页经营数据表微信及WeChat 的合併月活躍賬戶數 1,385 1,343 3% 百万计另有指明者除外年报自己的单位就是百万。模型答的1,385、增长3%两个数字全对还忠实反映了原文的百万口径。这题是全对被我判成了部分对。同一份结果里还有q13模型答255,792我判数字对但答非所问。回头看那是在一堆乱码chunk里捡到的某个会计科目数字。两条记录指向的是同一个结论上下文没有中文模型只能靠数字碰运气。5.2 教训评测集的金标准必须能逐条回溯到原文页码。我后来给自己立的规矩是每题除了expected_answer还要填expected_pages和note口径说明。没有出处页的答案本质上只是另一个猜测。六、重做之后0%到80%两个坑都填上了重跑基础版对照组。先放新旧两版的整体对照维度旧版pypdf抽取新版PyMuPDF抽取抽取字符数90,558191,402抽出的中文字数0128,008乱码字符占比6.0%0.0%切块数500/50333529向量RAG完全正确率0%0/1580%12/15平均查询耗时2.61秒4.04秒配置完全没有优化就是最朴素的那套chunk_size500、overlap50、bge-m3、FAISS、top_k3、DeepSeek-V3、temperature0。说明这组数字来自两次独立运行索引耗时实测在3541秒、平均查询在4.04.8秒之间波动同一脚本的正常抖动不影响准确率结论。题号难度答案判定q1简单6,603亿元正确q2简单IFRS 1,940.73亿Non-IFRS 2,227.03亿正确q3中等增值服务3,191.68亿占比称未披露部分正确q4简单13.85亿同比3%正确q5中等混元、元宝、AI融入搜一搜与广告平台正确q6中等营销服务1,213.74亿20%注明更名正确q7中等给出毛利997亿未给收入2,119.56亿部分正确q8中等无法回答错误q9困难ESG工作组、可持续社会价值创新、未成年人保护等正确q10简单1.13亿正确q11困难三个方向AI、产业互联网、内容与平台生态正确q12中等307,238,500股1,120亿港元正确q13简单1.21亿正确q14困难《帝国时代》手游、《流亡黯道2》、Supercell正确q15中等分部收入2,119.56亿4%并声明未披露云单列数据正确完全正确12/15部分正确2/15错误1/15。我还补记了一个指标召回率hit3——正确答案所在页有没有出现在检索结果里。组别hit3完全正确率基础组向量top-314/1593%12/1580%调优组BM25向量混合top-513/1587%更低q6、q15答错顺带修正一处q9的期望页我一开始标成了指向ESG报告的引用页实际答案内容在第106至107页把这两页补进标注后两组才算命中。召回率高于准确率这个对比值得单独说一句它意味着检索层基本是命中的剩下丢的分主要不在找没找到而在拿到之后怎么答q8检索命中了p5但模型选择拒绝回答q3检索命中但游戏收入占比要到附注里凑模型说未披露q7两组都没检索到收入分部表p8都答成了毛利也就是说解析层修好之后这套朴素配置的瓶颈落在生成层——检索层该找的基本都找到了。这跟我这个系列第3篇生成层实测的方向能对上。而调优组在q6上偏偏丢了命中——它检索到的是分部毛利表p9而不是收入表p8所以把毛利672.32亿当成了收入。混合检索多召回的那几篇文档把真正的收入页挤掉了——这是它比基础组差的直接原因不再是推测。再按题型分层看一眼开放题的判定弹性大分开算更稳类别题数完全正确正确率事实/数值题q1、q2、q3、q4、q6、q7、q10、q12、q139778%开放题q5、q8、q9、q11、q14、q156583%两类接近说明80%不是靠开放题放水撑起来的。反过来如果把开放题一律从严改判为部分正确完全正确率会降到7/1547%——这是同一组数据在最保守口径下的下限两个数字放在一起看才有意义。唯一答错的q8研发投入总额情有可原年报没有单独列示研发开支总额只在开支附注里体现模型拒绝回答反而是对的——这是我在出题时没核实清楚口径属于第三版要补的内容。6.1 顺手做了一组调优对照立项文档里我写过官方对比的是最差的向量RAG这不公平真正有意义的对比是PageIndex vs调优后的向量RAG。上一版因为对照组全崩这组没做成。这次补上了——BM25加向量混合检索RRF融合召回从3篇扩到5篇classEnsemble:BM25 向量混合标准 RRF 融合definvoke(self,q):raself.a.invoke(q)# BM25 top-8rbself.b.invoke(q)# 向量 top-8scores,seen{},{}# 注意两路必须分别计算排名不能拼接后统一 enumerateforrank,dinenumerate(ra):scores[d.page_content]scores.get(d.page_content,0.0)1.0/(60rank)seen.setdefault(d.page_content,d)forrank,dinenumerate(rb):scores[d.page_content]scores.get(d.page_content,0.0)1.0/(60rank)seen.setdefault(d.page_content,d)orderedsorted(scores.items(),keylambdax:-x[1])return[seen[c]forc,_inordered[:5]]结果并不好看题基础组调优组BM25向量q6营销服务收入1,213.74亿元20%正确672.32亿元31%错误q15腾讯云分部收入2,119.56亿并说明未披露无法回答q2净利润两个口径都给出只给了IFRS一个平均查询耗时4.04秒4.06秒调优组在q6上把分部毛利表里的营销服务毛利67,232百万元672.32亿元当成了收入。多召回的文档带来的只有同名不同口径的干扰——毛利表混进来之后收入就被顶掉了。这不意外和这个系列第1篇分块策略实测的结论是同一个方向——那篇跑了9组配置、900次检索Hit1全挤在0.81~0.83。检索策略的边际收益远小于你的文本到底有没有被读出来这件事的基础收益。七、PageIndex它没翻在兼容性上回到这次的主角。上一版我写它工具调用不兼容国产模型大多只做到第二层兼容性。这个结论我没有数据支撑——我有的只是它失败了然后我挑了一个自己最熟悉的原因往上套。7.1 它成功的两次把pageindex_cloud_deepseek.json完整打开q1的answer字段是这样的[tool_call] get_document_structure {doc_name: tencent-2024-annual-report.pdf} [tool_result] get_document_structure: {success: true, structure: [{title: Preface, node_id: 0000, start_index: 1, end_index: 1, summary: Tencent 腾讯...}]} [tool_call] get_page_content {doc_name: tencent-2024-annual-report.pdf, pages: 124} [tool_result] get_page_content: {success: true, total_pages: 274, requested_pages: 124, content: [{page: 124, text: # 綜合收益表}]} 腾讯控股2024年的总收入为6,602.57亿元人民币。具体数据如下 - 增值服务收入3,191.68亿元 - 营销服务收入1,213.74亿元 - 金融科技及企业服务收入2,119.56亿元 - 其他收入77.59亿元 数据来源《腾讯控股2024年年度报告》综合收益表第124页。把四个分部加起来3191.681213.742119.5677.596602.57和我对照第123页综合收益表的结果完全一致。这段输出包含三个关键动作DeepSeek-V3发起了结构化的tool_callsPageIndex接住并执行了工具把第124页的真实内容回传模型读到内容后给出正确答案还用对了营销服务这个2024年新口径**多轮工具调用的Agent循环在国产模型上是能跑通的。**我上一版给它打的两个不兼容判断全部撤回。至于[tool_call]这段为什么会混进答案里——调用本身是成功的流式输出把工具调用轨迹也当成内容块吐了出来而我的脚本无脑累加了全部chunkforchunkinclient.chat(q[question],doc_iddoc_id,streamTrue):ifisinstance(chunk,str):answerchunk# tool trace 也被拼进了 answer这是调用方的日志处理问题跟框架兼容性无关。7.2 它失败的十三次同一份JSON里q3到q15的错误一模一样一共13条The model backend failed: litellm.RateLimitError: RateLimitError: OpenAIException - Request was rejected due to rate limiting. Details: TPM limit reached.TPM是每分钟token数的速率上限。注意它跟余额是两回事——测完之后我的账户里还剩5.35元限流照样发生因为TPM上限跟着账户档位走跟余额还剩多少无关。PageIndex每次问答是多轮Agent循环一轮输入就要八千多token瞬时消耗远超低档位的TPM。为了确认这不是巧合我用同一个doc_id、同一份代码、同一个模型把请求间隔拉到4秒重跑了5道题[PI] doc_idpi-cmuq5jrky001e09mbxj0na2b9 modelopenai/deepseek-ai/DeepSeek-V3 n5 sleep4s [PI] q1 FAIL ...Request was rejected due to rate limiting [PI] q2 FAIL ...Request was rejected due to rate limiting [PI] q3 FAIL ...Request was rejected due to rate limiting [PI] q4 FAIL ...Request was rejected due to rate limiting [PI] q5 FAIL ...Request was rejected due to rate limiting [PI] success0/5两次实验合起来看q1、q2先成功从q3开始全部失败——这个形状符合滑动窗口限流的特征。一轮Agent循环的消耗把一分钟窗口填满之后后续请求无论怎么重试都会被拒而窗口一重置下一题一进来又立刻把它打满。代码一行没改变的只是每次请求落在窗口的哪个位置。7.3 上一版那个四层兼容性框架怎么改上一版我提了个四层模型说国产模型大多只做到第二层单轮tool callingPageIndex需要第四层。现在看至少DeepSeek-V3完成了第四层要求的完整动作。真正卡住它的是中间的OpenAI兼容层——这里是硅基流动在多轮Agent调用下速率上限TPM会比模型能力更早成为瓶颈。**这个锅怎么定位到硅基流动而不是PageIndex**三个判据报错是litellm.RateLimitError包着OpenAIException ... rate limiting ... TPM limit reached——litellm只是客户端库它转述的是上游OpenAI兼容接口返回的429。PageIndex自己的额度不足不会用TPM这个措辞Cloud索引走的是官方额度170秒跑完全程没报过任何配额错误报错全部集中在问答阶段而问答用的是我自己的硅基流动keytoken从我的账户扣这个区别很重要归因给模型开发者的选项只剩换模型或等厂商改归因给限速选项立刻变成升TPM档位、降并发、错峰跑、自己实现Agent层控制token后者今天就能动手。7.4 索引侧这一条结论没变Cloud模式建274页索引耗时170秒自带OCR不消耗自有token这一条和上一版一致项目PageIndex Cloud自跑向量RAGPyMuPDF建274页索引170秒35.11秒是否消耗自有token否是191,402字符embedding自带OCR是否单次成功问答耗时18.3秒/30.5秒两次样本4.04秒15题平均PageIndex慢得多但它慢的那部分工作理解文档结构正是向量索引不做的。八、国产环境的真实门槛排序测完这一轮如果有人问我国产环境下做一套文档问答先解决什么我的答案变了优先级环节这次踩到的坑后果1解析层pypdf抽0个汉字准确率0%而且看不出原因是解析2评测金标准15题错9题模型答对也判错方向彻底走反3速率限制TPM与并发13/15请求被TPM限流来自硅基流动侧Agent类框架直接不可用4检索策略调优BM25混合反而串了毛利与收入边际收益小于预期5模型/框架兼容性本轮没遇到实质问题之前被错误归因成了主因前两项加起来工作量不到半天但它们决定了后面所有数据的可信度。九、成本与延迟口径这次对了上一版的成本估算有个明显的口径错误这里一并更正。向量RAG修好解析后环节用量单价成本Embedding529 chunk191,402字符约13万token0.1元/百万token约0.013元15次问答DeepSeek-V3约5万输入0.8万输出token1元/百万输入5元/百万输出约0.09元合计——约0.1元数字和上一版接近但这次的191,402字符是真实抽出来的文本不是乱码。PageIndex CloudCloud索引走官方额度问答token自付。按成功样本粗估单轮多轮循环约8000输入500输出token约0.01元/次。这个数字只有参考价值因为总共只跑成功2次样本不足以做统计。上一版那张准确率50%/70%/90%三档的敏感性分析表已经整段删掉——分母错位拿基础组的部分正确率13%“当准确率”算出来的结论没有意义。十、验证边界这篇结论的适用范围我自己先标清楚**样本15题、1份文档、单人评判。**精度有限不能推广到所有中文财报**PageIndex的准确率没有统计意义。**全程只跑成功2次我给不出任何准确率数字只能说在这两次上答对了。要给出数字需要把TPM档位升上去再跑一轮——通常靠充值提升账户等级或者直连模型厂商的官方API——在那之前关于它准确率的一切说法都是推测官方那个98.7%同样是厂商自测我没能复现也没能证伪**Qwen2.5-72B的上下文问题我上一版说错了。**硅基流动同时提供Qwen/Qwen2.5-72B-Instruct32K和Qwen/Qwen2.5-72B-Instruct-128K两个入口我当初只试了前者就下了Qwen只有32K的结论**没有跑rerank组。**平台上有BAAI/bge-reranker-v2-m3可用这次没做它在我上面那张优先级表里排第4位。所以这篇回答不了精排到底能提多少这个问题只能留到下一轮**研发支出那道题口径没锁死。**q8的错更多出在出题口径与模型无关十一、如果你想自己跑一遍这次的脚本都在docker/scripts/下容器pageindex-test可以直接跑# 解析质量自检这一步一定要先跑dockerexecpageindex-test python scripts/_parse_check.py# 对照组基础版 / BM25 混合版dockerexecpageindex-test python scripts/test_vector_rag_v2.py\docs/tencent-2024-annual-report.pdf scripts/questions_v2.json\output/vector_basic_v3.json basic最重要的一条经验**任何RAG评测开始前先打印几个chunk用眼睛看一遍。**这个动作30秒能省掉后面几天的错误归因。RAG链路实测系列系列说明前5篇是经典向量RAG链路四件套加查询路由番外本篇第6篇开始探索下一代架构——无向量、推理型、Agent化检索。#篇目状态1分块策略实测9组配置900次检索Hit1全挤在0.81~0.83已发布2重排序实测500条真实查询精排Hit1 0.364→0.486已发布3生成层实测答案递到嘴边7B还是漏掉一半已发布46,208条答案打分实测判对率94%逐字正确率6%已发布5查询路由实测路由准确率要98.2%才不亏而我测出来最高97.1%已发布6PageIndex没翻车翻车的是我的解析器本篇本篇顺带推荐一篇工程向总结RAG六层架构实践指南哪些层值得做哪些层我实测没跑出差别。相关链接测试脚本与结果数据docker/scripts/与docker/output/测试文档腾讯控股2024年年度报告公开披露文件PageIndex官方文档docs.pageindex.ai下一步我打算补两件事给向量RAG加bge-reranker-v2-m3精排看第4位优先级到底值多少以及把TPM档位升上去重跑PageIndex把它的准确率从2次成功变成一个有统计意义的数字。在那之前如果你正准备给公司做一套文档问答建议的顺序是先用_parse_check.py这类脚本把你的PDF按解析器过一遍看到中文字数再来谈选型。这个顺序反过来你会得到一个很干净的数字和一个完全错误的结论。
返回列表