Intermedio 20 minPython

Crear un agente de IA local en Python con LangChain y Ollama

Un agente de IA local en Python con LangChain y Ollama no es solo un chatbot: es un programa que decide por sí mismo cuándo llamar a una función, leer un archivo o encadenar varios pasos para responder. Esta guía construye paso a paso un agente funcional en unos veinte minutos, con un modelo Qwen 3.5 9B que se ejecuta íntegramente en tu máquina. Ninguna clave API, ningún dato enviado a terceros.

Por Mohamed Meguedmi·Actualización 2026-08-27·Probado en Windows, macOS y Linux

#¿Por qué un agente de IA local en Python?

Un agente, en el sentido de LangChain, es un bucle simple: el LLM recibe una pregunta y la lista de sus herramientas, elige llamar a una (o ninguna), lee el resultado y vuelve a empezar hasta poder responder. Todo el mecanismo de "decisión" reside en la capacidad del modelo para emitir una llamada estructurada a una herramienta.

Hacerlo en local, con Ollama, cambia dos cosas concretas: tus datos nunca salen de la máquina y cada llamada cuesta cero euros. Es la diferencia entre crear un prototipo con OpenAI y acabar la semana con una factura de 50 €, e iterar sin preocuparte por el coste.

Confidencialidad
Los archivos que lee el agente (contratos, código propietario, notas médicas) no salen del equipo. No hay ningún DPA que firmar ni transferencias fuera de la UE.
Coste marginal nulo
Una vez descargado el modelo, puedes iterar cientos de veces al día sin que la factura suba.
Reproducibilidad
Fijas la versión exacta del modelo (qwen3.5:9b, granite4.2:8b, etc.). No hay cambios silenciosos como con gpt-4o-2024-11-20, que se convierte en otra cosa un mes después.
Latencia previsible
Sin viajes de ida y vuelta por la red. Con una GPU adecuada, el primer token llega en menos de un segundo.
i
Tampoco es magia
Un 9B local sigue siendo menos potente que un GPT-5 o Claude 4.7 en tareas muy complejas. Para el 80 % de los agentes útiles (leer un archivo, llamar a una API interna, realizar un cálculo, clasificar un correo), es completamente suficiente. Para el resto, es un excelente entorno de aprendizaje antes de pagar por tokens.

#Prerrequisitos

El kit Copiloto Local

Esta guía te lleva al modelo. El kit te lleva al copiloto que programa en tu editor.

  • Espacio en línea de por vida
  • PDF + archivos
  • Reembolsado 30 j
Python 3.10+
LangChain ya no se prueba en 3.9. Compruébalo con python --version.
Ollama instalado y arrancado
Debe escuchar en http://localhost:11434. Ver las guías de instalación de Ollama (Windows, macOS, Linux) si todavía no lo has hecho.
Un modelo que sabe llamar a herramientas
No todos los LLM saben llamar a herramientas. Qwen 3.5, Granite 4.2, Gemma 4, Devstral y GLM 4.7 Flash admiten de forma nativa las llamadas a herramientas. Evita los modelos ya obsoletos (Llama 2/3, Qwen 2.5, Mistral 7B).
Hardware
Qwen 3.5 9B Q4 pesa aproximadamente 6,6 GB en VRAM. Una GPU de 8 GB (RTX 3060, 4060) es suficiente; una de 12 GB (4070) ofrece margen. En Mac, cuenta con 16 GB de memoria unificada para tener margen.
→
La elección del modelo es crítica
Con un modelo que no sabe llamar a herramientas correctamente, tu agente inventará argumentos o responderá en texto libre en lugar de generar una llamada a una herramienta. Si estás empezando, sigue con qwen3.5:9b: es el punto óptimo entre calidad y VRAM en 2026.

#1. Inicializar el proyecto Python

Un entorno virtual, tres paquetes y eso es todo. Evitamos instalar LangChain en el Python del sistema: cambia rápido y contamina el entorno.

Crear y activar el venv
mkdir agent-local && cd agent-local
python -m venv .venv

# macOS / Linux
source .venv/bin/activate

# Windows PowerShell
# .venv\Scripts\Activate.ps1
Instalar las dependencias
pip install --upgrade pip
pip install langchain langchain-ollama langgraph
langchain
El corazón: abstracciones de prompts, herramientas, mensajes.
langchain-ollama
La integración oficial de Ollama. Mantenida por el equipo de LangChain desde 2024.
langgraph
Para el bucle del agente. Es el motor recomendado hoy, más estable que los antiguos AgentExecutor.
i
¿Por qué langgraph en lugar de AgentExecutor?
Los tutoriales antiguos de LangChain usan AgentExecutor + create_react_agent (de langchain.agents). Esta API está en modo de mantenimiento. La documentación oficial ahora remite a langgraph.prebuilt.create_react_agent: es lo que usaremos aquí. Más sencillo, con un tipado mejor y streaming gratuito.

