docs(mvp): document dense+BM25 hybrid knowledge retrieval

Add current RAG architecture covering MilvusClientV2 hybrid search,
chunk evidence identity, rebuild ops, and update the MVP architecture
index and system overview links.
This commit is contained in:
zhuyongxin
2026-07-28 09:56:08 +08:00
parent 729cd3544a
commit 2f40536248
3 changed files with 364 additions and 3 deletions
+3 -2
View File
@@ -1,6 +1,6 @@
# MVP 架构文档
**更新日期**:2026-07-26
**更新日期**:2026-07-28
**状态**:当前单 Diagnosis Agent + Harness 架构
当前文档入口:
@@ -12,7 +12,8 @@
| [harness-quality-gates.md](harness-quality-gates.md) | Run、Tool、Evidence、Semantic、Release 与 Trace Recorder 门禁 |
| [session-trace-lifecycle.md](session-trace-lifecycle.md) | sessionId/runId、SSE、统一 Timeline 和 reasoning audit 生命周期 |
| [diagnosis-information-gain-stop-architecture.md](diagnosis-information-gain-stop-architecture.md) | 已实施的信息增益评价、Harness 饱和检测、Draft 合同失败降级与证据不足停止设计 |
| [rag-knowledge-retrieval-architecture.md](rag-knowledge-retrieval-architecture.md) | 当前 `lookup_knowledge` 检索:MilvusClientV2 dense+BM25 hybrid、chunk 证据身份、重建运维 |
2026-07-22 前的多角色编排、双入口和旧证据链文档已移动到 `archive/2026-07-22-legacy/`,仅用于历史决策追溯,不代表当前运行时。
2026-07-22 前的多角色编排、双入口和旧证据链文档已移动到 `archive/2026-07-22-legacy/`,仅用于历史决策追溯,不代表当前运行时。其中旧 RAG 描述(Spring AI VectorStore 主路径 + Milvus SDK fallback)已被当前 hybrid 实现取代,请以 [rag-knowledge-retrieval-architecture.md](rag-knowledge-retrieval-architecture.md) 为准。
当前普通 Trace 与 Provider reasoning 审计使用独立存储和独立接口。Reasoning 访问控制、保留期限、加密要求以及真实 Provider/V015 验证仍由 ISS-015 跟踪,不能把“数据已分表”理解为“治理已经完成”。
+33 -1
View File
@@ -1,12 +1,14 @@
# 当前 MVP 架构
**更新日期**:2026-07-23
**更新日期**:2026-07-28
**状态**:当前可运行架构
## 1. 系统定位
SuperBizAgent 是面向故障诊断的可追踪 Agent 应用。当前系统只保留一个拥有 Tool loop 的 `Diagnosis Agent`;Harness 负责确定性的预算、取消、工具边界、证据验真、语义审查和安全发布。
知识检索当前为显式 `lookup_knowledge` 工具 + 单一 MilvusClientV2 后端(dense / dense+BM25 hybrid)。详细链路见 [rag-knowledge-retrieval-architecture.md](rag-knowledge-retrieval-architecture.md)。
## 2. 分层
```mermaid
@@ -63,6 +65,29 @@ Agent 只看到三个固定 Tool:
每次调用由框架提供 `tool_call_id`,Harness 校验 exact run、只读、Schema、预算和容量。Redis 保存 TTL 内完整 canonical invocation;MySQL `tool_invocation` 只保存长期有界 metadata,不保存完整参数、SQL/日志正文、raw response 或 Agent projection。
### 4.1 `lookup_knowledge` 检索边界
```text
Agent
-> RagToolAdapter / ToolBoundary
-> LookupKnowledgeTool
-> L0 hint(可选 category filter)
-> KnowledgeSearchPort
-> VectorSearchService
-> MilvusHybridKnowledgeStore # 唯一知识向量后端
-> RagResultProjector # 有界 Agent 投影
```
要点:
- 默认 `retrieval.search.mode=hybrid`:dense ANN + BM25 sparse ANN + RRFRanker。
- 也可切 `dense`:仅 dense ANN。
- 已移除知识路径上的 legacy `MilvusServiceClient` search 与 `vector-store.mode=sdk|spring|auto` 路由。
- 证据按 chunk 级 `evidenceKey` 去重;Agent 侧 `document_id` 为 chunk 级身份。
- 知识库全量重建:`python scripts/rebuild_hybrid_knowledge.py --confirm REBUILD`,默认操作 collection `biz`。
完整 schema、模式、重建与历史差异见 [rag-knowledge-retrieval-architecture.md](rag-knowledge-retrieval-architecture.md)。
## 5. Trace 与持久化
```text
@@ -90,6 +115,13 @@ chat_session(sessionId)
Reasoning endpoint 是敏感审计面,不属于普通业务 API。当前已完成数据和查询隔离;认证授权、保留期限、加密要求及真实 Provider 验证仍由 ISS-015 收敛。Feedback、文档与检索 API 保持独立;已删除的旧诊断和 Redis conversation Session endpoint 不提供兼容分支。
与知识检索相关的独立 API:
- `POST /api/knowledge/init`:导入/增量初始化 `knowledge_base`
- `POST /api/knowledge/rebuild-hybrid?confirm=REBUILD`:清空并重建 dense+BM25 collection(默认 `biz`)
- `GET /api/knowledge/stats`:文档元数据统计
- `GET /milvus/health`:MilvusClientV2 健康检查与 knowledge collection 名
## 7. 安全边界
- 普通 SSE、Trace、Evidence Snapshot、业务结果和应用日志不输出或保存 reasoning 原文。
@@ -0,0 +1,328 @@
# RAG 知识检索架构
**更新日期**:2026-07-28
**状态**:当前可运行架构
**关联实现**:`lookup_knowledge`、`MilvusHybridKnowledgeStore`、`KnowledgeSearchPort`
**关联运维**:`scripts/rebuild_hybrid_knowledge.py`、`POST /api/knowledge/rebuild-hybrid`
## 1. 定位
知识检索是 Diagnosis Agent 的显式证据工具,不是隐式 Advisor。
```text
Diagnosis Agent
-> lookup_knowledge(query)
-> Harness ToolBoundary / ACI projection
-> EvidenceGuard 只认当前 Run 的 READY canonical 证据
```
目标:
- 保留 Agent 可见的工具调用与证据边界
- 用单一向量后端完成 dense + BM25 hybrid 检索
- 用 chunk 级证据身份保证同文档多片段可同时进入上下文
- 检索行为可配置、可重建、可审计
## 2. 稳定边界
```mermaid
flowchart LR
subgraph AgentBoundary["Agent boundary"]
Agent["Diagnosis Agent"]
Tool["lookup_knowledge"]
end
subgraph HarnessBoundary["Harness boundary"]
Adapter["RagToolAdapter"]
Projector["RagResultProjector"]
Canonical["Redis canonical invocation"]
end
subgraph RetrievalBoundary["Retrieval boundary"]
Backend["LookupKnowledgeTool"]
Port["KnowledgeSearchPort"]
Store["MilvusHybridKnowledgeStore"]
end
Agent --> Tool
Tool --> Adapter
Adapter --> Backend
Backend --> Port
Port --> Store
Adapter --> Projector
Adapter --> Canonical
```
| 边界 | 职责 | 不负责 |
|---|---|---|
| Agent | 决定何时检索、如何用证据写报告 | 不直接访问 Milvus / MySQL 元数据表 |
| Harness | Tool 校验、投影裁剪、canonical 存证 | 不改写检索排序算法 |
| Retrieval | L0 hint、dense/BM25 召回、后处理、打包 | 不绕过 ACI 直接给 Agent 原始库响应 |
## 3. 当前主链路
```mermaid
flowchart TD
A["lookup_knowledge(query)"] --> B["KnowledgeQueryTransformer"]
B --> C["L0 hint: domain / keywords / categoryFilter"]
C --> D["KnowledgeDocumentRetriever"]
D --> E["KnowledgeSearchPort"]
E --> F["VectorSearchService"]
F --> G{"retrieval.search.mode"}
G -->|dense| H["MilvusHybridKnowledgeStore.searchDense"]
G -->|hybrid| I["MilvusHybridKnowledgeStore.searchHybrid"]
H --> J["candidates + chunk identity"]
I --> J
J --> K["KnowledgeEvidencePostProcessor"]
K --> L["evidenceKey dedup / maxChunksPerDocument / return-n"]
L --> M{"filtered low quality?"}
M -->|yes and had categoryFilter| N["unfiltered retry"]
N --> K
M -->|no| O["KnowledgeContextPacker"]
O --> P["LookupResultAssembler"]
P --> Q["RagResultProjector"]
Q --> R["Agent-facing RagToolResult"]
```
对应代码:
| 阶段 | 类 | 职责 |
|---|---|---|
| Tool 编排 | `LookupKnowledgeTool` | 串联 transform / retrieve / post / pack |
| Query 理解 | `KnowledgeQueryTransformer` + `KnowledgeIndexService` | L0 只产 hint 与可选 category filter |
| 检索端口 | `KnowledgeSearchPort` / `VectorKnowledgeSearchAdapter` | 屏蔽底层存储细节 |
| 检索门面 | `VectorSearchService` | `dense` 或 `hybrid` 路由 |
| 向量后端 | `MilvusHybridKnowledgeStore` | 唯一知识库读写后端(MilvusClientV2) |
| 后处理 | `KnowledgeEvidencePostProcessor` | 归一化、规则 boost、chunk 去重、相关度等级 |
| 打包 | `KnowledgeContextPacker` | 有界 context pack |
| 投影 | `RagResultProjector` | 只暴露 Agent 可见 evidence 字段 |
## 4. 唯一向量后端:MilvusClientV2
### 4.1 已废弃路径
以下路径**不再**用于 `lookup_knowledge`:
- legacy `MilvusServiceClient` search / insert
- `retrieval.vector-store.mode=sdk|spring|auto`
- Spring AI `VectorStore` 作为知识检索主路径
### 4.2 当前后端
```text
写入:
VectorIndexService
-> MilvusHybridKnowledgeStore.upsertChunk
读取:
VectorSearchService
-> MilvusHybridKnowledgeStore.searchDense
-> MilvusHybridKnowledgeStore.searchHybrid
```
默认 collection:
```yaml
milvus:
collection: biz
```
重建时会 drop + recreate 该 collection,并按 dense + BM25 schema 重建。
## 5. Collection Schema
`biz`(可配置)逻辑字段:
| 字段 | 类型 | 用途 |
|---|---|---|
| `id` | VarChar PK | chunk 级主键 |
| `content` | VarChar | 返回给 Agent 的原文片段 |
| `search_text` | VarChar + analyzer | BM25 输入文本 |
| `sparse_vector` | SparseFloatVector | BM25 Function 输出 |
| `vector` | FloatVector | dense embedding |
| `metadata` | JSON | docId / chunkIndex / category / kb_scope / title / breadcrumb 等 |
Function:
```text
BM25(search_text -> sparse_vector)
```
索引:
```text
vector -> IVF_FLAT + L2
sparse_vector -> SPARSE_INVERTED_INDEX + BM25
```
写入时:
- `content` 保存原始 chunk 正文
- `search_text` / dense embedding 使用 `Title + Path + Content` 拼装文本
- metadata 必须带 `docId`、`chunkIndex`,供 chunk 级证据身份使用
## 6. 检索模式
配置:
```yaml
retrieval:
search:
mode: hybrid # dense | hybrid
hybrid:
rrf-k: 60
kb-scope: ""
rag:
retrieve-k: 20
return-n: 5
max-chunks-per-document: 2
```
### 6.1 dense
```text
query
-> embedding
-> dense ANN on vector
-> topK
```
### 6.2 hybrid(当前默认)
```text
query
-> path A: dense ANN(query embedding)
-> path B: BM25 sparse ANN(raw query text)
-> Milvus hybridSearch + RRFRanker(k)
-> topK fused hits
```
阈值兼容:
- 后处理仍按 dense 兼容 L2 距离做 `normalizeL2`
- hybrid 命中若能从并行 dense 结果拿到同 id 的 L2,则回填该分数
- 仅 BM25 命中、无 dense 分时,按弱相关处理,避免虚高 `PRECISE`
### 6.3 category filter 与降级
```text
if L0 给出唯一 domain:
先 filtered 检索
if 无证据或 topSimilarity < referenceThreshold:
再 unfiltered retry
else:
直接 unfiltered
```
这里的 filter 是 metadata category / kb_scope 约束,不是第二套向量库。
## 7. 证据身份与去重
Delivery 1 已落地:
```text
evidenceKey =
docId#chunk-{chunkIndex}
fallback: vector:{id}
fallback: rank:{n}
```
规则:
- 去重按 `evidenceKey`,不是按 source 文档路径
- 同文档不同 chunk 可同时保留
- `rag.max-chunks-per-document` 限制单文档最多进入结果的 chunk 数
- `rag.return-n` 限制后处理后最多返回条数
- Agent 投影中的 `document_id` 使用 chunk 级 evidenceKey
这保证 hybrid 召回的多片段不会在后处理/投影阶段被文档级折叠吞掉。
## 8. L0 / L1 职责
| 层 | 做什么 | 不做什么 |
|---|---|---|
| L0 | domain/keyword hint、可选 category filter、trace 解释、轻规则 boost | 不直接当事实 evidence |
| L1 dense/BM25 | 事实证据召回 | 不依赖 frontmatter 关键词命中才返回正文 |
L0 命中文档正文不会在 L1 失败时兜底成 evidence。
## 9. Agent 可见契约
Agent 只看到有界 `RagToolResult`:
- `evidence_status`
- `tool_call_id`
- `query`
- `evidence[]`:`document_id` / `source` / `title` / `breadcrumb` / `excerpt`
- `relevance_level`
- `truncated` / `returned_count`
不暴露:
- raw score / fused score
- retrievalTrace / rerankTrace
- contextPack 全文
- Milvus 内部字段与凭据
完整内部结果仍在 `LookupResult` 中,供审计与调试使用。
## 10. 写入与重建
### 10.1 日常写入
文档上传 / 知识库初始化:
```text
markdown
-> frontmatter + body
-> DocumentChunkService
-> dense embedding + search_text
-> MilvusHybridKnowledgeStore.upsertChunk
-> MySQL api_document + L0 memory index
```
### 10.2 全量重建
危险操作,需显式确认:
```bash
python scripts/rebuild_hybrid_knowledge.py --confirm REBUILD
```
等价 API:
```text
POST /api/knowledge/rebuild-hybrid?confirm=REBUILD
```
服务端顺序:
1. drop + recreate `milvus.collection`(默认 `biz`)
2. 清空 MySQL `api_document`
3. 清空内存 L0
4. 扫描 `knowledge_base/**/*.md`(跳过 `README.md`)force 导入
不会修改磁盘上的 `knowledge_base/` 源文件。
## 11. 与旧文档的差异
| 旧描述(已归档) | 当前实现 |
|---|---|
| Spring AI VectorStore 主路径 + SDK fallback | 单一 MilvusClientV2 后端 |
| `retrieval.vector-store.mode=auto/sdk/spring` | 已移除;改为 `retrieval.search.mode=dense/hybrid` |
| source 级 evidence 去重 | chunk 级 `evidenceKey` 去重 |
| 应用层 sparse-lite lexical 伪 hybrid | 库内 dense ANN + BM25 + RRFRanker |
| 新建 `biz_hybrid` 过渡 collection | 默认使用并重建 `biz` |
历史材料见:
- `mvp/architecture/archive/2026-07-22-legacy/rag-architecture.md`
- `mvp/architecture/archive/2026-07-22-legacy/modular-rag-pipeline.md`
## 12. 当前已知边界
- hybrid 依赖云端/实例支持 BM25 Function 与 sparse index
- 全量重建受 embedding API 与 Milvus 写入延迟影响,可能较慢
- L0 关键词匹配仍较粗,只作 hint,不作主召回
- 尚未做邻块上下文自动扩展、cross-encoder rerank、真 query rewrite
- `totalVectors` 统计接口仍可能返回 0,不代表 collection 为空;以 rebuild/init 结果与检索命中为准