第 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 多模态实践建议
构建真实多模态应用时的几条经验:
- 压缩再上传——大图先缩放到合理分辨率(如最长边 1568px 内),省 token 且更快;
- 明确提问——"描述这张图"不如"图中有几辆红色的车"得到稳定结果;
- 错误兜底——对不支持视觉的模型准备纯文字降级(如 OCR 结果拼接);
- 成本控制——图片按 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. 下列哪条不是多模态应用的推荐做法?
🛠️ 动手实践
- 写一个命令行工具:接收图片路径参数,调用视觉模型输出图片描述,并处理"模型不支持视觉"的情况。
- 实现批量图片分类脚本:读取目录下所有 png,让模型给每张图打标签,结果写入 JSON。
- 给第 11 章的算法助手加上截图分析能力:粘贴题目截图即可讲解解题思路。
下一章处理生产环境绕不开的话题——第 13 章 · 停止原因、中止与错误处理。