Files
SuperBizAgent-java/mvp/issues/executor-structured-output-v2.md
T

46 KiB
Raw Blame History

Executor Structured Output V2 实施设计

状态:待规划
严重程度:高
日期:2026-07-07
文档类型:实施设计文档
范围:Chat Executor 输出结构、Gatekeeper、Verifier、Composer 数据契约调整
关联问题:

  • executor-evidence-attribution-hallucination
  • executor-self-evidence-loop-design-note
  • chat-verifier-agent
  • executor-evidence-output-contract

0. 给实现 Agent 的阅读入口

这份文档用于指导 Chat 复杂诊断链路的一次增量改造。实现时不要先从字段表开始,而应按以下顺序阅读:

  1. 先读 0.1 - 0.7,理解为什么改、当前链路是什么、目标链路是什么、哪些地方不能改。
  2. 再读 20 - 25,理解代码影响面、实施阶段、回滚策略和完成标准。
  3. 最后按需查阅 2 - 19 的详细数据契约、Gatekeeper 规则、Verifier/Composer 输入输出。

一句话目标:

把 Executor 从“诊断 + 表达”收敛为“证据收集 + 结构化事实输出”,
在 Verifier 前加 Gatekeeper 做确定性拦截,
让 Verifier 只判断 claim 是否能由证据合理推出,
最终用户答案交给 Composer 生成。

0.1 背景

当前 Chat 复杂诊断链路中,Executor 的输出既包含结构化证据归因,也包含最终面向用户的自然语言答案:

diagnosis_summary
user_facing_answer

这导致一个核心问题:Executor 在证据还不充分时,容易提前把“可能方向”写成“确认结论”。后续 Verifier 虽然会校验,但它面对的是自然语言答案和结构化字段混在一起的输出,容易出现以下风险:

  • Executor 编造不存在的 source_invocation_ids。
  • Executor 使用真实 invocation id,但 evidence_excerpt 与真实工具输出不一致。
  • Executor 把 hypothesis 写成 confirmed claim。
  • Executor 在 user_facing_answer 里夹带 claims 中没有的根因、错误码、指标值或修复建议。
  • Verifier 被迫从自然语言里逐字抽事实,校验边界不稳定。

因此,本次改造不是为了增加 Agent 数量,而是为了收紧职责边界和证据链路。


0.2 当前实现

当前代码中的复杂 Chat 链路是三 Agent 顺序执行:

chat_planner -> chat_executor -> chat_verifier

对应入口在:

ChatService.executeChatComplex(...)

当前数据流:

用户问题
  -> Planner 生成 planner_plan
  -> Executor 调用工具并输出 executor_evidence_v1
  -> VerifierInputHook 构造 verifier payload
  -> Verifier 输出 facts_checked/verdict
  -> ChatService 根据 verdict 生成最终 answer

当前关键问题在 Executor 与 Verifier 之间:

Executor 同时输出结构化 claims 和 user_facing_answer
Verifier 既要校验 structured output,又要扫描自然语言答案

这会让最终答案和证据归因之间出现缝隙。


0.3 目标设计

目标链路仍保持单条顺序链路,不新增 Controller,不改 Planner:

chat_planner
  -> chat_executor
  -> VerifierInputHook 内 Gatekeeper
  -> chat_verifier
  -> chat_composer
  -> final answer

职责边界:

组件 职责
Planner 选择 skill、拆解计划;本次不改
Executor 调用工具收集证据,输出结构化 claims/hypotheses/actions/missing_info
Gatekeeper 在 Verifier 前做确定性校验,拦截伪造 ID、工具名不匹配、明显张冠李戴、非法 schema
Verifier 判断 claims 是否能由证据合理推出,不再逐字扫描最终答案
Composer 只根据 Verifier 允许的材料生成最终用户答案

目标数据流:

Executor raw JSON
  -> parse JSON
  -> Gatekeeper.validate(...)
  -> Verifier claim-level validation
  -> ChatService 过滤 allowed_claims/allowed_hypotheses
  -> Composer 生成 user_facing_answer

0.4 分阶段实施总览

阶段 目标 主要改动 验收重点
阶段一 Executor V2 输出契约 改 chat-executor-prompt.md,移除 diagnosis_summary / user_facing_answer Executor 只输出结构化诊断材料
阶段二 Gatekeeper 接入 在 VerifierInputHook 中加入 Gatekeeper,写入 payload 和审计 伪造 id、工具名不匹配、schema 退化可被拦截
阶段三 Verifier V2 改 chat-verifier-prompt.md,从 facts_checked 转向 claim_checks Verifier 判断可推导性,不再逐字抽自然语言事实
阶段四 Composer 新增 Composer prompt/调用,由 ChatService 过滤输入 最终答案只使用 Verifier 允许的材料
阶段五 回归与审计 扩测试和 eval fixtures 证明幻觉拦截、生效路径、审计回溯都可验证

更详细的实施拆解见 21. 实施阶段。


0.5 非目标

本 issue 第一版明确不做以下事情:

  • 不改 Planner 的输入输出。
  • 不引入 Controller 或新的编排层。
  • 不改变现有 retry 机制。
  • 不要求 Gatekeeper 失败后自动回退 Executor 重试。
  • 不新增数据库表。
  • 不让 Gatekeeper 做根因判断。
  • 不让 Composer 调用工具或重新诊断。

0.6 关键设计决策

决策 结论 原因
是否改 Planner 不改 当前问题主要在 Executor 输出和 Verifier 校验边界
Gatekeeper 放在哪里 放在 VerifierInputHook 保持当前 workflow,不改 Executor hook 和编排
Gatekeeper 失败是否重试 第一版不重试 先建立拦截和审计闭环,避免扩大改动面
Executor 是否继续输出最终答案 不输出 防止未经 Verifier 的自然语言结论泄露
Verifier 是否逐字扫描答案 不扫描 主校验对象改为 claims
Composer 是否可以新增事实 不可以 Composer 只是表达层,不是诊断层
facts_checked 是否保留 兼容期保留 当前低置信模板、retry_context、评测可能依赖

