检索器 × 编排器:我们如何用评测打分给法律合规 RAG 选型

检索器 × 编排器:我们如何用评测打分给法律合规 RAG 选型

我们在为墨西哥、巴西的金融科技公司做一件听起来简单、做起来极难的事:让 AI 回答法律合规问题,每一句结论都贴上可溯源的法条出处。这篇文章讲我们为此搭的 RAG 评测平台——以及一个核心判断:RAG 没有银弹,靠评测在自己的语料上选。

引言:法律 RAG 为什么这么难

把通用 RAG(先检索、后生成)直接搬到法律合规场景,会在四个地方同时翻车:

① 强制溯源,错引比答错更致命。合规问答的硬性验收标准不是"答得对",而是"答得对引得准"。一个结论正确、但挂错法条号的答案,在监管语境里是不可接受的——客户照着它去合规操作,出处错了就是踩雷。这把"引用与结论必须咬合"从加分项变成了准入门槛。

② 低幻觉,模型最爱在没证据时编。大模型在缺乏证据约束时,最容易把甲法的条文记成乙法、把旧版限额当成现行规定、甚至先想好答案再回头凑几句"门面引用"。法律文本对这类幻觉零容忍。

③ 多语言,问题和法条常常不同语种。法条原文是西班牙语或葡萄牙语,用户却可能用中文、英文甚至混着问。多语言 embedding 号称"语言无关",现实里跨语言的向量对齐质量远不如同语言——证据明明在库里,就是检不出来。

④ 相似法规极易混淆。不同国家、不同年份的金融法规措辞高度雷同——"客户尽职调查""可疑交易报告""数据主体权利"这类条文在墨西哥法、巴西法、欧盟 GDPR 里几乎一个模子。裸嵌入后它们在向量空间挤成一团,给墨西哥客户作答却引到巴西的法条,是高频且致命的错误。

面对这些,业界有一堆方案——朴素向量、混合检索、agentic、GraphRAG、上下文检索……每一种都在某些场景闪光、在另一些场景拉胯。我们的判断是:不押注任何单一方案。与其赌一个"最好的 RAG",不如把问题拆成两根正交的轴,做成一张可组合的网格,再用评测打分在我们自己的合规语料上,公平地比出每一种组合到底治了什么、花了多少成本。

架构核心:候选 = 检索器 × 编排器

我们把一个完整的 RAG 流水线拆成两个相互独立的决策维度:

  • 检索器(retriever)——决定"证据从哪来、怎么找"。这是一根轴:从"干脆不查"到"混合检索 + 重排",再到"读懂文档骨架"的结构化检索。
  • 编排器(orchestrator)——决定"LLM 怎么用检索"。这是另一根轴:查一次就答、先锁证据再答、还是多轮自主反复查。

两轴正交,任意组合成一个具体的候选(candidate,c0…c14)。这样做的最大好处是:固定一根轴、变另一根,就能干净地 A/B 出后者的贡献——比如固定 hybrid 检索器,只换编排器,就能精确量出"agentic 比 single-shot 多花的 token 到底换回多少准度"。

检索器 × 编排器 = 候选 的二维网格 横轴是编排器、纵轴是检索器,两轴正交,交叉格子组成具体候选。 候选 = 检索器(纵轴) × 编排器(横轴) 编排器:LLM 怎么用检索 → ← 检索器:证据从哪来 单次检索 引用先行 智能体 无检索 朴素向量 混合+重排 结构化 c0 direct c1 naive c2 hybrid c4 pageindex c11 cite-first c7 dense-ag c5 agentic c6 pgidx-ag 每个交叉格 = 一个候选;固定一轴变另一轴 = 公平 A/B
两轴正交组合成候选;上图只标了部分格子,进阶检索器(跨语言 / 图 / 文档身份)同样落在纵轴上,可与任意编排器组合。

轴①·编排器:LLM 怎么用检索

编排器决定"模型怎么使唤检索"。同一份检索能力,编排得越重、模型来回查得越多,准度可能越高,token 也越贵。我们从最轻的基线一路加码到自主多轮,再用一个"分诊"把成本压回来。

单次检索(single-shot / 我们的 single-shot)

最朴素的基线:查一次、拼好证据、一次性带引用作答。

流程只有一条直线。拿到用户问题,调一次检索器取回 Top-K 证据块(k 一般 5–12),把这些块原文拼进 prompt 的"证据区",让模型读完后一次性输出答案,并要求每句结论后面贴上它依据的块编号。模型只看一次资料、只生成一次,没有回头补查、也没有二次筛选。它是整张"检索器 × 编排器"网格的原点——我们用它当锚,去衡量其它更重的编排到底多花了多少 token、换回了多少准度。

问题 检索一次 取 Top-K 块 拼证据块 大模型作答 一次生成带引用

