本篇目标:只讲一条主线——用户提一个问题,平台怎么从几十万分块里把最相关的几块捞出来,拼成证据,生成一个带引用的答案。每一步解决什么问题、关键技术怎么实现、踩过哪些坑。


企业AI 平台从 0 到 1(三):一个问题进来,怎么捞到答案——混合检索与 RAG 深度工程

上一篇我们讲完了知识入库:文件被切成一个个 800 字左右的分块,向量进向量库,正文进关键词索引。这一篇讲检索侧:

问题预处理 → 多路召回 → 分数融合 → 精排 Rerank → 证据组装 → 有据合成 → 带引用返回

一个工程师问"容灾切换的 RTO 要求是多少",几秒后 AI 给出答案,末尾跟着 1-2 个引用来源。这个"几秒"里发生了下面这一整条流水线:

用户问题

① 问题预处理
清洗 / 槽位 / 意图 / 查询扩展 / 多轮消歧

② 多路召回
向量检索 + BM25 关键词
(条件启用:语义 BM25 / 扩展向量)

③ 分数融合
RRF + 加权 + 软加权
(加一路绝不能降分)

④ 精排 Rerank
证据文本 + 多模型融合

⑤ 证据组装
去重 / 邻居扩展 / 按文档分组

⑥ 证据门控
证据不足 → 诚实拒答

⑦ 有据合成
低温生成 + 引用对齐

答案 + 来源引用

下面顺着这条线一站一站走。


一、问题预处理:先听懂问题,再检索

直接拿原话去检索是新手做法。用户的话里有语气词、有指代、有"用英文输出"这种格式指令,甚至有同义词。平台先做五件事:

1.1 清洗

去 emoji、去尾缀语气词(“啊”“呢”)、合并多余空白——把"请问一下,这个系统的备份策略是什么呢?"这种句子洗干净。

1.2 槽位抽取

从问题里识别结构化实体:单据编号、错误码、模块名、主机名。这些实体不是普通关键词——它们有明确指代,后面融合阶段会单独加权(第四节细讲)。

1.3 意图分类与查询扩展

判断问题意图(查询类 / 流程类 / 列表类……),然后做查询变换:

  • 同义词扩展:把领域内同义词/上下位词展开成多组查询;
  • 多查询:同一问题改写多个角度;
  • 可选 HyDE:先让模型"猜一个假设回答",用这个回答再检索一次(HyDE 是显式开启的路径,不是默认行为——因为成本高、不是每个问题都值得)。

最后所有结果打包成一个 QueryPlan:清洗后的检索句、槽位、意图、扩展查询、元数据过滤条件、标签提示、查询语言。RAG / 数据库 / 智能体三条链路共用同一份 Plan,保证"同一个问题"在语义建模上口径一致。

1.4 多轮消歧:把"它"翻译成主题

最难的是指代。用户先问"考勤制度有哪些",接着"用英文输出"——第二个问题没有主题词。

平台的规则式消歧(不调模型,快且稳):

  • "用英文输出"是纯格式指令 → 自动取上一轮用户问题当主题;
  • "用英文输出考勤制度"是前缀格式指令 + 主题 → 剥离前缀,用"考勤制度"检索;
  • "团队有哪些考勤制度,用英文输出"是后置指令 → 分段后移除指令段,保留主题段;
  • 主题段里再压缩掉疑问词(“有哪些”“怎么”),留下真正的关键词。

一句话:把"格式要求"和"检索主题"分开——语言指令管输出,主题词管检索,互不污染。

1.5 语言过滤

问题语言先检测(中/英/葡),检索时按语言偏好过滤候选(默认"偏好"模式),避免一个中文问题捞回一堆英文分块。


二、多路召回:向量 + 关键词,各干各的

这是本平台检索的核心工程决策。先问一个朴素问题:为什么不能只用向量检索?

看两个真实场景:

  • 用户问"RTO 是多少"——"RTO"是精确标识符,向量相似度可能把它当成普通词;
  • 用户问"怎么处理超时"——问法千变万化,关键词很难全部命中。

向量擅长"语义近似",关键词擅长"精确匹配"。单靠任何一路都会漏。所以平台默认跑两路,按条件再加路:

路径干什么默认状态
向量检索语义近似(query 向量 × 分块向量)✅ 常开
BM25 关键词精确/词面匹配(ES 分词全文检索)✅ 常开
语义 BM25分词后的模糊匹配,仅宽泛流程类问题启用条件
扩展向量用 Query Plan 的扩展查询再搜一轮,仅上游语义改写时启用条件
HyDE 向量假设回答再检索,需显式开启默认关

两个值得讲的工程细节:

1)ES 预筛(Pre-filter):全库向量 ANN 在海量分块下没必要。平台先用 ES 关键词粗召回一批 chunk id(默认最多 120 个),把向量搜索限制在候选集里;如果 ES 候选太少(少于 24 个)说明这个问题的关键词路线不可靠,回退全库 ANN。粗筛 + 精排,成本降一个量级。

2)向量结果缓存:未走预筛的纯向量检索结果按"知识库 + query 向量"缓存到 Redis(TTL 5 分钟),同一问题的重复请求直接命中。

