308 lines
26 KiB
Markdown
308 lines
26 KiB
Markdown
# Harness 面试复习笔记:五步复习与白板图沉淀(详细版)
|
||
|
||
**更新日期**:2026-08-06
|
||
**主题**:面试总复习成果固化——30 秒电梯陈述 / 三张白板图 / 九域五段式面试讲法 / 六个易错点 / 追问应对大全 / 支付超时案例
|
||
**配套**:[面试速查](Harness面试速查-一张图讲清设计.md)、[设计演进](Harness设计演进-从多Agent编排到确定性控制边界.md)、各域学习笔记
|
||
|
||
## 1. 五步复习路径
|
||
|
||
```text
|
||
① 30 秒电梯陈述 + 一张图
|
||
② 默画三张白板图(主链路 / 职责迁移 / 数据三层)
|
||
③ 六个易错点
|
||
④ 2 分钟真实案例(支付超时)
|
||
⑤ 每域面试话术背诵(九域五段式)
|
||
```
|
||
|
||
## 2. 30 秒电梯陈述(详细版)
|
||
|
||
### 2.1 一句话版本
|
||
|
||
> "Harness 是包围非确定性 Agent 的确定性控制边界。Diagnosis Agent 负责提出假设、选择 Tool、解释观察并生成 Draft;Harness 负责一次 Run 的身份、deadline、预算、取消、Tool 权限和事实保管,发布前再验证引用真实性与结论支持度。它不保证 Agent 每次都找到根因,但保证执行过程有边界、失败能够收敛,并且只有可验证的内容能够发布。"
|
||
|
||
### 2.2 逐句展开(面试官追问「具体怎么做」时用)
|
||
|
||
```text
|
||
「确定性控制边界」展开为三层边界:
|
||
运行边界:RunContext(身份/截止/预算/取消)+ 唯一终态(first-terminal-wins)
|
||
事实边界:ToolBoundary(权限/只读/容量)+ canonical 真相 + 有界观察
|
||
发布边界:EvidenceGuard 验引用 → SemanticGuard 判支持度 → Release 唯一出口
|
||
```
|
||
|
||
### 2.3 三个重点(背的时候盯住)
|
||
|
||
```text
|
||
Agent 负责业务推理(出草稿,不是出报告)
|
||
Harness 负责确定性约束(真相与观察分离)
|
||
Release 决定什么可以公开(引用真实与结论支持是两个独立门禁)
|
||
```
|
||
|
||
### 2.4 不要一开始列 10 个职责域
|
||
|
||
先给一句定义 + 三句话,面试官追问「具体怎么做」再沿三张白板图展开。
|
||
|
||
## 3. 三张白板图(详细版)
|
||
|
||
### 3.1 图一:主链路(含分支,不是单轮)
|
||
|
||
```text
|
||
chat 接口
|
||
→ 创建 RunContext(core.startRun:runId/deadline/budget/cancel/lifecycle)
|
||
→ 意图识别(IntentRouter,单次模型调用,输出契约恰好 {intent} 枚举)
|
||
→ 诊断 Agent(ReAct 多轮循环)
|
||
├─ agent 决策 → ToolBoundary
|
||
│ ├─ preflight(run 匹配/授权/只读/JSON/key)→ 失败不落库
|
||
│ ├─ 预算门禁(beforeToolCall + bytes 三笔预留)
|
||
│ ├─ canonical 状态机(begin PROJECTING → READY/ERROR)
|
||
│ ├─ 执行 + Projector 投影(严格校验 + 脱敏 + 截断)
|
||
│ └─ 有界观察返回 Agent(模型永远看不到 raw)
|
||
├─ progress 判 GAINED/NO_GAIN(连续 NO_GAIN → 饱和停止)
|
||
└─ ↺ 循环直到:出草稿 或 受控停止(预算/饱和/协议违规)
|
||
→ 分支 A(有结论草稿):
|
||
EvidenceGuard 验引用(key=runId+toolCallId 查账本,READY + kind 匹配)
|
||
├─ 失败 → EvidenceRepair 只修引用(prompt 锁死 + 语义不变性)→ 复查
|
||
│ └─ 仍失败 → SafeFallback(EVIDENCE_VALIDATION_FAILED)
|
||
└─ 通过 → SemanticGuard 判支持度(隔离守卫模型)
|
||
├─ SUPPORTED → Release → SUCCESS(唯一出口)
|
||
└─ UNSUPPORTED/不可用 → SafeFallback(SEMANTIC_UNSUPPORTED/UNAVAILABLE)
|
||
→ 分支 B(无草稿/无结论):Release 凭 progress 快照 → SafeFallback(INSUFFICIENT_EVIDENCE 等)
|
||
└─ 无安全进展 → fail closed 抛异常 → FAILED
|
||
```
|
||
|
||
**讲解要点**(讲主链路时抓四个时间点):
|
||
1. Agent 运行前先建立 Run 边界;
|
||
2. Tool 调用经过 Harness,但 Tool 选择仍由 Agent 决定;
|
||
3. Agent 只看到有界观察,完整事实由系统独立保管;
|
||
4. Draft 必须经过唯一发布出口,不能直接发送给用户。
|
||
|
||
**三个词记忆**:循环(多轮 ReAct + 收敛)/ 分支(验真失败有修复、无草稿也能降级)/ 分离(真相在 canonical,Agent 只见有界观察)。
|
||
|
||
### 3.2 图二:职责迁移(推理合并,权力拆分)
|
||
|
||
**为什么迁移**:早期多 Agent(Planner/Executor/Verifier/Composer)加上 Gatekeeper、StateGraph,代价是四套 Prompt/JSON/上下文策略。后来发现四个角色**加起来正好是一次完整 ReAct**:
|
||
|
||
```text
|
||
思考 → Planner
|
||
行动观察 → Executor + Tool
|
||
自我检查 → Verifier
|
||
最终回答 → Composer
|
||
```
|
||
|
||
外层在重复实现框架已有的循环。于是收敛成单个 React Agent + 控制面拆分:
|
||
|
||
| 早期角色 | 干什么 | 现在迁移到哪 |
|
||
|---|---|---|
|
||
| Planner | 制定排查计划 | Diagnosis Agent(ReAct 思考) |
|
||
| Executor | 调用 Tool 收集证据 | Diagnosis Agent(ReAct tool 调用) |
|
||
| Gatekeeper | 机械验真证据引用 | EvidenceGuard(真理源改为 canonical store,对象改为 DiagnosisDraft) |
|
||
| Verifier | 判断 Claim 是否可信 | SemanticGuard(隔离,无 Tool 无记忆) |
|
||
| Composer | 组织最终回答 | Release(唯一发布点) |
|
||
| StateGraph | 显式状态/分支/终态 | Harness 状态分层(正交枚举 + first-terminal-wins) |
|
||
| 预算止损 | 防止空转 | Progress Control(信息增益收敛,从止损升级为正常收敛) |
|
||
|
||
**两个洞察**:
|
||
1. 代码能机械证明的事实,不交给模型判断(Gatekeeper → EvidenceGuard 的思想延续);
|
||
2. 只有拥有不同数据权限、不同工具或真正独立业务目标的角色,拆成多 Agent 才值得——把一次 ReAct 的内部步骤外置成多角色,只会放大协议成本。
|
||
|
||
**结果**:业务推理合并回单个 Agent,但安全权力拆得更清楚——Agent 没有 canonical 读取权、不能自证引用、没有发布权。
|
||
|
||
### 3.3 图三:数据三层(一份工具结果,三个职责)
|
||
|
||
```text
|
||
┌─ 第 1 层:canonical(Redis,TTL 2h,key=runId+toolCallId)────────┐
|
||
│ request + raw_response + agent_result + status + evidenceStatus │
|
||
│ 用途:EvidenceGuard 回读验真 / 短期完整真相 / 排查 │
|
||
├─ 第 2 层:Model Observation(Projector 有界投影,冻结契约)──────┤
|
||
│ 白名单 / 脱敏 / 截断,只含 Agent 下一步推理所需字段 │
|
||
│ 用途:服务模型推理(不给 raw,防上下文膨胀/prompt injection) │
|
||
├─ 第 3 层:Metadata Audit(MySQL 长期)────────────────────────────┤
|
||
│ 只存 identity/状态/耗时/token/bytes,无正文无 raw 副本 │
|
||
│ 用途:长期回放(配合 trace 时序线) │
|
||
└───────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
**三分字段**(一次调用):
|
||
|
||
```text
|
||
request = 我问了什么(模型入参)
|
||
raw_response = 工具回了什么(完整返回,存 canonical 不外发)
|
||
agent_result = 我能信什么 / 模型能看到什么(投影后有界,供推理 + 验真)
|
||
```
|
||
|
||
**为什么不能共用一份数据**:raw 直接给模型 → 上下文膨胀 + 敏感泄漏 + prompt injection;只存裁剪观察 → EvidenceGuard 无法独立验真;raw 永久进审计 → 制造敏感副本。三个目标冲突,所以真相、观察、元数据各存各的。
|
||
|
||
**关键事实**:MySQL 不存完整工具返回和 agent_result——`JpaToolInvocationAuditSink` 落库时只提取 `output_preview`(默认仅 status/evidence_status)和 `output_length`(字节长度)。TTL 过期后只能元数据回放。
|
||
|
||
## 4. 九域五段式面试讲法
|
||
|
||
每域固定叙事结构:**① 动机 → ② 决策 → ③ 实现 → ④ 边界 → ⑤ 话术**,外加高频追问。
|
||
|
||
### 4.1 core:执行控制
|
||
|
||
- **① 动机**:非确定性 Agent 执行时,身份归属、截止时间、预算、取消、终态必须确定——异步调用和多轮会话中,事实到底属于哪次执行?迟到结果能不能发布?
|
||
- **② 决策**:RunContext 显式传递(不用 ThreadLocal);唯一终态 first-terminal-wins。
|
||
- **③ 实现**:`checkActive` 三道闸(模型调用前/工具调用前/工具执行中逐行);取消广播(onCancel → future.cancel);deadline;RunBudget;预算耗尽/取消走终态。
|
||
- **④ 边界**:协作式取消——同步 Provider 计算未必立即停止;终态防迟到发布但不物理强杀。
|
||
- **⑤ 话术**:
|
||
> "core 管一次 Run 的确定性边界:显式 RunContext 跨线程传递(挂进 config metadata,防并发串线),first-terminal-wins 保证唯一终态——第一个写入的终态不可被迟到结果覆盖;checkActive 在模型前、工具前、工具执行中逐行检查,预算/取消/超时到点即 abort;取消是协作式的,逻辑终态和发布被保护,但同步 Provider 计算未必立即停。"
|
||
- **追问**:取消是强杀吗?(协作式,检查点中止 + 终态防迟到)RunContext 为什么显式?(跨线程 + 并发隔离)预算和 Ledger 区别?(Run 资源门禁 vs 审计账本)
|
||
|
||
### 4.2 retry:显式可计量重试
|
||
|
||
- **① 动机**:框架/Agent 自带的重试是盲目重试——同一请求无限重试、不计量、不可审计,一个不可靠的工具能把整个 Run 预算耗光。
|
||
- **② 决策**:重试权从框架收归 Harness,做成显式可计量的 attempt 循环。
|
||
- **③ 实现**:分类裁决(技术性失败可重试 / 业务性失败不重试);次数/时间/成本三重封顶;剩余超时递减(总超时耗尽不再重试);attempt 可审计。
|
||
- **④ 边界**:业务性失败不重试(重试也没用);SDK 关闭后由 Harness 全权控制。
|
||
- **⑤ 话术**:
|
||
> "重试归 Harness 因为它是成本行为:框架自带的盲目重试不可计量不可审计,Harness 做成显式 attempt 循环——技术性失败才重试、业务性失败不重试,次数/时间/成本三重封顶,每次尝试有分类有记录可审计。Agent 和 Tool 不重试,它们只负责执行,要不要再来一次由 Harness 裁决。"
|
||
- **追问**:为什么 Agent/Tool 不重试?(重试是成本裁决权,执行层只管执行)
|
||
|
||
### 4.3 progress:信息增益收敛
|
||
|
||
- **① 动机**:预算只能止损(不能继续消耗资源),不能判断「继续查是否有价值」——Agent 可能拿着通用知识、相似查询、空日志反复空转,最后撞预算。
|
||
- **② 决策**:预算之外的第二套停止机制——信息增益控制。
|
||
- **③ 实现**:GAINED/NO_GAIN 判定(结果是否推进诊断);重复检测;Tracker 双计数/pending;连续 NO_GAIN → SATURATED 饱和停止(软/硬停止);拦截器五道门。
|
||
- **④ 边界**:SATURATED 只停收集,不是 Run 终态;`READY + NO_EVIDENCE` 是成功执行但空结果,不是技术异常。
|
||
- **⑤ 话术**:
|
||
> "progress 是预算之外的第二套停止机制:预算管能不能继续消耗资源,progress 管继续查是否推进诊断。它用信息增益判定(GAINED/NO_GAIN)+ 重复检测 + 饱和停止——连续 NO_GAIN 就停,防止 Agent 拿通用知识或空日志空转;空查询(NO_EVIDENCE)也是被完整建模的负向观察,不是技术异常。"
|
||
- **追问**:Agent 为什么不会无限调用 Tool?(预算止损 + 信息增益收敛双保险)
|
||
|
||
### 4.4 tool:事实边界
|
||
|
||
- **① 动机**:工具是证据边界——能查什么、查到多少、看到什么必须封死;工具直接连数据库/检索库有破坏面。
|
||
- **② 决策**:ToolBoundary 统一执行规则 + canonical 存真相 + Projector 有界投影;数据三层分离。
|
||
- **③ 实现**:preflight 五项(run 匹配/授权/只读/JSON/key)失败不落库;预算门禁(beforeToolCall + bytes 三笔);canonical 状态机(PROJECTING→READY/ERROR);审计 best-effort;每类工具一个 Projector(严格校验 + 脱敏 + 截断)。
|
||
- **④ 边界**:不理解业务内容(投影交给 ToolResultProjector);不做信息增益判断(progress 的事);只允许 READY/ERROR 离开。
|
||
- **⑤ 话术**:
|
||
> "tool 域是证据边界:ToolBoundary 统一四项职责——preflight(run 匹配/授权/只读/JSON 合法性/key 生成,失败不落库)、预算门禁(Tool 预算 + request→raw→agent_result 三笔字节预留)、canonical 状态机(PROJECTING→READY/ERROR)、审计。执行结果分三层:完整真相存 Redis canonical(2h),有界投影给模型,长期审计只留元数据。它明确不做业务投影和信息增益判断——那是 Projector 和 progress 的事。"
|
||
- **追问**:Tool 结果为什么不直接给模型?(三层数据责任:推理/验真/留存冲突);MySQL 沙箱怎么防?(语义/连接/输出三层防线)
|
||
|
||
### 4.5 guard:证据安全链双闸
|
||
|
||
- **① 动机**:Agent 会撒谎——编造工具调用、夸大结论。不信任模型自述。
|
||
- **② 决策**:双闸分离——EvidenceGuard 机械验引用真实(规则、可审计、不调模型),SemanticGuard 隔离判结论支持度(无工具无记忆的单轮二值判断)。
|
||
- **③ 实现**:EvidenceGuard 三层校验(结构校验 → 逐条引用验真 key=runId+toolCallId 查账本 + isReferencableBy + kind 匹配 → 重读投影重建证据,20 个违规码);SemanticGuard 严格 schema(恰好 {verdict, reason})+ 预算/重试/取消全栈衔接。
|
||
- **④ 边界**:EvidenceGuard 只问引用真不真,不问语义;SemanticGuard 不能探索事实、不能改写报告。
|
||
- **⑤ 话术**:
|
||
> "防编造证据用双闸:EvidenceGuard 是机械验真——模型草稿里每个 tool_call_id 都要去 canonical 账本查到真实记录(key 绑定 runId 防跨 Run、记录必须 READY、kind 与证据语义匹配、投影内部自洽),纯规则可审计不调模型;SemanticGuard 是隔离语义审查——无工具、无记忆、单轮二值判断,只判结论是否被已验证证据支持,输出硬校验为 {verdict, reason} 两个字段。先机械后语义:引用假的直接拦,不浪费模型调用。"
|
||
- **追问**:为什么 EvidenceGuard 通过还要 SemanticGuard?(引用真实 ≠ 结论被支持:一个防编造证据,一个防夸大结论)
|
||
|
||
### 4.6 release:唯一发布点
|
||
|
||
- **① 动机**:模型输出的是未经证明的断言,不能直接当答案返回。
|
||
- **② 决策**:唯一发布点——SUCCESS 只有一条路径(验真过 + 语义支持),其余全降级 SafeFallback。
|
||
- **③ 实现**:三分支决策树(受控停止凭 progress 快照 / 无结论验引用按进展降级 / 有结论走 Evidence→Repair→Semantic 链);fail closed(无安全进展抛异常);EvidenceRepair 只修引用(prompt 锁死 + 语义不变性检查);SafeFallbackFactory 五种降级(有界/去重/诚实)。
|
||
- **④ 边界**:终态异常透传(取消/预算耗尽不伪装成业务 FALLBACK);SafeFallback conclusion 恒 null。
|
||
- **⑤ 话术**:
|
||
> "release 是唯一发布点:任何对外内容必须经过验证。它按 Draft 形态三分支——受控停止(无草稿)凭 progress 快照发布 INSUFFICIENT_EVIDENCE,且必须有已验真事实否则 fail closed;无结论只验引用按进展降级;有结论走完整链——EvidenceGuard 验引用,失败则 EvidenceRepair 只修引用(prompt 锁死只能改引用字段 + 语义不变性保证用户可见内容不变)再复查,仍失败降级 EVIDENCE_VALIDATION_FAILED;验真通过后 SemanticGuard 判支持度,SUPPORTED 是唯一 SUCCESS 出口,其余降级。所有降级走 SafeFallbackFactory:有界、去重、诚实,保留已验证事实但不发布未证明的根因。"
|
||
- **追问**:FALLBACK 算成功还是失败?(正交:可 RunState.SUCCESS + FALLBACK,是安全发布结果不是失败)
|
||
|
||
### 4.7 application:Run 应用所有者
|
||
|
||
- **① 动机**:一次请求从创建到公开结果需要编排:建 Run、路由、执行分支、持久化、SSE 输出。
|
||
- **② 决策**:ChatApplicationUseCase 六步编排,不做业务判断,不把 HTTP/SSE 细节塞 Core。
|
||
- **③ 实现**:startRun → 读会话上下文(RoutingHistory + PreviousTurn)→ 路由 → executePath 分支 → completePath + persistFinish;统一失败出口(terminalOutcome + safeFailure);取消句柄(CoreRunControl → core.cancel)。
|
||
- **④ 边界**:路由只给枚举不执行;预算耗尽的 FALLBACK 不二次 completeSuccess。
|
||
- **⑤ 话术**:
|
||
> "application 是 Run 的应用所有者:六步编排——建 Run 边界(core.startRun)、意图路由(单次模型调用、输出契约严格为 {intent} 枚举)、按意图分叉执行、路径完成后写终态并持久化发布契约,异常统一走失败出口映射成安全的 ChatFailureCode;取消能力通过 SSE 句柄暴露给客户端(断连即 core.cancel)。路由只回答走哪条分支,分支执行权在 executePath。"
|
||
- **追问**:多轮记忆怎么实现?(RoutingHistory + PreviousTurn,只传发布后的安全摘要)
|
||
|
||
### 4.8 audit:可观测账本(含 trace)
|
||
|
||
- **① 动机**:要能回放决策过程,又不永久保存敏感正文——两个目标冲突。
|
||
- **② 决策**:metadata-only + trace 时序线 + Token 对账账本;audit 是域,trace 是域内子体系。
|
||
- **③ 实现**:trace 17 种事件按 sequence_no 单调落 diagnosis_trace_event(七阶段:RUN/ROUTING/AGENT/TOOL/EVIDENCE/SEMANTIC/RELEASE);明细账本(agent_step/tool_invocation/agent_reasoning_audit/diagnosis_run)承载完整字段;Token 三写闭环(ledger 分账 → Run 预算 → agent_step 回写);DiagnosisTraceService 三级回放。
|
||
- **④ 边界**:审计不阻断主流程(fail-safe);正文只在受限审计表;TTL 过期后只能元数据回放。
|
||
- **⑤ 话术**:
|
||
> "audit 是可观测账本,trace 是它内部的事件回放子体系。trace 用一张表按 sequence_no 记录全链路七阶段的事件时序线(每帧只带摘要和关联键),明细账本(agent_step/tool_invocation/agent_reasoning_audit/diagnosis_run)承载完整字段,两层通过 step_id/run_id 互链不重复存储。三个边界:审计不阻断主流程(fail-safe)、metadata-only(正文只在受限审计表)、Token 三写闭环(ledger 分账→Run 预算→明细回写)。回放三级:时间线→明细→推理。"
|
||
- **追问**:audit 和 trace 什么关系?(包含关系:trace 是 audit 域内的时序事件流,audit 还含 ledger/工具审计/推理审计)
|
||
|
||
### 4.9 contract:状态流正交
|
||
|
||
- **① 动机**:技术停了不等于用户看到失败;查了没查到不等于系统出错——状态语义混在一个枚举里就糊了。
|
||
- **② 决策**:分层 + 正交 + 显式映射。
|
||
- **③ 实现**:11 个状态枚举五层(技术 RunState / 证据 InvocationStatus+EvidenceStatus / 收集 StopReason / 发布 ReleaseOutcome+FallbackType / 协议 ChatApplicationStatus+SseOutcome+ChatFailureCode);四个正交轴;纵向映射链。
|
||
- **④ 边界**:SSE 只有三态(取消连接已断发不出 done);SseOutcome 未接线;FallbackType.BUDGET_EXHAUSTED 命名债务。
|
||
- **⑤ 话术**:
|
||
> "状态设计核心是分层正交:RunState(技术终态)和 ReleaseOutcome(用户结局)是正交轴——预算耗尽有安全进展→FALLBACK、没进展→FAILED,同一技术终态诚实映射到不同用户结局;工具调用也是两个正交轴(InvocationStatus 生命周期 vs EvidenceStatus 证据语义),查了但空仍是成功执行。映射链:CANCELLED→CANCELLED+RUN_CANCELLED,SUPPORTED→SUCCESS 唯一出口;协议层(SSE)复用 ReleaseOutcome 三态拒绝 CANCELLED。"
|
||
- **追问**:这些状态为什么不合并成一个枚举?(不同层回答不同问题,正交后独立演进、映射显式可审计)
|
||
|
||
## 5. 六个易错点(带「为什么」)
|
||
|
||
| # | ❌ 不说 | ✅ 应说 | 为什么 |
|
||
|---|---|---|---|
|
||
| 1 | Harness 安排 Agent 执行步骤 | ReAct Agent 自己选 Tool 和下一步;Harness 只管边界 | 边界 ≠ 编排:Harness 不替 Agent 决定查什么 |
|
||
| 2 | SemanticGuard 是第二个诊断 Agent | 无 Tool、无记忆、单轮二值判断的隔离审查器 | 职责 ≠ 角色:它没有探索能力,判完就走 |
|
||
| 3 | Tool 返回 SUCCESS 就找到证据 | READY 只表示调用完成,还要看 EvidenceStatus | 生命周期 ≠ 证据:调完成功和有没有证据是两回事 |
|
||
| 4 | FALLBACK 就是 Run 失败 | Fallback 是安全发布结果,可 RunState.SUCCESS + FALLBACK | 技术 ≠ 用户:两个正交维度 |
|
||
| 5 | Redis 是长期审计库 | canonical 只存当前 Run 短期真相(TTL 2h);长期审计只留元数据 | 短期真相 ≠ 长期审计:可验真 vs 不留敏感副本 |
|
||
| 6 | 取消能立刻杀死所有模型调用 | 协作式取消:终态防迟到发布,同步 Provider 未必立即停 | 逻辑保护 ≠ 物理强杀:终态定了但线程未必立刻停 |
|
||
|
||
## 6. 高频追问应对大全
|
||
|
||
| 追问 | 回答主线 |
|
||
|---|---|
|
||
| 什么是 Harness?30 秒讲清 | 确定性控制边界:运行/事实/发布三层边界 |
|
||
| 为什么不用多 Agent? | 四角色加起来是一次 ReAct;推理合并、权力拆分 |
|
||
| 为什么 Harness 不是工作流引擎? | Agent 选择下一步,Harness 只检查边界和发布资格 |
|
||
| RunContext 为什么显式传递? | 跨线程异步链 + 并发隔离,ThreadLocal 会丢/串 |
|
||
| 取消是强杀吗? | 协作式:检查点中止 + first-terminal-wins 防迟到 |
|
||
| 预算和 Ledger 区别? | Run 资源门禁 vs 审计账本(不同域) |
|
||
| FALLBACK 算成功还是失败? | 正交:技术终态(RunState)与用户结局(ReleaseOutcome) |
|
||
| 重试为什么归 Harness? | 盲目重试不可计量;显式可计量 attempt 循环 |
|
||
| 为什么 Agent/Tool 不重试? | 重试是成本裁决权,执行层只管执行 |
|
||
| 如何防止 Agent 编造证据? | framework Tool ID + canonical store + EvidenceGuard |
|
||
| 为什么双闸? | 引用真实(机械)≠ 结论被支持(语义) |
|
||
| Tool 结果为什么不直接给模型? | 真相/观察/审计三个数据责任冲突 |
|
||
| Agent 为什么不会无限调 Tool? | 预算止损 + 信息增益收敛双保险 |
|
||
| Tool 报错是不是 Run 就失败? | 局部失败先看是否可继续及是否已有安全进展 |
|
||
| 如何回放决策? | metadata audit + trace 时序线 + 三级回放 |
|
||
| 当前还有什么限制? | 语义去重、TTL、同步取消、SemanticGuard 不确定性、阈值校准 |
|
||
|
||
## 7. 支付超时案例(2 分钟完整版)
|
||
|
||
> "用户要求诊断支付服务超时。Application 先创建独立 Run,为 Router、Agent、Tool、Guard 共享同一套 deadline、预算和取消能力。Diagnosis Agent 自主调用知识库和日志 Tool;ToolBoundary 执行调用并把完整事实保存为当前 Run 的 canonical invocation,只把有界 Observation 返回给 Agent。Agent 根据两个 Tool 结果生成 Draft,但 Draft 没有直接发给用户。EvidenceGuard 回读 canonical store 后发现引用无法完成真实性校验,因此 Release 没有继续让模型润色或猜测,而是发布 EVIDENCE_VALIDATION_FAILED SafeFallback。最终数据库记录请求处理成功、ReleaseOutcome 为 FALLBACK,SSE 也完整结束,但未经验证的根因没有离开系统。"
|
||
|
||
**三个不等于**:Tool READY ≠ 引用已验真 / 引用已验真 ≠ 结论被支持 / Agent 生成 Draft ≠ 报告允许发布。
|
||
|
||
## 8. 复习中纠正的认知清单(最容易踩的坑)
|
||
|
||
| 错误认知 | 纠正为 |
|
||
|---|---|
|
||
| Harness 顶层所以控制 retry/progress | 不只是位置——重试是成本行为必须可计量封顶;progress 解决「预算不能判断价值」 |
|
||
| RunContext 因为「回调」显式传 | 跨线程异步链 + 并发隔离;显式挂 config metadata |
|
||
| ToolBoundary 管 token/收敛/重试次数 | 那些归 core/retry/progress;ToolBoundary 只四项(preflight/预算/状态机/审计) |
|
||
| 工具失败抛异常 | ToolBoundary 转 ERROR 状态 + 错误观察,Agent 可继续换工具;Run 是否失败看 hasObservedFacts |
|
||
| FALLBACK 可能因超时 | 超时(TIMED_OUT)通常走 FAILED;FALLBACK 前提是有已验证事实 |
|
||
| agent_result 也存 MySQL | 不存——MySQL 只留 output_preview + output_length;完整 agent_result 在 Redis canonical(2h) |
|
||
| 注入 skill/知识域给 agent | 注入的是 query + PreviousTurn + 系统 prompt;知识靠工具主动查 |
|
||
| 非法 draft 由 release 捕捉 | 反序列化在 agent 出口(recoverInvalidDraft);release 只做验证+裁决 |
|
||
| preflight 失败也落库 | 失败不落库(errorAndNoRecord)——只有 preflight 全过才写 PROJECTING |
|
||
| 多 Agent 一定不好 | 只有不同数据权限/独立业务目标的角色才值得拆;拆 ReAct 内部步骤只会放大协议成本 |
|
||
|
||
## 9. 面试前一天 Checklist
|
||
|
||
```text
|
||
□ 30 秒电梯陈述背熟(§2.1),三个重点不丢(§2.3)
|
||
□ 默画三张白板图(§3):主链路含分支 / 职责迁移对照 / 数据三层
|
||
□ 六个易错点扫一遍(§5)——重点看「为什么」列
|
||
□ 九域话术:挑 3 个最可能被追问的(guard/release/contract)背熟
|
||
□ 2 分钟支付超时案例 + 三个不等于(§7)
|
||
□ 过一遍纠正认知清单(§8)——这些是踩过的坑
|
||
□ 读一遍面试速查 §7 追问表,心里有数
|
||
```
|
||
|
||
## 10. 代码位置索引
|
||
|
||
| 组件 | 文件 |
|
||
|---|---|
|
||
| ToolBoundary(preflight/预算/状态机/审计) | `src/main/java/com/superbiz/agent/harness/tool/boundary/ToolBoundary.java` |
|
||
| JpaToolInvocationAuditSink(output_preview 落库) | `.../audit/JpaToolInvocationAuditSink.java` |
|
||
| DiagnosisAgentUseCase(RunContext 挂 config metadata) | `.../agent/DiagnosisAgentUseCase.java` |
|
||
| EvidenceGuard / SemanticGuard | `.../guard/evidence/` + `.../guard/semantic/` |
|
||
| DiagnosisReleaseUseCase / EvidenceRepair / SafeFallbackFactory | `.../release/` |
|
||
| DiagnosisProgressProjector / Tracker / Snapshot | `.../progress/` |
|
||
| ChatApplicationUseCase / IntentRouter | `.../application/` |
|
||
| DiagnosisTraceService / DiagnosisTraceController | `.../service/` + `.../controller/` |
|
||
| 状态枚举(RunState/ReleaseOutcome/FallbackType/...) | `.../contract/` + `.../core/RunState.java` |
|