知识库智能路由:如何将用户提问精准匹配到目标知识库

1. 背景与痛点

每个系统对应一个独立知识库,随着系统数量持续增长,知识库规模达到数十乃至上百个。每个知识库均有其独立的名称(Name)与范围描述(Description),文档按角色类型分类(desc / overview / architecture / api / business / product / ops / runtime),分类信息作为元数据写入向量库。

知识库数量庞大,无法将所有描述一次性塞入 LLM Prompt 暴力裁决(Token 成本、延迟、上下文窗口均不允许)。在初期尝试中,使用向量检索匹配知识库 Description 的方案召回准确率同样远低于预期。

核心痛点:

痛点 表现 根因
知识库数量多 数十到上百个知识库,全量裁决不可行 需要检索先收敛候选,再精准裁决
非对称检索 用户问"Redis 满容怎么办",检索不到描述为"提供 Redis 集群运维相关知识"的知识库 用户提问短、具体、多样;Description 抽象、概括、结构化,向量空间语义特征不匹配
硬字面量缺失 搜"Hubble 告警配置"召回了"监控系统运维"知识库而非"Hubble 使用手册"知识库 向量检索容易忽略业务专有名词,泛化过度
同义改述盲区 用户说"机器挂了",知识库描述是"主机故障处理",向量距离较远 单次检索只能覆盖一种表达角度,难以跨越口语/书面语鸿沟

2. 方案核心思路

知识库的文档内容已经完成向量化入库,每个文档分块(chunk)均携带 kb_id 元数据。因此不需要额外构建独立的路由索引 ------路由可以直接在已有的向量化内容上检索,按 kb_id 聚合结果即可判定目标知识库。

核心改进点在在线端

  1. 多角度 Query 改写:把用户的单一提问改写为 1~3 条不同视角的查询,扩大召回覆盖面,解决"同义改述盲区"
  2. Hybrid 检索:Dense(语义)+ Sparse(BM25)混合检索,解决"硬字面量缺失"
  3. kb_id 聚合 + Rerank:将 chunk 级别的检索结果聚合到知识库级别,Rerank 精排
  4. LLM 终审裁判:多个高置信候选时,LLM 做最终 N 选 1

前提条件:知识库文档需要人工持续完善(尤其是 FAQ 条目),文档质量直接决定路由准确率。AI 不生成合成数据,所有检索目标均来源于人工维护的真实文档内容。


3. 整体架构

3.1 已有基础设施

