Contextual retrieval: cómo arreglar tu RAG en TypeScript
Contextual retrieval: qué es, por qué tu RAG falla al trocear documentos y cómo implementarlo hoy en TypeScript con Claude y prompt caching, con costes reales.

Un usuario le pregunta a tu asistente de documentación: "¿Cuántas peticiones por minuto admite el plan Pro?". El sistema busca, encuentra un fragmento y responde con seguridad: 100.
El fragmento existe: "El límite es de 100 peticiones por minuto". Pero es del plan Free. El del plan Pro empieza con "En este caso, el límite sube a 1.000" y no nombra el plan.
Tu RAG no ha alucinado. Hizo lo que le pediste: trocear, vectorizar y devolver el fragmento más parecido, que al trocear perdió el título que le daba sentido. Ese hueco lo tapa contextual retrieval, la técnica que Anthropic publicó en septiembre de 2024 y que sigue siendo una de las mejoras más baratas que le puedes hacer a un RAG.
En corto: contextual retrieval consiste en pedirle a un LLM que escriba, para cada chunk, una o dos frases que lo sitúen dentro del documento, y en indexar ese contexto junto al chunk en embeddings y en BM25. En las pruebas de Anthropic, los fallos de recuperación bajaron un 49 % al combinar las dos cosas y un 67 % al añadir reranking. Con prompt caching y Claude Haiku 5.5, contextualizar un millón de tokens de documentos sale por unos 0,38 USD según mi cálculo con los precios de noviembre de 2026.
¿Qué es contextual retrieval?
Contextual retrieval es una técnica de indexado para RAG que antepone a cada chunk un contexto breve, generado por un LLM a partir del documento completo, antes de calcular su embedding y de añadirlo al índice BM25.
No cambia la consulta ni el modelo que responde: cambia lo que guardas. Donde antes indexabas "En este caso, el límite sube a 1.000", ahora indexas algo así:
Sección de límites de la API, plan Pro. Describe el rate limit por minuto y cómo se amplía respecto al plan Free.
En este caso, el límite sube a 1.000 peticiones por minuto.
Ahora la búsqueda vectorial y la de palabras clave encuentran "plan Pro".
Por qué falla el chunking en RAG clásico
El chunking en RAG trocea los documentos en fragmentos de unos pocos cientos de tokens. Es razonable, pero tiene un coste oculto: cada chunk pierde las referencias que vivían fuera de él.
Pronombres ("este caso"), siglas definidas tres párrafos antes, el producto que solo aparece en el H1, la versión de la API en la cabecera. Nada de eso viaja con el fragmento.
La búsqueda híbrida ayuda, pero no lo arregla: si el término no está en el chunk, BM25 no tiene nada que encontrar. Ya conté cómo montar esa combinación en búsqueda híbrida con embeddings en Supabase: contextual retrieval es la capa que va encima, no un sustituto.
Anthropic probó la alternativa obvia, añadir un resumen genérico del documento a cada chunk, y según el artículo las ganancias fueron muy limitadas. El contexto útil es específico de cada fragmento.
Cuánto mejora la recuperación: los números de Anthropic
Anthropic midió la tasa de fallo como 1 menos recall@20: el porcentaje de consultas en las que el chunk correcto no aparece entre los 20 primeros resultados. Estos son los datos del artículo de Anthropic, con su configuración de 2024 (contexto generado con Claude 3 Haiku; en la fila de reranking, 150 candidatos que el reranker de Cohere reduce a 20):
| Técnica | Tasa de fallo (top-20) | Reducción vs. base | Coste que añade |
|---|---|---|---|
| Base (embeddings sin contexto) | 5,7 % | — | Ninguno extra |
| + contextual embeddings | 3,7 % | 35 % | Una llamada al LLM por chunk al indexar |
| + contextual BM25 | 2,9 % | 49 % | Mantener un índice BM25 (barato) |
| + reranking | 1,9 % | 67 % | Una llamada al reranker por consulta: latencia y coste en cada búsqueda |
Mira la última columna: las dos primeras mejoras se pagan una vez, al indexar. El reranking se paga en cada consulta, y el propio artículo avisa de que añade algo de latencia y de coste. Si ya tienes el pipeline de RAG avanzado con búsqueda híbrida, contextual retrieval se añade en la ingesta sin tocar la consulta.
Cómo implementar contextual retrieval en TypeScript con Claude
Por cada chunk, una llamada al modelo con el documento entero y el chunk. Lo que la hace viable es el prompt caching: el documento es igual en todas las llamadas, así que lo marcas con cache_control y solo pagas su precio completo la primera vez.
Este ejemplo usa @anthropic-ai/sdk y claude-haiku-5-5, con un prompt propio en español:
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic(); // lee ANTHROPIC_API_KEY del entorno
const MODEL = "claude-haiku-5-5";
const instructions = (chunk: string) => `Este fragmento pertenece al documento anterior:
<chunk>
${chunk}
</chunk>
Escribe un contexto breve (50-100 tokens) que sitúe el fragmento dentro del documento
para mejorar su recuperación en búsquedas. Incluye producto, sección, versión o fechas
si aparecen. Responde solo con el contexto.`;
async function contextualizeChunk(doc: string, chunk: string): Promise<string> {
const res = await client.messages.create({
model: MODEL,
max_tokens: 200,
messages: [
{
role: "user",
content: [
{
type: "text",
text: `<document>\n${doc}\n</document>`,
cache_control: { type: "ephemeral" }, // 5 minutos por defecto
},
{ type: "text", text: instructions(chunk) },
],
},
],
});
// Comprueba que la caché funciona: a partir de la 2.ª llamada debería ser > 0
console.log("cache_read_input_tokens:", res.usage.cache_read_input_tokens);
const block = res.content.find((b) => b.type === "text");
return block?.type === "text" ? block.text.trim() : "";
}
export async function contextualizeDocument(
doc: string,
chunks: string[],
concurrency = 5,
): Promise<string[]> {
if (chunks.length === 0) return [];
// La primera llamada escribe la caché. Las que salgan antes de que
// empiece su respuesta no la verían y pagarían el documento entero.
const contexts = [await contextualizeChunk(doc, chunks[0])];
for (let i = 1; i < chunks.length; i += concurrency) {
const batch = chunks.slice(i, i + concurrency);
contexts.push(...(await Promise.all(batch.map((c) => contextualizeChunk(doc, c)))));
}
return chunks.map((chunk, i) => `${contexts[i]}\n\n${chunk}`);
}
Dos detalles importan. Según la documentación de prompt caching, en peticiones concurrentes la entrada de caché solo existe cuando empieza la primera respuesta. Si lanzas los 10 chunks a la vez con Promise.all, pagas 10 escrituras de caché del documento, cada una a 1,25 veces el precio de entrada. Por eso la primera llamada va sola. (Con lotes, cada uno espera al chunk más lento; si te importa la velocidad, un pool como p-limit va más rápido.)
Además, Haiku 5.5 no cachea prompts de menos de 512 tokens, y no da error: simplemente no cachea.
El texto que devuelve contextualizeDocument va a tu modelo de embeddings y a tu índice de palabras clave: BM25 o, en Postgres, un tsvector con ts_rank, que no es BM25 pero cumple el mismo papel. Guarda también el chunk original: el artículo sugiere que la respuesta puede mejorar si el modelo distingue contexto y contenido. Qué pasa con esos vectores dentro de la base de datos lo explico en cómo funciona una vector database con HNSW e IVF.
Cuánto cuesta contextual retrieval hoy
Anthropic calculó 1,02 USD por millón de tokens de documento con Claude 3 Haiku y precios de 2024. Lo he recalculado con los precios de Claude Haiku 5.5 a noviembre de 2026 y las mismas hipótesis del artículo: documentos de 8.000 tokens, chunks de 800, 50 tokens de instrucciones y 100 tokens de contexto por chunk. Cada llamada ronda los 8.850 tokens: por encima del mínimo de 512 para cachear y por debajo de los 100.000 a partir de los que sube la tarifa.
Un millón de tokens son 125 documentos y 1.250 chunks:
| Concepto | Tokens | Precio Haiku 5.5 | Coste |
|---|---|---|---|
| Escritura de caché (1 por documento) | 1.000.000 | 0,125 USD/MTok | 0,125 USD |
| Lecturas de caché (9 por documento) | 9.000.000 | 0,01 USD/MTok | 0,090 USD |
| Entrada sin caché (chunk + instrucciones) | 1.062.500 | 0,10 USD/MTok | 0,106 USD |
| Salida (contexto generado) | 125.000 | 0,50 USD/MTok | 0,063 USD |
| Total | ≈ 0,38 USD |
Sin caché, la misma operación costaría unos 1,17 USD: la caché ahorra dos tercios. Es mi cálculo, no una cifra de Anthropic, y no incluye el coste de los embeddings.
Cuándo NO usar contextual retrieval
La técnica no es gratis ni universal. Cuatro límites antes de meterla en tu pipeline.
Si tu base de conocimiento cabe en el prompt, sáltatela. El artículo dice que, por debajo de 200.000 tokens (unas 500 páginas), puedes meter todo en el contexto y olvidarte del RAG. Matiz de 2026: Haiku 5.5 cobra todo cinco veces más (entrada, caché y salida) en las peticiones de más de 100.000 tokens, contando también lo que sale de caché, así que el umbral depende del modelo. Y no todos comparten la idea. En el hilo de Hacker News sobre el artículo, un usuario escribió que "The statement about just throwing 200k tokens to get best answer for smaller datasets goes against my experience", porque, según contaba, cuanto más crece el prompt, menos consistente es la respuesta, y le pasaba ya muy por debajo de 25.000 tokens.
Documentos que cambian a menudo. Cada edición obliga a regenerar el contexto de todos los chunks del documento, porque cada contexto se genera leyéndolo entero. En una wiki que se edita a diario, el coste y la cola de reindexado crecen rápido.
Latencia de indexado. Una llamada al LLM por chunk añade tiempo a cada ingesta. En el mismo hilo, otro usuario lo planteaba así: "Even with prompt caching this adds a huge extra time to your vector database create/update, right?". Si necesitas que un documento sea buscable segundos después de subirlo, indexa primero sin contexto y contextualiza en segundo plano.
Documentos muy estructurados. Si tu documentación tiene buenos encabezados, anteponer la ruta de títulos al chunk (# Límites > ## Plan Pro) recupera parte de ese contexto sin llamar a ningún modelo. Un usuario del mismo hilo de HN contaba que su equipo lo hacía así y que "seems to work pretty well", sin LLM al indexar. Prueba eso primero y mide.
Cómo saber si te compensa
Contextual retrieval no se adopta por fe. Necesitas un conjunto de evaluación con preguntas reales y su chunk correcto: mides el recall@20 actual, contextualizas y vuelves a medir. Si no tienes ese conjunto, ese es tu primer trabajo. Y si dudas entre recuperar mejor o entrenar el modelo, empieza por RAG vs. fine-tuning.
Mi recomendación: si tu RAG falla cuando el dato existe pero el fragmento no dice de qué habla, empieza por contextual retrieval: cuesta céntimos y no cambia ni tu base de datos ni tu modelo.
En el ebook gratuito El Developer Agéntico tienes RAG explicado como parte de la arquitectura de un agente, junto a tools, memoria y MCP; el capítulo 5 trata el chunking y el late chunking, la alternativa sin LLM generativo a lo que has visto aquí. Y si quieres llevarlo a un producto de verdad, en el curso Construye con IA vamos de la idea al producto con Claude Code, paso a paso.
Preguntas frecuentes
¿Contextual retrieval es lo mismo que la búsqueda híbrida?
No. La búsqueda híbrida combina embeddings y BM25 al consultar. Contextual retrieval cambia lo que indexas en ambos: añade a cada chunk un contexto generado por un LLM. Se usan juntas, y en las pruebas de Anthropic la combinación redujo los fallos de recuperación un 49 %.
¿Necesito usar Claude para contextual retrieval?
No. Cualquier LLM puede generar el contexto. Lo que hace viable la técnica es el prompt caching, que abarata leer el mismo documento en cada chunk. Con otro proveedor, comprueba si tiene caché y a qué precio.
¿Cuánto cuesta aplicar contextual retrieval a mi documentación?
Con Claude Haiku 5.5, prompt caching y documentos de 8.000 tokens, unos 0,38 USD por millón de tokens de documento, una sola vez, más el coste de los embeddings. Si un documento pasa de 100.000 tokens, cada llamada supera ese umbral y Haiku 5.5 cobra todas sus tarifas por cinco, así que el coste también se multiplica por cinco.
¿Puedo usar contextual retrieval con pgvector o Supabase?
Sí. Contextual retrieval cambia la ingesta, no la base de datos: guardas el chunk contextualizado en pgvector como cualquier otro embedding, y la parte de palabras clave va en un tsvector de Postgres.
¿Cuánto debe ocupar el contexto de cada chunk?
Según Anthropic, suele ocupar entre 50 y 100 tokens. Cada token de salida se paga por chunk, así que pide en el prompt solo lo que se pierde al trocear: producto, sección, versión y fechas.
Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.
¿Quieres construir con agentes en serio?
Curso «Construye con IA» con Claude Code, de la idea al producto.
Developer con más de 15 años en frontend y creador de Dominicode. Escribe sobre IA aplicada al desarrollo de software.
¿Te resultó útil este artículo?
Compártelo con tu comunidad y ayuda a otros desarrolladores.