0.7 实现约束

实现时必须遵守:

  • 优先保持现有三 Agent 复杂链路可运行。
  • 每个阶段都应能单独测试和回滚。
  • 第一版以“降低幻觉风险”为目标,不追求一次性重构所有历史字段。
  • 所有最终用户可见答案都必须来自 Verifier 允许输出的材料。
  • 所有 Gatekeeper 校验结果都必须进入审计,至少能回溯到 self_evaluation.verifier_evaluation.gatekeeper_result。
  • 如果结构化输出 malformed,不允许回退到自然语言逐字抽取后给 PASS。

0.8 推荐实现切片

建议不要把所有改动塞进一个大 PR。推荐拆成以下可独立验收的切片:

切片 内容 可单独合入条件
PR-1 Executor V2 prompt + parse-only 边界调整 Executor 能输出 V2 JSON;不会再通过 Executor 直接生成最终用户答案
PR-2 Gatekeeper 基础框架 + schema/invocation 规则 Verifier payload 和审计中出现 gatekeeper_result;伪造 invocation id 可被拦截
PR-3 Verifier V2 claim_checks + facts_checked 兼容 Verifier 主校验 claims;现有低置信模板和 retry_context 不坏
PR-4 Composer 接入 + 最终答案渲染 PASS/LOW_CONFID/REJECT 最终答案都不再读取 Executor user_facing_answer
PR-5 eval fixtures + 回归测试补齐 覆盖伪造 ID、工具名不匹配、excerpt 张冠李戴、hypothesis 写成事实

每个切片都应保留当前复杂 Chat 链路可运行。若某个切片失败,优先回滚该切片,不要连带回滚已经稳定的前置切片。


1. 设计目标

当前 executor_evidence_v1 同时包含结构化诊断材料和自然语言表达字段:

  • diagnosis_summary
  • user_facing_answer

这两个字段容易让 Executor 提前进入“总结报告 / 用户表达”模式,并可能把未证实内容写成确认结论。

V2 的目标是让 Executor 只输出结构化诊断材料,不负责最终用户表达。


2. 输出结构

{
  "answer_version": "executor_evidence_v2",
  "claims": [
    {
      "claim_id": "claim-1",
      "claim_type": "symptom",
      "claim_text": "payment-service 出现请求超时日志。",
      "support_level": "direct",
      "evidence_bindings": [
        {
          "source_type": "tool_trace",
          "source_id": "trace-1",
          "tool_name": "query_logs",
          "source_invocation_ids": [394],
          "evidence_excerpt": "request timeout"
        }
      ]
    }
  ],
  "hypotheses": [
    {
      "hypothesis_text": "连接池压力可能参与了超时问题。",
      "basis": "当前已有超时现象,但缺少连接池 active/idle/pending 指标。",
      "needed_evidence": ["HikariCP active/idle/pending 指标"]
    }
  ],
  "recommended_actions": [
    {
      "action_text": "补充查询连接池 active/idle/pending 指标。",
      "reason": "用于确认连接池是否达到上限。",
      "evidence_bindings": []
    }
  ],
  "missing_info": [
    "缺少连接池指标,无法确认连接池耗尽是根因。"
  ]
}

3. 字段定义

字段 类型 必填 定义
answer_version string 是 固定为 executor_evidence_v2
claims array 是 已确认或有明确支撑的事实断言
hypotheses array 否 合理怀疑但未被当前证据确认的方向
recommended_actions array 否 建议补证据、排查或处理动作
missing_info array 否 当前无法确认结论所缺少的证据

4. claims

{
  "claim_id": "claim-1",
  "claim_type": "symptom",
  "claim_text": "payment-service 出现请求超时日志。",
  "support_level": "direct",
  "evidence_bindings": []
}
字段 类型 必填 定义
claim_id string 是 claim 唯一标识
claim_type string 是 claim 类型,例如 symptom / root_cause / impact / risk
claim_text string 是 已确认或有限确认的事实断言
support_level string 是 direct / indirect
evidence_bindings array 是 支撑该 claim 的证据绑定,不能为空

5. evidence_bindings

{
  "source_type": "tool_trace",
  "source_id": "trace-1",
  "tool_name": "query_logs",
  "source_invocation_ids": [394],
  "evidence_excerpt": "request timeout"
}
字段 类型 必填 定义
source_type string 是 证据来源类型,例如 tool_trace
source_id string 否 evidence block id、trace_ref 或可定位标识;第一版不作为硬校验依据
tool_name string 是 来源工具名
source_invocation_ids array 是 来源 tool_invocation.id
evidence_excerpt string 是 从工具返回中摘取的原话、指标值、日志片段或关键数据

6. hypotheses

{
  "hypothesis_text": "连接池压力可能参与了超时问题。",
  "basis": "当前已有超时现象,但缺少连接池 active/idle/pending 指标。",
  "needed_evidence": ["HikariCP active/idle/pending 指标"]
}
字段 类型 必填 定义
hypothesis_text string 是 未证实但值得排查的方向
basis string 是 它基于哪些已知证据,以及为什么仍只是推测
needed_evidence array 是 要确认该假设还缺少的证据
{
  "action_text": "补充查询连接池 active/idle/pending 指标。",
  "reason": "用于确认连接池是否达到上限。",
  "evidence_bindings": []
}
字段 类型 必填 定义
action_text string 是 建议动作
reason string 是 建议原因
evidence_bindings array 否 建议动作关联的证据绑定,可为空

8. 移除字段

V2 移除以下字段:

