Cambiar tema

Integración LangChain + Ollama: guía completa de desarrollo con LLM local

Easton editorial illustration: MCP integration socket hub

El mes pasado miré la factura de OpenAI: $52,3. Para un desarrollador individual que juega con IA de vez en cuando, duele. Entonces recordé Ollama en local: Llama 3.1 gratis, esperando.

El problema: llamar la API de Ollama a mano es verboso — formato de petición, parseo de respuesta, errores… LangChain unifica Chat, RAG y Agent y permite cambiar modelo en una línea.

Este artículo es la pieza de integración de frameworks de la serie Ollama LLM local: de langchain-ollama a Chat, RAG y Agent. Si ya leíste los primeros capítulos (API, multi-modelo), aquí conectamos todo en un marco de desarrollo.

Paquete langchain-ollama

Antes usaba langchain_community.llms.Ollama. Funcionaba, pero la documentación apuntaba a langchain-ollama — el paquete oficial independiente.

¿Por qué el paquete oficial?

Mejor tipado e IDE más útil. Mantenimiento alineado a LangChain. Los paquetes community pueden quedar obsoletos; el oficial es apuesta a largo plazo — aprendí eso a las malas.

Instalación en una línea:

pip install langchain-ollama

Tres clases principales:

ClaseUsoEscenario típico
ChatOllamaModelo conversacionalChat multi-turn, Q&A
OllamaLLMCompletado de textoGeneración puntual, continuación
OllamaEmbeddingsEmbeddingsRAG, búsqueda semántica

En la práctica, el 90% de casos bastan con ChatOllama: multi-turn y streaming — letra a letra, mucho mejor que un bloque único.

Ejemplo mínimo:

from langchain_ollama import ChatOllama

# Inicializar modelo
llm = ChatOllama(
    model="llama3.1:8b",  # Descargar antes con ollama pull
    temperature=0.7       # Aleatoriedad 0-1
)

# Enviar mensaje
response = llm.invoke("Hola, preséntate brevemente")
print(response.content)

Antes de ejecutar: ollama pull llama3.1:8b. Sin Ollama instalado, vuelve al primer artículo de la serie.

OllamaEmbeddings convierte texto en vectores; RAG lo usa en profundidad. Vista rápida:

from langchain_ollama import OllamaEmbeddings

embeddings = OllamaEmbeddings(model="nomic-embed-text")

# Embedding de una frase
vector = embeddings.embed_query("Texto de prueba")
print(f"Dimensión del vector: {len(vector)}")  # Suele ser 768+

# Lote
vectors = embeddings.embed_documents([
    "Primer texto",
    "Segundo texto"
])

nomic-embed-text es un embedding orientado a recuperación semántica; dimensión alta (768+), mejor que modelos genéricos.

Chat en la práctica: multi-turn y streaming

Una llamada es fácil; el chat real es más rico — el usuario sigue preguntando y el modelo necesita contexto. LangChain usa listas de mensajes.

Multi-turn

Tres tipos:

  • SystemMessage: rol y comportamiento (p. ej. “eres un asistente técnico”)
  • HumanMessage: entrada del usuario
  • AIMessage: respuesta del modelo
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage

llm = ChatOllama(model="llama3.1:8b", temperature=0.7)

messages = [
    SystemMessage(content="Eres un desarrollador que explica conceptos técnicos de forma clara y breve."),
    HumanMessage(content="¿Qué es una REST API?"),
    AIMessage(content="REST API es un estilo de interfaz web que usa métodos HTTP (GET/POST/PUT/DELETE) sobre recursos. En pocas palabras: accedes a datos por URL."),
    HumanMessage(content="¿Y en qué se diferencia GraphQL?")
]

response = llm.invoke(messages)
print(response.content)

El modelo ve el historial y entiende que preguntas por GraphQL vs REST. Sin el AIMessage previo, podría empezar GraphQL desde cero y romper el hilo.

Streaming: respuesta que “cobra vida”

El usuario no mira una pantalla en blanco — el texto aparece poco a poco, como si alguien escribiera. Clave en respuestas largas.

from langchain_ollama import ChatOllama

