重试、预算、适配与评估发布
失败分类决定下一步
参数错误、凭证失败与业务拒绝不会因等待自动消失;429、短暂 5xx、网络抖动可能恢复。重试必须受总 deadline、尝试次数和副作用可重复性共同约束。连接超时、读取超时、工具超时与任务超时分别归属不同层,最内层超时不能大于外层剩余预算。
保存 retry.py,Python 3.12 无网络运行。该函数计算下一次等待是否仍有预算,不执行真实重试:
def retry_delay(status,attempt,remaining,retry_after=None):
if status not in {429,500,502,503,504} or attempt>=3:return None
delay=retry_after if retry_after is not None else min(2**attempt,8)
if delay<0:raise ValueError('negative delay')
return delay if delay<remaining else None
assert retry_delay(400,0,30) is None
assert retry_delay(429,0,5,6) is None
assert retry_delay(503,1,10)==2
assert retry_delay(503,3,100) is None
print('retry policy passed')真实部署在退避基础上加随机抖动,避免大量客户端同一时刻恢复。Retry-After 可能是秒数或日期,先解析再传入;不要把任意 header 当整数。耗尽重试后按业务提供明确拒答、固定模板或能力较低的模型,并向用户标明降级范围。高风险任务不应悄悄换到未经评估的模型。
先预留预算,再结算用量
每租户任务开始时预留最大费用,结束后用实际输入、缓存输入、输出用量结算,释放余量。并发时“检查余额→调用→扣款”会被多个请求同时穿透;预留必须原子完成。异步长任务排队后返回任务 ID,用户查询状态,避免 HTTP 重试生成多个任务。
供应商兼容层保留统一输入、状态、usage 和错误分类,特殊能力通过显式扩展暴露。对于不支持图片的模型,拒绝请求比悄悄删除图片更可靠。密钥由服务端配置注入,不进入浏览器或公开日志;请求关联 ID 与密钥是不同数据。
用失败样本阻止错误发布
建立固定回归集,包括正常、边界、拒绝、多语言、未知资源、错误工具与长上下文。质量指标区分事实正确、证据忠实、工具名称和参数正确;运行指标区分首 token 延迟、完整响应延迟、工具耗时、错误率和成本。只比较平均延迟会掩盖长尾。
rows=[{'group':'zh','ok':True},{'group':'zh','ok':False},
{'group':'en','ok':True}]
for group in sorted({r['group'] for r in rows}):
subset=[r for r in rows if r['group']==group]
print(group,sum(r['ok'] for r in subset)/len(subset))输出 en=1.0、zh=0.5。总成功率 2/3 掩盖了中文组较差,灰度应看关键分组和样本量。小流量路由按稳定用户哈希,保留提示、schema、适配器和模型配置版本;回滚恢复整组配置。影子评估不执行真实写工具,否则“只测不影响用户”并不成立。
本章只验证确定性策略,真实吞吐量、模型质量与价格未在线测量。供应商细节以各平台课程和官方文档为准。
练习
在 retry_delay 中测试剩余预算恰好等于等待时间。为什么应返回 None?给英文组增加失败记录后重新计算两个分组。
先记录自己的输出与解释,再核对本章答案。