字段 移除原因
diagnosis_summary 容易让 Executor 提前总结诊断故事
user_facing_answer 容易夹带 claims 之外的确认式事实

最终用户答案应由 ChatService 或后续专门渲染阶段基于结构化字段生成。


9. Gatekeeper 设计

Executor 输出后、Verifier 接收前,增加一层确定性校验:

Executor raw output
  -> parse JSON
  -> Gatekeeper
  -> Verifier payload

Gatekeeper 的目标是拦截物理级幻觉,而不是替代 Verifier 做语义判断。

9.1 职责边界

组件 职责
Gatekeeper schema、引用 ID、工具名、excerpt、黑名单措辞等确定性校验
Verifier 判断 claim 是否被证据语义支撑、是否说重、是否缺关键证据

Gatekeeper 不判断根因是否正确,也不做新的检索。

9.2 接入位置

V1 接入位置保持在 VerifierInputHook 内,不改 Executor hook,不改 Chat workflow 编排:

parseExecutorOutput(...)
  -> buildVerifierTraceSummary(...)
  -> Gatekeeper.validate(...)
  -> verifierInput.put("gatekeeper_result", ...)

VerifierInputHook 的职责收敛为:

  • 解析 Executor raw output。
  • 构造 executor_output_parse_status。
  • 构造 tool_trace_summary。
  • 调用 Gatekeeper。
  • 组装 Verifier payload。

除 JSON parse 与最小可解析性判断外,VerifierInputHook 不再维护独立校验规则。

后续持久化时,将 gatekeeper_result 写入:

diagnosis_session.self_evaluation.verifier_evaluation.gatekeeper_result

10. Gatekeeper 规则加载

Gatekeeper 采用“规则代码稳定、规则配置可调”的设计。

Rule Index
  -> Rule Metadata
  -> Rule Implementation

10.1 索引层

索引层列出所有可用规则名和一句话描述,用于加载、展示和审计。

rules:
  - id: schema.executor_v2
    name: Executor V2 Schema
    description: 校验 Executor 输出是否符合 V2 schema
    enabled: true

  - id: evidence.invocation_ref
    name: Invocation Reference Check
    description: 校验 source_invocation_ids 是否属于当前 session 且工具名匹配
    enabled: true

  - id: evidence.excerpt_similarity
    name: Excerpt Similarity Check
    description: 校验 evidence_excerpt 与真实工具输出是否相似
    enabled: true

  - id: claim.hallucination_phrases
    name: Hallucination Phrase Check
    description: 禁止 confirmed claims 使用经验化、推测化措辞
    enabled: true

  - id: claim.evidence_utilization
    name: Evidence Utilization Check
    description: 检查 claim_text 与 evidence_excerpt 的关键词覆盖率
    enabled: false

10.2 元数据层

元数据层定义规则参数、阈值、严重级别和适用字段。调整阈值或黑名单时只改元数据,不改代码。

ruleMetadata:
  schema.executor_v2:
    severity: error
    verdictImpact: low_confid_on_fail
    params:
      requiredFields:
        - answer_version
        - claims
      deprecatedFields:
        - diagnosis_summary
        - user_facing_answer

  evidence.excerpt_similarity:
    severity: error
    verdictImpact: low_confid_on_fail
    params:
      passThreshold: 0.5
      warnThreshold: 0.3
      compareAgainst:
        - output_preview
        - retrieval_details
        - tool_trace_summary

  claim.hallucination_phrases:
    severity: error
    verdictImpact: low_confid_on_fail
    params:
      targetFields:
        - claims[].claim_text
      blacklist:
        - 通常情况下
        - 根据经验
        - 一般来说
        - 我认为
        - 理论上
        - 可能是
        - 推测
      allowInFields:
        - hypotheses[].hypothesis_text
        - hypotheses[].basis

  claim.evidence_utilization:
    severity: warning
    verdictImpact: warn_only
    params:
      minKeywordCoverage: 0.5

  evidence.invocation_ref:
    severity: error
    verdictImpact: reject_on_fail

10.3 规则实现层

规则实现使用代码中的固定接口。新增全新类型规则需要代码;调整阈值、词表、启用状态不需要改代码。

GatekeeperRule
  id()
  validate(context, metadata)
  -> RuleResult

10.4 与 VerifierInputHook 原有校验的关系

V2 中,VerifierInputHook 原有的结构判断只保留 parse-only 能力:

raw text
  -> sanitized JSON
  -> JsonNode / Map
  -> parse status

以下校验统一迁移到 Gatekeeper:

  • schema 字段是否完整。
  • answer_version 是否正确。
  • claims 是否为空或类型错误。
  • claims[].evidence_bindings 是否为空。
  • source_invocation_ids 是否存在。
  • tool_name 是否匹配。
  • evidence_excerpt 是否可信。
  • 是否出现已移除字段 diagnosis_summary / user_facing_answer。

这样避免 VerifierInputHook 和 Gatekeeper 出现两套规则、两套错误口径。


11. 推荐规则集

11.1 Schema 校验

规则 id:

schema.executor_v2

校验内容:

  • 输出必须是 JSON object。
  • answer_version 必须为 executor_evidence_v2。
  • claims 必须存在且为 array。
  • hypotheses、recommended_actions、missing_info 缺省时按空数组处理。
  • 不允许出现 diagnosis_summary。
  • 不允许出现 user_facing_answer。

Gatekeeper 输出给 Verifier 前应 normalize 结构:

missing hypotheses -> []
missing recommended_actions -> []
missing missing_info -> []

也就是说,Verifier 和 Composer 可以假定这三个字段存在且为数组。

11.2 Invocation 引用校验

规则 id:

evidence.invocation_ref

校验内容:

  • claims[].evidence_bindings 不能为空。
  • source_invocation_ids 必须为非空数组。
  • 每个 invocation id 必须属于当前 session。
  • tool_name 必须和对应 tool_invocation.tool_name 匹配。
  • 不允许引用其它 session 的工具调用。

