跳到主内容
快讯直播
AI智模界
教程

上手 Nano Banana 2.1:4K 与中文批量出图

Nano Banana 2.1 相比上一版,变化集中在三件事上:支持原生 4K 直出,不再依赖"先出小图再放大"的补救流程;画面内中文文字的渲染稳定性提升;批量生成任务的接口与返回结构更完整。这三件事恰好也是上手时最容易卡住的地方——4K 请求被静默降级、中文变成错字或方块、批量跑到一半断掉。

下面按排错流程走一遍:先看清现象,再按概率排查,最后给批量脚本和兜底方案。文中命令可以直接照抄,涉及模型标识、接口路径、参数名的地方,以官方文档当前版本为准。

报错现象

现象一:请求 4K,拿到的是小图

触发操作:在请求里写 "size": "3840x2160" 或把宽高分别写成 width/height 字段。

报错或表现:

  • 返回体里的 size / width / height 字段与请求值不一致,比如请求 3840×2160,返回还是 1024×1024 一类的小尺寸;
  • 或者直接报错,文案类似 invalid size、size not supported、image_size must be one of ...(具体文案各平台不同);
  • 请求成功、图也能下,但下载到本地后用工具查,真实像素宽度不足 3840。

影响范围:需要印刷、大屏、电商主图的场景直接不可用;即使强行拉伸,文字边缘也会发虚。

现象二:中文文字渲染出错

触发操作:提示词里写了"画面中央横排四个字:第二杯半价"这类要求。

报错或表现:

  • 出图上的字变成形近字("半价"写成"半介"),或笔画粘连、多一笔少一笔;
  • 出现提示词里根本没写的字,或本该 4 个字变成 5 个字;
  • 竖排被渲染成横排,或者行序从右往左、从左往右反了;
  • 上一版能渲染正确的双字词,新版换了一种更漂亮的字体风格后字形反而走样(版式变好,错字率没同步变好)。

影响范围:电商海报、公众号封面、菜单、PPT 配图这类"图上必须带字"的场景,出图直接不可用,而且不容易一眼发现——错一个字,整张图就废了。

现象三:批量任务部分失败

触发操作:脚本一次提交几十到几百条提示词。

报错或表现:

  • 返回里约五分之一是失败态,错误码常见 429(限流)、500/502/503/504(服务端抖动)、超时;
  • 串行脚本跑到第 20 多张后卡住不动,不报错也不返回;
  • 重试之后出现重复图、顺序和提示词对不上、文件名互相覆盖。

影响范围:批量出图是海报、素材库、多语言版本这类工作的主力用法,失败率上去之后,人工补图的时间会超过写脚本省下的时间。

可能原因

按出现概率从高到低:

1. 尺寸参数写法不对,或 4K 走的是独立参数/独立模型标识。很多平台并不是把 width 写大就能出大图,4K 往往对应另一个参数名、另一个模型标识,或者需要显式开启。概率靠前。

2. 客户端超时设置太短。4K 出图耗时明显长于低分辨率,HTTP 库默认 30 秒或 60 秒的读超时,很容易在服务端还在算的时候就被本地掐断。

3. 中文提示词写法问题。把要渲染的文字混在长句描述里、没有用引号或占位符隔离、字数太多、中英混排、同时要求字体风格和版式。

4. 并发太高触发限流。一次性并发几十个请求,返回 429。

5. 后处理环节把分辨率吃掉。保存时用了压缩参数、走了图片库的 resize、图片经过聊天软件或网盘中转被二次压缩。

6. 平台侧对 4K 或大尺寸有单独配额。账号权限、额度、并发上限未开。

7. 字体气质与提示词冲突。要求"毛笔""手写""书法"时,字形更容易崩。

8. 本地环境问题。依赖库版本、代理、证书、磁盘空间。

9. 读到了旧缓存或旧返回。文件名复用、本地缓存目录没清。

逐条排查与解决

第 1 条:确认尺寸参数到底有没有生效

