Crear RAG con Ollama
Qué aborda este artículo
- Qué es RAG y cómo funciona.
- Qué componentes necesita un sistema RAG local.
- Cómo dividir documentos en fragmentos.
- Cómo trabajan juntos los embeddings y las bases de datos vectoriales.
- Un ejemplo práctico en Python con Ollama y ChromaDB.
Introducción: Crear RAG con Ollama
Retrieval-Augmented Generation, o RAG, amplía los modelos de lenguaje con conocimiento externo. En lugar de confiar únicamente en el conocimiento almacenado en el modelo, se buscan secciones de documentos relevantes en tiempo de ejecución desde una base de datos de conocimiento y se insertan en el prompt. De esta forma, el modelo responde con más precisión, proporciona información más actualizada y puede acceder a tus propios documentos. Ollama es ideal para RAG porque tanto los modelos de lenguaje como los modelos de embedding pueden ejecutarse localmente.
Este artículo muestra cómo crear un sistema RAG simple con Ollama, un modelo de embedding y una base de datos vectorial.
Términos clave
- RAG: Retrieval-Augmented Generation.
- Embedding: Representación vectorial de un texto.
- Base de datos vectorial: Almacenamiento de embeddings con búsqueda de similitud.
- Chunk: Pequeño fragmento de texto de un documento.
- Retriever: Componente que encuentra chunks relevantes.
- Contexto: Chunks recopilados que se envían al modelo de lenguaje.
- Prompt: Consulta que incluye contexto y pregunta.
- Similitud de coseno: Medida de la proximidad entre dos vectores.
Arquitectura de un sistema RAG local
Un sistema RAG típico consta de cuatro partes:
- Cargar documentos: Leer PDF, texto, Markdown o páginas web.
- Chunking: Dividir documentos en fragmentos superpuestos.
- Generar embeddings: Convertir cada chunk en un vector.
- Almacenar y buscar: Guardar vectores en una base de datos y consultarlos.
- Generar respuesta: Enviar chunks relevantes como contexto a Ollama.
Cargar documentos
Con Python y langchain o código simple:
from pathlib import Path
doc_path = Path("dokumente/handbuch.md")
text = doc_path.read_text(encoding="utf-8")
Para PDF, pymupdf o pdfplumber funcionan bien.
Chunking
Los documentos se dividen en fragmentos de longitud fija con sobreposición:
def chunk_text(text, chunk_size=500, overlap=50):
chunks = []
for i in range(0, len(text), chunk_size - overlap):
chunks.append(text[i:i + chunk_size])
return chunks
chunks = chunk_text(text)
Valores típicos:
- Tamaño del chunk: 300 a 1000 caracteres.
- Sobreposición: 10 a 20 por ciento.
El chunking semántico, por ejemplo dividiendo por párrafos o encabezados, suele ser mejor que contar solo caracteres.
Generar embeddings
import requests
import json
def embed(texts, model="nomic-embed-text"):
url = "http://localhost:11434/api/embed"
payload = {"model": model, "input": texts}
resp = requests.post(url, json=payload)
return resp.json()["embeddings"]
vectors = embed(chunks)
Configurar la base de datos vectorial
ChromaDB puede ejecutarse localmente:
pip install chromadb
import chromadb
client = chromadb.Client()
collection = client.create_collection(name="wissen")
for i, (chunk, vector) in enumerate(zip(chunks, vectors)):
collection.add(
ids=[str(i)],
embeddings=[vector],
documents=[chunk]
)
Búsqueda
question = "¿Cómo se restablece la contraseña?"
question_vector = embed([question])[0]
results = collection.query(
query_embeddings=[question_vector],
n_results=3
)
context = "\n\n".join(results["documents"][0])
Generar la respuesta
import requests
url = "http://localhost:11434/api/chat"
payload = {
"model": "llama3.1",
"messages": [
{"role": "system", "content": "Responde la pregunta únicamente basándote en el contexto proporcionado."},
{"role": "user", "content": f"Contexto:\n{context}\n\nPregunta: {question}"}
],
"stream": False
}
resp = requests.post(url, json=payload)
print(resp.json()["message"]["content"])
Prompt del sistema para RAG
El prompt del sistema debe indicar que el modelo responda solo desde el contexto:
Respondes preguntas únicamente basándote en el contexto proporcionado.
Si la respuesta no está en el contexto, indica honestamente que no hay información disponible.
Bases de datos vectoriales alternativas
| Base de datos | Característica |
|---|---|
| ChromaDB | Simple, buena para prototipos. |
| Qdrant | Rápida, escalable, REST API. |
| Weaviate | Agnóstica del modelo, fuerte en empresa. |
| pgvector | Extensión de PostgreSQL. |
| FAISS | Biblioteca de Meta, muy rápida. |
Consejos para un buen RAG
- Preprocesar documentos adecuadamente.
- Elegir tamaños de chunk sensatos.
- Considerar chunking semántico.
- Usar un modelo de embedding apropiado.
- Ajustar el número de chunks devueltos.
- Revisar respuestas en busca de alucinaciones.
- Probar e iterar preguntas y respuestas.
Obstáculos típicos
- Chunks demasiado grandes: Demasiada información irrelevante en el contexto.
- Chunks demasiado pequeños: Se pierden las conexiones.
- Modelo de embedding incorrecto: Idioma o dominio no coinciden.
- Documentos sin limpiar: Encabezados, pies de página o HTML interfieren.
- Demasiados chunks en el contexto: El modelo excede su longitud de contexto.
- Sin citar fuentes: Los usuarios no pueden verificar las respuestas.
- Alucinaciones: El modelo inventa respuestas a pesar del contexto.
Extensiones
- Re-ranking: Encontrar muchos chunks rápidamente, luego ordenar los mejores.
- Búsqueda híbrida: Combinación de búsqueda por palabras clave y vectores.
- Metadatos: Filtrar por fecha, fuente o categoría.
- LangChain / LlamaIndex: Frameworks que simplifican cadenas de RAG.
- Open WebUI: Ofrece funciones de RAG integradas para Ollama.
Enlaces y recursos adicionales
- BotServ.de Ollama Embeddings
- BotServ.de Ollama REST API
- BotServ.de Ollama Befehle
- BotServ.de RAG Wissensdatenbank
- BotServ.de Vektordatenbanken
FAQ: RAG con Ollama
¿Necesito una GPU para RAG? Se recomienda, pero no es obligatorio. Los embeddings y la inferencia son mucho más rápidos con GPU.
¿Qué modelo de embedding es adecuado?
nomic-embed-text es una buena opción general, mxbai-embed-large es mejor para multiidioma.
¿Puedo usar PDF? Sí, después de extraer texto y hacer chunking.
¿Cuál debería ser el tamaño de los chunks? 300 a 1000 caracteres, depende del documento y la pregunta.
¿Es Open WebUI adecuado para RAG? Sí, ofrece una función de RAG integrada con carga de documentos.
Fuentes y lectura adicional
- LangChain RAG: https://python.langchain.com/docs/use_cases/question_answering/
- LlamaIndex: https://www.llamaindex.ai/
- ChromaDB: https://www.trychroma.com/
- Ollama RAG Tutorial: https://github.com/ollama/ollama/blob/main/docs/
Resumen: Crear RAG con Ollama
RAG amplía Ollama con tus propios documentos y conocimiento actualizado. La arquitectura incluye carga, chunking, embedding, base de datos vectorial y generación de respuestas. Con ChromaDB, Python y Ollama puedes crear un sistema RAG funcional rápidamente. Lo importante es limpiar documentos adecuadamente, elegir tamaños de chunk sensatos, usar un modelo de embedding apropiado y escribir un buen prompt del sistema. Quien pruebe e itere RAG de forma sistemática mejora la calidad de respuestas de manera precisa y respetando la privacidad.