该规则只检查 claims[].evidence_bindings。recommended_actions[].evidence_bindings 可以为空,不参与硬失败判定。

11.3 Excerpt 相似度校验

规则 id:

evidence.excerpt_similarity

校验内容:

  • 将 evidence_excerpt 与真实工具输出进行相似度比对。
  • 可比较来源包括:
    • tool_invocation.output_preview
    • tool_invocation.retrieval_details
    • tool_trace_summary.output_summary

建议阈值:

相似度 结果
>= 0.5 pass
0.3 - 0.5 warn
< 0.3 fail

如果只是 excerpt 相似度低,第一版判为 LOW_CONFID 级风险,不直接 REJECT,因为 output_preview 可能被截断,tool_trace_summary 也可能是摘要。

只有以下情况才进入 REJECT 级别:

  • invocation id 不存在。
  • invocation id 不属于当前 session。
  • tool_name 与 invocation 的真实工具名不匹配。
  • invocation 存在但 excerpt 明显指向另一个服务、错误码或指标值。

11.4 幻觉措辞校验

规则 id:

claim.hallucination_phrases

校验内容:

  • claims[].claim_text 不允许出现经验化、推测化措辞。
  • hypotheses 中允许出现推测措辞。

默认黑名单:

[
  "通常情况下",
  "根据经验",
  "一般来说",
  "可能是",
  "推测",
  "我认为",
  "理论上"
]

11.5 证据利用率校验

规则 id:

claim.evidence_utilization

校验内容:

  • 提取 claim_text 中的实词。
  • 提取 evidence_excerpt 中的实词。
  • 计算关键词覆盖率。

伪代码:

def check_evidence_utilization(claim_text, excerpt):
    claim_keywords = extract_keywords(claim_text)
    excerpt_keywords = extract_keywords(excerpt)
    overlap = claim_keywords & excerpt_keywords
    utilization = len(overlap) / len(claim_keywords)
    return utilization >= 0.5

第一版建议作为 warning,不作为硬拒绝条件。


12. Gatekeeper 输出

Gatekeeper 第一版只保留必要审计字段。

{
  "gatekeeper_result": {
    "status": "fail",
    "failed_rules": ["evidence.invocation_ref"],
    "warnings": ["evidence.excerpt_similarity"],
    "errors": [
      {
        "rule_id": "evidence.invocation_ref",
        "target": "claims[0].evidence_bindings[0]",
        "message": "source_invocation_ids not found in current session"
      }
    ]
  }
}

12.1 字段定义

字段 类型 定义
status string pass / warn / fail
failed_rules array 失败规则 id 列表
warnings array warning 规则 id 列表
errors array 最小错误明细
errors[].rule_id string 失败规则 id
errors[].target string 出问题的字段路径
errors[].message string 人类可读原因

12.2 总状态计算

任一规则 fail -> gatekeeper status = fail
否则任一规则 warn -> gatekeeper status = warn
否则 gatekeeper status = pass

第一版不记录 version、rule_set、summary、severity、details、checked_at 等字段,避免审计结构过重。

Verifier 如需判断 Gatekeeper fail 是否应导致 REJECT,使用规则元数据中的 verdictImpact,不依赖落库字段。


13. 审计落点

Gatekeeper 结果需要进入两处:

13.1 Verifier payload

{
  "executor_structured_output": {},
  "executor_output_parse_status": {},
  "tool_trace_summary": [],
  "gatekeeper_result": {}
}

Verifier 可根据 gatekeeper_result 调整判定,尤其是:

  • gatekeeper_result.status=fail 时,不应输出 PASS。
  • schema 或 invocation 引用失败时,应倾向 LOW_CONFID 或 REJECT。

13.1.1 parse status 与 schema status 边界

executor_output_parse_status 只表示 JSON 解析结果:

parse status 含义
valid raw output 可解析为 JSON object
missing raw output 为空或不是 JSON
malformed raw output 像 JSON 但解析失败

schema 合法性不再由 parse status 表达,统一交给 Gatekeeper:

JSON parse valid but schema invalid
  -> executor_output_parse_status.status = valid
  -> gatekeeper_result.status = fail
  -> failed_rules contains schema.executor_v2

13.2 self_evaluation

持久化位置:

diagnosis_session.self_evaluation.verifier_evaluation.gatekeeper_result

审计链路:

executor_raw_output
  -> executor_output_parse_status
  -> gatekeeper_result
  -> verifier_evaluation
  -> final_answer

14. Verifier 输入结构

V2 中 Verifier 以结构化输出为主输入,不再逐字抽取自然语言事实。

{
  "original_query": "用户原始问题",
  "executor_raw_output": "{raw executor output, debug/fallback only}",
  "executor_structured_output": {
    "answer_version": "executor_evidence_v2",
    "claims": [],
    "hypotheses": [],
    "recommended_actions": [],
    "missing_info": []
  },
  "executor_output_parse_status": {
    "status": "valid",
    "detail": "parsed executor evidence contract"
  },
  "tool_trace_summary": [],
  "gatekeeper_result": {
    "status": "pass",
    "failed_rules": [],
    "warnings": [],
    "errors": []
  },
  "retry_context": null
}
字段 用途
original_query 判断结构化诊断是否围绕用户问题
executor_raw_output 原始输出,仅用于 debug/fallback,不作为主校验来源
executor_structured_output Verifier 主校验对象
executor_output_parse_status 判断结构化输出是否可用
tool_trace_summary 证据索引
gatekeeper_result Gatekeeper 物理级校验结果
retry_context 第二轮时判断缺口是否被补足

兼容期可以保留旧字段名:

executor_final_answer

