Inteligencia Artificial / Procesamiento de Documentos 11 min lectura

Chat privado con tus PDFs y documentos usando LlamaIndex y Ollama: sistema RAG local paso a paso

Convierte tu carpeta de documentos en un asistente personal al que puedas preguntar en lenguaje natural, sin subir ni un solo archivo a la nube. Aprende a montar un pipeline RAG completo con LlamaIndex, embeddings locales y Ollama: indexación, recuperación semántica y generación de respuestas con fuentes. Todo gratuito, privado y ejecutándose en tu propio ordenador.

Por Equipo Starbyte

Chat privado con tus PDFs y documentos usando LlamaIndex y Ollama: sistema RAG local paso a paso

Chat privado con tus PDFs y documentos usando LlamaIndex y Ollama: sistema RAG local paso a paso

Problema real: Tienes cientos de documentos —manuales técnicos, papers académicos, informes de empresa, apuntes personales— y encontrar una información concreta te obliga a abrir cada archivo, hacer Ctrl+F y leer párrafos irrelevantes. Podrías subirlos a un servicio de IA en la nube, pero estarías regalando datos sensibles a terceros y además pagando por consulta. La alternativa es un sistema RAG (Retrieval-Augmented Generation) 100 % local: indexas tus documentos una sola vez y después preguntas en lenguaje natural, obteniendo respuestas precisas con citas al documento fuente, sin perder la privacidad.

Este post te guía paso a paso para construir ese sistema con LlamaIndex como framework de indexación y recuperación, Ollama como servidor de modelos de lenguaje y modelos de embedding gratuitos que se ejecutan en tu GPU. Al terminar tendrás un asistente de conocimiento privado al que preguntar como si hablaras con un experto que se ha leído todos tus archivos.


Requisitos previos

  • Python 3.10 o superior.
  • Ollama instalado y con al menos un modelo de lenguaje descargado (ej. qwen3.5:latest o llama3.1:8b). También necesitarás un modelo de embedding accesible desde Ollama (por ejemplo, nomic-embed-text o all-minilm).
  • Suficiente espacio en disco para los embeddings indexados (aprox. 1 GB por cada 10 000 páginas de texto).
  • Opcional: GPU con al menos 6 GB de VRAM para acelerar la generación de embeddings y la inferencia del LLM (con CPU funcionará, pero será más lento).
  • Documentos en formatos comunes: PDF, TXT, DOCX, CSV, Markdown o HTML.

1. ¿Qué es RAG y por qué vas a notar la diferencia?

Los modelos de lenguaje como Qwen 3.5 o Llama 3.1 tienen un conocimiento general excelente, pero sufren tres limitaciones graves cuando trabajas con documentos propios:

  1. Alucinaciones: si le preguntas por un dato que no está en su entrenamiento, puede inventarse una respuesta convincente pero falsa.
  2. Conocimiento estático: no sabe nada de los documentos que has escrito este año.
  3. Ventana de contexto limitada: no puedes volcar 500 páginas en un prompt sin gastar una barbaridad de tokens y perder precisión.

RAG resuelve los tres problemas separando el proceso en dos fases:

  • Indexación: trocea los documentos en fragmentos pequeños, los convierte en vectores numéricos (embeddings) y los almacena en una base de datos vectorial.
  • Consulta: cuando preguntas algo, busca los fragmentos más parecidos semánticamente a tu pregunta, los inyecta en el prompt del LLM y le pide que genere una respuesta basada solo en esos fragmentos, citando las fuentes.

El resultado: respuestas factuales, sin alucinaciones y con referencias explícitas a tus documentos.


2. Instalación y configuración del entorno

Crea un entorno virtual y activa las dependencias necesarias:

# Crear el entorno
python -m venv rag_env
# Activarlo (Windows)
rag_env\Scripts\activate
# Activarlo (macOS/Linux)
source rag_env/bin/activate

# Instalar LlamaIndex con conectores para Ollama
pip install llama-index llama-index-llms-ollama llama-index-embeddings-ollama

# Herramientas de lectura de documentos
pip install pypdf python-docx sentence-transformers chromadb

Verifica la instalación:

python -c "import llama_index; print(llama_index.__version__)"

3. Obtener los modelos necesarios en Ollama

Vas a necesitar dos tipos de modelos:

  • LLM para generación de respuestas: usaremos qwen3.5:latest (8B) o cualquier otro que tengas. Si tienes poca VRAM, puedes usar llama3.2:3b.
  • Modelo de embedding para convertir texto a vectores: en Ollama puedes usar nomic-embed-text:v1.5 (137M parámetros, ligero) o all-minilm (33M). Ambos son gratuitos y funcionan en CPU sin problemas.

Descárgalos desde la terminal:

ollama pull qwen3.5:latest
ollama pull nomic-embed-text:v1.5

Verifica que ambos aparezcan en la lista:

ollama list

4. Construcción del pipeline RAG completo