#2. Conectar Ollama desde Python

Antes de montar un agente, comprobamos que realmente nos comunicamos con el modelo. Descarga el modelo si todavía no lo has hecho y luego prueba la llamada más sencilla posible.

Descargar Qwen 3.5 9B
ollama pull qwen3.5:9b

La descarga asciende a aproximadamente 6,6 GB en Q4_K_M (la cuantización por defecto en Ollama). Una vez instalado, crea el primer script:

test_ollama.py
from langchain_ollama import ChatOllama

llm = ChatOllama(
    model="qwen3.5:9b",
    temperature=0,
    # base_url="http://localhost:11434",  # par défaut, à changer si Ollama est ailleurs
)

reponse = llm.invoke("En une phrase : qu'est-ce qu'un agent IA ?")
print(reponse.content)
Iniciar el test
python test_ollama.py

Si ves una frase coherente, la conexión Python ↔ Ollama funciona. Si obtienes un ConnectionError, revisa que Ollama esté funcionando (ollama ps debe listar un servicio activo).

→
temperature=0 para los agentes
Buscamos un comportamiento determinista cuando el modelo elige una herramienta. Una temperatura alta hace que las llamadas a herramientas varíen de una ejecución a otra: depurarlas es un infierno. Para las respuestas creativas, sube la temperatura a 0.7 más adelante.

#3. Definir las herramientas del agente

Una herramienta de LangChain es simplemente una función Python decorada con @tool. El docstring se convierte en la descripción que ve el LLM — él la utiliza para decidir cuándo llamarla. Sé preciso: un docstring vago produce llamadas aleatorias.

Vamos a crear dos herramientas representativas: un evaluador de expresiones aritméticas y un lector de archivos.

tools.py
from pathlib import Path
from langchain_core.tools import tool


@tool
def calculer(expression: str) -> str:
    """Évalue une expression arithmétique simple.

    Args:
        expression: une expression contenant uniquement des chiffres,
                    des espaces et les opérateurs + - * / ( ).

    Returns:
        Le résultat numérique sous forme de chaîne, ou un message d'erreur.
    """
    autorise = set("0123456789+-*/(). ")
    if not all(c in autorise for c in expression):
        return "Erreur : caractère non autorisé. Seuls 0-9 et + - * / ( ) sont permis."
    try:
        resultat = eval(expression, {"__builtins__": {}}, {})
        return str(resultat)
    except Exception as e:
        return f"Erreur de calcul : {e}"


@tool
def lire_fichier(chemin: str) -> str:
    """Lit le contenu d'un fichier texte du répertoire courant.

    Args:
        chemin: chemin relatif ou absolu vers un fichier texte (.txt, .md, .py, etc.).

    Returns:
        Le contenu du fichier, ou un message d'erreur si introuvable.
    """
    p = Path(chemin)
    if not p.exists():
        return f"Fichier introuvable : {chemin}"
    if not p.is_file():
        return f"Ce n'est pas un fichier : {chemin}"
    try:
        return p.read_text(encoding="utf-8")
    except UnicodeDecodeError:
        return "Fichier binaire ou encodage non UTF-8."
    except Exception as e:
        return f"Erreur de lecture : {e}"
!
eval() es peligroso en producción
El uso de eval(), incluso con __builtins__ vacío, no es una verdadera sandbox. Para un agente que corre en tu equipo y que tú controlas, es aceptable. Para cualquier cosa expuesta a usuarios externos, utiliza ast.parse con una whitelist de operadores, o la biblioteca simpleeval.

Tres reglas para que el modelo use correctamente las herramientas:

Nombre explícito
calculer en lugar de process, lire_fichier en lugar de get. El LLM elige primero basándose en el nombre.
Docstring detallado
Describe qué hace la herramienta, qué espera y qué devuelve. LangChain lee las anotaciones de tipo de Python y las expone al modelo.
Devolver una cadena
Siempre. Si la función devuelve un dict o un objeto, LangChain lo serializa, pero el resultado es menos legible para el modelo.

#4. Armar el agente

Tenemos un LLM, tenemos herramientas. La función create_react_agent de langgraph conecta los dos y gestiona el ciclo: mientras el modelo quiera llamar a herramientas, continuamos; cuando responda en texto, paramos.

