01. 幸存者偏差:Demo 里的“假成功”
很多人在做 AI 功能时,最专注的事情通常只有一件:“怎么让它跑出想要的结果?”
当模型第一次返回完美答复时,那种成就感很容易让人产生一种幻觉:这个功能已经做完了。但真实情况是,Demo 关注的是“上限”(模型能多聪明),而产品关注的是“下限”(系统能多稳健)。
真正的 AI 工程,不是只在成功时成立,它必须在失败的时候,依然保持清醒且不失控。
02. 为什么 AI 链路天生“易碎”?
传统 Web 开发的接口通常是确定的(要么通,要么断)。但 AI 链路叠加了多重不确定性:
- 远程调用风险:大模型 API 通常比普通接口更慢、更易超时。
- 内容合规拦截:模型可能会因为触发安全过滤而返回空值或报错。
- 结构化解析风险:模型返回了 JSON,但可能少了个括号,或字段类型突变。
- 模型幻觉:输出内容完全脱离预期。
在 AI 工程里,失败不是“万一”,而是“必然”。
03. 防御性编程:try-except 只是起点
如果你的代码里只有成功路径,那么网络抖动一下,你的整个应用就会直接“摔在地上”。
❌ 试玩版(极脆)
def get_ai_summary(text):
# 如果接口超时或 API Key 出问题,程序直接 crash
response = client.chat.completions.create(model="gpt-4", messages=[...])
return response.choices[0].message.content
✅ 工程版(具备韧性)
def get_ai_summary_safe(text):
try:
# 1. 显式设置超时,防止主线程被拖死
response = client.chat.completions.create(
model="gpt-4o",
messages=[...],
timeout=15.0
)
return response.choices[0].message.content
except openai.APITimeoutError:
print("请求超时,进入降级逻辑")
return "摘要生成中,请稍后再试..."
except Exception as e:
# 2. 捕获异常,确保系统不崩
logging.error(f"AI 调用异常: {e}")
return None
04. 进阶策略:重试、超时与降级
一个成熟的 AI 功能,应该具备以下三种工程直觉:
1. 重试意识(Retry)
网络瞬时不稳定是常态。对于非永久性错误(如 502/503 或网络抖动),自动重试 1-2 次通常能解决 80% 的偶发问题。 建议:使用指数退避算法(Exponential Backoff),不要紧接着立即重试。
2. 超时意识(Timeout)
AI 推理很慢,但程序不能无限等待。你必须明确:这个任务最多等多久? 超过 20 秒后是继续转圈还是告诉用户“换个短点的试试”?
3. 降级思维(Fallback)
如果 AI 彻底挂了,系统该怎么办?
- 文案改写场景:返回原句(不改总比崩了好)。
- 关键词提取场景:返回空数组。
- 智能客服场景:转接人工或返回静态 FAQ。
05. 解析失败:消费阶段的“隐形杀手”
很多人记住了“调用会失败”,却忘了“解析也会失败”。
即便模型返回了 200 OK,如果它给的 JSON 缺了一个字段,你的前端 data.item.name 依然会报 undefined。因此,解析逻辑必须也是失败路径的一部分。
直觉:模型吐出了内容,不代表流程安全了;只有校验通过了,流程才算真正闭环。
结语:让失败也“可预测”
一个成熟的 AI 工程师,在写下第一行 client.chat 之前,脑子里想的应该是:如果它没回我怎么办?如果它回乱码了怎么办?
AI 工程化的本质,是把模型的不确定性,通过程序侧的防御性设计,转化为用户侧的确定性体验。
讨论区:在你的 AI 项目中,哪种异常情况最让你头疼?你是如何做 Fallback 的?欢迎评论区交流!
本文首发于掘金,记录前端开发者向 AI 工程转型的稳定性实践。