Files
SuperBizAgent-java/mvp/archive/2026-07-20-doc-cleanup/issues/design-notes/executor-self-evidence-loop-design-note.md
T

13 KiB
Raw Blame History

Executor 自证循环与证据摘要链路设计记录

归档说明:本文是实施前的问题分析。当前实现以 mvp/architecture/executor-evidence-pipeline-refactor.md 和 OpenSpec 主规格为准。

状态:已形成方向,待创建 OpenSpec change 严重程度:高 记录时间:2026-07-07 来源:近期 Chat 诊断 LOW_CONFID 排查、Executor 幻觉问题复盘、与 interview-guide 类似评估链路对比 关联:executor-evidence-attribution-hallucination、chat-verifier-agent、evidence-trace-hardening


背景

近期诊断会话中,Executor 已经成功调用了 lookup_knowledge、query_logs、query_metrics 等证据工具,但最终仍频繁被 Verifier 判定为 LOW_CONFID。

复核工具调用和 Executor 输出后发现,问题不是“完全没有证据”,而是 Executor 在拿到部分工具返回后,会把以下内容混在一起:

  • 工具本次真实返回的事实;
  • runbook、RAG、历史案例里的通用模式;
  • 模型基于经验补全的诊断故事;
  • 其它服务的告警和日志;
  • 尚未被当前工具证明的具体错误、数值或因果关系。

这种行为导致 Executor 的最终答案看起来完整,但其中一部分关键事实并没有被当前会话证据支撑。Verifier 正确拦截后,系统长期停留在 LOW_CONFID。


关键发现

1. LOW_CONFID 不是因为 Verifier 只看 RAG

实际 verifier_evaluation.facts_checked[].evidence_refs 中已经出现了 query_logs 和 query_metrics。

例如,payment-service CPU 92% 可以被 Verifier 识别为来自:

  • query_metrics
  • query_logs

因此问题不是 Verifier 完全忽略非 RAG 工具。

真正的问题是:

  • Executor 的证据绑定不稳定;
  • 工具原始输出、摘要、Executor claim、Verifier 校验之间没有一条稳定的数据契约;
  • Executor 仍然可能把未证明内容写成 confirmed claim。

2. 工具返回目前不是统一格式

现有证据型工具返回结构不同:

  • query_logs 的证据主体在 logs[].message
  • query_metrics 的证据主体在 alerts[].description
  • lookup_knowledge 的证据主体在 evidenceBlocks[].content / contextPack.packedText

同时模型看到的工具名和持久化工具名也不完全一致:

  • 模型工具名:queryLogs、queryPrometheusAlerts、lookupKnowledge
  • 持久化工具名:query_logs、query_metrics、lookup_knowledge

这让 Executor 自己生成 tool_name、source_invocation_ids、source_id 时很容易漂移。

3. 规则抽取 text 不足以解决问题

曾讨论过由后端将不同工具返回统一抽成:

{
  "id": "tool:394:0",
  "tool": "query_logs",
  "invocation_id": 394,
  "domain": "system-metrics",
  "text": "CPU使用率过高: 92.0%, 线程数: 245"
}

这个方向能解决“证据可引用”的一部分问题,但有明显风险:

  • 不同工具返回形态不同,适配器会持续膨胀;
  • 长日志、堆栈、RAG 长文本很难靠固定规则安全缩短;
  • 规则生成的 text 可能丢掉否定、上下文或条件;
  • 一旦 text 被当成事实来源,它本身也可能成为幻觉入口。

因此,仅靠“工具适配器 + 规则 text”不是最终方案。


设计转向

我们最终认可的方向是:

LLM 做语义压缩,代码做边界控制;不要让 Executor 同时总结证据和使用证据下结论。

这意味着系统不再追求“所有工具由规则抽成完美 evidence block”,而是引入独立的证据摘要阶段。


Executor 自证循环

当前危险链路可以描述为:

Executor 调工具
  -> Executor 阅读工具输出
  -> Executor 自己总结工具输出
  -> Executor 自己生成 claims
  -> Executor 自己给 claims 绑定 evidence
  -> Verifier 事后校验

这个流程的风险是:如果 Executor 总结错了,它可能继续基于错误摘要生成 claim,形成“自己造证据,再用自己造的证据证明自己”的闭环。

要拆掉这个闭环,需要把“证据摘要”和“诊断推理”拆开。


目标链路

推荐链路如下:

