6.5 KiB
RAG 评测闭环架构
更新日期:2026-07-06
本文记录当前 RAG 质量闭环。它的目标不是证明检索“永远正确”,而是让每次改 lookup_knowledge、L0 hint、向量召回、post-retrieval、rerank 或 context packing 时,都能得到可重复的回归信号。
1. 闭环分层
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
核心资产:
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
运行:
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 必须使用当前模块化格式:
{
"lookupResult": {
"evidenceBlocks": [],
"contextPack": {},
"retrievalTrace": {},
"rerankTrace": {}
}
}
当前 golden cases 直接以模块化格式为唯一契约,因为这个版本的目标是验证完整 RAG pipeline,而不只是验证候选召回。
4. Fallback Case
当前 baseline 增加了 chat-l0-filter-fallback:
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 闭环
生成当前报告并与旧基线对比:
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
真实工具快照生成命令:
.\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:
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:
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.