第一期 payload 可以同时包含 executor_raw_output 和 executor_final_answer,二者内容相同。executor_final_answer 语义上视为 deprecated;Verifier 不应在结构化输出合法时从该字段抽取额外事实。


15. Verifier 字段使用规则

15.1 executor_structured_output

Verifier 主要校验:

  • claims
  • hypotheses
  • recommended_actions
  • missing_info

重点是 claims:

claim_text 是否能由 evidence_bindings 指向的证据合理推出?
support_level 是否说重?
是否引入证据外的新实体、新指标、新错误码或新根因?

15.2 tool_trace_summary

tool_trace_summary 用于判断 evidence binding 是否有语义支撑。

Verifier 不要求 claim 与证据逐字一致,而是判断可推导性:

证据:payment-service CPU 92%,线程数 245
claim:payment-service 当前存在 CPU 使用率过高现象
=> direct_observation

claim:CPU 过高可能导致支付接口超时
=> reasonable_inference

claim:CPU 过高是支付超时的唯一根因
=> overstated

15.3 gatekeeper_result

Gatekeeper 负责物理合法性,Verifier 消费结果:

status = pass
  -> 正常校验 claims

status = warn
  -> 正常校验 claims,但 rationale 可提及 warning

status = fail
  -> 不允许 PASS
  -> 相关 claim 至少应判 unsupported / external_unknown / contradicted

15.4 executor_output_parse_status

status = valid
  -> 使用结构化可推导性校验

status = missing / malformed
  -> 不再回退到自然语言逐字抽取
  -> verdict = LOW_CONFID
  -> groundedness_score = 0

15.5 executor_raw_output

executor_raw_output 只用于审计和 debug。

当 executor_structured_output 合法时,Verifier 不应从 executor_raw_output 中抽取额外事实。


16. Verifier 输出结构

V2 Verifier 输出从 facts_checked 转向 claim_checks。

{
  "verdict": "LOW_CONFID",
  "groundedness_score": 0.62,
  "claim_checks": [
    {
      "claim_id": "claim-1",
      "verification": "direct_observation",
      "detail": "query_metrics 显示 CPU 使用率为 92%,可直接支撑 CPU 过高现象。",
      "evidence_refs": [
        {
          "trace_ref": "trace-1",
          "tool_name": "query_metrics",
          "source_invocation_ids": [394],
          "note": "指标摘要包含 CPU=92%"
        }
      ]
    }
  ],
  "hypothesis_checks": [
    {
      "hypothesis_index": 0,
      "verification": "reasonable_hypothesis",
      "detail": "该假设明确标注为未证实,并列出需要补充的证据。"
    }
  ],
  "rationale": "已有证据支持超时现象,但根因仍缺少直接证据。"
}

兼容期建议同时保留 facts_checked:

  • claim_checks 作为 V2 主字段。
  • facts_checked 由 claim_checks 映射生成,供现有 Trace Workbench、eval 和降级输出继续使用。
  • 待前端和评测全部迁移后,再移除 facts_checked。

16.1 字段定义

字段 类型 定义
verdict string PASS / LOW_CONFID / REJECT
groundedness_score number 结构化 claim 的证据支撑评分
claim_checks array 对 claims 的可推导性校验结果
claim_checks[].claim_id string 被校验的 claim id
claim_checks[].verification string 可推导性判定
claim_checks[].detail string 判定说明
claim_checks[].evidence_refs array 使用的证据引用
hypothesis_checks array 对 hypotheses 的边界校验
hypothesis_checks[].hypothesis_index number hypothesis 数组下标
hypothesis_checks[].verification string reasonable_hypothesis / unsupported_hypothesis / overstated_as_fact
hypothesis_checks[].detail string 判定说明
rationale string 总体判定理由

16.1.1 facts_checked 兼容映射

兼容期内,ChatService 需要从 claim_checks 生成旧字段 facts_checked。

映射规则:

claim_checks[].verification facts_checked[].verification
direct_observation direct_evidence
reasonable_inference indirect_support
overstated indirect_support
unsupported no_evidence
external_unknown no_evidence
contradicted contradicted

facts_checked[].fact 建议格式:

{claim_id}: {claim_text}

facts_checked[].is_critical 规则:

claim_type in ["root_cause", "symptom", "impact", "risk"] -> true
其它 -> false

facts_checked[].evidence_refs 直接复用 claim_checks[].evidence_refs。

16.2 claim verification 枚举

verification 含义
direct_observation 证据直接观测到该事实
reasonable_inference 证据没有逐字说明,但可以合理推出
overstated 有部分依据,但 claim 说得太满
unsupported 证据不足
external_unknown 引入证据外的新服务、数值、错误码、根因等
contradicted 与证据冲突

external_unknown 需要区分严重程度:

场景 建议 verdict
引入证据外的核心服务名、订单号、错误码、关键指标值、根因 REJECT
引入非核心背景实体或表达不清 LOW_CONFID

17. Verifier 判定矩阵

PASS

必须同时满足:

  • gatekeeper_result.status != fail
  • 所有核心 claims 均为 direct_observation 或 reasonable_inference
  • 至少一个关键 claim 为 direct_observation
  • 不存在 overstated
  • 不存在 unsupported
  • 不存在 external_unknown
  • 不存在 contradicted

LOW_CONFID

满足任一条件:

  • 存在 unsupported
  • 存在 external_unknown
  • 存在 overstated
  • 所有核心 claims 都只是 reasonable_inference
  • executor_output_parse_status.status 为 missing 或 malformed
  • gatekeeper_result.status = fail,但失败不属于严重伪造

REJECT

满足任一条件:

  • 任一核心 claim 为 contradicted
  • Gatekeeper 发现严重伪造:
    • 编造 source_invocation_ids
    • 跨 session 引用
    • tool_name 与 invocation 不匹配
    • 使用真实 id 但 excerpt 明显张冠李戴
  • Verifier 发现核心 external_unknown:
    • 新增证据外服务名
    • 新增证据外订单号
    • 新增证据外错误码
    • 新增证据外关键指标值
    • 新增证据外根因

