Files
SuperBizAgent-java/mvp/architecture/RAG知识检索架构.md
zhuyongxin 473bb5d004 docs(mvp): update RAG docs for py-rag extraction
- rewrite RAG architecture doc for py-rag service contract mapping, ingest and rebuild ops
- refresh observability/trace doc for post-L0 single-attempt semantics
- add py-rag chain exploration note; mark superseded Milvus/L0 notes with status banners
- close ISS-017 (superseded by L0 sinking); mark knowledge_domain table orphaned
- refresh architecture/mvp/engineering indexes
2026-09-30 17:03:50 +08:00

237 lines
11 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.
# RAG 知识检索架构
**更新日期**:2026-09-29
**状态**:当前可运行架构
**关联实现**:`lookup_knowledge`、`KnowledgeSearchPort`、`PyRagKnowledgeSearchAdapter`、`PyRagClient`
**关联契约**:py-rag 仓库 `docs/Java接入文档.md`(API v1,冻结面)
**关联运维**:py-rag `/api/v1/collections:rebuild`(全量重建)、py-rag `/api/v1/documents:ingest`(单文档入库)
## 1. 定位
知识检索是 Diagnosis Agent 的显式证据工具,不是隐式 Advisor。
检索算法(dense+BM25 融合、rerank、判级)与文档入库(解析、frontmatter、分块、向量化)
**全部由独立的 py-rag 知识服务承担**;Java 侧只保留 harness 消费面与 HTTP 客户端。
```text
Diagnosis Agent
-> lookup_knowledge(query)
-> Harness ToolBoundary / ACI projection
-> EvidenceGuard 只认当前 Run 的 READY canonical 证据
```
目标:
- 保留 Agent 可见的工具调用与证据边界
- 检索/入库基础设施外置为独立服务,Java 侧不感知引擎细节
- 用 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"]
Remote["PyRagKnowledgeSearchAdapter"]
Service["py-rag 知识服务 (HTTP /api/v1)"]
end
Agent --> Tool
Tool --> Adapter
Adapter --> Backend
Backend --> Port
Port --> Remote
Remote -->|HTTP| Service
Adapter --> Projector
Adapter --> Canonical
```
| 边界 | 职责 | 不负责 |
|---|---|---|
| Agent | 决定何时检索、如何用证据写报告 | 不直接访问 py-rag / MySQL 元数据表 |
| Harness | Tool 校验、投影裁剪、canonical 存证 | 不改写检索排序算法 |
| Retrieval | 请求映射、后处理、打包;py-rag 承担召回/融合/rerank/判级 | 不绕过 ACI 直接给 Agent 原始库响应 |
## 3. 当前主链路
```mermaid
flowchart TD
A["lookup_knowledge(query)"] --> B["原始 query 直传(L0 已下沉 py-rag)"]
B --> C["KnowledgeDocumentRetriever"]
C --> D["KnowledgeSearchPort"]
D --> E["PyRagKnowledgeSearchAdapter"]
E -->|POST /api/v1/search| F["py-rag: dense+BM25 融合 / rerank / 判级"]
F --> G["hits + evidenceKey(docId#chunk-N)"]
G --> H["KnowledgeEvidencePostProcessor"]
H --> I["evidenceKey dedup / maxChunksPerDocument / return-n"]
I --> J["KnowledgeContextPacker"]
J --> K["LookupResultAssembler"]
K --> L["RagResultProjector"]
L --> M["Agent-facing RagToolResult"]
```
对应代码:
| 阶段 | 类 | 职责 |
|---|---|---|
| Tool 编排 | `LookupKnowledgeTool` | 串联 retrieve / post / pack;UNFILTERED 单 attempt 主路径 |
| 检索端口 | `KnowledgeSearchPort` / `PyRagKnowledgeSearchAdapter` | 防腐层;请求映射 + 命中归一化 |
| HTTP 客户端 | `PyRagClient` | API v1 调用、错误信封(`E_*`)、`X-Request-ID`、分端点超时 |
| 后处理 | `KnowledgeEvidencePostProcessor` | qualityScore(RERANK 直传)、chunk 去重、相关度等级 |
| 打包 | `KnowledgeContextPacker` | 有界 context pack |
| 投影 | `RagResultProjector` | 只暴露 Agent 可见 evidence 字段 |
2026-09-29 抽离时删除的 Java 侧组件:`MilvusHybridKnowledgeStore`、`VectorSearchService`、
`VectorKnowledgeSearchAdapter`、`RrfFusion` / `LexicalRanker`(融合评分下沉)、
`KnowledgeIndexService` / `KnowledgeDomainService`(L0 索引)、
`DocumentChunkService` / `FrontmatterParser` / `TextExtractorService`(入库解析)、
`KnowledgeQueryTransformer`(L0 query 理解)。
## 4. py-rag 检索契约映射
请求映射(`PyRagKnowledgeSearchAdapter`):
| Java(KnowledgeSearchRequest) | py-rag(/api/v1/search) | 说明 |
|---|---|---|
| `query` | `query` | 原始检索句直传,服务端自行处理边界与精排 |
| `mode=DENSE` | `mode=semantic` | 纯向量,对照/排障用 |
| `mode=HYBRID` | `mode=hybrid` | dense+BM25 融合,线上主路径(`retrieval.search.mode: hybrid`) |
| `topK` | `retrieve_k` / `return_n` / `max_chunks_per_document` | 三者同置 topK:chunk 去重截断由 Java 后处理器统一负责,避免服务端预截断 |
| `categoryFilter` | `category` | L0 下沉后恒为 null(不过滤) |
| — | `kb_scope` | 不传,由 py-rag 部署配置决定 |
响应映射:
| py-rag | Java(KnowledgeSearchHit) | 说明 |
|---|---|---|
| `evidence_key` | `evidenceKey` / `docId` / `chunkIndex` | `docId#chunk-N`,与 EvidenceGuard 验真约定一致 |
| `excerpt` | `content` | 进入 context pack 的正文 |
| `quality_score` | `score` / `rawScore` | rerank 绝对相关分 [0,1],越大越好 |
| — | `scoreLabel=RERANK` | `RetrievalScoreNormalizer` 对 RERANK 分支 quality 原样 clamp,不走 L2/rank 归一化 |
| `relevance_level` | (参考值) | Java 后处理按同阈值(0.75/0.5)独立判级,语义一致 |
| `evidence_status=no_evidence` | 空列表 | 正常业务响应(服务端保证 hits=[]),Agent 侧按"无知识可用"处理 |
超时与重试矩阵见 py-rag 仓库 `docs/Java接入文档.md` 第 6 节;Java 侧由 `pyrag.*` 配置承载。
## 5. 入库与重建
### 5.1 日常写入
```text
业务上传(DocumentController /api/documents/upload)
-> MySQL api_document(业务元数据:faultSource 等)+ 本地原件保存
-> PyRagClient.ingest(multipart 透传原件 + category)
-> py-rag:解析 / frontmatter 校验 / 分块 / 向量化 / 索引
简单上传(FileUploadController /api/upload)
-> 本地保存 + PyRagClient.ingest(category 可选参数,缺省 default;入库失败不影响上传成功语义)
```
MySQL `api_document.docId` 取 py-rag 返回的 `doc_id`(路径 slug + 内容 SHA-256 前 8 位),
与检索 `evidence_key` 的 docId 段对齐;`chunk_count` 取 ingest 响应。
### 5.2 全量重建
```text
POST /api/v1/collections:rebuild?confirm=REBUILD (py-rag 服务端)
GET /api/v1/tasks/{task_id} (任务状态)
```
- rebuild 为 py-rag 异步任务;执行期间 ingest 返回 409(`E_REBUILD_IN_PROGRESS`),search 不受影响
- 原料为 py-rag 服务端 `data/knowledge_base/` 下历次 ingest 落盘的 md
- 旧 Java 侧 `POST /api/knowledge/rebuild-hybrid` 与 `scripts/rebuild_hybrid_knowledge.py` 已删除
### 5.3 单文档删除
py-rag API v1 没有单文档删除端点。`DELETE /api/documents/{docId}` 只删 MySQL 元数据与本地原件;
py-rag 侧已入库内容需全量重建后才会消失(见 `DocumentManagementService.deleteDocument` 注释)。
## 6. 部署与配置
```yaml
pyrag:
base-url: ${PYRAG_BASE_URL:http://localhost:8000}
connect-timeout-ms: 3000
search-read-timeout-ms: 5000 # 正常 300–800ms(含 rerank 外呼)
ingest-read-timeout-ms: 30000
default-read-timeout-ms: 10000
```
- Milvus / etcd / MinIO 随 py-rag 部署,不再由本仓库 `docker-compose.yml` 管理(compose 仅剩 MySQL/Redis)
- `vector-database.yml` 已删除;Makefile 的 up/down/status 只管 MySQL/Redis
- `retrieval.search.mode: hybrid` 语义保留:映射 py-rag 的 `hybrid` / `semantic`
## 7. 证据身份与去重(不变)
```text
evidenceKey = docId#chunk-{chunkIndex}
fallback: vector:{id}
fallback: rank:{n}
```
- 去重按 `evidenceKey`,同文档不同 chunk 可同时保留
- `rag.max-chunks-per-document` / `rag.return-n` 在 Java 后处理器生效
- Agent 投影中的 `document_id` 使用 chunk 级 evidenceKey,EvidenceGuard 据此验真
## 8. Agent 可见契约(不变)
Agent 只看到有界 `RagToolResult`:
- `evidence_status` / `tool_call_id` / `query`
- `evidence[]`:`document_id` / `source` / `title` / `breadcrumb` / `excerpt`
- `relevance_level`(PRECISE / REFERENCE;`RagRelevanceLevel.HIGHLY_RELEVANT` 为保留档)
- `truncated` / `returned_count`
不暴露:raw score、retrievalTrace / rerankTrace、contextPack 全文、py-rag 地址与凭据。
完整内部结果仍在 `LookupResult` 中,供审计与调试使用。Trace / 审计读法见
[RAG检索可观测性与审计.md](./RAG检索可观测性与审计.md)。
## 9. L0 下沉
L0 query 理解(domain/keyword hint → 可选 categoryFilter)随本次抽离**整体下沉 py-rag**:
- `KnowledgeQueryTransformer` / `KnowledgeIndexService.analyzeQuery` 已删除
- `lookup_knowledge` 直传原始 query;`categoryFilter` 恒为 null,走 UNFILTERED 单 attempt
- `LookupKnowledgeTool` 中 filtered→unfiltered 降级分支保留但不可达(作为未来 Java 侧过滤策略的兜底骨架)
- `RetrievalTrace.queryHints` 恒为空结构;`attempt` 命名只剩 `UNFILTERED_VECTOR`
## 10. 与旧文档的差异
| 旧描述(2026-07-28 版) | 当前实现(2026-09-29 抽离后) |
|---|---|
| 进程内 MilvusClientV2,dense+BM25+RRF | py-rag 服务端承担;Java 经 `KnowledgeSearchPort` → HTTP |
| `retrieval.search.mode` 切 Milvus 查询算法 | 同名配置映射 py-rag `hybrid` / `semantic` |
| scoreLabel 仅 dense \| hybrid,L2/rank 归一化 | 新增 `RERANK`:py-rag rerank 绝对分直传 |
| L0 hint + categoryFilter + filtered/unfiltered retry | L0 下沉;原始 query 直传,单 attempt |
| Java 侧 frontmatter 解析 / 分块 / embedding 入库 | py-rag `documents:ingest`;Java 只做 MySQL 元数据 + 原件保存 |
| `POST /api/knowledge/rebuild-hybrid` 重建 | py-rag `POST /api/v1/collections:rebuild` |
| `GET /milvus/health` 健康检查 | py-rag `GET /api/v1/health`(含 milvus/embedding/rerank 探针) |
| 删除文档同步删向量索引 | 仅删 MySQL+本地文件;py-rag 侧靠全量重建生效 |
历史材料见:
- `mvp/architecture/archive/2026-07-22-legacy/rag-architecture.md`(Milvus 前身)
- `mvp/engineering/rag/Milvus-Hybrid接入清单.md`(进程内 Milvus hybrid 接入纪要,已过时)
- 本仓库 git 历史:`refactor/extract-rag-module` 分支,71 文件 / 约 -8000 行
## 11. 当前已知边界
- py-rag 判级阈值(0.75/0.5/0.3)未校准,`quality_score` 仅供排序与展示参考(契约已知边界)
- frontmatter 的 keywords/summary/covers/when_to_retrieve 当前仅上传方提供;Java 侧 LLM 补全(原 `DocumentFieldEnricher`)已随抽离移除,待 py-rag 开放
- `knowledge_base/` 历史原料需在 py-rag 侧完成一次性 ingest 迁移后方可检索
- 无单文档删除;下线文档靠 py-rag 全量重建
- eval/rag-retrieval 离线基线基于旧 L0/scoreLabel 语义构建,抽离后需重新校准(见 `mvp/engineering/rag/RAG离线评测-基线设计.md` 顶部说明)
- Trace/审计细节与限制见 [RAG检索可观测性与审计.md](./RAG检索可观测性与审计.md)