第 4 章 · 提示词与消息模型
本章目标:
- 掌握三种提示词形态:text prompt、system prompt(
instructions)与 message prompt- 理解
ModelMessage的角色体系与 content parts 结构- 学会在消息中携带图像、PDF、音频等多模态内容
- 了解 providerOptions 在函数级 / 消息级 / 消息部件级的三个作用层次
4.1 Prompt 是什么
Prompt(提示词)是你给大语言模型的指令,告诉它要做什么。就像向人问路——问题越清晰,得到的指引越好。
许多 LLM provider 的提示词接口很复杂,涉及不同的角色与消息类型。虽然强大,但难以理解和使用。为简化提示编写,AI SDK 支持 text、message、system 三种提示形式。
4.2 Text Prompt
Text prompt 就是字符串,适合简单的生成场景,例如对同一提示文本的不同变体反复生成。通过 generateText 或 streamText 等 AI SDK 函数的 prompt 属性设置:
import { generateText, createGateway } from 'ai';
const gateway = createGateway({
apiKey: process.env.AI_GATEWAY_API_KEY ?? '',
});
const result = await generateText({
model: gateway('openai/gpt-5'),
prompt: 'Invent a new holiday and describe its traditions.',
});可以用模板字面量为 prompt 注入动态数据:
const result = await generateText({
model,
prompt:
`I am planning a trip to ${destination} for ${lengthOfStay} days. ` +
`Please suggest the best tourist activities for me to do.`,
});4.3 System Prompt:instructions
System prompt 是给模型的初始指令集,用于引导和约束模型的行为与响应方式,通过 instructions 属性设置。它可与 prompt 或 messages 属性同时使用。
⚠️ 注意:默认情况下 prompt/messages 中的 system 消息会被拒绝;要么用 instructions 属性传系统指令,要么在发送含系统消息的历史记录时显式设置 allowSystemInMessages: true。
const result = await generateText({
model,
instructions:
`You help planning travel itineraries. ` +
`Respond to the users' request with a list ` +
`of the best stops to make in their destination.`,
prompt:
`I am planning a trip to ${destination} for ${lengthOfStay} days. ` +
`Please suggest the best tourist activities for me to do.`,
});⚠️ 开启
allowSystemInMessages会引入 prompt injection 风险——用户可能通过注入 system 消息覆盖系统提示。大多数情况下,只应由受信任的服务端代码通过instructions设置系统指令。
4.4 Message Prompt
Message prompt 是 user、assistant、tool 消息组成的数组,适合聊天界面和更复杂的多模态提示,通过 messages 属性设置。
每条消息都有 role 和 content 属性。content 既可以是纯文本,也可以是与该消息类型相关的内容部件(parts)数组:
const result = await generateText({
model,
messages: [
{ role: 'user', content: 'Hi!' },
{ role: 'assistant', content: 'Hello, how can I help?' },
{ role: 'user', content: 'Where can I buy the best Currywurst in Berlin?' },
],
});⚠️ 并非所有模型都支持所有消息与内容类型。例如某些模型不支持多模态输入或 tool 消息,请查阅所用模型的 capability 说明。
4.5 Provider Options 的三个层次
可以通过 providerOptions 把 provider 特有的元数据透传给底层 API,共有三个粒度:
函数调用级——不需要细粒度控制时使用:
const { text } = await generateText({
model,
providerOptions: {
openai: {
reasoningEffort: 'low',
},
},
prompt: 'Invent a new holiday and describe its traditions.',
});消息级——精确控制某条消息的行为,例如给 system 消息打上缓存断点:
const result = await generateText({
model,
instructions: {
role: 'system',
content: 'Cached system message',
providerOptions: {
// Sets a cache control breakpoint on the system message
anthropic: { cacheControl: { type: 'ephemeral' } },
},
},
prompt: 'Invent a new holiday and describe its traditions.',
});消息部件级——某些 provider 特有选项必须配置到具体的 part 上:
import { ModelMessage } from 'ai';
const messages: ModelMessage[] = [
{
role: 'user',
content: [
{
type: 'text',
text: 'Describe the image in detail.',
providerOptions: {
openai: { imageDetail: 'low' },
},
},
{
type: 'file',
mediaType: 'image',
data: 'https://github.com/vercel/ai/blob/main/examples/ai-functions/data/comic-cat.png?raw=true',
// Sets image detail configuration for image part:
providerOptions: {
openai: { imageDetail: 'low' },
},
},
],
},
];💡 AI SDK UI 的 hooks(如
useChat)返回的UIMessage数组不支持 provider options;应先用convertToModelMessages转成ModelMessage再附加。
4.6 User Messages:多模态内容部件
Text Parts
文本是最常见的内容类型。如果只需发文本,content 直接给字符串即可;也可以拆成多个 parts:
const result = await generateText({
model,
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: 'Where can I buy the best Currywurst in Berlin?',
},
],
},
],
});Image Parts
用户消息可包含图像,支持四种来源:
- base64 编码图像(字符串或 data URL);
- 二进制数据(
ArrayBuffer/Uint8Array/Buffer); - URL 字符串或
URL对象。
二进制图像示例(Buffer):
import fs from 'node:fs';
const result = await generateText({
model,
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'Describe the image in detail.' },
{
type: 'file',
mediaType: 'image',
data: fs.readFileSync('./data/comic-cat.png'),
},
],
},
],
});base64 与 URL 示例:
// base64
{
type: 'file',
mediaType: 'image',
data: fs.readFileSync('./data/comic-cat.png').toString('base64'),
}
// URL
{
type: 'file',
mediaType: 'image',
data: 'https://github.com/vercel/ai/blob/main/examples/ai-functions/data/comic-cat.png?raw=true',
}File Parts
用户消息还可以携带文件(同样支持 base64、二进制、URL 三种来源),需要指定 MIME 类型。目前仅部分 provider/model 支持文件部件(Google Generative AI、Google Vertex AI、OpenAI 音频/PDF、Anthropic 等)。
PDF 文件示例:
import fs from 'node:fs';
import { generateText } from 'ai';
const result = await generateText({
model,
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'What is the file about?' },
{
type: 'file',
mediaType: 'application/pdf',
data: fs.readFileSync('./data/example.pdf'),
filename: 'example.pdf', // optional, not used by all providers
},
],
},
],
});mp3 音频文件示例:
import fs from 'node:fs';
import { generateText } from 'ai';
const result = await generateText({
model,
messages: [
{
role: 'user',
content: [
{ type: 'text', text: 'What is the audio saying?' },
{
type: 'file',
mediaType: 'audio/mpeg',
data: fs.readFileSync('./data/galileo.mp3'),
},
],
},
],
});自定义下载函数(实验性)
默认实现会并行自动下载模型不支持的 URL 文件。你可以传入 experimental_download 实现限流、重试、认证、缓存等自定义逻辑:
const result = await generateText({
model,
experimental_download: async (
requestedDownloads: Array<{
url: URL;
isUrlSupportedByModel: boolean;
}>,
): PromiseLike<
Array<{
data: Uint8Array;
mediaType: string | undefined;
} | null>
> => {
// ... download the files and return an array with similar order
},
messages: [
{
role: 'user',
content: [
{
type: 'file',
data: new URL('https://api.company.com/private/document.pdf'),
mediaType: 'application/pdf',
},
],
},
],
});4.7 Assistant Messages
Assistant 消息的 role 为 assistant,通常是助手的历史回复,可包含文本、推理(reasoning)和工具调用部件。
纯文本回复:
const result = await generateText({
model,
messages: [
{ role: 'user', content: 'How many calories are in this block of cheese?' },
{
role: 'assistant',
content: [
{
type: 'tool-call',
toolCallId: '12345',
toolName: 'get-nutrition-data',
input: { cheese: 'Roquefort' },
},
],
},
],
});4.8 Tool Messages 与多模态工具结果
对于支持工具调用的模型,assistant 消息可含 tool-call 部件,tool 消息则承载工具输出。一条 assistant 消息可以并行调用多个工具,一条 tool 消息也可以包含多个结果:
import fs from 'node:fs';
const result = await generateText({
model,
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: 'How many calories are in this block of cheese?',
},
{
type: 'file',
mediaType: 'image',
data: fs.readFileSync('./data/roquefort.jpg'),
},
],
},
{
role: 'assistant',
content: [
{
type: 'tool-call',
toolCallId: '12345',
toolName: 'get-nutrition-data',
input: { cheese: 'Roquefort' },
},
// there could be more tool calls here (parallel calling)
],
},
{
role: 'tool',
content: [
{
type: 'tool-result',
toolCallId: '12345', // needs to match the tool call id
toolName: 'get-nutrition-data',
output: {
type: 'json',
value: {
name: 'Cheese, roquefort',
calories: 369,
fat: 31,
protein: 22,
},
},
},
// there could be more tool results here (parallel calling)
],
},
],
});工具结果本身也可以是多部件多模态的(如文本 + 图像),用 output: { type: 'content', value: [...] } 表达:
{
type: 'tool-result',
toolCallId: '12345', // needs to match the tool call id
toolName: 'get-nutrition-data',
// for models that support multi-part tool results:
output: {
type: 'content',
value: [
{
type: 'text',
text: 'Here is the nutrition data for the cheese:',
},
{
type: 'file-data',
data: fs
.readFileSync('./data/roquefort-nutrition-data.png')
.toString('base64'),
mediaType: 'image/png',
},
],
},
}对于不支持多部件结果的模型,仍可用普通 JSON 输出部件兜底。
4.9 System Messages
System 消息在用户消息之前发给模型,引导助手行为。也可以改用 instructions 属性(见 4.3 节):
const result = await generateText({
model,
messages: [
{ role: 'system', content: 'You help planning travel itineraries.' },
{
role: 'user',
content:
'I am planning a trip to Berlin for 3 days. Please suggest the best tourist activities for me to do.',
},
],
});本章小结
- 三种提示形态:
prompt(文本)、instructions(系统指令,推荐替代 system 消息)、messages(消息数组); - 默认拒绝 messages 中的 system 角色;
allowSystemInMessages: true有注入风险需谨慎; ModelMessage的 content 可由 text/image/file/tool-call/tool-result 等 parts 组合,一条消息可并行多个工具调用;providerOptions支持函数级、消息级、消息部件级三个粒度的 provider 特有配置;- UIMessage 不支持 provider options,需先经
convertToModelMessages转换。
🛠️ 动手实践
- 用同一个旅行规划需求分别以
prompt+instructions和 system message 两种方式实现,对比输出风格差异。 - 构造一条包含「文本 + 图片 URL」的用户消息发给视觉模型,再尝试把图片换成 base64 Buffer 形式,确认两种写法结果一致。
- 手工拼装一组完整的 user → assistant(tool-call) → tool(tool-result) 三条消息模拟工具历史,观察模型如何基于历史继续对话。