举例:用户问"SPEI 单笔转账上限是多少?"——这是事实直查类问题,答案就躺在 Banxico 关于 SPEI 的规定里。single-shot 检索一次拿到那一条,模型照着写"单笔无固定上限,但超过特定金额需额外风控核验"并贴上出处,干净利落。对这种一问一答、证据集中的场景,再上更重的编排纯属浪费——这也是为什么基线值得认真对待:很大一部分合规查询本就不需要更多。

相关论文/来源:基线编排,无专门论文——它是 RAG 的标准范式(先检索后生成),我们把它实现为可对照的锚点。

引用先行(citation-first / citation-first)

先挑出真正支持答案的最小证据集,再只依据选中片段逐条引用作答——专治"先编答案再凑引用"。

朴素编排有个隐患:模型常常先在脑子里想好答案,再回头从证据里挑几句话当"门面引用",于是引用看着齐全、实际跟结论对不上(hallucinated citation)。引用先行把顺序倒过来,分两步走。第一步是"选证据":让模型逐条审视检索回来的片段,只标出真正能支撑回答的那几句,宁缺毋滥——选不出来就如实说证据不足,而不是硬凑。第二步是"据此作答":把模型的视野锁死在被选中的片段上,让它一句结论对一处出处地写。因为答案是从证据长出来的、而不是反过来,引用和结论天然咬合。

问题 检索片段 候选证据 ①挑最小证据集 宁缺毋滥 ②仅据选中片段 逐条引用作答 先锁证据,再生成 → 引用与结论咬合

举例:用户问"客户单笔现金存入 60 万比索,机构需要上报吗?"在巴西,这归 Lei 9.613/1998(反洗钱法)和 COAF 的申报门槛管。检索回来一堆片段里既有真正的门槛条款,也有相邻的、看着相关其实不适用的条文。朴素编排可能先认定"要上报"再随手挂个条号;引用先行则强制模型先圈定"哪一条具体规定了这个金额门槛",圈不准就降级为"证据不足、建议人工复核"。对强制溯源的合规问答,这一步把"答案对但引用错"这类最危险的错配挡在门外。

相关论文/来源:Attribute First, then Generate: Locally-attributable Grounded Text Generation(ACL 2024)——先做内容选择、再据所选片段生成,使被选片段同时充当细粒度引用,正是我们 citation-first 的思想种子。

智能体(agentic / agentic)

模型多轮自主检索——搜知识库、读全文、查外部判例——证据够了再带引用作答;有轮数上限和早停防 token 爆炸。

前两种编排都"只检索一次"。但难题往往一次查不全:查到一部法规,发现它引用了另一部;读了条文摘要,还得调出全文确认例外条款。agentic 把检索变成一个由模型驱动的循环——它一边推理"我还缺什么证据",一边自己发起下一次检索动作(搜知识库 / 读某篇全文 / 查外部判例库),拿到结果接着推理,直到判断证据足够,才停下来带引用作答。这正是 ReAct 式"推理—行动交错"的范式,叠加 Self-RAG 那种"按需检索 + 自我反思是否够了"的判断。它最强,也最贵:每一轮都把累积的上下文重新喂一遍,token 是平方级长的。所以我们卡死两道闸:轮数 ≤ 8,且一旦模型判断证据已足就早停,不让它无意义地空转烧钱。

问题 推理:还缺什么? 决定下一步动作 检索动作 搜库/读全文/查判例 证据不足则再来一轮(≤ 8 轮,早停) 证据已足 带引用作答

举例:用户问"一家墨西哥金融科技公司(ITF)向客户提供加密资产托管,在 KYC 和可疑交易上报上要同时满足哪些义务?"这题跨好几部法:Ley Fintech 本体、其反洗钱二级细则、CNBV 的通函、以及加密资产相关的特别限制。agentic 先查 Ley Fintech 找到框架,发现它把细则下放给二级法规,于是再去检索那部细则;读到 KYC 门槛后又意识到加密托管有额外条款,再补查一轮 CNBV 通函;凑齐后才综合作答并逐条挂出处。single-shot 在这种"一查带出三查"的链式问题上必然漏证据,而 agentic 能自己把链走完——代价是 token,所以我们用早停和轮数上限给它套缰绳。

相关论文/来源:ReAct: Synergizing Reasoning and Acting in Language Models(2022/ICLR 2023,推理—行动交错的 tool-loop 范式);Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection(2023,按需检索 + 自我反思是否已足,正是我们早停判断的依据)。

自适应路由(adaptive-route / adaptive-route)

先用一次廉价模型判问题难易,简单合规查找走 single-shot,难题才升级 agentic——治 agentic 在简单题上动辄烧十几万到三十几万 token 的浪费。

agentic 强但贵,而真实流量里大多数问题其实很简单。如果不分青红皂白都跑 agentic,简单题也被拖进多轮循环,单题能烧到 16 万–33 万 token。adaptive-route 在最前面加一道极便宜的分诊:用一次廉价的大模型调用,只给问题判个难易档(简单 / 中等 / 难)——它不写答案、只做分类,所以又快又省。然后据档分流:简单的事实直查走 single-shot,中等的走引用先行,只有真正需要跨多部法规来回推理核对的难题,才升级到多轮 agentic。一句话:把"重武器"留给真正配得上它的那一小撮问题,平均成本被简单题大幅拉低,而难题的准度一点不让。