#mermaid-svg-vdF2VPI1EOc8YV56{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vdF2VPI1EOc8YV56 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vdF2VPI1EOc8YV56 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vdF2VPI1EOc8YV56 .error-icon{fill:#552222;}#mermaid-svg-vdF2VPI1EOc8YV56 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vdF2VPI1EOc8YV56 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vdF2VPI1EOc8YV56 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vdF2VPI1EOc8YV56 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vdF2VPI1EOc8YV56 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vdF2VPI1EOc8YV56 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vdF2VPI1EOc8YV56 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vdF2VPI1EOc8YV56 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vdF2VPI1EOc8YV56 .marker.cross{stroke:#333333;}#mermaid-svg-vdF2VPI1EOc8YV56 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vdF2VPI1EOc8YV56 p{margin:0;}#mermaid-svg-vdF2VPI1EOc8YV56 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-vdF2VPI1EOc8YV56 .cluster-label text{fill:#333;}#mermaid-svg-vdF2VPI1EOc8YV56 .cluster-label span{color:#333;}#mermaid-svg-vdF2VPI1EOc8YV56 .cluster-label span p{background-color:transparent;}#mermaid-svg-vdF2VPI1EOc8YV56 .label text,#mermaid-svg-vdF2VPI1EOc8YV56 span{fill:#333;color:#333;}#mermaid-svg-vdF2VPI1EOc8YV56 .node rect,#mermaid-svg-vdF2VPI1EOc8YV56 .node circle,#mermaid-svg-vdF2VPI1EOc8YV56 .node ellipse,#mermaid-svg-vdF2VPI1EOc8YV56 .node polygon,#mermaid-svg-vdF2VPI1EOc8YV56 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vdF2VPI1EOc8YV56 .rough-node .label text,#mermaid-svg-vdF2VPI1EOc8YV56 .node .label text,#mermaid-svg-vdF2VPI1EOc8YV56 .image-shape .label,#mermaid-svg-vdF2VPI1EOc8YV56 .icon-shape .label{text-anchor:middle;}#mermaid-svg-vdF2VPI1EOc8YV56 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vdF2VPI1EOc8YV56 .rough-node .label,#mermaid-svg-vdF2VPI1EOc8YV56 .node .label,#mermaid-svg-vdF2VPI1EOc8YV56 .image-shape .label,#mermaid-svg-vdF2VPI1EOc8YV56 .icon-shape .label{text-align:center;}#mermaid-svg-vdF2VPI1EOc8YV56 .node.clickable{cursor:pointer;}#mermaid-svg-vdF2VPI1EOc8YV56 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vdF2VPI1EOc8YV56 .arrowheadPath{fill:#333333;}#mermaid-svg-vdF2VPI1EOc8YV56 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vdF2VPI1EOc8YV56 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vdF2VPI1EOc8YV56 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vdF2VPI1EOc8YV56 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vdF2VPI1EOc8YV56 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vdF2VPI1EOc8YV56 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vdF2VPI1EOc8YV56 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vdF2VPI1EOc8YV56 .cluster text{fill:#333;}#mermaid-svg-vdF2VPI1EOc8YV56 .cluster span{color:#333;}#mermaid-svg-vdF2VPI1EOc8YV56 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vdF2VPI1EOc8YV56 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vdF2VPI1EOc8YV56 rect.text{fill:none;stroke-width:0;}#mermaid-svg-vdF2VPI1EOc8YV56 .icon-shape,#mermaid-svg-vdF2VPI1EOc8YV56 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vdF2VPI1EOc8YV56 .icon-shape p,#mermaid-svg-vdF2VPI1EOc8YV56 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vdF2VPI1EOc8YV56 .icon-shape .label rect,#mermaid-svg-vdF2VPI1EOc8YV56 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vdF2VPI1EOc8YV56 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vdF2VPI1EOc8YV56 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vdF2VPI1EOc8YV56 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-vdF2VPI1EOc8YV56 .kb>*{fill:#f9f!important;stroke:#333!important;stroke-width:2px!important;}#mermaid-svg-vdF2VPI1EOc8YV56 .kb span{fill:#f9f!important;stroke:#333!important;stroke-width:2px!important;}#mermaid-svg-vdF2VPI1EOc8YV56 .db>*{fill:#fbc!important;stroke:#333!important;stroke-width:2px!important;}#mermaid-svg-vdF2VPI1EOc8YV56 .db span{fill:#fbc!important;stroke:#333!important;stroke-width:2px!important;} 知识库 C
知识库 B
知识库 A
分块 + 向量化
分块 + 向量化
分块 + 向量化
分块 + 向量化
分块 + 向量化
分块 + 向量化
分块 + 向量化
文档 1

FAQ / SOP / 架构
文档 2
文档 N
文档 1
文档 N
文档 1
文档 N
Hybrid 向量库

chunk + kb_id 元数据

所有知识库的文档已完成分块、向量化,写入统一的 Hybrid 向量库。每个 chunk 携带 kb_idlayerdoc_type 等元数据,是路由的检索基础。

3.2 在线路由管线