llm = ChatOllama(model="llama3.1:8b")

print("Respuesta: ", end="", flush=True)
for chunk in llm.stream("Escribe quicksort en Python y explica la idea"):
    print(chunk.content, end="", flush=True)
print()

stream() devuelve un iterador de fragmentos. flush=True evita buffer y muestra al instante.

En pruebas, el streaming se siente más rápido que un bloque único — sobre todo pasado ~100 caracteres. Parece que “piensa”, no que “se colgó”.

RAG en la práctica: base de conocimiento local

RAG (Retrieval-Augmented Generation) es de los usos más prácticos de LLM: recuperas fragmentos relevantes y el modelo responde con ese contexto — así “sabe” lo que no estaba en su entrenamiento.

Desglose del flujo RAG

Cinco pasos:

  1. Cargar documentos — PDF, TXT, Markdown, etc.
  2. Trocear texto — fragmentos manejables para búsqueda
  3. Generar vectores — embedding del texto
  4. Almacenar índice — base vectorial (aquí ChromaDB)
  5. Recuperar y generar — ante una pregunta, recuperar y responder

Código completo que probé y funciona:

from langchain_ollama import ChatOllama, OllamaEmbeddings
from langchain_chroma import Chroma
from langchain_community.document_loaders import PyPDFLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

# === 1. Cargar documentos ===
loader = TextLoader("./my_document.txt")  # Tu ruta
docs = loader.load()

# === 2. Trocear ===
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200
)
splits = text_splitter.split_documents(docs)

# === 3 y 4. Vectores y almacenamiento ===
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma.from_documents(
    documents=splits,
    embedding=embeddings,
    persist_directory="./chroma_db"
)

# === 5. Retriever ===
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})

# === 6. RAG Chain ===
template = """Responde según el contexto. Si no hay información relevante, di claramente que no está en el documento.

Contexto:
{context}

Pregunta: {question}
"""
prompt = ChatPromptTemplate.from_template(template)

llm = ChatOllama(model="llama3.1:8b")