问题 判难易 一次廉价分类 简单 → 单次检索 中等 → 引用先行 难 → 多轮智能体 答案

举例:同一个问答系统里同时来两条问题。一条是"巴西 LGPD 下数据主体有几项基本权利?"——分诊判为简单,走 single-shot,查一次 Lei 13.709 列举即可,几千 token 搞定。另一条是前面那道"墨西哥 ITF 加密托管的 KYC + 可疑交易上报义务"——分诊判为难,才放给 agentic 去多轮跑。如果两条都无脑跑 agentic,前者会为了一个能一句话答完的问题白白烧掉十几万 token;adaptive-route 让简单题轻量答、把昂贵的多轮预算只花在真正难的那条上,平均成本立刻降下来。

相关论文/来源:Adaptive-RAG: Learning to Adapt Retrieval-Augmented Large Language Models through Question Complexity(NAACL 2024)——按问题复杂度动态选择检索/生成策略,正是我们 adaptive-route 的直接思想来源。


轴②·基础检索器

检索器是候选的第一根轴——它只回答一件事:「证据从哪来、怎么找」。下面三个是地基级的检索器,从「干脆不查」到「查得又快又准」,逐级加码。后面所有更花哨的检索器(引用图、跨语言扩展、文档级摘要……)都是在 hybrid 这个底座上长出来的,所以这三个一定要先吃透。

无检索(none)

什么都不查,纯靠模型「脑子里记的」作答——它存在的唯一意义是当对照基线。

这一档把检索整条关掉:用户的问题直接丢给大模型,模型凭训练时见过的语料(它的「内参记忆」)张口就答,不给它看任何法条原文。听起来很糙,但它是整个评测网格里最重要的一根标尺——只有先量出「不查资料能对几道题」,我们才能反过来说清楚「加了检索到底带来多少提升」。如果某个真实场景里 none 和带检索的候选打平,那说明这类问题模型本来就会,检索是白花的成本;反过来如果 none 一塌糊涂,就证明检索是刚需。它同时也是「幻觉地板」:模型在没有证据约束时最容易把甲法的条文记成乙法、把旧版限额当成现行。

问题 大模型凭记忆 直接作答(不查) 答案 没有任何外部证据进入这条链路

举例:问「墨西哥 SPEI 单笔转账有没有金额上限?」none 候选只能靠模型记忆答——它可能信誓旦旦报一个具体数字,但那很可能是某个旧版本或干脆混淆了别国制度,且给不出任何条文出处。在「强制引用溯源」是硬性验收标准的合规问答里,这种答案直接不合格。它的价值不在于答对,而在于让评测分数里多一条「地板线」,证明检索器组的提升是真实的、不是错觉。

相关论文/来源:无(这是对照基线,不对应任何检索方法)。我们的检索器 id:none

朴素向量(dense)

把每段法规和问题都翻译成一串「意思坐标」,按语义相似度召回最接近的若干段。

这是大多数人印象里的「RAG 检索」。建库阶段,我们把全部 8002 个法规文段逐段送进嵌入模型(embedding model,我们用 Jina embeddings v3),每段被压成一个 1024 维向量——可以理解为给这段话在「语义空间」里钉了一个坐标,意思相近的段落坐标也挨得近。这些向量预先算好,存进 PostgreSQL 的 pgvector 扩展,并建 HNSW 索引(一种近邻图,让「在百万级向量里找最近邻」从逐个比对变成顺着图跳几步就到,毫秒级返回)。查询时,把用户问题用同一个模型算成向量,去库里取坐标最近的若干段当证据。它的好处是不怕换说法:用户问「怎么报告可疑交易」,能命中写着「异常操作上报义务」的条款,哪怕一个字都不重合。它的死穴是精确符号——法条编号、机构简称这类「字面要对上」的东西,按意思找反而容易漏。

问题 嵌入模型 算成 1024 维向量 pgvector 向量库 8002 段·HNSW 索引 取语义最近若干段 证据 弱点:法条号、机构简称这类「精确词」按意思找容易漏

举例:巴西用户问「客户身份没核实清楚,平台要承担什么反洗钱责任?」——他没提任何法条号。dense 能凭语义把巴西反洗钱法(Lei 9.613/1998)里讲「客户尽职调查与上报义务」的段落捞出来,哪怕问句里没出现「9.613」「PLD」这些字眼。这正是纯关键词搜索做不到的:换个说法就搜不到。但反过来,如果用户精确地问「Lei 9.613 第 11 条具体怎么规定」,dense 反而可能把「第 11 条」漏掉而召回一堆语义相近的别的条——这就引出了下一个检索器。

