Relocate RAG and diagnosis decision/E2E writeups from docs/ root into mvp/engineering so architecture, issues, and engineering narrative stay together. Update indexes and cross-links; leave docs/learning as legacy.
13 KiB
Agent 如何读 relevance_level:它是什么、不是什么
日期:2026-07-28
范围:lookup_knowledge 投影给 Agent 的粗粒度相关度标签
读者:要在 Diagnosis Agent / 工具契约里正确使用知识库结果的工程与提示词同学
关联:
- ACI 契约:
RagToolResult.relevance_level/RagRelevanceLevel - 计算:
KnowledgeEvidencePostProcessor→qualityScore阈值 - 质量统一:
RAG-Hybrid质量分与后处理.md - 多路与 RRF:
RAG排序-多路召回与RRF.md - 运行时 Trace / 审计:
mvp/architecture/RAG检索可观测性与审计.md
1. 一句话定义
relevance_level 是对「这一次 lookup_knowledge 调用整体有多相关」的粗档标签,不是某一条 evidence 的分数,也不是 0~1 的相似度。
Agent 真正写诊断、做引用时,仍应以 evidence[] 里的 excerpt 为准;relevance_level 只帮助判断:这批评据大概有多硬、还要不要再查。
flowchart LR
subgraph tool["lookup_knowledge 结果"]
ES[evidence_status]
EV[evidence excerpt]
RL[relevance_level]
TR[truncated]
end
ES --> DEC{Agent 决策}
EV --> DEC
RL --> DEC
TR --> DEC
DEC --> A1[写结论 / 引用]
DEC --> A2[再查 / 换工具]
DEC --> A3[证据不足降级]
2. 它出现在哪里
成功(或有结果)的知识库工具投影里,典型形状:
{
"evidence_status": "EVIDENCE_FOUND",
"tool_call_id": "call-…",
"query": "用户/Agent 的检索句",
"evidence": [
{
"document_id": "doc#chunk-0",
"source": "…",
"title": "…",
"breadcrumb": "…",
"excerpt": "…"
}
],
"returned_count": 3,
"relevance_level": "PRECISE",
"truncated": false
}
要点:
- JSON 字段名是
relevance_level(snake_case) - Java 枚举:
RagRelevanceLevel(PRECISE/HIGHLY_RELEVANT/REFERENCE) - 无可用证据或质量不够时,字段常为 null / 省略(
NON_NULL) - Agent 看不到 raw L2、RRF 分、
retrievalTrace、rerankTrace(ACI 有意裁掉)
flowchart TB
subgraph internal["内部 LookupResult(审计/调试)"]
QS[qualityScore / topSimilarity]
RT[retrievalTrace / rerankTrace]
CP[contextPack 全文]
SC[raw score / scoreLabel]
end
subgraph project["RagResultProjector"]
P[裁剪与规范化]
end
subgraph agent["Agent 可见 RagToolResult"]
A1[evidence_status]
A2[tool_call_id / query]
A3[evidence excerpt 列表]
A4[relevance_level 可选]
A5[returned_count / truncated]
end
internal --> P --> agent
3. 枚举值怎么理解
| 值 | 产品语义 | Agent 侧更合理的用法 |
|---|---|---|
| PRECISE | 整体很贴:当前 top 证据质量高,继续同题检索不太可能更准 | 优先依据 evidence[] 组织结论;避免无意义的重复 lookup_knowledge |
| HIGHLY_RELEVANT | 高度相关(枚举保留) | 与 PRECISE 类似,略保守表述即可 |
| REFERENCE | 可作参考,但不到「已精准命中」 | 可引用,但结论留余地;缺维度时换 query 再查或叠日志/指标 |
| null / 不出现 | 没有可报的粗相关档(无证据或 top 质量偏低) | 不要当成知识库已证实;按证据不足处理 |
和 evidence_status 的分工
| 字段 | 回答的问题 |
|---|---|
evidence_status |
这次有没有合法、可引用的证据(如 EVIDENCE_FOUND / NO_EVIDENCE) |
relevance_level |
有证据时,整体有多贴(粗档) |
evidence[] |
具体可以引用哪些片段 |
没有证据时,不应指望靠 relevance_level「升级」出结论;契约上也不会用 level 把空结果扮成有证据。
flowchart TB
ES{evidence_status}
ES -->|NO_EVIDENCE| N1[不要当知识库已证实]
ES -->|EVIDENCE_FOUND| RL{relevance_level}
RL -->|PRECISE| U1[优先引用 excerpt · 少重复检索]
RL -->|REFERENCE| U2[可引用 · 结论留余地]
RL -->|null / 缺省| U3[有块但质量偏低 · 慎用强结论]
RL -->|HIGHLY_RELEVANT| U4[与 PRECISE 类似 · 略保守]
4. 它是怎么算出来的(实现口径)
4.1 只看「本轮第一名」的 qualityScore
后处理在完成排序、去重、截断之后:
取 originalRank 最优(排序后第一条)的 qualityScore
≥ highly-relevant-threshold (默认 0.75) → PRECISE
≥ reference-threshold (默认 0.5) → REFERENCE
否则 / 无可用证据 → null
配置(application.yml):
retrieval:
normalization:
max-l2-distance: 2.0
highly-relevant-threshold: 0.75
reference-threshold: 0.5
因此:
- level 描述的是 整次调用的 top 质量,不是每条 evidence 各打一档
- 列表里第 2、第 3 条即使偏弱,只要 top1 够高,整次仍可能是
PRECISE
flowchart TB
RET[检索有序候选] --> POST[后处理:保 originalRank · 去重 · 截断]
POST --> TOP[取排序后第一条 qualityScore]
TOP --> T1{≥ 0.75?}
T1 -->|是| PRECISE[PRECISE]
T1 -->|否| T2{≥ 0.5?}
T2 -->|是| REF[REFERENCE]
T2 -->|否| NULL[null / 不报档]
4.2 qualityScore 从哪来(和检索 mode 绑定)
统一经 RetrievalScoreNormalizer.toQualityScore:
retrieval.search.mode |
top qualityScore 含义 |
|---|---|
| dense | top1 的 L2 归一化:约 1 - L2 / maxL2Distance |
| hybrid | 优先同 id 的 denseDistance(绝对 L2 质量,供闸门/level);无 dense 邻域时 rank 回退 |
flowchart LR
subgraph dense_mode["mode=dense"]
L2[score = L2] --> QD[quality = 1 - L2/max]
end
subgraph hybrid_mode["mode=hybrid"]
RRF[RRF 序 = originalRank] --> SORT[列表顺序]
DD[denseDistance 可选] --> QH{有 dense?}
QH -->|是| QL[quality = L2 归一化]
QH -->|否| QR[quality = rank 映射]
end
QD --> LV[relevance_level]
QL --> LV
QR --> LV
读 level 时注意:
dense 下的 PRECISE ≈「向量足够近」
hybrid 下的 PRECISE ≈「top1 的绝对/回退 quality 跨过了 0.75」;排序仍跟 RRF,不是「又变回只信 L2 排序」。
不要把 hybrid 的 level 读成与 dense 完全同一把尺子,但也不要再假设「rank1 永远 PRECISE」(在附带 denseDistance 后,远邻 decoy 可以很低分并触发 filter fallback)。
4.3 关于 HIGHLY_RELEVANT
枚举和旧文档里仍有三档。历史上大致是:
高分 + L0 hint 支撑 → PRECISE
高分但无 hint → HIGHLY_RELEVANT
中等分 → REFERENCE
质量分统一之后,当前实现是:≥ 0.75 直接 PRECISE,不再要求 L0 contains 才能精准。
因此运行时 很少再单独产出 HIGHLY_RELEVANT;读旧 trace / 旧快照时仍可能见到。
5. Agent 应该怎么读(建议协议)
5.1 推荐读法
1. 先看 evidence_status
2. 再读 evidence[] 的 excerpt(唯一可引用正文)
3. 用 relevance_level 调节「敢多敢少」与「要不要再查」
flowchart TB
START[收到 RagToolResult] --> S1{evidence_status}
S1 -->|无证据| FAIL[不编造 · 换工具或安全降级]
S1 -->|有证据| S2[精读 evidence excerpt]
S2 --> S3{relevance_level}
S3 -->|PRECISE| C1[结论可较硬 · 少重复同 query 检索]
S3 -->|REFERENCE| C2[结论留余地 · 可换问法或叠日志指标]
S3 -->|缺省| C3[慎用强结论 · 优先补查]
C1 --> CITE[引用必须落在 excerpt]
C2 --> CITE
C3 --> CITE
| 组合 | 建议行为 |
|---|---|
| FOUND + PRECISE | 以 excerpt 为主写结论;少重复同 query 检索 |
| FOUND + REFERENCE | 可引用,表述保守;缺关键事实则改写 query 或换工具 |
| FOUND 但 level 空 | 有块但质量闸门偏低:慎用强结论,优先补查 |
| NO_EVIDENCE | 不编造知识库依据;走其他证据工具或安全降级 |
5.2 明确不要这样读
-
不要当逐条相关度
没有evidence[i].relevance_level;不能说「第 2 条是 REFERENCE」。 -
不要当连续分数
没有 0.83;只有粗档。不要在推理里假装有精确分。 -
不要在 hybrid 下当成绝对语义相似度
序数 quality 下 PRECISE 很常见,表示「本轮第一够格」,不等于「全局语义必近」。 -
不要代替 excerpt 引用
level 不能当证据正文;Gatekeeper / EvidenceGuard 认的是可核对片段与引用约束。 -
不要和 Harness 验真混为一谈
level 是检索侧粗标;工具生命周期、evidence_status、守卫校验是另一层。 -
不要用它驱动跨 mode 对比
同一 query 切 dense/hybrid 时,比命中集合与排名;别只比「是不是都 PRECISE」。
6. Agent 看不见、但会影响 level 的内部量
便于排查「为什么突然全是 PRECISE / 总是 null」:
| 内部量 | 作用 | Agent 是否可见 |
|---|---|---|
qualityScore / topSimilarity |
定 level、低质 retry | 否 |
originalRank |
排序权威;hybrid quality 输入 | 否 |
score + scoreLabel |
dense=L2 / hybrid=融合侧 | 否 |
| L0 domain/keyword | 现仅 hitReasons 解释,不改序、不抬 level | 否(reasons 也可能被投影裁掉) |
completenessHint |
内部完整度文案 | 通常否 |
| category filter + unfiltered retry | 低质时可能换一批 evidence 再定 level | 过程 trace 否 |
投影原则(ACI):模型只要能理解与引用结果;不给 raw score、阈值、trace。
flowchart TB
subgraph pipe["检索管道内部"]
STORE[Milvus hybrid/dense]
NORM[toQualityScore]
POST[PostProcessor]
STORE --> NORM --> POST
end
POST --> LV[relevance_level]
POST --> EB[evidenceBlocks]
POST --> TR[traces · 通常不投影]
EB --> PROJ[RagResultProjector]
LV --> PROJ
PROJ --> AGENT[Agent Observation]
7. 和相邻概念的边界
evidence_status 有没有证据
relevance_level 有的话有多贴(粗)
evidence[].excerpt 贴在哪一段文字上(细、可引用)
truncated 列表是否被预算截断(可能还有更好的没展示)
information_gain 等 诊断环路里「这轮工具对任务有没有增益」(另一契约)
flowchart TB
subgraph fields["同一次工具结果里的分工"]
ES[evidence_status<br/>有没有]
RL[relevance_level<br/>有多贴·粗]
EX[excerpt<br/>说什么·细]
TC[truncated<br/>是否被截断]
end
ES --> USE[Agent 使用]
RL --> USE
EX --> USE
TC --> USE
USE --> NOTE[结论锚在 excerpt<br/>level 只调力度]
truncated=true 时:即使 PRECISE,也只说明 已返回子集里的 top 很强,不保证库内没有更相关却被截掉的块。
8. 提示词 / 产品文案可用的短说明
可直接给模型或文档的精简版:
relevance_level 是本次知识库检索的整体相关度粗标:
- PRECISE:当前证据整体很贴,优先引用 evidence 写结论,避免无意义重复检索
- REFERENCE:仅供参考,结论需留余地,必要时换问法或改用其他工具
- 缺省:不要把本次结果当作高置信知识库证实
务必以 evidence 中的 excerpt 为唯一引用依据;不要编造未出现的文档内容。
在 hybrid 检索下,PRECISE 更多表示「本轮排序第一档」,不是精确相似度分数。
9. 常见误读示例
| 误读 | 更正 |
|---|---|
| 「PRECISE 所以三条 evidence 都精准」 | 只保证 top 质量跨线;其余条只是同批返回 |
| 「没有 relevance_level 就是工具失败」 | 更可能是无证据或质量偏低;看 evidence_status |
| 「hybrid 全是 PRECISE 说明召回完美」 | 可能只是 rank1→quality=1.0 的档位特性 |
| 「REFERENCE 的 excerpt 不能引用」 | 可以引用,但结论强度应下调 |
| 「level 高就可以跳过 excerpt」 | 不可;引用与验真仍看正文 |
10. 结语
relevance_level 是检索链路送给 Agent 的 粗粒度驾驶辅助:
- 告诉模型这批评据大概硬不硬
- 不替代 excerpt,不暴露打分细节,不等于逐条标注
在 dense 模式下,它更接近「向量有多近」;
在 hybrid 主路径下,它更接近「本轮融合第一名是否跨过质量门槛」。
读的时候记住三句即可:
1. 先 status,再 excerpt,最后才看 level
2. level 管「敢多敢少」,excerpt 管「说了什么」
3. hybrid 的 PRECISE ≠ 绝对语义满分
附录:代码与规格锚点
| 项 | 位置 |
|---|---|
| Agent 结果契约 | RagToolResult / RagRelevanceLevel |
| 投影 | RagResultProjector |
| 等级计算 | KnowledgeEvidencePostProcessor.computeRelevance |
| 质量分 | RetrievalScoreNormalizer |
| 规格 | openspec/specs/aci-evidence-tool-contracts、rag-retrieval-quality-score |
| 架构 | mvp/architecture/RAG知识检索架构.md §9 |