# FDE W5D3 评测题 · 超时、重试与退避、补偿

> 配套手册：《FDE-W5D3-超时重试退避补偿-学习手册.html》
> 满分约 117 分。L1 基础(24) / L2 进阶(36) / L3 深度(40) / L4 场景(17)。
> 评分建议：L1≥20、L2≥30、L3≥32、L4≥14 为各档达标；总分 ≥93（约 80%）为本次达标线。

---

## L1 基础（Q1–Q3，各 8 分，共 24 分）

### Q1. 为什么要给工具调用设超时？超时后只"返回错误"够吗？
- **考察点**：工具超时的目的。
- **评分维度**：防无限等待/资源挂死（3 分）；不同工具不同超时（2 分）；超时后还要取消+决策（3 分）。
- **参考方向**：防下游无响应挂死；按 P99 压测留余量；超时后取消底层请求并决定重试/换路/转人工，不能静默丢弃。

<details>
<summary>参考答案</summary>

为什么设超时：防止下游无响应时调用方无限等待、连接/线程被挂死，保护整体可用性。
只返回错误不够：超时后必须（1）真正取消底层请求（关闭连接），否则"超时返回但后台还跑"造成泄漏；（2）决定后续——重试 / 换路 / 转人工，不能静默丢弃让用户白等。
设值：按工具不同（缓存 200ms、外部接口 5s），按 P99 延迟压测留余量（如 P99×1.5），太长失去保护、太短误杀慢正常调用。
</details>

### Q2. 单工具超时和整体 Agent 超时是什么关系？
- **考察点**：超时层次。
- **评分维度**：单工具超时的作用（2 分）；整体超时的作用（2 分）；层次关系+配合（2 分）；都用绝对 deadline（2 分）。
- **参考方向**：单工具超时管单个下游调用，整体超时（时间预算）管整个 Loop 更上层；两者配合；中断要可恢复（Checkpointer）。

<details>
<summary>参考答案</summary>

- **单工具超时**：保护单个下游调用，超时返回受控错误，Agent 决策重试/换路。
- **整体 Agent 超时（时间预算）**：保护整个 Loop/连接/线程，超时中断循环进入优雅结束（PARTIAL）。更上层。
关系：单工具超时兜底慢工具，整体超时兜底整个循环卡死，缺一不可。两者都用绝对 deadline（now+budget）每轮检查，不靠累加（累加因调度抖动不准）。整体超时中断要安全——已做状态能恢复（Checkpointer）。
</details>

### Q3. 哪些错误可以重试，哪些不可以？各举一例。
- **考察点**：可重试性判断。
- **评分维度**：可重试类+例子（网络/429/偶发5xx，3 分）；不可重试类+例子（业务校验/状态冲突，3 分）；判断核心"是否瞬时"（2 分）。
- **参考方向**：可重试=瞬时错误；不可重试=业务校验失败（参数错/无权限/已结案）；核心是"失败是否暂时、重试能否成功"。

<details>
<summary>参考答案</summary>

可重试（瞬时错误）：网络超时/连接失败、429 限流、偶发 5xx。例：医保接口 504，稍后重试可能已过。
不可重试（输入/状态问题）：业务校验失败（参数不合法、无权限）、领域状态冲突。例：保单号不存在、理赔已结案不能再提交——重试一万次还是错，要改输入或转人工。
判断核心：这次失败是"暂时的、重试后可能成功"吗？是才重试。
</details>

---

## L2 进阶（Q4–Q7，各 9 分，共 36 分）

### Q4. 指数退避公式是什么？为什么必须加"上限 cap"和"抖动 jitter"？
- **考察点**：退避机制。
- **评分维度**：公式（2 分）；上限作用（防等太久/超整体超时，3 分）；抖动作用（打散同步重试防风暴，4 分）。
- **参考方向**：sleep=base×2^(n-1)+random(0,jitter) 且 cap；上限防退避太久触发整体超时；抖动防集体同步重试打垮下游。

<details>
<summary>参考答案</summary>

公式：delay = min(cap, base × 2^(attempt-1)) + random(0, jitter)。如 0.1s, 0.2s, 0.4s… 加随机抖动，设最大间隔 cap（如 30s）。
上限 cap 的作用：退避不能无限增长，否则第 10 次等几分钟，整体时间预算先到了——要在"给恢复时间"和"不等太久"间平衡。
抖动 jitter 的作用：不加抖动，所有失败请求会在同一时刻"集体重试"，瞬间把刚恢复的下游又打挂（重试风暴/雪崩）。随机抖动把重试波摊平、削峰。
</details>

