Files
SuperBizAgent-java/mvp/architecture/archive/2026-07-05-legacy/knowledge-retrieval-architecture.md
T

15 KiB
Raw Blame History

知识库检索架构(L0 + L1)

更新日期: 2026-06-25


一、概述

LookupKnowledgeTool 实现两阶段混合检索:

  • L0 精确匹配:基于内存索引的关键词匹配(< 10ms),索引从数据库加载
  • L1 语义检索:基于 Milvus 向量数据库的相似度搜索(200-500ms)

二、完整流程

用户查询
   │
   ▼
┌─────────────────────────────┐
│ L0: 关键词精确匹配          │  (< 10ms)
│   • 从内存索引做关键词匹配  │
│   • 索引来源: ApiDocument DB│
└──────────┬──────────────────┘
           │
           ▼
    ┌──────┴──────┐
    │ matches=1   │ ← 唯一匹配(高置信度)
    └──────┬──────┘
           │
           ▼
    ┌──────────────┐         ┌──────────────────┐
    │ 跳过 L1      │         │ L0 返回正文摘要  │
    │ 置信度: high │         │ buildCompactSummary│
    └──────────────┘         └──────────────────┘


    ┌──────┴──────┐
    │ matches=0   │ ← 无匹配
    └──────┬──────┘
           │
           ▼
    ┌──────────────┐         ┌──────────────────┐
    │ 触发 L1      │         │ L0 无结果         │
    │ L1 语义检索  │         │ 仅有 L1 补充结果  │
    └──────────────┘         └──────────────────┘


    ┌──────┴──────┐
    │ matches>=2  │ ← 多匹配
    └──────┬──────┘
           │
           ▼
    ┌──────────────┐
    │ 触发 L1      │
    │ L1 语义检索  │
    └──────┬──────┘
           │
     ┌─────┴─────┐
     │ ║         │
     ▼           ▼
  L1 有结果    L1 无结果
     │           │
     ▼           ▼
  元数据摘要   正文摘要
  (不读文件)   (读文件)

三、L0 返回内容策略

根据匹配场景决定 L0 返回给 LLM 的上下文内容量。

3.1 唯一匹配(高置信度,matches=1)

策略: buildCompactSummary()

L1 被跳过,LLM 只有 L0 信息来源,需要提供足够的正文内容。

文档: 支付网关错误码定义
摘要: 记录了支付网关所有核心错误码的含义及排查方向
章节:
  - 超时类错误
  - 业务类错误
  - 签名类错误
---
**含义**:支付网关请求超时
**常见原因**:网络延迟、第三方服务响应慢
...
组成部分 说明 大小
title + summary 从内存索引获取 ~50-100 字符
章节标题列表 从文件解析 ## 标题 ~50-200 字符
正文片段 去 frontmatter/标题行/空行,短文档 800/长文档 500 字符截断 ~300-800 字符
总计 ~400-1000 字符

3.2 多匹配 + L1 有结果

策略: buildMetadataOnlySummary()

L1 已有语义内容片段,L0 仅需告知 LLM 命中了哪些文档。不读文件,仅用内存索引。

文档: 支付网关错误码定义
摘要: 记录了支付网关所有核心错误码的含义及排查方向
关键词: ERR_TIMEOUT, 超时, 支付网关
来源: api/payment-errors.md
组成部分 说明 大小
title + summary + keywords 全部从内存索引获取 ~100-200 字符
总计 ~100-200 字符

3.3 多匹配 + L1 无结果

策略: buildCompactSummary()(同 3.1)

L1 未返回结果, L0 作为兜底提供正文内容。


四、决策矩阵

needFullContent = highConfidence || !hasL1
场景 matches L1 结果 needFullContent L0 策略 是否读文件 上下文大小
唯一匹配 1 未执行 true buildCompactSummary 是 ~600 字符
多匹配 + L1 有结果 2+ 有 false buildMetadataOnlySummary 否 ~150 字符
多匹配 + L1 无结果 2+ 无 true buildCompactSummary 是 ~600 字符
无匹配 0 有 — 无 L0,仅 L1 否 0

五、代码结构

LookupKnowledgeTool
 ├── lookupKnowledge(query)           # 入口:编排 L0 + L1
 ├── buildResult(l0, l1, confidence)  # 组装结果,选择摘要策略
 ├── buildCompactSummary(entry)       # 元数据 + 章节 + 正文片段(读文件)
 ├── buildMetadataOnlySummary(entry)  # 仅元数据(不读文件)
 ├── countMdHeadings(content)         # 统计章节数(日志用)
 └── extractFirstMeaningfulLine(...)  # 提取首个有意义文本行(日志用)

关键逻辑(buildResult)

boolean needFullContent = highConfidence || !hasL1;
String content = needFullContent
    ? buildCompactSummary(first)
    : buildMetadataOnlySummary(first);

六、日志输出示例

多匹配场景(matches=2, L1 有结果)