agent.py
from langchain_ollama import ChatOllama
from langgraph.prebuilt import create_react_agent
from tools import calculer, lire_fichier

llm = ChatOllama(model="qwen3.5:9b", temperature=0)

SYSTEM_PROMPT = (
    "Tu es un assistant en français. Tu disposes d'outils pour calculer "
    "et lire des fichiers. Utilise-les dès que c'est pertinent, sans jamais "
    "inventer un résultat. Réponds toujours en français."
)

agent = create_react_agent(
    model=llm,
    tools=[calculer, lire_fichier],
    prompt=SYSTEM_PROMPT,
)

if __name__ == "__main__":
    question = (
        "Combien fait 1234 * 5678 ? "
        "Ensuite, lis le fichier notes.txt et résume-le en deux phrases."
    )
    reponse = agent.invoke({"messages": [("user", question)]})

    # Le dernier message est la réponse finale du modèle
    print(reponse["messages"][-1].content)

Crea un pequeño archivo notes.txt al lado para probar:

Archivo de prueba
echo "Réunion projet Hermes : on garde Ollama comme runtime principal, on évalue vLLM pour la prod, RAG sur ChromaDB. Décision : POC en 2 semaines." > notes.txt

#5. Ejecutar y observar el bucle

Iniciar el agente
python agent.py

Deberías ver una respuesta que contenga tanto el resultado del cálculo (7 006 652) como un resumen del archivo. Pero es más instructivo ver lo que sucede durante la ejecución. Añade este modo detallado para seguir el bucle paso a paso:

Modo de streaming detallado
for evenement in agent.stream(
    {"messages": [("user", question)]},
    stream_mode="values",
):
    dernier = evenement["messages"][-1]
    dernier.pretty_print()
    print("---")

Vas a observar la secuencia típica de un agente: el modelo genera una llamada a calculer, recibe el resultado, genera una llamada a lire_fichier, recibe el contenido y luego genera la respuesta final. Tres iteraciones para una sola pregunta del usuario.

i
Si el modelo no llama a las herramientas
Dos causas frecuentes: (1) el modelo no tiene activadas las llamadas a herramientas en Ollama — vuelve a ejecutar ollama pull qwen3.5:9b para obtener la última versión. (2) El prompt del sistema es demasiado vago. Especifica explícitamente "usa las herramientas para los cálculos" en lugar de esperar que lo adivine.

#Consejos y solución de problemas

Contexto demasiado corto
Por defecto, Ollama trunca a 2048 tokens. Si tu agente encadena varias herramientas, ese límite se supera rápidamente. Usa num_ctx=8192 en ChatOllama(model="...", num_ctx=8192).
Modelo que inventa herramientas
Si el agente inventa nombres de funciones, reduce la temperatura a 0 y reformula el prompt del sistema enumerando explícitamente las herramientas disponibles.
Bucle infinito
Establece un límite: create_react_agent(..., recursion_limit=10). Al superarlo, el agente se detiene correctamente.
Latencia demasiado alta
En CPU, un 9B alcanza 5-10 tok/s. Pasa a qwen3.5:4b (3,4 GB de VRAM, 30+ tok/s en una GPU modesta) si la calidad sigue siendo aceptable para tu caso.
Error "context length exceeded"
El resumen de un archivo largo supera num_ctx. Añade una herramienta intermedia que divida el archivo en fragmentos o aumenta num_ctx hasta 32768 si tu VRAM lo permite.
→
Rastrear tus agentes con LangSmith
Para depurar seriamente, LangSmith registra cada llamada, cada token, cada herramienta. Es gratuito en desarrollo. Establece LANGSMITH_TRACING=true y LANGSMITH_API_KEY en tu entorno, y obtienes una línea de tiempo completa. Ningún dato se envía si no defines la clave.

#Para ir más allá

Tienes un agente que calcula, lee y razona en local. Tres vías naturales para seguir profundizando:

Darle acceso a tus documentos
Conectar el agente a una base vectorial para que pueda responder sobre un corpus interno: es exactamente el tema de la guía de introducción al RAG local.
Usar la CLI como entorno habitual para programar
Aider es un agente de desarrollo que edita directamente tus archivos desde el terminal. Puedes conectarlo al mismo Ollama y aprovechar Qwen3-Coder 30B o Devstral para la edición asistida.
Ajustar la cuantización del modelo
Si Qwen 3.5 9B Q4 te parece demasiado lento o demasiado justo en calidad, la guía de cuantización explica cuándo pasar a Q5_K_M o reducir el tamaño del modelo.
¿Esta guía te ha ayudado?

¿Un comentario, un error, una precisión? Avísanos, eso mejora la guía para todos.