### Q5. 退避+抖动为什么能避免雪崩？还需要哪些配套保护？
- **考察点**：雪崩原理与防护。
- **评分维度**：雪崩定义与正反馈链（3 分）；退避+抖动如何削峰（3 分）；限流+熔断配套（3 分）。
- **参考方向**：雪崩=故障→同步重试→下游更慢→崩；退避+抖动摊平重试波；限流控流、熔断断流。

<details>
<summary>参考答案</summary>

雪崩：下游故障→上游大量"立即"重试→下游压力翻倍→更慢→更多超时→彻底崩溃→上游全挂。这是正反馈链。
退避+抖动：把重试间隔指数拉大并加随机，使原本同步的重试波被打散成均匀分布，峰值被削平，下游压力可控、逐步恢复。
配套保护：
- **限流**：Runtime 对单工具做 QPS 限流（控流），防瞬间打爆。
- **熔断**：持续失败则暂时停止调用该下游（断流），给它恢复时间。
三者配合（削峰+控流+断流）才能真正防连锁崩溃。
</details>

### Q6. 重试失败后有哪些补偿动作？各适用什么场景？
- **考察点**：补偿设计。
- **评分维度**：四种动作（回滚/转人工/降级 PARTIAL/幂等去重，各 2 分，共 8 分，1 分给整体"拉回一致"）。
- **参考方向**：回滚已做部分（多步写）、转人工（高风险）、降级 PARTIAL（查询类）、幂等去重（防重复副作用）；核心是"不让系统卡在不一致"。

<details>
<summary>参考答案</summary>

补偿动作（把系统从"部分完成"拉回一致状态）：
1. **回滚已做部分**：撤销本流程内已成功的副作用。适用多步写操作（前几步成功、最后一步失败）。
2. **标记人工介入**：留工单/告警转人工。适用高风险（理赔提交失败）。
3. **降级返回部分结果**：返回 PARTIAL + 缺失说明。适用查询类（能答多少答多少）。
4. **幂等去重**：用 request_id 防重复提交。适用重试已部分成功的写操作。
核心：不让系统卡在不一致状态；高风险直接转人工并留痕。
</details>

### Q7. 重试和执行预算（W5D2）如何联动？为什么"重试前要统一校验预算"？
- **考察点**：预算与重试联动。
- **评分维度**：重试消耗三类预算（次数/Token/时间，4 分）；每次重试前校验、超限转补偿（3 分）；Runtime 统一做防漏（2 分）。
- **参考方向**：重试计入次数+Token+时间预算；退避 sleep 占时间；每次重试前统一校验，超限即补偿/优雅结束；统一在 Runtime 层做。

<details>
<summary>参考答案</summary>

重试消耗：每次重试都 +1 次数、+N token、+退避间隔（时间）。三类预算都被吃。
联动做法：每次重试前统一校验预算（次数<MAX && token<预算 && now<deadline），任一超限即进入补偿/优雅结束（PARTIAL），而不是无脑重试。
为什么统一校验：常见 bug 是重试逻辑没计次数预算，导致"重试把次数耗光"但主流程还以为没超；退避 sleep 忘了算进整体时间预算，导致退避直接超整体 deadline。必须在 Runtime 层统一管控，重试代码各自判断容易漏。
</details>

---

## L3 深度（Q8–Q11，各 10 分，共 40 分）

### Q8. 为什么不能无限重试？请系统说明代价与正确做法。
- **考察点**：重试边界。
- **评分维度**：四类代价（成本/延迟/雪崩/无效，各 2 分）；正确做法（上限+退避+预算+熔断+转补偿，2 分）。
- **参考方向**：成本爆炸、用户超时、持续打下游雪崩、对业务错误无效；有限次(3–5)+退避上限+预算约束+持续失败熔断+耗尽转补偿/人工。

<details>
<summary>参考答案</summary>

代价：
1. **成本**：每次重试烧 token、占资源，无限=无限烧钱+占线程。
2. **延迟**：用户等不到结果，体验崩，还可能先触发整体超时。
3. **雪崩**：持续打下游，把瞬时故障变永久崩溃。
4. **无效**：业务校验失败重试一万次还是错。
正确做法：有限次重试（MAX 3–5）+ 退避上限 + 执行预算约束 + 持续失败熔断（连续 N 次同错直接停，不等耗尽）+ 耗尽转补偿/人工。平衡"尽量成功"与"及时认输"。
</details>

