From n00b to ZeroCool / La nueva era
RAG sobre tu codebase: haz que la IA entienda tu proyecto (sin inventar cosas)
Arma RAG sobre tu repo: chunking, embeddings y búsqueda híbrida. Respuestas con citas (archivo y líneas) para menos alucinaciones y mejor debugging.
Lo que vale la pena leer aquí
La escena: 11:47 pm, el deploy truena en production, y en Slack cae la pregunta que siempre llega tarde: “¿Quién sabe dónde se valida el payload de facturación?”
La escena: 11:47 pm, el deploy truena en production, y en Slack cae la pregunta que siempre llega tarde: “¿Quién sabe dónde se valida el payload de facturación?”
Abres el repo. 2,300 archivos. Tres versiones del mismo helpers.ts. Una carpeta legacy/ que nadie toca “porque funciona”. Y tú con la laptop viejita echando calor como comal.
Le preguntas a la IA y te contesta con seguridad… pero te inventa funciones, o peor: mezcla módulos de otro proyecto. Le dices “lee el repo” y pues no: no puede cargar todo tu codebase en contexto.
Ahí es donde RAG sí brilla: no es magia, es hacer que la IA busque en tu repo y responda con evidencia.
Qué vas a sacar de esto
- Qué es RAG aplicado a un repo (y qué NO arregla).
- Cómo partir tu codebase en chunks que sí sirven para preguntas reales.
- Cómo indexar y consultar con embeddings + búsqueda híbrida (vector + keywords).
- Cómo forzar respuestas con citas (archivo + líneas) para bajar alucinaciones.
- Un workflow que paga la inversión: onboarding, debugging, “¿dónde se usa esto?”, “¿qué rompe si lo cambio?”.
Por qué esto te conviene en el jale (sin romanticismo)
Si trabajas en LatAm, esto te va a sonar:
- El onboarding es “ve preguntando”, porque la doc se quedó a medias desde el último cambio de prioridades.
- El repo creció con prisa: features para el cliente, hotfixes antes del corte, refactors que se quedaron a la mitad.
- A veces necesitas algo que jale local o self-hosted porque tu red decide morirse justo cuando estás corriendo tests.
RAG en tu codebase te ayuda cuando:
- Tienes que encontrar la pieza correcta sin abrir 20 tabs.
- Quieres que la IA se amarre a lo que existe: “esto está en
src/billing/validateInvoice.tslíneas 41–78”. - Necesitas un asistente que no se haga el listo: si no hay evidencia, que diga “no lo encontré”.
Tradeoff honesto:
- RAG no “entiende” como humano: recupera y sintetiza. Si tu arquitectura es un laberinto, no la va a limpiar… pero sí te da una linterna decente cuando traes deadline encima.
Guía principal: arma RAG para tu repo (paso a paso)
Setup que he visto funcionar en equipos chicos y medianos, sin volverte esclavo de la herramienta:
- Indexador en Python o Node.
- Embeddings (OpenAI, o local tipo
nomic-embed-text/bge-smallsi te preocupa costo/privacidad). - Vector DB (Chroma, Qdrant, pgvector) + búsqueda por texto (BM25) o híbrida.
- Un “answerer” que obliga citas.
1) Decide el alcance: ¿qué sí indexas y qué no?
No metas todo “porque sí”. Si indexas basura, la IA va a citar basura, y luego vas a creer que el RAG “no sirve”.
Incluye:
src/,app/,packages/.README.md, docs internas, ADRs si existen.- Config que realmente explica comportamiento:
docker-compose.yml,k8s/,terraform/,.github/workflows/.
Excluye (casi siempre):
node_modules/,dist/,build/,.next/,coverage/.- Lockfiles gigantes si no los necesitas.
- Binarios, minificados, snapshots enormes.
- Secrets (y si aparecen… ya tienes otro incendio que apagar).
Tip de guerra: si tu repo tiene legacy/ que nadie entiende, sí indexa, pero marca metadata area=legacy para filtrar cuando estés trabajando “lo nuevo”. Si no lo marcas, te va a responder con cosas viejas justo cuando el jefe te pide “nomás un cambiecito”.
2) Define un chunking que respete el código
Aquí se ganan o se pierden respuestas.
Regla práctica:
- Para código: chunks de 200 a 500 líneas máximo, idealmente por unidad semántica (función/clase/método) con tantito contexto.
- Para Markdown: chunks por secciones (H2/H3).
Si cortas cada N caracteres, vas a partir funciones a la mitad y la respuesta sale Frankenstein: medio import, medio return, cero sentido.
Estrategia simple y efectiva:
- Parsear por lenguaje cuando se pueda (Tree-sitter jala muy bien en varios lenguajes).
- Si no, heurística: separar por
class,function,def,export const, etc.
3) Saca metadata que luego te salva la vida
Cada chunk debería traer metadata tipo:
path:src/billing/validateInvoice.tslanguage:tssymbol:validateInvoice(si lo detectas)start_line,end_linegit_commit(opcional)area:billing,auth, etc. (si puedes inferir por path)
Esto te sirve para:
- Filtrar por carpeta.
- Mostrar citas confiables.
- Debuggear el retrieval cuando falle (porque va a fallar y necesitas saber por qué, no solo “se sintió raro”).
4) Indexa con embeddings (y guarda el texto original)
Necesitas dos cosas por chunk:
- El vector embedding.
- El texto original (para dárselo al modelo y para poder citar).
Ejemplo conceptual en Python (pseudo-código):
from pathlib import Path
EXCLUDE = {"node_modules", "dist", "build", ".next", "coverage", ".git"}
def iter_files(root: str):
for p in Path(root).rglob("*"):
if p.is_dir():
continue
if any(part in EXCLUDE for part in p.parts):
continue
if p.suffix.lower() in {".ts", ".tsx", ".js", ".py", ".go", ".java", ".md", ".yml", ".yaml"}:
yield p
def chunk_text(text: str, max_lines=280):
lines = text.splitlines()
buf = []
start = 1
for i, line in enumerate(lines, start=1):
buf.append(line)
if len(buf) >= max_lines:
yield start, i, "\n".join(buf)
buf = []
start = i + 1
if buf:
yield start, len(lines), "\n".join(buf)
def index_repo(root: str, embed, vectordb):
for file_path in iter_files(root):
text = file_path.read_text(errors="ignore")
for start, end, chunk in chunk_text(text):
vec = embed(chunk)
vectordb.upsert({
"id": f"{file_path}:{start}-{end}",
"vector": vec,
"text": chunk,
"meta": {
"path": str(file_path),
"start_line": start,
"end_line": end,
}
})
Decisión práctica: si tu repo está grande, indexa incremental.
- Guarda hash por archivo (o por chunk).
- Re-indexa solo lo que cambió.
Si no, vas a pagar lana y tiempo por re-hacer lo mismo cada commit, y tu workflow se muere por flojera.
5) Búsqueda híbrida: vector + keywords (cuando el nombre sí importa)
Vector search es buenísimo para “¿dónde se hace la validación de X?”.
Pero cuando tú ya sabes el término exacto (validateInvoice, JWT, X-Request-Id), keywords (BM25) suele ganar.
Lo que mejor jala en repos:
- Hacer híbrido: top-k por embeddings + top-k por BM25, luego re-rank.
Resultado: menos “me trajo cosas parecidas pero no era” y más “sí, aquí está el símbolo exacto que buscabas”.
6) Prompt con política estricta: respuestas con citas o nada
Si quieres bajar alucinaciones, no es opcional. Tu sistema debe obligar:
- Si no hay evidencia en los chunks recuperados, que diga “No tengo suficiente evidencia”.
- Que cite archivos y líneas.
- Que separe “lo que veo en el código” vs “recomendación”.
Plantilla útil (idea, no dogma):
Eres un asistente que responde SOLO usando el contexto provisto.
Si el contexto no contiene la respuesta, di: "No lo encontré en el repo con la evidencia disponible".
Incluye citas con formato: (path:start-end).
No inventes nombres de funciones ni archivos.
Pregunta: {question}
Contexto del repo:
{retrieved_chunks}
Respuesta (con pasos accionables y citas):
7) Preguntas que sí pagan la inversión
Prueba tu RAG con preguntas de vida real, de esas que salen cuando alguien pide un cambio “en corto” sin entender el impacto:
- “¿Dónde se valida el RFC y quién lo llama?”
- “Si cambio
InvoiceStatus, ¿qué módulos se rompen?” - “¿Cómo se arma el request al proveedor de timbrado y dónde se reintenta?”
- “¿Qué hace exactamente este cron y cómo se despliega?”
Si no puede responder esto, no es “falta de IA”: normalmente es chunking mal hecho, metadata floja, o retrieval muy corto.

