可靠性工程

本讲目标

让系统在出错时能自己恢复,并且不重复干同一件事。

你会做出

一份故障演练记录 + 一张延迟/成本表。

120 分钟怎么排
  1. 课前课前准备
  2. 0–30补核心
  3. 30–75讲错题
  4. 75–120拆案例
  5. 课后课后作业

课前:先自学,再做 15 道题

上课前,先花点时间自己看一页材料,就三样:

  • 弄懂 3 个词:超时/重试/退避/降级(四个不同动作)、幂等(同一请求重复到达,不重复执行)、成本(按"一次任务"算)。
  • 记住 1 个比方:它会坏——让它能自己恢复,而且别重复干同一件事。
  • 记住 1 条红线:别为了省几分钱砍用户体验;省成本的顺序:先减无效调用 → 换小模型 → 最后砍功能。

看完做 15 道自测题。哪几道大家错得多,直播时老师就重点讲哪几道。

直播 0–30|把核心快速过一遍

  1. 重试是好事,但对"写操作"重试是灾难。 查库存失败可以重试;创建工单失败再重试,可能建出两条 → 用幂等键(同一请求带同一键,只执行一次)。
  2. 超时/重试/退避/降级四个词要分清。 超时=等太久放弃;重试=再试一次;退避=越失败等越久;降级=换简单方案(模型挂了→模板回复+转人工)。
  3. 成本按"一次任务"算。 一次任务可能要调 3 次模型 + 2 次工具,算总账,别按"一次对话"。

直播 30–75|挑大家做错的题讲

  • 无限重试,失败一次重试一次,越重试越堵。
  • 重试写操作,没幂等键,重试就是复制。
  • 日志没有任务 ID,出了事连"哪一次"都说不清。

直播 75–120|拆一个真实案例:启衡精密,重复建单与长链路

启衡精密(制造企业)的报销预审 Agent 自动建任务,网络卡了一下,用户点了两次"提交",就建出两条重复任务;讲师点评"你没有做客户端幂等"。材料是两次运行日志(第二次 source_meeting: null,系统没法判断"已经建过")。

修复分四步:①用 会议ID + 行动项序号 生成幂等键 M-1021-A03;②建之前先查,键存在就跳过;③写入时把幂等键一起存;④补一条测试"同一输入连跑 3 次只建 1 组"。容易踩的坑有三个:只在应用层去重、没在数据层加唯一约束;用"标题"当去重键;重试时重新生成 ID。

再说长链路:10 个独立步骤各 95% 成功率,整条链路一次走通只有约 60%;企业 Agent 上线的硬门槛是"整链准确率稳定在 90% 以上"。

这一讲想让你记住的就一句:"任务成功"和"消息送达"是两件事,日志里分开记 task_status / result_saved / human_seen。

当堂练一个(8 分钟):挑一件你平时真会让 AI 做的事——比如"读一份 10 页材料、写 300 字摘要"。先猜:做这一次大概要花多少钱?然后真做一遍,看它到底消耗了多少额度/积分,按当期的积分价格把单次成本算出来;再算一笔账:如果每天用 20 次,一个月要花多少。最后从你常用的两三个 AI 里,指出哪一个做这件事最划算。

判断标准:能报出"这件事做一次的真实成本",并说清"一次任务里可能调了 3 次模型 + 2 次工具,都要算进总账",而不是只按"一次对话"——把成本看小了。

课后:答疑 + 陪跑,交一份作业

加幂等键 + 超时有限重试 + 分状态日志 + 降级;演练 3 次(重复提交/超时/返回丢失);做 5 类故障演练修 2 类,重跑第 12 讲测试集。

这节课你该会的:

  1. 能说清"幂等"是什么,并保证同一请求重复提交只执行一次;
  2. 能分清超时、重试、退避、降级四个动作,出错时给出用户能看懂的提示;
  3. 能按"一次任务"算成本,并能从日志还原一次失败"卡在哪一步、花了多久、花了多少"。

三个翻车:

  • 无限重试——失败一次重试一次,越重试越堵,把下游打挂;
  • 重试"写操作"却没用幂等键——重试就是在复制,一份变两份;
  • 日志不记任务 ID——出了事,你连"哪一次"都说不清。

延伸自读:《原理讲义》§13

展开查看
一句话定义

可靠性不是"不出错",而是"出错之后系统能自己恢复、并且不重复做同一件事"——当模型慢、工具挂、网络断、返回丢时,它是变成事故,还是退到一条可恢复、可追溯的路径。一句话:让它会坏,但坏得起。

核心原理