### Q9. 补偿动作本身为什么也要幂等？结合理赔场景说明。
- **考察点**：补偿的幂等性。
- **评分维度**：重试可能已部分成功（3 分）；补偿重复执行不能出错（4 分）；理赔例子（暂存草稿/提交审批，3 分）。
- **参考方向**：重试/恢复会重跑，补偿（回滚/去重）若非幂等会二次出错；如"回滚草稿"执行两次不能出错，request_id 防重复提交审批。

<details>
<summary>参考答案</summary>

原因：重试或崩溃恢复会"重跑"后续步骤，补偿动作可能被触发多次，若非幂等会二次出错。
例子（特药理赔）：Agent 调"暂存草稿理赔单"成功，但"提交审批"失败进入补偿"回滚草稿"。若系统恢复重跑，"回滚草稿"可能被执行两次——非幂等会删错或报错。同样，重试"提交审批"若没有幂等键（request_id），会向审批系统提交两次，造成重复赔付。
做法：补偿操作设计成幂等（同输入多次执行结果一致）；写操作带幂等键去重；回滚用"状态机+版本号"保证只回滚一次。
</details>

### Q10. 如何设计"持续失败熔断"？它和"重试上限"有什么区别？
- **考察点**：熔断 vs 重试上限。
- **评分维度**：熔断定义（连续 N 次同错即停，3 分）；与重试上限区别（重试上限是总量、熔断是"连续同错信号"，4 分）；熔断后转人工+半开探测（3 分）。
- **参考方向**：重试上限是次数总量约束；熔断是"下游不健康"的信号检测——连续失败即断定下游挂了、提前停；熔断后转人工/降级，半开探测恢复。

<details>
<summary>参考答案</summary>

持续失败熔断：监控最近调用，若连续 N 次同类型错误（如连续 5 次 5xx/超时），断定下游不健康，立即"熔断"——不再重试、提前转补偿/人工，避免无谓消耗。同时进入"半开"状态周期性试探，下游恢复后再放开。
与重试上限的区别：
- **重试上限**：次数总量约束（最多试 5 次），是"预算"。
- **熔断**：健康度信号检测，是"下游已挂"的判断。它比"等次数耗尽"更早发现"持续失败"，提前止损。
配合：熔断优先于重试上限——一旦熔断，剩余重试次数也不用浪费了，直接转人工/降级。
</details>

### Q11. Temporal 在"超时/重试/补偿"上提供了什么能力（了解级即可）？它和手写 Runtime 相比的取舍？
- **考察点**：Temporal 认知（了解）。
- **评分维度**：三项对应能力（持久化/超时重试/补偿，6 分）；取舍（运维成本/非银弹/业务补偿仍自写，4 分）。
- **参考方向**：Workflow 自动持久化可恢复、Activity 自带超时+指数退避、支持 saga 补偿；取舍=要跑集群有运维成本、非唯一答案、业务语义仍自写。

<details>
<summary>参考答案</summary>

Temporal 能力：
- **持久化/可恢复**：Workflow 自动持久化每一步，崩溃后从事件重放恢复（对应 W5D1 Checkpointer）。
- **超时/重试**：Activity 自带 ScheduleToClose/Heartbeat 超时 + RetryOptions（指数退避），框架托管。
- **补偿（saga）**：支持手动写补偿 Activity，或用 Temporal 补偿模式。
取舍：
- 它把"超时/重试/补偿/持久化"做成开箱能力，适合跨天理赔等长流程。
- 但要跑 Temporal Server/Cluster，有运维成本，小场景不划算。
- 不是银弹：LangGraph 持久化+重试也覆盖部分；业务补偿语义（怎么回滚理赔草稿）仍要自己写，框架只管"重试/持久化"不管业务。
</details>

---

## L4 场景（Q12–Q13，Q12 9 分 / Q13 8 分，共 17 分）

