RAG - Retrieval Augmented Generation
Generación Aumentada por Recuperación
Ejemplo práctico RAG – Parte 1: crear documentos e indexarlos
Una vez preparado el entorno, el siguiente paso es construir
un primer sistema RAG funcional, empezando por lo más importante:
los documentos y la búsqueda semántica.
En esta primera parte no generaremos respuestas con un modelo de lenguaje.
El objetivo es entender cómo:
- Se cargan documentos
- Se convierten en embeddings
- Se almacenan en una base vectorial
- Se recuperan por similitud
El proyecto utilizado es hello-world-rag.
1. Crear una carpeta para los documentos
Dentro del proyecto, creamos una carpeta llamada:
docs
La estructura del proyecto queda así:
hello-world-rag │ ├── docs │ ├── facturacion.txt │ └── clientes.txt │ ├── venv └── main.py
2. Crear documentos de ejemplo
Para el ejemplo, se crean dos documentos muy simples.
docs/facturacion.txt
La facturación permite generar facturas a clientes. Una factura debe tener cliente, fecha y líneas de servicio. Si el cliente no tiene NIF, la factura no se puede emitir.
docs/clientes.txt
Los clientes deben tener nombre y NIF. El NIF es obligatorio para poder facturar. Un cliente puede tener varios centros de coste.
Estos textos simulan documentación típica de un software de gestión.
3. Primer script: cargar e indexar documentos
Editamos el archivo main.py y añadimos el siguiente código:
import chromadb
from chromadb.utils import embedding_functions
import os
# Crear cliente de Chroma (base vectorial local)
client = chromadb.Client()
# Usamos una función de embeddings simple (por ahora)
embedding_function = embedding_functions.DefaultEmbeddingFunction()
# Crear o recuperar una colección
collection = client.get_or_create_collection(
name="documentacion",
embedding_function=embedding_function
)
# Cargar documentos desde la carpeta docs
docs_path = "docs"
documents = []
metadatas = []
ids = []
for i, filename in enumerate(os.listdir(docs_path)):
with open(os.path.join(docs_path, filename), "r", encoding="utf-8") as f:
documents.append(f.read())
metadatas.append({"archivo": filename})
ids.append(f"doc_{i}")
# Añadir documentos a la base vectorial
collection.add(
documents=documents,
metadatas=metadatas,
ids=ids
)
print("Documentos indexados correctamente")
4. Ejecutar el script
Desde la terminal, con el entorno virtual activo:
python main.py
Si todo funciona correctamente, el resultado será:
Documentos indexados correctamente
En este punto, los textos ya están convertidos en embeddings
y almacenados en la base vectorial.
5. Probar una búsqueda semántica
Ahora modificamos main.py para hacer una consulta:
# Consulta de ejemplo
query = "¿Es obligatorio el NIF para facturar?"
results = collection.query(
query_texts=[query],
n_results=2
)
print("Pregunta:", query)
print("Resultados:")
for doc, meta in zip(results["documents"][0], results["metadatas"][0]):
print("-", meta["archivo"])
print(doc)
Al ejecutar de nuevo:
python main.py
Se obtiene como resultado el texto más relevante,
aunque la pregunta no coincida literalmente con el documento.
Qué está pasando realmente aquí
- Los textos se convierten en números (embeddings)
- La pregunta también se convierte en números
- Chroma compara similitud, no palabras exactas
- Se devuelven los documentos más cercanos semánticamente
Esto es el corazón de cualquier sistema RAG.
Limitaciones de esta primera parte
Este ejemplo:
- No genera una respuesta redactada
- No usa todavía un modelo de lenguaje
- No aplica filtros por permisos o roles
Y eso es intencionado.
Antes de pedirle a la IA que responda, hay que asegurarse
de que el sistema recupera bien la información.
En la siguiente parte se añadirá el modelo de lenguaje
para generar respuestas a partir de los documentos recuperados.