先跑一个最小请求,把返回体完整打出来看字段:

```bash

curl -s -X POST "$API_BASE/v1/images/generations" \

-H "Authorization: Bearer $API_KEY" \

-H "Content-Type: application/json" \

-d '{"model":"'"$MODEL_ID"'","prompt":"一只橘猫坐在窗台上","size":"3840x2160","n":1}' \

| python -c "import sys,json;print(json.dumps(json.load(sys.stdin),ensure_ascii=False)[:800])"

```

判断方法:返回里如果有 size、width、height 字段,且和请求值不一致,就是被降级了。这时翻官方文档的"图片尺寸"或"参数说明"章节,确认 4K 对应的是哪个参数名、是否要换模型标识,以官方文档当前版本为准。

再验证真实像素,不看返回字段看文件本身:

```bash

file out.png # 有些格式会直接带尺寸信息

identify out.png # 装了 ImageMagick 时用这条

```

```python

from PIL import Image

im = Image.open("out.png")

print(im.size, im.mode) # 期望宽度 3840 左右

```

如果返回字段写的是 4K,但 Image.open().size 不是,问题出在下游:保存、传输或压缩环节。

第 2 条:确认是不是客户端超时

curl 加长超时:

```bash

curl -s --max-time 600 -X POST "$API_BASE/v1/images/generations" \

-H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \

-d '{"model":"'"$MODEL_ID"'","prompt":"测试超时","size":"3840x2160","n":1}' \

-o out.json -w "http=%{http_code} time=%{time_total}\n"

```

Python 侧把超时拆成连接超时和读超时:

```python

requests.post(url, headers=h, json=body, timeout=(10, 300))

```

判断方法:日志里出现 Read timed out、TimeoutError、ConnectionResetError,而平台后台任务列表里其实有成功记录——基本可以确定是本地超时太短,而不是服务端没出图。把读超时改到 300 秒以上再试一次即可确认。

第 3 条:把中文提示词的结构固定下来

可复用的写法是:场景描述 + 文字内容用引号单独拎出 + 明确数量和排布 + 明确"不出现其他文字"。

正例:

```

一张奶茶店促销海报。画面中央横排四个白色加粗黑体汉字,文字内容严格为:"第二杯半价"。

除这四个字以外,画面内不出现任何其他文字、字母或数字。背景为暖橙色渐变,右下角留白。

```

反例(同一需求,但约束被埋进长句):

```

做一个看起来像促销的、写着第二杯半价的感觉很热闹的奶茶海报,字要大一点酷一点。

```

判断方法:固定随机种子(平台支持时),只改文字部分,同一提示词连跑 5 次。

  • 每次错的位置都不一样 → 提示词约束不够,按上面的结构改写;
  • 每次都错同一个字 → 这个字本身难渲染,换成同义表达,或者把该字拆成后期叠字处理;
  • 只有字数超过十来个字时才错 → 超出模型稳定区间,改成"先生成无字底图,再后期排版"。

和上一版做中文字形与画质对比,用同一套方法

不要凭印象说"新版更好",按同一条件出对图:

1. 同一提示词、同一种子、同一尺寸,分别用上一版和新版各出一张;

2. 把两张图并排放在一起,缩放到同一像素宽度再看,避免"大图显得清楚"的错觉;

3. 文字区单独裁出来放大 2~3 倍,看笔画边缘是连贯还是有毛刺、粘连;

4. 用开源 OCR(如 tesseract,中文需要单独装语言包)回读图上文字,和预期串逐字比对;

5. 把结果记进一张表,逐条填,不填数字不下结论:

检查项上一版新版
4 字短词正确率(跑 10 次)
12 字长句正确率(跑 10 次)
竖排是否按要求
笔画边缘(放大后主观评价)
实际输出像素

经验上,新版在笔画连贯性和版式规整度上通常更稳,但长句和生僻字仍会出错;4K 直出相比"低分辨率再放大",边缘和细节保留更多,这一点在放大对比时能看出来。具体结论用你自己的表格数据说话。