相关论文/来源:jina-embeddings-v3: Multilingual Embeddings With Task LoRA(2024,Jina AI)。我们用它的多语言嵌入能力覆盖西/葡/英/中四语,默认 1024 维。我们的检索器 id:dense

混合 + 重排(hybrid)

语义召回 + 词面召回两路并行,RRF 融合成一份榜单,再请重排模型精读筛出 top-8——又快又准的底座。

这是我们网格里的主力底座,专治 dense 的死穴。它同时跑两条召回腿:第一条还是上面的语义召回(pgvector,按意思取前 30 段);第二条是 Postgres 全文检索tsvector,本质就是 BM25 那一类按词面打分的搜索引擎,西/葡语会自动做词形归一,比如 fracciónfracciones 算同一个词),它把「字面要对上」的精确词——法条编号、法规简称、专有术语——稳稳抓住,正好补语义召回漏掉的部分。两条腿各交一份排名后,用 RRF(Reciprocal Rank Fusion,互惠排名融合)合并:每段的得分 = 各路里「1 ÷(排名 + k)」之和(我们取 k=60,一个平滑常数,作用是别让任何单路的第一名一家独大)。RRF 的妙处是只看名次、不看原始分——语义相似度和 BM25 分根本不在一个量纲,硬加会乱套,按排名融合天然规避了这个问题。融合出一份候选后,最后请一个专门的 reranker(重排模型)把每段与问题逐段精读、重新打分,只留最相关的 8 段当最终证据:前面两路粗筛求「召回全」,这一步复审求「排得准」。

问题 语义召回(向量) 按意思取前 30 段 全文检索(BM25) 按词面取前 30 段 RRF 合并 按名次融合·k=60 重排精选 复审留 top-8 两路粗筛求「召回全」 → RRF 抹平量纲 → 重排求「排得准」

举例:墨西哥用户问「LFPDPPP 第 109 条对未经同意处理个人金融数据的罚则是什么?」这句话里「LFPDPPP 第 109 条」是命门。纯 dense 很可能召回一堆语义上都在讲「个人数据保护与处罚」的相邻条文,却恰好把第 109 条本身排在后面甚至漏掉——因为「109」这个数字在语义空间里几乎不携带信息。hybrid 的全文检索那条腿会精确锁定带「109」「LFPDPPP」字样的段落把它顶上来,语义腿同时保证「罚则/同意/金融数据」的上下文不丢,RRF 融合后重排再把最对题的 8 段拣出来。结果就是:精确法条号不漏,语义上下文也全——这正是合规问答里「答得对还得引得准」的刚需。

相关论文/来源:融合算法出自 Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods(Cormack et al., SIGIR 2009)。语义腿沿用上面的 Jina v3;全文检索为 Postgres 原生 tsvector;重排为独立 reranker 模型。两路召回 + RRF + 重排的串联是我们的实现。我们的检索器 id:hybrid


轴②·进阶混合检索(免重建 / 索引增强)

基础的 hybrid 检索(BM25 关键词 + dense 向量并联,再融合)已经能扛住大部分常规问答。但在跨语言、跨术语、跨指代这三种"问题和法条对不上号"的隐藏失分场景里,朴素 hybrid 会安静地漏召回——证据明明在库里,就是检不出来。下面三个检索器分别从查询侧翻译查询侧扩展索引侧增强三个角度补这个缺口。前两个免重建索引(只改查询),第三个需要在建库时多花一次 LLM 调用。

跨语言桥接(hybrid-xlingual)

先把用户的问题翻译到法条所在的辖区语言,再用译文去查 dense 向量,修"问题和法条不同语言、向量根本对不上"的最大隐藏失分。

在墨西哥/巴西的合规场景里,法条原文是西班牙语或葡萄牙语,但用户可能用中文、英文甚至混着问。多语言 embedding 模型号称"语言无关",可现实是:跨语言的向量对齐质量远不如同语言。一个中文问题的向量,和一条西语法条的向量,余弦相似度往往莫名偏低——不是语义不相关,纯粹是模型的跨语言桥没搭稳。结果就是 dense 腿明明该召回的法条沉了底。

这个检索器的做法很直接:在检索之前,先用一个轻量翻译步骤把问题改写成辖区的官方语言(西/葡),然后用译文去生成查询向量。这样 dense 腿就变成了"同语言对同语言"的检索,跨语言对齐的损耗被消掉。关键词 BM25 腿同样吃译文(法律术语翻译后才能字面命中法条用词)。注意它不动索引,只动查询那一侧,所以是零重建成本的改造。

用户问题 (中/英) 翻译到辖区语言 (西/葡) dense 腿(译文嵌入) 同语言对同语言 BM25 腿(译文关键词) 命中法条用词

举例:用户用中文问"墨西哥的 SPEI 转账每天有金额上限吗?"。朴素 hybrid 拿中文向量去撞 Banxico 的西语条文,dense 腿相似度偏低、漏召回。桥接版先把问题翻成 "¿Existe un límite diario por operación en transferencias SPEI?",用西语向量检索,直接命中 Banco de México 关于 SPEI 操作限额的西语规定;同时 BM25 用 "SPEI / límite / transferencia" 这些法条原词字面命中。一次翻译,就把一条本来检不出的核心证据捞了回来。