Screenshots sugeridos (para que se vea y se sienta real)
- Terminal con el indexador corriendo y conteo de chunks (
Indexed 12,482 chunks). - Pantalla de una consulta con resultados: lista de chunks con
pathy rango de líneas. - Ejemplo de respuesta final mostrando citas
(src/billing/validateInvoice.ts:41-78). - Comparación “sin RAG vs con RAG” para la misma pregunta.
Errores comunes (y cómo arreglarlos sin llorar)
Error 1: “La IA sigue inventando cosas”
Causa típica: el prompt no exige evidencia, o le pasas contexto insuficiente.
Solución:
- Política estricta: “si no está, no lo sé”.
- Sube
top_k(por ejemplo 8→20) y aplica re-rank. - Asegura que el contexto traiga el chunk completo (incluyendo imports/exports cercanos).
Error 2: “Encuentra cosas irrelevantes, puro ruido”
Causa típica: indexaste dist/, logs, snapshots o docs viejas; o chunks enormes con demasiadas cosas.
Solución:
- Mejora exclusiones.
- Chunking más semántico.
- Agrega metadata por
areay filtra por carpeta cuando preguntes.
Error 3: “No encuentra símbolos exactos”
Causa típica: embeddings no son tan buenos con tokens raros / nombres exactos.
Solución:
- Búsqueda híbrida (BM25 + vector).
- Agrega un campo “keywords” por chunk: extrae identifiers (regex simple) y úsalo para match.
Error 4: “Se tarda un buen y cuesta lana”
Causa típica: indexas demasiado y re-indexas todo cada vez.
Solución:
- Indexado incremental (hash por archivo/chunk).
- Modelos de embedding más baratos o locales.
- Evita indexar archivos gigantes si no aportan (migraciones viejas, dumps).
Error 5: “Me da respuestas correctas pero no accionables”
Causa típica: el modelo resume bonito pero no aterriza.
Solución:
- Pide formato de salida: pasos, ubicaciones, y “qué tocaría modificar”.
- Forza “lista de archivos a revisar” con citas.

