
RAG privado en tu propia máquina con turbovec
Busca en 177K fragmentos del BOE en local — sin nube, sin claves de API
- rag
- turbovec
- embeddings
- ollama
- boe
Las demos de “chatea con tus documentos” suelen acabar con una base de datos vectorial en la nube y una clave de API. Esta no: el modelo de embeddings, el índice y el modelo de lenguaje corren en tu propia máquina. Como corpus de prueba usé algo real y exigente — 2.000 documentos del BOE, el Boletín Oficial del Estado, convertidos a Markdown. La pieza interesante es el índice, turbovec, que comprime los vectores a 4 bits por dimensión y aun así busca más rápido que FAISS.
Por qué turbovec
- Sin fase de entrenamiento. La mayoría de los índices comprimidos (como los de FAISS) tienen que aprender de tus datos primero. TurboQuant deriva su compresión analíticamente: los vectores son buscables en cuanto se añaden.
- Diminuto. Todo el corpus de abajo —177K fragmentos— vive en un índice de 94 MB. Los mismos vectores sin comprimir ocuparían 727 MB.
- Búsqueda acotada. Puedes restringir una consulta a una carpeta o proyecto dentro del propio índice, así que los permisos no necesitan un índice aparte.
- Offline de verdad. Sin servicio ni telemetría. Con un modelo local de embeddings, nada sale del portátil.
La pila
| Capa | Elección | Por qué |
|---|---|---|
| Documentos | Corpus del BOE → Markdown | 2.000 leyes y normas; el español legal denso es una prueba de estrés real |
| Fragmentos | Pasajes de ~800 tokens | Suficiente contexto sin perder relevancia |
| Vectores | Qwen3-Embedding-0.6B vía Ollama | Pequeño, multilingüe, corre en CPU |
| Índice | turbovec, 4 bits | Ver arriba |
| Respuestas | Gemma 4 12B o Qwen3.8-27B vía Ollama | Los dos modelos del experimento anterior |
Cómo está montado
El pegamento son unas cien líneas de Python y el flujo son tres pasos:
Paso 1 — Indexar una vez. Trocear cada Markdown en pasajes de ~800 tokens, vectorizarlos y añadirlos a un índice de 4 bits. El sync hace la escritura incremental y tolerante a fallos — la ingesta de 177K fragmentos tardó unas horas y pudo reanudarse tras interrupciones.
index = turbovec.IdMapIndex(dim=1024, bit_width=4)
index.add_with_ids(vectors, chunk_ids) # vectors salen del modelo de embeddings
index.sync("boe.tvec") # incremental, a prueba de fallos
Paso 2 — Buscar. Vectorizar la pregunta y recuperar los seis pasajes más cercanos.
scores, ids = index.search(question_vector, k=6)
Paso 3 — Responder con citas. El modelo de chat solo ve los pasajes recuperados y tiene la orden de citarlos. Es la parte que lo mantiene honesto.
answer = chat(f"Responde usando solo estos pasajes, citando [n]:\n{passages}\n\nP: {question}")
Medido sobre este corpus
| Valor | |
|---|---|
| Corpus | 2.000 documentos del BOE · 445 MB de Markdown |
| Fragmentos indexados | 177.580 vectores (1024 dimensiones) |
| Índice en disco | 94,2 MB a 4 bits — ~7,7× más pequeño que los 727 MB en float32 |
| Carga del índice | 0,08 s |
| Búsqueda mediana, k = 6 | 1,35 ms en consultas sintéticas · ~27 ms de extremo a extremo en la batería real (incluye vectorizar la pregunta) |
| Tiempo de respuesta completa | mediana ~18 s con Gemma 4 12B en el Mac de 16 GB |
Después pasé una batería de 11 preguntas legales reales —duración de alquileres, obligaciones de protección de datos, puntos del carnet— por todo el pipeline. Todas las respuestas volvieron con citas a entradas reales del BOE, y la recuperación fue anecdótica: ~25 ms para encontrar los pasajes frente a segundos del modelo redactando. Mi resultado favorito es la prueba negativa: ante “¿qué dice la legislación española sobre la colonización de Marte?”, el sistema respondió sin más que los pasajes no lo cubren — en lugar de inventarse un artículo. Esa negativa es justo lo que quieres de un pipeline de recuperación.
Para poner las cifras en contexto: buscar en medio millón de palabras de español jurídico tarda más o menos lo mismo que renderizar un solo fotograma de un videojuego. La recuperación dejó de ser el cuello de botella hace tiempo — los segundos se van en el LLM leyendo los pasajes, que es justo por lo que importa combinarlo con un modelo local rápido.
Lo que me llevo
- El texto legal es un gran benchmark de RAG. Denso, formulaico, lleno de referencias cruzadas: si la recuperación funciona aquí, funcionará en corpus más amables.
- La parte difícil nunca es el índice. Trocear bien y escribir un prompt que obligue a citar importan mucho más que la base de datos que elijas.
- Las citas son la funcionalidad. Obligar al modelo a citar pasajes
[n]convierte las alucinaciones de invisibles en obvias — y te deja saltar a la ley real.
Experiencias relacionadas

Generación de imagen y vídeo en local con FLUX y Wan2.1
De los prompts en DALL·E de 2023 a un pipeline totalmente offline en una RTX 3090

LLMs en local: qué cabe en 16 GB frente a 32 GB+
Gemma 4 12B en un portátil contra Qwen3.8-27B en una RTX 3090 — medido, no supuesto