Todos los recursos

Una sola superficie tipada sobre un montón de proveedores de modelos (streaming, tool calls, salida estructurada y hooks de React) para que una app de Next.js lance funciones de LLM en días, no en semanas. Aquí va cuándo es la opción correcta, cuándo conviene caer al SDK nativo y las grietas que vale la pena conocer antes de ponerte a construir.

Vercel AI SDK: el toolkit LLM para TypeScript que no te ata a ningún proveedor

En resumen

  • Un SDK de TypeScript (el paquete «ai») que te da generateText, streamText, generateObject y streamUI detrás de una misma interfaz para Anthropic, OpenAI, Google y muchísimos más.
  • Te quita de encima el boilerplate que se come tu primera semana: parsear SSE, el bucle de tool calls y esa salida con pinta de JSON que, sin él, te tocaría parsear a mano y cruzar los dedos.
  • generateObject más un schema de Zod te devuelve datos tipados de punta a punta. Nada de JSON.parse, nada de código para reparar la respuesta.
  • La abstracción tiene sus grietas con lo propio de cada proveedor. Prompt caching, extended thinking y ciertos detalles de las tools requieren opciones del proveedor o directamente el SDK nativo.
  • Es el mejor default por cobertura y velocidad en un stack Next.js/React. Pásate al SDK oficial de Anthropic cuando necesites ese último 10% de control.

La mayoría de los equipos que arman su primera función de LLM en una app de TypeScript se pasan la primera semana reinventando una infraestructura que nadie debería tener que escribir: parsear Server-Sent Events a mano, montar el bucle de tool calls, exprimir el texto del modelo para sacarle JSON y luego escribir código que repare la respuesta cuando no viene como debe. El Vercel AI SDK, el paquete «ai» en npm, resume todo eso en una sola superficie tipada que sirve para Anthropic, OpenAI, Google y decenas de proveedores más. Es el camino de menor fricción para meter funciones de LLM en un stack Next.js, y es por donde arranco cuando quiero cubrir mucho terreno rápido. Lo que sigue es la versión honesta: dónde brilla, dónde se le ven las costuras a la abstracción y cómo combinarlo con el SDK nativo cuando esas costuras importan.

01 · Qué es en realidad

El AI SDK son dos cosas bajo un mismo nombre. El core («ai») es un toolkit del lado del servidor, independiente del framework, con un puñado de funciones («generateText», «streamText», «generateObject», «streamObject» y un runtime de tool calls) que reciben un handle de modelo y devuelven resultados tipados. La capa de UI («@ai-sdk/react» y compañía) trae hooks como «useChat» y «useCompletion» que enganchan un endpoint con streaming a tus componentes casi sin código de pegamento.

La pieza que lo independiza del proveedor es el paquete de proveedor. Instalas «@ai-sdk/anthropic», «@ai-sdk/openai» o «@ai-sdk/google», y cada uno exporta una factory que produce un «LanguageModel» que las funciones del core saben entender. Cambiar de proveedor es modificar una sola línea ahí donde haces la llamada. El resto de tu código no se toca.

import { generateText } from "ai"
import { anthropic } from "@ai-sdk/anthropic"

const { text } = await generateText({
  model: anthropic("claude-opus-4-8"),
  prompt: "Resume este changelog en tres bullets.",
})

Nota

El string del modelo es lo único atado al proveedor en ese snippet. Apúntalo a «openai("gpt-...")» y todo el código de alrededor queda igual. Esa portabilidad es el argumento de venta entero, y también de dónde salen los tradeoffs de la sección 06.

02 · Por qué se gana un lugar en el stack

Apenas lo adoptas se te van dos dolores de cabeza, y son justo los dos que más tiempo te roban en un primer build.

El primero es el streaming. Hacerlo a mano implica parsear un byte stream de SSE en el servidor, re-trocearlo y renderizar los tokens según van llegando al cliente sin que se te pierda ni se te duplique ninguno. «streamText» devuelve un stream que puedes pasar directo a la respuesta de un Route Handler de Next.js, y «useChat» lo consume en el cliente con el estado de carga y de error ya resueltos.

// app/api/chat/route.ts
import { streamText, convertToModelMessages } from "ai"
import { anthropic } from "@ai-sdk/anthropic"

export async function POST(req: Request) {
  const { messages } = await req.json()
  const result = streamText({
    model: anthropic("claude-opus-4-8"),
    messages: convertToModelMessages(messages),
  })
  return result.toUIMessageStreamResponse()
}