Checklist final (para tu RAG de repo que sí sirve)
- Tengo lista de inclusiones/exclusiones por carpeta y extensión.
- Mis chunks respetan funciones/clases (o al menos no cortan a la mitad).
- Cada chunk guarda
path+start_line/end_line. - Uso búsqueda híbrida (vector + keywords) o al menos tengo plan para símbolos.
- El prompt obliga evidencia y citas.
- Puedo correr indexado incremental y no rehago todo cada commit.
- Probé 10 preguntas reales del equipo y medí “acierta / no acierta / inventa”.
- Tengo guardrails: si no hay evidencia, no responde “seguro”.
FAQ
1) ¿RAG reemplaza documentación y diagramas?
No. Lo que sí hace es que la doc “implícita” (el código) sea consultable en lenguaje natural. La doc buena sigue siendo la que explica por qué existe algo, no solo dónde está.
2) ¿Qué vector DB conviene: Chroma, Qdrant o pgvector?
- Chroma: rápido para arrancar local.
- Qdrant: sólido en producción, buen performance.
- pgvector: si ya vives en Postgres y quieres menos moving parts.
Elige la que tu equipo pueda operar a las 2 am cuando se caiga. Neta, ahí se decide.
3) ¿Qué tan seguido re-indexo?
Ideal: incremental por commit o al menos por cambios en main. Si estás en modo “startup con fuego”, un re-index nocturno también funciona mientras el repo no cambie cada hora.
4) ¿Cómo manejo secretos y datos sensibles?
Primero: no deberían estar en el repo. Pero siendo realistas… agrega escaneo (regex) para claves comunes y excluye esos archivos del índice. Si el proyecto es sensible, usa embeddings locales y guarda el índice cifrado.
5) ¿Puedo usar esto para generar PRs automáticos?
Sí, pero con límites. RAG te da contexto para que el modelo proponga cambios, pero antes de “auto-merge”: tests, linters, revisión humana y plan de rollback. Darle acceso al repo sin guardrails es receta segura para un incidente.
Siguiente episodio
Ya tienes a la IA “leyendo” tu repo con evidencia.
Lo que sigue es ponerle manos: cómo convertir ese contexto en cambios seguros, pull requests chicos y tests que no den pena.
Idea para cerrar bien este post: toma una sola práctica de aquí y conviértela en algo que tu equipo pueda aplicar hoy.
Cuando un artículo aterriza en decisiones reales, deja de ser contenido y se vuelve ventaja.