### Q12. 场景题：特药理赔 Agent 调"医保结算接口"时频繁超时（下游偶尔抽风）。你如何设计超时、重试、退避、补偿，既不误伤用户也不打垮下游？
- **考察点**：综合韧性设计。
- **评分维度**：超时设定（2 分）；可重试判定+幂等（2 分）；指数退避+抖动+上限（2 分）；预算联动（1 分）；补偿转人工/PARTIAL（2 分）。
- **参考方向**：医保接口超时 5s；网络超时可重试带幂等键；指数退避+抖动+cap；重试计入预算；耗尽转人工留痕+降级 PARTIAL。

<details>
<summary>参考答案</summary>

设计：
- **超时**：医保接口设 5s 超时（按 P99 留余量），超时返回受控错误，并真正取消底层 HTTP 请求防泄漏。
- **可重试判定**：网络超时/偶发 5xx 视为可重试；业务校验（如"该药品不在结算范围"）不可重试，直接反馈。
- **重试退避**：指数退避（0.2→0.4→0.8s）+ 抖动 + cap 30s，分散重试波防雪崩；每次重试带 request_id 幂等键，防重复结算。
- **预算联动**：重试计入次数/Token/时间预算（W5D2），每次重试前校验，超限即停。
- **补偿**：重试耗尽（如 3 次仍超时）→ 不硬编"结算成功"，返回 PARTIAL 说明"医保结算暂不可用"，标记人工介入并留痕（附已查到的保单/药品信息摘要），让用户/人工后续处理。
- **配套**：对该接口做 QPS 限流 + 持续失败熔断，下游持续不健康时提前转人工。
</details>

### Q13. 场景题：你的理赔 Agent 调"提交审批"失败了，但之前已"暂存草稿"成功。如果不做补偿会怎样？你会怎么设计补偿？
- **考察点**：补偿的实务。
- **评分维度**：不补偿后果（状态不一致/孤儿草稿/可能泄漏，4 分）；补偿设计（回滚/幂等/转人工留痕，4 分）。
- **参考方向**：不补偿→系统卡在"草稿已存但审批没提交"的不一致态；设计=回滚草稿（幂等）或标记人工带完整上下文，提交审批带幂等键防重复。

<details>
<summary>参考答案</summary>

不补偿的后果：
- 系统卡在"草稿已存、审批没提交"的中间态——既不是成功也不是明确失败，用户看到"处理中"永远不结束。
- 这条孤儿草稿可能后续被误当成"已提交"，或堆积占用资源；若恢复重跑还可能重复提交审批。
补偿设计：
- **回滚已做部分**：补偿动作"撤销草稿"（幂等，用草稿 ID + 状态机保证只撤一次），让系统回到一致起点。
- **或标记人工介入**：留工单转人工，附完整上下文（保单号、药品、已暂存草稿 ID、失败原因），让人决定"重提还是作废"。
- **提交审批幂等**：重试/恢复时带 request_id，确保即使多次触发也只提交一次，避免重复赔付。
- 高风险操作（提交审批）默认倾向"转人工 + 留痕"，而非自动回滚后默默重试。
</details>

---

## 评分汇总表（满分 117）

| 题号 | 级别 | 主题 | 满分 | 你的得分 |
|----|----|----|----|----|
| Q1 | L1 基础 | 工具超时 | 8 |  |
| Q2 | L1 基础 | 超时层次 | 8 |  |
| Q3 | L1 基础 | 可重试性 | 8 |  |
| Q4 | L2 进阶 | 退避公式 | 9 |  |
| Q5 | L2 进阶 | 防雪崩 | 9 |  |
| Q6 | L2 进阶 | 补偿动作 | 9 |  |
| Q7 | L2 进阶 | 预算联动 | 9 |  |
| Q8 | L3 深度 | 无限重试 | 10 |  |
| Q9 | L3 深度 | 补偿幂等 | 10 |  |
| Q10 | L3 深度 | 熔断 vs 上限 | 10 |  |
| Q11 | L3 深度 | Temporal 取舍 | 10 |  |
| Q12 | L4 场景 | 医保接口韧性 | 9 |  |
| Q13 | L4 场景 | 提交审批补偿 | 8 |  |
| **合计** | | | **117** |  |

**达标线**：
- 各档：L1 ≥ 20 / L2 ≥ 30 / L3 ≥ 32 / L4 ≥ 14。
- 总分 **≥ 93 分（约 80%）** 为本次面试达标；≥ 105（约 90%）为优秀。
- 任一 L3 题得分低于 6 分，建议回看《FDE-W5D3-超时重试退避补偿-学习手册.html》对应章节重做。