第 4 条:限流与批量重试

判断方法:错误码 429,或响应头里带 Retry-After。把并发降到 2~4 起步,加上指数退避和随机抖动。

一个可以直接改的批量脚本骨架,包含重试、断点续跑和结果记录:

```python

import os, json, time, random, pathlib

from concurrent.futures import ThreadPoolExecutor

import requests

API_BASE = os.environ["API_BASE"]

API_KEY = os.environ["API_KEY"]

MODEL_ID = os.environ["MODEL_ID"] # 以官方文档当前版本为准

OUT = pathlib.Path("out"); OUT.mkdir(exist_ok=True)

LOG = pathlib.Path("log.jsonl")

def gen(prompt, size="3840x2160"):

r = requests.post(

f"{API_BASE}/v1/images/generations",

headers={"Authorization": f"Bearer {API_KEY}"},

json={"model": MODEL_ID, "prompt": prompt, "size": size, "n": 1},

timeout=(10, 300),

)

r.raise_for_status()

return r.json()

def gen_with_retry(prompt, tries=5):

last = None

for i in range(tries):

try:

return gen(prompt)

except requests.HTTPError as e:

code = e.response.status_code if e.response is not None else 0

last = f"HTTP {code}"

if code in (408, 429, 500, 502, 503, 504):

time.sleep(min(60, 2 ** i) + random.uniform(0, 1))

continue

raise

except (requests.Timeout, requests.ConnectionError) as e:

last = type(e).__name__

time.sleep(min(60, 2 ** i) + random.uniform(0, 1))

raise RuntimeError(f"重试耗尽: {last}")

def done_ids():

if not LOG.exists():

return set()

ok = set()

for line in LOG.read_text(encoding="utf-8").splitlines():

try:

rec = json.loads(line)

except json.JSONDecodeError:

continue

if rec.get("status") == "ok":

ok.add(rec["id"])

return ok

def run(task):

tid, prompt = task["id"], task["prompt"]

if tid in done_ids():

return

try:

data = gen_with_retry(prompt)

不同平台返回结构不同,按官方文档取图片内容或 URL

img = data["data"][0]

path = OUT / f"{tid}.png"

if "b64_json" in img:

import base64

path.write_bytes(base64.b64decode(img["b64_json"]))

else:

path.write_bytes(requests.get(img["url"], timeout=(10, 300)).content)

rec = {"id": tid, "status": "ok", "file": str(path), "prompt": prompt}

except Exception as e:

rec = {"id": tid, "status": "fail", "error": repr(e), "prompt": prompt}

with LOG.open("a", encoding="utf-8") as f:

f.write(json.dumps(rec, ensure_ascii=False) + "\n")

tasks = json.loads(pathlib.Path("tasks.json").read_text(encoding="utf-8"))

with ThreadPoolExecutor(max_workers=3) as pool: # 先 3,稳了再往上加

list(pool.map(run, tasks))

```

几个关键点:

  • 幂等:文件名用任务 id,不用序号,重跑不会互相覆盖;
  • 断点续跑:done_ids() 每次启动重读日志,已成功的不再重复提交;
  • 失败单独留痕:status=fail 的记录留在日志里,最后单独捞出来重试;
  • 并发从小到大:max_workers 从 2 或 3 开始,观察 429 出现频率再决定加不加。

判断方法:跑完后统计日志里 ok 和 fail 的比例。如果失败集中在某个时间段,多半是限流;如果失败分散且错误各不相同,多半是单条提示词或尺寸参数的问题。

第 5 条:检查后处理是否吃掉分辨率

绕开所有中间环节,直接把响应原始字节写盘:

```python

r = requests.post(url, headers=h, json=body, timeout=(10, 300))

open("raw.png", "wb").write(r.content)

```

然后 identify raw.png 看尺寸。如果这里是对的,但最终交付的文件不对,问题就在保存参数、resize 或传输环节,逐个关掉再验。

第 6 条:确认账号侧的大尺寸配额

