feat: add chat verifier agent

This commit is contained in:
zhuyongxin
2026-07-03 10:54:33 +08:00
parent 4f5316d473
commit 9050487307
28 changed files with 3200 additions and 209 deletions
@@ -0,0 +1,58 @@
# Acceptance: chat-verifier-agent
## Classification
standard
## Task Status
| Task | Status | Notes |
| --- | --- | --- |
| Verifier prompt | Done | Strict JSON schema, verdict matrix, fact classifications, and `evidence_refs` are defined. |
| VerifierInputHook | Done | Explicit verifier payload replaces raw conversation history. |
| ChatService integration | Done | Planner, executor, and verifier are called explicitly with max two rounds. |
| Verdict routing | Done | PASS, LOW_CONFID, and REJECT paths are handled in code. |
| Trace summary | Done | Evidence summaries include `trace_ref` and `source_invocation_ids`. |
| self_evaluation merge | Done | `rule_evaluation` and `verifier_evaluation` are preserved independently. |
| Verifier observability | Done | `verifier_evaluation` persists facts, evidence refs, trace summary, rationale, score, and round. |
## Static Verification
- [x] OpenSpec artifacts exist: `proposal.md`, `design.md`, `specs/chat-verifier-agent/spec.md`, `tasks.md`, `.committed`.
- [x] `change.json` exists and has `metadata.status = committed`.
- [x] `.archive-ready` exists.
- [x] devflow archive-prep files exist: `brief.md`, `evidence.md`, `decisions.md`, `acceptance.md`.
- [x] `devflow/index.md` contains `chat-verifier-agent` with status `archived`.
## Script Verification
- [x] `mvn -q -DskipTests compile` passed.
## Runtime Verification
- [x] POST `/api/chat` with a complex question returned successfully.
- [x] Runtime session `9138f064` showed planner, executor, and verifier execution in logs.
- [x] Runtime session `9138f064` wrote `verifier_evaluation.verdict = LOW_CONFID`.
- [x] Runtime session `9138f064` wrote `facts_checked[*].evidence_refs`.
- [x] Runtime session `9138f064` wrote `tool_trace_summary[*].source_invocation_ids`.
- [x] LOW_CONFID final answer included disclaimer and verifier-derived evidence gaps.
## Unverified
| Scenario | Reason | Risk | Follow-up |
| --- | --- | --- | --- |
| PASS runtime path | The exercised complex runtime case produced LOW_CONFID. | Low; PASS routing is simple pass-through after parsed verifier decision. | Add a fixture or deterministic verifier test if this becomes product-critical. |
| REJECT runtime path | No forced contradiction case was run after traceability changes. | Medium; REJECT is the safety-critical degraded path. | Add a targeted test with a fabricated claim and evidence contradiction. |
| Document-path-level evidence mapping | Current implementation records invocation ids and source document labels, not guaranteed canonical document paths for every retrieval mode. | Low for current audit need; medium for future UI drill-down. | Extend retrieval details with canonical document paths in a later change. |
## Remaining Risks
1. Verifier output still depends on model compliance with JSON schema; code falls back to LOW_CONFID on missing or invalid output.
2. `AgentLoggingHook` is shared by several agent paths; current changes preserve compile and runtime behavior but should be watched in AiOps flows.
3. `SupervisorAgent` construction remains as legacy residue in `ChatService`; runtime orchestration is explicit, but a later cleanup should remove unused supervisor construction.
## Archive State
- [x] OpenSpec change is archive-ready.
- [x] OpenSpec change has been moved to `openspec/changes/archive/2026-07-03-chat-verifier-agent/`.
- [x] Main spec exists at `openspec/specs/chat-verifier-agent/spec.md`.
@@ -0,0 +1,36 @@
# Brief: chat-verifier-agent
## Background
The complex Chat path previously returned Executor answers without a synchronous quality gate. Existing rule scoring was asynchronous and post-hoc, so it could not prevent unsupported answers from reaching users.
## Goals
1. Add a Verifier Agent after Executor in the complex chat path.
2. Require structured verifier output with `PASS`, `LOW_CONFID`, or `REJECT`.
3. Route final user output in code based on verifier verdict.
4. Persist verifier results under `diagnosis_session.self_evaluation.verifier_evaluation`.
5. Preserve rule scoring under `rule_evaluation`.
6. Make verifier decisions traceable to real tool invocations through `evidence_refs` and `source_invocation_ids`.
## Scope
- `ChatService`: explicit `planner -> executor -> verifier` orchestration, max two rounds, verdict routing, retry context, verifier persistence.
- `VerifierInputHook`: explicit verifier input payload.
- `ToolTraceSummaryService`: evidence summary from persisted tool calls.
- `VerifierContextHolder`: round-local verifier context.
- `SelfEvaluationMergeService`: safe JSON merge for evaluation channels.
- `AgentLoggingHook`: concise verifier thought and fuller structured output retention.
- `chat-verifier-prompt.md`: verifier contract, verdict matrix, and traceability schema.
## Non-Goals
- Verifier does not call tools.
- Verifier does not rewrite Executor output.
- Single-agent chat path remains outside this change.
- No database schema migration is included.
- Document-path-level evidence attribution is deferred; current traceability is invocation-level with source document labels.
## Related OpenSpec
`openspec/changes/archive/2026-07-03-chat-verifier-agent/`
@@ -0,0 +1,123 @@
# Decisions: chat-verifier-agent
## 过程日志
### Clarify 阶段
**入口摘要**: 在 Chat 多 Agent 链路中新增 Verifier Agent,作为 Executor 输出后的质量门禁,做事实核查。
**slug**: `chat-verifier-agent`
**规模分档**: standard
### Context 阶段
**devflow/index.md 使用状态**: 已命中。前序 change `executor-action-memory-relevance`(archived)提供了 Chat 多 Agent 当前链路(Supervisor → Planner → Executor)。
**不能违反的历史决策**:
1. Executor 已有完整的行动记忆和归一化质量等级,Verifier 不需要重复验证检索质量
2. Chat Supervisor 的职责是调度,Verifier 作为子 Agent 加入后不改变 Supervisor 的定位
3. 已有 evidence_score 做事后评分,Verifier 是事前门禁,两者不冲突
**需进入 OpenSpec 的上下文点**:
1. Verifier 不需要工具调用,只是一个质量核查 Agent
2. Verifier 需要访问 Executor 的输出 + 工具调用记录
3. Supervisor prompt 需要重写以包含 Verifier 调度规则
4. groundedness_score 的阈值需要在代码中定义
### Grill 阶段 — Question Pool
| # | 维度 | 问题 | 模式 | 状态 |
|---|------|------|------|------|
| Q1 | 术语 | evidence_score(事后评分)与 Verifier(事前门禁)职责是否冲突? | evidence-driven | 已解决 |
| Q2 | 边界 | Verifier 需要的"工具调用记录"在 SupervisorAgent 中是否自动传递? | evidence-driven | 已解决 |
| Q3 | 边界 | LOW_CONFID < 0.5 回调 Planner 后的新输出是否再次走 Verifier?循环上限多少? | user-interview | 已解决 |
| Q4 | 验收 | Verifier 判决结果如何可观测?是否写入 agent_step 或 tool_invocation? | user-interview | 已解决 |
| Q5 | 验收 | 当前 Supervisor 硬编码 prompt 是否支持多 Agent 路由变更? | evidence-driven | 已解决 |
| Q6 | 技术 | Verifier 如何隔离 Executor 的中间推理过程,只看到干净的 query + tool 记录 + 最终答案? | user-interview | 已解决 |
| Q7 | 验收 | groundedness_score 阈值(0.5)是否需要配置化? | user-interview | 已解决 |
### Evidence-driven 结论
| 结论 | 证据来源 | 是否已汇报用户 |
|------|---------|-------------|
| evidence_score(异步事后)与 Verifier(同步事前门禁)不冲突 | EvaluationService.java: @Async 注解 | 已汇报 |
| SupervisorAgent 自动传递完整对话状态,Verifier 无需额外传递工具记录 | Spring AI Alibaba SupervisorAgent 实现 | 已汇报 |
| Supervisor prompt 为字符串字面量,直接修改即可 | ChatService.java:353 .systemPrompt("...") | 已汇报 |
### User-interview 记录
| 问题 | 用户原话 | 确认状态 | OpenSpec 回写 |
|------|---------|---------|-------------|
| Q3: LOW_CONFID < 0.5 回调 Planner 循环上限? | "可以,回调一次" | 已确认 | 已回写 proposal |
| Q4: Verifier 判决写入哪里做可观测? | "可以"(写入 diagnosis_session.self_evaluation JSON) | 已确认 | 已回写 proposal |
| Q6: Verifier 如何隔离 Executor 中间推理? | "用 MessagesModelHook 过滤 messages" | 已确认 | 已回写 design |
| Q7: groundedness_score 阈值是否需要配置化? | "需要配置化" | 已确认 | 已回写 design |
### Specify 阶段 — Cross-Artifact 对齐检查
| 上游 → 下游 | 检查内容 | 状态 |
|---|---|---|
| proposal → design | 范围、约束、关键承诺是否进入 design | 已对齐 |
| design → specs | 关键决策、模块地图是否进入 specs | 已对齐 |
| specs → tasks | 可观察行为是否被 tasks 覆盖为可执行切片 | 已对齐 |
**接口影响分级**:
- buildChatVerifierAgent() 新增方法 → L1(内部方法,无外部消费者)
- VerifierInputHook 类 → L1(内部 Hook,无外部消费者)
- Supervisor prompt 重写 → L1(仅影响 Chat 多 Agent 内部调度)
- subAgents 列表变更 → L1(Supervisor 内部配置)
- verifier.low-confidence-threshold 配置 → L1(新增配置项,不改已有配置)
### Audit 阶段
**模块链路**:
```
用户 → Supervisor → Planner(步骤) → Executor(答案+工具记录)
│
Supervisor 调用 Verifier
│
[VerifierInputHook BEFORE_MODEL]
├─ 保留:system prompt + user query
├─ 保留:tool call 记录(输入+返回)
├─ 保留:Executor 最终答案
└─ 去除:Executor 中间推理、Planner 规划过程
│
Verifier 判决
│
┌─── PASS ───→ 直接输出
├─── LOW_CONFID≥0.5 → 带声明输出
├─── LOW_CONFID<0.5 → 回调 Planner(一次)
└─── REJECT → 降级输出
│
写入 self_evaluation JSON
```
**架构风险评估**(5 句以内):
1. Verifier 是轻量 Agent(无工具、无外部依赖),架构风险低。
2. MessagesModelHook 纯过滤逻辑,不引入新数据源。
3. LOW_CONFID 分级处理 + 回调仅一次的设计,避免无限循环风险。
4. REJECT 降级确保编造内容不到达用户。
5. 审计结论不影响现有 design/tasks,无需回写。
### 关键取舍
- 决策:LOW_CONFID < 0.5 回调 Planner 一次
- 原因:给系统一次修正机会,但避免无限循环
- 影响:Supervisor prompt 需维护"已回调"状态
- 风险接受:用户已确认
- 决策:Verifier 判决写入 diagnosis_session.self_evaluation JSON
- 原因:不改表结构,与 evidence_score 统一可观测体系
- 影响:ChatService 后处理需追加 JSON
- 风险接受:用户已确认
### Archive-Ready Update
- 实现调整:最终运行链路由 `ChatService` 显式调用 `planner -> executor -> verifier`,不再依赖 Supervisor prompt 保证 verifier 被调用。
- 可追溯性补充:`tool_trace_summary` 增加 `trace_ref`、`source_invocation_ids`、查询样本、检索层级、相关性等级和来源文档标签。
- 可追溯性补充:`facts_checked[*].evidence_refs` 被 prompt 要求、代码解析并持久化。
- 验证记录:`mvn -q -DskipTests compile` 通过。
- 验证记录:运行会话 `9138f064` 走通 planner、executor、verifier,并持久化 `verifier_evaluation.facts_checked[*].evidence_refs` 与 `tool_trace_summary[*].source_invocation_ids`。
- 当前状态:OpenSpec change 已归档到 `openspec/changes/archive/2026-07-03-chat-verifier-agent/`,主规格已同步到 `openspec/specs/chat-verifier-agent/spec.md`。
@@ -0,0 +1,52 @@
# Evidence: chat-verifier-agent
## Code Evidence
### Complex chat path now invokes verifier deterministically
- File: `src/main/java/com/superbiz/agent/service/ChatService.java`
- Evidence: `executeChatComplex` calls planner, executor, then verifier directly through `callAgent(...)`.
- Conclusion: runtime no longer depends on prompt-only Supervisor behavior to call verifier.
### Verifier receives explicit inputs
- File: `src/main/java/com/superbiz/agent/hook/VerifierInputHook.java`
- Evidence: the hook builds a JSON payload with `original_query`, `executor_final_answer`, `tool_trace_summary`, and `retry_context`.
- Conclusion: verifier input is stable and does not depend on guessing the last assistant message from raw history.
### Tool evidence is traceable to persisted invocations
- File: `src/main/java/com/superbiz/agent/service/ToolTraceSummaryService.java`
- Evidence: summaries include `trace_ref`, `source_invocation_ids`, `query_samples`, `retrieval_layers`, `relevance_levels`, and `source_documents`.
- Conclusion: verifier facts can be correlated with actual `tool_invocation` rows.
### Verifier facts preserve evidence references
- File: `src/main/java/com/superbiz/agent/service/ChatService.java`
- Evidence: verifier parsing preserves `facts_checked[*].evidence_refs` and persists `tool_trace_summary` under `verifier_evaluation`.
- Conclusion: `self_evaluation` now contains both verifier judgments and the evidence index used to form them.
### Evaluation channels no longer overwrite each other
- File: `src/main/java/com/superbiz/agent/service/SelfEvaluationMergeService.java`
- Evidence: rule and verifier evaluations are merged into separate keys.
- Conclusion: asynchronous rule scoring preserves verifier output.
### Verifier logging is less noisy
- File: `src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java`
- Evidence: verifier `thought` stores a concise verdict summary, while fuller model output remains available in structured storage.
- Conclusion: `agent_step.thought` is no longer a misleading place for full verifier JSON.
## Runtime Evidence
- Compile verification passed: `mvn -q -DskipTests compile`.
- Runtime session `9138f064` executed `planner -> executor -> verifier`.
- Runtime session `9138f064` persisted `verifier_evaluation.facts_checked[*].evidence_refs`.
- Runtime session `9138f064` persisted `verifier_evaluation.tool_trace_summary[*].source_invocation_ids`.
## Design Evidence
- `LOW_CONFID` returns a fixed disclaimer and verifier-derived gaps.
- `REJECT` returns degraded output and does not pass through the raw Executor answer.
- `retry_context` is derived from verifier-identified missing evidence facts.