工作台:第一次调用,就带上重试
从第一行代码起,把"失败"当常态而不是意外
教程里的第一个例子长这样:response = client.chat(...),一行,跑通,鼓掌。
这门课的第一个例子不一样——它自带超时、重试和退避。因为上一节你已经看到:四座山里的第一座,从第一次调用就开始咬人。这一节把工作台搭起来,并且用一个对比实验让你亲眼看见:同样的网络抖动,裸调用崩了,生产版活了下来。
新手司机上路,系安全带是"想起来才系";老司机上车第一个动作就是系。不是因为老司机更怕死,是因为他知道意外不挑时间。重试之于 API 调用,就是安全带——从第一次调用起就系上,不是等出事了再加。
三步搭好工作台
第 1 步:拿 key。注册 DeepSeek 开放平台 → 充 10 元(练完前几章绰绰有余)→ 创建 API key。⚠️ key 只完整显示一次,立刻存好。
第 2 步:key 放进环境变量,不写进代码。
export DEEPSEEK_API_KEY="你的key" # macOS/Linux
为什么不写进代码?——AP1.5 会专门讲这场事故(密钥进 Git 历史 = 全网公开)。现在只需养成这个手势。
第 3 步:确认能通。跑本节代码里的 first_call.py,看到输出即成功。
两个版本,一个对照实验
版本 A(裸调用)——绝大多数教程教的写法:
def ask_naive(msg, timeout=30):
return _post(msg, timeout)
版本 B(生产版)——这门课从第一节起用的写法:
def ask_robust(msg, timeout=30, retries=3):
last = None
for i in range(retries):
try:
return _post(msg, timeout)
except Exception as e: # 超时/网络错/5xx 都在这
last = e
wait = (2 ** i) + random.uniform(0, 0.3) # 1s, 2s, 4s(+抖动)
if i < retries - 1:
time.sleep(wait)
raise RuntimeError(f"重试 {retries} 次仍失败:{last}")
三个关键点,记住它们(AP1.1 会展开):
- 超时:不设超时的请求可能挂住整个进程(用户那边就是永远转圈);
- 指数退避:1s→2s→4s,而不是立刻重试——服务在喘气的时候,你别一直捶它;
- 抖动(那个
random):避免所有客户端在同一毫秒集体重试,把服务打得更惨。
实测:坏网络下谁活下来
把超时压到 0.3 秒(必然超时),模拟网络抖动。真实输出:
① 正常网络:两个版本都跑通(裸调用 1.38s / 生产版 1.80s)
② 坏网络:
裸调用:
💥 直接崩了:timeout —— 用户看到的就是 500 报错页
生产版(前两次必超时,第三次网络恢复):
第1次失败(timeout),等 1.3s 重试
第2次失败(timeout),等 2.0s 重试
✅ 第3次成功(5.90s)
→ 用户端:只是多等了几秒,完全不知道后台重试过两次
同一个 API、同一个网络。差别只在于:一个把"失败"当意外,一个把"失败"当常态。
代价也要说清:生产版正常情况下慢了 0.4 秒(多一层封装),坏情况下用户多等了几秒。用几秒延迟换掉一个报错页,这笔交易在产品里永远划算。
🔧 动手做:让你的第一个调用带上安全带(12 分钟)
- 三步搭好工作台,跑通
first_call.py(本节代码可下载)。 - 亲手制造事故:把
ask_naive的 timeout 改成0.1,跑——看它崩的样子(记下报错类型)。 - 亲手救回来:把同样的 0.1 秒超时用在
ask_robust上(retries 设 5),看它重试几次后放弃、最终报什么错。注意:这次它也会失败——因为网络是真的一直不通;重试救的是"抖动",不是"断网"。 - 改一个数字体会退避:把
wait从2 ** i改成固定0.1,连着跑几次——你在用暴力捶服务;想想如果一万个客户端都这么干会怎样。 - 把
ask_robust存进你自己的项目文件(比如llm.py)——这是你这门课的第一块地基,后面每一章都会调用它。
✅ 做到这里你应该有:一个能跑的工作台 + 一个自己写的、带重试的调用函数,并且亲眼见过它救场和救不了的两种情况。
为什么:所有 AI 产品的最底层都是"调外部服务",而外部服务一定会失败——不是"可能",是"一定",只是频率问题。今天多写的这 8 行,是你产品可用率的第一道保险。
危险的误用:对参数错误(400)、认证失败(401)、余额不足这类错误重试——它们重试一百次也不会成功,只是白烧时间和额度。更糟的是对非幂等操作(比如"扣一次费""发一条消息")盲目重试:第一次其实成功了、只是响应超时,重试就变成了扣两次费、发两条消息。该重试的:超时、连接错误、5xx、429 限流(配退避)。不该重试的:4xx 业务错误、以及任何"重复执行会产生副作用"的操作。AP1.1 会把这张表补全。
这是我写的大模型调用函数:【粘贴你的 ask_robust】。请按生产标准审查:1) 该重试和不该重试的错误分清了吗?2) 超时设置合理吗(连接超时/读取超时)?3) 重试次数和退避策略有什么问题?4) 缺了哪些日志会让线上排障困难?逐条给改法。
🎉 AP0 完结!你现在有:全课地图和毕业方向(ap0.1)、四座山的现场取证(ap0.2)、一个带安全带的工作台(本节)。
从下一章起进入 AP1「API 工程基础」——把这 8 行地基扩建成一整套结实的调用层:错误分类重试、流式输出、并发限流、缓存省钱、密钥安全、成本仪表。每一节都有实测数字,每一节的代码都能下载运行。
💳 试看到此结束。后续 49 节为付费内容——如果这三节的密度和诚实度是你要的,欢迎继续;如果不是,也感谢你读到这里。
🔎 来源与核验· 2 条,点开核对