#mermaid-svg-fR3inln1fVzunYjH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fR3inln1fVzunYjH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fR3inln1fVzunYjH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fR3inln1fVzunYjH .error-icon{fill:#552222;}#mermaid-svg-fR3inln1fVzunYjH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fR3inln1fVzunYjH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fR3inln1fVzunYjH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fR3inln1fVzunYjH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fR3inln1fVzunYjH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fR3inln1fVzunYjH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fR3inln1fVzunYjH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fR3inln1fVzunYjH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fR3inln1fVzunYjH .marker.cross{stroke:#333333;}#mermaid-svg-fR3inln1fVzunYjH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fR3inln1fVzunYjH p{margin:0;}#mermaid-svg-fR3inln1fVzunYjH .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-fR3inln1fVzunYjH .cluster-label text{fill:#333;}#mermaid-svg-fR3inln1fVzunYjH .cluster-label span{color:#333;}#mermaid-svg-fR3inln1fVzunYjH .cluster-label span p{background-color:transparent;}#mermaid-svg-fR3inln1fVzunYjH .label text,#mermaid-svg-fR3inln1fVzunYjH span{fill:#333;color:#333;}#mermaid-svg-fR3inln1fVzunYjH .node rect,#mermaid-svg-fR3inln1fVzunYjH .node circle,#mermaid-svg-fR3inln1fVzunYjH .node ellipse,#mermaid-svg-fR3inln1fVzunYjH .node polygon,#mermaid-svg-fR3inln1fVzunYjH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fR3inln1fVzunYjH .rough-node .label text,#mermaid-svg-fR3inln1fVzunYjH .node .label text,#mermaid-svg-fR3inln1fVzunYjH .image-shape .label,#mermaid-svg-fR3inln1fVzunYjH .icon-shape .label{text-anchor:middle;}#mermaid-svg-fR3inln1fVzunYjH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-fR3inln1fVzunYjH .rough-node .label,#mermaid-svg-fR3inln1fVzunYjH .node .label,#mermaid-svg-fR3inln1fVzunYjH .image-shape .label,#mermaid-svg-fR3inln1fVzunYjH .icon-shape .label{text-align:center;}#mermaid-svg-fR3inln1fVzunYjH .node.clickable{cursor:pointer;}#mermaid-svg-fR3inln1fVzunYjH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-fR3inln1fVzunYjH .arrowheadPath{fill:#333333;}#mermaid-svg-fR3inln1fVzunYjH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-fR3inln1fVzunYjH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-fR3inln1fVzunYjH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fR3inln1fVzunYjH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-fR3inln1fVzunYjH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fR3inln1fVzunYjH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-fR3inln1fVzunYjH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fR3inln1fVzunYjH .cluster text{fill:#333;}#mermaid-svg-fR3inln1fVzunYjH .cluster span{color:#333;}#mermaid-svg-fR3inln1fVzunYjH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-fR3inln1fVzunYjH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-fR3inln1fVzunYjH rect.text{fill:none;stroke-width:0;}#mermaid-svg-fR3inln1fVzunYjH .icon-shape,#mermaid-svg-fR3inln1fVzunYjH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fR3inln1fVzunYjH .icon-shape p,#mermaid-svg-fR3inln1fVzunYjH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-fR3inln1fVzunYjH .icon-shape .label rect,#mermaid-svg-fR3inln1fVzunYjH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fR3inln1fVzunYjH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-fR3inln1fVzunYjH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-fR3inln1fVzunYjH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-fR3inln1fVzunYjH .online>*{fill:#bbf!important;stroke:#333!important;stroke-width:2px!important;}#mermaid-svg-fR3inln1fVzunYjH .online span{fill:#bbf!important;stroke:#333!important;stroke-width:2px!important;} LLM 意图改写
短句 1
短句 2
短句 3
结果汇总
结果汇总
结果汇总
Rerank 重新打分
组装上下文 Prompt
输出
用户原始输入
改写为 1~3 条

不同视角查询短句
Hybrid 检索 Top N chunks
Hybrid 检索 Top N chunks
Hybrid 检索 Top N chunks
按 kb_id 聚合去重
收敛至 Top K 知识库
LLM 终审裁判 K 选 1
最终目标知识库 + Top chunks


4. 前提:文档内容的质量要求

路由准确率直接取决于向量库中文档内容的质量。以下是对知识库文档维护的要求:

要求 说明 影响
每个知识库至少有 5 条 FAQ FAQ 的 question 是最接近用户提问形式的内容,是路由命中的核心锚点 FAQ 不足会导致口语化提问无法命中
文档章节标题清晰具体 H2 标题应体现具体话题("Redis 满容排查"而非"问题处理") 模糊标题降低语义匹配精度
包含业务专有名词 文档中明确出现系统名、组件名、错误码等专有名词 缺失专有名词导致 BM25 精确匹配失效
文档角色分类准确 每篇文档按角色类型(desc / overview / architecture / api / business / product / ops / runtime)分类 分类错误导致按类型过滤时漏检
chunk 元数据完整 每个 chunk 携带 kb_idlayerdoc_type 等元数据 元数据缺失无法做 kb_id 聚合和类型过滤

5. 在线路由管线

5.1 基于文档角色类型的 Query 改写

用户的一条提问可能涉及多种文档角色类型。通过 LLM 识别最相关的意图类型,并为每种意图生成一条优化后的查询短句,实现按类型精准召回。

文档角色类型定义:

类型 含义 典型内容
desc 实体描述 服务、组件或概念的定义与说明
overview 术语表与项目总览 项目整体介绍、术语定义、名词解释
architecture 系统架构文档 架构设计、模块拆分、技术选型、部署拓扑
api API 接口文档 接口定义、请求/响应格式、参数说明
business 业务逻辑文档 业务流程、规则引擎、状态机、数据流转
product 产品手册 功能说明、使用指南、产品特性
ops 运维手册 部署流程、监控告警、故障排查、变更操作
runtime 服务运行时 运行时配置、性能调优、日志分析、资源监控

改写 Prompt:

text 复制代码
System:
  根据用户问题,从以下文档角色类型中识别出最相关的意图,
  并为每种意图生成一条优化后的搜索查询短句。

  文档角色类型:
  - desc: 实体描述 --- 对某个服务、组件或概念的定义与说明
  - overview: 术语表与项目总览 --- 项目整体介绍、术语定义、名词解释
  - architecture: 系统架构文档 --- 架构设计、模块拆分、技术选型、部署拓扑
  - api: API 接口文档 --- 接口定义、请求/响应格式、参数说明
  - business: 业务逻辑文档 --- 业务流程、规则引擎、状态机、数据流转
  - product: 产品手册 --- 功能说明、使用指南、产品特性
  - ops: 运维手册 --- 部署流程、监控告警、故障排查、变更操作
  - runtime: 服务运行时 --- 运行时配置、性能调优、日志分析、资源监控

  要求:
  1. 从上述类型中选出与问题最相关的意图,最少 1 条,最多 {max_count} 条,不要重复
  2. 如果用户意图非常明确且只涉及单一文档类型,返回 1 条即可,不必凑数
  3. 每条查询是完整的句子,适合语义搜索
  4. 保留原问题中的关键专有名词
  5. category 值必须使用上述英文标识(如 desc、api、ops 等)

  输出 JSON:
  [
    {"category": "ops", "query": "优化后的搜索查询短句"}
  ]

User:
  用户问题:{user_query}

改写示例:

用户原始提问 改写结果
"Redis 满容了怎么办" ops: "Redis 满容故障排查与处理步骤" ② runtime: "Redis 内存使用监控与容量分析"
"配置中心的推送链路是怎么设计的" architecture: "配置中心推送链路架构设计"
"payment-service 的接口返回格式" api: "payment-service 接口返回格式与参数说明"
"Hubble 怎么创建自定义监控大盘" product: "Hubble 自定义监控大盘创建指南"

改写产出的 category 字段可在后续 Hybrid 检索中作为元数据过滤条件,进一步提升精准度。

5.2 Hybrid 检索

每条改写查询分别执行 Hybrid 检索(Dense + Sparse),直接命中已有向量库中的文档 chunks。改写产出的 category 可作为元数据过滤条件,缩小检索范围。

检索参数:

参数 说明
Dense 权重 0.6 语义匹配为主
Sparse 权重 0.4 BM25 关键词匹配,保障专有名词精确召回
每条查询 Top-K 10 单次检索返回 10 个 chunks
相似度下限 0.3 低于阈值的结果丢弃,避免噪声
元数据过滤 doc_type == category 按改写产出的文档角色类型过滤(可选)

为什么 Sparse 权重较高(0.4):

知识库路由场景中,专有名词(Hubble、CMDB、配置中心)是强区分信号。BM25 对精确词匹配的优势在这个场景下比通用 RAG 更有价值。

元数据过滤策略: 当改写只产出 1 条查询时,启用 doc_type 过滤以提高精度;当产出多条查询时,每条查询按各自的 category 独立过滤,结果合并后覆盖面更广。

5.3 kb_id 聚合与去重

将 1~3 条改写查询的检索结果汇总,按 kb_id 聚合为知识库级别的候选:

  1. kb_id 聚合 :同一知识库被命中的所有 chunks,取最高分 chunk 作为该知识库的代表得分
  2. 命中数加权:同时记录每个知识库被命中的 chunk 数量,作为辅助排序信号(命中越多说明覆盖面越广)
  3. 综合排序最终分 = 代表得分 × 0.7 + 归一化命中数 × 0.3

聚合后通常得到 5~15 个候选知识库。

5.4 Rerank 精排(可选环节)

使用 Rerank 模型(BGE-Reranker-v2 / Cohere Rerank)对候选结果重新打分:

  • 输入:用户原始提问 + 每个候选知识库的代表 chunk 内容
  • 输出:每个候选的 Rerank 分数
  • 收敛:取 Top 3~5 个知识库进入终审

既然有 LLM 终审,为什么还需要 Rerank?

Rerank 并非必要环节,最终裁决权在 LLM。但它在以下场景中有明确优势:

维度 直接跳到 LLM 终审 先 Rerank 再 LLM 终审
候选数量 聚合后通常 5~15 个候选全部送入 LLM,Prompt 较长 Rerank 先收敛到 3~5 个,LLM 只需在少量候选中裁决
LLM 成本 候选越多 Token 越多,成本线性增长 减少 60~70% 的 LLM 输入 Token
LLM 准确率 候选过多时 LLM 容易被干扰项分散注意力 少量高质量候选让 LLM 裁决更稳定
延迟 LLM 处理长 Prompt 耗时增加 Rerank(~150ms)+ 短 Prompt LLM 总耗时更低

建议策略: 当聚合后候选数 ≤ 5 时,可跳过 Rerank 直接进 LLM 终审;候选数 > 5 时,先 Rerank 收敛再终审。

5.5 LLM 终审裁判

Rerank 收敛后,仍可能存在多个高置信候选。用 LLM 做最终 N 选 1 裁判。

终审 Prompt:

text 复制代码
System:
  你是一个知识库路由裁判。用户提了一个问题,系统检索到了多个候选知识库。
  请判断用户的问题最应该由哪个知识库来回答。

  候选知识库(按初步相关性排序):
  {candidates}

  每个候选包含:
  - kb_name: 知识库名称
  - kb_description: 知识库范围描述
  - matched_chunk: 命中的代表性文档片段
  - score: 初步相关性分数

  判断规则:
  1. 优先选择与用户问题语义最匹配的知识库
  2. 当多个知识库都可能相关时,选择范围最聚焦(而非最宽泛)的那个
  3. 如果没有任何知识库能回答用户问题,输出 null

  输出 JSON:
  {
    "selected_kb_id": "kb-xxx" 或 null,
    "confidence": 0.0~1.0,
    "reason": "简短的选择理由"
  }

User:
  用户问题:{user_query}

5.6 全链路延迟预估

环节 预估耗时 是否可并行
Query 改写(LLM) 300~500ms ---
Hybrid 检索 × 3 50~100ms × 3 三条查询并行执行
kb_id 聚合 + 去重 < 10ms ---
Rerank 100~200ms ---
LLM 终审 300~600ms ---
端到端 P95 ~1.2s ---