1. 超时 / 重试 / 退避 / 降级是四种药,治四种病,不能混成一句"加了重试"。

  • 超时治"卡住":Agent 每一步都在等别人——模型生成、工具调用、下游接口,任一环节不回应就会永远卡死、拖垮整条链路。超时把"无限等待"变成"有界失败"。
  • 重试治"暂时性错误":网络抖动、限流、对方恰好重启,再试一次往往就好了。但前提是——失败是暂时的、而且操作是安全的。
  • 退避治"重试本身造成的拥堵":下游已经过载才超时,你立刻重试等于再踩一脚油门,所以越失败等越久(指数退避),再加随机抖动让大量客户端错峰。
  • 降级治"核心依赖彻底断了":模型挂了就不回答吗?不——换简单方案,用模板回复 + 转人工,先保住"用户得到回应"这条底线。

举个例子:某零售企业的商品问答,查库存接口 500ms 无响应就超时;超时后再试 2 次、间隔 1s/2s/4s;连续失败则降级为"库存信息暂不可用,已为您转人工",而不是让用户干等或收到一句"系统错误"。

2. 幂等:让"重试"从灾难变成安全网。 查库存失败重试没关系(读是幂等的),但"创建订单""扣库存"这类写操作重试就是复制——第一次的响应丢了,客户端再发一次,就产生两张单。幂等说白了,就是给"这一次请求"一张身份证:客户端在发起前生成唯一幂等键,同一请求无论到达多少次,服务端按键去重、只执行一次。举个例子:会议 Agent 用"会议 ID + 行动项序号"生成键 M-1021-A03,建任务前先查键、存在即跳过、写入时把键一起存。三个细节——客户端生成键、重试不换键、数据层加唯一约束——缺一不可(见下方边界)。

3. 成本按"一次任务"算,不按"一次对话"算。 一次任务是一条多步流水线:可能调 3 次模型、2 次工具、1 次检索;重试和退避再把每个环节的调用次数翻几倍——一次失败的任务可能调 9 次模型才放弃。按"一次对话"记账会严重低估真实成本。优化顺序是:先减无效调用(砍重复检索、缩短上下文、少重试)→ 换小模型(只在必须精度的环节用大模型)→ 最后才砍功能,因为功能是用户价值,不该从它开刀。

4. 长链路可靠性是"乘积",不是"平均"。 10 个步骤各自 95% 成功率,听起来很高,但整条链路一次走完的成功率是 0.95¹⁰ ≈ 60%——单步再可靠,链路一长就塌方。所以企业 Agent 上线要的是"整条链路稳定达标",不是"每一步看着都还行"。应对之道不是把每步做到 100%(做不到),而是三层:用重试/降级压低每步失败率、用幂等消灭"重试带来的次生事故"、再用人工兜底接住最后 40% 里最危险的部分。

常见误区 / 边界
  • 别无限重试、别对写操作裸重试:失败一次重试一次、越重试越堵,还会复制单据;重试必须有上限,写操作必须先幂等。
  • 别把"重试"当通用开关:参数错误、权限不足是确定性错误,重试一百次也没用,直接报错;只重试暂时性错误。
  • 别用"标题/内容"当幂等键、别在重试时重新生成 ID:业务值会变、会撞车;键一变,幂等就失效,重试变成复制——用客户端生成的稳定唯一键,且数据层加唯一约束。
  • 别按"一次对话"算成本:按"一次任务的完整调用链 × 重试放大系数"算总账。
  • 别为省几分钱砍体验:优化顺序是"先减无效调用 → 换小模型 → 最后砍功能",不能反过来。
  • 别把"任务成功"和"消息送达"当一回事:一个"状态"背后常藏着三个状态(任务执行完 / 结果已保存 / 人已看到),日志要分开记,否则"完成了但没人知道"。
一句可带走的话

让它会坏,但坏得起:出错了自己恢复、重复了不重复干、成本按一次任务算——可靠性不是消灭错误,而是让错误变得便宜、可控、可追溯。

案例包 · 15 题自测

展开查看

15 道题分三块,各约 5 道:第 1–5 题讲重试对写操作是灾难、幂等键、日志任务 ID;第 6–10 题讲超时/重试/退避/降级四个词分清、分状态日志;第 11–15 题讲成本按"一次任务"算。

每题都有解析,容易错的地方标了出来。大家错得多的题,就是直播时要重点讲的。

  1. (单选)下面哪个操作失败后,可以直接无脑重试,不用担心重复?
    • A. 创建工单
    • B. 扣减余额
    • C. 查询库存
    • D. 发送下单成功短信

