182 lines
6.5 KiB
Markdown
182 lines
6.5 KiB
Markdown
# RAG 评测闭环架构
|
||
|
||
**更新日期**:2026-07-06
|
||
|
||
本文记录当前 RAG 质量闭环。它的目标不是证明检索“永远正确”,而是让每次改 `lookup_knowledge`、L0 hint、向量召回、post-retrieval、rerank 或 context packing 时,都能得到可重复的回归信号。
|
||
|
||
## 1. 闭环分层
|
||
|
||
```text
|
||
RAG pipeline change
|
||
-> LookupKnowledgeTool snapshot generation
|
||
-> offline RAG retrieval baseline
|
||
-> RAG baseline diff
|
||
-> diagnosis eval baseline
|
||
-> diagnosis baseline diff
|
||
-> accept / fix / archive
|
||
```
|
||
|
||
| 层级 | 位置 | 作用 |
|
||
|---|---|---|
|
||
| RAG retrieval baseline | `eval/rag-retrieval/` | 检查固定 query 是否命中期望证据、路径和 fallback |
|
||
| RAG baseline diff | `scripts/eval_rag_retrieval.py --compare-to ...` | 对比当前报告和旧基线,输出 regression/change |
|
||
| Diagnosis eval baseline | `mvp/eval/` | 检查 Agent 最终诊断 trace、报告和证据行为 |
|
||
| Live acceptance | `scripts/eval_rag_live_acceptance.py` | 在应用和向量库运行后做真实环境 smoke check |
|
||
|
||
## 2. Offline RAG Baseline
|
||
|
||
核心资产:
|
||
|
||
```text
|
||
eval/rag-retrieval/cases/golden-cases.json
|
||
eval/rag-retrieval/fixtures/*.json
|
||
eval/rag-retrieval/reports/baseline.json
|
||
eval/rag-retrieval/reports/baseline.md
|
||
scripts/eval_rag_retrieval.py
|
||
scripts/generate_rag_lookup_snapshots.ps1
|
||
src/test/java/com/superbiz/agent/eval/RagLookupSnapshotGeneratorTest.java
|
||
```
|
||
|
||
运行:
|
||
|
||
```powershell
|
||
python scripts\eval_rag_retrieval.py
|
||
```
|
||
|
||
该 baseline 完全离线,不依赖 MySQL、Redis、Milvus、LLM 或 Spring Boot。它适合在改 RAG 代码后快速判断:
|
||
|
||
- 期望 source 是否仍在 topK 内。
|
||
- breadcrumb 和 evidence keyword 是否仍能覆盖。
|
||
- `LookupResult` 是否仍包含 `evidenceBlocks/contextPack/retrievalTrace/rerankTrace`。
|
||
- selected attempt 是否符合预期。
|
||
- fallback reason 是否符合预期。
|
||
- context pack 是否包含期望 source。
|
||
- rerank top source 是否稳定。
|
||
|
||
## 3. 模块化输出契约
|
||
|
||
fixture 必须使用当前模块化格式:
|
||
|
||
```json
|
||
{
|
||
"lookupResult": {
|
||
"evidenceBlocks": [],
|
||
"contextPack": {},
|
||
"retrievalTrace": {},
|
||
"rerankTrace": {}
|
||
}
|
||
}
|
||
```
|
||
|
||
当前 golden cases 直接以模块化格式为唯一契约,因为这个版本的目标是验证完整 RAG pipeline,而不只是验证候选召回。
|
||
|
||
## 4. Fallback Case
|
||
|
||
当前 baseline 增加了 `chat-l0-filter-fallback`:
|
||
|
||
```text
|
||
FILTERED_VECTOR low quality or no evidence
|
||
-> UNFILTERED_VECTOR_RETRY
|
||
-> fallbackReason = filtered_vector_low_quality | filtered_vector_no_evidence
|
||
```
|
||
|
||
这个 case 固化了 MVP 版本的降级策略:如果经过 L0 filter 后 L1 低质量或没有证据,就跳过 L0 filter,用原始 query 再做一次无过滤向量检索。不同向量后端对“低质量候选”和“无候选”的边界可能不同,所以 golden case 允许两个 fallback reason,但强制要求 retry 行为和最终证据正确。
|
||
|
||
## 5. Diff 闭环
|
||
|
||
生成当前报告并与旧基线对比:
|
||
|
||
```powershell
|
||
python scripts\eval_rag_retrieval.py `
|
||
--json-report eval\rag-retrieval\reports\current.json `
|
||
--markdown-report eval\rag-retrieval\reports\current.md `
|
||
--compare-to eval\rag-retrieval\reports\baseline.json `
|
||
--diff-json-report eval\rag-retrieval\reports\baseline-diff.json `
|
||
--diff-markdown-report eval\rag-retrieval\reports\baseline-diff.md
|
||
```
|
||
|
||
diff 会检查:
|
||
|
||
- pass rate
|
||
- recall@K
|
||
- strong hit rate
|
||
- miss count
|
||
- case pass state
|
||
- hit level
|
||
- first expected rank
|
||
- selected attempt
|
||
- fallback reason
|
||
- evidence status
|
||
- rerank top source
|
||
|
||
当 case 失败或 diff 出现 regression 时,脚本会返回非 0 退出码,可作为本地质量门禁或 CI 门禁。
|
||
|
||
## 6. 与 Diagnosis Eval 的关系
|
||
|
||
RAG baseline 解决的是“证据有没有被正确检索、处理和打包”。
|
||
|
||
Diagnosis eval 解决的是“Agent 有没有把证据用于最终诊断,并保持 trace 可解释”。
|
||
|
||
两者不是替代关系:
|
||
|
||
- 改 RAG pipeline:先跑 RAG baseline,再跑相关 Agent 测试。
|
||
- 改 prompt、Agent 编排、Verifier:重点跑 diagnosis eval。
|
||
- 改 embedding 输入、reindex、向量库配置:跑 RAG baseline + live acceptance。
|
||
|
||
## 7. 面试表达
|
||
|
||
可以概括为:
|
||
|
||
> 我没有只做一个 RAG 调用,而是把 RAG 拆成 Query Transform、Retrieval、Post-Retrieval、Rerank、Context Packing,并为它建设了离线 golden cases、baseline report、baseline diff 和上层 diagnosis eval,形成可回放、可对比、可回归的 Agent 质量闭环。
|
||
|
||
## 8. LookupKnowledgeTool Snapshot
|
||
|
||
真实工具快照生成命令:
|
||
|
||
```powershell
|
||
.\scripts\generate_rag_lookup_snapshots.ps1
|
||
```
|
||
|
||
该命令默认使用 `retrieval.vector-store.mode=spring`,通过 `RagLookupSnapshotGeneratorTest` 启动 Spring test context,注入真实 `LookupKnowledgeTool` bean,对 `golden-cases.json` 中每个 query 调用 `lookupKnowledge(query)`,并把返回的 `LookupResult` 写入 `eval/rag-retrieval/fixtures/{caseId}.json`。
|
||
|
||
普通测试不会执行快照生成器;只有显式传入 `rag.snapshot.enabled=true` 时才会写 fixture。
|
||
|
||
## 9. Seed Docs And Scope Isolation
|
||
|
||
Live `LookupKnowledgeTool` snapshots are only stable if the expected documents
|
||
exist in the real knowledge base and vector index. The eval loop therefore adds
|
||
a canonical seed layer:
|
||
|
||
```text
|
||
eval/rag-retrieval/seed-docs/*.md
|
||
-> scripts/prepare_rag_eval_seed.ps1
|
||
-> RagEvalSeedImporterTest
|
||
-> DocumentManagementService.uploadDocument
|
||
-> api_document metadata + L0 index + Milvus chunks
|
||
```
|
||
|
||
Seed frontmatter includes:
|
||
|
||
```yaml
|
||
source: mysql-connection-pool
|
||
breadcrumb: Database > MySQL > Connection Pool
|
||
kb_scope: rag-eval
|
||
```
|
||
|
||
`source` becomes the stable `docId` when it fits the DB column, and is also
|
||
written to vector metadata as `_source` and `source`. `breadcrumb` is copied into
|
||
chunk metadata so evidence blocks can keep a stable path. `kb_scope` isolates
|
||
eval documents from local production documents.
|
||
|
||
Default runtime behavior keeps `retrieval.kb-scope` empty, so existing documents
|
||
without `kb_scope` are still searchable. Eval scripts pass
|
||
`-Dretrieval.kb-scope=rag-eval`, so L0 query hints, the filtered attempt, and
|
||
the unfiltered retry stay inside the eval corpus while the retry still skips the
|
||
L0 category filter.
|
||
|
||
Frontmatter is used for DB metadata, L0 hints, and vector metadata. It is
|
||
stripped before document chunking so embedding content represents the Markdown
|
||
body, not the YAML control plane. This is important for fallback eval: a decoy
|
||
document may intentionally match L0 keywords, but its body should remain low
|
||
quality evidence so the retry path can be exercised.
|