
Durante años fui acumulando documentación.
Manuales, procedimientos, informes, configuraciones, artículos, notas, exportaciones de páginas web, documentos de proyectos, pruebas de laboratorio y soluciones a problemas que probablemente volverían a aparecer algún día.
La información estaba ahí.
El problema era encontrarla cuando realmente la necesitaba.
Una estructura de carpetas ayuda. Un buen nombre de archivo también. Y un buscador tradicional puede localizar una palabra concreta. Pero ninguna de esas cosas responde bien a preguntas como estas:
- ¿Qué conclusión saqué cuando comparé dos modelos de embeddings?
- ¿Dónde documenté el problema que tuve con una red Docker?
- ¿Qué decisiones tomé al configurar la memoria de un agente?
- ¿Qué procedimiento seguí la última vez que migré una base de datos?
- ¿En qué documentos aparece una idea aunque no utilicen exactamente las mismas palabras?
Ahí fue donde empecé a interesarme de verdad por RAG.
No porque quisiera instalar otra herramienta de inteligencia artificial.
Quería recuperar mejor el conocimiento que ya tenía.
Mi RAG no empezó el día que elegí un modelo de embeddings. Empezó el día que entendí que una carpeta llena de documentos no es todavía una base de conocimiento.
Nota de alcance: el RAG descrito en esta serie es un proyecto estrictamente personal y de aprendizaje. No procesa documentación, datos, sistemas ni contenidos internos o identificables de ninguna organización. Los ejemplos son sintéticos, generales o reformulados con fines divulgativos.
Qué es RAG sin complicarlo demasiado
RAG son las siglas de Retrieval-Augmented Generation, que suele traducirse como generación aumentada mediante recuperación.
El nombre puede parecer más complicado que la idea.
Un modelo de lenguaje sabe generar texto, razonar sobre un contexto y relacionar información. Pero no conoce automáticamente mis documentos, mis notas ni las decisiones que he ido tomando durante años.
Un sistema RAG añade un paso antes de generar la respuesta.
- Recibe una pregunta.
- Busca dentro de una colección documental los fragmentos más relacionados con ella.
- Entrega esos fragmentos al modelo de lenguaje.
- El modelo responde utilizando la pregunta y el contexto recuperado.
La diferencia es importante.
El modelo no responde únicamente con lo que aprendió durante su entrenamiento. Responde también con información que acaba de recuperar de mis propios documentos.
Eso no convierte automáticamente la respuesta en verdadera. Pero permite que se apoye en una memoria externa, actualizable y verificable.
RAG no significa entrenar un modelo con mis documentos
Esta es una de las primeras confusiones que conviene evitar.
Cuando incorporo documentación a mi RAG no estoy reentrenando el modelo de lenguaje ni introduciendo permanentemente mis archivos dentro de sus parámetros.
Lo que hago es otra cosa.
Los documentos se procesan, se dividen en fragmentos y cada uno de esos fragmentos se convierte en una representación numérica que puede buscarse más adelante.
Cuando hago una pregunta, el sistema recupera algunos de esos fragmentos y los coloca dentro del contexto que recibe el modelo de lenguaje.
Por eso puedo añadir, actualizar o eliminar documentación sin volver a entrenar el modelo que redacta la respuesta.
También puedo cambiar el modelo generativo sin tener que reconstruir necesariamente toda la memoria documental.
Pero si cambio el modelo de embeddings, la situación es distinta. Cada modelo ha aprendido una forma propia de organizar matemáticamente el lenguaje, y los vectores generados por uno no deberían mezclarse con los generados por otro.
Es parecido a cambiar de sistema de coordenadas. Aunque los dos mapas describan el mismo territorio, no puedes mezclar directamente los puntos calculados con uno y con otro.
Si cambio el modelo de embeddings, normalmente no necesito volver a extraer los documentos originales si conservo los fragmentos limpios y sus metadatos. Lo que sí debo hacer es volver a generar los vectores de todos esos fragmentos con el nuevo modelo y reconstruir el índice vectorial.
El modelo de embeddings y el modelo de lenguaje no hacen el mismo trabajo
En un RAG intervienen modelos diferentes y es fácil confundirlos porque ambos forman parte de lo que llamamos inteligencia artificial.
Pero no hacen lo mismo.
Un modelo de embeddings recibe un texto y devuelve una lista de números. Su trabajo no es redactar, explicar ni conversar. Su trabajo es representar relaciones de significado para que después puedan compararse textos, preguntas y documentos.
Un modelo de lenguaje, en cambio, recibe texto y contexto, predice qué tokens deben venir después y genera una respuesta.
Una forma sencilla de imaginarlo es pensar en una biblioteca.
El modelo de embeddings se parece al bibliotecario que intenta localizar los libros o páginas más relacionados con una pregunta.
El modelo de lenguaje se parece a la persona que lee esas páginas y redacta una respuesta.
La comparación tiene sus límites, pero ayuda a entender algo importante: si el primer paso recupera los documentos equivocados, una respuesta muy bien redactada no corrige el error.
El modelo de lenguaje puede sonar convincente incluso cuando el contexto recuperado no era el adecuado.
Por eso, en un RAG, encontrar bien viene antes que redactar bien.
Qué es un embedding explicado de una forma sencilla
Un embedding es una representación numérica de las relaciones de significado que un modelo ha aprendido durante su entrenamiento.
Cuando mi sistema procesa un fragmento de texto, el modelo de embeddings no guarda una definición, un resumen ni una copia comprimida del contenido.
Devuelve una lista de números: un vector.
En la configuración que describo en esta fase utilizo la representación densa de bge-m3, de 1.024 dimensiones.
Eso significa que cada fragmento queda representado por una lista de 1.024 valores numéricos.
No son 1.024 palabras clave ni 1.024 categorías que una persona pueda interpretar por separado.
Cada número, aislado, nos dice muy poco. Es la posición completa del vector y su relación con otros vectores lo que resulta útil.
La forma más sencilla que he encontrado para imaginarlo es pensar en un mapa enorme.
En un mapa geográfico, Madrid y Toledo aparecen relativamente cerca porque sus coordenadas están próximas. En un espacio de embeddings, dos textos quedan cerca cuando el modelo ha aprendido que sus significados están relacionados.
La diferencia es que este mapa no tiene dos o tres ejes visibles. Tiene cientos o miles de dimensiones matemáticas.
Por ejemplo, estos dos fragmentos podrían terminar cerca:
La copia nocturna no pudo completarse porque el volumen estaba lleno.
El backup falló por falta de espacio disponible en el almacenamiento.
No utilizan exactamente las mismas palabras, pero describen prácticamente el mismo problema.
Un buscador literal intenta encontrar coincidencias como «copia», «backup», «volumen» o «almacenamiento». Una búsqueda semántica intenta localizar textos que ocupan zonas próximas dentro de ese mapa de significados, aunque el vocabulario no sea idéntico.
Cuando escribo una pregunta, esa pregunta también se transforma en un vector.
Después, el sistema compara su posición con la de los fragmentos almacenados. Para hacerlo utiliza medidas matemáticas de similitud o distancia, como la similitud del coseno.
No se pregunta si dos textos contienen exactamente las mismas palabras.
Se calcula hasta qué punto sus representaciones apuntan en direcciones parecidas dentro del espacio vectorial.
Un embedding no guarda una respuesta. Guarda una posición aproximada dentro de un mapa de significados.
La base vectorial tampoco sustituye a los documentos. Normalmente conserva el vector junto con el texto original y metadatos como el nombre del archivo, la ruta, la fecha, el tipo de documento o la sección de procedencia.
De dónde salen los modelos de embeddings
Estos modelos no aparecen de la nada y yo tampoco los he entrenado con mis documentos.
Han sido creados y entrenados previamente por organizaciones y equipos de investigación que después publican los pesos del modelo para que otras personas podamos ejecutarlos y utilizarlos con nuestra propia documentación.
Durante su entrenamiento, el modelo recibe grandes cantidades de ejemplos de textos relacionados y no relacionados.
Puede aprender, por ejemplo, que una pregunta debería quedar cerca del fragmento que la responde, que dos explicaciones sobre el mismo problema deberían estar próximas o que textos sobre asuntos diferentes deberían separarse.
De forma simplificada, el entrenamiento intenta acercar las representaciones de los ejemplos relacionados y alejar las de los ejemplos que no lo están.
Para conseguirlo se ajustan millones de parámetros una y otra vez.
Algunos ejemplos negativos son sencillos. Otros son deliberadamente difíciles: textos que comparten vocabulario, pero que en realidad hablan de cosas distintas. Esos casos ayudan al modelo a no depender únicamente de palabras coincidentes.
Según su arquitectura y el objetivo para el que se entrenen, estos modelos pueden combinar aprendizaje contrastivo, destilación de conocimiento, instrucciones que indican el tipo de tarea y diferentes formas de representar la información.
El resultado final es un modelo capaz de transformar textos nuevos en vectores sin haber visto antes mis documentos concretos.
Eso es importante.
Yo no enseño al modelo el contenido de mi documentación. Utilizo lo que ya aprendió sobre el lenguaje para calcular posiciones matemáticas para mis propios fragmentos.
No es magia.
Es una red neuronal que ha aprendido relaciones estadísticas y semánticas, y que después las expresa mediante números.
El recorrido completo de un documento
Cuando incorporo un documento a mi RAG, no pasa directamente del disco al modelo de lenguaje.
Hay una cadena completa de procesamiento:
- Descubrir el archivo.
- Identificar su formato.
- Extraer el contenido.
- Limpiar aquello que no aporta información.
- Separar el contenido en fragmentos con sentido.
- Añadir metadatos.
- Generar un embedding para cada fragmento.
- Guardar el vector, el texto y los metadatos.
- Registrar qué se ha procesado y qué ha fallado.
Ese esquema general describe el recorrido básico. Pero en la práctica cada tipo de archivo se comporta de forma distinta durante la extracción.
No todos los documentos deben pasar por el mismo procesador
Uno de los errores más fáciles de cometer al diseñar una ingesta es intentar utilizar una sola herramienta para todos los formatos.
En mis pruebas comprobé que no tenía sentido tratar igual un PDF, un documento Word, un XML, un fichero de texto estructurado o una hoja de cálculo.
Los PDF, los documentos ofimáticos y las presentaciones pueden beneficiarse de herramientas que reconstruyen su estructura, detectan tablas y conservan títulos. Los formatos antiguos pueden necesitar una conversión previa. En cambio, un XML, un CSV o un fichero de texto estructurado suelen procesarse mejor con lectores específicos que respeten su formato original.
Las imágenes y los PDF escaneados deben pasar por OCR cuando realmente sea necesario. Los formatos desconocidos, incompletos o dudosos deben enviarse a revisión o cuarentena.
La solución no fue buscar una herramienta universal. Fue diseñar un sistema de enrutamiento:
- PDF, DOCX y presentaciones hacia un procesador documental;
- formatos antiguos mediante una conversión previa;
- XML, CSV y texto estructurado mediante parsers específicos;
- imágenes y documentos escaneados mediante OCR cuando sea necesario;
- y formatos desconocidos hacia revisión o cuarentena.
Una buena ingesta no obliga a todos los documentos a recorrer el mismo camino.
Extraído no significa publicable
Conseguir texto de un documento no significa que ese contenido deba entrar automáticamente en la memoria.
Entre la extracción y la indexación necesito una fase de validación.
Un documento puede quedar:
- aprobado;
- pendiente de revisión;
- en cuarentena;
- omitido;
- marcado como histórico;
- marcado como obsoleto;
- o clasificado como restringido.
Esta separación evita que un proceso técnicamente correcto publique contenido incorrecto, sensible, desactualizado o fuera de contexto.
La ingesta extrae. La política de publicación decide.
Ese recorrido es bastante menos vistoso que hablar con un modelo de lenguaje.
Pero ahí está gran parte del trabajo real.
Una demostración de RAG puede montarse en pocos minutos. Un sistema que procese de forma fiable años de documentación heterogénea necesita bastante más cuidado.
Antes del RAG está la organización documental
Durante la construcción de mi sistema confirmé algo que ya había aprendido en otros proyectos.
La tecnología no corrige una mala organización. Como mucho, consigue buscar más rápido dentro de ella.
Antes de indexar, intento que la documentación tenga una estructura comprensible incluso sin inteligencia artificial.
No hace falta diseñar una clasificación perfecta. Pero sí conviene mantener algunos criterios:
- separar áreas o temas principales;
- utilizar nombres de archivo reconocibles;
- evitar copias innecesarias;
- diferenciar borradores de versiones definitivas;
- conservar fechas cuando aporten contexto;
- no mezclar documentación vigente con material claramente obsoleto;
- mantener cerca los archivos que forman parte del mismo proyecto.
También intento distinguir entre tres tipos de información:
- Documentación estable: manuales, procedimientos, arquitectura y decisiones consolidadas.
- Documentación evolutiva: notas de proyectos, pruebas y configuraciones que siguen cambiando.
- Material histórico: versiones antiguas que quiero conservar, pero que no deberían aparecer como si fueran actuales.
Los metadatos permiten mantener esa diferencia durante la recuperación.
Si un fragmento conserva su ruta, fecha, proyecto, versión y tipo de documento, después puedo filtrar mejor y entender de dónde procede.
Un RAG puede encontrar un fragmento relevante. Los metadatos ayudan a decidir si además es el fragmento correcto.
Dividir bien los documentos importa más de lo que parece
Los modelos de embeddings no suelen trabajar con una biblioteca completa de una sola vez.
Los documentos se dividen en fragmentos, normalmente llamados chunks.
Si un fragmento es demasiado grande, puede mezclar varios asuntos y perder precisión. Si es demasiado pequeño, puede quedarse sin el contexto necesario para entender lo que significa.
No existe un tamaño universal que funcione igual para todos los documentos.
Un procedimiento, una conversación, una tabla, un manual técnico y un artículo no tienen la misma estructura.
Por eso prefiero conservar unidades semánticas siempre que sea posible:
- un título con sus párrafos;
- una sección completa de un procedimiento;
- una decisión junto con su justificación;
- una tabla con su explicación;
- un error junto con la solución aplicada.
Cortar únicamente cada cierto número de caracteres es sencillo, pero puede separar una pregunta de su respuesta o una decisión del contexto que la explica.
El solapamiento entre fragmentos puede ayudar cuando un corte es inevitable, pero tampoco conviene duplicarlo todo. Demasiado solapamiento llena el índice de contenido repetido y puede hacer que los resultados sean menos variados.
Con el tiempo he entendido que el chunking no es una operación previa sin importancia.
Es una decisión editorial sobre qué partes de un documento deben conservar su significado juntas.
Los modelos de embeddings que he probado
No empecé directamente con bge-m3.
Durante la evolución de mi RAG he utilizado varios modelos. Entre ellos, nomic-embed-text:latest, mxbai-embed-large y, en la configuración que describo en esta fase del proyecto, bge-m3.
Los tres persiguen un objetivo parecido: convertir textos en vectores que puedan compararse.
Pero no producen necesariamente el mismo tipo de representación, no han sido entrenados con los mismos datos ni responden igual ante todos los idiomas y tareas.
nomic-embed-text
nomic-embed-text, creado por Nomic AI, fue uno de los modelos con los que empecé a trabajar.
Es un modelo especializado exclusivamente en embeddings. No genera texto ni funciona como un modelo conversacional.
nomic-embed-text-v1.5 genera representaciones de 768 dimensiones y fue diseñado para admitir textos de contexto amplio. Además, permite reducir el tamaño de esos vectores mediante una técnica llamada Matryoshka Representation Learning.
La versión oficial utiliza además prefijos que indican la tarea, por ejemplo si el texto es una consulta o un documento. Eso ayuda al modelo a distinguir entre una pregunta y un fragmento que podría contener la respuesta.
En mi instalación lo utilicé a través de la etiqueta nomic-embed-text:latest de Ollama. Como las etiquetas pueden evolucionar, conservar el nombre exacto, la versión o el identificador del modelo forma parte también de documentar bien el RAG.
Fue una buena forma de empezar a comprobar que la búsqueda semántica funcionaba y que podía recuperar ideas aunque las palabras no coincidieran exactamente.
Pero seguir probando modelos me permitió entender que no bastaba con mirar una clasificación o un resultado de benchmark. También tenía que valorar cómo se comportaba con mi documentación real, mayoritariamente en español, con textos técnicos, procedimientos, notas y contenidos de diferentes épocas.
mxbai-embed-large
Después utilicé mxbai-embed-large, desarrollado por Mixedbread.
Genera vectores de 1.024 dimensiones y fue especialmente bien valorado en evaluaciones de recuperación en inglés. También admite técnicas para reducir el número de dimensiones o cuantificar los vectores para ocupar menos espacio.
Su contexto es más limitado que el de modelos posteriores como bge-m3, pero funcionaba correctamente y durante una etapa fue el modelo principal de mi memoria.
Su orientación, sin embargo, era principalmente inglesa y yo no trabajo solo con documentación en inglés. Buena parte de mis procedimientos, informes, notas y decisiones están escritos en español, aunque también conservo documentación técnica en otros idiomas.
No llegué a la conclusión de que fuera un mal modelo.
Llegué a la conclusión de que quería una opción más claramente multilingüe y con más margen para evolucionar la forma de recuperar información.
Por qué terminé quedándome con bge-m3
Después de probar distintos modelos, terminé quedándome con bge-m3 porque se adapta mejor a la documentación que manejo, funciona con contenido en distintos idiomas y me deja más margen para evolucionar la búsqueda en el futuro.
bge-m3 fue desarrollado por BAAI. El nombre M3 resume tres de sus características principales:
- multilingüe: está preparado para trabajar con más de cien idiomas;
- multifunción: puede utilizar recuperación densa, dispersa y multivector;
- multigranular: puede representar desde frases cortas hasta textos largos.
En la configuración que describo en esta fase utilizo su representación densa de 1.024 dimensiones.
Eso no significa que 1.024 sea automáticamente mejor que 768, ni que un vector más largo produzca siempre mejores resultados.
La calidad depende también del entrenamiento, de los idiomas, de la tarea, de cómo se fragmentan los documentos y de la forma en que se recuperan los resultados.
En esta fase del proyecto, mi búsqueda utiliza únicamente la representación densa de bge-m3. Combinarla con recuperación dispersa para construir una búsqueda híbrida y añadir después una etapa de reranking son posibilidades que quiero explorar, no funciones que deba presentar como ya implantadas.
También puedo ejecutarlo dentro de mi propia infraestructura, sin enviar mi documentación a un servicio externo para generar los vectores.
La colección ya contiene miles de fragmentos y sigue creciendo a medida que incorporo, actualizo o retiro documentación.
La cifra concreta cambia continuamente y no es, por sí sola, una medida de calidad.
Lo importante es comprobar que la cadena completa puede descubrir los archivos, extraer el contenido, fragmentarlo, generar los vectores y registrar el resultado de forma repetible.
Cambiar de modelo obliga a reconstruir la memoria vectorial
Cambiar el modelo que redacta la respuesta no es lo mismo que cambiar el modelo de embeddings.
Si sustituyo el modelo generativo, puedo seguir entregándole los fragmentos recuperados por el mismo índice.
Pero si cambio el modelo de embeddings, normalmente tengo que volver a generar todos los vectores.
Cada modelo organiza el espacio matemático de una forma distinta.
Dos modelos pueden representar el mismo texto con listas de números completamente diferentes, aunque ambos sean capaces de relacionarlo correctamente con una pregunta.
Tampoco deben mezclarse vectores de dimensiones incompatibles dentro de una misma colección.
Por eso documento el modelo activo, su versión, las dimensiones utilizadas y la fecha de indexación.
La memoria no es solo el contenido que guarda.
También es el sistema de coordenadas con el que ese contenido fue representado.
La base vectorial no entiende mis documentos
Una base vectorial almacena y busca vectores de forma eficiente.
No comprende la documentación como lo haría una persona.
Cuando recibe el embedding de una pregunta, calcula qué vectores están más próximos según la métrica configurada, normalmente similitud del coseno en este tipo de búsqueda semántica.
Después devuelve los fragmentos asociados.
Por eso la calidad final depende de varias piezas:
- el texto que se consiguió extraer;
- la forma en la que se dividió;
- el modelo de embeddings;
- los metadatos;
- la estrategia de recuperación;
- el número de fragmentos recuperados;
- y la capacidad del modelo para utilizar correctamente ese contexto.
El modelo generativo es la parte más visible, pero no puede responder bien si el recuperador le entrega fragmentos equivocados.
Muchas veces un problema que parece del modelo de lenguaje es, en realidad, un problema de recuperación.
Cómo trabajo realmente con el RAG
Un RAG no se aprovecha igual que un buscador tradicional.
Las preguntas demasiado vagas suelen producir resultados vagos.
En lugar de preguntar:
¿Qué tengo sobre Docker?
prefiero preguntar:
¿Qué problemas documenté relacionados con redes Docker y cómo los resolví?
O en vez de:
Háblame de backups.
preguntaría:
Localiza los procedimientos en los que se explique cómo validar una restauración y dime de qué documento procede cada uno.
Mi forma de trabajar suele seguir este recorrido:
- plantear una pregunta concreta;
- limitar el ámbito cuando sea posible;
- pedir que identifique las fuentes recuperadas;
- revisar los fragmentos antes de aceptar una conclusión importante;
- hacer preguntas de seguimiento sobre el mismo contexto;
- volver al documento original cuando la decisión lo justifique.
No utilizo el RAG para dejar de leer documentación.
Lo utilizo para llegar antes a la documentación que merece la pena leer.
Lo que más problemas me ha dado no ha sido la inteligencia artificial
Los problemas más incómodos suelen aparecer mucho antes de generar una respuesta.
Archivos con extensiones incorrectas. Documentos corruptos. Copias parciales. Formatos que parecen una cosa y contienen otra. Imágenes sin texto extraíble. Tablas difíciles de interpretar. Versiones duplicadas. Ficheros temporales creados por herramientas de sincronización.
No todos los errores significan que el documento esté mal
Durante una de las ejecuciones, muchos documentos comenzaron a aparecer como fallidos de forma repentina.
La primera interpretación podía ser que todos aquellos archivos estaban dañados. Pero el patrón contaba otra historia: a partir de un punto concreto comenzaron a fallar PDF, documentos Word, hojas de cálculo y otros formatos que antes se habían procesado correctamente.
El problema no estaba en todos esos documentos. El servicio encargado de analizarlos había dejado de responder correctamente.
Esta diferencia es importante:
- un error documental suele afectar a un archivo concreto;
- un error de formato suele repetirse en archivos del mismo tipo;
- un error de infraestructura aparece de forma repentina y puede afectar a formatos distintos.
Por eso no basta con registrar que algo ha fallado. También hay que conservar cuándo ocurrió, qué servicio estaba procesando el documento, qué error técnico se produjo, cuántos fallos consecutivos aparecieron y si el proceso debe detenerse o reintentarse.
Observar el patrón de los errores forma parte también del diseño del sistema.
La aceleración también introduce nuevos modos de fallo
Utilizar una GPU puede acelerar mucho el análisis de documentos complejos, especialmente cuando intervienen modelos de visión, detección de estructura u OCR.
Pero acelerar el proceso no elimina sus riesgos. Introduce otros.
Un trabajo pesado puede fallar dentro del servicio de procesamiento y dejarlo aparentemente disponible, aunque ya no sea capaz de analizar correctamente los siguientes documentos.
Por eso comprobar que un contenedor o un proceso sigue encendido no equivale a comprobar que el servicio está sano.
También hay que vigilar los reinicios, los tiempos de procesamiento, los errores consecutivos, las pérdidas de conexión y la capacidad real del servicio para completar una prueba de salud.
La aceleración mejora el rendimiento, pero también obliga a mejorar la supervisión.
Un proceso de ingesta serio no debería ocultar esos problemas. Debe registrarlos, y por eso mantengo:
- logs de archivos procesados;
- errores de extracción;
- extensiones desconocidas;
- documentos omitidos;
- número de fragmentos generados;
- modelo de embeddings utilizado;
- y resultado final de cada ejecución.
No basta con que el proceso termine.
Necesito saber qué ha conseguido procesar y qué ha dejado fuera.
Un RAG silencioso ante los errores puede dar una falsa sensación de conocimiento completo.
Actualizar sin indexarlo todo cada vez
Cuando la colección crece, volver a procesarlo todo en cada ejecución deja de tener sentido.
El sistema debería poder detectar:
- archivos nuevos;
- archivos modificados;
- archivos eliminados;
- documentos que no han cambiado;
- y fragmentos que deben sustituirse.
Para eso resulta útil conservar huellas o hashes del contenido, fechas de modificación y un inventario de lo ya procesado.
La actualización incremental reduce tiempo y consumo, pero también introduce una responsabilidad: eliminar del índice aquello que ya no existe o ha quedado obsoleto.
Añadir siempre es fácil.
Mantener una memoria limpia exige saber también cuándo olvidar.
Repetir una ejecución no debería significar empezar de cero
Una ingesta fiable debe poder detenerse y continuar.
Si ya se han procesado correctamente cientos de documentos y el servicio se reinicia, no tiene sentido volver a extraerlos todos.
Para evitarlo, registro al menos:
- el hash del archivo de entrada;
- el estado del procesamiento;
- la versión del procesador;
- las rutas de los resultados;
- la fecha de procesamiento;
- y la relación entre el documento original y sus derivados.
Cuando vuelvo a ejecutar el proceso, los documentos que siguen siendo válidos se reutilizan. Solo se procesan los nuevos o modificados, se reintentan los fallidos y se retiran del índice los eliminados u obsoletos.
Esto convierte una ejecución larga en una operación reanudable y evita que un fallo puntual obligue a repetir horas de trabajo.
En una canalización documental, reanudar bien es casi tan importante como procesar bien.
Cómo compruebo si realmente funciona
Que el sistema devuelva una respuesta convincente no demuestra que el RAG funcione bien. Necesito comprobar la recuperación, y para ello utilizo preguntas cuya respuesta ya conozco:
- si recupera el documento esperado;
- si devuelve la sección correcta;
- si las fuentes son suficientemente diversas;
- si aparecen versiones antiguas antes que las vigentes;
- si una consulta formulada con palabras distintas sigue localizando el contenido;
- y si el modelo distingue entre lo documentado y lo que está deduciendo.
Una pequeña colección de preguntas de prueba resulta mucho más útil que confiar en impresiones generales.
Cada vez que cambio el modelo, el tamaño de los fragmentos, la estrategia de recuperación o los filtros, puedo volver a ejecutar esas preguntas y comparar el resultado.
El RAG también necesita pruebas.
Local no significa automáticamente seguro
Una de las razones por las que construí este sistema localmente fue mantener el control sobre mi documentación.
Pero ejecutar el RAG en casa no elimina las responsabilidades de seguridad.
La colección puede contener configuraciones, rutas internas, informes, credenciales olvidadas, datos personales o documentación que no debería aparecer en cualquier respuesta.
Por eso siguen siendo necesarios:
- control de acceso;
- permisos sobre los documentos originales;
- protección de la base vectorial;
- copias de seguridad;
- separación de colecciones sensibles;
- revisión de secretos y saneamiento de datos personales antes de fragmentar e indexar;
- y trazabilidad de las consultas cuando el contexto lo requiera.
Los datos personales deben limpiarse antes de generar los embeddings
Un embedding no debe considerarse una forma de anonimización. Si el texto original ya se utilizó para crear un vector, la información sensible llegó a la base vectorial aunque después se oculte en la respuesta.
Por eso el saneamiento debe ocurrir antes del chunking y antes de generar los embeddings.
En mi diseño separo varias capas:
- originales restringidos que nunca se modifican;
- extracciones temporales;
- derivados saneados;
- fragmentos aprobados;
- y vectores generados únicamente desde esos fragmentos.
Los identificadores directos, como DNI, IBAN, teléfonos o direcciones, pueden eliminarse cuando no son necesarios. Otros elementos, como contratos, casos o personas que deban relacionarse entre varios documentos, pueden sustituirse por identificadores seudónimos estables.
La decisión no consiste únicamente en borrar datos. También consiste en determinar cuánto contexto necesita realmente el sistema para seguir siendo útil.
El texto sensible no debería llegar a la base vectorial si no es necesario.
Y una respuesta generada no debería mostrar información a la que el usuario no tendría acceso en la fuente original.
El RAG hereda la sensibilidad de la documentación que contiene.
Lo que un RAG no arregla
Un RAG no corrige documentación incorrecta.
No sabe por sí solo qué versión está vigente.
No garantiza que los fragmentos recuperados sean suficientes.
No elimina las alucinaciones, ni sustituye una política documental.
No convierte automáticamente años de archivos en conocimiento fiable.
Y tampoco evita que una pregunta mal planteada conduzca a una respuesta poco útil.
Lo que sí puede hacer es reducir muchísimo el tiempo necesario para localizar información relacionada, conectar documentos que utilizan vocabularios diferentes y colocar contexto relevante delante de un modelo de lenguaje.
Es una ayuda para recuperar y razonar.
No una licencia para dejar de verificar.
La arquitectura que estoy construyendo
Todo lo que he explicado hasta ahora habla de criterios, decisiones y experimentos. La implementación práctica es otra historia, bastante más compleja.
Detrás de este artículo hay un sistema real que he ido ajustando mientras aprendía. Inventario documental, deduplicación por contenido, conversión de formatos antiguos, extracción por rutas distintas, saneamiento de datos personales, fragmentación adaptativa, embeddings, una base vectorial, control de acceso y una API de consulta con trazabilidad.
Cada una de esas piezas ha planteado decisiones técnicas, errores y compromisos que merecen una explicación separada.
Este artículo es el primero de una serie en la que voy a documentar la construcción de mi propio RAG personal.
Aquí he querido centrarme en los principios, las decisiones y los conceptos que ayudan a entender qué es realmente un sistema RAG.
En el segundo artículo de la serie explico la primera de esas etapas: construir un inventario documental fiable antes de generar embeddings. A partir de ahí iré documentando la ingesta, el enrutamiento por formatos, el saneamiento de datos personales, la generación de embeddings, la base vectorial, la evaluación y los problemas que han ido apareciendo durante el proyecto.
Mi objetivo no es publicar un tutorial rápido ni enseñar a instalar unas herramientas concretas.
Quiero dejar documentado un proceso de ingeniería real, con sus cambios de diseño, sus errores, las decisiones descartadas y las razones que me llevaron a construir el sistema de la forma en que lo hice.
Puede que dentro de unos años cambien las herramientas, los modelos o incluso la arquitectura. Lo que espero que siga teniendo valor son las decisiones de ingeniería que hay detrás de ellas.
Mi criterio hoy
Después de construir y ajustar mi propio RAG, tengo bastante claro dónde está su valor.
No está en poder decir que tengo inteligencia artificial conectada a mis documentos.
Está en conseguir que años de documentación vuelvan a ser utilizables.
El modelo generativo es importante. El modelo de embeddings también. Pero ninguno de los dos compensa una ingesta deficiente, unos fragmentos sin contexto o una colección llena de versiones contradictorias.
Si hoy tuviera que empezar otra vez, seguiría el mismo orden:
- organizar la documentación;
- decidir qué merece entrar;
- extraer y limpiar con trazabilidad;
- fragmentar conservando el sentido;
- añadir buenos metadatos;
- generar los embeddings;
- probar la recuperación;
- y solo después preocuparme por cómo redacta el modelo.
Un buen RAG no empieza preguntando qué modelo utilizar. Empieza preguntando qué conocimiento merece ser recuperado y cómo voy a saber si he recuperado el correcto.
Mi objetivo no es que el sistema responda a todo.
Es que me ayude a encontrar antes aquello que ya aprendí, documenté y probablemente necesitaré volver a utilizar.
Fuentes técnicas
- Nomic AI — ficha oficial de nomic-embed-text-v1.5
- Mixedbread — ficha oficial de mxbai-embed-large-v1
- Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks — artículo original sobre RAG
- Retrieval-Augmented Generation for Large Language Models: A Survey
- BGE M3-Embedding: Multi-Lingual, Multi-Functionality, Multi-Granularity
- BAAI/bge-m3 — ficha oficial del modelo
- Ollama — documentación oficial sobre embeddings
- Unstructured — documentación sobre fragmentación de documentos
¿Quieres seguir explorando?
Puedes descubrir más artículos, seguir mis publicaciones en LinkedIn o escribirme.