先在本地解决一个实际问题
你的 AI 小工具请求失败时,总显示“出错了,请重试”。本课把它改为可区分的结果:配置问题先修配置,临时故障有限重试,超时保留结果未知,成功响应缺内容则检查协议。
使用 DeepSeek 对话或自己已配置的编程助手,把下面的虚构样例作为输入。这里只运行本地函数,不填写密钥,不实际请求服务。
先给完整输入输出约定
请实现 classify(status, payload)。
status 为 HTTP 状态整数,连接超时用 None;payload 为已解析 JSON 对象或 None。
输出字典包含 category、message、retryable。
401:配置问题,不重试。
429 且本应用归一化 reason=quota:额度问题,不重试。
其他 429:暂时受限,可有限重试。
500~599:服务失败,可有限重试。
超时:结果未知,不自动重发。
200 且 text 为非空字符串:成功。
200 但缺少有效 text:协议问题,不重试。
其他输入:未知失败。不能把 payload 原样放到用户消息里。
给完整 Python 标准库实现、样例和断言。
reason=quota 是本课应用自己的归一化字段,不是宣称 DeepSeek 一定返回这个错误对象。真实接口要先写适配层,把服务响应转换成这个约定。
保存并运行参考答案
以下保存为 errors.py,运行 python errors.py:
def classify(status, payload):
data = payload if isinstance(payload, dict) else {}
if status is None:
result = ("unknown_result", "请求超时,请先查询原任务", False)
elif type(status) is not int:
result = ("unknown", "响应状态无法识别", False)
elif status == 401:
result = ("configuration", "请检查服务凭据", False)
elif status == 429 and data.get("reason") == "quota":
result = ("quota", "可用额度不足", False)
elif status == 429 or 500 <= status <= 599:
result = ("temporary", "服务暂时不可用", True)
elif status == 200 and isinstance(data.get("text"), str) and data["text"].strip():
result = ("success", "已完成", False)
elif status == 200:
result = ("protocol", "响应缺少有效内容", False)
else:
result = ("unknown", "请求未完成", False)
return dict(zip(("category", "message", "retryable"), result))
assert classify(401, {"token": "fictional-secret"})["retryable"] is False
assert classify(429, {"reason": "quota"})["category"] == "quota"
assert classify(429, None)["retryable"] is True
assert classify(None, None)["category"] == "unknown_result"
assert classify(200, {"text": " "})["category"] == "protocol"
assert classify(200, {"text": "完成"})["category"] == "success"
assert "fictional-secret" not in str(classify(401, {"token": "fictional-secret"}))
print("错误分类与消息边界通过")
函数先处理 payload 不是字典的情况,避免服务已经失败,你的错误处理又因取字段崩溃。它不原样暴露错误对象,用户消息更可控。
为什么超时不能直接无限重试
超时只说明本次等待没拿到结果,服务可能已经受理。对会创建任务、扣费或发送内容的请求,重新发送可能产生第二次操作。先查原任务或按服务支持的幂等规则恢复,不能由这个分类函数单独决定。
retryable=True 也只是“可以考虑重试”,调用方仍应限制次数、间隔并遵循服务返回的等待要求。本课没有实现重试调度器,别把一个布尔值当作完整容错系统。
用一个反例指导修订
如果助手把所有 429 都标为立即重试,给出:
classify(429, {"reason":"quota"}) 应返回 quota 且 retryable=False;当前实现把额度不足当成短期限流。请先判断本应用归一化的额度原因,再处理其他 429。保留 payload=None 的用例,不新增网络请求。
如果它把原始错误字符串拼到 message,补一个含教学秘密标记的样例,确认输出不包含该标记。只说“注意安全”没有可验证的行为。