Files
SuperBizAgent-java/mvp/issues/design-notes/executor-self-evidence-loop-design-note.md

444 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Executor 自证循环与证据摘要链路设计记录
**状态**:已形成方向,待创建 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` 不足以解决问题
曾讨论过由后端将不同工具返回统一抽成:
```json
{
"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 自证循环
当前危险链路可以描述为:
```text
Executor 调工具
-> Executor 阅读工具输出
-> Executor 自己总结工具输出
-> Executor 自己生成 claims
-> Executor 自己给 claims 绑定 evidence
-> Verifier 事后校验
```
这个流程的风险是:如果 Executor 总结错了,它可能继续基于错误摘要生成 claim,形成“自己造证据,再用自己造的证据证明自己”的闭环。
要拆掉这个闭环,需要把“证据摘要”和“诊断推理”拆开。
---
## 目标链路
推荐链路如下:
```text
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` 等证据工具;
- 不输出根因;
- 不输出修复建议;
- 不输出最终诊断结论。
输出:
```json
{
"collection_summary": "已完成知识库、日志、指标查询",
"tool_invocation_ids": [392, 393, 394, 395]
}
```
### Evidence Digest Chain
职责:
- 读取工具原始输出或持久化工具调用记录;
- 对工具结果做语义摘要;
- 每条摘要必须引用 `source_invocation_ids`;
- 不做因果判断;
- 不输出修复建议;
- 不把“可能原因”改写成“确定根因”。
输出:
```json
{
"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 做诊断推理;
- 区分直接观测、合理推导、假设和证据缺口。
输出:
```json
{
"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`:与证据冲突。
输出示例:
```json
{
"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 结果构造:
```json
{
"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 过早执行等问题。
推荐先保留明确编排:
```text
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:
```text
问答记录
-> 分批评估 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 自己生成证据再证明自己的自证循环。