答案:C | 解析:查询库存是读操作,重复执行不改变结果;创建、扣减、发送都是写操作,重试可能重复执行。

  1. (单选)幂等键的作用是?
    • A. 让请求更快
    • B. 同一请求重复到达时,只执行一次
    • C. 加密请求
    • D. 压缩请求体

答案:B | 解析:幂等 = 同一输入重复执行结果不变;幂等键让系统能识别"这已经是同一次请求"。

  1. (判断)查库存失败可以重试,创建工单失败也可以直接重试,两者一样安全。

答案:错 | 解析:读操作重试安全;创建工单是写操作,重试可能建出两个,必须先带幂等键。 容易错:很多人以为"重试 = 保险",对写操作也直接重试,结果复制出重复单据。

  1. (单选)重试时,每次重试都"重新生成一个随机 ID"当作幂等键,会导致?
    • A. 更安全
    • B. 幂等键失效,每次重试被当成新请求,重复建单
    • C. 响应更快
    • D. 日志更全

答案:B | 解析:幂等键必须在"同一次业务请求"内保持不变,重试要沿用第一次生成的键,否则去重失效。 容易错:很多人以为"每次随机更安全",其实恰恰破坏了幂等。

  1. (单选)日志里没有"任务 ID / 幂等键",出了事故最大的问题是?
    • A. 查不到花了多少钱
    • B. 连"是哪一次请求"都说不清,没法复现
    • C. 看不到用了哪个模型
    • D. 不能统计耗时

答案:B | 解析:没有任务 ID,日志就是一堆孤立事件,出事时定位不到具体哪次运行。 容易错:很多人只关心"记没记",不关心"能不能定位到哪一次"。

  1. (单选)"设一个等待上限,到点就放弃,不再等"是哪个动作?
    • A. 重试
    • B. 退避
    • C. 超时
    • D. 降级

答案:C | 解析:超时 = 等太久就放弃,避免无限挂起。

  1. (单选)"越失败,等得越久再试下一次"是哪个动作?
    • A. 超时
    • B. 退避
    • C. 降级
    • D. 幂等

答案:B | 解析:退避(backoff)= 失败后把重试间隔拉长,避免把下游越打越堵。

  1. (单选)模型挂了,系统自动改用"模板回复 + 转人工",这是?
    • A. 重试
    • B. 退避
    • C. 降级
    • D. 超时

答案:C | 解析:降级 = 换一个更简单但可用的方案兜底,保证用户仍拿到出口。

  1. (判断)"重试 3 次"和"退避"是同一个意思。

答案:错 | 解析:重试管"试几次"(次数),退避管"两次之间等多久"(间隔),要搭配使用。

  1. (单选)日志里只有一条 task_status: 完成,你查不出什么?
    • A. 用了哪个模型
    • B. 结果有没有保存、人有没有看到
    • C. 花了多少钱
    • D. 谁发的请求

答案:B | 解析:一个"状态"背后其实是三个状态——task_status(跑完没有)/ result_saved(存了没有)/ human_seen(人看到没有),要分开记。 容易错:很多人以为 task_status=完成 就万事大吉,忘了"任务成功"和"消息送达"是两件事。

  1. (单选)"成本按一次任务算"指的是?
    • A. 只看一次对话的最后一条回复
    • B. 一次任务里所有模型调用 + 工具调用的总账
    • C. 只看模型调用,不算工具调用
    • D. 按月均摊

答案:B | 解析:一次任务可能调 3 次模型 + 2 次工具,要算总账,不能按"一次对话"或"最后一次回复"算。

  1. (判断)一次任务调了 3 次模型 + 2 次工具,算成本时只算最后一次模型调用就够了。

答案:错 | 解析:3 次模型 + 2 次工具都要算,漏算工具调用会严重低估真实成本。

  1. (单选)想降成本,正确的优化顺序是?
    • A. 先砍功能 → 换小模型 → 最后减无效调用
    • B. 先减无效调用 → 换小模型 → 最后砍功能
    • C. 直接砍功能
    • D. 换最便宜的模型

答案:B | 解析:先减无效调用(不花钱)→ 换小模型(同任务用小模型)→ 最后才砍功能(伤体验)。

  1. (判断)为了省几分钱,把"转人工"去掉、让用户干等,是可以接受的成本优化。

答案:错 | 解析:不要为省几分钱砍用户体验;降级要给出口(转人工),不能让用户卡死。

  1. (单选)无限重试(失败一次就立刻重试一次,不限次数)最直接的后果是?
    • A. 响应变快
    • B. 失败一次重试一次,越重试越堵,把下游打挂
    • C. 省钱
    • D. 更安全