El segundo es la salida estructurada. Lo difícil de sacarle datos a un modelo nunca fue conseguir JSON. Es conseguir JSON correcto, siempre, respetando las restricciones de cada campo. «generateObject» recibe un schema de Zod, valida la salida del modelo contra ese schema y te entrega un objeto tipado. Sin «JSON.parse», sin try/catch envolviendo un string, sin tener que blindarte por si "el modelo lo metió dentro de un fence de markdown".

  • Describes la forma una sola vez, en Zod.
  • El SDK la traduce al mecanismo de salida estructurada del proveedor.
  • A cambio recibes un valor tipado en tiempo de compilación y validado en runtime.

03 · Arranque rápido: instalar y primeras llamadas

Para empezar, instala el core y un solo proveedor, nada más. Pon la key del proveedor como variable de entorno. El paquete la lee solo, así que no le pasas la key desde el código.

npm install ai @ai-sdk/anthropic zod
# .env.local
# ANTHROPIC_API_KEY=sk-ant-...

Este es el camino de la salida estructurada, que es el que más uso. Un clasificador que te devuelve un veredicto tipado en lugar de un párrafo que después tocaría parsear:

import { generateObject } from "ai"
import { anthropic } from "@ai-sdk/anthropic"
import { z } from "zod"

const { object } = await generateObject({
  model: anthropic("claude-opus-4-8"),
  schema: z.object({
    risk: z.enum(["low", "medium", "high"]),
    reason: z.string(),
  }),
  prompt: `Evalúa el riesgo de seguridad de este cambio de dependencia:\n${diff}`,
})

// object.risk es "low" | "medium" | "high", tipado y validado.
if (object.risk === "high") flagForReview(object.reason)

Consejo

Empieza por «generateObject» antes que por «streamText», hasta para una función de chat. Un objeto validado es mucho más fácil de testear y de razonar que un stream de tokens, y el streaming se lo montas encima una vez que el comportamiento base esté bien. Construye primero lo aburrido y testeable.

04 · Tool calls sin escribir el bucle

Cuando un modelo necesita hacer algo, como buscar un registro, llamar a una API o correr un cálculo, le das tools y dejas que las llame. Montar esto a mano es un bucle: llamas al modelo, miras si pidió usar una tool, ejecutas la tool, le devuelves el resultado y repites hasta que el modelo deja de pedir. El AI SDK corre ese bucle por ti. Defines las tools con un schema de Zod y una función «execute», pones «stopWhen» para acotar los pasos y llamas a «generateText».

import { generateText, tool, stepCountIs } from "ai"
import { anthropic } from "@ai-sdk/anthropic"
import { z } from "zod"

const { text } = await generateText({
  model: anthropic("claude-opus-4-8"),
  stopWhen: stepCountIs(5),
  tools: {
    getInvoice: tool({
      description: "Busca una factura por id.",
      inputSchema: z.object({ id: z.string() }),
      execute: async ({ id }) => db.invoice(id),
    }),
  },
  prompt: "¿Cuál es el total de la factura INV-204?",
})

Un par de cosas que conviene tener claras:

  1. La función «execute» es tu código, así que la frontera de seguridad corre por tu cuenta. Valida las entradas, acota las credenciales y trata cada tool como una superficie de ataque, porque el prompt injection va a tantear tus tools, no solo tu chat.
  2. «stopWhen» no es opcional, aunque el tipo lo permita. Sin un tope de pasos, un modelo que se confunde puede quedarse en bucle y quemar tokens. Ponlo.
  3. Las tools y la salida estructurada se llevan bien. Puedes correr un paso de tool calls y forzar la respuesta final a un schema en la misma llamada.

Atención

Toda tool que el modelo puede llamar es una tool que un atacante va a intentar alcanzar a través de él. Nunca le entregues a una tool un token de admin que lo puede todo, valida cada entrada dentro de «execute» del lado del servidor, y deja las acciones destructivas o difíciles de revertir detrás de una confirmación explícita en lugar de permitir que el bucle las dispare por su cuenta.

05 · Cuándo usarlo frente a las alternativas

La decisión casi nunca es "AI SDK o nada". Es "AI SDK o el SDK nativo del proveedor", y el eje es cobertura contra profundidad.

Usa el AI SDK cuando

  • Estás en una app Next.js / React y quieres chat o completions con streaming enganchados a la UI con el mínimo de código de pegamento.
  • Quieres portabilidad entre proveedores: hacer un A/B entre dos modelos, tener fallback de un proveedor a otro o dejar la puerta abierta para cambiar más adelante.
  • Tus necesidades son el 90% de siempre: generar texto, extracción estructurada, clasificación, enrutamiento y tool calls.

