Skip to content

第 14 章 · 图像生成与多模态输入

本章目标:

  • 掌握 generateImage 生成图像的基本用法与尺寸/宽高比设置
  • 学会批量生成、指定 seed、providerOptions 等高级配置
  • 了解 wrapImageModel 图像模型中间件与错误处理
  • 掌握 uploadFile 上传文件并通过 ProviderReference 引用的机制
  • 理解多 provider 场景下的文件引用合并策略

14.1 用 generateImage 生成图像

AI SDK 提供 generateImage 函数,基于给定 prompt 使用 image model 生成图像。

tsx
import { generateImage, createGateway } from 'ai';
import 'dotenv/config';

const gateway = createGateway({ apiKey: process.env.AI_GATEWAY_API_KEY ?? '' });

// 字符串模型 ID 会经全局默认 provider(AI Gateway)解析;
// 自定义 OpenAI 兼容 provider 可用 myProvider.image('your-image-model')
const { image } = await generateImage({
  model: gateway.image('openai/dall-e-3'),
  prompt: 'Santa Claus driving a Cadillac',
});

你可以通过 base64uint8Array 属性访问图像数据:

tsx
const base64 = image.base64; // base64 图像数据
const uint8Array = image.uint8Array; // Uint8Array 二进制数据

14.2 基础设置

尺寸(Size)与宽高比(Aspect Ratio)

根据模型不同,你可以指定 size 或 aspect ratio。size 以 {width}x{height} 格式的字符串表示——模型仅支持少数几种尺寸,且不同模型和 provider 各不相同:

tsx
import { generateImage } from 'ai';
import 'dotenv/config';

const { image } = await generateImage({
  model: 'openai/dall-e-3',
  prompt: 'Santa Claus driving a Cadillac',
  size: '1024x1024',
});

aspect ratio 则以 {width}:{height} 格式表示,同样只有部分取值可用:

tsx
import { generateImage } from 'ai';
import 'dotenv/config';

const { image } = await generateImage({
  model: 'openai/dall-e-3',
  prompt: 'Santa Claus driving a Cadillac',
  aspectRatio: '16:9',
});

批量生成多张图

generateImage 支持一次生成多张图像:

tsx
import { generateImage } from 'ai';
import 'dotenv/config';

const { images } = await generateImage({
  model: 'openai/dall-e-3',
  prompt: 'Santa Claus driving a Cadillac',
  n: 4, // number of images to generate
});

generateImage 会自动按需(并行)调用模型以生成请求数量的图像。每个 image model 对单次 API 调用能生成的图片数有内部上限,SDK 会自动合理分批(例如 DALL-E 3 单次只能生成 1 张,DALL-E 2 单次最多 10 张)。

如有需要,可通过 maxImagesPerCall 覆盖默认批量大小——这对新增或自定义模型尤其有用:

tsx
const { images } = await generateImage({
  model: 'openai/dall-e-2',
  prompt: 'Santa Claus driving a Cadillac',
  maxImagesPerCall: 5, // Override the default batch size
  n: 10, // Will make 2 calls of 5 images each
});

指定 Seed

提供 seed 可以控制图像生成的输出。如果模型支持,相同 seed 总是产出相同图像:

tsx
import { generateImage } from 'ai';
import 'dotenv/config';

const { image } = await generateImage({
  model: 'openai/dall-e-3',
  prompt: 'Santa Claus driving a Cadillac',
  seed: 1234567890,
});

Provider 专属设置

image model 通常有 provider 甚至模型专属的设置,通过 providerOptions 参数传入即可(选项会成为请求体属性)。下面的示例沿用官方文档中 OpenAI 的写法展示 providerOptions 的结构:

tsx
import { generateImage, createGateway } from 'ai';
import 'dotenv/config';

const gateway = createGateway({ apiKey: process.env.AI_GATEWAY_API_KEY ?? '' });

const { image } = await generateImage({
  model: gateway.image('openai/dall-e-3'),
  prompt: 'Santa Claus driving a Cadillac',
  size: '1024x1024',
  providerOptions: {
    openai: {
      style: 'vivid',
      quality: 'hd',
    },
  },
});

中止信号与超时

generateImage 接受可选的 AbortSignal 类型 abortSignal 参数,可用于中止图像生成或设置超时:

