7.8 KiB
Context
Current Chat flow explicitly runs Planner -> Executor -> Verifier. VerifierInputHook builds a structured verifier payload containing:
original_queryexecutor_final_answertool_trace_summaryretry_context
This satisfies the earlier design goal that Verifier should not see Planner/Executor intermediate reasoning. However, Executor's answer is still natural language. Verifier must infer claims from prose, then compare those claims to tool traces. Recent low-confidence sessions show that Executor often converts weak or unrelated evidence into confirmed conclusions before Verifier sees it.
The fix should move evidence attribution earlier: Executor must state which claims are confirmed, which evidence supports them, and which points remain hypotheses or gaps.
Goals / Non-Goals
Goals:
- Make Executor final output machine-checkable.
- Separate confirmed claims, hypotheses, recommended actions, and missing information.
- Make every confirmed claim bind to concrete tool evidence identifiers or excerpts.
- Let Verifier consume structured claims directly instead of reconstructing all facts from prose.
- Preserve Verifier input isolation from intermediate reasoning.
- Preserve existing behavior when Executor output is malformed by falling back to natural-language verification and low-confidence handling.
Non-Goals:
- Do not add database tables or columns.
- Do not change evidence tool method signatures.
- Do not let Verifier call tools.
- Do not require full raw tool outputs in verifier input.
- Do not make user-facing answers become raw JSON-only unless the product layer explicitly chooses that rendering.
Decisions
Decision: Executor emits an evidence-attribution contract
Executor final output SHALL be a single JSON object. The recommended contract is:
{
"answer_version": "executor_evidence_v1",
"diagnosis_summary": "1-2 sentence summary using only supported facts",
"claims": [
{
"claim_id": "claim-1",
"claim_type": "root_cause",
"claim_text": "The payment-service connection pool is saturated",
"support_level": "direct",
"evidence_bindings": [
{
"source_type": "tool_trace",
"source_id": "trace-1",
"tool_name": "query_metrics",
"source_invocation_ids": [101],
"evidence_excerpt": "active connections reached max pool size"
}
]
}
],
"hypotheses": [
{
"hypothesis_text": "A connection leak may be contributing",
"basis": "metrics show saturation, but no leak evidence was returned",
"needed_evidence": ["connection lifetime metrics", "leak detection logs"]
}
],
"recommended_actions": [
{
"action_text": "Check HikariCP active/idle/pending connection metrics",
"reason": "Needed to confirm pool saturation scope",
"evidence_bindings": []
}
],
"missing_info": [
"No log evidence confirming a connection leak was returned"
],
"user_facing_answer": "Chinese answer rendered from the same confirmed claims, hypotheses, actions, and gaps"
}
Rationale: this keeps the machine contract explicit while still allowing the product to return a readable Chinese answer.
Decision: Evidence binding uses generic source fields
chunk_id alone is too specific to lookup_knowledge. The binding shape SHALL support all evidence-bearing tools:
source_type:tool_trace,lookup_evidence_block, or another stable source familysource_id:tool_trace_summary.trace_ref, evidence block id, or equivalent stable idtool_name: evidence tool name when availablesource_invocation_ids: persistedtool_invocationids when availableevidence_excerpt: bounded excerpt copied or summarized from tool evidence
Rationale: query_logs, query_metrics, and lookup_knowledge expose evidence differently. A generic binding prevents the prompt contract from overfitting to RAG chunks.
Decision: Confirmed claims are stricter than hypotheses and actions
Confirmed claims SHALL contain only facts supported by current-session evidence. Runbook instructions, skill guidance, and historical case patterns SHALL NOT appear as confirmed claims unless the current tool trace supports that exact fact.
Unsupported but useful diagnostic ideas SHALL be placed under hypotheses or recommended_actions.
Rationale: this directly addresses the observed hallucination: turning plausible patterns into current incident facts.
Decision: Verifier prefers structured claims but keeps fallback
Verifier prompt SHALL use this order:
- If
executor_structured_output.claimsis valid, verify each claim directly. - Also scan
user_facing_answerfor extra confirmed-sounding facts not present inclaims; mark them as facts to check. - If the structured output is missing or invalid, fall back to the existing natural-language extraction from
executor_final_answer.
Invalid structured output SHALL NOT crash the flow. It SHOULD produce a fallback verifier decision and make malformed structure visible in verifier_evaluation.
Rationale: the new contract should improve precision without making runtime brittle.
Decision: Verifier still does not see intermediate reasoning
The verifier payload MAY add:
executor_structured_outputexecutor_output_parse_status
It SHALL continue to exclude Planner reasoning, Executor intermediate reasoning, and raw conversation noise.
Rationale: this preserves the original verifier design: verify the final answer and tool traces, not hidden reasoning.
Decision: User-facing output remains Chinese
For Chat user-facing pages and answers, the rendered answer SHALL be Chinese. If the Executor emits JSON, either:
user_facing_answeris returned to the user after verifier routing, or- ChatService renders a Chinese answer from the structured contract.
The raw machine contract may remain visible in trace/debug views, but the normal user answer should not become an English/JSON-only artifact.
Rationale: this aligns with current UI/product language requirements while keeping machine-checkable evidence.
Risks / Trade-offs
- [Risk] LLM may emit malformed JSON. Mitigation: parse-status fallback and verifier natural-language fallback.
- [Risk] Executor may put unsupported facts in
user_facing_answerbut omit them fromclaims. Mitigation: Verifier scansuser_facing_answerfor extra confirmed-sounding facts. - [Risk] Evidence excerpts may be fabricated. Mitigation: Verifier checks binding ids against
tool_trace_summaryand treats missing refs as no evidence. - [Risk] More verbose output increases tokens. Mitigation: keep excerpts bounded and put detailed raw evidence only in tool traces.
- [Risk] Prompt-only enforcement is soft. Mitigation: add focused tests/eval fixtures and later consider code-level schema validation.
Migration Plan
- Update
chat-executor-prompt.mdwith the evidence-attribution JSON contract. - Add parsing in Chat runtime for Executor output:
- valid JSON -> preserve parsed
executor_structured_output - invalid JSON -> mark parse status and keep raw
executor_final_answer
- valid JSON -> preserve parsed
- Update verifier payload assembly to include
executor_structured_outputand parse status. - Update
chat-verifier-prompt.mdto prefer structured claims and verify extra facts inuser_facing_answer. - Persist parsed or raw structured output in existing trace/evaluation snapshots without schema changes.
- Add focused tests and regression fixtures for unsupported confirmed claims.
- Validate OpenSpec and run targeted tests.
Open Questions
- Should
user_facing_answerbe mandatory in Executor JSON, or should ChatService render it from structured fields? - Should malformed Executor JSON force
LOW_CONFID, or should Verifier decide based on natural-language fallback alone? - Should
support_levelallow onlydirect,indirect, andnone, or should it also includecontradictedfor Executor self-reporting?