[L0 精确匹配] 完成: matches=2, time=3ms
[置信度判断] highConfidence=false, reason=多个或零个匹配
[L1 语义检索] L0非唯一匹配,触发L1语义检索...
[L1 语义检索] 完成: matches=1, time=245ms
----------------------------------------
<<< [工具返回] lookup_knowledge
<<< [L0 主结果] 标题: 支付网关错误码定义
<<< [L0 主结果] 摘要: 记录了支付网关所有核心错误码的含义及排查方向    ← 仅元数据
<<< [L0 主结果] 内容: 126 字符, 0 个章节                              ← 约150字符
<<< [L1 补充] 相似度: 0.8234
<<< [L1 补充] 内容片段: 支付网关请求超时...                           ← L1 提供具体内容

唯一匹配场景(matches=1, 跳过 L1)

[L0 精确匹配] 完成: matches=1, time=2ms
[置信度判断] highConfidence=true, reason=唯一匹配
[L1 语义检索] L0唯一匹配,跳过L1检索
----------------------------------------
<<< [工具返回] lookup_knowledge
<<< [L0 主结果] 标题: 支付网关错误码定义
<<< [L0 主结果] 摘要: 记录了支付网关所有核心错误码的含义及排查方向
<<< [L0 主结果] 内容: 725 字符, 3 个章节                              ← 约700字符

七、MVP 效率评估 & 改进方向

7.1 当前效率评估

维度 评分 说明
L0 匹配速度 ★★★★★ 内存索引,< 10ms,几乎没有优化空间
L1 检索速度 ★★★★☆ Milvus 向量检索,200-500ms,取决于数据量
L0 匹配准确率 ★★☆☆☆ 子串匹配,无排序无评分,匹配即返回
L1 检索准确率 ★★★☆☆ 语义相似度,但分块缺少上下文信息
召回率(查全) ★★★☆☆ L0+L1 两阶段覆盖大多数场景,但缺乏融合重排
上下文利用率 ★★★★☆ 根据场景动态控制 L0 内容量,已优化
综合 ★★★☆☆ MVP 可用,但检索质量有提升空间

7.2 关键瓶颈

瓶颈 1:分块丢失上下文(✅ 已修复—见下方 7.5)

当前每个 Chunk 只记录最近的 ## 标题:

{
  "content": "**含义**:支付网关请求超时\n**常见原因**:网络延迟",
  "title": "超时类错误",
  "chunkIndex": 2
}

LLM 收到这个片段时不知道它属于"支付网关错误码定义"这个文档,也不知道具体错误码名称是 ERR_TIMEOUT。如果同时检索了多个文档的片段,LLM 容易混淆。

瓶颈 2:L0 关键词匹配过于简单

当前 KnowledgeIndexService.matchesKeywords() 只做子串包含匹配,没有:

  • 排序/评分(多个匹配时按什么顺序?)
  • 权重(标题匹配 > 正文匹配)
  • 部分匹配("timeout" 匹配 "ERR_TIMEOUT")

瓶颈 3:L0 和 L1 无交叉融合

两阶段检索结果只是简单的"1位L0 + 1位L1"拼接,没有:

  • RRF 或加权融合重排
  • 重复内容去重
  • 根据相关性选择 top-K

7.3 改进方向分析

方向 A:面包屑导航(Chunk 携带层级上下文)

做法:分块时记录完整的标题层级路径作为 breadcrumb。

当前分块 metadata:

{ "title": "超时类错误" }

改进后:

{
  "title": "超时类错误",
  "breadcrumb": "支付网关错误码定义 > 超时类错误 > ERR_TIMEOUT",
  "heading_h1": "支付网关错误码定义",
  "heading_h2": "超时类错误",
  "heading_h3": "ERR_TIMEOUT"
}

收益评估:

场景 无面包屑的问题 有面包屑的改善 提升幅度
单文档多分块 LLM 知道标题但不知道层级关系 清楚"文档>章节>条目"归属 中等
跨文档混合结果 分块看不出源文档 breadcrumb 第一段就是文档标题 大
深层嵌套文档(3+ 级) 分块内容难以定位 完整路径一目了然 显著
向量检索相关性 只对 chunk content 做 embedding breadcrumb 可拼入 content 做 embedding 或单独索引 中等

MVP 阶段价值:当前文档结构较浅(2-3级),breadcrumb 对 LLM 理解帮助中等。但如果后续文档层级加深(像你提到的"排障指南 > 支付网关 > 502错误处理"),价值会显著提升。

实现成本:低。修改 DocumentChunkService 的分块逻辑,积累当前标题栈,写入 DocumentChunk 和 Milvus metadata。

方向 B:混合检索 + RRF 重排

做法:L0 关键词和 L1 向量检索并行执行 → 结果用 Reciprocal Rank Fusion 统一排序 → 取 top-K。

用户查询 → 并行的:
            ├── L0 关键词匹配 → 得分向量 S₀
            └── L1 向量检索  → 得分向量 S₁
                           ↓
                   RRF 融合重排
                           ↓
                   top-K 统一结果

RRF 公式:对每个文档 d,score(d) = Σ 1/(k + rank_r(d)),其中 k=60(常数)。

