LLM integration with Vercel AI SDK

LLM integration with Vercel AI SDK

使用 Vercel AI SDK 集成大语言模型 (LLM)

Large language models (LLMs) understand and generate text from prompts. The Vercel AI SDK is a provider-agnostic layer over LLM APIs - core functions are generateText, streamText, and embed. This post uses the OpenAI provider and mirrors the patterns from the OpenAI Responses API post. For the lower-level openai npm package, see the Chat Completions API and Responses API posts. 大语言模型 (LLM) 可以理解并根据提示词 (prompts) 生成文本。Vercel AI SDK 是一个独立于特定服务商的 LLM API 封装层,其核心功能包括 generateTextstreamTextembed。本文将使用 OpenAI 提供程序,并沿用 OpenAI Responses API 文章中的模式。若需了解底层的 openai npm 包,请参阅 Chat Completions API 和 Responses API 相关文章。

Prerequisites

前置要求

  • OpenAI account

  • Generated API key

  • Enabled billing

  • Node.js version 26

  • ai, @ai-sdk/openai, and zod installed (npm i ai @ai-sdk/openai zod)

  • For Markdown output: marked, dompurify, and jsdom (npm i marked dompurify jsdom)

  • OpenAI 账户

  • 已生成的 API Key

  • 已开启计费

  • Node.js 版本 26

  • 已安装 ai@ai-sdk/openaizod (npm i ai @ai-sdk/openai zod)

  • 若需 Markdown 输出,需安装 markeddompurifyjsdom (npm i marked dompurify jsdom)

Client setup

客户端设置

Create an OpenAI provider with your API key (read from the environment in production). 使用你的 API Key 创建一个 OpenAI 提供程序(在生产环境中应从环境变量中读取)。

import { createOpenAI } from '@ai-sdk/openai';

const openai = createOpenAI({
  apiKey: process.env.OPENAI_API_KEY
});

The same provider can target other hosts that implement a compatible API by setting baseURL and apiKey: 通过设置 baseURLapiKey,同一个提供程序也可以指向其他实现了兼容 API 的主机:

const openai = createOpenAI({
  apiKey: process.env.LLM_API_KEY,
  baseURL: 'https://your-gateway.example/v1',
});

Many third-party gateways support Chat Completions only. The examples below use openai(model) (Responses API path). If your provider does not support it, switch to openai.chat(model) and skip the web search example. 许多第三方网关仅支持 Chat Completions。以下示例使用 openai(model)(Responses API 路径)。如果你的提供程序不支持该路径,请切换为 openai.chat(model) 并跳过网页搜索示例。

Basic integration

基础集成

Pass a string as prompt and read text from the result. 传入一个字符串作为提示词,并从结果中读取文本。

import { generateText } from 'ai';
import { createOpenAI } from '@ai-sdk/openai';

const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });

const { text } = await generateText({
  model: openai('gpt-5.5'),
  prompt: 'Write a one-sentence bedtime story about a unicorn.',
});

console.log(text);

System prompt

系统提示词 (System prompt)

Use the system parameter for stable behavior (tone, format, role). It takes precedence over casual wording in the user message. 使用 system 参数以获得稳定的行为表现(如语气、格式、角色)。它的优先级高于用户消息中的随意表述。

const { text } = await generateText({
  model: openai('gpt-5.5'),
  system: 'Reply in one short sentence. Use plain language.',
  prompt: 'Explain what an LLM is.',
});

console.log(text);

Few-shot prompting

少样本提示 (Few-shot prompting)

Pass prior turns in a messages array with user and assistant roles, then the new user message. Keep task rules in system. 在 messages 数组中传入包含 userassistant 角色的历史对话,然后传入新的用户消息。任务规则应保留在 system 中。

const { text } = await generateText({
  model: openai('gpt-5.5'),
  system: 'Classify sentiment as exactly one word: positive, negative, or neutral.',
  messages: [
    { role: 'user', content: 'I love this!' },
    { role: 'assistant', content: 'positive' },
    { role: 'user', content: 'This is awful.' },
    { role: 'assistant', content: 'negative' },
    { role: 'user', content: 'It is fine I guess.' },
  ],
});

console.log(text);

Streaming

流式传输

