Skip to content

第 12 章 · 图片输入与图像生成

本章目标:学会向视觉模型发送图片输入、使用图像生成能力,并在 Agent 中实现多模态交互。

12.1 图片输入基础

支持视觉的模型可以处理图片。与思考能力一样,先用模型属性判断能力,不匹配时静默忽略:

typescript
import { readFileSync } from 'fs';
import { createModels } from '@earendil-works/pi-ai';

const models = createModels();
const model = models.getModel('openai', 'gpt-4o-mini')!;

// 通过 input 属性检查是否支持图片输入
if (model.input.includes('image')) {
  console.log('Model supports vision');
}

// 读取本地图片并转为 base64
const imageBuffer = readFileSync('image.png');
const base64Image = imageBuffer.toString('base64');

12.2 发送带图消息

用户消息的 content 可以是字符串,也可以是内容块数组——把文本块和图片块混在一起即可实现"看图说话":

typescript
const response = await models.complete(model, {
  messages: [{
    role: 'user',
    timestamp: Date.now(),
    content: [
      // 文本块:提出问题
      { type: 'text', text: 'What is in this image?' },
      // 图片块:base64 数据 + MIME 类型
      { type: 'image', data: base64Image, mimeType: 'image/png' },
    ],
  }],
});

// 遍历响应内容块
for (const block of response.content) {
  if (block.type === 'text') {
    console.log(block.text);
  }
}

给非视觉模型发图不会报错

如果目标模型的 input 不含 image,图片会被静默忽略——模型只看到文字。生产代码应显式检查能力或做路由兜底。

12.3 在 Agent 中发送图片

Agent.prompt() 第二个参数直接接受图片附件数组:

typescript
import { Agent } from '@earendil-works/pi-agent-core';

const agent = new Agent({
  initialState: {
    systemPrompt: '你是看图助手,用中文描述图片内容。',
    model,
    tools: [],
    messages: [],
  },
  streamFn: models.streamSimple.bind(models),
});

// 文本 + 图片一起作为一条 prompt 发出
await agent.prompt('这张图里有什么?', [
  { type: 'image', data: base64Image, mimeType: 'image/jpeg' },
]);

多张图片同样支持——在数组里放多个 image 块,模型会一并理解。

12.4 图像生成

除了"读图",pi-ai 也封装了图像生成能力。生成方向是反过来的:文字进、图片数据出。典型流程:

typescript
// 图像生成:请求返回的 content 中包含图片数据块
const gen = await models.complete(genModel, {
  messages: [{
    role: 'user',
    content: '画一只在写 TypeScript 的猫,扁平插画风',
    timestamp: Date.now(),
  }],
});

for (const block of gen.content) {
  if (block.type === 'image') {
    // 把生成的图片保存到磁盘
    writeFileSync('cat.png', Buffer.from(block.data, 'base64'));
  }
}

选择生成模型时,同样通过目录查询确认模型具备图像输出能力,避免把生成任务路由到纯文本模型。

12.5 多模态实践建议

构建真实多模态应用时的几条经验:

  1. 压缩再上传——大图先缩放到合理分辨率(如最长边 1568px 内),省 token 且更快;
  2. 明确提问——"描述这张图"不如"图中有几辆红色的车"得到稳定结果;
  3. 错误兜底——对不支持视觉的模型准备纯文字降级(如 OCR 结果拼接);
  4. 成本控制——图片按 token 计费且价格高于文本,非必要不传高清原图。

一个实用的能力路由函数:

typescript
// 按能力自动选模型的简单路由器
function pickVisionModel(models: Models, preferCheaper = true) {
  const candidates = ['gpt-4o-mini', 'claude-sonnet-4-5', 'gemini-2.5-flash'];
  const found = candidates
    .map((name) => /* 逐个提供商查询 */ models.getModel('openai', name))
    .filter((m): m is NonNullable<typeof m> => !!m && m.input.includes('image'));
  return preferCheaper ? found.at(-1) : found[0];
}

本章小结

  • model.input.includes('image') 判断视觉能力;给非视觉模型发图会被静默忽略;
  • 用户消息 content 用块数组混合 text + image,图片以 base64 + mimeType 表示;
  • agent.prompt(text, images[]) 是 Agent 中发送图片的快捷方式;
  • 图像生成返回的 content 中含 image 块,可解码为文件;
  • 多模态应用要做压缩、明确提问、能力路由和成本控制。

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. 如何判断一个模型是否支持图片输入?

2. 向不支持视觉的模型发送图片会发生什么?

3. 在 Agent.prompt() 中附带图片的正确方式是?

4. 下列哪条不是多模态应用的推荐做法?

🛠️ 动手实践

  1. 写一个命令行工具:接收图片路径参数,调用视觉模型输出图片描述,并处理"模型不支持视觉"的情况。
  2. 实现批量图片分类脚本:读取目录下所有 png,让模型给每张图打标签,结果写入 JSON。
  3. 给第 11 章的算法助手加上截图分析能力:粘贴题目截图即可讲解解题思路。

下一章处理生产环境绕不开的话题——第 13 章 · 停止原因、中止与错误处理