Crea un archivo rag_local.py y añade el siguiente código. Lo explicaremos bloque a bloque.

4.1 Importaciones y configuración de modelos

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.llms.ollama import Ollama
from llama_index.embeddings.ollama import OllamaEmbedding
from llama_index.core.node_parser import SentenceSplitter
import chromadb
from llama_index.vector_stores.chroma import ChromaVectorStore
import os

# Configuración global de LlamaIndex
Settings.llm = Ollama(
    model="qwen3.5:latest",
    temperature=0.2,
    context_window=4096,
    request_timeout=120.0
)

Settings.embed_model = OllamaEmbedding(
    model_name="nomic-embed-text:v1.5",
)

Settings.text_splitter = SentenceSplitter(
    chunk_size=1024,
    chunk_overlap=80
)

Explicación breve:

  • Settings.llm define qué modelo generará las respuestas.
  • Settings.embed_model asigna el modelo que transforma texto en vectores.
  • SentenceSplitter trocea los documentos en fragmentos de ~1024 tokens, con un solapamiento de 80 tokens para que no se pierda contexto entre fragmentos consecutivos.

4.2 Indexar los documentos

Crea una carpeta data en el mismo directorio y coloca dentro todos los PDFs, TXT o DOCX que quieras indexar.

# Cargar documentos
documentos = SimpleDirectoryReader("data").load_data()
print(f"Documentos cargados: {len(documentos)}")

# Crear la base de datos vectorial en ChromaDB
chroma_client = chromadb.PersistentClient(path="./chroma_db")
coleccion = chroma_client.get_or_create_collection("mis_documentos")
vector_store = ChromaVectorStore(chroma_collection=coleccion)

# Crear el índice
indice = VectorStoreIndex.from_documents(
    documentos,
    vector_store=vector_store,
    show_progress=True
)
print("Indexación completada.")

Tras ejecutar este bloque (puede tardar varios minutos según el número de páginas), tendrás tu base de conocimiento vectorizada en la carpeta chroma_db.

4.3 Consultar el índice

# Crear el motor de consulta
motor = indice.as_query_engine(similarity_top_k=3, streaming=False)

# Preguntar en bucle
while True:
    pregunta = input("\nPregunta (o 'salir'): ")
    if pregunta.lower() == "salir":
        break
    respuesta = motor.query(pregunta)
    print("\nRespuesta:", respuesta)
    print("\nFuentes:")
    for i, nodo in enumerate(respuesta.source_nodes, 1):
        print(f"  [{i}] {nodo.metadata.get('file_name', '?')} — relevancia: {nodo.score:.3f}")

similarity_top_k=3 indica que recuperará los 3 fragmentos más similares a tu pregunta. Puedes subirlo a 5-6 si necesitas más contexto, pero aumentará el consumo de tokens.


5. Ejecución completa del sistema

Guarda el archivo rag_local.py y ejecútalo:

python rag_local.py

La primera ejecución indexará los documentos (solo necesita hacerlo una vez; las siguientes cargarán el índice desde disco). Después verás el prompt interactivo donde puedes preguntar.

Ejemplo de consulta:

Pregunta (o 'salir'): ¿Cuál es la política de devolución para productos electrónicos?

Respuesta: Según el documento "política_devoluciones_2026.pdf", los productos electrónicos
pueden devolverse en un plazo de 30 días naturales desde la compra, siempre que estén en su
embalaje original y con todos los accesorios. No se aceptan devoluciones de software
desprecintado.

Fuentes:
  [1] política_devoluciones_2026.pdf — relevancia: 0.912
  [2] condiciones_generales.pdf — relevancia: 0.834
  [3] preguntas_frecuentes.pdf — relevancia: 0.789

6. Configuraciones avanzadas para mejorar la precisión

6.1 Aumentar el tamaño del fragmento (chunk)

Si tus documentos tienen párrafos largos o información muy dependiente del contexto, sube el chunk_size a 1536 o 2048 y ajusta el chunk_overlap a 150-200.

Settings.text_splitter = SentenceSplitter(chunk_size=1536, chunk_overlap=200)

6.2 Usar un LLM más potente

Con una GPU de 12 GB de VRAM o más, puedes cargar qwen3.5:14b o llama3.1:70b (si tienes suficiente RAM y CPU para respaldar la GPU) para obtener respuestas más elaboradas. Solo cambia la línea:

Settings.llm = Ollama(model="qwen3.5:14b", temperature=0.2, request_timeout=180.0)

6.3 Búsqueda híbrida (semántica + palabras clave)

Para documentos técnicos con mucha jerga, combina recuperación vectorial con búsqueda léxica (BM25). LlamaIndex lo permite con pocos cambios:

from llama_index.core.retrievers import VectorIndexRetriever, BM25Retriever
from llama_index.core.retrievers import RouterRetriever

retriever_semantico = VectorIndexRetriever(index=indice, similarity_top_k=3)
retriever_bm25 = BM25Retriever.from_defaults(nodes=indice.docstore.docs.values(), similarity_top_k=3)