rag_chain = (
    {"context": retriever, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

# === 7. Consulta ===
response = rag_chain.invoke("¿Cuál es el tema principal del documento?")
print(response)

Parece largo, pero el núcleo es rag_chain: LCEL (LangChain Expression Language) encadena retriever, prompt, modelo y parser con |.

Ajustes útiles:

chunk_size: 800 en docs técnicos densos; 1000-1500 en prosa.

k (fragmentos): 3-5 suele bastar; muchos diluyen relevancia, pocos pierden contexto.

persist_directory es obligatorio — sin él, cada reinicio re-embeddea y pierdes tiempo.

La primera vez no puse persistencia: cada cambio de código re-embeddeaba. Con persist_directory, cargas en segundos.

Agent en la práctica: herramientas con JSON

La diferencia clave del Agent: puede llamar herramientas externas.

Si preguntas “¿qué tiempo hace en Madrid?”, un chat normal puede inventar. Un Agent consulta una API de tiempo y responde con datos reales.

El límite del tool calling en Ollama

Con franqueza: Ollama no iguala a OpenAI en tools. GPT identifica cuándo y cómo llamar funciones; Llama 3.1 aún va por detrás.

Solución de LangChain: JSON Agent — el modelo emite JSON estructurado y el framework decide la herramienta. Funciona para tareas básicas, menos fluido que OpenAI nativo.

Herramientas personalizadas

from langchain_ollama import ChatOllama
from langchain_core.tools import tool

@tool
def get_weather(city: str) -> str:
    """Obtiene el tiempo de una ciudad."""
    weather_data = {
        "Madrid": "Soleado, 25°C, buena calidad del aire",
        "Barcelona": "Nublado, 22°C, posible lluvia ligera",
        "Valencia": "Caluroso, 30°C, UV alto"
    }
    return weather_data.get(city, f"Sin datos para {city}")

@tool
def calculate(expression: str) -> str:
    """Ejecuta un cálculo matemático."""
    try:
        result = eval(expression)  # En producción: implementación más segura
        return f"Resultado: {result}"
    except:
        return "Error en la expresión"

@tool
def search_local_docs(query: str) -> str:
    """Busca en la biblioteca local de documentos."""
    return f"Búsqueda de '{query}': 3 registros relacionados"

@tool convierte funciones en herramientas LangChain; el docstring es la descripción que usa el modelo.

Crear JSON Agent:

from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate

llm = ChatOllama(model="llama3.1:8b")
tools = [get_weather, calculate, search_local_docs]

prompt = ChatPromptTemplate.from_messages([
    ("system", "Eres un asistente útil que puede usar herramientas."),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])

agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

response = agent_executor.invoke({
    "input": "Consulta el tiempo en Madrid y calcula 23 + 45"
})

print(response["output"])

verbose=True muestra el razonamiento del Agent — útil para depurar.

Experiencia real:

70-80%
Éxito JSON Agent
Tareas simples OK; combos complejos fallan más a menudo
Source: Datos del autor

En pruebas, ~70-80% de acierto. Tiempo y cálculos simples van bien; varias herramientas a veces fallan — formato de parámetros o herramienta equivocada. Es el patrón habitual del Agent local.

Si necesitas más fiabilidad:

  1. Modelo más fuerte (Qwen 2.5, DeepSeek)
  2. Simplificar flujo y menos herramientas
  3. OpenAI nativo — más costo, mucha más estabilidad

OpenAI vs Ollama: cambiar en una línea

Pregunta frecuente: ¿puedo usar OpenAI y Ollama con el mismo código LangChain? Sí, y es más simple de lo que parece.

Opción 1: cambiar import

Código con OpenAI:

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4", temperature=0.7)
response = llm.invoke("Explica la computación cuántica")

A Ollama, un import:

from langchain_ollama import ChatOllama

llm = ChatOllama(model="llama3.1:8b", temperature=0.7)
response = llm.invoke("Explica la computación cuántica")

Prompts, chains y parsers no cambian. La abstracción de LangChain hace el cambio casi transparente.

Opción 2: API compatible con OpenAI

Ollama puede “fingir” ser OpenAI — sin cambiar import:

from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="llama3.1:8b",
    base_url="http://localhost:11434/v1",
    api_key="ollama"  # Cualquier valor; Ollama no valida
)

response = llm.invoke("Explica la computación cuántica")

Útil si el proyecto ya usa ChatOpenAI y quieres probar local sin reestructurar.

Tabla comparativa

AspectoOpenAI (GPT-4)Ollama (Llama 3.1)
Costo$0.03/1K tokens inputGratis (solo electricidad GPU local)
PrivacidadDatos en la nubeProcesamiento local
ToolsNativo, estableJSON Agent ~70-80%
LatenciaRápida (1-3 s primer token)Depende de GPU (3-10 s)
CapacidadGPT-4 entre los mejoresLlama 3.1 8B sólido, no al nivel GPT-4

Recomendación:

  • Aprendizaje y prototipos: Ollama, ahorro y libertad para experimentar
  • Producción y alta concurrencia: OpenAI, estabilidad y velocidad
  • Datos sensibles: Ollama, datos no salen del equipo
  • Agent complejos: OpenAI, tools más fiables

Lo ideal: ambos — dev con Ollama, prod con OpenAI. El cambio cuesta una línea.

Resumen

Ya tienes el mapa completo de LangChain + Ollama.

Empezamos con langchain-ollama y las tres clases: ChatOllama, OllamaLLM, OllamaEmbeddings. Luego tres escenarios: Chat multi-turn (streaming mejora la UX), RAG (documentos locales → Q&A), Agent (JSON Agent como compromiso actual). Al final, estrategia OpenAI/Ollama — una línea de código, de ~$50/mes a gratis en local.

¿Cuándo Ollama?

Cuando quieres ahorrar, privacidad o aprender sin miedo a la factura.

¿Cuándo OpenAI?

Agent complejos, producción concurrente, exigencia de latencia y estabilidad. El local aún no sustituye del todo la experiencia cloud.

Si aún no lo probaste, empieza por Chat — código mínimo, efecto inmediato. Luego RAG con tus documentos. Agent puede esperar: más trampas y paciencia en depuración.

La serie sigue: multi-modelo, rendimiento y despliegue en producción. Si te interesa, continúa leyendo.

Comenta o abre issue en GitHub. Los ejemplos los ejecuté; si fallan, suele ser modelo sin pull o dependencias — sigue el mensaje de error.

Desarrollo con LangChain + Ollama

De instalación a Chat, RAG y Agent: domina el desarrollo local de apps LLM

⏱️ Estimated time: 60 min

  1. 1

    Step 1: Instalar langchain-ollama

    Ejecuta:

    ```bash
    pip install langchain-ollama
    ```

    Asegúrate de tener Ollama y un modelo descargado (p. ej. `ollama pull llama3.1:8b`).
  2. 2

    Step 2: Crear app Chat

    Inicializa ChatOllama y envía mensajes:

    ```python
    from langchain_ollama import ChatOllama

    llm = ChatOllama(model="llama3.1:8b", temperature=0.7)
    response = llm.invoke("Hola")
    print(response.content)
    ```

    Soporta multi-turn y streaming.
  3. 3

    Step 3: Construir base de conocimiento RAG

    Cinco pasos:

    • Cargar documentos (TextLoader / PyPDFLoader)
    • Trocear texto (RecursiveCharacterTextSplitter)
    • Generar vectores (OllamaEmbeddings)
    • Almacenar índice (ChromaDB)
    • Recuperar y generar (RAG Chain)

    Parámetros clave: chunk_size=1000, k=4, persist_directory obligatorio.
  4. 4

    Step 4: Implementar Agent con herramientas

    Define herramientas y crea JSON Agent:

    ```python
    @tool
    def get_weather(city: str) -> str:
    """Obtiene el tiempo de una ciudad"""
    ...

    agent = create_tool_calling_agent(llm, tools, prompt)
    agent_executor = AgentExecutor(agent=agent, tools=tools)
    ```

    ~70-80% de éxito; tareas complejas mejor con OpenAI.
  5. 5

    Step 5: Alternar OpenAI / Ollama

    Opción 1: cambiar import

    ```python
    from langchain_ollama import ChatOllama # Ollama
    from langchain_openai import ChatOpenAI # OpenAI
    ```

    Opción 2: API compatible OpenAI (sin cambiar import)

    ```python
    llm = ChatOpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama"
    )
    ```

FAQ

¿Qué diferencia hay entre langchain-ollama y langchain_community.llms.Ollama?
langchain-ollama es el paquete oficial independiente, con mejor tipado y mantenimiento alineado a la versión principal. langchain_community.llms.Ollama es comunitario y puede quedar obsoleto. Recomendado: langchain-ollama.
¿ChatOllama u OllamaLLM?
En el 90% de casos basta ChatOllama: multi-turn, streaming e historial. OllamaLLM sirve para generación puntual o continuación de texto.
¿Cómo configurar chunk_size y k en RAG?
chunk_size: 800 para docs técnicos, 1000-1500 para prosa. k (fragmentos recuperados): 3-5; demasiados diluyen relevancia, pocos pierden contexto. Siempre define persist_directory.
¿Por qué el tool calling de Ollama es menos estable que OpenAI?
Los modelos Ollama (incluido Llama 3.1) no tienen function calling nativo; se usa JSON Agent para salida estructurada (~70-80% éxito). OpenAI es más fiable en Agent complejos.
¿Cómo alternar entre OpenAI y Ollama?
Opción 1: cambiar import (ChatOpenAI ↔ ChatOllama). Opción 2: API compatible de Ollama, solo base_url y api_key. Prompts, chains y parsers no cambian.
¿Ollama sirve en producción?
Depende. Aprendizaje, prototipos y datos sensibles: sí. Alta concurrencia, Agent complejos o latencia estricta: OpenAI. Ideal: dev con Ollama, prod con OpenAI.

8 min de lectura · Publicado el: 7 abr 2026 · Actualizado el: 21 ago 2026

Comentarios

Inicia sesión con GitHub para dejar un comentario

Easton BlogEaston Blog