先发一个低分辨率请求。低分辨率也失败,那是账号、密钥或网络问题;只有 4K 失败,就去看文档里有没有单独的开关、白名单或额度限制,以官方页面为准。

第 7 条:换个字体气质再试

把"毛笔""手写""书法"改成"黑体""无衬线",把装饰性要求降下来,看错字率是否下降。如果文字区域始终崩,改用"无字底图 + 后期叠字"。

第 8 条:本地环境

```bash

python -c "import sys, requests; print(sys.version); print(requests.__version__)"

df -h .

env | grep -i proxy

```

判断方法:磁盘写满、代理拦截 TLS、依赖库版本过旧,都会表现为"接口通但不返回完整数据"。

第 9 条:缓存与旧返回

换新文件名、加时间戳、清掉本地缓存目录再跑一次。这一步几秒钟就能排除,放在最后做。

都不管用时的兜底方案

方案一:降一级尺寸出图,再做放大。 把尺寸降到 2K 级别稳定出图,再用常见的图像放大工具做一次超分。画质不如原生 4K 直出,但至少能交付,适合赶时间的场景。

方案二:把文字从画面里拆出来。 提示词里只描述底图,明确"画面内不出现任何文字",然后用排版工具叠字。PIL 版本:

```python

from PIL import Image, ImageDraw, ImageFont

im = Image.open("bg.png").convert("RGB")

d = ImageDraw.Draw(im)

字体路径按本机实际字体改:Windows 常见 msyh.ttc,macOS 常见 PingFang.ttc,

Linux 常见 Noto Sans CJK

font = ImageFont.truetype("/path/to/NotoSansCJK-Bold.otf", 140)

text = "第二杯半价"

w = d.textlength(text, font=font)

d.text(((im.width - w) / 2, int(im.height * 0.42)), text,

font=font, fill=(255, 255, 255))

im.save("poster.png")

```

这样文字 100% 可控,模型只负责底图。ImageMagick 的 convert -annotate、Figma、PS 都能做同样的事。

方案三:换异步任务模式。 如果同步接口在 4K 下总超时,看文档里有没有"提交任务 + 轮询状态"的异步路径,以官方文档当前版本为准。异步模式对长耗时的容忍度更好。

方案四:从最小可复现例子重建。 关掉并发、关掉后处理、关掉所有可选参数,只留模型标识、提示词、尺寸三个字段,跑通一次,再一项一项往回加。哪一项加回去就坏,问题就在那一项。

如何预防再次发生

建一套回归测试集。 固定 5 条左右提示词:四字短词、十二字长句、竖排、中英混排、纯图形不带字。每次升级模型或改参数,跑一遍,人工过一眼字。字数少、结构固定的用例先跑,能第一时间发现字形退化。

把验收标准写死在脚本里。 三条硬指标:输出真实像素不低于请求值;OCR 回读的文字与预期完全一致;批量失败率低于你自己定的阈值(比如 5%)。不达标就不交付,不靠肉眼扫一遍。

参数集中管理。 把模型标识、尺寸、超时、并发数、重试次数放进一个配置文件或环境变量,改一处全局生效,避免脚本里散落着写死的尺寸字符串。

日志留全。 每条任务记录:任务 id、提示词、模型标识、尺寸、返回状态、错误信息、耗时。出问题时,日志能直接告诉你是限流还是参数问题,不用重跑一遍。

批量任务做幂等和断点续跑。 文件名用任务 id,成功的任务不重复提交,失败的任务单独放一个目录方便重试。跑长任务前先确认磁盘空间够。

中文字数控制在稳定区间。 画面内文字控制在几个字到十几个字;超过这个量级,直接走"无字底图 + 后期叠字",比反复重试省钱也省时间。

关注官方变更说明。 模型版本、参数名、尺寸支持范围都可能调整,上线前看一眼官方文档当前版本,比事后排查便宜得多。

AI 生成本文由 AI 基于公开信息自动生成,仅供参考。