Busca en todas las páginas de la documentación
npm install ai @ai-sdk/openai @ai-sdk/anthropic// app/api/chat/route.ts
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai("gpt-4o"),
messages,
});
return result.toDataStreamResponse();
}// app/chat/page.tsx
"use client";
import { useChat } from "@ai-sdk/react";
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
Cuándo usarlo: Necesitas integrar chat LLM, completions, o llamadas a herramientas en una aplicación React o Next.js con soporte de streaming y boilerplate mínimo.
// app/components/ChatWithTools.tsx
"use client";
import { useChat } from "@ai-sdk/react";
export default function ChatWithTools() {
const { messages, input, handleInputChange, handleSubmit, isLoading } =
useChat({
api:
// app/api/chat-tools/route.ts
import { streamText, tool } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";
export async function POST(req: Request) {
const { messages }
Lo que esto demuestra:
useChatmaxStepsstreamText devuelve un objeto StreamTextResult que se convierte en una Response a través de toDataStreamResponse(), enviando Server-Sent Events al clienteuseChat gestiona el estado completo de la conversación: historial de mensajes, estado de entrada, carga, error y controlador de abortomaxSteps iteracionesgenerateText es la contraparte sin streaming para procesamiento por lotes o generación del lado del servidorUsando OpenRouter para acceso a modelos:
npm install @openrouter/ai-sdk-providerimport { createOpenRouter } from "@openrouter/ai-sdk-provider";
const openrouter = createOpenRouter({
apiKey: process.env.OPENROUTER_API_KEY,
});
const result = streamText({
model: openrouter("anthropic/claude-sonnet-4-20250514"),
messages,
});Generación sin streaming:
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
const { text, usage } = await generateText({
model: openai("gpt-4o"),
prompt: "Resume este artículo en 3 puntos.",
});Salida estructurada con generateObject:
import { generateObject } from "ai";
import { z } from "zod";
const { object } = await generateObject({
model: openai("gpt-4o"),
schema: z.object({
recipe: z.string(),
useCompletion para prompts de un solo turno:
"use client";
import { useCompletion } from "@ai-sdk/react";
export default function Completion() {
const { completion, input, handleInputChange, handleSubmit } = useCompletion({
api: "/api/completion",
});
Message de ai incluye id, role, content y el opcional toolInvocationsexecuteuseChat devuelve messages: Message[] fuertemente tipadoproviderOptionsimport type { Message } from "ai";
// Los tipos de resultado de herramientas se infieren del esquema Zod
const weatherTool = tool({
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => {
// city está tipado como string
return { temp:
Claves API faltantes — El SDK lanza un error en tiempo de ejecución si la variable de entorno de clave API del proveedor no está configurada. Solución: Establece OPENAI_API_KEY, ANTHROPIC_API_KEY, etc. en .env.local. Cada proveedor tiene su propio nombre de variable de entorno esperado.
useChat no se actualiza — Si los mensajes no se transmiten, la ruta de API puede no devolver una respuesta de datos en stream. Solución: Siempre devuelve result.toDataStreamResponse(), no result.text o una respuesta JSON simple.
Llamadas a herramientas no se ejecutan — Herramientas definidas pero maxSteps no configurado tiene valor predeterminado de 1, por lo que el uso de herramientas multi-paso no funcionará. Solución: Establece maxSteps: 5 (o superior) para permitir que el modelo procese resultados de herramientas y continúe.
Errores CORS en desarrollo — Las rutas de API deben estar en la misma aplicación Next.js. Solución: Usa rutas de API de Next.js (app/api/) en lugar de llamar a un servidor externo directamente desde useChat.
Bundle grande de importaciones de proveedor — Importar múltiples proveedores aumenta el tamaño del bundle del cliente. Solución: Las importaciones de proveedores son solo del servidor; mantenlas en rutas de API o Server Actions, nunca en archivos "use client".
| Librería | Mejor Para | Ventaja/Desventaja |
|---|---|---|
| Vercel AI SDK | Aplicaciones React/Next.js IA full-stack | Opinada, vinculada a convenciones de ecosistema Vercel |
| LangChain.js | Cadenas complejas, RAG, agentes | Abstracción más pesada, curva de aprendizaje más pronunciada |
| OpenAI SDK directamente | Uso simple solo OpenAI | Sin hooks React en streaming, proveedor único |
| Anthropic SDK directamente | Uso simple solo Claude | Sin hooks React en streaming, proveedor único |
| LlamaIndex.ts | Indexación y recuperación de datos | Enfocado en RAG, menos en interfaz de chat |
streamText y cómo llega al cliente?streamText devuelve un objeto StreamTextResult.toDataStreamResponse() para convertirlo en una Response con Server-Sent EventsuseChat en el cliente consume este stream y actualiza los mensajes en tiempo realresult.text o JSON simple -- el hook espera el protocolo de stream de datosimport { openai } from "@ai-sdk/openai";
import { anthropic } from "@ai-sdk/anthropic";
// Solo cambia la línea del modelo:
const result = streamText({
model: anthropic("claude-sonnet-4-20250514"),
messages,
});La interfaz unificada significa que solo el parámetro model cambia.
maxSteps y por qué mis llamadas de herramientas no se ejecutan sin él?maxSteps controla cuántos turnos de llamada-a-herramienta-y-resultado puede realizar el modelomaxSteps: 5 o superior para uso de herramientas multi-pasoimport { tool } from "ai";
import { z } from "zod";
const weatherTool = tool({
description: "Obtener clima para una ciudad",
parameters: z.object({
city: z.string().describe("Nombre de la ciudad"),
useChat?result.toDataStreamResponse(), no una respuesta JSONapi en useChat apunte a la ruta correctastreamText y generateText?streamText envía tokens al cliente conforme se generan (streaming)generateText espera la respuesta completa y la devuelve de una sola vezstreamText para interfaces de chat donde quieras mostrar tokens en tiempo realgenerateText para procesamiento por lotes o generación del lado del servidor donde el streaming no es necesarioimport { generateObject } from "ai";
import { z } from "zod";
const { object } = await generateObject({
model: openai("gpt-4o"),
schema: z.object({
title: z.string
useCompletion para prompts de un solo turno en lugar de chat multi-turno?useCompletion gestiona un único ciclo de prompt/respuesta, no una conversacióncompletion (el texto de respuesta), input y manejadores de formularioapi a una ruta que usa streamText con un prompt en lugar de messages@ai-sdk/openai, @ai-sdk/anthropic) son solo del servidor"use client" los incluye en el JavaScript del clienteuseChat y useCompletion son los únicos imports del AI SDK seguros para componentes del clienteuseChat?useChat devuelve messages: Message[] donde Message incluye id, role, content y el opcional toolInvocationsMessage de "ai" si necesitas tipificar props que acepten mensajesimport type { Message } from "ai";import { createOpenRouter } from "@openrouter/ai-sdk-provider";
const openrouter = createOpenRouter({
apiKey: process.env.OPENROUTER_API_KEY,
});
const result = streamText({
model: openrouter("anthropic/claude-sonnet-4-20250514"),
messages,
});Los tipos de parámetros de herramientas se infieren automáticamente del esquema Zod.