检索系统概览
检索系统是 Knowledge 服务的核心能力,提供从简单向量检索到复杂混合检索的多种方案,支持重排序优化和上下文补全。
检索架构
检索系统采用 四步流水线 设计:
| 步骤 | 说明 | 是否可选 |
|---|---|---|
| 基础检索 | 向量检索或混合检索 | 必选 |
| 信息补全 | 从数据库补全标题、位置、内容 | 自动执行 |
| 重排序 | qwen3-rerank 精排优化 | 可选 |
| 上下文扩展 | 扩展相邻分片 | 可选 |
基础检索
向量检索 (默认)
基于语义相似度的智能检索,能够理解查询意图:
查询文本 → Embedding 模型 → 查询向量 → 向量相似度计算 → 返回 TopK 相似分片优势:
- ✅ 理解语义,支持同义匹配
- ✅ 不需要精确关键词
劣势:
- ❌ 可能遗漏专有名词、精确词
混合检索 (可选)
结合关键词检索和向量检索,双路召回:
优势:
- ✅ 兼顾语义理解与精确匹配
- ✅ 召回更全面
适用场景: 包含专有名词、技术术语的查询
信息补全 (DocumentEnricher)
基础检索返回的结果可能缺少部分信息 (如标题、完整内容),需要从数据库补全:
java
// 伪代码 - 信息补全流程
public List<RetrievedDocument> enrich(List<RetrievedDocument> docs) {
// 1. 收集需要补全的文档 ID
Set<Long> documentIds = collectDocumentIds(docs);
// 2. 批量查询文档信息 (标题、作者、分类等)
Map<Long, KlDocumentEntity> documents =
documentMapper.selectByIds(documentIds);
// 3. 批量查询分片信息 (字符位置、完整内容等)
Map<Long, KlDocumentChunkEntity> chunks =
chunkMapper.selectByVectorIds(vectorIds);
// 4. 填充信息
for (RetrievedDocument doc : docs) {
KlDocumentEntity document = documents.get(doc.getDocumentId());
doc.setTitle(document.getTitle());
doc.setFileType(document.getFileType());
doc.setSource(document.getSource());
KlDocumentChunkEntity chunk = chunks.get(doc.getChunkId());
doc.setCharStartIndex(chunk.getCharStartIndex());
doc.setCharEndIndex(chunk.getCharEndIndex());
// 如果向量库不支持返回原文,从数据库补全
if (doc.getContent() == null) {
doc.setContent(chunk.getContent());
}
}
return docs;
}补全内容:
- 文档标题
- 文件类型
- 来源信息
- 字符位置 (
charStartIndex,charEndIndex) - 完整内容 (如果向量库未返回)
重排序 (可选)
对初检结果进行精细化排序,提升结果相关性:
初检结果 (Top 20) → qwen3-rerank 模型 → 精排结果 (Top 5)原理:
- 重排序模型深度理解查询与文档的相关性
- 比向量相似度更精准
成本:
- 需调用外部 API (阿里云 DashScope)
- 有额外延迟和费用
适用场景: 对检索精度要求高的场景
上下文扩展 (可选)
通过扩展相邻分片,解决分片截断导致的语义不完整问题:
问题场景
原文:
...分布式锁的实现方式有多种,常见的包括:
1. 基于数据库的实现
2. 基于 Redis 的实现
3. 基于 ZooKeeper 的实现...
分片结果:
Chunk 5: ...分布式锁的实现方式有多种,常见的包括:
Chunk 6: 1. 基于数据库的实现
Chunk 7: 2. 基于 Redis 的实现
Chunk 8: 3. 基于 ZooKeeper 的实现...
检索命中 Chunk 6,但缺少上下文...解决方案
自动扩展命中分片的前后相邻分片:
命中 Chunk 6 → 扩展 Chunk 5, 6, 7 → 合并为完整语义片段区间合并:
- 当多个命中分片在同一文档内且位置相邻时,自动合并区间
- 允许 100 字符间隙
- 避免返回重复内容
检索模式对比
| 模式 | 配置 | 效果 | 成本 |
|---|---|---|---|
| 基础模式 | 仅向量检索 | 语义匹配 | 低 |
| 混合模式 | 向量 + 关键词 | 召回更全面 | 中 |
| 精排模式 | 向量 + 重排序 | 结果更精准 | 中高 |
| 完整模式 | 混合 + 重排序 + 上下文 | 最佳效果 | 高 |
元数据过滤
所有检索模式都支持元数据过滤,缩小检索范围:
java
RetrievalOptions options = RetrievalOptions.builder()
.libraryIds(List.of("lib-1", "lib-2")) // 按知识库过滤
.documentId("doc-001") // 按文档过滤
.author("张三") // 按作者过滤
.category("技术文档") // 按分类过滤
.tag("分布式") // 按标签过滤
.enableHybridSearch(true) // 启用混合检索
.build();支持的过滤字段:
| 字段 | 说明 | 查询类型 |
|---|---|---|
library_id | 知识库 ID | EQ / IN |
document_id | 文档 ID | EQ |
author | 作者 | EQ |
category | 分类 | EQ |
tags | 标签 | IN (多标签) |
核心组件
| 组件 | 接口/类 | 说明 |
|---|---|---|
| 检索编排 | KnowledgeRetrievalService | 四步流水线编排 |
| 向量检索 | VectorSearchService | Spring AI VectorStore 实现 |
| 关键词检索 | KeywordSearchService | ES / Lucene 实现 |
| 混合检索 | HybridSearchService | 双路召回 + 融合 |
| 重排序 | RerankService | qwen3-rerank 调用 |
| 信息补全 | DocumentEnricher | 数据库补全信息 |
| 上下文扩展 | ContextExpander | 相邻分片扩展 |