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

9.8 KiB
Raw Blame History

知识库初始化 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:强制重新导入所有文档

请求示例:

# 首次导入(去重模式)
curl -X POST http://localhost:9900/api/knowledge/init

# 强制重新导入
curl -X POST http://localhost:9900/api/knowledge/init?force=true

响应示例:

{
  "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

请求示例:

curl http://localhost:9900/api/knowledge/stats

响应示例:

{
  "success": true,
  "totalDocuments": 6,
  "totalVectors": 48,
  "categories": {
    "api": 1,
    "domain": 1,
    "infrastructure": 3,
    "troubleshooting": 1
  }
}

字段说明:

  • totalDocuments:数据库中的文档总数
  • totalVectors:Milvus 中的向量总数(chunk 数量)
  • categories:按分类统计的文档数量

使用场景

场景 1:项目启动时初始化

# 1. 启动应用
mvn spring-boot:run

# 2. 等待应用启动完成(约 10 秒)

# 3. 调用初始化接口
curl -X POST http://localhost:9900/api/knowledge/init

# 4. 查看结果
# 日志输出:知识库初始化完成: 扫描=6, 跳过=0, 新增=6, 失败=0

场景 2:添加新文档后重新初始化

# 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:强制重新导入所有文档

# 适用场景:
# - 数据库被清空,需要重新导入
# - 文档内容有更新,需要刷新
# - 索引损坏,需要重建

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. 文件移动会被视为新文档:

    # 移动前:api/payment-errors.md
    # 移动后:errors/payment-errors.md
    # 结果:会被当作两个不同的文档
    
  2. 文件重命名会被视为新文档:

    # 重命名前:payment-errors.md
    # 重命名后:payment-error-codes.md
    # 结果:会被当作两个不同的文档
    
  3. 内容更新不触发重新导入(非 force 模式):

    # 修改文件内容后调用 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 结构

{
  "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 的内存索引:

KnowledgeEntry entry = KnowledgeEntry.builder()
    .filePath(relativePath)
    .title(title)
    .keywords(keywords)
    .summary(summary)
    .category(category)
    .build();
knowledgeIndexService.addToIndex(entry);

验证 L0 索引:

# 应用启动后查看日志
grep "知识库索引加载完成" logs/application.log

# 输出示例:
# [INFO] 知识库索引加载完成,共 6 个文档

错误处理

常见错误

1. 目录不存在

{
  "success": false,
  "message": "初始化失败: 知识库目录不存在: knowledge_base"
}

解决:

mkdir -p knowledge_base/api
mkdir -p knowledge_base/infrastructure
mkdir -p knowledge_base/domain
mkdir -p knowledge_base/troubleshooting

2. 文档格式无效

{
  "success": true,
  "scanned": 6,
  "inserted": 5,
  "failed": 1,
  "details": {
    "test/invalid.md": "格式无效: frontmatter 解析失败"
  }
}

原因:

  • 缺少 frontmatter
  • YAML 格式错误
  • 缺少必填字段(title, keywords, summary)

解决:

---
title: 文档标题
keywords: [关键词1, 关键词2]
summary: 文档摘要
category: api
---

# 正文内容

问题 4: Milvus 连接失败

症状:

{
  "success": true,
  "scanned": 6,
  "inserted": 0,
  "failed": 6,
  "details": {
    "api/payment-errors.md": "Milvus 索引失败: Connection refused"
  }
}

原因:

  • Milvus 服务未启动
  • 网络连接问题
  • 配置错误

解决:

# 检查 Milvus 是否运行
docker ps | grep milvus

# 检查配置
grep milvus application.yml

# 启动 Milvus
docker-compose up -d milvus-standalone

问题 5: 文档分块失败

症状:

{
  "details": {
    "test/large-doc.md": "Milvus 索引失败: Document too large"
  }
}

原因:

  • 文档内容过大
  • 分块配置不当

解决:

  • 检查 DocumentChunkConfig 配置
  • 调整 chunk size 和 overlap

3. 文档缺少标题

{
  "details": {
    "test/no-title.md": "缺少标题"
  }
}

解决:在 frontmatter 中添加 title 字段。


最佳实践

✅ 推荐做法

  1. 首次启动后立即初始化:

    mvn spring-boot:run
    sleep 15  # 等待启动完成
    curl -X POST http://localhost:9900/api/knowledge/init
    
  2. 新增文档后增量导入:

    # 不使用 force,只导入新文档
    curl -X POST http://localhost:9900/api/knowledge/init
    
  3. 定期检查统计信息:

    curl http://localhost:9900/api/knowledge/stats
    
  4. 更新文档内容后强制刷新:

    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