docs(interview): refresh materials for single-agent harness narrative

Archive pre-refactor interview notes and add current deep-dives on
architecture evolution, issue-derived stories, and evidence gates.
This commit is contained in:
zhuyongxin
2026-07-24 18:14:49 +08:00
parent e47f2dead0
commit de5a5b09d9
18 changed files with 2622 additions and 57 deletions
+31 -57
View File
@@ -1,66 +1,40 @@
# SuperBizAgent 面试资料包
# SuperBizAgent 面试资料
**更新日期**:2026-07-24
**当前主叙事**:单 Diagnosis ReAct Agent + 确定性 Harness(ISS-014 后)
## 当前入口
| 文档 | 用途 |
|---|---|
| [architecture-evolution-deep-dive.md](architecture-evolution-deep-dive.md) | **主材料**:架构演进深读(为什么设计 / 问题 / 重构 / 业界对比 / 图与白板) |
| [issues-interview-stories.md](issues-interview-stories.md) | **故事材料**:从已解决 Issues 提炼的可讲案例(STAR / 追问 / 挂载演进) |
| [topic-evidence-attribution-and-gates.md](topic-evidence-attribution-and-gates.md) | **主题深读**:证据归因幻觉 + 质量门禁(质量辨识度主故事) |
配套现行架构事实(非面试话术):
| 文档 | 用途 |
|---|---|
| [mvp/architecture/README.md](../mvp/architecture/README.md) | 当前架构文档入口 |
| [mvp/architecture/current-mvp-architecture.md](../mvp/architecture/current-mvp-architecture.md) | 分层、主链、API、安全边界 |
| [mvp/demo/README.md](../mvp/demo/README.md) | Demo 运行与输出 |
| [mvp/issues/active/ISS-015-diagnosis-runtime-quality-and-reasoning-audit.md](../mvp/issues/active/ISS-015-diagnosis-runtime-quality-and-reasoning-audit.md) | 架构冻结后的运行质量收敛 |
## 一句话定位
SuperBizAgent 是一个面向企业故障诊断场景的 Agent 工程项目。它把用户问题或 AIOps 告警转换成可追踪的 Agent 执行链路,并把工具证据、模型步骤、最终答案、自评估和用户反馈统一沉淀到诊断 Trace 中。
SuperBizAgent 是面向故障诊断的可追踪 Agent 系统:业务侧一个 Diagnosis Agent 负责推理与写 Draft;Harness 负责预算、工具边界、证据验真、语义审查与安全发布。每次执行用 `sessionId + runId` 回放统一 Timeline。
## 面试重点
## 建议使用方式
- **Agent 编排**:Chat 复杂问题走 `Planner -> Executor -> Verifier`;AIOps 告警入口走 `Supervisor -> Planner / Executor`。
- **工具证据链**:知识库、日志、指标、Prometheus 告警都通过显式工具调用进入链路,并记录到 `tool_invocation`。
- **可追踪诊断**:一次诊断对应一个 `sessionId`,可通过 `GET /api/diagnosis/{sessionId}/trace` 回放。
- **质量门禁**:Chat Verifier 校验 groundedness;AIOps 规则评估检查报告完整性、payload 聚焦和证据工具覆盖。
- **RAG 工程化**:`lookup_knowledge` 是显式 Agent Tool,底层通过 Spring AI VectorStore 主路径 + Milvus SDK fallback。
- **反馈闭环**:用户反馈 `useful` 会沉淀 `case_library`,`not_useful` 保留 bad case 信号。
1. 先读深读文档 §0–§6 + §10,建立演进骨架。
2. 按 §15 默画白板图 A/C/D(当前主链、职责迁移、数据三层)。
3. 需要事实核对时回到 `mvp/architecture/*`,不要用归档面试稿当现行口径。
4. 未完成项用 ISS-015 收尾,体现判断力而非完美叙事。
## 推荐阅读顺序
## 归档
1. `mvp/architecture/interview-one-pager.md`:一页式架构图和 2-5 分钟讲解。
2. `mvp/demo/ten-minute-interview-demo.md`:10 分钟现场演示脚本。
3. `interview/story-cases.md`:可复用的面试故事案例。
4. `interview/architecture.md`:面试版系统架构。
5. `interview/design-tradeoffs.md`:关键设计取舍。
6. `interview/demo-script.md`:更细的命令式演示脚本。
7. `interview/acceptance-checklist.md`:面试前验收清单。
8. RAG 专题文档:`rag-refactor-story.md`、`rag-vectorstore-interview-notes.md`、`rag-retrieval-quality-report.md`。
2026-07-24 之前的面试资料(多角色编排、双入口、旧 RAG/AIOps 讲解等)已移至:
## 核心演示链路
### Chat 诊断
```text
POST /api/chat
-> ChatService
-> Planner -> Executor -> Verifier
-> lookup_knowledge / query_logs / query_metrics
-> diagnosis_session + agent_step + tool_invocation
-> GET /api/diagnosis/{sessionId}/trace
-> POST /api/feedback
```
### AIOps 告警诊断
```text
POST /api/ai_ops
-> AiOpsService
-> PAYLOAD_TARGETED / AUTO_DISCOVERY
-> ai_ops_supervisor
-> planner_agent / executor_agent
-> queryPrometheusAlerts + logs + metrics + lookup_knowledge
-> alert report
-> aiops_rule_evaluation
-> GET /api/diagnosis/{sessionId}/trace
```
## 当前完成度
- Chat 诊断链路:可运行、可追踪、有 Verifier。
- AIOps 告警链路:可运行、可追踪、支持 payload scope control。
- RAG 检索链路:Spring AI VectorStore 主路径、Milvus SDK fallback、L0 hint、检索评测 baseline。
- Trace API:统一返回 session、agent steps、tool invocations 和 summary。
- Demo 材料:`mvp/demo/README.md`、`mvp/demo/ten-minute-interview-demo.md`。
## 主叙事
这个项目不是简单调用大模型,而是在做一个可审计、可验证、可回归的 Agent 诊断系统。模型可以规划和推理,但每一步工具证据、最终结论、Verifier 结果和用户反馈都能被 Trace API 回放。面试时重点展示“从问题到证据到答案到验证再到反馈”的闭环。
[archive/2026-07-24-legacy/](archive/2026-07-24-legacy/)
仅用于历史追溯,不代表当前 runtime、API 或验收口径。说明见同目录 `_ARCHIVE_NOTE.md`。
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,66 @@
# SuperBizAgent 面试资料包
## 一句话定位
SuperBizAgent 是一个面向企业故障诊断场景的 Agent 工程项目。它把用户问题或 AIOps 告警转换成可追踪的 Agent 执行链路,并把工具证据、模型步骤、最终答案、自评估和用户反馈统一沉淀到诊断 Trace 中。
## 面试重点
- **Agent 编排**:Chat 复杂问题走 `Planner -> Executor -> Verifier`;AIOps 告警入口走 `Supervisor -> Planner / Executor`。
- **工具证据链**:知识库、日志、指标、Prometheus 告警都通过显式工具调用进入链路,并记录到 `tool_invocation`。
- **可追踪诊断**:一次诊断对应一个 `sessionId`,可通过 `GET /api/diagnosis/{sessionId}/trace` 回放。
- **质量门禁**:Chat Verifier 校验 groundedness;AIOps 规则评估检查报告完整性、payload 聚焦和证据工具覆盖。
- **RAG 工程化**:`lookup_knowledge` 是显式 Agent Tool,底层通过 Spring AI VectorStore 主路径 + Milvus SDK fallback。
- **反馈闭环**:用户反馈 `useful` 会沉淀 `case_library`,`not_useful` 保留 bad case 信号。
## 推荐阅读顺序
1. `mvp/architecture/interview-one-pager.md`:一页式架构图和 2-5 分钟讲解。
2. `mvp/demo/ten-minute-interview-demo.md`:10 分钟现场演示脚本。
3. `interview/story-cases.md`:可复用的面试故事案例。
4. `interview/architecture.md`:面试版系统架构。
5. `interview/design-tradeoffs.md`:关键设计取舍。
6. `interview/demo-script.md`:更细的命令式演示脚本。
7. `interview/acceptance-checklist.md`:面试前验收清单。
8. RAG 专题文档:`rag-refactor-story.md`、`rag-vectorstore-interview-notes.md`、`rag-retrieval-quality-report.md`。
## 核心演示链路
### Chat 诊断
```text
POST /api/chat
-> ChatService
-> Planner -> Executor -> Verifier
-> lookup_knowledge / query_logs / query_metrics
-> diagnosis_session + agent_step + tool_invocation
-> GET /api/diagnosis/{sessionId}/trace
-> POST /api/feedback
```
### AIOps 告警诊断
```text
POST /api/ai_ops
-> AiOpsService
-> PAYLOAD_TARGETED / AUTO_DISCOVERY
-> ai_ops_supervisor
-> planner_agent / executor_agent
-> queryPrometheusAlerts + logs + metrics + lookup_knowledge
-> alert report
-> aiops_rule_evaluation
-> GET /api/diagnosis/{sessionId}/trace
```
## 当前完成度
- Chat 诊断链路:可运行、可追踪、有 Verifier。
- AIOps 告警链路:可运行、可追踪、支持 payload scope control。
- RAG 检索链路:Spring AI VectorStore 主路径、Milvus SDK fallback、L0 hint、检索评测 baseline。
- Trace API:统一返回 session、agent steps、tool invocations 和 summary。
- Demo 材料:`mvp/demo/README.md`、`mvp/demo/ten-minute-interview-demo.md`。
## 主叙事
这个项目不是简单调用大模型,而是在做一个可审计、可验证、可回归的 Agent 诊断系统。模型可以规划和推理,但每一步工具证据、最终结论、Verifier 结果和用户反馈都能被 Trace API 回放。面试时重点展示“从问题到证据到答案到验证再到反馈”的闭环。
@@ -0,0 +1,36 @@
# Archive Note
**归档日期**:2026-07-24
**状态**:历史面试材料,不代表当前 runtime / 架构口径
## 为何归档
本目录保存切换到「单 Diagnosis Agent + Harness」之前整理的面试资料包,内容仍以:
- Chat:`Planner -> Executor -> Verifier`(及后续五段 Gatekeeper/Composer)
- AIOps 独立入口与规则评估
- 旧 Trace / Demo 叙事
为主。现行可运行架构见:
- `mvp/architecture/`
- `interview/architecture-evolution-deep-dive.md`(当前面试深读主文档)
## 归档文件
| 文件 | 原用途 |
|---|---|
| `README.md` | 旧面试资料包入口 |
| `architecture.md` | 旧面试版系统架构 |
| `design-tradeoffs.md` | 旧设计取舍 |
| `demo-script.md` | 旧命令式演示脚本 |
| `acceptance-checklist.md` | 旧面试前验收清单 |
| `story-cases.md` | 旧故事案例 |
| `rag-*.md` | 旧 RAG 专题与验收笔记 |
| `aiops-*.md` | 旧 AIOps 讲解材料 |
## 使用边界
- 可作历史决策与旧 Demo 话术追溯。
- 不得当作当前 API、编排或验收标准。
- 若引用其中内容,须同时说明归档日期与现行替代文档。
+380
View File
@@ -0,0 +1,380 @@
# 从 Issues 提炼的面试故事
**更新日期**:2026-07-24
**用途**:从 `mvp/issues` 已解决问题中,筛出可讲、值得讲、能举一反三的案例
**配套**:[architecture-evolution-deep-dive.md](architecture-evolution-deep-dive.md)(讲演进骨架);本文讲**具体踩坑与决策**
---
## 0. 怎么用
| 场景 | 用法 |
|---|---|
| 行为面试 / 项目深挖 | 选 2–3 个 ★★★ 故事,用 STAR 讲 |
| 架构追问 | 把故事挂回演进阶段(Phase2 证据 / Phase3 重构 / 工程化) |
| 避免踩坑 | ★ 仅作补充,勿当主叙事;过时方案要说「后来被什么吸收」 |
**总原则**
> 面试官要的不是 Issue 编号,而是:**现象 → 根因分层 → 你选了什么杠杆 → 如何验证 → 后来边界怎么演进**。
---
## 1. 全景评分(先看这张表)
| Issue / 主题 | 面试价值 | 最适合回答的问题类型 | 一句话钩子 | 注意 |
|---|:---:|---|---|---|
| **证据归因幻觉** + Gatekeeper 链路 | ★★★ | 防幻觉 / 质量门禁 | 「工具调了,结论仍是编的」 | 旧角色名要映射到现在 Guard |
| **ISS-014** 单 Agent + Harness | ★★★ | 架构重构 / 为什么简化 | 「不是砍验证,是换装载层」 | 主故事,深读文档已覆盖 |
| **ISS-008** 窄范围越界 | ★★★ | Agent 约束 / Prompt 不够 | 「只问 CPU,却去查全家桶」 | 好举一反三 |
| **ISS-009** 负向证据 | ★★★ | 证据建模 / no-hit | 「没查到也是证据」 | 区分「无问题」vs「无数据」 |
| **ISS-001→002→004→015** 重复检索族 | ★★★ | 迭代加深 / Prompt vs 硬约束 | 「去重了仍狂调 20 次」 | 讲演进链,别只讲一次补丁 |
| **ISS-010** session/run 隔离 | ★★★ | 可观测 / 多轮正确性 | 「同会话多轮 Trace 串台」 | 和 runId 真理源强绑定 |
| **ISS-012** Token/上下文膨胀 | ★★★ | 成本 / ACI / 上下文工程 | 「工具返回把上下文撑爆」 | 接到 projection 三层数据 |
| **ISS-006 + fixtures + baseline diff** | ★★ | 工程化 / 回归 | 「改 Prompt 怎么知道没退步」 | 体现测试思维 |
| **ISS-007** 摘要失真 → 自证循环 | ★★★ | 信息通路设计 | 「证据在,摘要丢了关键句」 | 可与归因幻觉合并讲 |
| **ISS-013** SSE / 入口解耦 | ★★ | 后端工程 / 协议边界 | 「假流式 + Controller 过重」 | 偏工程,Agent 味稍淡 |
| **ISS-005** 证据状态契约 | ★★ | 契约 / 失败语义 | 「failed/no_evidence/deduped 语义乱」 | 作 001/007 的基础设施铺垫 |
| **RAG 子问题集** | ★★ | RAG 专题 | L0 降级、显式 Tool、breadcrumb | 合成一条 RAG 故事,勿逐条念 |
| **ISS-003** 总 Review | ★ | 过程 | 问题发现清单 | 不宜单独讲 |
| **ISS-015**(进行中) | ★★ | 诚实收尾 / 判断力 | 「架构冻了,策略还在收」 | 讲未完成,勿假装已完美 |
---
## 2. 推荐主故事包(面试只带这 5 个就够)
### 故事包怎么组合(15 分钟项目介绍)
```text
1) 开场架构(2 min) → 深读文档 / ISS-014 结论
2) 质量核心(4 min) → 证据归因幻觉 + Gatekeeper/EvidenceGuard
3) 约束演进(3 min) → 重复检索 001→002→硬预算 / 窄范围 008
4) 工程底座(3 min) → run 隔离 010 + eval harness 006
5) 重构与未完(3 min) → ISS-014 为什么合并 + ISS-015 诚实项
```
---
## 3. ★★★ 故事详解(可直接练口述)
### 3.1 证据归因幻觉(最高辨识度)
| 项 | 内容 |
|---|---|
| 来源 | `executor-evidence-attribution-hallucination` + ISS-007 + design-note 自证循环 |
| 完整深读 | [topic-evidence-attribution-and-gates.md](topic-evidence-attribution-and-gates.md) |
| 阶段 | Phase 2 正确性建设 |
| 现象 | 多次 E2E:工具已调 `lookup_knowledge/logs/metrics`,Verifier 仍大面积 `LOW_CONFID`;答案里出现 OOM、Full GC 次数等**工具返回里没有的「精确事实」** |
| 错误归因(你要主动否定) | 「是不是 Verifier 太严 / 只认 RAG?」——查 `evidence_refs` 后发现并非如此 |
| 真根因 | **Executor 证据归因幻觉**:把 runbook/历史模式/模型常识写进「当前已证实事实」,未区分 direct / reference / hypothesis / missing |
| 解法演进 | ① 结构化 claim + binding(invocation/path/excerpt)② **代码 Gatekeeper** 验引用 ③ Verifier 只判可推导 ④ Composer 控表达 → 后来迁到 EvidenceGuard + SemanticGuard + Release |
| 验证 | 固定 session 表(groundedness、no_evidence 计数);eval fixture;Trace 可指出「哪条 claim 无 binding」 |
| 现行映射 | Gatekeeper → **EvidenceGuard**;Verifier → **SemanticGuard**;最终出门 → **Release** |
**STAR 口述(约 90 秒)**
> 我们诊断链路经常 LOW_CONFID。第一反应像是验证器太狠,但拉 Trace 发现工具其实调用成功了。
> 对比答案和 tool raw 后定位到:模型会把知识库里的「常见故障模式」写成「这次故障已观测事实」。
> 所以我们把「有没有这句证据」从 LLM 判断里拆出来,做成代码级引用校验;模型只负责在已验真片段上做推导。
> 这直接把问题从「提示词求稳」升级成「证据所有权与类型系统」。
> 后来重构单 Agent 时,这层语义保留了,只是从流水线角色变成了 Harness 门禁。
**追问预备**
- Q: 为什么不靠更强模型?
A: 分布上仍会混用常识与观测;确定性校验可回归、可解释。
- Q: excerpt 子串匹配会不会太死?
A: 对防伪造必须偏严;表达层再允许归纳,但不允许无根引用。
- Q: 和 RAG 引用角标有何不同?
A: 角标常是生成时装饰;我们校验的是**当次 Run 的 tool_call 所有权**。
**举一反三**
- 客服:「政策规定 7 天」≠「本单已同意退款」
- 代码 Agent:「README 说应有测试」≠「本 PR 已有测试」
---
### 3.2 窄范围查询越界(ISS-008)
| 项 | 内容 |
|---|---|
| 现象 | 用户只要确认 `payment-service` 是否有 HighCPU 告警;Agent 却扩展到内存、日志、根因故事 |
| 根因 | ReAct 默认「有工具就多查」;Prompt 未区分 **observation 任务** vs **root-cause 任务**;claim 类型未收窄 |
| 解法 | 窄范围只允许 `observation` / `negative_observation`;禁止随手 root_cause;工具选择与输出 schema 双约束 |
| 验证 | narrow-highcpu 类 fixture:该 PASS 的 observation 不因「没讲根因」被打成失败 |
| 现行 | DiagnosisDraft 分析项仍强调证据绑定;范围控制在 Agent 指令 + Guard 语义审查 |
**金句**
> Agent 的能力上限往往不是「会不会查」,而是「知不知道何时停、查什么算完成」。
**举一反三**
- SQL Agent:用户要 `SELECT count` 时禁止顺手 `UPDATE`
- 调查 Agent:「只要时间线」时禁止输出处置工单
---
### 3.3 负向证据(ISS-009)
| 项 | 内容 |
|---|---|
| 现象 | 工具明确 no-hit 时,模型要么不说,要么说成「已排除该根因」,且引用对不上 |
| 根因 | 只建模「命中证据」,没有一等公民的 **no_evidence 路径**(如 `$.no_evidence`) |
| 解法 | `negative_observation` + 固定 raw_path/excerpt 契约;Gatekeeper 校验「无证据」也可以是合法引用 |
| 价值 | 排障里「查过没有」改变后验;也避免虚假排除 |
**金句**
> 在证据系统里,空结果若不可引用,模型就会用语言填补真空——那就是幻觉温床。
---
### 3.4 重复检索演进链(ISS-001 → 002 → 004 → 015)
这是**最好的「迭代加深」故事**:同主题三次升级约束强度。
```text
ISS-001 同文档内容重复进上下文
→ session 文档去重 / Prompt「别重复」
ISS-002 去重后仍 lookup 20+ 次(换 query 刷同一域)
→ 根因:约束只打在 Planner,Executor 不知情
→ Executor 注入 map + 每域一次等 Prompt 约束
ISS-004 Prompt 仍挡不住「再确认一次」
→ 设计域级水位 / 硬限制(后被架构变更吸收)
ISS-014/015 约束归属变化
→ 不再靠 Executor 旁路状态打补丁
→ Harness 预算 + Agent 硬停止 + 重复 lookup 策略(015 进行中)
```
**面试怎么讲这条链**
> 第一阶段我们以为是重复文档,做了内容去重。
> 第二阶段发现模型换关键词继续刷,说明**去重粒度错了**,且约束注入点错了(只告诉了 Planner)。
> 第三阶段承认 Prompt 约定不是安全边界,必须**预算/次数硬停止**。
> 架构重构后,这些不再散落在 Tool 旁路,而进入统一 Harness 控制面。
> 这说明我处理 Agent 问题的习惯是:先观测 → 分层根因 → 逐步把约束从「软」推到「硬」,并在架构变了以后迁移装载点,而不是叠补丁。
**对应业界概念**:Action masking / tool budget / circuit breaker;不是调参玄学。
---
### 3.5 Session / Run Trace 隔离(ISS-010)
| 项 | 内容 |
|---|---|
| 现象 | 同 `sessionId` 多轮诊断时,步骤/工具/评价串台或「取最新一条」导致回放错乱 |
| 根因 | 缺少把**一次执行**定为真理源的 `runId`;查询与写入未全程 exact id |
| 解法 | `diagnosis_run`;step/invocation/trace 均挂 run;API 强制 `runId`;禁止 latest 语义 |
| 价值 | 评测、排障、面试 Demo 都依赖可复现回放 |
**金句**
> 可观测性若不能精确到一次 Run,就只是日志堆,不是诊断系统的记忆。
**举一反三**
- 工作流引擎的 `workflowId` vs `runId`
- CI 的 pipeline vs job attempt
---
### 3.6 Token 与上下文膨胀(ISS-012)→ ACI / 三层数据
| 项 | 内容 |
|---|---|
| 现象 | Executor 上下文暴涨;工具结果含 debug/rerank/大段重复;成本与截断不可控 |
| 根因 | Tool 返回**面向开发者**而非 Agent;完整 raw 与模型可见视图未分离 |
| 解法方向 | Token 可观测;硬预算;结果投影;证据引用带稳定 id(后由 ISS-014 的 Redis canonical + projector 落地) |
| 现行 | canonical / projection / durable audit 三层 |
**金句**
> 上下文工程首先是接口设计问题:Agent 的观察通道必须有界,验真通道才能完整。
---
### 3.7 单 Agent + Harness 重构(ISS-014)
深读文档已写透,这里只留**Issue 视角的故事钩子**:
| 项 | 内容 |
|---|---|
| 触发 | 多角色 = 外层重复 ReAct;JSON 接力;Token;失败语义组合爆炸 |
| 保留 | 物理验真 → 语义审查 → 发布 的正确性模型 |
| 迁移 | 角色流水线 → 执行边界(Harness) |
| 证据 | 阶段 E2E:成功诊断 ~8k tokens / 1 次 tool;Knowledge Query 独立路径修复 invalid schema |
**和 3.1 的关系(必说清)**
> 014 不是推翻 007/归因幻觉的成果,而是避免用「五个 LLM 角色」去实现本该由一个 ReAct + 一层确定性门禁完成的事。
---
### 3.8 评测 Harness(ISS-006 + fixtures + baseline diff)
| 项 | 内容 |
|---|---|
| 动机 | 只有 Demo 无法判断改 Prompt/Tool 是否退步 |
| 做法 | 固定 case;expected tools/verdict/keywords;**确定性** trace 校验(非一上来 LLM-as-judge);baseline + diff |
| 价值 | 把 Agent 质量从「感觉」变成「回归」 |
**金句**
> 没有 baseline diff 的 Agent 迭代,只是在用生产用户当测试集。
**注意**:面试强调「先确定性检查,再考虑 LLM judge」,显得克制。
---
### 3.9 SSE 与入口解耦(ISS-013)
| 项 | 内容 |
|---|---|
| 现象 | `/api/chat` 与 `/api/chat_stream` 双入口;stream 实为整答后假分片;Controller 编排过重 |
| 解法 | 唯一 `POST /api/chat` named SSE;UseCase 拥有业务;Controller 只协议;disconnect → cancel Run |
| 适合 | 问到 Spring/API 设计、背压、职责边界时 |
---
## 4. ★★ 可合并讲的「专题束」
### 4.1 RAG 专题束(不要逐 Issue 报菜名)
把 `mvp/issues/rag/*` 收成 **一条 2 分钟故事**:
```text
问题簇:
L0 关键词当终局、breadcrumb 不进向量、切片丢层级、
无 packing/rerank、分数语义不清、Advisor 隐式注入 vs 显式 Tool
收敛原则:
1) 检索决策要对 Agent 可见 → lookup_knowledge 保持 Tool
2) L0 降级为 hint,不替代语义召回
3) 向量主路径可演进(VectorStore)+ 过渡期 fallback
4) 召回质量与「能否被引用验真」一起设计
```
**面试官若只问 RAG**:用这条;若问 Agent 质量:退回 3.1。
### 4.2 证据契约束(ISS-005 + 007 + 结构化输出设计笔记)
```text
统一 evidence 状态:supported / no_evidence / deduped / failed
摘要不可当唯一证据源
Executor 产出可绑定结构,Gatekeeper 验,Verifier 判
```
适合接在「你们怎么保证工具结果语义一致」类问题。
---
## 5. 不建议当主故事的
| 项 | 原因 | 若被问到怎么说 |
|---|---|---|
| ISS-003 总 Review | 清单型,缺单点冲突 | 「那是问题发现基线,具体落地看 005/006/014」 |
| ISS-004 原文方案细节 | 实现被 014/015 吸收,细节易过时 | 「方向是硬水位,装载点已迁到 Harness 预算/停止策略」 |
| 归因幻觉的旧 Prompt 补丁 alone | 不完整 | 必须接到 Gatekeeper/Guard |
| 未归档的「计划中」口吻 | 很多已 done | 统一用「已归档 / 被 014 吸收 / 015 进行中」三态 |
---
## 6. 问题类型 → Issue 速查
| 面试官问… | 优先故事 |
|---|---|
| 怎么防幻觉? | 3.1 归因幻觉 + Guard 映射 |
| Prompt 够不够? | 3.4 重复检索链 + 3.2 窄范围 |
| 多 Agent 为什么又合并? | 3.7 ISS-014(挂 3.1 证明没砍质量) |
| 成本 / Token? | 3.6 + 数据三层 |
| 如何回归? | 3.8 eval |
| 如何调试一次错误诊断? | 3.5 run 隔离 + Timeline |
| 没找到证据怎么办? | 3.3 负向证据 + Release fallback |
| SSE / 接口设计? | 3.9 |
| RAG 怎么做的? | 4.1 专题束 |
| 还有什么没做完? | ISS-015:硬停止、Repair schema、reasoning 治理、信息化 fallback |
---
## 7. 与架构演进的挂载图
```text
Phase1 能跑
└─ 暴露:重复检索 001/002
Phase2 能验
├─ 证据状态 005
├─ 归因幻觉 + 007 自证循环
├─ 窄范围 008 / 负向证据 009
├─ eval 006 / baseline
└─ run 隔离 010
Phase2 负债
└─ Token 012、入口 013、角色编排税
Phase3 能控
└─ 014 单 Agent + Harness(吸收 004/012/013 与证据门禁语义)
Phase4 治理中
└─ 015 停止策略 / Repair / reasoning / fallback 信息量
```
---
## 8. 建议你精炼的「个人贡献表述」模板
按真实参与度改主语,结构建议:
```text
我负责/主导了 ___(问题)。
通过 Trace 看到 ___(证据),排除了 ___(错误假设)。
方案上选择 ___ 而不是 ___,因为 ___。
用 ___(fixture/E2E/指标)验证。
后续在 014 重构中,该能力迁移为 ___,我学到 ___。
```
示例(归因幻觉):
```text
我负责排查 Chat 诊断大面积 LOW_CONFID。
通过对比 tool raw 与最终答案,确认是证据归因幻觉而非 Verifier 误杀。
推动「结构化 claim + 代码 Gatekeeper + Verifier 只做推导」而不是继续堆 Prompt。
用固定 E2E session 与 eval fixture 回归。
014 重构后该语义保留为 EvidenceGuard/SemanticGuard/Release。
```
---
## 9. 源文件索引
| 故事 | 路径 |
|---|---|
| 归因幻觉 | `mvp/issues/archived/executor-evidence-attribution-hallucination.md` |
| 自证/摘要 | `mvp/issues/archived/ISS-007-...` / `design-notes/executor-self-evidence-loop-design-note.md` |
| 窄范围 | `mvp/issues/archived/ISS-008-...` |
| 负向证据 | `mvp/issues/archived/ISS-009-...` |
| 重复检索 | `ISS-001` `ISS-002` `ISS-004` |
| Run 隔离 | `ISS-010` |
| Token | `ISS-012` |
| SSE | `ISS-013` |
| 重构 | `ISS-014-single-react-agent-harness-aci-ptk-refactor.md` |
| 评测 | `ISS-006` `expand-diagnosis-eval-fixtures` `diagnosis-eval-baseline-diff` |
| 进行中 | `mvp/issues/active/ISS-015-...` |
| RAG 簇 | `mvp/issues/rag/*` |
---
## 10. 自测
1. 不看文档,讲清「工具调用成功为何仍 LOW_CONFID」的根因与门禁分层。
2. 用 001→002→004→015 说明你如何升级约束强度。
3. 画旧 Gatekeeper 到新 EvidenceGuard 的映射,并说明 014 保留了什么。
4. 举一个负向证据防止的错误用户话术。
5. 用一句话说明 eval harness 为什么先做确定性检查。
能答 1–3,项目深挖通常已够用;4–5 用于区分「做过功能」和「有质量体系」。
@@ -0,0 +1,739 @@
# 主题深读:证据归因幻觉 + 现行质量门禁
**用途**:巩固知识 + 面试准备 + 举一反三
**不是**:逐字讲稿、旧 Issue 复述、过时五段流水线说明书
**材料日期**:2026-07-24
**叙事原则**:**以现行设计为主讲;早期 Issue 只说明「问题从哪来」**
**主题定位**:质量辨识度主故事——「工具调了,结论为何仍不能直接给用户」
**现行依据(面试默认口径)**
| 层级 | 路径 |
|---|---|
| 架构 | `mvp/architecture/current-mvp-architecture.md` |
| 编排 | `mvp/architecture/agent-orchestration.md` |
| 门禁 | `mvp/architecture/harness-quality-gates.md` |
| Draft 契约 | `.../harness/contract/DiagnosisDraft.java`、`AnalysisKind.java` |
| 物理验真 | `.../harness/guard/evidence/EvidenceGuard.java` |
| 语义审查 | `.../harness/guard/semantic/SemanticGuard.java`、`semantic-guard-prompt.md` |
| 发布 | `.../harness/release/DiagnosisReleaseUseCase.java`、`SafeFallbackFactory.java` |
| Agent 规则 | `src/main/resources/prompts/diagnosis-agent-prompt.md` |
**历史依据(只作起源,不代表 runtime)**
- `mvp/issues/archived/executor-evidence-attribution-hallucination.md`(2026-07-07,旧 Executor 链路)
- Phase2 Gatekeeper / `executor_evidence_v2` 归档文档
**配套**
- 演进骨架 → [architecture-evolution-deep-dive.md](architecture-evolution-deep-dive.md)
- 故事索引 → [issues-interview-stories.md](issues-interview-stories.md) §3.1
---
## 0. 怎么用 / 怎么讲
| 目标 | 用法 |
|---|---|
| 巩固 | 先背现行三道门与 `DiagnosisDraft` 引用闭包,再看历史问题为何逼出这套设计 |
| 面试 | **先讲现在怎么拦,再补一句早期怎么发现**;禁止把主链路讲成 Planner→Executor→Verifier |
| 举一反三 | 用现行组件名迁移到客服/代码/合规场景 |
**开场主线(先背这句,现行口径)**
> 当前系统里,Diagnosis Agent 是唯一报告作者,它在 ReAct 里查只读工具并写出结构化 `DiagnosisDraft`。
> 但 Draft **默认不能出门**:必须先过 **EvidenceGuard(0 LLM,验 tool_call 归属与投影)**,再过 **SemanticGuard(隔离单轮,判是否越证)**,最后由 **Release Policy** 决定公开报告还是 SAFE_FALLBACK。
> 这套门禁要防的核心失败,是早期线上已经见过的 **证据归因幻觉**:有工具调用,却把 runbook/常识写成「本 Run 已证实事实」。
**禁止的过时口径**
| 不要说 | 要说 |
|---|---|
| 我们主链路是 Planner→Executor→Gatekeeper→Verifier→Composer | 单 Diagnosis Agent + Harness 门禁 |
| Gatekeeper 验 `source_invocation_id + raw_path + excerpt` | EvidenceGuard 验 `tool_call_id` + 当前 Run canonical/projection |
| Verifier 输出 LOW_CONFID/PASS | SemanticGuard 输出 `SUPPORTED` / `UNSUPPORTED` |
| 工具有 metrics/Prometheus | 现行诊断 Tool:`lookup_knowledge` / `query_logs` / `query_mysql` |
| 引用主键是 DB `tool_invocation.id` | 框架 `tool_call_id`;完整调用在 Redis canonical |
**四轴(现行)**
1. **谁写报告**:仅 Diagnosis Agent
2. **谁保证引用真**:EvidenceGuard + Redis canonical(Harness only)
3. **谁保证语义不越界**:SemanticGuard(无 Tool、无记忆)
4. **谁决定用户看见什么**:Release Policy(Draft ≠ 公开 SSE)
**图目录**
| 图 | 位置 | 白板优先级 |
|---|---|---|
| 现行主链(质量视角) | §1 | ★★★ |
| DiagnosisDraft 引用闭包 | §2 | ★★★ |
| EvidenceGuard 校验步骤 | §3 | ★★★ |
| AnalysisKind × EvidenceStatus | §3.3 | ★★ |
| SemanticGuard 输入冻结 | §4 | ★★★ |
| Release / Repair / Fallback | §5 | ★★★ |
| 数据三层如何服务验真 | §6 | ★★ |
| 历史问题 → 现行映射(30 秒) | §8 | ★★ |
| 白板速画 | §13 | ★★★ |
---
## 1. 现行设计:质量门禁长什么样
### 1.1 在系统中的位置
```text
POST /api/chat (SSE)
→ ChatApplicationUseCase
→ Intent Router → DIAGNOSIS
→ Diagnosis ReAct Agent
只读 Tool × 3,观察的是 projection
产出 DiagnosisDraft
→ DiagnosisReleaseUseCase
EvidenceGuard →(可选 EvidenceRepair 一次)→ SemanticGuard → Release
→ 公开 content | SAFE_FALLBACK | failure
```
```mermaid
flowchart TB
Q["query + safe previous_turn"] --> A["Diagnosis Agent<br/>唯一报告作者 · ReAct"]
A <--> TB["ToolBoundary"]
TB --> Redis["Redis canonical<br/>Harness only"]
TB --> Proj["bounded agent_result"]
Proj --> A
A --> Draft["DiagnosisDraft<br/>内部制品"]
Draft --> RU["DiagnosisReleaseUseCase"]
RU --> EG["EvidenceGuard · 0 LLM"]
EG -->|invalid| RP["EvidenceRepair 最多一次"]
RP --> EG
EG -->|valid snapshot| SG["SemanticGuard · 隔离单轮"]
SG -->|SUPPORTED| Out["Release SUCCESS<br/>公开 typed report"]
SG -->|UNSUPPORTED / 不可用| FB["SAFE_FALLBACK"]
EG -->|仍 invalid| FB
```
**面试一句话**
> Agent 负责「尽量基于证据写对」;Harness 负责「写错了也不能当成功答案发出去」。
### 1.2 职责切分(现行,必背)
| 组件 | 做 | 不做 |
|---|---|---|
| **Diagnosis Agent** | 规划、调 Tool、写完整 Draft、证据不足时写 limitations | HTTP/SSE、预算、物理验真、语义终审、发布 |
| **ToolBoundary** | schema/只读/预算、写 canonical、projector、只回有界观察 | 业务推理 |
| **EvidenceGuard** | Draft 结构、analysis 闭包、`tool_call_id` 属本 Run、READY/可引用、kind↔status、投影可解析 | 调模型、改报告语义 |
| **EvidenceRepair** | 在证据失败时尝试一次结构化修复 | 无限重试、绕过验真 |
| **SemanticGuard** | 在 verified snapshot 上判断整份报告是否被支持 | Tool、记忆、Redis、改写报告、部分放行 |
| **Release** | SUPPORTED 才公开 Draft;否则固定 fallback/failure | 把未验证 Draft 流式出去 |
对应代码入口:`DiagnosisReleaseUseCase.execute(run, query, draft)`。
### 1.3 和「纯 ReAct Demo」的差(质量视角)
```text
纯 ReAct: Model ↔ Tools → 文本直接给用户
现行: Model ↔ ToolBoundary/projection → DiagnosisDraft
→ EvidenceGuard → SemanticGuard → Release → SSE
+ run 预算/取消 + Timeline(EVIDENCE/SEMANTIC/RELEASE 事件)
```
---
## 2. 现行契约:`DiagnosisDraft` 如何逼归因诚实
### 2.1 结构(代码事实)
```text
DiagnosisDraft
conclusion?
text
based_on_analysis_ids[] ← 必须指向本 Draft 内 analysis_id
analysis[]
analysis_id ← 唯一
kind: NORMAL | NEGATIVE_OBSERVATION
text
tool_call_ids[] ← 至少一个;必须是本 Run 真实 id
action_plan[]
action
based_on_analysis_ids[]
requires_human_confirmation
recommendations[]
text
based_on_analysis_ids[]
limitations ← 必填 scope(EvidenceGuard 校验)
scope
missing_info[]
```
```mermaid
flowchart TB
C["conclusion / actions / recommendations"] -->|"based_on_analysis_ids"| A["analysis_id"]
A -->|"tool_call_ids"| T["本 Run tool_call_id"]
T --> Canon["Redis canonical<br/>runId + toolCallId"]
Canon --> Status["evidence_status<br/>FOUND / NO_EVIDENCE"]
A --> Kind["kind NORMAL / NEGATIVE"]
Kind -.->|"must match"| Status
```
**设计意图(对着归因幻觉)**
| 约束 | 防什么 |
|---|---|
| 每条 analysis 必须带 `tool_call_ids` | 「凭空结论」「常识当观测」 |
| conclusion 不直接绑 tool,只绑 analysis | 结论必须落在已声明的分析链上,形成闭包 |
| `limitations` 强制存在 | 证据不足时不能装成完整结案 |
| `kind` 二分 | 负向观察与正向命中不能混用同一类证据状态 |
### 2.2 Agent Prompt 里的硬规则(现行)
`diagnosis-agent-prompt.md` 关键口径(面试可直接引用思想,不必背原文):
1. **唯一报告作者**;内部规划,不对外输出 CoT。
2. **PreviousTurn 不是本 Run 证据**,不能引用其 tool_call_id。
3. 只有 `evidence_status=EVIDENCE_FOUND|NO_EVIDENCE` 且带真实 `tool_call_id` 的观察才能当证据。
4. **NORMAL** 只能引 FOUND;**NEGATIVE_OBSERVATION** 只能引 NO_EVIDENCE。
5. **NO_EVIDENCE ≠ 系统健康 / 已排除根因**。
6. Tool **ERROR 不是证据**,禁止引用。
7. 证据不足:`conclusion=null`,写 scope/missing_info,**禁止编根因**。
8. 不暴露 raw、凭据、内部错误、hidden reasoning。
**金句**
> Prompt 负责教 Agent「怎么写才诚实」;EvidenceGuard 负责「写得不诚实就过不了」。两者缺一不可,但**安全边界在代码**。
### 2.3 和早期「分区文案」的关系(30 秒)
早期 Issue 要求 Executor 输出「已证实 / 推测 / 缺口 / 动作」分区。
现行不是同一套 JSON 字段名,但**语义被结构吸收了**:
| 早期分区意图 | 现行落点 |
|---|---|
| 已证实事实 | `analysis`(NORMAL + FOUND) |
| 负向观察 | `analysis`(NEGATIVE_OBSERVATION + NO_EVIDENCE) |
| 证据缺口 | `limitations.missing_info` + 可空 `conclusion` |
| 建议动作 | `action_plan` / `recommendations`(必须 based_on analysis) |
| 禁止常识当事实 | Guard 不认无 tool_call 的 analysis;Semantic 审越证 |
---
## 3. EvidenceGuard:现行物理验真(0 LLM)
### 3.1 它在防什么
不是「这句话好不好听」,而是:
> 报告里声明依赖的每一个 tool_call,是否真的在本 Run 发生过、状态是否可引用、投影是否自洽、analysis kind 是否与 evidence_status 匹配,以及 conclusion/action 是否只引用存在的 analysis。
### 3.2 校验流水(按代码路径讲)
`EvidenceGuard.validate(RunContext, DiagnosisDraft)` 大致两段:
**A. Draft 结构与报告闭包**
- draft / analysis 非空
- `analysis_id` 存在且唯一
- `kind`、`text` 必填
- 每条 analysis 的 `tool_call_ids` 非空
- conclusion / action_plan / recommendations:text 非空,且 `based_on_analysis_ids` 非空、id 都认识
- `limitations.scope` 必填
**B. 逐 tool_call 验真**
对每个 `tool_call_id`:
1. 用 `runId + toolCallId` 生成 key,查 **Redis canonical**
2. 找不到 → `INVOCATION_MISSING`(典型:编造 id)
3. id 不一致 → `INVOCATION_ID_MISMATCH`
4. `!isReferencableBy(runId)` 或 agent_result 空 → `INVOCATION_NOT_REFERENCABLE`
(跨 Run、未 READY、不可引用状态)
5. `analysis.kind.accepts(invocation.evidenceStatus)`
- NORMAL ↔ EVIDENCE_FOUND
- NEGATIVE_OBSERVATION ↔ NO_EVIDENCE
否则 `EVIDENCE_KIND_MISMATCH`
6. 按 tool 反序列化 **agent_result 投影**(不是让模型再读 raw 讲故事):
- `lookup_knowledge` / `query_logs` / `query_mysql`
7. 投影内 `tool_call_id`、`evidence_status` 与 canonical 一致
8. FOUND 必须有可展示证据条目;NO_EVIDENCE 必须空列表且 count=0
9. 通过则写入 `VerifiedEvidence`,汇总为 `VerifiedEvidenceSnapshot`
```mermaid
flowchart TB
Draft["DiagnosisDraft"] --> S["结构 + analysis 闭包"]
S --> Loop["foreach tool_call_id"]
Loop --> Key["key = runId + toolCallId"]
Key --> Redis["Canonical store"]
Redis -->|missing| V1["INVOCATION_MISSING"]
Redis -->|not referencable| V2["NOT_REFERENCABLE"]
Redis -->|ok| K["kind vs evidence_status"]
K -->|mismatch| V3["KIND_MISMATCH"]
K --> P["Parse projection"]
P -->|invalid| V4["PROJECTION_*"]
P --> Snap["VerifiedEvidenceSnapshot"]
```
### 3.3 `AnalysisKind` × `EvidenceStatus`(高频考点)
```text
NORMAL → 只能绑 EVIDENCE_FOUND
NEGATIVE_OBSERVATION → 只能绑 NO_EVIDENCE
ERROR → 根本不是证据(Agent Prompt + 边界)
```
**面试例子**
| Agent 想说 | 错误绑法 | Guard |
|---|---|---|
| 「CPU 告警 92%」 | 编造 tool_call_id | MISSING |
| 「未查到池耗尽日志」 | kind=NORMAL 却绑 NO_EVIDENCE | KIND_MISMATCH |
| 「已排除内存泄漏」 | 仅 NO_EVIDENCE 却写排除结论 | 物理可能过,**Semantic 应 UNSUPPORTED** |
| 引用上一轮 previous_turn 的 id | 非本 Run canonical | MISSING / NOT_REFERENCABLE |
### 3.4 为什么验的是 projection 且 canonical 在 Redis
| 设计 | 原因 |
|---|---|
| Agent 只见 projection | 有界 ACI;降低上下文里的 debug 噪声与胡拼素材 |
| Guard 读 canonical 元数据 + 校验投影 | 确认「Agent 引用的 id」对应真实调用,且投影自洽 |
| Agent 不能访问 Redis | 防止自己翻 raw 再编第二套故事 |
| MySQL `tool_invocation` 只 metadata | 长期审计 ≠ 验真主存;完整 raw 短 TTL |
**与早期 Gatekeeper 的差异(讲清楚就加分)**
| 早期 Gatekeeper | 现行 EvidenceGuard |
|---|---|
| 多角色流水线中的一环 | Harness Release 路径上的确定性步骤 |
| `source_invocation_id` + `raw_path` + `excerpt` 字符串闭合 | `tool_call_id` + Run ownership + 投影结构/状态闭合 |
| 面向 `executor_evidence_v2` claims | 面向 `DiagnosisDraft` analysis 闭包 |
| 工具集合含 metrics 等 | 现行三 Tool;投影类型 Rag/Logs/Mysql |
语义继承:**都是 0 LLM 的物理/契约验真**;协议与装载层已现代化。
### 3.5 失败码怎么用于口述
挑几个最能讲故事的 `EvidenceViolationCode`:
| Code | 一句话 |
|---|---|
| `TOOL_REFERENCE_MISSING` | analysis 根本没绑工具 |
| `INVOCATION_MISSING` | 引用了不存在的 tool_call(归因造假) |
| `INVOCATION_NOT_REFERENCABLE` | 调用存在但不可作为证据(错 Run/未就绪/空结果) |
| `EVIDENCE_KIND_MISMATCH` | 负向/正向证据用错 kind |
| `ANALYSIS_REFERENCE_UNKNOWN` | 结论引用了不存在的 analysis_id |
| `PROJECTION_INVALID` | 投影与契约不一致,不能当干净证据 |
---
## 4. SemanticGuard:现行语义保险丝
### 4.1 输入被故意冻死
`SemanticGuardInput.from(query, draft, verifiedSnapshot)`:
```text
只给:
原始 query
+ 完整 Draft 视图
+ EvidenceGuard 产出的 verified snapshot
明确没有:
Tool / 记忆 / Redis / 主 Agent 回调 / 诊断历史
```
Prompt(`semantic-guard-prompt.md`)要求:
- 查:evidence 是否支持各 analysis;analysis 是否支持 conclusion;action/recommendation 是否越界;limitations 是否如实
- **禁止**改写、纠正、摘要扩展、**部分批准**
- 只返回 `{"verdict":"SUPPORTED|UNSUPPORTED","reason":"..."}`
### 4.2 它专门接住 EvidenceGuard 接不住的归因幻觉
EvidenceGuard 通过只说明:
> 「你引用的调用是真的,投影也合法。」
仍可能:
| 漏洞 | 例子 | 谁拦 |
|---|---|---|
| 真日志推不出该根因 | 只有超时日志 → 写「确定是死锁」 | SemanticGuard |
| 负向观察说成排除 | NO_EVIDENCE → 「不可能是池耗尽」 | SemanticGuard + Agent 规则 |
| 结论超出 analysis 集合语义 | analysis 只谈 A,conclusion 谈 B | SemanticGuard |
| 建议动作无分析支撑 | 乱给变更建议 | SemanticGuard + 结构上 based_on |
```mermaid
flowchart LR
EG["EvidenceGuard<br/>物理真"] --> SG["SemanticGuard<br/>语义立"]
SG -->|SUPPORTED| R["可发布"]
SG -->|UNSUPPORTED| F["Fallback<br/>保留 observed_facts"]
```
### 4.3 为什么必须隔离、且无 Tool
| 若 SemanticGuard 能再查库 | 后果 |
|---|---|
| 自建第二证据世界 | 与主 Agent / snapshot 不一致 |
| 「审稿时补证」 | 绕过用户可见的排查过程 |
| 又变成带 Tool 的第二 Executor | 归因问题换个角色重演 |
**金句**
> SemanticGuard 是保险丝,不是第二名侦探。
### 4.4 技术失败策略(现行)
- 输入/输出字节上限(`SemanticGuardLimits`)
- 同输入有限重试;仍失败 → `semanticUnavailable` fallback(有 snapshot 时仍可带已验证事实)
- 不把内部异常原文甩给用户
---
## 5. Release:Draft 与公开通道切断
### 5.1 `DiagnosisReleaseUseCase` 决策序
```text
1) EvidenceGuard.validate
2) 若失败 → EvidenceRepair 一次 → 再 validate
3) 仍失败 → EVIDENCE_VALIDATION_FAILED fallback
4) SemanticGuard.review(query, draft, snapshot)
5) SUPPORTED → SUCCESS(公开 candidate Draft + snapshot 元数据路径)
6) UNSUPPORTED → SEMANTIC_UNSUPPORTED fallback(可带 observed_facts)
7) Semantic 技术不可用 → SEMANTIC_UNAVAILABLE fallback
```
Timeline 会记:`EVIDENCE_GUARD_INITIAL` / `RECHECK` / semantic / release 决策(普通 Trace 可回放阶段,不靠「感觉」)。
### 5.2 SAFE_FALLBACK 在防什么
不是空白 500,而是**可信的不完整**:
| Fallback 类型 | 用户侧含义(思想) |
|---|---|
| 证据校验失败 | 引用/结构没过,不能确认根因;可带 validation 问题方向 |
| 语义不支持 | 已有可验证事实,但撑不起当前根因结论 |
| 语义不可用 | 有事实,但审不过/审不了,暂不发根因 |
`SafeFallbackFactory` 会从 snapshot 抽取有界 `observed_facts` / sources(有上限),并给出 `failure_stage`、`next_steps` 等——**在不泄 Prompt/raw/内部 Draft 细节的前提下**尽量可操作。
**金句**
> 我们宁可发布「已经核实到什么、卡在哪」,也不发布「流畅但未过门禁的完整故事」。
### 5.3 PreviousTurn 与门禁的衔接
- 仅 **同 Session、最近一次 DIAGNOSIS + SUCCESS + published_result** 可进下一轮
- Fallback/失败/raw **不进** PreviousTurn
- Prompt 明确:previous_turn **不可当本 Run 证据**
防止「上一轮没过门禁的句子」在下一轮被当成已证实事实——这是归因幻觉的跨轮版本。
---
## 6. Tool 边界:归因幻觉的上游防线
门禁是下游闸门;上游仍要减少「胡拼素材」。
```text
framework tool_call_id
→ exact Run / schema / read-only / budget
→ 执行
→ Redis canonical(request/raw/agent_result/status)
→ projector → bounded agent_result
→ 只把 projection 给 Agent
→ MySQL 仅 metadata audit
```
现行 Agent 可见 Tool 固定三个:
- `lookup_knowledge`
- `query_logs`
- `query_mysql`
**与归因的关系**
| 机制 | 作用 |
|---|---|
| 投影有界 | 少把 rerank/debug 大字段留给模型拼案情 |
| 统一 evidence_status | FOUND/NO_EVIDENCE/ERROR 语义稳定,供 kind 匹配 |
| 每调必有 tool_call_id | Draft 绑定有稳定主键 |
| 禁止 Agent 见 Redis | 不能「翻完整 raw 再假装引用」 |
---
## 7. Reasoning 明确不是证据(现行安全边界)
架构硬约束:
- Provider reasoning 若存在,进独立 `agent_reasoning_audit`
- **不进**普通 SSE、Trace 正文、Evidence Snapshot、业务判断
- **不能**绕过 EvidenceGuard / SemanticGuard
- 未返回则记 unavailable,**禁止伪造**
面试若被问「你们保存思考过程吗」:
> 审计与事实分离。思考不是 tool evidence,更不能当发布依据。
---
## 8. 历史问题:只用来回答「为什么要这套现行设计」
### 8.1 早期现象(30–45 秒够)
2026-07 旧 Chat 链路(Planner/Executor/Verifier…)上:
- 多次 E2E:`lookup_* / logs / metrics` 有调用,仍大量 `LOW_CONFID`
- 答案出现工具 raw 中不存在的「精确事故事实」(OOM 次数、慢 SQL 秒数等)
- 根因命名:**证据归因幻觉**——把 runbook/常识/他服事实写成「本会话已证实」
- 曾伴随摘要失真、自证闭环(自己总结再自己绑引用)
**正确用法**
> 这段证明「只靠模型自觉 + 事后 LLM Verifier」不够,必须把物理引用做成确定性约束,并把发布权从生成模型手里拿走。
**错误用法**
> 把整场面试讲成旧五段角色和 `executor_evidence_v2` 字段细节,却说不清现在的类名与 API。
### 8.2 语义迁移表(历史 → 现行)
| 历史概念 | 现行概念 | 说明 |
|---|---|---|
| Executor 综合答案 | Diagnosis Agent 写 Draft | 仍是模型生成,但是唯一作者 |
| claim + excerpt binding | analysis + `tool_call_ids` | 主键协议变更 |
| Gatekeeper | EvidenceGuard | 仍 0 LLM;装入 Release 用例 |
| Verifier LOW_CONFID | SemanticGuard UNSUPPORTED | 隔离输入;二元 verdict |
| Composer 控表达 | Draft 结构 + Release/Fallback | 表达权在 Agent,发布权在 Harness |
| 调低阈值换 PASS | **明确不做** | 用 fallback 信息量换体验 |
```mermaid
flowchart LR
H1["早期:归因幻觉被发现"] --> H2["正确性模型:物理验真+语义审+控表达"]
H2 --> H3["ISS-014:装载到单 Agent + Harness"]
H3 --> Now["现行:Draft→EG→SG→Release"]
```
### 8.3 一句话定位两阶段
> 早期 Issue 解决的是 **「要什么正确性」**;
> 现行架构解决的是 **「正确性如何成为默认运行路径」**。
---
## 9. 和业界主流的区别(用现行组件说)
| 常见做法 | 缺口 | 本项目现行 |
|---|---|---|
| 纯 ReAct 直接吐最终答案 | 无发布闸 | Draft 默认内部,Release 才公开 |
| 答案末尾 sources 角标 | 角标可假 | `tool_call_id` 必须在本 Run canonical 可解析 |
| 单一 LLM-as-Judge | 真伪与语义混判、不可复现引用检查 | EG 代码 + SG 隔离模型 |
| 质检 Agent 再带 Tool | 第二证据世界 | SG 无 Tool,冻结 snapshot |
| 离线 RAGAS | 不挡单次错误出门 | 在线门禁 + Timeline + eval 夹具 |
| 只靠更强模型 | 无工程边界 | 与模型代际正交的 Harness |
**三个不一样(现行表述)**
1. **引用是 Run 级所有权问题**,不是文案装饰。
2. **物理与语义拆分**,失败阶段可进 Trace / fallback。
3. **公开通道与生成通道切断**,SUPPORTED 才是成功产品语义。
---
## 10. 决策环(填的是现行答案)
| # | 问题 | 现行答案 |
|---|---|---|
| 1 | 威胁? | 带 tool 外观的完整假案情进入 SSE |
| 2 | 谁强制? | EG 强制引用;SG 强制语义;Release 强制发布 |
| 3 | 数据面? | canonical / projection / metadata audit;reasoning 另表 |
| 4 | 失败用户看到? | SAFE_FALLBACK(阶段、有界事实、下一步),非假成功 |
| 5 | 如何证明? | 单元/契约测 violation;E2E release_outcome;Timeline 事件 |
| 6 | 演进? | 误杀先查投影与 schema/Repair;不给 SG 加 Tool;停止策略见 ISS-015 |
---
## 11. 面试题库(默认用现行答)
### 11.1 90 秒主叙述(推荐背这个版本)
> 故障诊断里最危险的不是完全不查工具,而是查了一点真实信号就补成完整事故——我们早期在旧链路上把它定义为证据归因幻觉。
> **现在**的做法是:唯一 Diagnosis Agent 用 ReAct 查三个只读工具,只看投影,输出结构化 DiagnosisDraft;每条分析必须绑定本 Run 的 tool_call_id。
> Draft 先过 EvidenceGuard:纯代码检查结构闭包、调用是否存在于当前 Run 的 Redis canonical、证据状态是否与 NORMAL/负向观察匹配、投影是否自洽。
> 通过后生成 verified snapshot,再交给无工具的 SemanticGuard 做整份语义是否越证的审查。
> 只有 SUPPORTED 才经 Release 进入 SSE;否则走 SAFE_FALLBACK,宁可告诉用户已核实事实和卡住的阶段,也不发未验证根因。
> 所以质量辨识度是三句话:**可调用 ≠ 可归因;可归因 ≠ 语义成立;语义成立才可发布。**
### 11.2 为什么题
| 问题 | 现行得分点 |
|---|---|
| 怎么防幻觉? | Draft 绑定 tool_call_id → EG → SG → Release |
| 为什么 EG 不用模型? | 归属与状态是确定性的;要可回归 |
| 为什么还要 SG? | 真调用推不出假根因;负向≠排除 |
| 为什么 SG 不能有 Tool? | 冻结证据集,防第二世界 |
| 引用主键为什么是 tool_call_id? | 框架协议 id;与当次调用一致;不靠「最新 DB 行」 |
| Agent 能看 raw 吗? | 不能;只看 projection;canonical Harness only |
| 证据不足怎么办? | conclusion 可空 + limitations;或 fallback;不编根因 |
| 和旧 Gatekeeper 啥关系? | 语义祖先;现装在 Harness,协议已换 |
### 11.3 对抗题
**Q:这不就是多 Agent 质检吗?**
A:不是。业务侧只有一个带 Tool 的 Diagnosis Agent。SG 是无 Tool 的隔离单轮审查,属于 Harness 控制面,不是协作同事。
**Q:你们重构掉多角色后质量是不是弱了?**
A:弱的是重复的 LLM 角色编排;强的是默认路径上的确定性 EG + 发布切断。正确性模型保留,装载点从流水线角色变成 Release 用例。
**Q:投影校验不看 raw 原文子串,会不会漏?**
A:现行 EG 强调 **调用所有权 + 状态 + 投影结构自洽 + kind 匹配**,再交给 SG 做语义。上游靠 projector 把可引用证据做成稳定结构。若追问 excerpt 级闭合,可承认协议从早期 raw_path/excerpt 演进到投影契约,并强调 **不能引用 ERROR/跨 Run/不可引用调用** 仍是硬的。
**Q:用户体验会不会总是 fallback?**
A:体验做在「信息化 fallback + 成功路径的 limitations」,不是放宽 Guard。ISS-015 继续收敛停止策略与 fallback 信息量。
### 11.4 现场设计题
1. 给「工单退款 Agent」设计等价于 `tool_call_ids` + EG 的字段。
2. 若增加第四个 Tool,EG 要补哪些分支?kind/status 如何扩展?
3. Knowledge Query 路径(非完整 DIAGNOSIS)如何复用「引用必须真实」而不照搬整份 SemanticGuard?
4. 如何用 Timeline 事件向面试官演示一次 UNSUPPORTED 的失败阶段?
---
## 12. 原则清单(现行)
1. **唯一报告作者,多个确定性关卡**
2. **Draft 是 staging,SSE 是 production**
3. **引用主键 = 本 Run 的 framework tool_call_id**
4. **NORMAL / NEGATIVE 与 FOUND / NO_EVIDENCE 强匹配**
5. **NO_EVIDENCE 不是健康证明**
6. **ERROR 与跨 Run id 绝不能当证据**
7. **PreviousTurn 不是证据**
8. **SemanticGuard 冻结 snapshot,无 Tool**
9. **Reasoning 不是证据**
10. **历史 Issue 论证问题,现行代码定义答案**
---
## 13. 白板默画(只画现行)
### 13.1 图 A · 60 秒主链
```text
Diagnosis Agent → DiagnosisDraft
↓
EvidenceGuard (0 LLM, tool_call_id)
↓ verified snapshot
SemanticGuard (no tools)
↓ SUPPORTED?
Release → SSE or SAFE_FALLBACK
```
### 13.2 图 B · 45 秒闭包
```text
conclusion.based_on → analysis_id → tool_call_ids
↓
Redis canonical (this runId)
↓
FOUND / NO_EVIDENCE
↓
kind must match
```
### 13.3 图 C · 30 秒历史锚点(可选)
```text
早期发现:有 tool 仍假案情
→ 要物理验真 + 语义审 + 发布权
→ 现装在 EG / SG / Release
```
### 13.4 红线
- 画出 Planner/Executor/Composer 当主路径
- 说 Verifier 输出 LOW_CONFID 当现行 API
- SG 带检索箭头
- Draft 直连用户
- 说 metrics Tool 仍是诊断三件套之一(现行是 knowledge/logs/mysql)
---
## 14. 复习路径(偏现行)
| 步骤 | 动作 |
|---|---|
| 1 | 读 `diagnosis-agent-prompt.md` + `DiagnosisDraft` / `AnalysisKind` |
| 2 | 通读 `EvidenceGuard.validate` 与 `EvidenceViolationCode` |
| 3 | 读 `DiagnosisReleaseUseCase` + `semantic-guard-prompt.md` |
| 4 | 对照 `harness-quality-gates.md` 默画 §13 图 A/B |
| 5 | 用 §11.1 录音;再花 20 秒提早期归因幻觉作动机 |
| 6 | 扫一眼归档 Issue 标题与现象表即可,不背旧字段 |
---
## 15. 源文件索引
### 现行(主)
| 内容 | 路径 |
|---|---|
| 架构总览 | `mvp/architecture/current-mvp-architecture.md` |
| 执行序列 | `mvp/architecture/agent-orchestration.md` |
| 门禁 | `mvp/architecture/harness-quality-gates.md` |
| Draft | `src/main/java/.../harness/contract/DiagnosisDraft.java` |
| Kind/Status | `AnalysisKind.java` / `EvidenceStatus.java` |
| EG | `.../guard/evidence/EvidenceGuard.java` |
| SG | `.../guard/semantic/SemanticGuard.java` |
| Release | `.../release/DiagnosisReleaseUseCase.java` |
| Fallback | `.../release/SafeFallbackFactory.java` |
| Agent Prompt | `src/main/resources/prompts/diagnosis-agent-prompt.md` |
| SG Prompt | `src/main/resources/prompts/semantic-guard-prompt.md` |
### 历史(辅)
| 内容 | 路径 |
|---|---|
| 归因幻觉发现 | `mvp/issues/archived/executor-evidence-attribution-hallucination.md` |
| 自证闭环笔记 | `mvp/issues/design-notes/executor-self-evidence-loop-design-note.md` |
| 旧证据契约 | `mvp/architecture/archive/2026-07-22-legacy/executor-evidence-pipeline-refactor.md` |
| 重构承接 | `mvp/issues/archived/ISS-014-...` |
| 运行质量后续 | `mvp/issues/active/ISS-015-...` |
---
## 16. 自测(必须能用现行组件名回答)
1. 画出 Draft 从产生到 SSE 的完整门禁序,并标出哪步 0 LLM。
2. `NORMAL` 与 `NEGATIVE_OBSERVATION` 分别能绑哪种 `evidence_status`?
3. EvidenceGuard 如何发现「编造 tool_call_id」?
4. 为什么 conclusion 要 `based_on_analysis_ids` 而不是直接绑 tool?
5. SemanticGuard 的输入有哪三样?为什么不能有 Tool?
6. Evidence 失败时 Repair 最多几次?仍失败用户看到什么产品语义?
7. PreviousTurn 为什么不能提供可引用的 tool_call_id?
8. Reasoning 能否帮助 Draft 过 EG/SG?
9. 用 20 秒说明早期归因幻觉与现行三道门的关系(动机 vs 实现)。
10. 举一个「EG 通过但 SG 应 UNSUPPORTED」的例子。
---
## 17. 和旧版材料的关系
若你曾按「五段流水线 + excerpt 外键」准备:
- **保留**:归因幻觉定义、物理/语义拆分、发布切断思想
- **替换**:所有主路径类名、Tool 列表、verdict 枚举、引用主键、API
- **降级**:Executor/Gatekeeper/Composer 仅出现在「历史动机」小节
**面试默认叠词顺序**
```text
1. 现行:Agent → Draft → EG → SG → Release
2. 机制:tool_call_id、kind/status、snapshot、fallback
3. 动机:早期归因幻觉(可选一句)
4. 演进:正确性模型保留,装载进 Harness(若追问重构)
```