Files
zhuyongxin a1c896ebda chore(docs): 归档 ISS-001 session-dedup-knowledge-map + ISS-002 mvp 文档
- 移动 session-dedup-knowledge-map OpenSpec 到 archive 目录
- 提交 ISS-001 遗留的 devflow 档案文件
- 更新 ISS-002 状态为已修复
- 新增 mvp/architecture/action-memory-relevance.md 设计文档
- 更新 mvp/README.md 文档导航
- 更新 devflow/index.md OpenSpec 链接指向 archive
2026-07-01 18:27:04 +08:00

158 lines
6.7 KiB
Markdown
Raw Permalink 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.
# Design: session-dedup-knowledge-map
## 1. 整体架构
本 change 包含两个独立但互补的部分:
```
Part A: 工具层去重
LookupKnowledgeTool
├── 维护 ConcurrentHashMap<sessionId, Set<filePath>>(JVM 内)
├── 每次检索前过滤已召回文档
└── SessionContextHolder.clear() 时同步清理
Part B: 知识图谱
┌─────────────────────────────────────────────┐
│ 文档上传 (DocumentManagementService) │
│ → LLM 生成 doc.covers + doc.when_to_retrieve │
│ → 存入 api_document.metadata │
│ → 触发域级重算 (KnowledgeDomainService) │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 域级聚合 (KnowledgeDomainService) │
│ → 读取同域所有文档的 when_to_retrieve │
│ → LLM 生成 domain.when_to_retrieve │
│ → 存入 knowledge_domain 表 │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 启动 (KnowledgeIndexService.loadIndex) │
│ → 加载 knowledge_domain 表 │
│ → 某域无记录则触发域级生成 │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Planner prompt (ChatService) │
│ → 注入 knowledge map(域级) │
│ → Planner 做粗粒度检索决策 │
└─────────────────────────────────────────────┘
```
---
## 2. 数据结构定义
### 2.1 Frontmatter 新增字段
```yaml
# 新增两个字段,其余不变
covers: ["支付失败排查", "扣款无回调"] # List<String>:业务场景标签,Planner 决策用
when_to_retrieve: "用户描述支付失败、超时时" # String:文档级检索时机,LLM 上传时生成
```
对应 `Frontmatter.java` 新增两个字段:
- `List<String> covers`
- `String whenToRetrieve`
对应 `KnowledgeEntry.java` 新增两个字段(同上)。
### 2.2 knowledge_domain 表(新表)
```sql
CREATE TABLE knowledge_domain (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
domain_id VARCHAR(64) NOT NULL UNIQUE, -- category 值,如 "payment"
description VARCHAR(256), -- 域描述(聚合自文档 summary)
when_to_retrieve TEXT, -- 域级检索时机(LLM 生成)
document_count INT DEFAULT 0, -- 该域当前文档数
updated_at DATETIME,
created_at DATETIME
);
```
### 2.3 knowledge map 结构(注入 Planner 的 YAML 文本)
```yaml
available_knowledge_domains:
- domain_id: "payment"
description: "支付链路问题排查"
when_to_retrieve: "用户问题涉及支付、退款、对账时检索;优先检索一次,勿重复"
documents:
- title: "支付失败排查手册"
covers: ["支付超时", "扣款无回调"]
- title: "退款处理指南"
covers: ["退款未到账", "退款状态异常"]
- domain_id: "infrastructure"
...
```
---
## 3. 新增组件
### 3.1 KnowledgeDomainService(新类)
职责:域级聚合与存储
```
buildDomainSummary(category)
→ 读取同域所有 KnowledgeEntry(含 when_to_retrieve)
→ 拼装 prompt,调用 LLM
→ 写入 knowledge_domain 表
buildKnowledgeMap()
→ 读取所有 knowledge_domain 记录
→ 拼装 YAML 文本(含 documents 列表)
→ 返回 String(供 Planner prompt 注入)
onDocumentChange(category)
→ 调用 buildDomainSummary(category)(只重算受影响域)
```
### 3.2 RetrievedDocTracker(新类,或内联入 LookupKnowledgeTool)
职责:session 级已召回文档追踪
```
ConcurrentHashMap<String, Set<String>> retrieved
key: sessionId
value: Set<filePath>
isAlreadyRetrieved(sessionId, filePath) → boolean
markRetrieved(sessionId, filePath)
clearSession(sessionId) ← 由 SessionContextHolder.clear() 触发
```
---
## 4. 改动文件清单
| 文件 | 改动类型 | 说明 |
|---|---|---|
| `LookupResult.java` | 修改 | 新增 `message` 字段(去重提示文本) |
| `Frontmatter.java` | 修改 | 新增 `covers`、`whenToRetrieve` |
| `KnowledgeEntry.java` | 修改 | 新增 `covers`、`whenToRetrieve` |
| `FrontmatterParser.java` | 修改 | 解析新字段 |
| `DocumentManagementService.java` | 修改 | upload 时调 LLM 生成文档级字段;upload/delete 后触发域级重算 |
| `KnowledgeIndexService.java` | 修改 | loadIndex 时加载域级数据;若域无记录则触发生成 |
| `KnowledgeDomainService.java` | 新增 | 域聚合、LLM 调用、DB 读写、buildKnowledgeMap |
| `KnowledgeDomain.java`(entity) | 新增 | knowledge_domain 表映射 |
| `KnowledgeDomainRepository.java` | 新增 | JPA Repository |
| `LookupKnowledgeTool.java` | 修改 | 集成 RetrievedDocTracker,检索前过滤,检索后标记 |
| `SessionContextHolder.java` | 修改 | clear() 时通知 RetrievedDocTracker |
| `RetrievedDocTracker.java` | 新增 | session 级去重状态管理 |
| `ChatService.java` | 修改 | buildChatPlannerAgent 注入 knowledge map |
| `chat-planner-prompt.md` | 修改 | 添加 knowledge map 使用规则 |
| `V009__add_knowledge_domain.sql` | 新增 | Flyway 建表脚本 |
---
## 5. 关键决策记录
1. **域级 when_to_retrieve 存 DB**:避免每次重启调 LLM;文档变更时只重算受影响域
2. **文档级 when_to_retrieve 存 metadata JSON**:沿用现有 frontmatter 存储路径,无需新字段
3. **RetrievedDocTracker 独立于 SessionContextHolder**:SessionContextHolder 只持有 sessionId,Tracker 是业务状态,职责分离;clear() 时通过 Tracker.clearSession() 联动
4. **Planner 只看域级**:文档级 when_to_retrieve 留 Executor 筛选(Phase 2),MVP 不暴露给 Planner
5. **LLM 调用同步执行**:上传时同步生成,接受约 1-2s 延迟,保证数据库和 L0 索引立即一致