Planner
  -> Collector Agent
      只调用工具,收集证据
  -> Evidence Digest Chain
      只总结工具输出,不做诊断
  -> Diagnosis Executor Chain
      只基于 evidence_digests 做诊断推理
  -> Verifier
      校验 digest 是否忠实 raw,claim 是否可合理推出
  -> Final Composer Chain
      基于 verifier 过滤后的内容生成最终用户答案

这里并不要求所有阶段都实现为 Agent。

  • Collector 需要调用工具,适合作为 Agent。
  • Evidence Digest 不调用工具,适合作为无状态 LLM chain。
  • Diagnosis Executor 可以先作为无工具 LLM chain。
  • Verifier 可以继续作为质量门。
  • Final Composer 不调用工具,只做最终表达,也适合作为 LLM chain。

各阶段职责

Collector Agent

职责:

  • 根据 Planner 计划调用工具;
  • 调用 lookup_knowledge、query_logs、query_metrics 等证据工具;
  • 不输出根因;
  • 不输出修复建议;
  • 不输出最终诊断结论。

输出:

{
  "collection_summary": "已完成知识库、日志、指标查询",
  "tool_invocation_ids": [392, 393, 394, 395]
}

Evidence Digest Chain

职责:

  • 读取工具原始输出或持久化工具调用记录;
  • 对工具结果做语义摘要;
  • 每条摘要必须引用 source_invocation_ids;
  • 不做因果判断;
  • 不输出修复建议;
  • 不把“可能原因”改写成“确定根因”。

输出:

{
  "digests": [
    {
      "digest_id": "digest-1",
      "source_invocation_ids": [394],
      "tool": "query_logs",
      "domain": "system-metrics",
      "summary": "payment-service 的系统指标日志显示 CPU 使用率为 92.0%,线程数为 245。",
      "source_quote": "CPU使用率过高: 92.0%, 进程: java (PID: 1), 线程数: 245"
    }
  ]
}

Diagnosis Executor Chain

职责:

  • 只读取用户问题、Planner 计划、evidence_digests;
  • 不直接读取 raw 工具输出;
  • 不调用工具;
  • 基于 digest 做诊断推理;
  • 区分直接观测、合理推导、假设和证据缺口。

输出:

{
  "claims": [
    {
      "claim_id": "claim-1",
      "claim_type": "observation",
      "claim_text": "payment-service 当前存在 CPU 使用率过高现象。",
      "evidence_refs": ["digest-1"]
    },
    {
      "claim_id": "claim-2",
      "claim_type": "reasonable_inference",
      "claim_text": "CPU 使用率过高可能是支付接口超时的重要因素。",
      "evidence_refs": ["digest-1", "digest-knowledge-1"]
    }
  ],
  "candidate_answer": "..."
}

Verifier

Verifier 不再只判断“是否存在直接证据”,而是校验两层:

  1. digest 是否忠实于 raw 工具输出;
  2. claim 是否可由 digest / raw 合理推出。

推荐判定类型:

  • direct_observation:证据直接观测到;
  • reasonable_inference:可以从证据合理推出;
  • overstated:有部分依据,但结论说重了;
  • unsupported:证据不足;
  • external_unknown:引入了证据外的新实体、新数值、新错误;
  • contradicted:与证据冲突。

输出示例:

{
  "digest_checks": [
    {
      "digest_id": "digest-1",
      "verification": "faithful"
    }
  ],
  "claim_checks": [
    {
      "claim_id": "claim-2",
      "verification": "reasonable_inference",
      "detail": "CPU 92% 是直接观测事实;将其作为超时可能因素属于合理推导,但仍需延迟和错误率证据确认因果链。"
    }
  ]
}

Final Composer Chain

代码不应负责写语义总结;代码只负责过滤输入。

Final Composer 的输入应由后端根据 Verifier 结果构造:

{
  "original_query": "支付接口最近出现超时...",
  "confirmed_findings": [
    {
      "text": "payment-service CPU 使用率为 92%,线程数 245",
      "basis": "query_logs/query_metrics"
    }
  ],
  "reasonable_inferences": [
    {
      "text": "CPU 过高可能导致接口处理变慢",
      "basis": "CPU 过高 + runbook 说明 CPU 飙高会伴随慢请求"
    }
  ],
  "insufficient_evidence": [
    {
      "text": "order-service OOM 是根因",
      "reason": "当前证据未发现 OOM 日志"
    }
  ],
  "allowed_actions": [
    "排查 payment-service CPU 热点线程",
    "补充查询接口 P95/P99 延迟、错误率和下游依赖耗时"
  ]
}

Composer 只允许基于上述字段生成用户答案,不允许引入新的服务名、指标值、错误码或根因。


是否需要改成 SupervisorAgent