retriever_combinado = RouterRetriever.from_defaults(
    retriever_tools=[retriever_semantico, retriever_bm25],
    select_multi=True
)
motor = indice.as_query_engine(retriever=retriever_combinado)

Esto elige automáticamente la mejor estrategia para cada consulta y fusiona resultados.


7. Errores frecuentes y soluciones

Error Causa Solución
ModuleNotFoundError Falta alguna dependencia Reinstala con pip install llama-index llama-index-llms-ollama llama-index-embeddings-ollama chromadb pypdf.
ConnectionError al conectar con Ollama El servicio no está corriendo o el puerto está ocupado Ejecuta ollama serve en una terminal antes de lanzar el script.
CUDA out of memory La GPU se queda sin VRAM al generar embeddings o al contestar Usa nomic-embed-text:v1.5 (CPU) para embeddings y libera VRAM para el LLM. Cierra otras aplicaciones que usen GPU.
Respuestas genéricas o alucinaciones similarity_top_k demasiado bajo, no recupera la información necesaria Aumenta a 5-8. Ajusta el chunk_size para capturar más contexto.
KeyError: 'file_name' al mostrar fuentes Algunos documentos no tienen metadatos de nombre de archivo Usa nodo.metadata.get('file_name', 'documento sin nombre') como fallback.
Indexación extremadamente lenta (horas) Documentos con muchas imágenes o mal escaneados Convierte los PDFs a texto con pdftotext antes de indexar. Elimina páginas en blanco o imágenes no textuales.
OllamaEmbedding no encuentra el modelo Nombre incorrecto del modelo de embedding En Ollama, el nombre exacto es sensible a mayúsculas. Usa ollama list y copia el nombre tal cual aparece.

8. Casos prácticos de uso

8.1 Asistente legal privado

Indexa todos los contratos, términos y condiciones y legislación relevante de tu empresa. Después, cualquier empleado puede preguntar: "¿Puedo compartir este dato con un tercero bajo la cláusula 4.2 del contrato de confidencialidad?" y obtener una respuesta fundamentada con la cita exacta del documento.

8.2 Investigador académico con memoria perfecta

Carga 300 papers de arXiv sobre un campo de investigación. El sistema te responde preguntas como "¿Qué métodos superaron el estado del arte en segmentación de imágenes médicas en 2025?" con referencias a los artículos concretos y los porcentajes de mejora.

8.3 Manual de empleado interactivo

Vuelcas el manual de recursos humanos, las políticas de teletrabajo y los procedimientos de IT en la carpeta data. Los nuevos empleados preguntan en lugar de buscar entre 200 páginas. La respuesta incluye siempre la sección del documento fuente para que puedan verificarlo.

8.4 Centro de conocimiento técnico

Mantenimiento de una wiki interna con procedimientos de despliegue, resolución de incidencias y configuraciones de servidores. Un agente de guardia pregunta: "¿Cómo se reinicia el servicio X sin afectar a los usuarios conectados?" y obtiene el procedimiento exacto.


9. Buenas prácticas

  • Limpia los documentos antes de indexarlos. Quita pies de página repetitivos, números de página y marcas de agua que añaden ruido a los embeddings.
  • Organiza la carpeta data por categorías (subcarpetas legal/, finanzas/, tecnicos/). LlamaIndex conserva los metadatos de la ruta, lo que permite filtrar consultas después por categoría.
  • Reindexa solo cuando cambien los documentos. La indexación es costosa; si añades un archivo nuevo, no reindexes todo. Usa indice.insert(documento_nuevo) para añadirlo incrementalmente.
  • Ajusta la temperatura del LLM a 0.2 o 0.1. En RAG no quieres creatividad, quieres precisión. Una temperatura baja reduce drásticamente las alucinaciones.
  • Verifica las fuentes. Las respuestas deben incluir siempre los nodos fuente. Si una respuesta no cita fuentes, desconfía; puede estar inventando.
  • Actualiza los modelos de embedding periódicamente. Cada pocos meses aparecen versiones mejoradas. Cambiar de nomic-embed-text:v1.5 a una v2 puede aumentar la relevancia de las búsquedas sin cambiar nada más.
  • Ejecuta el sistema en una máquina dedicada si es para producción. Un servidor con GPU mediana y 32 GB de RAM puede servir a varios usuarios simultáneamente usando una API REST que expongas con FastAPI.

10. Cierre con idea clave

Tener una IA que conoce tus documentos es como contratar a un empleado que jamás olvida nada y responde en segundos. Montar un sistema RAG local con LlamaIndex y Ollama te da el control absoluto sobre tus datos sin depender de servicios externos, con la tranquilidad de que nada sale de tu máquina. En menos de 100 líneas de código has pasado de buscar a ciegas a conversar con tu propia base de conocimiento.

Etiquetas: #rag #llamaindex #ollama #embeddings #documentos #open-source