答案:B | 解析:无上限、无间隔地重试,等于在故障点上不断加压,越堵越死;正确做法是"有限次数 + 退避"。 容易错:很多人以为"重试越多越稳",其实无限重试本身就是新故障。

案例包 · 案例拆解素材

对应:第 13 讲「可靠性工程」

课堂用时:案例拆解 45 分钟(直播 75–120)

材料与提示词思路:全部写在这个文件里

1. 客户与场景

启衡精密(制造企业)的报销预审 Agent 会自动建任务。一次网络卡顿,用户点了两次"提交",系统建出两条重复任务;两周累计 200 多条重复。

讲师点评直接点破:"你没有做客户端幂等。"

2. 为什么这个案例值得教
  • 真实数字讲清"长链路不可靠":10 个独立步骤各 95% 成功率,整条链路一次走通的理论成功率只有约 60%;
  • 企业 Agent 上线硬门槛:整条链路准确率稳定在 90% 以上,其余风险靠人工兜底;
  • 它把"超时 / 重试 / 幂等 / 降级 / 成本"五个词串进一个真实故障里。
3. 原始材料(真实故障)

故障:两次运行日志,第二次 source_meeting = null,系统无法判断"这条已经建过了",于是重复建单。

修复:

  1. 用 会议ID + 行动项序号 生成幂等键(如 M-1021-A03);
  2. 建任务前先查"这个键存在吗",存在就跳过;
  3. 写入时把幂等键一起存;
  4. 补一条测试:同一输入连跑 3 次,只允许建 1 组。
4. 故意埋的三个坑
坑 1:只在应用层去重,没在数据层加唯一约束

并发时还是重复。正确:应用层 + 数据层双保险。

坑 2:用"任务标题"做去重键

两个不同会议有同名任务,会被误删。正确:用稳定的业务 ID,不用会变的标题。

坑 3:重试时重新生成了 ID

幂等键失效。正确:同一个请求始终带同一个键。

5. 两版提示词思路(内联)
  • v1(故意有缺陷):无幂等键、无重试上限、日志不分状态。
  • v2(修复后):幂等键 + 有限重试 + 日志分开记 task_status / result_saved / human_seen + 失败转人工。
6. 验收样例(3 条)
#场景期望判定
1同一输入连跑 3 次只建 1 组任务通过
2接口超时后重试有限重试,不无限重试通过
3任务"成功"但没写进约定表日志能区分"执行成功 / 结果保存 / 人看到"通过
7. 案例拆解 45 分钟流程
分钟做什么
0–5抛"连点两次提交,重复付款"的真实后果
5–15找坑:应用层才去重 / 标题做去重键 / 重试重新生成 ID
15–30判对错:用 v1 检查这段日志,看它能不能发现重复
30–40给修复:幂等键 + 唯一约束 + 分状态日志,重跑
40–45收口:重试对"写操作"是灾难;"任务成功"和"消息送达"是两件事
8. 一句话总结

10 个步骤各 95% 成功,整条链路只有 60%——生产系统必须在关键节点校验、恢复、兜底;写操作必须幂等。

案例包 · 课后操作单

目标:给你的项目加"幂等 + 有限重试 + 分状态日志 + 降级"这四样,做 5 类故障演练修 2 类,重跑第 12 讲测试集。

时间:课后 90 分钟。

你要交的东西
  1. 一份故障演练记录:重复提交 / 超时 / 返回丢失 3 次演练,每次记下现象和修复;
  2. 一张延迟 / 成本表:按"一次任务"算总账(3 次模型 + 2 次工具各多少,不是按"一次对话");
  3. 项目里加上的这四样:幂等键 + 有限重试(≤3 次、退避)+ 分状态日志 + 降级。
步骤
第 1 步:找出最危险的写操作,定幂等键(15 分钟)
  1. 在你的项目里列一个"会写库/发通知/扣减"的操作清单。
  2. 挑最危险的一个,定幂等键规则(如"会议ID + 行动项序号"),写清格式和样例。
  3. 确认:幂等键在同一次业务请求内保持不变,重试沿用,不重新生成。
第 2 步:加有限重试 + 退避(15 分钟)
  1. 把"失败就重试"改成:最多重试 3 次,间隔指数退避(如 1s → 2s → 4s)。
  2. 读操作可重试,写操作重试前先查幂等键。
  3. 把"无限重试"删掉,写一句说明为什么。
第 3 步:分状态日志(15 分钟)
  1. 找到只记一个"完成/失败"的地方,拆成三个状态:task_status / result_saved / human_seen。
  2. 每条日志带上任务 ID / 幂等键,出事能定位到"哪一次"。