当前结论:暂时不需要。

原因:

  • 当前目标是固定 pipeline 的职责隔离;
  • SupervisorAgent 主要解决动态路由和调度问题;
  • 过早引入 Supervisor 可能增加不确定执行顺序,重新引入 Verifier 过早执行等问题。

推荐先保留明确编排:

planner.call()
collector.call()
evidenceDigestService.digest(...)
diagnosisExecutorChain.call(...)
verifier.call(...)
finalComposerChain.call(...)

当未来出现以下需求时,再考虑 Supervisor:

  • Verifier 要求补证据后自动回到 Collector;
  • 不同诊断 skill 选择不同 worker;
  • 需要多轮动态停止条件;
  • 工具调用策略由 Supervisor 统一决策。

从 interview-guide 借鉴的设计

Snailclimb/interview-guide 不是多 Agent 编排,而是多阶段 LLM pipeline:

问答记录
  -> 分批评估 LLM
  -> 结构化 BatchReportDTO
  -> 代码合并批次结果
  -> 二次汇总 LLM
  -> 结构化 SummaryDTO
  -> 失败降级
  -> EvaluationReport

可借鉴点:

  1. LLM 做语义,代码做边界;
  2. 中间结果必须结构化;
  3. 先局部处理,再二次汇总;
  4. 结构化输出调用应统一封装;
  5. 每个 LLM 阶段都要有解析失败、格式错误和降级路径。

对应到本项目,建议新增类似 StructuredLlmInvoker 的基础组件,统一处理:

  • 严格 JSON prompt;
  • LLM 调用;
  • JSON 解析;
  • schema 校验;
  • 重试;
  • parse status;
  • fallback。

为什么最终方案比规则适配器更合适

规则适配器适合做工程边界:

  • 过滤非证据工具;
  • 保留 invocation id;
  • 切分长输出;
  • 限长;
  • 保存 trace。

但规则不适合做语义摘要:

  • 堆栈长短和重点不固定;
  • RAG 长文本需要理解上下文;
  • 告警描述里可能包含“可能原因”,不能被规则粗暴改写;
  • 固定字段拼接无法保证给 Verifier 提供足够语义。

因此,规则层只做预处理,语义摘要交给独立 Evidence Digest Chain,且 Verifier 需要校验 digest 忠实性。


推荐实施路线

Phase 1:在现有 Sequential 流程旁插入 Evidence Digest

保持现有 Planner -> Executor -> Verifier 基本流程,先新增:

  • EvidenceDigestService
  • evidence_digests 持久化或存入 self_evaluation
  • Verifier 输入增加 evidence_digests
  • Verifier 判定类型扩展为可推导性校验

目标:先解决“非 RAG 工具事实无法被合理推导识别”和“Verifier 只做硬证据匹配过窄”的问题。

Phase 2:拆分 Executor

将当前 Executor 拆为:

  • CollectorAgent
  • DiagnosisExecutorChain

DiagnosisExecutor 不再调用工具,不再直接看 raw 工具输出,只基于 Evidence Digest 做诊断。

目标:拆掉 Executor 自证循环。

Phase 3:引入 Final Composer Chain

不再直接将 Executor 原文作为最终答案。

后端根据 Verifier 结果构造 Composer 输入,由 Composer LLM 生成最终用户答案。

目标:避免 unsupported / overstated 内容绕过 Verifier 重新出现在用户答案里。

Phase 4:按需考虑 SupervisorAgent

只有当补证据循环、动态 worker 路由或多轮停止条件变复杂时,再迁移到 SupervisorAgent。


验收方向

  • Executor 不再同时负责证据摘要和诊断结论;
  • Diagnosis Executor 不能调用工具;
  • Diagnosis Executor 不能引用不存在的 digest;
  • Verifier 能区分 direct_observation、reasonable_inference、overstated、unsupported、external_unknown、contradicted;
  • Final Composer 只能看到 Verifier 允许使用或降级后的材料;
  • LOW_CONFID 输出不再把 unsupported claim 表达成确认结论;
  • 对 mock 工具、真实 RAG、日志、指标均能保持同一套可审计链路;
  • 结构化输出失败时有明确降级路径。

结论

本次讨论确认:单纯加强 Executor prompt 或增加规则式 evidence text 不能根治幻觉问题。

最终认可的方向是:

将证据收集、证据摘要、诊断推理、推理校验、最终表达拆成独立阶段;LLM 负责语义任务,代码负责边界、结构、过滤和降级。

这套设计既保留 Agent 工具调用能力,也避免 Executor 自己生成证据再证明自己的自证循环。