相关论文/来源:无单一标准论文。跨语言 dense 检索的对齐难题与多语言 embedding 现状见 Multilingual E5 Text Embeddings: A Technical Report(2024);"查询侧先翻译再检索"的工程组合是我们的实现

法律推理扩展(hybrid-legalexpand)

先让模型把口语化的问题扩展成一条"法律检索式"——补齐同义法条术语、相关概念、关联制度——再拿扩展后的查询去检索,把召回率拉上来。

普通用户不会用法言法语提问。他们说"洗钱要报多少钱以上的",而法条里写的是"操作可疑(operaciones inusuales)"、"门槛额度(umbral)"、"金融情报单位(UIF)申报义务"。这两套词汇的字面和向量都对不齐,dense 和 BM25 双双吃瘪。法律检索的召回缺口,很大一部分就卡在这个"外行话 ↔ 专业术语"的鸿沟上。

扩展检索器在检索前插一步:用模型读懂用户的真实意图,把口语问题改写/扩写成一段带专业术语的检索查询——补上同义的法定表述、相关的法条编号线索、上位概念和并列概念。然后用这段"加料"后的查询去跑 hybrid。它和上一个跨语言桥接正交:一个解决"语言不对",一个解决"术语层级不对",两者可以叠加(先扩展、再翻译)。同样只改查询、不重建索引。

口语问题 "洗钱报多少钱" 模型扩成法律检索式 补同义术语 / 概念 / 法条线索 hybrid 检索 召回率↑

举例:用户问"巴西这边给客户做尽调要查到什么程度?"。直接检索几乎只能撞到字面带"尽调"的零散内容。扩展器把它改写成带专业表述的查询:"devida diligência / conheça seu cliente (KYC) / dever de identificação de clientes 依据 Lei 9.613/1998(巴西反洗钱法)及 COAF 规定下的客户身份识别与持续监控义务"。补进 "Lei 9.613"、"COAF"、"KYC"、"PEP(政治公众人物)" 这些法定术语后,dense 与 BM25 都能命中真正规定 CDD 义务的条文,而不是停在用户的大白话上。

相关论文/来源:借鉴 Stanford RegLab 关于法律 RAG 召回与可靠性的研究——Hallucination-Free? Assessing the Reliability of Leading AI Legal Research Tools(Magesh et al., 2024)指出法律检索失败常源于查询与法条表述错位,强调检索质量是抑制幻觉的前提;"模型把问题扩成法律检索式"的具体落地是我们的实现

上下文索引(hybrid-contextual)

建索引时,给每个切片前置一段 LLM 生成的"这段在全文里讲的是什么"的语境前缀再做嵌入,让向量自带文档级语境,治"本条 / 该机构 / 前述情形"这类指代漂移。

法律文本被切成小片段后,最大的问题是指代失锚。一个孤立片段写着"违反本条第二款的,处以前条规定罚款的两倍"——"本条""前条"指谁,离开上下文就成了悬空指针。这种片段嵌进向量库后,既检不准(向量里没有"这是哪部法、哪一条"的信息),就算检出来 LLM 也没法安全引用。前两个方法改查询侧,这个方法改的是索引侧

做法:建库时对每个切片,先调一次 LLM,让它读"完整文档 + 这个切片",生成一句话语境说明("本切片出自《XX 法》第 N 条关于 YY 的规定,前文在讲 ZZ"),把这句前缀拼到切片前面再去嵌入、也一并进 BM25 索引。这样向量就带上了文档级坐标,孤立片段被重新"锚定"回它在全文中的位置。代价是建库时每片多一次 LLM 调用(可用 prompt caching 把整篇文档缓存住、对各切片复用,压成本),但这是一次性离线开销,查询时零额外成本。

建索引阶段(一次性离线) 完整法律文档 切成片段 孤立片段 "违反本条…" LLM 生成语境前缀 "出自《XX法》第N条…" 前缀 + 片段 → 嵌入 & BM25 入库 向量自带文档坐标 指代被重新锚定

举例:《LFPDPPP》(墨西哥联邦个人数据保护法)里有一条片段写"违反前述义务的,由主管机关处以……,加重情形按本法第六十四条加倍"。裸切片嵌进库,"前述义务""主管机关"全是悬空的——用户问"墨西哥个人数据泄露不通知会被罚多少"时根本检不到它。上下文索引在建库时给它加前缀:"本片段出自 LFPDPPP 关于安全义务与处罚的章节,前文规定了数据控制者的泄露通知义务,主管机关指 INAI。"加锚后,这条片段既能被"数据泄露/通知/罚款"召回,LLM 也能直接溯源到具体法条做引用。