严重伪造由 Gatekeeper 规则元数据中的 verdictImpact=reject_on_fail 定义。


18. 与 V1 Verifier 的差异

项目 V1 V2
主校验对象 executor_final_answer 和 structured output executor_structured_output
校验方式 从自然语言中抽取 facts 并逐条校验 对 claims 做可推导性校验
原始文本作用 事实抽取来源之一 debug/fallback only
输出字段 facts_checked claim_checks
Gatekeeper 无 前置物理级校验
malformed 输出 可回退自然语言校验 直接 LOW_CONFID

19. Composer 设计

Composer 是最终表达层。它不负责诊断,不调用工具,不补充新事实。

Executor structured output
  -> Gatekeeper
  -> Verifier
  -> Composer
  -> final answer

19.1 职责边界

组件 职责
Executor 输出结构化诊断材料
Gatekeeper 做物理级确定性校验
Verifier 判断 claims 是否可由证据合理推出
Composer 将 Verifier 允许输出的材料组织成用户可读中文答案

Composer 禁止:

  • 调用工具。
  • 重新诊断。
  • 重新判断根因。
  • 新增服务名、订单号、时间、指标值、错误码、根因。
  • 把 hypothesis 写成 confirmed claim。
  • 把相关性写成因果。

19.2 Composer 输入

Composer 输入应由 ChatService 根据 Executor、Gatekeeper、Verifier 的结果过滤得到。

{
  "original_query": "用户原始问题",
  "verdict": "LOW_CONFID",
  "allowed_claims": [
    {
      "claim_id": "claim-1",
      "claim_type": "symptom",
      "claim_text": "订单123支付失败期间出现 ERR_TIMEOUT,请求耗时 5.3 秒。"
    }
  ],
  "allowed_hypotheses": [
    {
      "hypothesis_text": "网关超时阈值可能偏低。",
      "needed_evidence": ["网关超时阈值配置"]
    }
  ],
  "missing_info": [
    "缺少网关侧具体配置参数,无法确认阈值是否过低。"
  ],
  "recommended_actions": [
    {
      "action_text": "检查网关侧超时阈值配置",
      "reason": "当前缺少网关配置参数,需确认阈值是否低于实际请求耗时。"
    }
  ],
  "rationale": "已有证据支持请求超时现象,但根因仍缺少直接证据。"
}
字段 类型 定义
original_query string 用户原始问题
verdict string Verifier verdict
allowed_claims array Verifier 允许作为确认事实输出的 claims
allowed_hypotheses array Verifier 允许作为合理推测输出的 hypotheses
missing_info array 证据缺口
recommended_actions array 允许输出的建议动作
rationale string Verifier 总体判定理由

Composer 不应接收 raw tool output,也不应接收未经筛选的完整 Executor 输出。

19.2.1 Composer 输入组装规则

ChatService 根据 Verifier 输出组装 Composer 输入:

Verifier 结果 Composer 输入
claim_checks[].verification = direct_observation 放入 allowed_claims
claim_checks[].verification = reasonable_inference 可放入 allowed_claims,但表达时不得写成唯一根因
claim_checks[].verification = overstated 不放入 allowed_claims,可降级为 allowed_hypotheses 或 missing_info
claim_checks[].verification = unsupported 不输出为事实,放入 missing_info
claim_checks[].verification = external_unknown 不输出,必要时放入 missing_info
claim_checks[].verification = contradicted 不输出,触发 REJECT 降级表达

allowed_hypotheses 只允许来自:

  • 原始 hypotheses。
  • hypothesis_checks 判为 reasonable_hypothesis 的条目。
  • 被 Verifier 判为 overstated 后降级的 claim。

Composer 执行条件:

Verifier 输出有效 verdict 后才执行 Composer。
executor_output_parse_status = missing/malformed 时,可跳过 Composer,直接使用固定低置信模板。
gatekeeper_result.status = fail 且 verdict = REJECT 时,Composer 只能接收 allowed_claims、missing_info、recommended_actions,不接收 allowed_hypotheses。

REJECT 场景下:

  • allowed_hypotheses 必须为空。
  • user_facing_answer 不得出现根因结论。
  • 推荐动作只能是补证据或人工复核类动作。

19.3 Composer 输出

Composer 输出严格 JSON。

{
  "answer_summary": "当前已确认订单123支付失败期间出现 ERR_TIMEOUT,请求耗时 5.3 秒;网关阈值是否过低尚未确认。",
  "recommended_actions": [
    {
      "action_text": "检查网关侧超时阈值配置",
      "reason": "当前缺少网关配置参数,需确认阈值是否低于实际请求耗时。"
    }
  ],
  "user_facing_answer": "您的订单123在支付失败期间出现了请求超时,记录显示 ERR_TIMEOUT,耗时约 5.3 秒。目前还不能确认网关阈值配置就是根因,因为缺少网关侧具体配置参数。建议下一步检查网关超时阈值,并与该请求耗时进行比对。"
}
字段 类型 定义
answer_summary string 一句话摘要,只能总结 Verifier 允许输出的内容
recommended_actions array 面向用户的建议动作
recommended_actions[].action_text string 建议动作
recommended_actions[].reason string 建议原因
user_facing_answer string 最终面向用户的中文答案

19.4 Verdict 表达规则

PASS

  • 可以表达确认结论。
  • 只能使用 allowed_claims 和 recommended_actions。
  • 只有当 allowed_claims 中存在 root cause 类型 claim 时,才能使用“根因已确认”类表述。

LOW_CONFID

  • 必须说明当前证据仍有缺口。
  • 必须区分“已确认信息”和“可能方向”。
  • 不得把 allowed_hypotheses 写成确认结论。
  • 必须包含至少一个证据缺口或下一步建议。