Quédate (o cae) en el SDK nativo de Anthropic cuando

  • Dependes de funciones propias del proveedor que la abstracción no expone con limpieza: prompt caching con breakpoints explícitos, thinking extendido/adaptativo, o control fino de los headers del request.
  • Estás construyendo un producto de un solo proveedor y la capa de portabilidad es pura indirección que nunca le vas a sacar provecho.
  • Necesitas un comportamiento que va por delante del ciclo de releases del SDK. Una capacidad nueva del proveedor suele aterrizar antes en el SDK nativo.

En un build muy centrado en Anthropic muchas veces uso los dos a la vez: el AI SDK para la parte ancha (la UI de chat, los endpoints comunes) y el «@anthropic-ai/sdk» oficial para las rutas donde los headers de caching o la config de thinking deciden el costo y la latencia. Conviven sin problema. No hay ninguna regla que diga que un codebase tiene que elegir uno solo.

06 · Los tradeoffs honestos

Toda abstracción sobre muchos proveedores paga la cobertura con algo de profundidad, y el AI SDK no es la excepción. Conocer las grietas de antemano te ahorra una tarde de frustración.

  • Lo propio de cada proveedor se escapa. El prompt caching, el thinking extendido y ciertas semánticas de las tools viven detrás de «providerOptions», una válvula de escape tipada que solo deja pasar lo que le mandes, y algunas ni siquiera aparecen hasta que un release las pone al día. Cuando una función es clave para el costo o la calidad, comprueba que funcione de punta a punta a través del SDK antes de montarlo todo encima.
  • Estás siguiendo un paquete que se mueve rápido. El paquete «ai» avanza a buen ritmo, y sus versiones mayores han rehecho las APIs de mensajes y de streaming más de una vez. Fija tu versión, lee las notas de migración antes de actualizar y no des por hecho que un snippet de un blog viejo todavía compila.
  • La abstracción de proveedor puede ocultarte el costo. Como cambiar de modelo es una sola línea, es fácil apuntar producción a un modelo más caro sin enterarte. El SDK no te va a gestionar presupuestos ni fallbacks entre proveedores. Eso es tarea de un gateway, no de una librería cliente.
  • El debug cruza una frontera. Cuando un request se porta raro, ahora tienes que razonar sobre tu código, la capa de traducción del AI SDK y la API del proveedor al mismo tiempo. Conecta el tracing pronto para poder ver el request real que el SDK terminó enviando.

Importante

La grieta es parte del diseño, no un bug. Es el precio de la portabilidad, y para la mayoría de las apps es un precio justo. El error es enterarte de ella en producción. Decide función por función si te conviene la cobertura del AI SDK o la profundidad del SDK nativo, y deja que mande el requisito, no la comodidad.

El Vercel AI SDK es la forma más rápida que conozco de poner una función de LLM real en producción dentro de una app de TypeScript, y para los casos comunes es genuinamente la herramienta correcta, no un mal menor. Trátalo como el default por cobertura y pásate al SDK nativo en el puñado de rutas donde una función del proveedor decide el resultado. Construye primero el camino testeable de la salida estructurada, define tus topes de pasos y tu frontera de seguridad con intención, y te quedas con casi todo el valor y muy poco del dolor.

Puntos clave

  • Adóptalo como el default para funciones de LLM en una app Next.js/React: te borra el boilerplate de parsear SSE, el bucle de tools y el exprimir JSON que te cuesta la primera semana.
  • Construye primero el camino de la salida estructurada («generateObject» + Zod): tipado, validado, testeable y fácil de envolver en streaming más adelante.
  • Pon «stopWhen» en las corridas con tool calls y hazte cargo de la frontera de seguridad de «execute»: valida las entradas, acota las credenciales y pon barreras a las acciones destructivas.
  • Cuenta con que a la abstracción se le verán las costuras en lo propio de cada proveedor; verifica caching/thinking de punta a punta antes de depender de ellos, o usa el SDK nativo en esas rutas.
  • Fija la versión de «ai» y lee las notas de migración antes de actualizar: el paquete itera rápido y las versiones mayores han rehecho la API.

Preguntas frecuentes

¿El Vercel AI SDK te amarra a Vercel o a Next.js?

No. El core («ai») es independiente del framework y corre donde corra Node o un runtime de edge: Express, Hono, un worker, un script suelto. Los hooks de React vienen muy bien dentro de Next.js, pero son opcionales, y también hay bindings para Svelte y Vue. No necesitas una cuenta de Vercel para usarlo.

¿En qué se diferencia de llamar al SDK de Anthropic directamente?