Use streamText and iterate over textStream for incremental text. 使用 streamText 并遍历 textStream 以获取增量文本。

import { streamText } from 'ai';

const result = streamText({
  model: openai('gpt-5.5'),
  prompt: 'List three colors.',
});

for await (const part of result.textStream) {
  process.stdout.write(part);
}

Structured output with JSON schema

使用 JSON Schema 进行结构化输出

Constrain the model to JSON matching your schema via Output.object() and a Zod schema. The SDK validates the result. 通过 Output.object() 和 Zod schema 将模型输出限制为符合你定义的 JSON 格式。SDK 会自动验证结果。

import { generateText, Output } from 'ai';
import { z } from 'zod';

const { output } = await generateText({
  model: openai('gpt-5.5'),
  prompt: 'The film Inception was directed by Christopher Nolan.',
  output: Output.object({
    schema: z.object({
      title: z.string(),
      director: z.string(),
    }),
    schemaName: 'movie_summary',
  }),
});

console.log(output.title, output.director);

Markdown output to HTML

Markdown 转 HTML 输出

Ask for Markdown in system, then convert text to HTML and sanitize before rendering (for example with innerHTML in the browser or when storing HTML). 在 system 中要求使用 Markdown,然后将文本转换为 HTML,并在渲染前进行清理(例如在浏览器中使用 innerHTML 或存储 HTML 时)。

import { marked } from 'marked';
import { JSDOM } from 'jsdom';
import DOMPurify from 'dompurify';

const purify = DOMPurify(new JSDOM('').window);

const { text } = await generateText({
  model: openai('gpt-5.5'),
  system: 'Reply in Markdown only. Use a heading and a short bullet list.',
  prompt: 'Explain what an LLM is in three bullet points.',
});

const markdown = text;
const html = marked.parse(markdown);
const safeHtml = purify.sanitize(html);

Always run DOMPurify.sanitize on model-generated HTML. The model can emit unsafe markup. Sanitization strips scripts and other dangerous content. 务必对模型生成的 HTML 运行 DOMPurify.sanitize。模型可能会输出不安全的标记。清理过程会移除脚本和其他危险内容。

Web search tool

网页搜索工具

Enable the built-in web search tool when the answer should use current information from the web. 当答案需要使用来自网络的最新信息时,启用内置的网页搜索工具。

const result = await generateText({
  model: openai('gpt-5.5'),
  tools: { web_search: openai.tools.webSearch() },
  prompt: 'What was a major tech headline this week? Cite sources briefly.',
});

console.log(result.text);

Web search adds latency and tool usage cost. Use a model that supports tools. 网页搜索会增加延迟和工具使用成本。请使用支持工具的模型。

Embeddings

嵌入 (Embeddings)

Embeddings are numeric vectors that represent the semantic meaning of text. Use them for semantic search, clustering, and RAG. Pass a single string to embed and read the vector from embedding. 嵌入是表示文本语义的数字向量。可将其用于语义搜索、聚类和 RAG(检索增强生成)。将单个字符串传给 embed,并从 embedding 中读取向量。

import { embed } from 'ai';

const { embedding } = await embed({
  model: openai.embedding('text-embedding-3-small'),
  value: 'How do I connect pgvector to PostgreSQL?',
});

console.log(embedding.length);

Pass multiple strings in a values array with embedMany. Results are in the same order as the input. 使用 embedManyvalues 数组中传入多个字符串。结果的顺序与输入顺序一致。

import { embedMany } from 'ai';

const chunks = [
  'pgvector adds vector similarity search to PostgreSQL.',
  'LangChain helps split long documents into retrieval-friendly chunks.',
  'RAG retrieves context first, then asks an LLM to answer.',
];

const { embeddings } = await embedMany({
  model: openai.embedding('text-embedding-3-small'),
  values: chunks,
});

console.log(embeddings.length); // 3

For a full RAG flow with pgvector, see the RAG with OpenAI embeddings post. 有关使用 pgvector 的完整 RAG 流程,请参阅“使用 OpenAI 嵌入进行 RAG”的文章。

Demo

演示

Runnable scripts for each section live in the vercel-ai-sdk-demo folder. 各章节的可运行脚本位于 vercel-ai-sdk-demo 文件夹中。