Ir al contenido

Vercel AI SDK — el minimalista

Vercel AI SDK no es “un framework de RAG”. Es una capa provider-agnostic sobre LLMs y embedders, con utilidades chiquitas (embed, embedMany, generateText, streamText). Para hacer RAG, vos componés: vos llamás embed(), vos llamás qdrant.query(...), vos armás el prompt, vos llamás generateText().

Cero abstracción de alto nivel. El framework ni siquiera sabe que estás haciendo RAG. Te da las cuatro piezas y vos las cosés.

Tradeoff: más LOC, más control. Si necesitás meter mano en cualquier paso (un retriever propio, una métrica custom, un wrapper de logging), no hay capa que romper — el código ya es vos.

packages/01-vercel-ai-sdk/src/ingest.ts — 76 líneas. Mostramos los 3 stages clave:

ingest.ts: stages 1-3
const docs = await loadMarkdownDir(DATA_DIR);
const chunks = chunkDocs(docs);
await recreateCollection();
const embeddingModel = ollama.embeddingModel(OLLAMA_EMBED);
const { embeddings } = await embedMany({
model: embeddingModel,
values: chunks.map((c) => c.content),
});

embedMany es la primitiva del SDK: le pasás un array de strings, te devuelve un array paralelo de vectores. Internamente puede paralelizar/batchear; vos no te enterás. Sin estado, sin clases, sin builder pattern.

packages/01-vercel-ai-sdk/src/query.ts — 96 líneas. El stage de retrieve + generate:

query.ts: retrieve + generate
const { embedding } = await embed({
model: ollama.embeddingModel(OLLAMA_EMBED),
value: question,
});
const results = await qdrant.query(COLLECTION, {
query: embedding,
limit: TOP_K,
with_payload: true,
});
const prompt = `You are a helpful assistant. Answer the question using ONLY the context below.
If the context does not contain enough information, say so.
Context:
${contextBlocks.join('\n\n---\n\n')}
Question: ${question}`;
const { text } = await generateText({
model: ollama(OLLAMA_LLM),
prompt,
});

Mirá lo que NO hay:

  • No hay retriever.search(...). Vos llamás directo a Qdrant.
  • No hay chain.invoke(...). Vos armás el prompt y llamás generateText.
  • No hay magic state global. Settings.llm = ... no existe.

Cada paso es explícito. Si querés cambiar el prompt, cambiás un string. Si querés cambiar el retriever, cambiás un await qdrant.query(...) por otra cosa.

A — el más estricto de los 4. Funciones del SDK son full generic:

tipos del SDK
const { embedding } = await embed({ model, value });
// ^^^^^^^^^ inferido como number[]
const { embeddings } = await embedMany({ model, values });
// ^^^^^^^^^^^ inferido como number[][]
const { text } = await generateText({ model, prompt });
// ^^^^ inferido como string

Sin any, sin as unknown as .... Funciona limpio con tsconfig.strict = true y noUncheckedIndexedAccess. El único cast que hace falta en el query.ts del repo es para validar el payload de Qdrant (que viene tipado unknown por diseño), y para eso hay un type guard isChunkPayload explícito.

  • Equipos TS-strict que valoran tipos limpios y errores en compile-time.
  • Implementar técnicas avanzadas (Nivel 3): hybrid retrievers, rerankers, multi-query, citations. Cuando vos sos el que escribe el retriever, no hay framework que pelear.
  • Edge runtime (Cloudflare Workers, Vercel Edge): el SDK se reduce a fetch() calls. El query.ts lo movés a edge cambiando 4 líneas (Nivel 4 / cap 04).
  • Provider-agnóstico: cambiar de Ollama a OpenAI a Anthropic es cambiar 1 import. La API del SDK es la misma.
  • Si querés “todo incluido”: integraciones con vector stores raros, document loaders para 30 formatos, retrievers con 15 estrategias preparadas — Vercel no te da nada de eso. Tenés que escribir o instalar piezas separadas.
  • Para experimentar con agentes y tools: Vercel tiene tool calling pero no abstracciones de high-level agents. Si querés un agent con memory, planning, retries — Mastra te ahorra trabajo.
  • Si tu equipo viene de LangChain Python: la mental model es distinta. No hay Chain, no hay Runnable. Es un cambio de paradigma.

LOC mínimo del query end-to-end (sin imports ni comments): 21 líneas. Latencia base: ~1842 ms sobre el corpus del curso. Las dos métricas son las más altas del nivel — Vercel paga el costo de “vos componés cada paso” pero no paga ningún costo de overhead de framework.

LangChain.js — el opuesto de Vercel. Mismo problema, otra filosofía: “abstracciones reutilizables sobre LLMs” + ecosistema gigante. Más compacto en LOC, más conceptos para aprender.