Files
SuperBizAgent-java/.docs/2026-06-25-knowledge-base-init-api.md
T
zhuyongxin 3ed48e38cd feat(knowledge): 完整实现知识库初始化 - 包含 Milvus 向量索引
## 核心改动

在上一版本基础上,补充完整的 Milvus (L1) 向量索引功能。

### 新增依赖注入

```java
@Autowired
private DocumentChunkService documentChunkService;

@Autowired
private VectorIndexService vectorIndexService;

@Autowired
private VectorEmbeddingService vectorEmbeddingService;
```

### 完整的数据流

```
knowledge_base/*.md
    ↓ 1. 扫描 & 解析 frontmatter
    ↓ 2. 保存到 MySQL (api_document)
    ↓ 3. 提取正文 & 文档分块
    ↓ 4. 生成向量并索引到 Milvus
    ↓ 5. 加入 L0 内存索引
完成 (L0 + L1 双层索引)
```

### 关键代码

```java
// 1. 提取正文(去除 frontmatter)
String body = extractBody(content);

// 2. 文档分块
List<DocumentChunk> chunks = documentChunkService.chunkDocument(body, relativePath);

// 3. 上传到 Milvus
vectorIndexService.indexDocumentChunks(document.getDocId(), chunks, category);

// 4. 更新状态
document.setStatus("INDEXED");
document.setChunkCount(chunks.size());
```

### 错误处理

- Milvus 索引失败时:
  - 更新文档状态为 FAILED
  - 记录错误信息到 error_message 字段
  - 继续处理下一个文档(不中断整个流程)

### 响应示例

```json
{
  "success": true,
  "scanned": 6,
  "inserted": 6,
  "failed": 0,
  "details": {
    "api/payment-errors.md": "导入成功(L0+L1)"
  }
}
```

### 数据库字段

新增:
- `chunk_count`:分块数量
- `error_message`:错误信息(失败时)

## 验证步骤

```bash
# 1. 启动应用(确保 Milvus 已运行)
mvn spring-boot:run

# 2. 初始化知识库
curl -X POST http://localhost:9900/api/knowledge/init

# 3. 验证结果
# - MySQL: 检查 api_document 表
# - Milvus: 检查 knowledge_base_collection
# - L0: 日志显示"知识库索引加载完成,共 6 个文档"

# 4. 测试 L1 语义检索
# lookup_knowledge("支付为什么会失败")
# 应该返回 semantic_L1 结果
```

## 文档更新

- 更新使用文档,删除"暂未实现 L1"的说明
- 添加 Milvus 数据结构说明
- 添加 Milvus 相关错误处理
2026-06-25 11:00:10 +08:00

