1. 生图接口的图片输入到底怎么传
生图接口的图片输入传递方式,是很多开发者在接入多模型生图能力时第一个卡住的地方。文生图只需要给一段文字描述,图生图却要把参考图和指令一起塞进请求体,两者的参数结构完全不同。如果你正在做 AI 绘画工具、电商换背景、批量出图流水线,或者只是想把生图能力接进自己的后端服务,这篇会帮你把两种模式的传参差异彻底理清。
核心问题其实就一个:图片输入到底放在哪个字段里,用什么格式传。OpenAI 兼容协议下,文生图的content是纯字符串,图生图的content是数组,数组里同时包含image_url和text两种类型的元素。这个差异看起来小,但传错了就是 400 报错,或者模型完全忽略你的参考图。
我实测下来,最容易踩的坑有三个:一是把本地文件路径直接塞进image_url,服务端根本访问不到;二是文生图和图生图共用一套请求体,结果图生图模式下参考图被当成普通文本;三是超时设置照抄对话接口的 30 秒,图还没生成完客户端就断了,钱花了图没拿到。
这篇会给出 TaoToken 统一 Key 的配置骨架、文生图与图生图的请求体参数对照表,以及可以直接复制的 curl 验证命令。目标很明确:让你在半小时内跑通两种模式,并且知道每个参数为什么这么传。
2. TaoToken 统一 Key 的前置配置
TaoToken 的定位是统一密钥接入多模型生图能力,端点兼容 OpenAI 协议,换model字符串就能切换模型,不用为每个模型单独写一套 SDK。官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 端点是 https://taotoken.net/api 。
在开始写生图代码之前,先把密钥和基础配置准备好。这一步不复杂,但配置文件的字段名写错了后面会一直报 401。
2.1 获取 API Key
登录后进入控制台,在 API Keys 页面创建一个新密钥。建议按项目或环境分开创建,比如dev-image、prod-image,方便后续排查是哪个环境在消耗额度。密钥只在创建时完整显示一次,复制后立刻存进环境变量或密钥管理服务,不要硬编码进代码仓库。
如果你用的是 Claude Code 或类似的编码 Agent 工具,长期跑生图任务的话可以看下 Coding Plan,额度模型和按次计费不太一样,批量场景下更划算。
2.2 settings.json 配置片段
如果你用的是支持settings.json的工具链(比如某些 CLI 或 IDE 插件),配置骨架大概长这样:
{ "image": { "baseUrl": "https://taotoken.net/api", "apiKey": "${TAOTOKEN_API_KEY}", "defaultModel": "gpt-image-2", "timeoutMs": 120000, "models": { "draft": "nano-banana2", "final": "gpt-image-2", "wide": "nano-banana-pro" } } }这里把模型分了三档:draft跑量试错,final出终稿,wide处理超宽超高比例。超时统一给到 120 秒,因为生图是整张图生成完才返回,中间没有任何流式输出。
2.3 config.toml 配置片段
如果你的项目用 TOML 管理配置,等价写法如下:
[image] base_url = "https://taotoken.net/api" api_key = "${TAOTOKEN_API_KEY}" default_model = "gpt-image-2" timeout_ms = 120000 [image.models] draft = "nano-banana2" final = "gpt-image-2" wide = "nano-banana-pro"两种格式选一种就行,关键是base_url不要带多余的路径,/v1之类的后缀由具体端点拼接时处理。TaoToken 的 API 地址就是https://taotoken.net/api,不要自己加 UTM 参数到 API 调用里,那些参数只用于官网跳转统计。
注意:环境变量
TAOTOKEN_API_KEY要在启动服务前注入,不要写死在配置文件里提交到 Git。CI/CD 环境用 secrets 管理。
3. 文生图与图生图的请求体参数对照
这是整篇最核心的部分。文生图和图生图在 OpenAI 兼容协议下走的是同一个端点,区别只在messages[].content的结构。下面用表格把两种模式的参数差异列清楚。
| 参数 | 文生图 | 图生图 | 说明 |
|---|---|---|---|
model | 必填 | 必填 | 模型 ID,如gpt-image-2 |
messages[0].role | user | user | 固定值 |
messages[0].content | 字符串 | 数组 | 核心差异所在 |
content[].type | 无 | image_url/text | 图生图必须显式声明类型 |
content[].image_url.url | 无 | 可访问的 URL | 本地文件需先上传 |
content[].text | 无 | 指令文本 | 描述要改什么 |
timeout | 建议 120s | 建议 120s | 生图比对话慢得多 |
文生图的content就是一段描述文字,模型根据文字从零生成图片。图生图的content是一个数组,里面至少有一个image_url元素和一个text元素,模型根据参考图和指令做修改、换背景、局部调整。
3.1 文生图请求体
{ "model": "gpt-image-2", "messages": [ { "role": "user", "content": "一只橘猫坐在窗台上,午后阳光,浅景深,胶片质感" } ] }content直接给字符串,不需要任何类型声明。这是最简单的形式,也是很多人第一次接生图接口时唯一会写的模式。
3.2 图生图请求体
{ "model": "gpt-image-2", "messages": [ { "role": "user", "content": [ { "type": "image_url", "image_url": { "url": "https://your-cdn.example.com/input/cat.jpg" } }, { "type": "text", "text": "把背景换成海边日落,猫的位置和姿态保持不变" } ] } ] }注意content从字符串变成了数组,每个元素都有type字段。image_url的url必须是服务端能访问到的公网地址,内网地址、localhost、本地文件路径都不行。
3.3 两种模式共用一个封装函数
既然只有content一处不同,完全可以封装成一个函数,根据是否传入参考图自动切换:
async function generateImage({ prompt, imageUrl, model = 'gpt-image-2' }) { const content = imageUrl ? [ { type: 'image_url', image_url: { url: imageUrl } }, { type: 'text', text: prompt }, ] : prompt; const res = await fetch('https://taotoken.net/api/v1/chat/completions', { method: 'POST', headers: { Authorization: `Bearer ${process.env.TAOTOKEN_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model, messages: [{ role: 'user', content }], }), signal: AbortSignal.timeout(120000), }); if (!res.ok) { const err = await res.text(); throw new Error(`${model} HTTP ${res.status}: ${err}`); } return res.json(); }调用文生图时只传prompt,调用图生图时同时传prompt和imageUrl。这样业务层不用关心底层是哪种模式,传参逻辑收敛在一个地方,后面排查问题也方便。
4. 用 curl 验证两种模式
配置和封装写完之后,先用 curl 把两种模式各跑一遍,确认密钥、端点、参数都没问题,再往业务代码里集成。这样出问题时能快速定位是配置层还是业务层。
4.1 文生图验证
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "nano-banana2", "messages": [ { "role": "user", "content": "一只柴犬在草地上奔跑,晴天,运动模糊背景" } ] }'跑量场景先用nano-banana2,出图快、成本低,适合验证链路通不通。返回结果里会包含图片的 URL 或 base64 数据,具体格式取决于模型。
4.2 图生图验证
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-2", "messages": [ { "role": "user", "content": [ { "type": "image_url", "image_url": { "url": "https://your-cdn.example.com/input/dog.jpg" } }, { "type": "text", "text": "把草地换成雪地,柴犬的毛色和姿态不变" } ] } ] }'图生图验证时,先把参考图上传到自己的对象存储或图床,拿到公网可访问的 URL 再填进image_url.url。这一步不能省,直接填本地路径一定会失败。
4.3 成功返回的特征
两种模式成功后返回的结构类似,都会包含生成结果。你需要关注的是:HTTP 状态码 200、返回体里有图片数据或图片 URL、没有error字段。如果返回 200 但内容为空,大概率是模型 ID 写错了,或者content结构不符合该模型的要求。
拿到返回的图片 URL 后,立刻转存到自己的存储。返回链接通常有有效期,过期就取不回来了,数据库里应该存自己的地址而不是上游的临时链接。
5. 本篇常见传参报错排查
生图接口的报错信息有时候不太直观,下面把最常见的几类问题和排查方向列出来。
5.1 400 报错:content 类型不匹配
如果你在文生图模式下传了数组,或者图生图模式下传了字符串,都会触发 400。排查方法很简单:看你的content是字符串还是数组。文生图必须是字符串,图生图必须是数组且每个元素带type。
还有一种情况是图生图的数组里只有text没有image_url,或者只有image_url没有text。两种元素至少要各有一个,否则模型不知道你要改什么。
5.2 图片 URL 无法访问
图生图最常见的失败原因是参考图 URL 服务端拉不到。可能的原因包括:用了内网地址、用了localhost、图片需要鉴权、URL 有防盗链、图片格式不被支持。排查时先用curl -I检查这个 URL 在公网能不能直接访问,返回 200 且Content-Type是图片类型才行。
5.3 超时导致图丢失
把超时设成 30 秒是很多人的默认习惯,因为对话接口 30 秒够用。但生图是整张图生成完才返回,重模型可能要一两分钟。客户端提前断开后,服务端其实已经出图成功,这次调用照样计费,但图拿不到。
解决办法是按模型分档设置超时:跑量的快模型给 60 秒,终稿的重模型给 120 秒。重试之前先确认上一次是真失败还是只是客户端超时,否则会重复计费。
5.4 前端直接调接口导致密钥泄露
生图接口不应该由前端直接调用。一是前端等两分钟不现实,二是密钥会打进前端包。正确做法是后端收到请求先落一条任务记录返回任务 ID,后台异步跑生图,前端轮询自己的任务表。这样既避免了密钥泄露,也避免了前端超时。
5.5 返回链接过期
上游返回的图片链接是有有效期的,直接存进数据库过几天就失效了。拿到结果后立刻转存到自己的对象存储,数据库里存自己的地址。这一步在批量场景下尤其重要,否则历史记录里的图全变成裂图。
6. 把生图能力稳定接进业务
跑通两种模式只是第一步,真正上线还要考虑成本控制和稳定性。核心思路是分级:跑量用便宜的快模型多出几版,挑中的才用贵的出终稿。一上来就用最贵的模型试错,钱都花在废图上了。
再加一层结果缓存,同样的描述和参数如果已经出过图,直接返回旧结果,不要重复调用。批量场景下这一层省下的比换模型还多。
如果你需要长期跑生图任务,或者在做编码 Agent 相关的图像生成功能,可以看下 Coding Plan 的额度模型。模型对话页面可以直接测试不同模型的出图效果,接入文档里有完整的端点和参数说明,API Keys 页面管理你的密钥。
生图接口的图片输入传递,说到底就是记住一件事:文生图content给字符串,图生图content给数组,数组里image_url和text各司其职。把这个结构记牢,剩下的就是超时、重试、转存这些工程细节。