REJECT

  • 必须说明当前无法基于已获取证据生成可靠结论。
  • 不得输出根因结论。
  • 只输出已确认信息和下一步建议。

19.5 Composer Prompt 草案

你是 Answer Composer。你的职责是把 Verifier 允许输出的结构化材料,组织成用户可读的中文答案。

边界:
- 你不负责诊断。
- 你不调用工具。
- 你不补充新事实。
- 你不重新判断根因。
- 你只能使用输入中的 allowed_claims、allowed_hypotheses、missing_info、recommended_actions、rationale。

输入字段:
- original_query:用户原始问题
- verdict:PASS / LOW_CONFID / REJECT
- allowed_claims:允许作为确认事实输出的结论
- allowed_hypotheses:允许作为合理推测输出的内容
- missing_info:证据缺口
- recommended_actions:建议动作
- rationale:Verifier 判定理由

表达规则:
1. 如果 verdict=PASS:
   - 可以表达确认结论。
   - 只能使用 allowed_claims 和 recommended_actions。
2. 如果 verdict=LOW_CONFID:
   - 必须说明当前证据仍有缺口。
   - 必须区分“已确认”和“可能方向”。
   - 不得把 allowed_hypotheses 写成确认结论。
3. 如果 verdict=REJECT:
   - 必须说明当前无法基于已获取证据生成可靠结论。
   - 不得输出根因结论。
   - 只输出已确认信息和下一步建议。

禁止:
- 禁止新增输入中不存在的服务名、订单号、时间、指标值、错误码、根因。
- 禁止把相关性写成因果。
- 禁止把假设写成事实。
- 禁止输出 Markdown。
- 禁止输出 JSON 之外的任何文字。

输出格式:
{
  "answer_summary": "...",
  "recommended_actions": [
    {
      "action_text": "...",
      "reason": "..."
    }
  ],
  "user_facing_answer": "..."
}

20. 当前代码影响面

本 issue 按当前三 Agent 实现增量落地,不改 Planner,不引入 Controller。

模块 当前职责 本次改动
chat-planner-prompt.md 选择 skill、拆解计划 不改
chat-executor-prompt.md 执行工具并输出 executor_evidence_v1 改为输出 executor_evidence_v2,移除最终表达字段
VerifierInputHook 解析 Executor 输出、构造 Verifier payload 收敛为 parse + trace summary + Gatekeeper + payload
ToolTraceSummaryService 从 tool_invocation 汇总证据索引 原则上不改;只有 Gatekeeper 缺少比对字段时才补最小字段
chat-verifier-prompt.md 校验 executor_final_answer 与证据 改为校验 executor_structured_output.claims 的可推导性
ChatService.parseVerifierDecision(...) 解析 facts_checked 增加 claim_checks 解析和 facts_checked 兼容生成
ChatService.persistVerifierEvaluation(...) 写入 verifier 审计结果 增加 gatekeeper_result、claim_checks、Composer 结果
ChatService 最终答案渲染 PASS 使用 user_facing_answer,LOW_CONFID/REJECT 用模板 改为由 Composer 或固定降级模板生成最终答案

第一版落地原则:

  • Planner 不改。
  • Gatekeeper 仍放在 Verifier 的 hook,即 VerifierInputHook。
  • VerifierInputHook 原有结构校验迁移到 Gatekeeper,hook 自身只保留 JSON parse。
  • 兼容期保留 executor_final_answer,但只作为 raw debug 字段。
  • 兼容期保留 facts_checked,但由 claim_checks 映射生成。

21. 实施阶段

阶段一:Executor V2 输出契约

目标:先让 Executor 不再输出最终诊断话术,只输出结构化诊断材料。

改动范围:

  • 更新 chat-executor-prompt.md。
  • answer_version 从 executor_evidence_v1 改为 executor_evidence_v2。
  • 移除 diagnosis_summary 和 user_facing_answer。
  • 保留 claims、hypotheses、recommended_actions、missing_info 的整体形状。

验收标准:

  • Executor 示例输出可被 JSON 解析。
  • 输出中不再出现 diagnosis_summary、user_facing_answer。
  • claims[].evidence_bindings 仍要求非空。
  • 现有流程即使尚未接入 Composer,也不会把 Executor raw JSON 直接当最终答案泄露给用户。

阶段二:Gatekeeper 接入 VerifierInputHook

目标:在 Verifier 之前用确定性规则拦截物理级幻觉。

改动范围:

  • 新增 Gatekeeper 规则接口和校验服务。
  • 新增规则索引与元数据配置。
  • 在 VerifierInputHook 中调用 Gatekeeper。
  • 将 gatekeeper_result 写入 Verifier payload。
  • 将 gatekeeper_result 持久化到 self_evaluation.verifier_evaluation。

验收标准:

  • JSON parse 成功但 schema 不合法时,executor_output_parse_status.status=valid,gatekeeper_result.status=fail。
  • 编造不存在的 source_invocation_ids 时,failed_rules 包含 evidence.invocation_ref。
  • tool_name 与真实 invocation 不匹配时,Gatekeeper fail。
  • 缺省 hypotheses、recommended_actions、missing_info 时,传给 Verifier 前会 normalize 为 []。
  • 旧的 VerifierInputHook 结构校验不再和 Gatekeeper 重复维护。

阶段三:Verifier V2 可推导性校验

目标:Verifier 不再逐字扫描自然语言,而是校验 claim 是否能由证据合理推出。

改动范围:

  • 更新 chat-verifier-prompt.md。
  • Verifier 主输入改为 executor_structured_output。
  • 输出新增 claim_checks。
  • 兼容期继续输出或由代码生成 facts_checked。
  • parseVerifierDecision(...) 能处理 claim_checks 和旧 facts_checked。

