RAG con Ollama: LLM Local, Datos Privados, Cero API Externa
RAG (Retrieval-Augmented Generation) permite que un LLM responda preguntas a partir de tus propios documentos. La mayoría de los tutoriales envían todo a OpenAI o Anthropic. Aquí está cómo hacer lo mismo completamente en local con Ollama.
Por Qué Local?
Tres razones prácticas:
- RGPD: los datos sensibles nunca salen de tu infraestructura
- Coste: cero llamadas API, cero facturación por token
- Offline: funciona sin conexión a internet
La contrapartida: necesitas una máquina suficientemente potente (mínimo 8 GB VRAM para modelos 7B).
Stack
Ollama → servidor LLM local (Llama 3.1, Mistral, Phi-3...)
nomic-embed → modelo de embedding local (vía Ollama)
ChromaDB → vector store en memoria o persistente
Python → pegamento
Pipeline en 4 Pasos
1. Instalar Ollama y los Modelos
# Instalar Ollama (Linux/Mac)
curl -fsSL https://ollama.com/install.sh | sh
# Descargar el LLM y el modelo de embedding
ollama pull llama3.1:8b
ollama pull nomic-embed-text
2. Indexar Documentos
import chromadb
import ollama
def embed(text: str) -> list[float]:
resp = ollama.embeddings(model="nomic-embed-text", prompt=text)
return resp["embedding"]
client = chromadb.Client()
collection = client.create_collection("docs")
documents = [
{"id": "doc1", "text": "La política RGPD de la empresa establece que..."},
{"id": "doc2", "text": "Los datos de clientes se almacenan en..."},
]
for doc in documents:
collection.add(
ids=[doc["id"]],
embeddings=[embed(doc["text"])],
documents=[doc["text"]],
)
3. Retrieval — Encontrar Pasajes Relevantes
def retrieve(query: str, n: int = 3) -> list[str]:
results = collection.query(
query_embeddings=[embed(query)],
n_results=n,
)
return results["documents"][0]
4. Generación con Contexto
def rag(question: str) -> str:
passages = retrieve(question)
context = "\n\n".join(passages)
response = ollama.chat(
model="llama3.1:8b",
messages=[{
"role": "user",
"content": f"""Responde la pregunta usando ÚNICAMENTE el contexto proporcionado.
Si la respuesta no está en el contexto, dilo claramente.
Contexto:
{context}
Pregunta: {question}"""
}]
)
return response["message"]["content"]
Lo Que Cambia vs RAG en la Nube
Embedding local vs cloud: nomic-embed-text es notablemente menos preciso que text-embedding-3-large de OpenAI en corpus complejos. En documentos de dominio específico, la diferencia es real — prueba siempre con tus datos reales antes de elegir.
Latencia: en un MacBook M2 o una máquina Linux con GPU de gama media, espera 2-5 segundos por respuesta 7B. Aceptable para herramientas internas, no para tiempo real.
ChromaDB en producción: usa el modo persistente o reemplaza con pgvector (PostgreSQL) para volúmenes de datos mayores.
# ChromaDB persistente
client = chromadb.PersistentClient(path="/data/chroma")
Casos de Uso Ideales
- Base de conocimiento RRHH interna (contratos, políticas)
- Soporte al cliente sobre documentación propietaria
- Asistente sobre datos médicos o jurídicos
- Cualquier contexto donde los datos no puedan salir de la red interna
Stéphanie Caumont
Product Owner de IA · Saber más