RAG con TypeScript, de cero a comparativa.
Curso autodidacta para construir, entender y comparar pipelines RAG en producción. Seis niveles, código real, mismo dataset en cuatro frameworks distintos. Sin atajos.
Aún no empezaste el curso.
Cuando arranques, vas a ver tu avance acá.
Seis niveles, una progresión.
De los conceptos básicos al benchmark de cuatro frameworks. Cada nivel agrega una capa nueva sobre la anterior; nada se da por sabido.
Conceptos
¿Qué es RAG, por qué existe y cuándo usarlo? Cinco capítulos sin código: anatomía del pipeline, vocabulario mínimo, local-first y por qué TypeScript.
- 01 · ¿Qué es RAG?
- 02 · Anatomía del pipeline
- 03 · Vocabulario mínimo
- 04 · ¿Por qué local-first?
Manos a la obra
Pipeline RAG end-to-end con Vercel AI SDK + Qdrant. Setup, corpus, ingestión, query, inspección de chunks y errores comunes en tu primer RAG.
- 01 · Setup del stack
- 02 · Corpus y chunking
- 03 · Lab: ingestión
- 04 · Lab: query
Calidad y evaluación
Cómo saber si tu RAG sirve. Eval harness propio, métricas (faithfulness, context recall), datasets sintéticos y golden sets. Sin métricas, no hay producción.
- 01 · ¿Por qué evaluar?
- 02 · Faithfulness
- 03 · Golden set
- 04 · Datasets sintéticos
Avanzado
Hybrid search, reranking, multi-query, query rewriting y patrones de citation. Lo que separa un RAG de demo de uno que aguanta usuarios reales.
- 01 · Hybrid search
- 02 · Reranking
- 03 · Multi-query
- 04 · Query rewriting
Operación
Observabilidad, costos, caching de embeddings, refresco del índice y deploys edge-ready. La parte que rara vez se enseña pero siempre se necesita.
- 01 · Tracing
- 02 · Costos y caching
- 03 · Refresco del índice
- 04 · Edge deploys
Comparativa de frameworks
Mismo dataset, cuatro frameworks: Vercel AI SDK, LangChain.js, LlamaIndex.TS y Mastra. Eval harness en acción, resultados y análisis para elegir el tuyo.
- 01 · ¿Por qué comparar?
- 02 · 4 frameworks lado a lado
- 03 · Mismo input, 4 salidas
- 04 · Resultados del harness
Código real, no pseudocódigo.
Cada lección viene con snippets ejecutables, tipos estrictos y diffs paso a paso. El mismo retriever en cuatro sabores.
1// retriever.ts — Vercel AI SDK + Qdrant
2import { embed } from "ai";
3import { openai } from "@ai-sdk/openai";
4import { QdrantClient } from "@qdrant/js-client-rest";
5
6const qdrant = new QdrantClient({ url: "http://localhost:6333" });
7export async function retrieve(query: string, k = 4) {
8 const { embedding } = await embed({
9 model: openai.embedding("text-embedding-3-small"),
10 value: query,
11 });
12
13 const hits = await qdrant.search("corpus", {
14 vector: embedding, limit: k, with_payload: true,
15 });
16
17 return hits.map((h) => ({
18 text: h.payload?.text as string,
19 score: h.score,
20 }));
21}1// retriever.ts — LangChain.js + Qdrant
2import { OpenAIEmbeddings } from "@langchain/openai";
3import { QdrantVectorStore } from "@langchain/qdrant";
4
5const store = await QdrantVectorStore.fromExistingCollection(
6 new OpenAIEmbeddings({ model: "text-embedding-3-small" }),
7 { url: "http://localhost:6333", collectionName: "corpus" },
8);
9
10export const retriever = store.asRetriever({ k: 4 });
11
12export async function retrieve(query: string) {
13 const docs = await retriever.invoke(query);
14 return docs.map((d) => ({ text: d.pageContent, score: d.metadata.score }));
15}1// retriever.ts — LlamaIndex.TS + Qdrant
2import { VectorStoreIndex, Settings } from "llamaindex";
3import { QdrantVectorStore } from "@llamaindex/qdrant";
4import { OpenAIEmbedding } from "@llamaindex/openai";
5
6Settings.embedModel = new OpenAIEmbedding({ model: "text-embedding-3-small" });
7
8const vs = new QdrantVectorStore({ url: "http://localhost:6333", collectionName: "corpus" });
9const index = await VectorStoreIndex.fromVectorStore(vs);
10const retriever = index.asRetriever({ similarityTopK: 4 });
11
12export async function retrieve(query: string) {
13 const nodes = await retriever.retrieve(query);
14 return nodes.map((n) => ({ text: n.node.getContent(), score: n.score }));
15}1// retriever.ts — Mastra + Qdrant
2import { Mastra } from "@mastra/core";
3import { QdrantVector } from "@mastra/qdrant";
4import { openai } from "@ai-sdk/openai";
5
6const mastra = new Mastra({
7 vectors: { qdrant: new QdrantVector({ url: "http://localhost:6333" }) },
8});
9
10export async function retrieve(query: string, k = 4) {
11 const { embedding } = await mastra.embed({ model: openai.embedding("text-embedding-3-small"), value: query });
12 return await mastra.vectors.qdrant.query({ indexName: "corpus", queryVector: embedding, topK: k });
13}Comparativa de frameworks.
Mismo dataset, mismas preguntas, misma evaluación. Resultados publicados en el Nivel 5 con harness completo y dataset reproducible.
| Framework | DX | Tipos | Velocidad | Ecosistema | LOC mínimo |
|---|---|---|---|---|---|
| Vercel AI SDK @ai-sdk/openai · 4.0 | 21 LOC | ||||
| LangChain.js @langchain/core · 0.3 | 15 LOC | ||||
| LlamaIndex.TS llamaindex · 0.10 | 15 LOC | ||||
| Mastra @mastra/core · 0.6 | 13 LOC |
// los puntajes son cualitativos · ver nivel 5 para la metodología completa