470 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 知识库初始化 API 使用文档
## 概述
提供了知识库批量初始化接口,用于将 `knowledge_base` 目录下的所有 Markdown 文档导入到数据库和向量索引(L0 + L1)。
**功能特点**:
1. ✅ **批量扫描**:递归扫描 knowledge_base 目录下所有 .md 文件
2. ✅ **自动去重**:基于文件路径检查,避免重复导入
3. ✅ **数据入库**:保存文档元数据到 MySQL
4. ✅ **L0 索引**:自动加入内存精确匹配索引
5. ✅ **L1 索引**:文档分块并上传到 Milvus 向量数据库
---
## API 接口
### 1. 初始化知识库
**端点**:
```
POST /api/knowledge/init?force=false
```
**参数**:
- `force`(可选):是否强制重新导入,跳过去重检查
- `false`(默认):跳过已存在的文档
- `true`:强制重新导入所有文档
**请求示例**:
```bash
# 首次导入(去重模式)
curl -X POST http://localhost:9900/api/knowledge/init
# 强制重新导入
curl -X POST http://localhost:9900/api/knowledge/init?force=true
```
**响应示例**:
```json
{
"success": true,
"message": "知识库初始化完成",
"scanned": 6,
"skipped": 0,
"inserted": 6,
"failed": 0,
"details": {
"api/payment-errors.md": "导入成功(L0+L1)",
"domain/spring-ai-tool-best-practices.md": "导入成功(L0+L1)",
"infrastructure/flyway-best-practices.md": "导入成功(L0+L1)",
"infrastructure/mysql-connection-pool.md": "导入成功(L0+L1)",
"infrastructure/redis-config.md": "导入成功(L0+L1)",
"troubleshooting/fault-diagnosis-process.md": "导入成功(L0+L1)"
}
}
```
**字段说明**:
- `scanned`:扫描到的文件总数
- `skipped`:跳过的文件数量(已存在)
- `inserted`:成功导入的文件数量
- `failed`:失败的文件数量
- `details`:每个文件的处理结果详情
---
### 2. 查询知识库统计
**端点**:
```
GET /api/knowledge/stats
```
**请求示例**:
```bash
curl http://localhost:9900/api/knowledge/stats
```
**响应示例**:
```json
{
"success": true,
"totalDocuments": 6,
"totalVectors": 48,
"categories": {
"api": 1,
"domain": 1,
"infrastructure": 3,
"troubleshooting": 1
}
}
```
**字段说明**:
- `totalDocuments`:数据库中的文档总数
- `totalVectors`:Milvus 中的向量总数(chunk 数量)
- `categories`:按分类统计的文档数量
---
## 使用场景
### 场景 1:项目启动时初始化
```bash
# 1. 启动应用
mvn spring-boot:run
# 2. 等待应用启动完成(约 10 秒)
# 3. 调用初始化接口
curl -X POST http://localhost:9900/api/knowledge/init
# 4. 查看结果
# 日志输出:知识库初始化完成: 扫描=6, 跳过=0, 新增=6, 失败=0
```
---
### 场景 2:添加新文档后重新初始化
```bash
# 1. 添加新文档到 knowledge_base 目录
echo "---
title: 新文档
keywords: [测试, test]
summary: 这是一个测试文档
category: test
---
# 新文档内容
" > knowledge_base/test/new-doc.md
# 2. 调用初始化接口(去重模式)
curl -X POST http://localhost:9900/api/knowledge/init
# 3. 查看结果
# 只会导入新文档,跳过已存在的 6 个文档
# 响应: scanned=7, skipped=6, inserted=1, failed=0
```
---
### 场景 3:强制重新导入所有文档
```bash
# 适用场景:
# - 数据库被清空,需要重新导入
# - 文档内容有更新,需要刷新
# - 索引损坏,需要重建
curl -X POST http://localhost:9900/api/knowledge/init?force=true
# 响应: scanned=6, skipped=0, inserted=6, failed=0
```
---
## 去重机制
### 去重依据
- **文件路径**:相对于 `knowledge_base` 目录的相对路径
- 示例:`api/payment-errors.md`
### 去重逻辑
```
if (!force && existingFilePaths.contains(relativePath)) {
跳过该文档
} else {
导入该文档
}
```
### 注意事项
1. **文件移动会被视为新文档**:
```bash
# 移动前:api/payment-errors.md
# 移动后:errors/payment-errors.md
# 结果:会被当作两个不同的文档
```
2. **文件重命名会被视为新文档**:
```bash
# 重命名前:payment-errors.md
# 重命名后:payment-error-codes.md
# 结果:会被当作两个不同的文档
```
3. **内容更新不触发重新导入**(非 force 模式):
```bash
# 修改文件内容后调用 init(非 force)
# 结果:跳过该文档,数据库中仍是旧内容
# 解决:使用 force=true 强制重新导入
```
---
## 数据存储
### 完整的数据流
```
knowledge_base/*.md
↓ 1. 扫描
KnowledgeBaseInitService
↓ 2. 解析 frontmatter
Frontmatter (title, keywords, summary)
↓ 3. 保存到数据库
MySQL (api_document)
↓ 4. 提取正文 & 分块
DocumentChunkService
↓ 5. 生成向量
VectorEmbeddingService
↓ 6. 索引到 Milvus
Milvus (L1 向量索引)
↓ 7. 加入内存索引
KnowledgeIndexService (L0)
```
---
### 数据库表结构(api_document)
| 字段 | 类型 | 说明 | 示例 |
|------|------|------|------|
| `id` | BIGINT | 主键 | 1 |
| `doc_id` | VARCHAR(64) | 文档唯一标识 | uuid |
| `file_name` | VARCHAR(256) | 文件名 | payment-errors.md |
| `file_path` | VARCHAR(512) | 相对路径 | api/payment-errors.md |
| `api_name` | VARCHAR(128) | 文档标题 | 支付网关错误码定义 |
| `status` | VARCHAR(16) | 状态 | INDEXED / FAILED |
| `chunk_count` | INT | 分块数量 | 8 |
| `error_message` | TEXT | 错误信息 | null |
| `metadata` | TEXT | Frontmatter JSON | {"title":"...","keywords":[...]} |
| `file_size` | BIGINT | 文件大小(字节) | 2048 |
| `indexed_at` | DATETIME | 索引时间 | 2026-06-25 10:00:00 |
### metadata JSON 结构
```json
{
"title": "支付网关错误码定义",
"summary": "记录了支付网关所有核心错误码的含义及排查方向",
"category": "api",
"keywords": ["ERR_TIMEOUT","超时","支付网关"]
}
```
---
### Milvus 向量索引
每个文档会被分块(chunk)并生成向量,存储到 Milvus 集合中:
**Collection**: `knowledge_base_collection`
**字段**:
- `doc_id`:文档 ID
- `chunk_id`:分块 ID
- `chunk_text`:分块文本内容
- `embedding`:768 维向量
- `category`:文档分类
- `file_path`:文件路径
**分块策略**:
- Chunk Size:根据 `DocumentChunkConfig` 配置(默认 500 token)
- Overlap:重叠区域(默认 50 token)
---
## L0 内存索引
导入过程会自动将文档加入 `KnowledgeIndexService` 的内存索引:
```java
KnowledgeEntry entry = KnowledgeEntry.builder()
.filePath(relativePath)
.title(title)
.keywords(keywords)
.summary(summary)
.category(category)
.build();
knowledgeIndexService.addToIndex(entry);
```
**验证 L0 索引**:
```bash
# 应用启动后查看日志
grep "知识库索引加载完成" logs/application.log
# 输出示例:
# [INFO] 知识库索引加载完成,共 6 个文档
```
---
## 错误处理
### 常见错误
#### 1. 目录不存在
```json
{
"success": false,
"message": "初始化失败: 知识库目录不存在: knowledge_base"
}
```
**解决**:
```bash
mkdir -p knowledge_base/api
mkdir -p knowledge_base/infrastructure
mkdir -p knowledge_base/domain
mkdir -p knowledge_base/troubleshooting
```
---
#### 2. 文档格式无效
```json
{
"success": true,
"scanned": 6,
"inserted": 5,
"failed": 1,
"details": {
"test/invalid.md": "格式无效: frontmatter 解析失败"
}
}
```
**原因**:
- 缺少 frontmatter
- YAML 格式错误
- 缺少必填字段(title, keywords, summary)
**解决**:
```markdown
---
title: 文档标题
keywords: [关键词1, 关键词2]
summary: 文档摘要
category: api
---
# 正文内容
```
---
### 问题 4: Milvus 连接失败
**症状**:
```json
{
"success": true,
"scanned": 6,
"inserted": 0,
"failed": 6,
"details": {
"api/payment-errors.md": "Milvus 索引失败: Connection refused"
}
}
```
**原因**:
- Milvus 服务未启动
- 网络连接问题
- 配置错误
**解决**:
```bash
# 检查 Milvus 是否运行
docker ps | grep milvus
# 检查配置
grep milvus application.yml
# 启动 Milvus
docker-compose up -d milvus-standalone
```
---
### 问题 5: 文档分块失败
**症状**:
```json
{
"details": {
"test/large-doc.md": "Milvus 索引失败: Document too large"
}
}
```
**原因**:
- 文档内容过大
- 分块配置不当
**解决**:
- 检查 `DocumentChunkConfig` 配置
- 调整 chunk size 和 overlap
---
#### 3. 文档缺少标题
```json
{
"details": {
"test/no-title.md": "缺少标题"
}
}
```
**解决**:在 frontmatter 中添加 `title` 字段。
---
## 最佳实践
### ✅ 推荐做法
1. **首次启动后立即初始化**:
```bash
mvn spring-boot:run
sleep 15 # 等待启动完成
curl -X POST http://localhost:9900/api/knowledge/init
```
2. **新增文档后增量导入**:
```bash
# 不使用 force,只导入新文档
curl -X POST http://localhost:9900/api/knowledge/init
```
3. **定期检查统计信息**:
```bash
curl http://localhost:9900/api/knowledge/stats
```
4. **更新文档内容后强制刷新**:
```bash
curl -X POST http://localhost:9900/api/knowledge/init?force=true
```
---
### ❌ 避免做法
1. **不检查响应就认为成功**:
- 始终检查 `failed` 字段
- 查看 `details` 了解具体失败原因
2. **频繁使用 force=true**:
- 会重复插入数据(违反唯一约束)
- 建议先清理数据库,再使用 force
3. **不检查文档格式就导入**:
- 先手动验证 frontmatter 格式
- 确保必填字段完整
---
## 相关文档
- **知识库使用指南**:`mvp/architecture/knowledge-retrieval-usage.md`
- **知识库架构**:`mvp/architecture/knowledge-retrieval-architecture.md`
- **Executor Prompt**:`src/main/resources/prompts/executor-prompt.md`