ts
import { generateImage } from 'ai';
import 'dotenv/config';

const { image } = await generateImage({
  model: 'openai/dall-e-3',
  prompt: 'Santa Claus driving a Cadillac',
  abortSignal: AbortSignal.timeout(1000), // Abort after 1 second
});

自定义 Headers 与警告

可选的 headers 参数(类型 Record<string, string>)可为图像生成请求添加自定义 header;若模型返回警告(例如不支持的参数),可在结果的 warnings 属性中获取:

tsx
const { image, warnings } = await generateImage({
  model: 'openai/dall-e-3',
  prompt: 'Santa Claus driving a Cadillac',
});

Provider 附加元数据

一些 provider 会在结果整体或每张图上暴露额外的元数据。返回的 providerMetadata 外层键是 provider 名,内层是元数据;其中总有一个 images 键,是与顶层 images 数组等长的数组:

tsx
const prompt = 'Santa Claus driving a Cadillac';

const { image, providerMetadata } = await generateImage({
  model: 'openai/dall-e-3',
  prompt,
});

const revisedPrompt = providerMetadata.openai.images[0]?.revisedPrompt;

console.log({
  prompt,
  revisedPrompt,
});

14.3 错误处理

generateImage 无法生成有效图像时,会抛出 AI_NoImageGeneratedError。该错误的可能原因:模型未能生成响应,或生成了无法解析的响应。

错误对象保留了以下信息便于记录问题:responses(图像模型响应元数据,含时间戳、模型、headers)和 cause(根因,可用于更细粒度的错误处理):

ts
import { generateImage, NoImageGeneratedError } from 'ai';

try {
  await generateImage({ model: 'openai/dall-e-3', prompt: 'A futuristic city' });
} catch (error) {
  if (NoImageGeneratedError.isInstance(error)) {
    console.log('NoImageGeneratedError');
    console.log('Cause:', error.cause);
    console.log('Responses:', error.responses);
  }
}

14.4 图像中间件(Image Middleware)

可以使用 wrapImageModelImageModelV4Middleware 增强 image model,比如设置默认值或实现日志。下面是一个在未提供 size 时设置默认值的示例:

ts
import { generateImage, wrapImageModel, createGateway } from 'ai';
import 'dotenv/config';

const gateway = createGateway({ apiKey: process.env.AI_GATEWAY_API_KEY ?? '' });

const model = wrapImageModel({
  model: gateway.image('openai/dall-e-3'),
  middleware: {
    specificationVersion: 'v3',
    transformParams: async ({ params }) => ({
      ...params,
      size: params.size ?? '1024x1024',
    }),
  },
});

const { image } = await generateImage({
  model,
  prompt: 'Santa Claus driving a Cadillac',
});

14.5 用语言模型生成图像

一些语言模型(如 Google gemini-2.5-flash-image)支持包含图像的多模态输出。使用这类模型时,可以通过响应的 files 属性访问生成的图像:

ts
import { generateText, createGateway } from 'ai';
import 'dotenv/config';

const gateway = createGateway({ apiKey: process.env.AI_GATEWAY_API_KEY ?? '' });

const result = await generateText({
  model: gateway('google/gemini-2.5-flash-image'),
  prompt: 'Generate an image of a comic cat',
});

for (const file of result.files) {
  if (file.mediaType.startsWith('image/')) {
    // The file object provides multiple data formats:
    // Access images as base64 string, Uint8Array binary data, or check type
    // - file.base64: string (data URL format)
    // - file.uint8Array: Uint8Array (binary data)
    // - file.mediaType: string (e.g. "image/png")
  }
}

官方文档维护了各 provider 的 image models 及其支持尺寸/宽高比的清单(xAI Grok、OpenAI gpt-image-2/dall-e 系列、Amazon Nova Canvas、Fal FLUX 系列、Google Gemini Image、Black Forest Labs flux-kontext 等),详见 Image Generation 页面的 Image Models 表格。

14.6 文件上传(File Uploads)

AI SDK 提供 uploadFile 函数,把文件上传到 provider 并拿回一个 ProviderReference 用于后续 API 调用。

在 AI SDK 中,上传后的文件由一个 ProviderReference 标识——它是把 provider 名映射到 provider 专属标识符的 Record<string, string>。这一概念也用于其他 provider 专属资源引用(如已上传的 skills):