优化手段:

  • Query 改写使用轻量模型(DeepSeek-V3 / GPT-4o-mini),降低改写延迟
  • 当改写只产出 1 条查询时,跳过聚合,直接进 Rerank
  • LLM 终审当 Rerank Top1 分数 > 0.9 且 Top1 与 Top2 差距 > 0.2 时,跳过终审直接输出

6. 路由结果的使用

路由输出 selected_kb_id + confidence 后,影响后续 RAG 检索的范围:

置信度 检索策略
高置信(> 0.8) 仅在选定知识库内检索,按 L1~L5 分层过滤
中置信(0.5~0.8) 在选定知识库 + 相邻知识库内检索
低置信(< 0.5) 全库检索,不做知识库过滤

路由过程中命中的 Top chunks 可以直接复用到后续 RAG Pipeline,避免重复检索。


7. 兜底与异常处理

场景 处理策略
Rerank Top1 置信度 < 0.4 不路由,直接回复用户"未找到匹配的知识库,请补充更多信息"
LLM 终审返回 null 同上,并记录该 query 到未覆盖日志,作为知识库缺口信号
LLM 终审 confidence 在 0.4~0.6 路由到选定知识库,但答案附带"此回答可能不完全匹配,建议联系 {kb_owner}"
改写 LLM 超时 降级为用户原始 query 直接检索(跳过改写)
Rerank 模型不可用 降级为按 Hybrid 检索原始分数排序
用户 query 过短(< 3 字) 追问用户补充信息,不直接路由

8. 总结

本方案的核心设计决策:

决策 选择 理由
路由索引 复用已有向量库,不建独立索引 文档已全量向量化,额外索引增加维护成本且容易与源数据脱节
离线增强 人工维护文档和 FAQ,不用 AI 生成合成数据 合成 QA 质量不可控,且与真实文档内容脱节
Query 改写 基于文档角色类型改写,而非通用角度改写 与文档分类体系对齐,改写结果可直接用于元数据过滤
检索方式 Dense + Sparse 混合检索 兼顾语义匹配和专有名词精确匹配
Rerank 可选环节,候选 > 5 时启用 减少 LLM 终审的输入量和成本,提升裁决稳定性
最终裁决 LLM 终审 向量分数和 Rerank 分数是局部最优,LLM 能综合判断全局最优

一句话总结:直接复用已有向量化文档,叠加"多角色改写 → Hybrid 检索 → kb_id 聚合 → LLM 终审"的在线路由管线,无需额外建设离线索引,以最小改造量解决知识库路由问题。


相关推荐
技术小甜甜2 小时前
Dify 工作流场景目录(2026):客服、回访、采购、知识库、系统集成怎么找入口
workflow·知识库·客服·工作流·dify·场景
小小资源铺4 小时前
KnowBase v2.1 英文版 - 一个知识库和论坛网站WordPress主题
知识库·论坛·网站模板·wordpress 主题·网站搭建模板·主题推荐·knowbase
ZGi.ai5 小时前
ZGI 父子分块:连接检索片段与完整上下文
人工智能·算法·知识库·企业ai·zgi·父子分块
艾伦_耶格宇1 天前
【AI】-7 从知识库到 AI Agent -进阶
人工智能·知识库·obsidian·opencode·ai运维
TizzyGoodhealth4 天前
从零到一搭建Spring‑AI原生Tool‑Calling AI Agent|架构对比+完整实战源码+踩坑实录
java·ai·知识库·rag·ai agent·spring ai
ZGi.ai11 天前
知识库更新后仍回答旧内容:五层排查指南
知识库·rag·知识检索·zgi
小田学Python12 天前
RAG和Embedding技术解析:从理论到实践的探索
大模型·embedding·知识库·向量检索·rag
独码侠13 天前
Dify 知识库索引(中):打开源码,拆穿关于“经济索引”的三个谣言
后端·python·django·embedding·知识库·索引·dify
初圣魔门首席弟子15 天前
用毛选五把利剑斩断焦虑根源——毛选实战局学习笔记
知识库