El SDK de Anthropic te da acceso nativo y completo a un proveedor: cada header, cada función en beta, tal como la API lo expone. El AI SDK te da una interfaz uniforme sobre muchos proveedores, más los helpers de streaming y del bucle de tools, a cambio de perder algo de profundidad en cada proveedor. Usa el AI SDK por cobertura y velocidad; usa el SDK nativo cuando una función como el prompt caching o el thinking adaptativo es decisiva.

¿Aún puedo usar prompt caching o thinking extendido a través de él?

Muchas veces sí, vía «providerOptions», una vía tipada que deja pasar los ajustes propios del proveedor. Pero el soporte siempre va un paso por detrás del proveedor, y no todos los detalles quedan expuestos con limpieza. Antes de apoyar costo o calidad en alguno de estos, pruébalo de punta a punta a través del SDK y confirma que de verdad surte efecto; si no, esa ruta es candidata para el SDK nativo.

¿Tengo que escribir yo mismo el bucle de las tool calls?

No, esa es una de las razones de peso para adoptarlo. Defines cada tool con un schema de Zod y una función «execute», pones «stopWhen» para acotar los pasos, y «generateText» corre el bucle de llamar, ejecutar la tool y devolver el resultado hasta que el modelo termina. Tu responsabilidad son las implementaciones de las tools y su frontera de seguridad, no la orquestación.

¿generateObject garantiza que la salida coincide con mi schema?

Valida la salida del modelo contra tu schema de Zod en runtime y te entrega un objeto tipado, así que para cuando lo lees, o cumple o la llamada lanza error. Eso te quita el paso de parsear y cruzar los dedos, pero no es magia: mantén los schemas precisos pero alcanzables. Una restricción imposible solo hace que el modelo reintente y al final falle, así que registra los fallos de validación para detectar schemas que ningún prompt va a poder satisfacer.

¿La API es estable o se rompe entre versiones?

Se mueve rápido. Las versiones mayores han rehecho las APIs de mensajes y de streaming más de una vez, así que un snippet de un post viejo puede que ya no compile. Fija tu versión, lee la guía de migración antes de actualizar, y reserva algo de tiempo para ajustar los sitios donde haces las llamadas cuando saltas de mayor. Ese vaivén es el costo de una librería joven y en desarrollo activo: llevadero si no actualizas a ciegas.

Abrir recurso (abre en pestaña nueva)

¿Prefieres que lo hagamos por ti?

Esto mismo lo construimos para negocios como el tuyo. La primera conversación es gratis y sin compromiso.

Escríbenos por WhatsApp

Escríbenos por WhatsApp

Escanéalo con tu teléfono para escribirnos por WhatsApp.

Escanéalo con tu teléfono para escribirnos por WhatsApp.

¿Estás desde el teléfono y no puedes escanear? Escríbenos a info@ilustrari.com

Primera conversación gratis. Te responde el fundador.

Recursos relacionados

Plugin / MCPClaude Code

Conecta tu propio servidor MCP a Claude Code

Los servidores MCP que vienen listos cubren lo de siempre: Postgres, GitHub, Slack. Pero apenas tu tarea se vuelve específica de tu sistema, dejas de buscar un plugin y te armas el tuyo. Aquí montamos un servidor MCP stdio pequeño en TypeScript: las tools que expone, cómo registrarlo en Claude Code, dónde va de verdad la autorización, y los fallos que te explotan en la primera llamada real.

11 may 202613 min de lectura
ToolTypeScript

Playwright: automatización de navegador confiable para scraping y agentes

Las páginas renderizadas con JavaScript rompen los fetch HTTP simples, y la solución de siempre, un navegador headless, va filtrando memoria sin avisar hasta que te tumba el host. Playwright es la base confiable que resuelve el primer problema; esto es cómo usarlo sin caer en el segundo. Sales sabiendo cuándo lanzar un navegador, cuándo no, y cómo manejarlo con un pool para que un scraper sobreviva en un solo VPS.

7 abr 202612 min de lectura
ToolPython

Instructor: salida estructurada validada de cualquier LLM

Lo difícil de la salida estructurada no es sacar JSON. Es sacar JSON correcto, siempre, bajo condiciones reales. Instructor hace que el modelo te devuelva un objeto Pydantic ya validado y se vuelve a preguntar solo cuando la validación falla, así el texto difuso se convierte en datos tipados en los que el código sí puede confiar. Acá va cuándo usarlo, cómo funciona el bucle de reintentos y las concesiones que nadie menciona hasta que se dispara la factura de tokens.

5 abr 202612 min de lectura