八成以上「知识库没生效」的排查结果,其实是内容没被检索到,而不是内容缺失。本文拆解混合召回的五环链路(范围、召回、扩展、重排、拼装),给出内容问题与排名问题的判定表,以及在动手补内容之前该做的免费复现。
一个高频困惑:「知识库里明明写了,AI 就是答不上来」
这是接入知识库之后第一个月最容易遇到的问题。团队把产品手册、FAQ、案例、资质证书全部导进去,问一句「你们支持哪些部署方式」,AI 答得含含糊糊,或者干脆说“资料中没有相关信息”。
多数人的第一反应是「知识库没生效」或「模型太笨」。但实际排查下来,八成以上的情况不是内容缺失,而是内容没被检索到。
这两件事的处置完全不同:
- 内容缺失 → 去补内容;
- 检索没召回 → 内容写着也没用,改的是检索条件或内容组织方式。
如果用错方向,就会陷入「按 AI 提示的缺口反复补文章,补了还是答不上来」的死循环。这篇文章就是讲怎么在动手补内容之前,先用一次检索复现把方向定准。
一、先理解检索是怎么走的
我们的知识库检索不是单纯的向量相似度。完整链路大致是这样:
① 范围确定。 先确定这次检索在哪些知识库里找。这一步会按当前租户、项目、可见性做筛选——如果某些知识库被排除在范围外,再怎么调召回也找不到它。
② 混合召回。 三条通道并行:
| 通道 | 权重 | 说明 |
|---|---|---|
| 向量召回 | 0.7 | 语义相似,能匹配“意思相近但用词不同”的问法 |
| 关键词召回 | 0.3 | 字面命中,对产品型号、专有名词、编号类查询很重要 |
| 标题/章节召回 | 0.15 | 命中标题或章节名,对结构化资料的定位很有效 |
三条通道的结果用 RRF(Reciprocal Rank Fusion,k=60) 融合。RRF 的意义在于:它不看原始分数的绝对值,只看排名——这样不同通道的分数尺度不一致也不会互相干扰。
另外有一个元数据加成(0.08),按知识库身份给一个静态质量分。它不参与 RRF,因为它对同一个库的每个切片都相同,排序它等于按库名排序,没有信息量。
③ 查询扩展(按需触发)。 如果基础召回的数量低于门槛(默认是候选限额的 50%),系统会自动生成查询变体再捞一轮,去重后合并。这是“召回不足时的补救”,不是每轮都跑。
④ 重排。 召回结果会经过重排(rerank)再取前若干条拼成证据上下文。
⑤ 拼装上下文。 最终返回的是证据条目(默认取前 5 条,上下文长度上限 3200 字符),连同来源信息一起交给生成模型。
看明白这条链路,排查就有顺序了:范围 → 召回 → 扩展 → 重排 → 拼装,每一环都可能把内容滤掉。
二、诊断对象:为什么“没检索到”是可观测的
平台为每次检索记录了一份诊断信息,字段刻意保持少量但语义明确:
- 范围规模:请求了几个库、实际参与检索几个、有没有被安全阀截断;
- 候选规模:向量通道和关键词通道各召回了多少切片;
- 各阶段滤除计数:被时效性排除多少、被范围筛选排除多少;
- 查询扩展:是否触发、触发门槛是多少、用了哪些变体、额外捞到多少;
- 最终返回:几条、耗时多少、有没有告警。
这份诊断的价值在于:它能回答「到底哪一步把内容滤掉了」。
举一个实际会遇到的形态:诊断显示向量候选 40 条、关键词候选 12 条,最终返回 5 条,但答案里没有你需要的那条。这说明召回没问题,问题在排名——你的目标切片进了候选池,只是没排进前 5。这种情况下补内容没用,要改的是这条内容的表述方式或检索参数。
反过来,如果诊断显示范围里只剩 1 个库、向量候选只有 3 条,那问题在范围或召回——要么库被过滤了,要么切片太少。
三、两类失败:内容问题与排名问题
这是本文最重要的一张对照表:
| 现象 | 判据 | 正解 |
|---|---|---|
| 内容确实没有 | 检索复现时完全没进候选,且按关键词搜库内也搜不到 | 补内容 |
| 内容有但排不进前 K | 进了候选池,但最终取证时被挤掉 | 改表述/补专题篇章,不是补一行 |
| 内容有但召回不到 | 按字面关键词能在库里搜到,语义检索却召不回 | 内容与问法词汇差异过大,补同义表述 |
| 召回正常但答不好 | 证据进了上下文,模型仍答错 | 检索/生成口径问题,不是知识库问题 |
特别提醒第三行和第四行:按“缺口”补一行表项,往往召回还是打不过——因为一行表项的语义信号太弱。要补就补专题篇章:标题和段落里覆盖用户真实会用的问法词,这样语义召回的信号才够强。
四、一次免费的最小复现
排查不该拿付费对话来试。检索复现本身只花 embedding 的钱,成本极低。
具体做法:
- 把用户那个问句原样(不要改写)拿去跑一次
retrieveEvidence—— 取前 8 条证据; - 逐条看你期望的那段内容在不在里面;
- 按上面表格定位是哪一类失败;
- 再决定是补内容、改表述、还是调参数。
关键纪律:用用户的原话,不要用你整理过的规范问法。用规范问法测出来能召回到,不代表用户那样问也能召回到——而线上是用户在问。
五、几个容易被忽略的坑
「改了默认值」不等于「生效了」。 检索和生成的相关配置有优先级:数据库里保存的值优先于代码里的默认值。只改代码默认值,线上跑的还是 DB 里那份旧配置。这类“看起来改了但没变”的问题,靠界面是看不出来的,必须核对实际生效值。
分块没同步完,检索结果就是 0。 内容入库是异步链:准备 → 向量化 → 完成。这期间状态是 pending 或 processing,切片数是 0。这时候去检索当然什么都没有——看起来完全像“入库失败”,实际是在正常处理中。判据是看切片同步状态是否 ready,不是看入库脚本有没有返回成功。
时效性会静默排除内容。 过了时效的资料会被排除在检索范围外。如果某个库里的内容都属于“会过期的事实”,而你没维护复审时间,它可能整体失效而不报错。
“检索到”和“答对了”是两件事。 证据进了上下文,模型仍可能组织错。这时候要看生成侧的提示词与上下文拼装,不要在知识库上继续加内容。
六、这套做法的适用边界
需要说清楚的几点:
- 检索诊断是排查工具,不是评分。它不给你“知识库质量 78 分”这种数字,因为质量问题不是单一维度能概括的。
- 混合召回的权重与 RRF 参数是默认值,可调。不同知识库类型(结构化手册 vs 叙事型案例)最优参数不一样,调参前先做上面那套复现,否则是盲调。
- 补内容永远是最后一招。先确认前面五环都没问题,再动内容——否则你会补一堆用不上的东西,还破坏了原本的组织结构。