- T6 (Issue6): RerankConfig(enabled/model=BAAI/bge-reranker-v2-m3/device)
- rag-layer-design §6.3 Rerank 精排:窗口=RRF top-10、候选≤top_k 跳过、
故障降级 RRF 原序;原 §6.3-6.6 顺延 6.4-6.7
- config-design §5 新增 rerank 段;design §5.5 检索策略加 rerank
- T11 (OV2): EmbeddingConfig.model 默认 bge-small-zh-v1.5 → BAAI/bge-m3(日文语料)
- rag-layer-design 选型表/依赖表/manifest/流程图同步 + 新增 §2.3 日文样本验证
- design.md / implementation-plan 4.3 / config-design embedding 同步
- 新增 test_rag_design_consistency.py 一致性门禁(6 用例防文档漂移)
- TDD: RED(默认模型仍旧 + rerank 字段不存在)→ GREEN → 全量 198 passed / 100.00%(996 stmts/252 br)
712 lines
25 KiB
Markdown
712 lines
25 KiB
Markdown
# RAG 基础设施层详细设计
|
||
|
||
> 版本: v1.0 | 日期: 2026-07-30 | 状态: 初版
|
||
>
|
||
> 本文档是 `docs/design.md` 第5章(RAG 基础设施层)的详细展开。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [定位与职责](#1-定位与职责)
|
||
2. [技术选型](#2-技术选型)
|
||
3. [文档分割策略](#3-文档分割策略)
|
||
4. [存储架构](#4-存储架构)
|
||
5. [版本管理](#5-版本管理)
|
||
6. [检索引擎](#6-检索引擎)
|
||
7. [规则冲突处理](#7-规则冲突处理)
|
||
8. [集成接口](#8-集成接口)
|
||
9. [存储适配层(Storage Adapter)](#9-存储适配层storage-adapter)
|
||
10. [降级与容错](#10-降级与容错)
|
||
11. [v2 迭代预留](#11-v2-迭代预留)
|
||
12. [与 design.md 的关系](#12-与-designmd-的关系)
|
||
|
||
---
|
||
|
||
## 1. 定位与职责
|
||
|
||
RAG 不是独立 Agent,而是 **Parser 与 Writer/Impact/QA 之间的基础设施层**。它负责:
|
||
|
||
- 接收 Parser 解析后的规则文档,构建**规则手册**(持久化存储)
|
||
- 为 Writer / Impact / QA 提供**统一规则检索入口**
|
||
- 管理规则手册的**版本生命周期**(更新、回退、追溯)
|
||
|
||
### 1.1 存储内容分类
|
||
|
||
RAG 层存储三类内容,分类在 Parser 解析时完成:
|
||
|
||
| 类型 | 内容 | 检索方 |
|
||
|------|------|--------|
|
||
| **Type A: 写入规则** | 记入规则、图表规则、字体/格式规范 | Writer Agent(每章生成时) |
|
||
| **Type B: 设计规则** | 架构约束、安全要求、设计方针 | Impact Agent(关联推理时)+ Writer |
|
||
| **Type C: 参考设计文档**(可选)| 过往概要设计书、设计决策记录 | Impact Agent(改修场景参考)|
|
||
|
||
> 说明:Type C 为**可选增强**,初期聚焦 Type A + Type B。Type C 文档若纳入,由用户显式上传到「参考文档」分类。
|
||
|
||
---
|
||
|
||
## 2. 技术选型
|
||
|
||
| 选型点 | 决策 | 说明 |
|
||
|--------|------|------|
|
||
| 向量数据库 | **Chroma(v1 唯一)** | 初期用 Chroma(轻量本地,嵌入进程,Docker 部署最简);通过 Storage Adapter 抽象保留接口,Qdrant 切换为 v2 预留(Scope 缩减裁定,T5 整改)|
|
||
| Embedding 模型 | **bge-m3**(本地运行) | 多语言模型(中/日/英),适配实际日文语料(OV2/T11);统一配置 `config/rag.yaml` 的 `embedding.model`(见 docs/config-design.md §5);稠密向量 1024 维,CPU 可跑 |
|
||
| Rerank 模型 | **bge-reranker-v2-m3**(v1 引入,I6/T6) | 精排阶段使用;统一配置 `config/rag.yaml` 的 `rerank.model`;默认启用,可通过 `rerank.enabled=false` 关闭降级为纯 RRF 结果 |
|
||
| 实现方式 | **手写实现**(不引入 LangChain/LlamaIndex) | chromadb + rank_bm25 + sentence-transformers 直接实现;依赖轻、可控性强、与现有轻量技术栈一致 |
|
||
|
||
### 2.1 为什么手写而非框架
|
||
|
||
| 维度 | 分析 |
|
||
|------|------|
|
||
| 检索效果 | 相同(Embedding + BM25 + RRF 为标准算法,框架也调用同样的库)|
|
||
| 分割质量 | 本项目需要「按格式适配分割」(Word标题层级/Excel规则块/PPT页),框架无现成方案,仍需自写 |
|
||
| 可追溯性 | 手写可完美对接 Provenance 体系(source_uri / headings)|
|
||
| 依赖负担 | 轻(3 个库);框架引入 langchain 全家桶 ~100+ 传递依赖 |
|
||
| 调试维护 | 手写直接可控;框架封装层级深,出问题难定位 |
|
||
| 代码量 | 向量+BM25+RRF 约 100~200 行,不值得为此引入重框架 |
|
||
|
||
### 2.2 关键依赖
|
||
|
||
```
|
||
chromadb # 向量存储(Chroma)
|
||
sentence-transformers # Embedding 编码(bge-m3)+ Rerank 精排(bge-reranker-v2-m3)
|
||
rank_bm25 # BM25 关键词检索
|
||
pydantic # 数据模型(RuleChunk 等)
|
||
```
|
||
|
||
### 2.3 多语言与日文样本验证(OV2/T11)
|
||
|
||
实际规则语料为**日文**(要件定义/概要设计/记入规则),因此:
|
||
|
||
- Embedding 采用多语言模型 **bge-m3**(支持中/日/英,稠密向量 1024 维)
|
||
- Rerank 采用多语言精排模型 **bge-reranker-v2-m3**(Cross-Encoder,query×chunk 打分)
|
||
- **日文样本验证**(Phase4 实施时执行):用真实日文规则片段(如「見出しは「1.1」形式で記述する」)构造检索用例,断言:
|
||
1. 语义近义日文 query 能召回对应规则(top-5 命中)
|
||
2. rerank 后相关片段排位不低于 RRF 原始排位(不劣化)
|
||
3. 日英混合/片假名术语 query 不空召回
|
||
|
||
---
|
||
|
||
## 3. 文档分割策略
|
||
|
||
### 3.1 按格式适配分割(业界最佳实践)
|
||
|
||
规则文档为多格式(Word / Excel / PPT),分割器需感知格式:
|
||
|
||
```
|
||
规则文档(多格式)
|
||
│
|
||
├── 📄 Word (.docx) — 标题结构最清晰
|
||
│ 分割单位: Heading 1/2/3 层级 → 每个小节一个 chunk
|
||
│ 表格处理: 表格整体作为一个 chunk(标题 + 表格内容)
|
||
│ 列表处理: 列表项随所属小节
|
||
│
|
||
├── 📊 Excel (.xlsx) — 表格型规则
|
||
│ 分割单位: 每个 Sheet 的「规则块」为 chunk
|
||
│ (规则块 = 表头 + 数据行组,按语义分组切分)
|
||
│ 例: 记入规则的「表头行 + 5条规则行」作为一个 chunk
|
||
│
|
||
└── 📽 PPT (.pptx) — 幻灯片要点型
|
||
分割单位: 每 1~2 页幻灯片作为一个 chunk
|
||
(单页内容少时合并,保证 chunk 有意义)
|
||
标题+正文分别作为 chunk 文本的一部分
|
||
```
|
||
|
||
### 3.2 统一 Chunk 结构
|
||
|
||
```python
|
||
@dataclass
|
||
class RuleChunk:
|
||
chunk_id: str # 形如 rules-write_v3_001
|
||
doc_id: str # 源文档名
|
||
doc_type: str # "word" | "excel" | "ppt"
|
||
content: str # 纯文本内容(含结构标记)
|
||
headings: list[str] # 所属标题路径,如 ["3. 記入規則", "3.2 表の書き方"]
|
||
source_uri: str # 可追溯来源
|
||
position: int # 文档内顺序
|
||
token_count: int # token 数(用于后续优化)
|
||
```
|
||
|
||
### 3.3 分割器实现
|
||
|
||
```
|
||
Chunking Pipeline
|
||
├── WordChunker # 遍历 python-docx 段落,按 Heading 样式切分
|
||
├── ExcelChunker # 遍历 openpyxl 行,按「表头+数据行组」切分
|
||
└── PPTChunker # 遍历 pptx 幻灯片,1~2页合并为一个 chunk
|
||
```
|
||
|
||
分割规则:
|
||
- **chunk 上限**:默认 max_tokens=512,超出时按语义段落追加切分
|
||
- **chunk 下限**:内容过短(< 30 tokens)时与相邻 chunk 合并(PPT 场景)
|
||
- **保留结构**:headings 记录标题路径,供检索后的上下文组装
|
||
|
||
---
|
||
|
||
## 4. 存储架构
|
||
|
||
### 4.1 目录结构
|
||
|
||
```
|
||
/data/shared/rules-handbook/ # 规则手册(全用户共享)
|
||
├── chroma/ # Chroma 持久化数据目录
|
||
│ ├── v1/
|
||
│ │ ├── rules-write/ # Collection: 写入规则 v1
|
||
│ │ ├── rules-design/ # Collection: 设计规则 v1
|
||
│ │ └── ref-docs/ # Collection: 参考设计文档 v1(可选)
|
||
│ └── v2/
|
||
│ ├── rules-write/
|
||
│ ├── rules-design/
|
||
│ └── ref-docs/
|
||
├── chunks/ # 分割后的文本(JSON,可追溯)
|
||
│ ├── v1/
|
||
│ │ ├── rules-write/
|
||
│ │ │ ├── chunk_001.json
|
||
│ │ │ └── ...
|
||
│ │ └── rules-design/
|
||
│ └── v2/
|
||
└── manifests/ # 版本清单(元数据)
|
||
├── v1.json
|
||
└── v2.json
|
||
```
|
||
|
||
### 4.2 Collection 命名规范
|
||
|
||
```
|
||
格式: {content_type}-v{version}
|
||
例:
|
||
rules-write-v3 # 写入规则 v3
|
||
rules-design-v3 # 设计规则 v3
|
||
ref-docs-v3 # 参考设计文档 v3(可选)
|
||
```
|
||
|
||
### 4.3 版本清单 manifest.json
|
||
|
||
```json
|
||
{
|
||
"version": "v3",
|
||
"created_at": "2026-07-30",
|
||
"active": true,
|
||
"source_files": [
|
||
{"name": "记入规则.docx", "hash": "sha256:...", "type": "write", "built": "reuse_from_v2"},
|
||
{"name": "图表规则.xlsx", "hash": "sha256:...", "type": "write", "built": "rebuilt"},
|
||
{"name": "设计方针.docx", "hash": "sha256:...", "type": "design", "built": "reuse_from_v2"}
|
||
],
|
||
"collections": {
|
||
"rules-write": {"chunk_count": 130, "embedding_model": "bge-m3", "rerank_model": "bge-reranker-v2-m3"},
|
||
"rules-design": {"chunk_count": 45, "embedding_model": "bge-m3", "rerank_model": "bge-reranker-v2-m3"}
|
||
},
|
||
"active_previous": "v2"
|
||
}
|
||
```
|
||
|
||
> 说明:`collections[*].embedding_model` 为版本清单的**记录字段**,记录该版本实际使用的模型名;其值来源于统一配置 `config/rag.yaml` 的 `embedding.model`(见 docs/config-design.md),两者保持一致,不再单独配置。
|
||
|
||
### 4.4 Chunk 持久化(JSON)
|
||
|
||
> 说明:示例 content 为模拟日文规则文档的原始文本(技术必要保留)。
|
||
|
||
```json
|
||
{
|
||
"chunk_id": "rules-write_v3_001",
|
||
"doc_id": "记入规则.docx",
|
||
"doc_type": "word",
|
||
"content": "見出しは「1.1」形式…",
|
||
"headings": ["3. 記入規則", "3.2 見出しの書き方"],
|
||
"source_uri": "记入规则.docx#見出し!3.2",
|
||
"position": 15,
|
||
"token_count": 240
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 版本管理
|
||
|
||
### 5.1 文档级增量 + 版本组合
|
||
|
||
规则手册 = 多个文档(记入规则、图表规则、设计方针…)。当**只更改其中一个文档**时,避免全量重建。
|
||
|
||
```
|
||
更新时流程:
|
||
1. 计算所有上传文档的内容 hash(sha256)
|
||
2. 与当前激活版本的 manifest 对比
|
||
3. 识别出「变化/新增/删除」的文档
|
||
4. 只对变化的文档重新解析 → 分割 → embedding
|
||
5. 未变化的文档直接复用上一版本的 chunks + embeddings
|
||
6. 生成新版本 Collection
|
||
```
|
||
|
||
### 5.2 示例场景
|
||
|
||
用户上传 3 个规则文档,**只修改了「图表规则.xlsx」**:
|
||
|
||
```
|
||
更新前(handbook-v2):
|
||
记入规则.docx hash=A → 100 chunks
|
||
图表规则.xlsx hash=B → 30 chunks
|
||
设计方针.docx hash=C → 45 chunks
|
||
|
||
用户更新「图表规则.xlsx」→ hash=B'(内容变了)
|
||
|
||
更新后(handbook-v3):
|
||
记入规则.docx hash=A → 100 chunks 【复用 v2,不重新 embedding】
|
||
图表规则.xlsx hash=B' → 32 chunks 【重新构建】
|
||
设计方针.docx hash=C → 45 chunks 【复用 v2,不重新 embedding】
|
||
```
|
||
|
||
### 5.3 变化类型处理
|
||
|
||
| 场景 | 处理方式 |
|
||
|------|---------|
|
||
| 文档内容变化 | 只重建该文档 |
|
||
| 新增文档 | 只构建新增文档 |
|
||
| 删除文档 | 新版本不含该文档,旧版本仍保留 |
|
||
| 所有文档未变化 | 不创建新版本(提示用户「无变化」)|
|
||
|
||
### 5.4 会话锁版本
|
||
|
||
- **会话开始**(用户上传要件定义时)锁定当时激活的规则版本
|
||
- 整个生成过程固定用该版本,避免生成中途规则更新导致前后不一致
|
||
- 设计书元数据记录「使用的规则版本号 + 冲突决策列表」,可完全追溯
|
||
|
||
### 5.5 回退策略
|
||
|
||
```
|
||
回退到 v2:
|
||
manifest v2 的 active 字段 → true
|
||
会话锁版本逻辑不变(新会话锁 v2)
|
||
v3 保留不删除(可再回退)
|
||
```
|
||
|
||
### 5.6 存储冗余说明
|
||
|
||
v3 会复制未变化文档的 embeddings。对规则文档几 MB 的量级,冗余可接受,且换来逻辑简单与完全可追溯。
|
||
|
||
---
|
||
|
||
## 6. 检索引擎
|
||
|
||
### 6.1 检索请求流程
|
||
|
||
```
|
||
调用方(Writer/Impact/QA)
|
||
│ 传入: 检索意图 + 查询文本 + 约束
|
||
▼
|
||
┌──────────────────────────────────────────┐
|
||
│ Retrieval Engine │
|
||
│ │
|
||
│ Intent Router(意图路由) │
|
||
│ ├── Writer → 检索 rules-write Collection
|
||
│ ├── Impact → 检索 rules-design Collection
|
||
│ └── QA → 双 Collection 都检索
|
||
│ │
|
||
│ 查询构造: │
|
||
│ ├── 查询文本 = 用户提供的 query 文本 │
|
||
│ ├── 上下文增强 = 当前章节/要素信息 │
|
||
│ └── 过滤条件 = version + category │
|
||
│ │
|
||
│ 双通道检索: │
|
||
│ ├── VectorRetriever(向量语义检索 top-10) │
|
||
│ │ 使用 bge-m3 编码查询 │
|
||
│ └── BM25Retriever(关键词检索 top-10) │
|
||
│ │
|
||
│ RRF Fusion(结果融合) │
|
||
│ └── 合并两通道结果,按 RRF 公式排序 │
|
||
│ │
|
||
│ Rerank 精排(v1 新增,I6/T6) │
|
||
│ └── bge-reranker-v2-m3 对候选重打分 │
|
||
│ └── 输出 top-N 个 RuleChunk │
|
||
└──────────────────────────────────────────┘
|
||
```
|
||
|
||
### 6.2 RRF 融合
|
||
|
||
```
|
||
RRF_score(d) = Σ 1 / (k + rank(d)) # k=60 常用值
|
||
|
||
示例(k=60):
|
||
向量通道排名第2: 1/(60+2) = 0.0161
|
||
BM25通道排名第5: 1/(60+5) = 0.0154
|
||
总分 = 0.0315(两通道都命中的文档分数更高)
|
||
|
||
参数:
|
||
通道 top-k = 10(各自取 top-10,扩大召回窗口)
|
||
融合后 top-k = 调用方传参(默认 5)
|
||
```
|
||
|
||
### 6.3 Rerank 精排(v1 新增,I6/T6)
|
||
|
||
RRF 融合后、注入 LLM prompt 前,对候选做 **Cross-Encoder 精排**(2026 主流实践:向量→rerank→精排):
|
||
|
||
```
|
||
RRF 候选(默认 top-10 窗口)
|
||
│
|
||
▼
|
||
bge-reranker-v2-m3(Cross-Encoder)
|
||
│ 对每对 (query, chunk) 打分,输出相关性分数
|
||
▼
|
||
按分数降序重排 → 截取最终 top_k(默认 5)
|
||
```
|
||
|
||
| 项目 | 决策 |
|
||
|------|------|
|
||
| 模型 | `BAAI/bge-reranker-v2-m3`(多语言 Cross-Encoder,与日文语料匹配) |
|
||
| 开关 | `rerank.enabled`(默认 true);false 时跳过精排,直接取 RRF 前 top_k |
|
||
| 打分窗口 | RRF 融合后 top-10 候选(与通道 top-k 一致,避免重排成本随全文增长) |
|
||
| 候选过少 | 候选 ≤ top_k 时跳过 rerank(无重排必要,节省推理) |
|
||
| 故障降级 | rerank 推理异常 → 降级为 RRF 原始顺序,不阻断检索(同 §10 容错策略) |
|
||
|
||
### 6.4 上下文增强(Contextual Enrichment)
|
||
|
||
检索时不仅用 query 文本,还拼入当前上下文:
|
||
|
||
| 调用方 | 查询上下文增强 |
|
||
|--------|--------------|
|
||
| Writer | 「第3章 機能一覧」的生成 → query + 章名 + 相关要素ID |
|
||
| Impact | 「要素 F001 与 TB001 的关系」推理 → query + 要素类型 + 要素描述 |
|
||
| QA | 「校验某段内容的规则遵守」→ query + 待校验段落 |
|
||
|
||
### 6.5 各 Agent 查询构造规范
|
||
|
||
| 调用方 | query 构造方式 |
|
||
|--------|--------------|
|
||
| Writer | query = 章目标题 + 相关要素 ID + 生成意图描述 |
|
||
| Impact | query = 要素类型 + 要素描述 + 待推论的关联方向 |
|
||
| QA | query = 待校验段落内容 + 所属章 |
|
||
|
||
### 6.6 top_k 配置
|
||
|
||
`top_k` 由调用方传参,允许按章差异配置:
|
||
|
||
| 章节类型 | 建议 top_k |
|
||
|---------|-----------|
|
||
| 概要章 | 3 |
|
||
| DB 设计章 | 8 |
|
||
| 其余章 | 5 |
|
||
|
||
### 6.7 检索结果上下文组装
|
||
|
||
检索出的 chunk 注入 LLM prompt 时,保留结构信息:
|
||
|
||
> 说明:以下示例模拟日文规则文档的原始内容(规则文档本身为日文,技术必要保留)。
|
||
|
||
```
|
||
--- 适用的记入规则(来自规则手册 v3)---
|
||
【3.2 見出しの書き方】
|
||
見出しは「1.1」「1.2」形式で記述する。
|
||
(来源: 记入规则.docx#見出し!3.2)
|
||
|
||
【5.1 表の書き方】
|
||
表のヘッダー行は太字で記載する。
|
||
(来源: 记入规则.docx#表!5.1)
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 规则冲突处理
|
||
|
||
### 7.1 冲突检测时机
|
||
|
||
在**检索引擎返回结果后、注入 LLM prompt 前**执行:
|
||
|
||
```
|
||
检索返回 top-N chunks
|
||
│
|
||
▼
|
||
┌────────────────────────────────┐
|
||
│ Conflict Detector(冲突检测器)│
|
||
│ 1. 按「内容主题」对 chunks 分组 │
|
||
│ 2. 同一主题下,检测规则约束是否矛盾│
|
||
│ └ 对比: 格式(字体/字号/边距) │
|
||
│ 结构(标题层级/编号) │
|
||
│ 内容(必填项/禁止项) │
|
||
│ 3. 发现矛盾 → 标记为冲突组 │
|
||
└────────────────────────────────┘
|
||
│
|
||
▼
|
||
有冲突? ──否──→ 正常注入 prompt,继续生成
|
||
│
|
||
是
|
||
▼
|
||
用户确认介入(不阻塞整章,只阻塞该章)
|
||
```
|
||
|
||
### 7.2 冲突检测示例
|
||
|
||
> 说明:以下示例模拟日文规则文档的原始规则文本(技术必要保留)。
|
||
|
||
```
|
||
主题: 「表のヘッダー行」格式
|
||
|
||
[记入规则.docx #5.1] 表ヘッダーは太字+下線で記載する
|
||
[图表规则.xlsx #2.3] 表ヘッダーは太字のみ(下線なし)
|
||
|
||
→ 检测到矛盾:下線の有無
|
||
```
|
||
|
||
### 7.3 用户确认界面
|
||
|
||
```
|
||
─────────────────────────────────────────
|
||
⚠ 检测到规则冲突(第3章 機能一覧)
|
||
|
||
主题: 表ヘッダー行のフォーマット
|
||
|
||
┌────────────┬────────────┬──────────────┐
|
||
│ 来源文档 │ 规则内容 │ 章节出处 │
|
||
├────────────┼────────────┼──────────────┤
|
||
│ 记入规则.docx│ 太字+下線 │ 5.1 │
|
||
│ 图表规则.xlsx│ 太字のみ │ 2.3 │
|
||
└────────────┴────────────┴──────────────┘
|
||
|
||
[采用「记入规则」] [采用「图表规则」] [两规则都标注给人工]
|
||
─────────────────────────────────────────
|
||
```
|
||
|
||
### 7.4 冲突决策记录
|
||
|
||
```json
|
||
{
|
||
"conflict_id": "c-001",
|
||
"session_id": "genesis-xxx",
|
||
"chapter": "機能一覧",
|
||
"topic": "表ヘッダー行のフォーマット",
|
||
"conflicting_chunks": [
|
||
{"chunk_id": "rules-write_v3_012", "doc": "记入规则.docx", "rule": "太字+下線"},
|
||
{"chunk_id": "rules-write_v3_045", "doc": "图表规则.xlsx", "rule": "太字のみ"}
|
||
],
|
||
"user_decision": "adopt_记入规则",
|
||
"decided_at": "2026-07-30 12:00",
|
||
"resolution_uri": "generated_doc#章3"
|
||
}
|
||
```
|
||
|
||
### 7.5 冲突决策的后续影响
|
||
|
||
- 决策结果存入会话(session),**同会话内相同主题冲突不再重复询问**
|
||
- 决策记录写入设计书元数据(可追溯「本设计书如何处理了规则冲突」)
|
||
- QA 校验时,以**已决策的规则**为准,不再对已决冲突告警
|
||
|
||
---
|
||
|
||
## 8. 集成接口
|
||
|
||
### 8.1 各 Agent 的调用场景
|
||
|
||
```
|
||
Parser ──→ RAG: 构建规则手册(首次上传 / 规则更新)
|
||
调用: build_handbook(file_list, category)
|
||
返回: version_id
|
||
|
||
Writer ──→ RAG: 每章生成前检索该章相关写入规则
|
||
调用: search(session_id, query, category="write", top_k=章配置)
|
||
返回: list[RuleChunk](含冲突标记)
|
||
|
||
Impact ──→ RAG: 关联推理时参考设计规则
|
||
调用: search(session_id, query, category="design", top_k=5)
|
||
返回: list[RuleChunk]
|
||
|
||
QA ──────→ RAG: 校验时检查规则遵守(双 Collection)
|
||
调用: search(session_id, query, category="write"|"design", top_k=5)
|
||
返回: list[RuleChunk]
|
||
|
||
Orchestrator ──→ RAG: 创建会话时锁定版本
|
||
调用: lock_version(session_id)
|
||
get_latest_version()
|
||
```
|
||
|
||
### 8.2 RAG Service 公开 API 一览
|
||
|
||
```python
|
||
# 构建与版本管理
|
||
class RuleHandbookManager:
|
||
def build_handbook(self, files: list[UploadedFile], categories: dict) -> str
|
||
# 增量构建,返回新版本号(无变化则返回 None)
|
||
def get_latest_version(self) -> str
|
||
def get_version(self, version_id: str) -> Manifest
|
||
def list_versions(self) -> list[Manifest]
|
||
def rollback_to(self, version_id: str) -> None
|
||
# 回退 = 重新激活指定版本(不删除任何版本)
|
||
|
||
# 会话版本锁定
|
||
class SessionVersion:
|
||
def lock_version(self, session_id: str, version_id: str | None = None) -> None
|
||
# version_id 为空时锁定当前最新版本
|
||
def get_locked_version(self, session_id: str) -> str
|
||
|
||
# 检索
|
||
class RagService:
|
||
def search(
|
||
self, *,
|
||
session_id: str,
|
||
query: str,
|
||
category: Literal["write", "design"],
|
||
top_k: int = 5,
|
||
agent: str,
|
||
) -> SearchResult
|
||
# SearchResult = {chunks: list[RuleChunk], conflicts: list[ConflictGroup]}
|
||
|
||
# 冲突决策
|
||
class ConflictHandler:
|
||
def get_pending_conflicts(self, session_id: str) -> list[ConflictGroup]
|
||
def resolve_conflict(self, conflict_id: str, decision: str) -> None
|
||
# 决策: 采用哪条规则 / 标注给人工
|
||
```
|
||
|
||
### 8.3 会话生命周期中的版本管理
|
||
|
||
```
|
||
① 创建会话 → 锁定当前最新版本 v3
|
||
② 用户上传要件定义+模板(不含规则文档)
|
||
→ Writer/Impact 检索时自动使用锁定的 v3
|
||
③ 规则手册更新为 v4
|
||
→ 已存在的会话仍用 v3(会话锁版本)
|
||
→ 新会话自动锁定 v4
|
||
④ 设计书完成
|
||
→ 元数据记录: 使用规则版本 v3 + 冲突决策列表
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 存储适配层(Storage Adapter)
|
||
|
||
### 9.1 定位
|
||
|
||
向量存储访问的**统一抽象层**。RAG 业务逻辑(分割/检索/融合)不直接依赖具体向量数据库,而是通过 Storage Adapter 访问。v1 仅实现 **ChromaAdapter**(本地持久化,零外部依赖)。(T5 架构审查整改:Scope 缩减裁定移除 Qdrant 可切换抽象,QdrantAdapter 为 v2 预留。)
|
||
|
||
### 9.2 接口定义
|
||
|
||
```python
|
||
class VectorStoreAdapter(ABC):
|
||
"""向量存储统一接口"""
|
||
|
||
@abstractmethod
|
||
def create_collection(self, name: str) -> None: ...
|
||
|
||
@abstractmethod
|
||
def delete_collection(self, name: str) -> None: ...
|
||
|
||
@abstractmethod
|
||
def upsert(
|
||
self,
|
||
collection: str,
|
||
ids: list[str],
|
||
embeddings: list[list[float]],
|
||
documents: list[str],
|
||
metadatas: list[dict],
|
||
) -> None: ...
|
||
|
||
@abstractmethod
|
||
def query(
|
||
self,
|
||
collection: str,
|
||
query_embedding: list[float],
|
||
top_k: int,
|
||
where: dict | None = None, # metadata 过滤条件
|
||
) -> list[VectorHit]: ...
|
||
|
||
@abstractmethod
|
||
def count(self, collection: str) -> int: ...
|
||
|
||
@dataclass
|
||
class VectorHit:
|
||
id: str
|
||
document: str
|
||
metadata: dict
|
||
score: float
|
||
```
|
||
|
||
### 9.3 实现类
|
||
|
||
| 实现 | 说明 | 使用场景 |
|
||
|------|------|---------|
|
||
| **ChromaAdapter** | v1 唯一实现,chromadb 本地持久化(`/data/shared/rules-handbook/chroma/`)| 默认 |
|
||
| **QdrantAdapter** | v2 预留(不实现)| Scope 缩减裁定移除;接口保留供 v2 扩展 |
|
||
|
||
### 9.4 配置
|
||
|
||
```yaml
|
||
# config/inference.yaml 或 config/rag.yaml
|
||
vector_store:
|
||
adapter: chroma # v1 仅 "chroma"(Scope 缩减裁定)
|
||
chroma:
|
||
persist_dir: /data/shared/rules-handbook/chroma
|
||
```
|
||
|
||
### 9.5 工厂与依赖注入
|
||
|
||
```python
|
||
class StorageAdapterFactory:
|
||
@staticmethod
|
||
def create(config: dict) -> VectorStoreAdapter:
|
||
# v1 仅 ChromaAdapter(Qdrant 分支 v2 预留)
|
||
return ChromaAdapter(config["vector_store"]["chroma"])
|
||
|
||
# 使用: RagService / RuleHandbookManager 通过构造注入 adapter
|
||
rag_service = RagService(
|
||
adapter=StorageAdapterFactory.create(config),
|
||
...
|
||
)
|
||
```
|
||
|
||
### 9.6 一致性保证
|
||
|
||
- v1 仅 ChromaAdapter(无跨实现一致性要求;v2 新增实现时需保证对同一数据的操作结果一致)
|
||
- 单元测试中可注入 **MockAdapter**(内存实现),使检索逻辑测试不依赖真实向量库
|
||
|
||
---
|
||
|
||
## 10. 降级与容错
|
||
|
||
### 10.1 无规则手册时的降级
|
||
|
||
```
|
||
场景1: 用户完全没上传规则文档
|
||
→ 系统内置「默认最小规则集」(硬编码基础规范,如「内容可追溯」)
|
||
→ search() 返回空时,Writer 正常生成但标记「无规则约束」
|
||
|
||
场景2: 规则手册构建失败(解析失败/LLM不可用)
|
||
→ 返回错误给用户,提示重试
|
||
→ 不影响已锁定的旧版本使用
|
||
```
|
||
|
||
### 10.2 Embedding 服务故障
|
||
|
||
```
|
||
Embedding 编码失败:
|
||
→ 降级为仅 BM25 检索(单通道)
|
||
→ 提示用户「语义检索暂不可用,已降级为关键词检索」
|
||
```
|
||
|
||
---
|
||
|
||
## 11. v2 迭代预留
|
||
|
||
以下内容**v1 不实现**,记入设计文档避免遗漏,v2 迭代:
|
||
|
||
### 11.1 检索质量反馈回路
|
||
|
||
```
|
||
v2: QA → 检索调优的反馈回路
|
||
├── QA 发现「规则未被遵守」
|
||
├── 判断根因: 「生成了但违规」 vs 「规则未被检索到」
|
||
├── 后者 → 记录 (query, 期望规则, 实际召回)
|
||
└── 定期分析 → 优化 query 重写策略 / top_k / 关键词扩展
|
||
```
|
||
|
||
### 11.2 检索延迟优化
|
||
|
||
```
|
||
v2: 缓存与批量
|
||
├── 同类 query 的 embedding 结果缓存
|
||
└── 按章批量检索(一次检索多主题)
|
||
```
|
||
|
||
---
|
||
|
||
## 12. 与 design.md 的关系
|
||
|
||
- 本文档是 `docs/design.md` 第5章(RAG 基础设施层)的详细展开
|
||
- `docs/design.md` 第5章保留概要,并指向本文档
|