ts
import { uploadFile, generateText, createGateway } from 'ai';
import fs from 'node:fs';
import 'dotenv/config';

const gateway = createGateway({ apiKey: process.env.AI_GATEWAY_API_KEY ?? '' });

const { providerReference } = await uploadFile({
  api: gateway,
  data: fs.readFileSync('./photo.png'),
  filename: 'photo.png',
});

const { text } = await generateText({
  model: gateway('openai/gpt-5'),
  messages: [
    {
      role: 'user',
      content: [
        { type: 'text', text: 'Describe what you see in this image.' },
        { type: 'file', mediaType: 'image', data: providerReference },
      ],
    },
  ],
});

作为简写,可以直接把 provider 实例传给 api 而不必显式调用 .files()——SDK 会替你调用:

ts
const { providerReference } = await uploadFile({
  api: gateway, // shorthand for gateway.files()
  data: fs.readFileSync('./photo.png'),
  filename: 'photo.png',
});

支持的文件类型

依据 provider 的不同,可以上传图片、PDF、文本文件和其他文档。未显式指定时会从文件字节自动探测 media type:

ts
const { providerReference } = await uploadFile({
  api: gateway,
  data: fs.readFileSync('./document.pdf'),
  mediaType: 'application/pdf', // optional, auto-detected if omitted
  filename: 'document.pdf',
});

在文件 content part 中使用 providerReference 时带上 media type:

ts
{
  role: 'user',
  content: [
    { type: 'text', text: 'Summarize this document.' },
    { type: 'file', data: providerReference, mediaType: 'application/pdf' },
  ],
}

Provider 专属选项

一些 provider 通过 providerOptions 接受额外选项,例如 OpenAI 要求 purpose 字段:

ts
const { providerReference } = await uploadFile({
  api: gateway,
  data: fs.readFileSync('./photo.png'),
  providerOptions: {
    openai: {
      purpose: 'assistants',
    },
  },
});

Provider References 的结构

ProviderReference 是把 provider 名映射到 provider 专属文件标识的 Record<string, string>

ts
// Example ProviderReference
{
  openai: 'file-abc123',
}

当把 ProviderReference 作为消息 content part 的 dataimage 字段传入时,当前 provider 会从中查找自己的文件 ID;如果引用里没有当前 provider 的条目,就会抛出错误。

多 Provider 使用

如果在对话中途切换 provider(比如把 OpenAI 开启的对话续接到 Anthropic),需要把文件上传到两个 provider 并合并引用:

ts
const openaiResult = await uploadFile({
  api: gateway,
  data: imageBytes,
  filename: 'photo.png',
});

const anthropicResult = await uploadFile({
  api: gateway,
  data: imageBytes,
  filename: 'photo.png',
});

const mergedProviderReference = {
  ...openaiResult.providerReference,
  ...anthropicResult.providerReference,
};

这样合并后的引用对两个 provider 都有效——这也正是「同一份文件跨网关与自定义 provider 复用」的关键技巧。

本章小结

  • generateImage 是图像生成的统一入口,支持 size / aspectRatio / n / seed / abortSignal / headers
  • 多图生成由 SDK 自动并行分批,maxImagesPerCall 可覆盖单次调用上限;
  • provider 专属参数与元数据分别走 providerOptionsproviderMetadata
  • 失败抛出 NoImageGeneratedError,用 isInstance 判定并读取 cause / responses
  • wrapImageModel 可以给 image model 加中间件(如默认尺寸);支持图像输出的语言模型通过 result.files 取图;
  • uploadFile 返回 ProviderReference(provider 名 → 文件 ID 的映射),跨 provider 复用时需上传到各 provider 后合并引用。

🛠️ 动手实践

  1. generateImage 分别以 size: '1024x1024'aspectRatio: '16:9' 各生成一张图,把 uint8Array 写入本地 png 文件并对比效果。
  2. 实现「同 prompt + 同 seed 两次调用结果一致」的验证脚本;再尝试 n: 3 批量生成并打印 images.length
  3. 编写脚本:上传一张本地 PDF 到 AI Gateway,然后用文件 content part 发起 generateText 让模型总结内容;再把返回的 providerReference 打印出来观察其键值结构。