# RAG 检索可观测性、审计与 Trace(现行) **更新日期**:2026-07-28 **状态**:当前可运行 **关联**:`lookup_knowledge`、Harness `ToolBoundary`、`tool_invocation`、`DiagnosisTraceService`、离线 eval --- ## 1. 三层边界 ```mermaid flowchart TB subgraph A["A. 请求内 Trace"] LR[LookupResult
retrievalTrace / rerankTrace / relevanceLevel] end subgraph B["B. 持久化审计 + Trace API"] TI[tool_invocation 表] DT[diagnosis_trace 事件摘要] API["GET /api/diagnosis/{sessionId}/trace"] end subgraph C["C. 质量回归"] EV[eval/rag-retrieval offline baseline] end subgraph agent["Agent 可见(非审计)"] RT[RagToolResult
evidence + optional relevance_level] end LK[LookupKnowledgeTool] --> LR LR --> PROJ[RagResultProjector] PROJ --> RT LR --> BOUND[ToolBoundary audit] BOUND --> TI BOUND --> DT TI --> API DT --> API EV -.->|不替代运行时 Trace| LK ``` | 层 | 完善度 | 说明 | |----|--------|------| | A 请求内 | 高 | attempt / fallback / quality 齐全 | | B 持久化 + Trace API | 中高 | RAG 富字段入 `tool_invocation`,经 Trace API 回放 | | C 离线 eval | 高 | hybrid fixtures 回归 | **Agent 看到的不是完整 Trace。** 完整检索轨迹在 A/B;Agent 只拿投影后的证据契约。 --- ## 2. 端到端:从 lookup 到 Trace API ```mermaid sequenceDiagram participant Agent participant Adapter as RagToolAdapter participant Bound as ToolBoundary participant Tool as LookupKnowledgeTool participant Sink as JpaToolInvocationAuditSink participant DB as tool_invocation participant Trace as DiagnosisTraceService participant API as GET .../trace Agent->>Adapter: lookup_knowledge(query) Adapter->>Bound: execute(legacy, projector) Bound->>Tool: execute(query) Tool-->>Bound: raw LookupResult JSON Note over Tool: 内含 retrievalTrace / rerankTrace / evidenceBlocks Bound->>Bound: project → RagToolResult Bound->>Sink: AuditEvent + rawResultJson + agentResultJson Sink->>Sink: RagLookupAuditEnricher Sink->>DB: 富字段行 Bound-->>Agent: 投影后 agent_result(无完整 trace) API->>Trace: sessionId + optional runId Trace->>DB: find tool_invocation by run/session Trace-->>API: DiagnosisTraceResponse.toolInvocations[] ``` --- ## 3. A 层:请求内 Trace(`LookupResult`) 一次成功的 `lookup_knowledge` 内部出口是 **`LookupResult`**(比 Agent 契约更富)。 ### 3.1 结构总览 ```mermaid flowchart TB LR[LookupResult] LR --> F[found] LR --> EB[evidenceBlocks[]] LR --> CP[contextPack] LR --> RT[retrievalTrace] LR --> RR[rerankTrace] LR --> RL[relevanceLevel] LR --> CH[completenessHint] LR --> CNT[evidenceCandidateCount / evidenceBlockCount] RT --> ATT[attempts[]] RT --> SEL[selectedAttempt] RT --> FB[fallbackReason] RT --> HINT[queryHints L0] ``` | 字段 | 含义 | |------|------| | `found` | 是否有可用证据块 | | `evidenceBlocks` | 后处理后的 chunk 级证据(含 evidenceKey、source、content…) | | `contextPack` | 字符预算打包文本(内部/审计用) | | `retrievalTrace` | **检索路径 Trace**(见下) | | `rerankTrace` | 后处理排序/quality 痕迹(现多为保序后的 quality) | | `relevanceLevel` | PRECISE / REFERENCE / null | | `completenessHint` | 给模型的天花板提示文案 | ### 3.2 `retrievalTrace`(检索路径) | 字段 | 含义 | |------|------| | `originalQuery` | 原始查询 | | `rewrittenQuery` | L0/变换后用于检索的 query | | `categoryFilter` | 首次过滤的 category(可 null) | | `selectedAttempt` | 最终采用的 attempt 名 | | `fallbackReason` | 如 `filtered_vector_low_quality`;未降级为 null | | `evidenceStatus` | 内部:`supported` / `no_evidence` 等 | | `queryHints` | L0:domains、keywords、entities、l0_match_count… | | `attempts[]` | 每次检索尝试快照 | **常见 `selectedAttempt`:** | 值 | 含义 | |----|------| | `FILTERED_VECTOR` | 带 category 的首次检索即采用 | | `UNFILTERED_VECTOR` | 无 category,直接全库检索 | | `UNFILTERED_VECTOR_RETRY` | filtered 低质/无证据后去掉 category 重试 | **单次 `attempts[]` 元素:** | 字段 | 含义 | |------|------| | `name` | attempt 名 | | `query` | 该次实际检索句 | | `categoryFilter` | 该次 filter | | `candidateCount` | 召回候选数 | | `usable` | 后处理阈值后是否可用 | | `topScore` / `topSimilarity` | 引擎分 / 归一化 quality(0~1) | | `durationMs` | 耗时 | | `errorMessage` | 失败时 | ### 3.3 一次典型路径(含 filter fallback) ```mermaid flowchart TB Q[query] --> L0[L0 hint → 可选 categoryFilter] L0 --> A1[attempt FILTERED_VECTOR] A1 --> PQ{isLowQuality?} PQ -->|否| USE1[selectedAttempt = FILTERED_VECTOR] PQ -->|是| A2[attempt UNFILTERED_VECTOR_RETRY] A2 --> USE2[selectedAttempt = RETRY
fallbackReason = low_quality / no_evidence] USE1 --> POST[PostProcess · evidenceBlocks · relevanceLevel] USE2 --> POST POST --> LR[LookupResult 完整 Trace] ``` ### 3.4 与 Agent 投影的关系 ```mermaid flowchart LR LR[LookupResult 全量 Trace] --> PROJ[RagResultProjector] PROJ --> AG[RagToolResult] AG --> F1[evidence_status] AG --> F2[evidence excerpt] AG --> F3[relevance_level 可选] AG --> F4[truncated / returned_count] LR -.->|不投影| X1[retrievalTrace] LR -.->|不投影| X2[rerankTrace] LR -.->|不投影| X3[raw scores / contextPack 全文] ``` 人/系统要「为什么这样检索」→ 看 **A 全量** 或 **B 落库摘要**,不要只看 Agent 字段。 --- ## 4. B 层:持久化 + Trace API ### 4.1 写入路径 | 组件 | 职责 | |------|------| | `ToolBoundary` | 执行后发 `ToolInvocationAuditEvent`(含 raw LookupResult JSON + agent JSON) | | `RagLookupAuditEnricher` | 从 LookupResult 抽有界 RAG 字段 | | `JpaToolInvocationAuditSink` | 写入 `tool_invocation` | | `TraceAuditEvents.toolInvocation` | 另写一条 diagnosis_trace 摘要事件(不含全文 LookupResult) | ### 4.2 `tool_invocation` 列(RAG) | 列 | lookup_knowledge | 其它工具 | |----|------------------|----------| | `tool_name` | `lookup_knowledge` | 各自工具名 | | `retrieval_layer` | 通常 `L1` | `HARNESS` | | `relevance_level` | **PRECISE / REFERENCE / …** | **null**(不再写 evidence_status) | | `l0_match_count` | queryHints | null | | `l1_match_count` | evidence 块数等 | null | | `is_truncated` | 投影 truncated | false | | `retrieval_details` | JSON `rag_lookup_v1` | 通用 status 元数据 | | `output_preview` | level/attempt 摘要 | status=… | | `duration_ms` / `success` | 有 | 有 | ### 4.3 `retrieval_details`(rag_lookup_v1)示例 ```json { "audit_schema": "rag_lookup_v1", "search_mode": "hybrid", "selected_attempt": "UNFILTERED_VECTOR_RETRY", "fallback_reason": "filtered_vector_low_quality", "category_filter": "overfilter-decoy", "evidence_keys": ["doc#chunk-0"], "sources": ["doc"], "evidence_candidate_count": 8, "evidence_block_count": 2, "l0_hints": { "domains": ["mysql"], "matched_keywords": ["pool"] }, "attempts": [ { "name": "FILTERED_VECTOR", "category_filter": "overfilter-decoy", "candidate_count": 2, "usable": false, "top_similarity": 0.3, "duration_ms": 12 }, { "name": "UNFILTERED_VECTOR_RETRY", "candidate_count": 5, "usable": true, "top_similarity": 0.9, "duration_ms": 20 } ], "truncated": false, "returned_count": 2, "evidence_status": "EVIDENCE_FOUND", "invocation_status": "READY", "tool_call_id": "call-…" } ``` **默认不落库:** 原始 query 全文、chunk 正文 excerpt、完整 rerankTrace(体积与隐私)。 ### 4.4 Trace API:人怎么读 RAG **接口:** ```http GET /api/diagnosis/{sessionId}/trace GET /api/diagnosis/{sessionId}/trace?runId={runId} ``` **实现:** `DiagnosisTraceController` → `DiagnosisTraceService.getTrace` 按 `sessionId`(可选精确 `runId`)拉 run、steps、**toolInvocations**、摘要等。 **响应中与 RAG 相关的核心块:** `DiagnosisTraceResponse.toolInvocations[]` | API 字段 | 来源列 | 读法 | |----------|--------|------| | `toolName` | `tool_name` | 是否为 `lookup_knowledge` | | `retrievalLayer` | `retrieval_layer` | L1 / HARNESS | | `relevanceLevel` | `relevance_level` | RAG 粗相关度(非 evidence_status) | | `l0MatchCount` / `l1MatchCount` | 同名列 | L0/L1 规模提示 | | `truncated` | `is_truncated` | 证据是否被投影截断 | | `outputPreview` | `output_preview` | 一行摘要(level/attempt…) | | `retrievalDetails` | 解析自 `retrieval_details` | **RAG Trace 主阵地** | | `retrievalDetailsRaw` | 原始 JSON 字符串 | 调试 | | `durationMs` / `success` / `errorMessage` | 同名列 | 耗时与成败 | | `inputParams` | 通常仅 tool_call_id、request_bytes | **不含完整 query**(有意) | ```mermaid flowchart TB API["GET /api/diagnosis/{sessionId}/trace"] --> SVC[DiagnosisTraceService] SVC --> ROW[tool_invocation 行] ROW --> T1[列: relevanceLevel, L0/L1 count, layer…] ROW --> T2[retrievalDetails Map] T2 --> D1[search_mode] T2 --> D2[selected_attempt / fallback_reason] T2 --> D3[attempts[] / evidence_keys] T2 --> D4[evidence_status 契约状态] ``` ### 4.5 读 Trace 的推荐顺序(排查「这次知识库怎么检的」) ```mermaid flowchart TB S1[找到 toolName=lookup_knowledge 的 invocation] --> S2{success?} S2 -->|否| E[看 errorMessage / evidence_status] S2 -->|是| S3[看 retrievalDetails.search_mode] S3 --> S4[看 selected_attempt + fallback_reason] S4 --> S5[看 attempts[] 每次 candidate_count / top_similarity / usable] S5 --> S6[看 evidence_keys / sources] S6 --> S7[看 relevanceLevel 列] S7 --> S8[需要原文?看 Agent 侧 evidence 或当时 canonical 存储 · 审计默认无 excerpt] ``` | 现象 | 优先看 | |------|--------| | 为何走了 retry | `fallback_reason` + 两次 `attempts` | | 是否 hybrid | `search_mode` | | 滤错域 | `category_filter` + L0 domains | | 相关度档 | 列 `relevanceLevel`(PRECISE/REFERENCE) | | 返回了哪些块 | `evidence_keys` / `sources`(无正文) | | Agent 是否被截断 | `truncated` / `returned_count` | ### 4.6 diagnosis_trace 事件 vs tool_invocation 行 | 通道 | 内容 | 用途 | |------|------|------| | `tool_invocation` 行 | RAG 富字段完整摘要 | **主审计/回放** | | `diagnosis_trace` 中 `TOOL_INVOCATION` | tool_call_id、status、字节数、`has_raw_result` 等薄摘要 | 时间线事件,**不含**完整 retrieval_details | 查 RAG 细节以 **`toolInvocations[].retrievalDetails`** 为准。 --- ## 5. 与 Agent / Eval 的边界 ```mermaid flowchart LR subgraph human["人 / 运维 / 评测"] TRACE[Trace API] EVAL[Offline eval] end subgraph model["模型"] AGENT[RagToolResult only] end TI[(tool_invocation)] --> TRACE FX[fixtures] --> EVAL PROJ[Projector] --> AGENT ``` | 消费者 | 能看到 | |--------|--------| | Agent | evidence + 可选 relevance_level,无 attempt 细节 | | Trace API | 落库摘要:mode/attempt/fallback/keys/level… | | Offline eval | 冻结 fixture 全量 LookupResult(含 trace),与 golden 比对 | --- ## 6. 与旧文档差异 | 旧(archive `retrieval-observability`) | 现 | |----------------------------------------|-----| | `vector-store.mode` 多后端 | `search_mode` dense\|hybrid,单一 V2 store | | sink 理想化未落地 | `RagLookupAuditEnricher` + 列回填 | | `relevance_level` 混用 evidence_status | **列仅 RAG 等级**;契约状态在 details | | 未写清 Trace API 读法 | 本文 §4.4–4.5 | --- ## 7. 代码锚点 | 职责 | 类 / 路径 | |------|-----------| | 内建 Trace | `LookupKnowledgeTool`、`RetrievalTrace`、`LookupResult` | | 投影 | `RagResultProjector`、`RagToolResult` | | 审计事件 | `ToolInvocationAuditEvent`、`ToolBoundary` | | 富化 | `RagLookupAuditEnricher` | | 落库 | `JpaToolInvocationAuditSink`、`ToolInvocation` | | Trace API | `DiagnosisTraceController`、`DiagnosisTraceService`、`DiagnosisTraceResponse.ToolInvocationTrace` | | 离线回归 | `eval/rag-retrieval/`、`scripts/eval_rag_retrieval.py` | --- ## 8. 已知限制 - 持久化 **不存** 完整 query/excerpt(有意);要正文需 Agent 侧证据或其它存储 - `dedup_reason` 列可能仍为空 - 非 `lookup_knowledge` 工具仍为薄审计 - **历史** `tool_invocation` 行可能仍把 evidence_status 写进 `relevance_level`(旧 sink) - `diagnosis_trace` 时间线事件不替代 `retrieval_details` --- ## 9. 相关文档 | 文档 | 内容 | |------|------| | `mvp/architecture/RAG知识检索架构.md` | 检索主架构 | | `docs/RAG-Agent如何读relevance_level.md` | Agent 如何读 level | | `docs/RAG-Hybrid质量分与后处理.md` | quality / 排序闸门 | | `docs/RAG离线评测-基线设计.md` | 离线评测(非运行时 Trace) | | `mvp/architecture/session-trace-lifecycle.md` | 会话/run Trace 总览(若存在) |