验收标准:

  • direct_observation、reasonable_inference、overstated、unsupported、external_unknown、contradicted 均有测试覆盖。
  • gatekeeper_result.status=fail 时 Verifier 不允许输出 PASS。
  • malformed/missing Executor 输出不回退自然语言抽事实,直接进入 LOW_CONFID。
  • facts_checked 兼容字段能继续支撑现有低置信模板、retry_context 和评测用例。

阶段四:Composer 输出最终答案

目标:把最终用户表达从 Executor 中移出,由 Composer 基于 Verifier 允许的材料生成。

改动范围:

  • 新增 chat-composer-prompt.md 或等价 Composer 调用。
  • ChatService 在 Verifier 之后组装 Composer 输入。
  • Composer 只接收 allowed_claims、allowed_hypotheses、missing_info、recommended_actions、rationale。
  • PASS/LOW_CONFID/REJECT 均不再读取 Executor 的 user_facing_answer。

验收标准:

  • Composer 输出严格 JSON,包含 answer_summary、recommended_actions、user_facing_answer。
  • Composer 不接收 raw tool output。
  • REJECT 时 allowed_hypotheses=[],最终答案不出现根因结论。
  • LOW_CONFID 时必须区分已确认信息和可能方向。
  • PASS 时只有存在 root cause 类型 allowed claim,才允许表达“根因已确认”。

阶段五:回归评测与审计闭环

目标:确认新链路真的降低证据归因幻觉,而不是只改变字段名。

改动范围:

  • 扩展 VerifierInputHookTest。
  • 扩展 ChatServiceSequentialAgentTest。
  • 增加诊断 eval fixtures,覆盖伪造 ID、张冠李戴、过度推断、缺证据降级。
  • 检查 diagnosis_session.self_evaluation 中的审计字段。

验收标准:

  • 伪造 invocation id 必须进入 REJECT 或至少不可 PASS。
  • excerpt 相似度不足但 invocation 合法时,默认进入 LOW_CONFID,不直接误杀为严重伪造。
  • Executor 把 hypothesis 写进 claim 时,Verifier 至少判 overstated 或 unsupported。
  • 最终答案中不再出现未通过 Verifier 的 claim。
  • 审计链路能从 final answer 回溯到 Composer 输入、Verifier 判定、Gatekeeper 结果、tool invocation。

22. 兼容与回滚策略

22.1 兼容字段

第一版保留以下兼容字段,降低一次性改动风险:

字段 保留原因 后续处理
executor_final_answer 当前 Verifier payload、fallback、日志中仍使用该名称 作为 deprecated raw 字段保留一版
facts_checked 当前低置信模板、retry_context、评测可能依赖 从 claim_checks 映射生成
traceability_version 当前审计结构已有字段 V2 可改为 v2,但不作为功能判断依据

22.2 回滚开关

建议保留最小运行时开关:

structuredOutputV2.enabled
gatekeeper.enabled
composer.enabled

回滚策略:

  • 仅 Executor V2 出问题:关闭 structuredOutputV2.enabled,回到 V1 prompt。
  • Gatekeeper 误杀:关闭 gatekeeper.enabled,Verifier 仍可按 V2 claim 校验运行。
  • Composer 输出异常:关闭 composer.enabled,回到固定 LOW_CONFID/REJECT 模板;PASS 暂不直接使用 Executor 输出。

即使回滚 Composer,也不能恢复使用 Executor 的 user_facing_answer,否则会重新引入本 issue 要解决的问题。


23. 数据库与审计最小字段

不新增表,第一版继续写入 diagnosis_session.self_evaluation。

建议结构:

{
  "verifier_evaluation": {
    "verdict": "LOW_CONFID",
    "groundedness_score": 0.62,
    "critical_fact_count": 1,
    "claim_checks": [],
    "facts_checked": [],
    "rationale": "...",
    "round": 1,
    "traceability_version": "v2",
    "executor_output_parse_status": {},
    "executor_structured_output": {},
    "tool_trace_summary": [],
    "gatekeeper_result": {},
    "composer_output": {}
  }
}

字段控制原则:

  • Gatekeeper 只落 status、failed_rules、warnings、errors。
  • 不在数据库中保存规则元数据完整快照。
  • 不新增 checked_at、rule_set_version、details 等重字段。
  • 如果后续需要复盘规则版本,再单独设计审计版本字段。

24. 实施前待确认点

以下问题不阻塞第一阶段,但实施前需要明确默认答案:

问题 建议默认
Composer 是第四个 Agent 还是普通服务调用? 作为 chat_composer Agent,但由 ChatService 在 Verifier 后过滤输入再调用
schema.executor_v2 失败是否 REJECT? 第一版 LOW_CONFID,因为它可能是格式退化,不一定是伪造
evidence.excerpt_similarity 失败是否 REJECT? 默认 LOW_CONFID;只有明显张冠李戴才 REJECT
claim.evidence_utilization 是否启用? 第一版禁用或 warn-only,避免中文分词误杀
是否改 Planner? 不改
是否改现有重试机制? 不改;Gatekeeper 失败第一版不触发自动回退重试

25. Definition of Done

本 issue 完成时,需要同时满足:

  • Executor 不再输出 diagnosis_summary 和 user_facing_answer。
  • Gatekeeper 已接入 VerifierInputHook,并进入 Verifier payload 与 self_evaluation。
  • Verifier 以 claim_checks 为主输出,并保留 facts_checked 兼容。
  • Composer 负责最终 user_facing_answer。
  • PASS 答案不包含未通过 Verifier 的 claim。
  • LOW_CONFID/REJECT 答案不泄露 Executor 原始结论。
  • 关键回归测试覆盖伪造 ID、工具名不匹配、excerpt 张冠李戴、hypothesis 写成事实、schema 退化。