收益评估:

场景 当前的问题 混合 + RRF 提升幅度
精确关键词("ERR_TIMEOUT") L0 匹配但不排序,L1 可能不匹配 L0 高排名 → RRF 拉到顶部 大
语义查询("支付超时如何处理") L0 可能不匹配,全靠 L1 L1 兜底不受影响 无变化
混合查询("ERR_TIMEOUT 支付网关超时") L0 匹配一个、L1 匹配一个,无融合 RRF 统一排序,更合理 中等
多文档匹配 L0 返回无序列表 + L1 独立结果 统一排序、去重 大

MVP 阶段价值:RRF 的实现成本和维护成本较高,而当前 MVP 数据量小(6 个文档),人工检查即可确定哪些匹配是好的。建议数据量 > 50 个文档时引入。

方向 C:Breadcrumb + Embedding 增强

做法:将 breadcrumb 拼入 chunk content 后再做 embedding,让向量包含层级语义。

// 当前
embeddingService.generateEmbedding(chunk.getContent())

// 改进
String augmentedContent = chunk.getBreadcrumb() + "\n" + chunk.getContent();
embeddingService.generateEmbedding(augmentedContent);

这样搜索"ERR_TIMEOUT"时,"支付网关错误码定义 > 超时类错误 > ERR_TIMEOUT" 也会匹配到,而不只是 chunk 正文。

场景 当前 Breadcrumb + Embedding 提升
搜索"支付网关超时" 匹配到正文含"超时"和"支付网关"的 chunk breadcrumb 直接含"支付网关",匹配更准 中等
搜索"错误码定义" 可能匹配不到具体错误内容的 chunk breadcrumb 含"错误码定义",相关性更高 大

7.4 实施优先级建议

优先级 改进项 复杂度 收益 状态
P0 Breadcrumb 上下文(方向 A) 低 中 ✅ 已实现 (2026-06-26)
P1 下个版本 低 中-大 待定
P1 L0 排序(匹配评分 + 排序) 低 中 待定
P2 混合检索 + RRF 重排 高 大 数据量 > 50 文档时引入

7.5 Breadcrumb 实现说明

已于 2026-06-26 实现。改动范围:

文件 改动
DocumentChunk.java 新增 breadcrumb 字段
DocumentChunkService.java splitByHeadings() 维护标题层级栈,Section 新增 level/breadcrumb,chunkSection() 和 saveChunkAndGetNextStart() 透传 Breadcrumb
VectorIndexService.java buildMetadata() 和 buildDocumentMetadata() 将 breadcrumb 写入 Milvus metadata

层级栈算法

// 在 splitByHeadings() 中,每次匹配到标题时:
while (!headingStack.isEmpty() && headingStack.size() >= level) {
    headingStack.remove(headingStack.size() - 1); // 弹出同级或更高级
}
headingStack.add(title);  // 追加当前标题
currentBreadcrumb = String.join(" > ", headingStack);

示例:处理 fault-diagnosis-process.md 的完整面包屑路径──

// 分块 "应急响应流程 > 1. 初步评估"
{ "breadcrumb": "故障诊断流程规范 > 应急响应流程 > 1. 初步评估" }

// 分块 "根因分析方法 > 5-Why 分析法"  
{ "breadcrumb": "故障诊断流程规范 > 根因分析方法 > 5-Why 分析法" }

当前 metadata 结构(Milvus)

{
  "_source": "knowledge_base/api/payment-errors.md",
  "_file_name": "payment-errors.md",
  "category": "api",
  "chunkIndex": 2,
  "totalChunks": 5,
  "title": "超时类错误",
  "breadcrumb": "支付网关错误码定义 > 超时类错误 > ERR_TIMEOUT"
}

以 fault-diagnosis-process.md 为例:

# 故障诊断流程规范          ← heading_h1

## 应急响应流程            ← heading_h2

### 1. 初步评估           ← heading_h3(分块1)
内容...

### 2. 快速止血           ← heading_h3(分块2)
内容...

## 根因分析方法            ← heading_h2

### 5-Why 分析法          ← heading_h3(分块3)
内容...

改造后每个分块的 metadata:

分块1: breadcrumb = "故障诊断流程规范 > 应急响应流程 > 1. 初步评估"
分块2: breadcrumb = "故障诊断流程规范 > 应急响应流程 > 2. 快速止血"
分块3: breadcrumb = "故障诊断流程规范 > 根因分析方法 > 5-Why 分析法"

LLM 视角受益:当检索到 "2. 快速止血" 时,LLM 立刻知道它属于"故障诊断流程规范 > 应急响应流程"体系,不需要额外读取其他分块来推断上下文。

文件 说明
LookupKnowledgeTool.java 检索工具入口
KnowledgeIndexService.java L0 内存索引管理
VectorSearchService.java L1 向量检索(Milvus)
KnowledgeEntry.java 索引条目 DTO(含 title, summary, keywords)
LookupResult.java 查询结果 DTO
PrimaryResult.java L0 结果 DTO
SupplementResult.java L1 结果 DTO