另外每路都是 top_k × 2 召回——召回阶段宁可多捞,精排阶段再砍,漏了就没得救,捞多了可以砍。


三、分数融合:RRF + 加权,以及一条铁律

多路结果回来了,同一分块可能被多路同时命中。怎么合并排序?平台用RRF(Reciprocal Rank Fusion)+ 加权分数 + 软加权三层:

3.1 RRF:排名即分数

不比较不同路分数的绝对值(向量余弦 0.7 和 BM25 分数 12.5 根本不可比),只比排名:

score_rrf = Σ 1 / (k + rank_i)      # k 为平滑常数,rank 是第 i 路的排名

在某一路排第 1 得 1/(k+1),排第 10 得 1/(k+10)。被多路同时命中的分块,RRF 天然更高——这是"多路共识"的信号。

3.2 加权分数:同量纲的加总

对每路的实际分数(向量余弦、BM25 分)按权重加总,权重按语言配置(当前 profile 默认:向量 0.30、BM25 0.20、扩展向量 0.22、语义 BM25 0.10……)。

3.3 软加权:槽位命中加分

第二节抽出的槽位在这里派上用场。分块内容里如果显式包含用户问题里的单据编号 / 错误码 / 模块名 / 主机名,各加不同权重(编号 +0.4、错误码 +0.2、模块名 +0.15、主机名 +0.1)——精确标识符命中是强证据,必须让它浮上来。

3.4 一条踩出来的铁律

增加一路检索,永远不能降低另一路证据支撑的分数。

当初的实现是"所有路径分数取平均"——结果出现一个怪现象:一个分块被关键词强命中、向量余弦很低时,加进来的低分向量把总分拉低了,反而是负贡献。

现在的实现:

weighted_score = max(全部路径平均, 词法路径平均, 稠密路径平均)

词法证据强的用词法平均,稠密证据强的用稠密平均,两路都强的取最高——新增路径只能加分,不能惩罚。这条经验比任何调参都值钱。

融合还会加:多路一致性加分(被 ≥2 路命中 +0.03,≥3 路 +0.06)、单一路径且无任何加分信号时 ×0.72 惩罚(防止"只有一路碰巧命中"的弱证据上榜)。

最后每个候选带一份 score_breakdown(RRF 分 / 加权分 / 各路径分 / 各 boost),检索结果可解释——这是后面 QC 和排查问题的基础。


四、精排 Rerank:把"看起来相关"变成"真的相关"

融合排序还是"召回视角"。Rerank 是"精排视角":用一个专门的排序模型,对着 query 重新给每个候选打分。

4.1 喂给 Rerank 的不是原文,是"证据文本"

这是平台的一个关键设计。直接把分块正文丢给排序模型效果一般,平台先为每个候选构建判别性证据文本:

文档:容灾管理规范
章节路径:4 系统架构 > 容灾方案
答案判定要点:RTO;恢复时间目标;容灾切换
候选答案片段:
- RTO 要求为 30 分钟以内……
关键词上下文:……
原文节选:……

把文档名、章节路径、判定要点、答案片段拼好再送排序模型——模型判断的是"这段证据能不能回答问题",而不是"这段文字像不像问题",命中率明显更高。

4.2 本地证据评分兜底

排序模型可能挂了、可能超时。平台有一个不依赖外部模型的本地证据评分:

本地证据分 = 已有检索信号 × 0.42
           + 判定短语命中率 × 0.26
           + 候选答案片段覆盖 × 0.20
           + 多路命中 × 0.025/路(上限 0.10)
           + 值型特征(编号/数字/表格)0.08
           + 保护候选 +0.08

外部排序模型分数和本地证据分结合使用——模型是增强,本地信号是底线。

4.3 多模型融合与防抖

  • 多模型并行:最多 3 个排序模型并行调用(3 秒超时),取平均分融合;单模型配置时走单模型路径;
  • 短期分数缓存:同 (query, 分块, 模型) 的分数缓存 10 分钟,避免重复请求反复调用排序 API;
  • 长文本截断:单条证据超过 1000 字符截断,防止排序模型 token 超限;
  • 五级降级:多模型超时 → 用已完成模型结果;全失败 → 本地证据分;本地也失败 → 原始融合序;总超时 5 秒 → 直接放弃重排用原序。Rerank 是增强,绝不能因为它的失败拖垮整条检索。

另外一个朴素的规则:候选 ≤5 条时跳过 Rerank——数据量小,排序模型提升有限,白花钱。


五、证据组装:去重、补上下文、按文档分组

精排完选出 top-N,还不能直接拼给模型。要做三件事:

5.1 Jaccard 去重

相邻分块往往高度相似(尤其是滑动窗口切分)。用 Jaccard 相似度去重:两个分块 token 重叠率 > 0.7 时,保留分数高的那个。否则同样的内容会占掉两三个上下文名额。

5.2 邻居上下文扩展

检索命中是"点",但答案可能需要"上下文"。平台会加载每个命中分块所在文档的物理邻居分块(同文档、按 chunk 顺序取前后 N 块)。

