把 Nano Banana 2 接入生产环境:超时、报错、重试和降级方案
Nano Banana 2 的 API 标注着 "Preview"。这两个字意味着:它可以用,但不保证稳定。
如果你只是在 AI Studio 里玩一玩,偶尔超时刷新一下就行了。但如果你要把它接入一个面向用户的生图服务——比如电商的自动海报生成、社交 App 的头像制作——你得提前想好出错时怎么办。
这篇文章整理了 Gemini 3.1 Flash Image Preview 在实际 API 调用中已知的稳定性问题,以及对应的工程化解决方案。
已知的稳定性问题
根据 GitHub issues 和开发者论坛的反馈,目前主要有这几类问题:
1. 偶发超时(约 5% 的请求)
Google 论坛上有开发者反馈,大约 5% 的请求会遇到 "fetch failed sending request" 错误。多数出现在复杂请求(长 Prompt、多模态输入、带参考图)时。
症状:请求发出后长时间无响应,最终返回超时错误。
原因推测:Preview 版本的后端资源分配不如 GA 版本稳定,高峰期可能出现队列拥堵。
2. SSL/TLS 连接错误
Gemini CLI 的用户报告过偶发的 ssl/tls alert bad record mac 错误,大约每小时出现一次。这类错误和请求内容无关,更像是网络层的问题。
3. 流式 + 工具调用组合不稳定
使用 gemini-3-flash-preview 模型时,如果同时开启了 Streaming 和 Tools,LLM 的响应可能返回空白。这是 ADK(AI Development Kit)里的一个已知 bug。
4. 安全过滤误伤
Google 的安全过滤比较保守。一些正常的商业场景描述(比如泳装产品图、医学图示)可能被标记为 FinishReason.SAFETY 而拒绝生成。
5. Rate Limit
Preview 版本的并发限制比较严。具体数值没有公开文档,但多个开发者反馈在 10 QPS 左右就开始被限流。
重试策略
对于超时和网络错误,重试是最直接的解决方案。但不能无脑重试。
指数退避 + 抖动
import time
import random
def generate_with_retry(model, prompt, config, max_retries=3):
for attempt in range(max_retries):
try:
response = model.generate_content(
contents=[prompt],
generation_config=config,
request_options={"timeout": 60}
)
if response.parts:
return response
except Exception as e:
if attempt == max_retries - 1:
raise e
wait = (2 ** attempt) + random.uniform(0, 1)
print(f"Attempt {attempt + 1} failed: {e}. Retrying in {wait:.1f}s")
time.sleep(wait)
return None
要点:
- 超时设置为 60 秒(默认可能太短,特别是 4K 图片)
- 指数退避:第一次等 1-2 秒,第二次等 2-3 秒,第三次等 4-5 秒
- 加随机抖动(jitter),避免多个客户端同时重试导致"重试风暴"
- 最多重试 3 次。超过 3 次还失败,说明不是偶发问题
区分可重试和不可重试的错误
不是所有错误都应该重试:
| 错误类型 | 是否重试 | 处理方式 |
|---|---|---|
| 超时 | 是 | 指数退避重试 |
| 网络/SSL 错误 | 是 | 指数退避重试 |
| Rate Limit (429) | 是 | 等待更长时间后重试(按 Retry-After 头) |
| 安全过滤 (SAFETY) | 否 | 修改 Prompt 或调整 safety_settings |
| 参数错误 (400) | 否 | 修复请求参数 |
| 认证失败 (401/403) | 否 | 检查 API Key |
降级方案
重试解决的是偶发故障。如果模型整体不可用(比如大规模故障或被限流),需要降级方案。
方案一:分辨率降级
4K 生成失败时,自动降到 2K;2K 也失败,降到 1K。低分辨率的请求对后端压力更小,成功率更高。
sizes = ["4K", "2K", "1K", "512"]
def generate_with_fallback_size(model, prompt, sizes):
for size in sizes:
try:
response = generate_with_retry(model, prompt, {"size": size})
if response:
print(f"Generated at {size}")
return response
except Exception:
continue
return None
方案二:模型降级
Nano Banana 2 失败时,切换到其他模型。比如用 Imagen 4 做兜底,或者用 DALL-E 3 做备选。
models = [
("gemini-3.1-flash-image-preview", "Nano Banana 2"),
("imagen-4.0-generate-001", "Imagen 4"),
]
def generate_with_fallback_model(prompt, config):
for model_id, name in models:
try:
model = genai.GenerativeModel(model_id)
response = generate_with_retry(model, prompt, config)
if response:
print(f"Generated with {name}")
return response
except Exception:
continue
return None
方案三:异步队列化
如果你的业务场景允许延迟返回(比如用户下单后 5 分钟内收到商品图),可以把生图请求放到消息队列里,后台 Worker 异步处理。
好处是:
- 失败后可以自动重试,用户无感知
- 可以控制并发数,避免触发 Rate Limit
- 可以做优先级排序(VIP 用户的请求优先处理)
技术选型:Redis Queue、RabbitMQ、或者云厂商的消息服务(阿里云 MNS、AWS SQS)都可以。
可观测性
上线后你需要能实时看到系统状态。建议监控以下指标:
- 成功率:过去 5 分钟的生图成功率,低于 90% 时告警
- P99 延迟:正常情况下应该在 15 秒以内,超过 30 秒说明有问题
- 错误分布:按错误类型分类统计(超时 / 限流 / 安全过滤 / 其他)
- 降级触发次数:如果降级频繁触发,说明主模型不稳定,需要评估是否切换
- 成本:每日/每周的 API 调用费用
用 Prometheus + Grafana 或者云厂商的监控服务(阿里云 ARMS、AWS CloudWatch)都能实现。
什么时候可以上生产?
Preview 模型上生产不是不行,但要做好几个准备:
- 重试 + 降级 + 队列化的完整链路
- 可观测性到位,能在问题扩大前发现
- 用户侧有"生成中"的等待状态,而不是直接卡死
- 有明确的 SLA 预期(比如:95% 的请求在 30 秒内返回结果,剩下 5% 可能需要 1-2 分钟)
- 和 Google 确认你的配额是否足够(Preview 版本的默认 QPS 较低,可能需要申请提升)
满足这些条件,Preview 模型就可以用于生产环境。模型本身的生成质量没问题,需要工程上补的是稳定性这一课。
参考链接