Cómo alimentar una IA local con tus documentos usando un agente RAG (sin pagar un centavo en APIs)
Guía práctica para montar un agente de IA local que lea, indexe y responda preguntas sobre tus propios documentos — todo en tu máquina, sin enviar datos a la nube. Usamos Ollama como motor LLM, ChromaDB como base vectorial y LangChain como orquestador. Con código funcional, requisitos de hardware y errores comunes.
Por Equipo Starbyte
Cómo alimentar una IA local con tus documentos usando un agente RAG
Tu IA local es inteligente — hasta que le preguntas algo sobre tus datos. Entonces inventa, adivina o simplemente dice que no sabe. El problema no es el modelo; es que no tiene acceso a tu información.
La solución se llama RAG (Retrieval-Augmented Generation): en lugar de que el modelo responda solo desde su memoria de entrenamiento, primero busca en tus documentos y luego genera una respuesta fundamentada en datos reales.
En esta guía vamos a montar un sistema completo — desde cero, en tu máquina, sin pagar APIs — que te permita hacerle preguntas a tus PDFs, manuales, contratos o cualquier documento como si tuvieras un asistente experto.
La arquitectura en 30 segundos
El sistema tiene tres piezas:
- Ollama — el motor que ejecuta el LLM (Llama 3, Mistral, Qwen) directamente en tu hardware. Cero costo por token, cero datos enviados a la nube.
- ChromaDB — una base de datos vectorial que almacena tus documentos como embeddings (representaciones numéricas del significado del texto).
- LangChain — el orquestador que conecta todo: recibe tu pregunta, busca los fragmentos relevantes en ChromaDB y se los pasa al LLM para que responda con contexto.
El flujo completo es: Pregunta → Búsqueda vectorial → Contexto relevante → LLM genera respuesta con citas.
Requisitos de hardware
Antes de empezar, verifica que tu equipo pueda correr un LLM local:
| Componente | Mínimo | Recomendado |
|---|---|---|
| RAM | 8 GB | 16 GB+ |
| GPU (VRAM) | No requerida (CPU funciona) | 8 GB+ NVIDIA/Apple Silicon |
| Disco | 10 GB libres | 50 GB+ (múltiples modelos) |
| CPU | 4 cores | 8 cores+ |
| SO | Windows 10+, macOS 12+, Linux | Cualquiera de los tres |
Nota importante: sin GPU, el modelo funciona pero es 5-10x más lento. Un modelo de 8B parámetros en CPU genera ~5-10 tokens/segundo. Con una GPU NVIDIA decente, sube a 30-50+ tokens/segundo.
Paso 1: Instalar Ollama y descargar un modelo
Ollama es como Docker pero para modelos de IA. Un comando descarga, otro ejecuta.
# Instalar Ollama (macOS/Linux)
curl -fsSL https://ollama.com/install.sh | sh
# En Windows, descarga el instalador desde ollama.com
# Verificar instalación
ollama --version
# Descargar Llama 3.1 8B (modelo recomendado para empezar)
ollama pull llama3.1
# Probar que funciona
ollama run llama3.1 "Dime en una frase qué es RAG"
Si quieres un modelo más liviano para equipos con poca RAM:
ollama pull phi3 # 3.8B parámetros, ~3 GB
ollama pull mistral # 7B parámetros, ~4 GB
Para embeddings (la representación vectorial de tus documentos), necesitas un modelo adicional:
ollama pull nomic-embed-text
Paso 2: Preparar el entorno Python
# Crear entorno virtual
python -m venv rag-agent
source rag-agent/bin/activate # Linux/macOS
# rag-agent\Scripts\activate # Windows
# Instalar dependencias
pip install langchain langchain-ollama langchain-chroma
pip install chromadb
pip install pypdf # Para leer PDFs
pip install unstructured # Para otros formatos
Paso 3: Cargar y fragmentar tus documentos
El secreto de un buen RAG está en cómo divides tus documentos. Fragmentos muy grandes pierden precisión; muy pequeños pierden contexto.
from langchain_community.document_loaders import PyPDFLoader
from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Cargar todos los PDFs de una carpeta
loader = DirectoryLoader(
"./mis_documentos/",
glob="**/*.pdf",
loader_cls=PyPDFLoader
)
documentos = loader.load()
print(f"Documentos cargados: {len(documentos)} páginas")
# Fragmentar en chunks con overlap
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000, # ~1000 caracteres por fragmento
chunk_overlap=200, # 200 caracteres de solapamiento
separators=["\n\n", "\n", ". ", " ", ""]
)
chunks = splitter.split_documents(documentos)
print(f"Fragmentos generados: {len(chunks)}")
¿Por qué 1000 caracteres con 200 de overlap? Es el punto de equilibrio para la mayoría de documentos técnicos. El overlap evita que una idea que cruza dos fragmentos se pierda. Si trabajas con documentos legales o contratos, sube a 1500/300.
Paso 4: Crear la base vectorial con ChromaDB
Aquí convertimos los fragmentos de texto en vectores numéricos y los almacenamos para búsqueda semántica.
from langchain_ollama import OllamaEmbeddings
from langchain_chroma import Chroma
# Configurar el modelo de embeddings local
embeddings = OllamaEmbeddings(
model="nomic-embed-text",
base_url="http://localhost:11434"
)
# Crear la base vectorial (se guarda en disco)
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./mi_base_vectorial"
)
print(f"Base vectorial creada con {vectorstore._collection.count()} vectores")
Este paso toma entre 30 segundos y varios minutos dependiendo del volumen de documentos. La base se guarda en disco, así que solo lo ejecutas una vez (o cuando añadas documentos nuevos).
Paso 5: Construir el agente RAG
Aquí es donde todo se conecta. El agente recibe tu pregunta, busca en la base vectorial, y le pasa el contexto al LLM para que responda.
from langchain_ollama import ChatOllama
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
# Configurar el LLM local
llm = ChatOllama(
model="llama3.1",
temperature=0.2, # Bajo para respuestas más precisas
base_url="http://localhost:11434"
)
# Configurar el retriever
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 4} # Recuperar los 4 fragmentos más relevantes
)
# Prompt personalizado en español
template = """Usa los siguientes fragmentos de contexto para responder
la pregunta del usuario. Si no encuentras la respuesta en el contexto,
di claramente que no tienes esa información.
Contexto:
{context}
Pregunta: {question}
Respuesta (en español, citando las fuentes cuando sea posible):"""
prompt = PromptTemplate(
template=template,
input_variables=["context", "question"]
)
# Crear la cadena RAG
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
chain_type_kwargs={"prompt": prompt},
return_source_documents=True
)
# ¡Preguntar!
resultado = qa_chain.invoke({"query": "¿Cuáles son los ejes estratégicos?"})
print("RESPUESTA:")
print(resultado["result"])
print("\nFUENTES:")
for doc in resultado["source_documents"]:
print(f" - {doc.metadata.get('source', 'Desconocido')} (pág. {doc.metadata.get('page', '?')})")
Paso 6: Hacerlo interactivo
Para convertirlo en un asistente con el que puedas conversar:
def asistente():
print("=" * 50)
print("ASISTENTE RAG LOCAL")
print("Escribe 'salir' para terminar")
print("=" * 50)
while True:
pregunta = input("\nTú: ").strip()
if pregunta.lower() in ["salir", "exit", "quit"]:
print("¡Hasta luego!")
break
if not pregunta:
continue
print("\nBuscando en documentos...")
resultado = qa_chain.invoke({"query": pregunta})
print(f"\nAsistente: {resultado['result']}")
print(f"\n📄 Fuentes consultadas: {len(resultado['source_documents'])}")
asistente()
Errores comunes y cómo resolverlos
"Connection refused" al conectar con Ollama
Ollama no está corriendo. Ejecuta ollama serve en otra terminal antes de lanzar tu script Python. Verifica que responde en http://localhost:11434.
Respuestas inventadas o que no coinciden con los documentos
Baja la temperatura del modelo a 0.1. Aumenta el número de chunks recuperados (k=6 o k=8). Revisa que tus PDFs no sean imágenes escaneadas sin OCR.
Proceso muy lento sin GPU
Usa un modelo más pequeño (phi3 en lugar de llama3.1). Reduce el chunk_size a 500. Considera que la primera carga del modelo toma más tiempo.
ChromaDB lanza errores de dimensiones
Asegúrate de usar el mismo modelo de embeddings para indexar y para consultar. Si cambias de modelo, borra la carpeta mi_base_vectorial/ y regenera.
¿Cuándo usar esto vs. una API en la nube?
Usa un agente RAG local cuando:
- Tus documentos contienen información sensible (contratos, datos médicos, financieros)
- Necesitas iterar rápido sin preocuparte por costos de tokens
- Trabajas offline o en redes restringidas
- Quieres control total sobre el modelo y los datos
Usa una API en la nube cuando:
- Necesitas la mejor calidad de respuesta posible (GPT-4o, Claude Opus)
- Procesas volúmenes masivos que requieren infraestructura escalable
- El tiempo de setup importa más que la privacidad
Idea clave
Un agente RAG local no reemplaza a ChatGPT o Claude — pero hace algo que ellos no pueden: trabajar con tus documentos privados sin que salgan de tu máquina. Con Ollama, ChromaDB y LangChain, montar este sistema toma menos de una hora y cuesta exactamente cero. Lo único que necesitas es un equipo con RAM suficiente y documentos que valga la pena consultar.
La IA más útil no es la más grande — es la que conoce tu contexto.