docs(harness): add loop inner/outer exception handling guide
This commit is contained in:
@@ -0,0 +1,468 @@
|
|||||||
|
# Harness 异常处理:Loop 内 vs Loop 外
|
||||||
|
|
||||||
|
**日期**:2026-07-30
|
||||||
|
**范围**:诊断路径(`intent=DIAGNOSIS`)上 ReactAgent ReAct 循环内外的异常、受控停止、降级与终态
|
||||||
|
**读者**:已读 E2E 全流程 / 运行控制,需要把「失败时系统到底怎么走」串成一张图
|
||||||
|
|
||||||
|
**关联文档**:
|
||||||
|
|
||||||
|
- [Harness 失败图谱](./Harness失败图谱-异常-停止-降级与终态.md)(失败类型总览)
|
||||||
|
- [Harness 生命周期与状态](./Harness生命周期与状态.md)(RunState / CollectionState)
|
||||||
|
- [信息增益停止](./Harness信息增益停止-让无证据诊断正常收敛.md)(SATURATED / STOP_REQUIRED)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 先记住一张总图
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph app["Application 编排"]
|
||||||
|
UC[ChatApplicationUseCase]
|
||||||
|
EX[DiagnosisChatExecutor]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph agent["Agent 用例"]
|
||||||
|
UC2[DiagnosisAgentUseCase]
|
||||||
|
CE[controlledExecution]
|
||||||
|
RF[recoverInvalidDraft]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph loop["ReactAgent ReAct Loop"]
|
||||||
|
MI[HarnessModelInterceptor]
|
||||||
|
LLM[ChatModel]
|
||||||
|
TI[HarnessToolInterceptor]
|
||||||
|
TB[ToolBoundary]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph release["Release"]
|
||||||
|
REL[DiagnosisReleaseUseCase]
|
||||||
|
FB[SafeFallback / FALLBACK]
|
||||||
|
OK[SUCCESS 报告]
|
||||||
|
end
|
||||||
|
|
||||||
|
UC --> EX
|
||||||
|
EX --> UC2
|
||||||
|
UC2 -->|agent.call| loop
|
||||||
|
MI --> LLM
|
||||||
|
LLM -->|tool_call| TI
|
||||||
|
TI --> TB
|
||||||
|
TB -->|observation| LLM
|
||||||
|
|
||||||
|
loop -->|受控异常穿出| CE
|
||||||
|
CE -->|stopped draft=null| REL
|
||||||
|
loop -->|正常返回坏 draft| UC2
|
||||||
|
UC2 -->|DiagnosisAgentOutputException| RF
|
||||||
|
RF -->|有 observedFacts| REL
|
||||||
|
REL --> FB
|
||||||
|
REL --> OK
|
||||||
|
CE -->|取消/超时再抛| UC
|
||||||
|
RF -->|无 facts 再抛| UC
|
||||||
|
```
|
||||||
|
|
||||||
|
**一句话**:
|
||||||
|
|
||||||
|
| 区域 | 异常怎么处理 |
|
||||||
|
|------|----------------|
|
||||||
|
| **Loop 内** | 多数变成 **tool/model 侧 observation 或拦截**;少数 **受控异常穿出 loop** |
|
||||||
|
| **Loop 边界** | `controlledExecution`:受控停止 → `stopped`;不可控 → 包装/再抛 |
|
||||||
|
| **Loop 外(Executor)** | `recoverInvalidDraft`:坏 draft + 有事实 → FALLBACK;否则失败 |
|
||||||
|
| **Release** | 有 draft 走 Guard;无 draft / 非法 draft 走专用降级 |
|
||||||
|
| **Application** | 未消化异常 → `ChatFailureCode` + Run 终态落库 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 状态有三层,不要混
|
||||||
|
|
||||||
|
异常处理会同时碰到三套状态,职责不同:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph core["Core 执行面"]
|
||||||
|
RS[RunState<br/>RUNNING / SUCCESS / FAILED<br/>CANCELLED / TIMED_OUT / BUDGET_EXHAUSTED]
|
||||||
|
end
|
||||||
|
subgraph prog["Progress 收集面"]
|
||||||
|
CS[CollectionState<br/>COLLECTING / SATURATED]
|
||||||
|
SR[DiagnosisStopReason]
|
||||||
|
end
|
||||||
|
subgraph out["对外发布面"]
|
||||||
|
RO[ReleaseOutcome<br/>SUCCESS / FALLBACK / FAILED / CANCELLED]
|
||||||
|
FT[FallbackType]
|
||||||
|
CF[ChatFailureCode]
|
||||||
|
end
|
||||||
|
RS -.->|"预算耗尽可并存"| RO
|
||||||
|
SR -.->|"有 facts 常映射"| FT
|
||||||
|
RO -.->|"失败粗码"| CF
|
||||||
|
```
|
||||||
|
|
||||||
|
| 层 | 枚举 | 回答的问题 |
|
||||||
|
|----|------|------------|
|
||||||
|
| Core | `RunState` | 这次 Run 技术上还能不能继续? |
|
||||||
|
| Progress | `DiagnosisStopReason` / `CollectionState` | 证据收集为何停、是否已饱和? |
|
||||||
|
| 发布 | `ReleaseOutcome` / `FallbackType` | 用户看到报告、降级还是失败? |
|
||||||
|
| 协议失败 | `ChatFailureCode` | SSE failure 的粗粒度原因? |
|
||||||
|
|
||||||
|
**典型组合**:
|
||||||
|
|
||||||
|
| 场景 | RunState | StopReason | ReleaseOutcome |
|
||||||
|
|------|----------|------------|----------------|
|
||||||
|
| 正常成功 | SUCCESS | — | SUCCESS |
|
||||||
|
| 信息饱和且有事实 | 常仍可 SUCCESS 收尾* | INFORMATION_SATURATED | FALLBACK / INSUFFICIENT_EVIDENCE |
|
||||||
|
| 预算耗尽且有事实 | BUDGET_EXHAUSTED | BUDGET_LIMIT_REACHED | FALLBACK / INSUFFICIENT_EVIDENCE |
|
||||||
|
| 预算耗尽且无事实 | BUDGET_EXHAUSTED | BUDGET_LIMIT_REACHED | FAILED |
|
||||||
|
| 客户端断开 | CANCELLED | — | CANCELLED / 可能无 done |
|
||||||
|
|
||||||
|
\*饱和后若 Agent 合法写完 draft 并过 Guard,也可能 SUCCESS;若 stopped 无 draft 则走 FALLBACK。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 架构位置:异常在哪一层被「接住」
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
subgraph L0["L0 协议"]
|
||||||
|
CTRL[ChatController / SSE]
|
||||||
|
end
|
||||||
|
subgraph L1["L1 Application"]
|
||||||
|
APP[ChatApplicationUseCase<br/>统一 catch → ChatFailureCode]
|
||||||
|
DEX[DiagnosisChatExecutor<br/>recoverInvalidDraft]
|
||||||
|
end
|
||||||
|
subgraph L2["L2 Agent 用例"]
|
||||||
|
DAU[DiagnosisAgentUseCase<br/>controlledExecution]
|
||||||
|
end
|
||||||
|
subgraph L3["L3 框架 Loop"]
|
||||||
|
RA[ReactAgent.call]
|
||||||
|
end
|
||||||
|
subgraph L4["L4 Interceptor / Boundary"]
|
||||||
|
MI[ModelInterceptor]
|
||||||
|
TI[ToolInterceptor]
|
||||||
|
TB[ToolBoundary]
|
||||||
|
CORE[DiagnosisHarnessCore]
|
||||||
|
end
|
||||||
|
|
||||||
|
CTRL --> APP --> DEX --> DAU --> RA
|
||||||
|
RA --> MI --> CORE
|
||||||
|
RA --> TI --> TB --> CORE
|
||||||
|
|
||||||
|
MI -.->|BudgetExceeded / RunAborted 上抛| DAU
|
||||||
|
TI -.->|多数 error observation 留在 loop| RA
|
||||||
|
TI -.->|CollectionStopped 上抛| DAU
|
||||||
|
DAU -.->|stopped| DEX
|
||||||
|
DAU -.->|Draft 契约异常| DEX
|
||||||
|
DEX -.->|未恢复| APP
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Loop 内:一次 ReAct 轮次里发生什么
|
||||||
|
|
||||||
|
### 3.1 正常成功路径(对照)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant DAU as DiagnosisAgentUseCase
|
||||||
|
participant RA as ReactAgent
|
||||||
|
participant MI as ModelInterceptor
|
||||||
|
participant LLM as ChatModel
|
||||||
|
participant TI as ToolInterceptor
|
||||||
|
participant TB as ToolBoundary
|
||||||
|
|
||||||
|
DAU->>RA: agent.call(input, config)
|
||||||
|
RA->>MI: interceptModel
|
||||||
|
MI->>MI: beforeModelCall 预算闸
|
||||||
|
MI->>LLM: handler.call
|
||||||
|
LLM-->>MI: tool_call
|
||||||
|
MI-->>RA: ModelResponse
|
||||||
|
RA->>TI: interceptToolCall
|
||||||
|
TI->>TI: 协议/重复/饱和检查
|
||||||
|
TI->>TB: invoke
|
||||||
|
TB-->>TI: READY + agentResult
|
||||||
|
TI-->>RA: 投影 observation
|
||||||
|
RA->>MI: interceptModel 第 2 轮
|
||||||
|
MI->>LLM: 写 Draft
|
||||||
|
LLM-->>MI: 文本 JSON
|
||||||
|
MI-->>RA: ModelResponse
|
||||||
|
RA-->>DAU: AssistantMessage
|
||||||
|
DAU->>DAU: 解析 DiagnosisDraft
|
||||||
|
DAU-->>DAU: completed(draft, progress)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 Loop 内:Model 路径异常(会穿出 loop)
|
||||||
|
|
||||||
|
**触发点**:`HarnessModelInterceptor.interceptModel`
|
||||||
|
|
||||||
|
```text
|
||||||
|
beforeModelCall / handler.call / checkActive
|
||||||
|
→ BudgetExceededException
|
||||||
|
→ RunAbortedException(已终态、超时、取消)
|
||||||
|
→ 其它 RuntimeException(供应商错误等)
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant RA as ReactAgent
|
||||||
|
participant MI as ModelInterceptor
|
||||||
|
participant Core as DiagnosisHarnessCore
|
||||||
|
participant DAU as DiagnosisAgentUseCase
|
||||||
|
|
||||||
|
RA->>MI: interceptModel(第 N 次模型)
|
||||||
|
MI->>Core: beforeModelCall
|
||||||
|
Core-->>MI: throw BudgetExceeded / RunAborted
|
||||||
|
Note over MI: 不吞异常,不转 observation
|
||||||
|
MI-->>RA: 异常上抛
|
||||||
|
RA-->>DAU: agent.call 失败
|
||||||
|
DAU->>DAU: controlledExecution(e)
|
||||||
|
```
|
||||||
|
|
||||||
|
| 异常 | Loop 内是否消化 | 穿出后 |
|
||||||
|
|------|-----------------|--------|
|
||||||
|
| `BudgetExceededException` | 否 | → `stopped(BUDGET_LIMIT_REACHED)` |
|
||||||
|
| `RunAbortedException(BUDGET_EXHAUSTED)` | 否 | → 同上 |
|
||||||
|
| `RunAbortedException(CANCELLED/TIMED_OUT/…)` | 否 | controlledExecution **再抛** → Application |
|
||||||
|
| 其它未识别 | 否 | → `DiagnosisAgentOutputException(EXECUTION_FAILED)` |
|
||||||
|
|
||||||
|
### 3.3 Loop 内:Tool 路径(多数不穿出)
|
||||||
|
|
||||||
|
**触发点**:`HarnessToolInterceptor.interceptToolCall` + `ToolBoundary`
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
TC[收到 tool_call] --> SUP{是否证据工具?}
|
||||||
|
SUP -->|否| H[handler.call 旁路]
|
||||||
|
SUP -->|是| SAT{已 SATURATED 且 stop 已交付?}
|
||||||
|
SAT -->|是| EX[throw DiagnosisCollectionStoppedException]
|
||||||
|
SAT -->|否| PARSE[解析 Envelope / previous_observation]
|
||||||
|
PARSE -->|协议违规| REP[可修复 error observation<br/>或连续违规后 stop]
|
||||||
|
PARSE --> DUP{重复 scope?}
|
||||||
|
DUP -->|是| DUPR[DUPLICATE_SCOPE observation]
|
||||||
|
DUP -->|否| INV[ToolBoundary.invoke]
|
||||||
|
INV -->|READY| OBS[投影 modelObservation 回注]
|
||||||
|
INV -->|BUDGET_EXHAUSTED 等 error| ERR[error observation<br/>markBudgetLimitReached]
|
||||||
|
EX --> OUT[穿出 ReactAgent loop]
|
||||||
|
OBS --> LOOP[留在 loop,模型继续]
|
||||||
|
ERR --> LOOP
|
||||||
|
REP --> LOOP
|
||||||
|
DUPR --> LOOP
|
||||||
|
```
|
||||||
|
|
||||||
|
**设计选择**:
|
||||||
|
|
||||||
|
| 情况 | 策略 | 原因 |
|
||||||
|
|------|------|------|
|
||||||
|
| 工具执行失败、投影失败、结果过大 | **error observation 留在 loop** | 给模型一次感知/改写机会,不立刻整 run 崩 |
|
||||||
|
| 预算在 ToolBoundary 触顶 | **先 error observation** + progress 标记预算 | 本轮不强制撕开 loop;下一轮 model 的 `beforeModelCall` 会硬闸 |
|
||||||
|
| 信息饱和后仍要工具 | **`DiagnosisCollectionStoppedException` 穿出** | 收集已无价值,禁止空转 |
|
||||||
|
| 协议违规(未达阈值) | **repairable error observation** | 要求模型补 previous_observation 等 |
|
||||||
|
|
||||||
|
`ToolBoundary` 对预算的处理(**吞异常 → 错误码**,不抛给框架):
|
||||||
|
|
||||||
|
```text
|
||||||
|
catch (RunAbortedException | BudgetExceededException)
|
||||||
|
→ ToolBoundaryResult.error(BUDGET_EXHAUSTED | RUN_INACTIVE)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Loop 边界:`controlledExecution`
|
||||||
|
|
||||||
|
**位置**:`DiagnosisAgentUseCase`,包住 `agent.call(...)`。
|
||||||
|
|
||||||
|
**职责**:把「Harness 约定的受控停止」从异常栈(含 cause 链)捞出来,转成 **`DiagnosisAgentExecution.stopped`**;其余失败交给外层。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
E[catch Exception from agent.call] --> F1{cause 含 CollectionStopped?}
|
||||||
|
F1 -->|是| S1[stopped progress + stopReason]
|
||||||
|
F1 -->|否| F2{cause 含 RunAborted?}
|
||||||
|
F2 -->|是且 BUDGET_EXHAUSTED| S2[markBudgetLimitReached<br/>stopped BUDGET_LIMIT_REACHED]
|
||||||
|
F2 -->|是且其它终态| R1[再抛 RunAborted]
|
||||||
|
F2 -->|否| F3{BudgetExceeded 或 lifecycle 已预算耗尽?}
|
||||||
|
F3 -->|是| S2
|
||||||
|
F3 -->|否| N[return null]
|
||||||
|
N --> W[包装 DiagnosisAgentOutputException EXECUTION_FAILED]
|
||||||
|
S1 --> RET[正常 return 给 Executor]
|
||||||
|
S2 --> RET
|
||||||
|
```
|
||||||
|
|
||||||
|
| 输入信号 | 输出 |
|
||||||
|
|----------|------|
|
||||||
|
| `DiagnosisCollectionStoppedException` | `stopped(stopReason)`,`draft=null` |
|
||||||
|
| 预算耗尽类 | `stopped(BUDGET_LIMIT_REACHED)` |
|
||||||
|
| 取消 / 超时类 `RunAborted` | **不转 stopped,再抛** |
|
||||||
|
| 未知 | `null` → 包装执行失败异常 |
|
||||||
|
|
||||||
|
**结果形态**:
|
||||||
|
|
||||||
|
```text
|
||||||
|
completed(draft, progress) // 有合法草稿
|
||||||
|
stopped(progress, stopReason) // 无草稿,仅有进度快照
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Loop 外:坏 Draft 与 `recoverInvalidDraft`
|
||||||
|
|
||||||
|
**时机**:`agent.call` **已经返回**(或解析阶段),最终文本 **不是**合法 `DiagnosisDraft`。
|
||||||
|
|
||||||
|
**位置**:`DiagnosisChatExecutor` catch `DiagnosisAgentOutputException`。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A[DiagnosisAgentOutputException] --> K{isDraftContractFailure?}
|
||||||
|
K -->|否 EXECUTION_FAILED| P1[再抛 → Application FAILED]
|
||||||
|
K -->|是 EMPTY/INVALID_JSON/SCHEMA| H{hasObservedFacts?}
|
||||||
|
H --> AUD[审计 agentDraftInvalid]
|
||||||
|
AUD --> H2{hasObservedFacts?}
|
||||||
|
H2 -->|否| P1
|
||||||
|
H2 -->|是| SSE[status SAFETY_VALIDATING]
|
||||||
|
SSE --> RID[releaseInvalidDraft progress]
|
||||||
|
RID --> FB[FALLBACK INSUFFICIENT_EVIDENCE]
|
||||||
|
```
|
||||||
|
|
||||||
|
要点(与常见误解对照):
|
||||||
|
|
||||||
|
| 误解 | 实际 |
|
||||||
|
|------|------|
|
||||||
|
| recover 里再验 draft 完不完整 | draft 合法性已在 Agent 用例判定;此处只看 **异常 Kind** |
|
||||||
|
| hasProgress = 有过 tool_call | = **`progress.observedFacts` 非空**(可发布观察事实) |
|
||||||
|
| 降级会带上坏 JSON | **丢弃非法正文**,只根据 progress 生成 SafeFallback |
|
||||||
|
|
||||||
|
**专用发布**:`DiagnosisReleaseUseCase.releaseInvalidDraft`
|
||||||
|
|
||||||
|
- 不再跑 Evidence/Semantic Guard(没有可校验 draft)
|
||||||
|
- 要求 `hasObservedFacts()`,否则 `IllegalStateException`
|
||||||
|
- 产出 `FallbackType.INSUFFICIENT_EVIDENCE`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Release:按 execution 形态分叉
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
EX[DiagnosisAgentExecution] --> D{draft == null?}
|
||||||
|
D -->|是 stopped| CS[releaseControlledStop<br/>需有 observedFacts]
|
||||||
|
D -->|否| C{conclusion == null?}
|
||||||
|
C -->|是| NC[releaseNoConclusion<br/>部分 Evidence + progress]
|
||||||
|
C -->|否| RC[releaseConclusion<br/>Evidence → 可选 Repair → Semantic]
|
||||||
|
CS --> FB[FALLBACK]
|
||||||
|
NC --> FB
|
||||||
|
RC -->|SUPPORTED| OK[SUCCESS]
|
||||||
|
RC -->|其它| FB
|
||||||
|
```
|
||||||
|
|
||||||
|
| 入口 | 典型来源 |
|
||||||
|
|------|----------|
|
||||||
|
| `releaseControlledStop` | `controlledExecution` → stopped |
|
||||||
|
| `releaseInvalidDraft` | `recoverInvalidDraft`(loop 结束坏 draft) |
|
||||||
|
| `releaseConclusion` | 正常 completed + 有结论 |
|
||||||
|
| `releaseNoConclusion` | draft 合法但无 conclusion |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Application 统一失败出口
|
||||||
|
|
||||||
|
未被转成 FALLBACK / SUCCESS 的异常,进入 `ChatApplicationUseCase`:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant EX as DiagnosisChatExecutor
|
||||||
|
participant APP as ChatApplicationUseCase
|
||||||
|
participant Core as DiagnosisHarnessCore
|
||||||
|
participant Store as ChatRunStore
|
||||||
|
participant SSE as ChatSseSession
|
||||||
|
|
||||||
|
EX-->>APP: 抛 ChatApplicationException 或 RuntimeException
|
||||||
|
APP->>Core: terminalOutcome / completeFailure
|
||||||
|
APP->>Store: finish(terminal, ...)
|
||||||
|
APP->>APP: safeFailure → ChatFailureCode
|
||||||
|
APP-->>SSE: fail(code, 安全文案)
|
||||||
|
```
|
||||||
|
|
||||||
|
常见映射直觉:
|
||||||
|
|
||||||
|
| 情况 | ChatFailureCode 倾向 |
|
||||||
|
|------|----------------------|
|
||||||
|
| 取消 | `RUN_CANCELLED` |
|
||||||
|
| 路由失败 | `ROUTING_UNAVAILABLE` |
|
||||||
|
| 落库失败 | `RUN_PERSISTENCE_FAILED` |
|
||||||
|
| 其它 | `INTERNAL_FAILURE` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 端到端对照表(按场景)
|
||||||
|
|
||||||
|
| # | 场景 | 发生位置 | 关键信号 | 第一处理点 | 用户侧 |
|
||||||
|
|---|------|----------|----------|------------|--------|
|
||||||
|
| 1 | 第 N 次模型前预算没了 | Loop 内 Model | `BudgetExceeded` | controlledExecution → stopped | 有 facts→FALLBACK;无→FAILED |
|
||||||
|
| 2 | 工具执行失败 | Loop 内 Tool | `TOOL_EXECUTION_ERROR` observation | 留在 loop | 模型可能改写或再试 |
|
||||||
|
| 3 | 工具触顶预算 | Loop 内 ToolBoundary | error + markBudget | 常留在 loop,下轮 model 硬闸 | 同预算结局 |
|
||||||
|
| 4 | 饱和后仍要工具 | Loop 内 Tool | `DiagnosisCollectionStopped` | controlledExecution → stopped | 有 facts→FALLBACK |
|
||||||
|
| 5 | 取消/超时 | Core → 任意 checkActive | `RunAborted` | controlledExecution **再抛** | CANCELLED / FAILED |
|
||||||
|
| 6 | 模型返回烂 JSON | Loop 外解析 | `INVALID_JSON` 等 | recoverInvalidDraft | 有 facts→FALLBACK;无→FAILED |
|
||||||
|
| 7 | 执行崩溃未识别 | Loop 边界 | `EXECUTION_FAILED` | recover 不恢复,上抛 | FAILED |
|
||||||
|
| 8 | Guard 引用失败 | Loop 外 Release | Evidence 违规 | repair 或 FALLBACK | FALLBACK EVIDENCE_* |
|
||||||
|
| 9 | 语义不支持 | Loop 外 Release | UNSUPPORTED | FALLBACK | FALLBACK SEMANTIC_* |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 两条主恢复路径对比(必记)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph mid["Loop 中途打断"]
|
||||||
|
A1[Interceptor / Core 异常] --> B1[controlledExecution]
|
||||||
|
B1 --> C1[stopped draft=null]
|
||||||
|
C1 --> D1[releaseControlledStop]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph end["Loop 正常结束但输出坏"]
|
||||||
|
A2[解析 Draft 失败] --> B2[DiagnosisAgentOutputException]
|
||||||
|
B2 --> C2[recoverInvalidDraft]
|
||||||
|
C2 --> D2[releaseInvalidDraft]
|
||||||
|
end
|
||||||
|
|
||||||
|
D1 --> E[INSUFFICIENT_EVIDENCE FALLBACK<br/>前提 hasObservedFacts]
|
||||||
|
D2 --> E
|
||||||
|
```
|
||||||
|
|
||||||
|
| | `controlledExecution` | `recoverInvalidDraft` |
|
||||||
|
|--|----------------------|------------------------|
|
||||||
|
| 时机 | loop **中途** | loop **结束后** |
|
||||||
|
| 输入 | `Throwable` cause 链 | `DiagnosisAgentOutputException` |
|
||||||
|
| 成功产物 | `Execution.stopped` | 直接 `DiagnosisExecutionResult(FALLBACK)` |
|
||||||
|
| 发布入口 | `releaseControlledStop` | `releaseInvalidDraft` |
|
||||||
|
| 共同点 | 都依赖 **可发布 observedFacts**;都 **fail closed** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 代码索引
|
||||||
|
|
||||||
|
| 组件 | 路径 |
|
||||||
|
|------|------|
|
||||||
|
| Model 拦截 | `harness/agent/HarnessModelInterceptor.java` |
|
||||||
|
| Tool 拦截 | `harness/agent/HarnessToolInterceptor.java` |
|
||||||
|
| 工具边界 | `harness/tool/boundary/ToolBoundary.java` |
|
||||||
|
| 受控停止转换 | `harness/agent/DiagnosisAgentUseCase#controlledExecution` |
|
||||||
|
| 坏 Draft 恢复 | `harness/application/executor/DiagnosisChatExecutor#recoverInvalidDraft` |
|
||||||
|
| 非法 draft 发布 | `harness/release/DiagnosisReleaseUseCase#releaseInvalidDraft` |
|
||||||
|
| 受控停止发布 | `DiagnosisReleaseUseCase#releaseControlledStop` |
|
||||||
|
| 应用失败出口 | `harness/application/ChatApplicationUseCase` |
|
||||||
|
| 错误码注释 | `ChatFailureCode` / `ReleaseOutcome` / `FallbackType` / `RunState` / `DiagnosisStopReason` / `ToolBoundaryErrorCode` 等 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 阅读检查清单
|
||||||
|
|
||||||
|
1. 这个失败是 **还在 loop 里**,还是 **已经穿出 agent.call**?
|
||||||
|
2. 是 **资源/取消**(Core),还是 **收集收敛**(Progress),还是 **输出契约**(Draft Kind)?
|
||||||
|
3. 最终有没有 **`observedFacts`**?有才能谈 FALLBACK。
|
||||||
|
4. `RunState` 与 `ReleaseOutcome` 是否一致理解(预算耗尽 ≠ 一定 FAILED)?
|
||||||
|
5. Tool 错误是 **observation** 还是 **异常穿出**?不要默认「有 error 就崩 run」。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 一句话总结
|
||||||
|
|
||||||
|
> **Loop 内:能安全回注的变成 observation,必须停收集或硬预算的穿出异常。**
|
||||||
|
> **Loop 边界:controlledExecution 把受控停止收成 stopped。**
|
||||||
|
> **Loop 外:坏 draft 用 recoverInvalidDraft,只认 observedFacts 做降级。**
|
||||||
|
> **全程 fail closed:没有可验证事实,就不发「看起来友好」的假成功。**
|
||||||
@@ -63,6 +63,11 @@ flowchart TB
|
|||||||
|
|
||||||
| 当你想知道 | 再阅读 |
|
| 当你想知道 | 再阅读 |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
| 准备面试,想用一张图快速复习完整设计 | [Harness 面试速查](Harness面试速查-一张图讲清设计.md) |
|
||||||
|
| 想看 Harness 如何处理一次真实支付超时诊断 | [支付超时诊断案例](案例-从一次支付超时诊断看Harness如何控制Agent.md) |
|
||||||
|
| 想知道这套设计如何从多 Agent 和 StateGraph 演进而来 | [Harness 设计演进](Harness设计演进-从多Agent编排到确定性控制边界.md) |
|
||||||
|
| 想知道异常、停止、降级和最终状态如何对应 | [Harness 失败图谱](Harness失败图谱-异常-停止-降级与终态.md) |
|
||||||
|
| 想分清 ReactAgent loop 内外异常怎么走、和状态如何对应 | [Loop 内外异常处理](Harness异常处理-Loop内外与状态流.md) |
|
||||||
| 想逐步认识 Harness 的各组组件 | [组件渐进式导读](components/README.md) |
|
| 想逐步认识 Harness 的各组组件 | [组件渐进式导读](components/README.md) |
|
||||||
| 为什么选这种控制边界,而不是工作流编排 | [Harness 主设计](Harness设计-非确定性Agent的确定性控制边界.md) |
|
| 为什么选这种控制边界,而不是工作流编排 | [Harness 主设计](Harness设计-非确定性Agent的确定性控制边界.md) |
|
||||||
| 一次请求从开始到结束经历什么 | [生命周期与状态](Harness生命周期与状态.md) |
|
| 一次请求从开始到结束经历什么 | [生命周期与状态](Harness生命周期与状态.md) |
|
||||||
|
|||||||
Reference in New Issue
Block a user