两个设计细节:

  • 扩展只看物理顺序,不看章节元数据——章节路径可能标错,物理相邻不会骗人;
  • 有总量上限(组内约 6500 字符、总约 18000 字符),防止上下文爆炸。

5.3 按文档分组

最终上下文按文档分组输出:

【文档:容灾管理规范】
……分块 1……
……分块 2……

【文档:应急预案】
……分块 3……

文档间按最高分排序、文档内按原始顺序排列。这样模型能清楚感知"哪段属于哪篇文档",生成时更容易引用正确来源。分组时还会提取分块里的图片说明并保留图片标记,要求模型原样输出图片标记,前端才能展示真实截图。


六、有据合成与反幻觉:答案必须有出处

这是 RAG 系统最关键的一层——宁可说不知道,不能编。平台用四道防线:

6.1 证据门控(Abstain Gate)

合成前先问:检索到的证据够不够回答这个问题?

  • 完全没检索到分块 → 走"无命中"路径;
  • 有分块但最高分低于阈值(默认 0.18)且无强字面命中(问题原文/短语完整出现)→ 拒答,返回澄清引导(“知识库中没有找到与 X 相关的内容,请补充……”),而不是硬编一个答案;
  • 有其它可靠上下文(如数据库结果)→ 放行。

6.2 有据合成规则与低温

  • system prompt 里注入有据作答规则(“只能基于【知识内容】作答,内容中没有的必须明说”)——注意这个规则文本来自界面配置,代码不内置口径,运营可以随时改;
  • 有据合成温度默认 0.0——RAG 回答要的是确定性,不是创意;
  • 特定场景(如查"某个配置步骤的标识")走确定性合成:直接从 Markdown 表格里按列名查表生成答案,完全跳过 LLM 归纳——表格查值这种场景,LLM 反而容易"润色"出错。

6.3 引用对齐与修剪

答案生成后,平台会对"答案 ↔ 来源"做一次对齐:

  • 提取答案里的判别性锚点(文档标题、关键编号),反向给每个来源打分;
  • 修剪掉答案里根本没提到的来源——避免出现"引用了但没用上"的误导引用;
  • 引用按文档去重,同一文档只展示一次。

6.4 诚实 Miss:状态流

“没有答案"也是一种答案。平台有标准的答案状态(有据 / 无据 / 证据不足),miss 类回答走诚实路径:明确告知"知识库未覆盖”,绝不用"根据我的了解……"糊弄。


七、质量保障:机器自己给自己打分

上线容易,长期准不准难。平台把质检做成流水线:

1)L0 确定性预检(规则,零成本):引用可追溯性(引用的来源必须真实存在)、无来源捏造检测、参数幻觉检测(答案里的数字/编号必须能在来源里找到)、语言一致性。

2)客观忠实度旁路信号:把答案的关键锚点(编号、术语、数字)拿去和引用正文比对,算 Jaccard 重叠率、答案覆盖率、关键术语命中率——不依赖任何模型,纯字符串计算,随时可跑。

3)L1 LLM 裁判:对内容质量做单条裁判,按状态分流(miss 类问题只查 miss 一致性,不要求它产出完整答案)。

4)归因信号:证据充分性评估 + 库内可召回探针——“这个问题的答案,在知识库里到底能不能被检索到”。

配合检索侧已有的可解释性(每个候选带 score_breakdown 和命中原因),一个问题答错了,是预处理、召回、融合、重排、门控哪一环的问题,可以一步步追。


八、踩坑清单(都是真金白银)

坑后果解法
只用向量检索精确标识符(RTO、错误码)漏召回向量 + BM25 多路
多路分数直接平均低分向量把强词法证据拉低max(全平均, 词法平均, 稠密平均)
全库向量 ANN海量分块下检索慢ES 预筛候选集,候选不足回退全库
把格式指令当检索主题“用英文输出"去检索"英文输出”指令/主题分离,多轮消歧
让 LLM 重写表格答案数字被"润色"错表格查值走确定性合成
Rerank 阻塞主链路排序模型慢 → 整个对话超时多级超时 + 降级回退
直接拼原文给排序模型判别性证据不足,排序不准构建证据文本再送
上下文塞满相似分块重复内容浪费名额Jaccard 去重 + 邻居扩展上限
引用来源与实际不符误导用户答案-来源对齐 + 修剪

九、小结与下期预告

这一篇的四个核心结论:

  • 召回要广:向量 + 关键词多路,条件加路,ES 预筛控成本;
  • 融合要稳:RRF 比分数,加权看量纲,槽位软加权,加路不降分是铁律;
  • 精排要专:证据文本 + 本地证据分兜底 + 多级降级,Rerank 是增强不是依赖;
  • 输出要诚:证据门控拒答、低温有据合成、引用对齐修剪、确定性查表,反幻觉靠的是工程不是提示词。

下一篇进入生成与对话工程:上下文拼好之后,流式输出、SSE、多模型路由、Agent 工具调用、成本与延迟的取舍——把一个"能检索的 RAG"变成一个"能对话的 AI 平台"。


(本文基于项目当前实现整理。文中默认参数、路径权重、阈值均以仓库实现为准,不同部署环境可能不同。)

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