相关论文/来源:Introducing Contextual Retrieval(Anthropic, 2024)——给每个 chunk 前置 LLM 生成的语境再做 Contextual Embeddings 与 Contextual BM25,官方报告检索失败率下降约 49%(叠加 reranking 达 67%)。我们把该思路适配到法律文本的条文指代锚定。


轴②·结构化检索(树 / 图 / 文档身份)

把法规当成有结构的文书来检索——目录树、引用关系、文档身份,而不是一堆打散的向量碎片。

大多数 RAG 把文档切成几百字一块的 chunk,再各自嵌成向量,文档原本的结构(这一段属于哪一章、哪一条引了哪一条、这块文字出自哪部法)全丢了。法律文本恰恰最吃这层结构:律师查法不是「语义最相似」,而是顺着目录翻、顺着「依据第 X 条」跳、还要分清同名条款到底出自哪部法。下面三个检索器各补一条结构线索——(pageindex)、(citation-graph)、文档身份(hybrid-sac)。

目录树导航(PageIndex / pageindex

无向量、无切块:把每篇法规建成一棵带摘要的目录树,让大模型像律师翻书一样在树上一层层选中相关条文。

建索引时不做嵌入,而是把整篇文档解析成一棵 目录树(JSON outline):编 → 章 → 节 → 条,每个节点带上「标题 + 一句话摘要」。查询时不算余弦相似度,而是把这棵树的骨架交给大模型,让它先看目录决定「该翻到哪一章」,逐层下钻,最后只取中选节点的原文。整个过程是推理式的——模型给得出「为什么选这条」的理由,每一步都可回溯,天然契合「强制引用溯源」的合规要求。代价是每次检索要多轮模型调用,更慢更贵,适合长、结构清晰的单部法规,不适合海量短文档。

PageIndex 目录树导航流程 大模型先看法规目录树,逐层下钻选中相关条文,再取出原文作答。 用户问题 法规目录树(节点带标题+摘要) 反洗钱法(根) 第二章 主体义务 第三章 报告 第 12 条 限额上报 大模型逐层导航 取原文作答

举例:墨西哥客户问「单笔现金存款超过多少要向 CNBV 上报?」朴素向量检索会把全库里所有提到「现金 / 上报 / 限额」的碎片都捞上来,混进商业银行内规、旧版通函。PageIndex 让模型先认准《反洗钱法》(Ley Federal para la Prevención e Identificación de Operaciones con Recursos de Procedencia Ilícita)这一部,再沿目录下钻到「报告义务」那一章、定位到具体条款,取出整条原文。答案带着「编-章-条」路径,引用溯源天然成立,不会把别的法的限额张冠李戴。

相关论文/来源:PageIndex: Vectorless, Reasoning-based RAG(VectifyAI,官方仓库)(2025),官网 pageindex.ai。我们的 pageindex 检索器是按其「目录树 + 推理式导航」思路在法规域上的实现。

引用图多跳(Citation Graph / citation-graph

纯正则、零模型:把法条里「依据第 X 条 / 参见 Lei Y」解析成有向引用图,命中片段后沿引用边把被引的上位母法也一并拉进来。

建索引时跑一遍确定性正则,扫描所有「依据本法第 X 条」「参见 Lei nº 9.613」「nos termos do art. 11」这类交叉引用,抽成一张「谁引用谁」的有向图,落进 doc_citations 边表。检索分两步:先用普通的混合检索(向量 + BM25)命中最相关的若干片段,再沿引用边外扩一跳——把这些片段引用到的上位法条、母法定义也补进证据集。这治的是「答案漏了被引母法」:很多法条本身只是个壳,真正的定义和罚则藏在它引用的另一条里。它借鉴 GraphRAG 的图思路,但刻意做成确定性正则版、不用 LLM 抽取——边是规则解析出来的,可逐条核验、可复现、零模型成本,避免 LLM 抽关系时的幻觉边。

Citation Graph 引用图多跳流程 正则解析法条交叉引用建有向图,混合检索命中片段后沿引用边外扩拉入被引母法。 混合检索命中 第 11 条片段 doc_citations 有向引用图(正则解析) art. 11 报告义务 art. 1º 洗钱 定义(母法) 依据 art.1º 证据集 = 命中片段 + 沿边外扩的 被引母法

举例:巴西客户问「金融机构未上报可疑交易,法律后果是什么?」混合检索命中《反洗钱法》(Lei nº 9.613/1998)第 11 条「报告义务」,但第 11 条只说「依据第 1 条所定义之犯罪……应上报」,真正的「洗钱罪定义」和罚则在它引用的第 1 条。若不外扩,模型只看到「要上报」却说不清「不报会怎样、针对哪类犯罪」,答案残缺。引用图沿 art. 11 → art. 1º 这条边把母法定义一并拉进证据集,模型才能给出完整、可引用的链条。

相关论文/来源:借鉴自 Microsoft GraphRAG — From Local to Global: A Graph RAG Approach to Query-Focused Summarization(2024)的图增强检索思路。区别:GraphRAG 用 LLM 抽取实体与关系建图,我们的 citation-graph确定性正则版、非 LLM 抽取——只解析法条显式交叉引用,边可逐条核验、零模型成本。

混合 · 文档级摘要前缀(Hybrid-SAC / hybrid-sac,SAC = Summary-Augmented Chunking)

嵌入前给每个片段前置一句「来自哪部法、哪个辖区」的文档级身份摘要,让长得像的相似法规片段按「出处」分开,治跨库误归因。

问题根源:不同国家、不同年份的金融法规,措辞高度雷同——「客户尽职调查」「可疑交易报告」「数据主体权利」这类条文在墨西哥法、巴西法、欧盟 GDPR 里几乎一个模子。把它们各自切块、裸嵌入,向量空间里就挤成一团,检索时极易把巴西的条文当成墨西哥的捞回来,造成跨库误归因。SAC 的做法:建索引时先为每个片段生成一句文档级身份摘要(「本段出自巴西《通用数据保护法》LGPD 第 18 条,关于数据主体权利」),把这句话前置到片段正文再做嵌入。于是「内容相似但出处不同」的片段在向量空间里被身份信息推开,检索按出处区分。这是「混合」检索(向量 + 关键词)叠加文档级语境增强,没有单一标准论文,思路上对齐 Anthropic 的 Contextual Retrieval。

Hybrid-SAC 文档级摘要前缀流程 嵌入前给每个片段前置文档级身份摘要,让相似但出处不同的法规片段在向量空间被推开。 原始片段(内容雷同) 「数据主体有权访问…」 「数据主体有权访问…」 前置身份摘要再嵌入 [巴西·LGPD 第18条] 前置身份摘要再嵌入 [墨西哥·LFPDPPP] 向量空间按出处分开 BR MX 被推开 检索不再误归因

举例:问「数据主体行使删除权(derecho de supresión / direito de eliminação)的法定时限?」墨西哥 LFPDPPP 和巴西 LGPD 都有几乎一字不差的条款。裸嵌入时两国片段在向量空间贴在一起,给墨西哥客户作答却很可能引到巴西 LGPD 的条文与时限——合规答案错引法源,是致命问题。SAC 把「[巴西·LGPD 第18条]」「[墨西哥·LFPDPPP]」的身份前缀写进嵌入,两簇片段被推开,检索按辖区命中正确法源,引用溯源指向对的那部法。

相关论文/来源:借鉴文档级语境增强思路 ——Anthropic «Introducing Contextual Retrieval»(2024,嵌入前为每个 chunk 前置文档级上下文)。hybrid-sac 是我们在法律多辖区场景下的实现:身份摘要聚焦「哪部法 / 哪个辖区」以治跨库误归因,并与关键词检索做混合。


14 个候选组合一览表

把上面两根轴交叉起来,就得到下面这张候选清单。每一行就是一个具体的「检索器 × 编排器」组合,最右一列写明它专门治什么。评测平台逐个跑这些候选,在我们自己的合规语料上打分——没有一个是「天然最优」,谁胜谁负由数据说了算。

候选 id 检索器 编排器 一句话治什么
c0-direct none(无检索) single-shot 对照地板线:量出「不查资料」能答对多少,凸显检索的真实增益
c1-naive dense(朴素向量) single-shot 最小可用 RAG:语义召回能换说法,但精确法条号易漏
c2-hybrid hybrid(混合+重排) single-shot 主力底座:语义 + 词面双路 + RRF + 重排,精确号与上下文都不漏
c4-pageindex pageindex(目录树) single-shot 长法规结构化导航,答案带「编-章-条」路径,溯源天然成立
c5-agentic hybrid agentic(智能体) 链式难题「一查带出三查」,模型自主多轮把证据链走完
c6-pageindex-agentic pageindex agentic 结构化导航 + 多轮自主,跨章节、跨条款的复杂法规推理
c7-dense-agentic dense agentic 消融对照:固定 agentic、退回纯向量,量出 hybrid 那条腿的贡献
c8-hybrid-xlingual hybrid-xlingual(跨语言桥接) single-shot 问题与法条不同语种,先翻译到辖区语言再检索,修跨语言漏召回
c9-hybrid-legalexpand hybrid-legalexpand(法律扩展) single-shot 口语 ↔ 专业术语鸿沟,模型把问题扩成法律检索式提召回
c10-hybrid-contextual hybrid-contextual(上下文索引) single-shot 切片指代失锚(本条/前条/该机构),建库时给片段加文档级语境前缀
c11-citation-first hybrid citation-first(引用先行) 先锁最小证据集再作答,专治「先编答案再凑引用」的错配
c12-adaptive hybrid adaptive-route(自适应路由) 先廉价分诊难易再分流,治 agentic 在简单题上的 token 浪费
c13-citation-graph citation-graph(引用图) single-shot 答案漏被引母法,正则建引用图、命中后沿边外扩拉入母法定义
c14-sac hybrid-sac(文档级摘要前缀) single-shot 相似法规跨库误归因,身份摘要把不同辖区的雷同条文在向量空间推开

评测方法学:三层判定

有了候选,下一个问题是:怎么公平地给它们打分?合规问答的评判维度多——引用对不对、答得全不全、推理稳不稳、语言匹不匹配——全靠一个大模型裁判一锤定音,既贵又不稳。我们把判定拆成三层,由廉到贵、由确定到主观,能用便宜手段定下来的就绝不动用昂贵裁判。

三层评测判定流程 L0 确定性检查、L1 便宜 entailment、L2 跨家族裁判,由廉到贵逐层升级。 L0 确定性 引用解析/存在性 逐字/语言匹配 L1 便宜 entailment 结论是否被证据蕴含 小模型批量过滤 L2 跨家族裁判 qwen3.7-max · A/B 换位 4 维 pairwise 加权 引用.35 质量.35 推理.2 风格.1 由廉到贵、由确定到主观:前层能判的不进后层 L0 硬性卡门(引用错直接出局)→ L1 批量筛 → L2 才上重裁判
L0 · 确定性检查(最便宜,纯代码、零模型)。不调任何模型,用规则就能判死的先判死:引用解析(答案里的引用格式能不能被解析成结构化的「法名 + 条号」)、存在性(被引的法条在语料库里是否真实存在,杜绝凭空捏造的条号)、逐字核对(引文是否与原文逐字一致,还是被模型篡改)、语言匹配(回答语言是否与用户提问语言一致)。这一层是硬性卡门——引用解析失败或引到不存在的法条,无论答案内容多漂亮,直接出局。合规场景下「错引法源」比「答不全」更危险,所以把它放在最前、用零成本手段先筛。
L1 · 便宜 entailment(中等成本,小模型批量)。L0 通过后,用一个便宜的小模型做蕴含判断(entailment):答案里的每条结论,是否真的能被它所引的证据片段逻辑蕴含?这一步抓的是「引用存在且格式正确,但片段其实支撑不了这句结论」的隐性幻觉。因为是批量、便宜的二分类式判断,可以对所有候选的所有结论铺开跑,把明显不成立的过滤掉,再把剩下的交给最贵的一层。
L2 · 跨家族裁判(最贵,大模型 pairwise)。只有过了前两层的答案,才值得动用最贵的裁判。我们用 qwen3.7-max 做裁判——刻意选一个和被测生成模型不同家族的模型,避免「自己人偏袒自己人」的自评偏置。判定方式是 pairwise(两两对比)+ A/B 换位:同一对答案以 A/B 和 B/A 两种顺序各判一次,消掉位置偏好(裁判模型天然偏爱排在前面的)。打分按四个维度加权citation(引用准确性,权重 .35)quality(答案质量/完备性,.35)reasoning(推理严谨度,.2)style(表达风格,.1)。权重分配本身就是我们价值观的编码——引用和质量并列最高、风格垫底,因为在合规场景里「引得准、答得全」远比「写得漂亮」重要。

这套分层不是我们凭空发明的,方法学上站在几项公开工作的肩膀上:RAGAS(无需人工标注、用指标自动评 RAG 的 faithfulness / context relevance,启发了我们 L1 的蕴含判断)、LegalBench-RAG(法律域 RAG 检索基准,强调抽取「最小、最相关」片段以降低成本、提升引用准确——正是我们 citation-first 和 L0 逐字核对的同源动机)、以及 ALCE(带引用生成的自动评测基准,从 fluency / correctness / citation 三个面打分,与我们 L2 的多维加权一脉相承)。区别在于:我们把这些思路分层成本化,并针对法律合规把「引用正确性」提到硬门槛和最高权重。


结语:银弹不存在,评测才是

读到这里,你应该已经感觉到了——上面 14 个候选,没有一个能在所有场景里通吃。none 是地板,hybrid 是稳妥底座,agentic 在链式难题上无可替代却烧钱,pageindex 在长法规上溯源漂亮却慢,hybrid-sac 专治跨库误归因、对单辖区却是过度设计。每一个都是某个具体失分场景的解药,也都有它不该被用的地方。

这正是我们不押单一方案、把架构拆成「检索器 × 编排器」可组合网格的原因:真实世界的合规语料、问题分布、辖区构成,决定了哪个组合在你的场景里胜出——而这件事无法靠读论文或拍脑袋决定,只能靠在自己的数据上跑评测、看分数。三层判定让这种比较既便宜又可信:L0 把错引法源的答案零成本挡在门外,L1 批量筛掉支撑不住的结论,L2 才用跨家族裁判做最后的多维裁决。

所以我们交付的从来不是「一个最好的 RAG」,而是一台能在你的语料上、为你的问题分布,公平地选出最好 RAG 的评测机器。方案会过时、论文会迭代、模型会换代——但「用评测在自己的场景里选型」这个方法本身,不会。银弹不存在,评测才是。

感谢您的收看 祝你天天开心~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