第 4 步:加降级(15 分钟)
  1. 给模型调用加一个降级出口:模型挂了 → 模板回复 + 转人工(或缓存结果),不让用户卡死。
  2. 给下游慢/超时加超时上限,到点走降级。
第 5 步:故障演练 + 延迟成本表(30 分钟)
  1. 做 3 次演练:①重复提交同一请求 → 只执行一次;②模拟超时 → 触发有限重试不复制;③模拟返回丢失 → 日志能看到"结果没送达人"。
  2. 做一张延迟 / 成本表:一次任务里每个模型调用、每个工具调用的延迟和成本,算总账。
  3. 做 5 类故障演练(重复提交 / 超时 / 返回丢失 / 模型挂 / 下游慢),修其中 2 类。
课后作业
  1. 把 5 类故障演练做完,至少修 2 类,写进演练记录。
  2. 重跑第 12 讲的测试集,确认可靠性改造没有破坏原有功能(回归不倒退)。
  3. 写 100 字:你的项目里,哪个"写操作"最危险?幂等键怎么定、为什么不能用标题?
达标标准(这节课你该会的)
  1. 能说清"幂等"是什么,并保证同一请求重复提交只执行一次;
  2. 能分清超时、重试、退避、降级四个动作,出错时给出用户能看懂的提示;
  3. 能按"一次任务"算成本,并能从日志还原一次失败"卡在哪一步、花了多久、花了多少"。
常见错误
  • 只做应用层去重,没加数据层唯一约束 → 并发重复。
  • 用"标题/名称"做幂等键 → 撞名误删。
  • 重试时重新生成 ID → 幂等键失效。
  • 日志只记一个"完成" → 出问题查不出是哪一次。
  • 成本只看"一次对话",漏掉工具调用 → 低估真实成本。
  • 无限重试 → 越堵越死,把下游打挂。

案例包 · 教师脚本(教师用)

展开查看
课前准备
  • 把启衡精密重复建单日志 + 幂等键修复方案准备好(见 case_card.md)。
  • 自己先跑 v1,确认它无幂等、无重试上限。
  • 开课前看一眼 quiz 的错误率,圈出大家错得多的题。
0–30|把核心快速过一遍(3 个点)
  1. 重试是好事,但对"写操作"重试是灾难(10 分钟)— 用幂等键。
  2. 超时/重试/退避/降级四个词分清(10 分钟)。
  3. 成本按"一次任务"算(10 分钟)。
30–75|挑大家做错的题讲
  • 无限重试 → 越重试越堵。
  • 重试写操作 → 没幂等键,重试就是复制。
  • 日志没有任务 ID → 出事了连"哪一次"都说不清。
75–120|拆一个真实案例:启衡精密,重复建单与长链路

抛故障(5 分钟):启衡精密报销预审 Agent 自动建任务,网络卡了一下,用户点了两次"提交",建出两条重复任务。讲师点评:"你没有做客户端幂等。"

找坑(12 分钟):三组分别暴露①只在应用层去重、没在数据层加唯一约束;②用"任务标题"做去重键;③重试时重新生成了 ID。

判对错(10 分钟):看两次运行日志(第二次 source_meeting = null),问"系统能判断这条已经建过了吗?"——不能。

给修复(13 分钟):①用 会议ID+行动项序号 生成幂等键;②建前先查;③写入存键;④补测试"同一输入连跑 3 次只建 1 组"。

长链路(5 分钟):10 个独立步骤各 95% 成功率,整条链路一次走通只有约 60%;企业 Agent 上线硬门槛是"整链准确率稳定在 90% 以上"。

标准答案
  • 幂等键:M-1021-A03(会议ID + 行动项序号)。
  • 同一输入连跑 3 次 → 只建 1 组。
  • 日志分开记 task_status / result_saved / human_seen。
学生会错在哪
  1. 无限重试。
  2. 重试写操作。
  3. 只在应用层去重。
  4. 用标题做去重键。
  5. 日志没任务 ID。
评分点(每条 1 分,共 5 分)
  • [ ] 幂等键生成正确(业务 ID,不是随机数);
  • [ ] 建前先查 + 数据层唯一约束;
  • [ ] 有限重试 + 失败转人工;
  • [ ] 日志分状态(task_status/result_saved/human_seen);
  • [ ] 能说清"10 步×95% = 60%"这个长链路道理。
如果学生问"重试两次是不是太保守"

回答:写操作宁可少重试、多重试前先查幂等键;读操作可以多试几次。关键是"重试会不会产生副作用"——有副作用就上幂等 + 人工兜底。

可搜索 16 讲与全部课程章节。