Intermédiaire 20 minPython

Créer un agent IA local en Python avec LangChain et Ollama

Un agent IA local en Python avec LangChain et Ollama, ce n'est pas juste un chatbot : c'est un programme qui décide tout seul quand appeler une fonction, lire un fichier ou enchaîner plusieurs étapes pour répondre. Ce guide construit pas à pas un agent fonctionnel en une vingtaine de minutes, avec un modèle Qwen 3 14B qui tourne intégralement sur votre machine. Zéro clé API, zéro donnée envoyée à un tiers.

Par Mohamed Meguedmi·Màj 2026-05-12·Testé sur Windows, macOS, Linux

#Pourquoi un agent IA local en Python ?

Un agent, dans le sens LangChain, c'est une boucle simple : le LLM reçoit une question et la liste de ses outils, il choisit d'en appeler un (ou pas), lit le résultat, et recommence jusqu'à pouvoir répondre. Toute la mécanique de "décision" tient dans la capacité du modèle à émettre un tool call structuré.

Faire ça en local, avec Ollama, change deux choses concrètes : vos données ne sortent jamais de la machine, et chaque appel coûte zéro euro. C'est la différence entre prototyper avec OpenAI à 50 € de facture en fin de semaine, et itérer sans compter.

Confidentialité
Les fichiers que l'agent lit (contrats, code propriétaire, notes médicales) ne quittent pas le poste. Pas de DPA à signer, pas de transfert hors UE.
Coût marginal nul
Une fois le modèle téléchargé, vous pouvez itérer des centaines de fois par jour sans facture qui grimpe.
Reproductibilité
Vous figez la version exacte du modèle (qwen3:14b, mistral:7b-instruct-v0.3, etc.). Pas de drift silencieux comme avec gpt-4o-2024-11-20 qui devient autre chose un mois plus tard.
Latence prévisible
Pas d'aller-retour réseau. Sur un GPU correct, le premier token tombe en moins d'une seconde.
i
Ce n'est pas magique non plus
Un 14B local reste plus faible qu'un GPT-5 ou Claude 4.7 sur des tâches très complexes. Pour 80 % des agents utiles (lire un fichier, appeler une API interne, faire un calcul, classer un mail), c'est largement suffisant. Pour le reste, c'est un excellent terrain d'apprentissage avant de payer du token.

#Prérequis

Python 3.10+
LangChain n'est plus testé sur 3.9. Vérifiez avec python --version.
Ollama installé et démarré
Il doit écouter sur http://localhost:11434. Voir les guides d'installation Ollama (Windows, macOS, Linux) si ce n'est pas fait.
Un modèle qui sait appeler des outils
Tous les LLM ne savent pas. Qwen 3 (14B et +), Llama 3.1, Mistral 7B Instruct v0.3 et Granite 3 supportent nativement le tool calling. Évitez les vieux modèles type Llama 2.
Matériel
Qwen 3 14B Q4 pèse environ 9 Go en VRAM. Un GPU 12 Go (RTX 3060, 4070) suffit. Sur Mac, comptez 16 Go de mémoire unifiée pour respirer.
Le choix du modèle est critique
Avec un modèle qui ne sait pas appeler d'outils proprement, votre agent va halluciner des arguments ou répondre en texte libre au lieu de produire un tool call. Si vous débutez, restez sur qwen3:14b — c'est le sweet spot qualité / VRAM en 2026.

#1. Initialiser le projet Python

Un environnement virtuel, trois paquets, et c'est tout. On évite d'installer LangChain dans le Python système — ça change vite et ça pollue.

Créer et activer le venv
mkdir agent-local && cd agent-local
python -m venv .venv

# macOS / Linux
source .venv/bin/activate

# Windows PowerShell
# .venv\Scripts\Activate.ps1
Installer les dépendances
pip install --upgrade pip
pip install langchain langchain-ollama langgraph
langchain
Le cœur : abstractions de prompts, outils, messages.
langchain-ollama
L'intégration officielle Ollama. Maintenue par la team LangChain depuis 2024.
langgraph
Pour la boucle d'agent. C'est le moteur recommandé aujourd'hui, plus stable que les anciens AgentExecutor.
i
Pourquoi langgraph plutôt qu'AgentExecutor ?
Les vieux tutos LangChain utilisent AgentExecutor + create_react_agent (depuis langchain.agents). Cette API est en mode maintenance. La doc officielle pointe désormais vers langgraph.prebuilt.create_react_agent — c'est ce qu'on utilisera ici. Plus simple, mieux typé, streaming gratuit.

#2. Connecter Ollama depuis Python

Avant de monter un agent, on vérifie qu'on parle bien au modèle. Téléchargez le modèle si ce n'est pas déjà fait, puis testez l'appel le plus simple possible.

Télécharger Qwen 3 14B
ollama pull qwen3:14b

Le téléchargement fait environ 9 Go en Q4_K_M (la quantization par défaut chez Ollama). Une fois en place, créez le premier script :

test_ollama.py
from langchain_ollama import ChatOllama

llm = ChatOllama(
    model="qwen3:14b",
    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)
Lancer le test
python test_ollama.py

