feat(knowledge): 完成 L0+L1 混合检索集成

核心功能:
- 新增 FrontmatterParser 解析 YAML frontmatter
- 新增 KnowledgeIndexService L0 内存索引
- 新增 LookupKnowledgeTool 混合检索工具
- 增强 DocumentManagementService 文件保存和索引同步

技术实现:
- 数据库迁移 V004: api_document.metadata (TEXT)
- 依赖新增: snakeyaml 2.0
- 配置新增: knowledge.base-path
- 可观测性: requestId 追踪 + 性能日志

质量保证:
- 单元测试: 31/31 通过
- 测试覆盖: FrontmatterParser(11), KnowledgeIndexService(13), LookupKnowledgeTool(7)
- 启动验证: L0 索引正常加载

归档文档:
- OpenSpec: openspec/changes/lookup-knowledge-integration/
- devflow 档案: devflow/projects/2026-06-24-lookup-knowledge-integration/
- handoff: handoff/2026-06-24-lookup-knowledge-integration.md
This commit is contained in:
zhuyongxin
2026-06-24 16:07:10 +08:00
parent c86045b33f
commit d6229f3385
32 changed files with 5396 additions and 67 deletions
@@ -0,0 +1,332 @@
# Lookup Knowledge Integration - Handoff Document
## 变更概述
**变更名称**: L0+L1 混合检索集成
**完成日期**: 2026-06-24
**OpenSpec 路径**: `openspec/changes/lookup-knowledge-integration/`
### 一句话总结
为 Agent 提供混合检索工具(lookup_knowledge),优先使用 L0 精确匹配,必要时补充 L1 语义检索,支持 Markdown frontmatter 元数据管理。
---
## 核心变更
### 1. 新增服务
**FrontmatterParser** (`com.superbiz.agent.service.FrontmatterParser`)
- 解析 Markdown 文件头的 YAML frontmatter
- 必填字段:title, keywords, summary
- 可选字段:category, version, author
**KnowledgeIndexService** (`com.superbiz.agent.service.KnowledgeIndexService`)
- L0 内存索引,启动时扫描 `knowledge_base/` 目录
- 精确关键词匹配(不区分大小写)
- 线程安全(CopyOnWriteArrayList)
### 2. 增强服务
**DocumentManagementService**
- 上传时保存原始文件到 `knowledge_base/{category}/{filename}`
- 解析 frontmatter 并存储到 `api_document.metadata` (JSON)
- 上传成功后更新 L0 索引
- 删除时同步清理本地文件和 L0 索引
### 3. 新增工具
**LookupKnowledgeTool** (`com.superbiz.agent.tool.LookupKnowledgeTool`)
- Agent 可调用工具:`lookup_knowledge(query)`
- L0 唯一匹配 → 高置信度 → 不调用 L1
- L0 多匹配/未匹配 → 低置信度 → 调用 L1
- 返回:primary (L0) + supplement (L1)
### 4. 数据库变更
**Flyway V004**: `api_document` 表新增 `metadata` 列
```sql
ALTER TABLE api_document
ADD COLUMN metadata TEXT COMMENT 'Frontmatter 元数据 (JSON)';
```
### 5. 配置变更
**application.yml**
```yaml
knowledge:
base-path: knowledge_base/
```
**pom.xml**
```xml
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.0</version>
</dependency>
```
---
## 使用方式
### Agent 调用示例
**场景 1: 唯一匹配(高置信度)**
```
Agent: lookup_knowledge("ERR_TIMEOUT")
返回:
{
"found": true,
"primary": {
"content": "# 支付网关错误码\n\n## ERR_TIMEOUT\n...",
"source": "knowledge_base/api/payment-errors.md",
"matchType": "exact_L0",
"confidence": "high"
},
"supplement": null
}
```
**场景 2: 多个匹配(低置信度 + L1 补充)**
```
Agent: lookup_knowledge("超时")
返回:
{
"found": true,
"primary": {
"content": "...",
"confidence": "low"
},
"supplement": {
"content": "语义相关的内容片段...",
"matchType": "semantic_L1"
}
}
```
### 文档上传示例
**带 frontmatter 的 Markdown**:
```markdown
---
title: 支付网关错误码定义
keywords: [ERR_TIMEOUT, 超时, 支付网关]
summary: 记录了支付网关所有核心错误码的含义及排查方向
category: api
---
# 正文内容
```
**上传后**:
- 文件保存: `knowledge_base/api/payment-errors.md`
- L0 索引: keywords 用于精确匹配
- L1 索引: 正文内容向量化
---
## 可观测性
### 日志追踪
**查询流程**(带 requestId):
```
[a1b2c3d4] 收到知识库查询请求: query=ERR_TIMEOUT
[a1b2c3d4] L0精确匹配完成: matches=1, time=2ms
[a1b2c3d4] 置信度判断: highConfidence=true, reason=唯一匹配
[a1b2c3d4] L0唯一匹配,跳过L1检索
[a1b2c3d4] 查询完成: found=true, confidence=high, totalTime=5ms
```
**文档上传**:
```
开始上传文档: fileName=payment-errors.md, size=1024 bytes
解析到frontmatter: title=支付网关错误码, keywords=[ERR_TIMEOUT], time=5ms
文档分块完成: chunks=3, time=12ms
文档向量索引完成: docId=abc123, time=850ms
文档已加入L0索引: docId=abc123, title=支付网关错误码
文档上传完成: totalTime=920ms
```
### 关键指标
- **L0 查询耗时**: < 10ms
- **L0+L1 总耗时**: < 500ms
- **文档上传耗时**: < 2s(含向量化)
### 详细文档
参考:`.docs/knowledge-observability.md`
---
## 测试覆盖
### 单元测试(31/31 通过)✅
- **FrontmatterParserTest**: 11 个用例
- 有效/无效/格式错误 frontmatter
- 边界情况(空文件、缺少必填字段)
- **KnowledgeIndexServiceTest**: 13 个用例
- 精确匹配(单个/多个/零个)
- 不区分大小写
- 文档读取(成功/失败/超长截断)
- **LookupKnowledgeToolTest**: 7 个用例
- 唯一匹配(高置信度,不调用 L1)
- 多个匹配(低置信度,调用 L1)
- 未匹配(仅返回 L1)
### 启动验证 ✅
- Flyway V004 迁移成功执行
- KnowledgeIndexService 正常扫描并加载索引
- 测试文档成功解析并加入 L0 索引
---
## 运维指南
### 启动流程
1. **扫描知识库目录**
```
开始扫描知识库目录: knowledge_base/
知识库索引加载完成,共 5 个文档
```
2. **验证索引**
- 检查日志中文档数量是否符合预期
- 如有 WARN 日志,检查 frontmatter 格式
### 故障排查
**问题 1: L0 索引为空**
- **原因**: knowledge_base/ 目录不存在或无 .md 文件
- **解决**: 检查目录权限,确保至少有一个带 frontmatter 的 .md 文件
**问题 2: 查询总是调用 L1**
- **原因**: L0 未匹配或多个匹配
- **解决**: 检查查询关键词是否在文档的 keywords 列表中
**问题 3: 文档上传后未进入 L0 索引**
- **原因**: frontmatter 格式错误或缺少必填字段
- **解决**: 检查 WARN 日志,修正 frontmatter 格式
### 日志分析
**查看单次查询完整流程**:
```bash
grep "[requestId]" logs/application.log
```
**统计 L0 命中率**:
```bash
grep "L0精确匹配完成" logs/application.log | \
awk -F'matches=' '{print $2}' | \
awk -F',' '{print $1}' | \
sort | uniq -c
```
**查看慢查询**:
```bash
grep "totalTime=" logs/application.log | \
awk -F'totalTime=' '{print $2}' | \
awk -F'ms' '{if ($1 > 1000) print}'
```
---
## 限制与注意事项
### 当前限制
1. **L0 索引持久化**
- 索引存储在内存中
- 应用重启需要重新扫描
- 解决方案:启动时自动扫描,通常 < 1s
2. **章节锚点(MVP 未实现)**
- sectionTitle 参数预留
- availableSections 字段返回 null
- 后续 Phase 2 实现
3. **批量导入**
- 当前仅支持单文件上传
- 大量文档需要循环调用 API
### 最佳实践
1. **编写高质量 frontmatter**
- keywords 精准且全面
- summary 简洁明了
- 避免关键词重复(导致多匹配)
2. **知识库目录组织**
```
knowledge_base/
├── api/ # API 相关
├── domain/ # 领域知识
└── troubleshoot/ # 故障排查
```
3. **监控告警**
- 慢查询: totalTime > 2s
- 失败率: > 10%
- L0 索引加载失败
---
## 后续增强方向
### Phase 2 候选特性
1. **章节锚点**
- 支持 sectionTitle 参数
- 直接定位到文档特定章节
- 减少返回内容长度
2. **L0 索引持久化**
- 序列化到文件
- 避免重启扫描
3. **批量导入工具**
- 支持目录批量导入
- 进度监控
4. **知识库管理 API**
- CRUD 接口
- 在线编辑
5. **向量化元数据**
- title/summary 也参与 L1 检索
- 提升语义检索准确度
---
## 相关文档
- **OpenSpec**: `openspec/changes/lookup-knowledge-integration/`
- proposal.md
- design.md
- specs/functional-specs.md
- tasks.md
- decisions.md
- **可观测性**: `.docs/knowledge-observability.md`
- **测试**: `src/test/java/com/superbiz/agent/`
- service/FrontmatterParserTest.java
- service/KnowledgeIndexServiceTest.java
- tool/LookupKnowledgeToolTest.java
---
## 联系人
**开发者**: Claude Code
**完成时间**: 2026-06-24
**审核状态**: ✅ 已归档
如有问题,请参考 OpenSpec 文档或联系团队。