Si vous voyez une phrase cohérente, la liaison Python ↔ Ollama fonctionne. Si vous obtenez une ConnectionError, vérifiez qu'Ollama tourne bien (ollama ps doit lister un service actif).

temperature=0 pour les agents
On veut un comportement déterministe quand le modèle choisit un outil. Une température élevée fait varier les appels d'outils d'une exécution à l'autre — c'est l'enfer à déboguer. Pour les réponses créatives, remontez à 0.7 plus tard.

#3. Définir les outils de l'agent

Un outil LangChain est juste une fonction Python décorée avec @tool. Le docstring devient la description que voit le LLM — il l'utilise pour choisir quand l'appeler. Soyez précis : un docstring vague produit des appels aléatoires.

On va créer deux outils représentatifs : un évaluateur d'expressions arithmétiques, et un lecteur de fichiers.

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() est dangereux en production
L'utilisation d'eval(), même avec __builtins__ vidé, n'est pas une vraie sandbox. Pour un agent qui tourne sur votre poste et que vous contrôlez, c'est acceptable. Pour quoi que ce soit exposé à des utilisateurs tiers, utilisez ast.parse avec une whitelist d'opérateurs, ou la bibliothèque simpleeval.

Trois règles pour des outils que le modèle utilise correctement :

Nom explicite
calculer plutôt que process, lire_fichier plutôt que get. Le LLM choisit d'abord sur le nom.
Docstring détaillé
Décrivez ce que fait l'outil, ce qu'il attend, ce qu'il renvoie. Les annotations de type Python sont lues par LangChain et exposées au modèle.
Renvoyer une string
Toujours. Si la fonction renvoie un dict ou un objet, LangChain le sérialise, mais vous perdez en lisibilité côté modèle.

#4. Assembler l'agent

On a un LLM, on a des outils. La fonction create_react_agent de langgraph cable les deux et gère la boucle : tant que le modèle veut appeler des outils, on continue ; quand il répond en texte, on s'arrête.

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

llm = ChatOllama(model="qwen3:14b", 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)

Créez un petit fichier notes.txt à côté pour tester :

Fichier de test
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. Exécuter et observer la boucle

Lancer l'agent
python agent.py

Vous devriez voir une réponse qui contient à la fois le résultat du calcul (7 006 652) et un résumé du fichier. Mais c'est plus instructif de voir ce qui se passe pendant l'exécution. Ajoutez ce mode verbeux pour suivre la boucle pas à pas :

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

Vous allez observer la séquence typique d'un agent : le modèle produit un appel à calculer, reçoit le résultat, produit un appel à lire_fichier, reçoit le contenu, puis génère la réponse finale. Trois itérations pour une seule question utilisateur.

i
Si le modèle n'appelle pas les outils
Deux causes fréquentes : (1) le modèle n'a pas le tool calling activé côté Ollama — ressortez ollama pull qwen3:14b pour avoir la dernière version. (2) Le prompt système est trop vague. Précisez explicitement "utilise les outils pour les calculs" plutôt que d'espérer qu'il devine.

#Astuces et dépannage

Contexte trop court
Par défaut, Ollama tronque à 2048 tokens. Si votre agent enchaîne plusieurs outils, ça déborde vite. Passez num_ctx=8192 dans ChatOllama(model="...", num_ctx=8192).
Modèle qui hallucine des outils
Si l'agent invente des noms de fonctions, baissez la température à 0 et reformulez le system prompt en listant explicitement les outils disponibles.
Boucle infinie
Mettez une limite : create_react_agent(..., recursion_limit=10). Au-delà, l'agent s'arrête proprement.
Latence trop élevée
Sur CPU, un 14B fait 5-10 tok/s. Passez à qwen3:8b (5 Go VRAM, 30+ tok/s sur GPU modeste) si la qualité reste acceptable pour votre cas.
Erreur "context length exceeded"
Le résumé d'un long fichier dépasse num_ctx. Ajoutez un outil intermédiaire qui chunke le fichier, ou augmentez num_ctx jusqu'à 32768 si votre VRAM suit.
Tracer ses agents avec LangSmith
Pour déboguer sérieusement, LangSmith trace chaque appel, chaque token, chaque outil. C'est gratuit en dev. Posez LANGSMITH_TRACING=true et LANGSMITH_API_KEY dans votre environnement, et vous avez une timeline complète. Aucune donnée n'est envoyée si vous ne définissez pas la clé.

#Pour aller plus loin

Vous avez un agent qui calcule, lit, raisonne, en local. Trois directions naturelles pour creuser :

Lui donner accès à vos documents
Coupler l'agent à une base vectorielle pour qu'il puisse répondre sur un corpus interne — c'est exactement le sujet du guide d'introduction au RAG local.
Vivre en CLI pour le code
Aider est un agent dev qui édite directement vos fichiers depuis le terminal. Vous pouvez le brancher sur le même Ollama et profiter de Qwen Coder ou DeepSeek pour de l'édition assistée.
Ajuster la quantization du modèle
Si vous trouvez Qwen 3 14B Q4 trop lent ou trop limite en qualité, le guide quantification explique quand passer à Q5_K_M ou descendre en taille de modèle.
Ce guide vous a aidé ?

Un retour, une erreur, une précision ? Faites-nous signe, ça améliore le guide pour tout le monde.