DevGuide

Agent IA local avec Ollama + Qwen 2.5

Sur cette page
  1. Pourquoi l'IA locale en 2026
  2. Installer Ollama (Windows, Linux, macOS)
  3. Choisir le bon modèle Qwen 2.5 pour ta VRAM
  4. Les bases de l'HTTP API d'Ollama
  5. Appeler le modèle depuis Python
  6. Intégration LangChain pour les agents
  7. Exemple complet : assistant de réponse aux mails
  8. Réglages de performance et benchmarks
  9. Sources et pour aller plus loin

Tu veux construire un agent IA local qui ne téléphone jamais à la maison ? Je fais tourner mes agents sur mes propres machines maintenant, plus comme une expérience de labo, juste comme un truc qui marche. Ollama cache toute la galère du runtime, et Qwen 2.5 s'est rapproché assez de GPT-4 sur le code et le raisonnement, à des tailles qui rentrent vraiment sur un GPU grand public, pour que la seule facture qui reste soit le compteur électrique. Voici le truc complet, dans l'ordre où je m'y prendrais : installer Ollama, choisir la taille de Qwen que ta VRAM digère, l'attaquer depuis Python, faire entrer LangChain, et finir sur un vrai assistant de réponse aux mails en 80 lignes.

The short answer

Installe Ollama (un seul binaire), télécharge une taille de Qwen 2.5 qui rentre dans ta VRAM, puis attaque http://localhost:11434/api/chat depuis Python ou LangChain. Rien ne quitte la machine. Le gain, c'est la confidentialité, une latence quasi nulle, et une facture d'électricité plate au lieu d'un coût par token.

qwen2.5:14bmeilleur qualité / coût
11434port API local
80 lignesagent mail fonctionnel
Carte réponse montrant un agent IA local construit avec Ollama et Qwen 2.5, avec zéro donnée envoyée vers le cloud.
Toute la stack sur une seule machine : ton script, Ollama sur le 11434, Qwen qui réfléchit. PNG

Je fais tourner mes agents sur mes propres machines maintenant. Plus comme une expérience de labo, juste comme un truc qui marche. Ollama cache toute la galère du runtime, et Qwen 2.5 s'est rapproché assez de GPT-4 sur le code et le raisonnement, à des tailles qui rentrent vraiment sur un GPU grand public, pour que la seule facture qui reste soit le compteur électrique. Ça, plus l'après-midi que tu vas y laisser pour le coller dans ta stack. Bref. Voici le truc complet, dans l'ordre où je m'y prendrais. Installer Ollama sur Windows, Linux ou macOS, puis choisir la taille de Qwen que ta VRAM peut digérer, l'attaquer depuis Python via l'HTTP API, faire entrer LangChain dès que le workflow arrête d'être un seul appel, et finir sur un vrai assistant de réponse aux mails en 80 lignes. J'ai lancé chaque commande ici en mai 2026 contre Ollama 0.6 et la série Qwen 2.5. Si quelque chose ne colle pas, c'est sans doute juste que ça a bougé depuis.

Pourquoi l'IA locale en 2026

Qu'est-ce qui me ramène sans cesse à faire tourner ça moi-même ? Commence par la confidentialité. Les données clients, les prompts, les docs internes, les dépôts de code, rien de tout ça ne quitte les murs pour le cloud de quelqu'un d'autre. Si tu es dans la santé, la finance ou le juridique, ou si tu touches juste à des données personnelles à un volume sérieux, cette seule propriété, c'est tout le oui-ou-non. L'argent, c'est l'autre moitié. Une fois que tu t'appuies vraiment sur ces modèles, le seuil de rentabilité face aux API payantes tombe quelque part autour de 5 millions de tokens par mois, et passé cette ligne le matériel que tu as déjà amorti face à la facture d'électricité gagne tout simplement. Ensuite la latence, qu'on oublie toujours. Un 7B sur un GPU à peu près récent crache le premier token en 50-80 ms. Aucune API cloud ne s'en approche, peu importe l'épaisseur de ton tuyau.

Le hic (il y en a toujours un), c'est la qualité. Un 7B ou un 14B sur ton bureau, ce n'est pas GPT-5 turbo, et ce n'est pas Claude Opus 4.7. Ne te raconte pas d'histoires là-dessus. Quand la tâche est vraiment dure, démêler un argument juridique, un refactor de code bien tordu, je dégaine encore une API flagship et je ne perds pas le sommeil pour autant. Mais la classification. L'extraction. Le résumé, les éternels brouillons de mails routiniers, les boucles d'agent du quotidien ? Qwen 2.5 14B tient la route. J'ai vu des gens incapables de le distinguer des gros modèles cloud dans une comparaison à l'aveugle, et honnêtement ça te dit l'essentiel.

Installer Ollama (Windows, Linux, macOS)

Le meilleur dans Ollama ? Un seul binaire. Il embarque le runtime, l'endroit où tes modèles vivent sur le disque, plus un petit serveur REST sur le port 11434. Tout ça, regroupé. Quel que soit ton OS, l'installeur a fini en moins d'une minute.

macOS et Linux

curl -fsSL https://ollama.com/install.sh | sh
ollama --version  # confirm install

Windows (PowerShell)

Récupère l'installeur sur ollama.com/download, lance-le une fois, puis vérifie que c'est bien en place depuis PowerShell :

ollama --version
# Should print: ollama version is 0.6.x

Il se met en place comme service en arrière-plan et revient tout seul à chaque redémarrage, donc tu peux à peu près l'oublier. Tâte l'API pour t'assurer qu'il est bien réveillé :

curl http://localhost:11434/api/tags
# Returns JSON with the list of locally installed models (empty at first)

Note pare-feu. Par défaut Ollama écoute sur 127.0.0.1:11434, en loopback uniquement, donc rien d'extérieur à la machine ne peut l'atteindre. C'est le réglage sûr. Laisse-le là sauf si tu as une raison. Tu veux que d'autres machines du LAN lui parlent ? Mets OLLAMA_HOST=0.0.0.0:11434, mais dans la foulée écris une règle de pare-feu qui ne laisse entrer que ton sous-réseau LAN. Ne saute pas cette étape. S'il te plaît.

Choisir le bon modèle Qwen 2.5 pour ta VRAM

Qwen 2.5 existe en une poignée de tailles que tu utiliserais vraiment pour de bon. Mets le tableau en favori. Il te donne la VRAM minimale au quant standard Q4_K_M (celui qu'Ollama choisit pour toi) et l'ordre de grandeur des tokens par seconde sur une carte grand public récente. La dernière colonne, c'est à quoi chaque palier sert honnêtement. Un truc à bien comprendre : la VRAM est le mur sur lequel tu tapes en premier ici, pas le calcul. Lis cette colonne avant de craquer pour un chiffre.

ModèleVRAM minDébitCas idéal
qwen2.5:0.5b1.5 GB~150 tok/sAppareils edge, autocomplétion, classification
qwen2.5:1.5b2.5 GB~120 tok/sChat léger, extraction, sur laptops CPU-only
qwen2.5:3b4 GB~90 tok/sRésumé, usage simple d'outils, RAG
qwen2.5:7b6 GB~70 tok/sAgent polyvalent, complétion de code
qwen2.5:14b10 GB~45 tok/sRaisonnement complexe, agents multi-étapes (meilleur rapport qualité / coût sur RTX 3060 12GB et plus)
qwen2.5:32b22 GB~22 tok/sQualité quasi-flagship, exige une RTX 3090 / 4090 / 5090 ou un Apple M3 Max+
qwen2.5:72b48 GB~12 tok/sQualité haut de gamme, demande un double GPU ou une seule A6000 / H100

Télécharge celui sur lequel tu t'es arrêté. Téléchargement unique, et il atterrit dans ~/.ollama/models pour de bon :

ollama pull qwen2.5:7b       # general purpose default
ollama pull qwen2.5:14b      # better reasoning if VRAM allows
ollama pull qwen2.5-coder:7b # code-specialised variant

Avant d'écrire une seule ligne de code contre lui, parle-lui d'abord dans le terminal. Juste pour être sûr qu'il a toute sa tête :

ollama run qwen2.5:7b
>>> Write a Python function that fetches a URL and returns the JSON.
# Streams a complete answer with code.

Les bases de l'HTTP API d'Ollama

Tu ne toucheras vraiment qu'à trois endpoints. /api/chat est le plus récent. Il parle le format de messages d'OpenAI, et c'est celui que je prends par défaut à chaque fois. Ensuite /api/generate, le vieux style raw-prompt, encore dans les parages, rarement ce que tu veux vraiment. Et /api/embeddings te rend des vecteurs quand tu montes une pipeline RAG.

# Chat (recommended)
curl http://localhost:11434/api/chat -d '{
  "model": "qwen2.5:7b",
  "messages": [
    {"role": "system", "content": "You are a concise coding assistant."},
    {"role": "user", "content": "Explain async/await in Python in one paragraph."}
  ],
  "stream": false
}'

En retour vient un seul objet JSON, avec le texte du modèle posé dans message.content. Bascule plutôt stream: true et tu obtiens un token par ligne, délimité par des sauts de ligne. Même forme que ce qu'OpenAI envoie en streaming, donc ce que tu as écrit pour eux marche à peu près tel quel.

La plupart des réglages du schéma OpenAI Chat Completions passent direct, soit au niveau racine, soit nichés sous options. Tu as temperature, top_p, seed, puis num_ctx pour la fenêtre de contexte, num_predict pour plafonner les tokens en sortie, et stop pour les séquences qui coupent la génération net. Le tool calling est là depuis Ollama 0.5. Passe un tableau tools de la façon dont la doc de l'endpoint chat l'expose.

Appeler le modèle depuis Python

Bien sûr, tu peux lui parler avec un seul appel requests. Mais à la seconde où tu construis un agent tu auras dépassé ça avant midi. Fais-toi plaisir, démarre sur le client officiel.

# pip install ollama

import ollama

client = ollama.Client(host="http://localhost:11434")

response = client.chat(
    model="qwen2.5:7b",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Summarise the benefits of local AI in 3 bullets."}
    ],
    options={"temperature": 0.3, "num_ctx": 8192}
)

print(response.message.content)

Ce paquet ollama gère tout ce que tu vas chercher. Le streaming, avec client.chat(..., stream=True) qui te livre des morceaux token par token. Les embeddings via client.embeddings. Le tool calling aussi. Et il ne traîne rien au-delà de requests, ce qui est exactement pourquoi il reste mon défaut pour les scripts et ces petits services que personne ne prend jamais vraiment le temps de réécrire.

Intégration LangChain pour les agents

Dès qu'il te faut plus d'un tour (chaînes, RAG, routage vers des outils, garder de la mémoire), LangChain et son binding Ollama t'évitent de réinventer un tas de plomberie que tu raterais de toute façon. Tire les deux paquets :

pip install langchain langchain-community langchain-ollama

Le plus petit truc qui fait quelque chose d'utile ressemble à ça. Qwen derrière un prompt template, un parser boulonné au bout :

from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOllama(model="qwen2.5:14b", temperature=0.2)

prompt = ChatPromptTemplate.from_messages([
    ("system", "Translate the user's message into French."),
    ("user", "{text}")
])

chain = prompt | llm | StrOutputParser()
print(chain.invoke({"text": "Hello, how are you today?"}))

Tu veux que le truc appelle vraiment des outils ? Lâche ce même ChatOllama dans le constructeur d'agent classique de LangChain et c'est parti. La boucle, le lancement des outils, le maintien de la mémoire entre les tours, toute la plomberie de prompts, le framework porte tout ça pour toi. Ce qui est la grande raison pour laquelle tu t'embêterais avec lui en premier lieu.

Exemple complet : assistant de réponse aux mails

Voici un truc que tu lancerais vraiment. 80 lignes qui tirent tes 10 derniers messages non lus via IMAP, font écrire à Qwen 2.5 14B une réponse qui a clairement lu le mail, puis déposent chacune dans les Brouillons pour qu'un humain y jette un œil avant que quoi que ce soit ne parte. Mets tes propres identifiants. Et pour l'amour du ciel, pointe-le vers une boîte de test jetable pour le premier coup. J'ai lâché un script de mail bancal sur une vraie boîte une fois. Une seule fois.

import imaplib
import email
from email.message import EmailMessage
import ollama

IMAP_HOST = "imap.example.com"
IMAP_USER = "you@example.com"
IMAP_PASS = "app-specific-password"

SYSTEM_PROMPT = """You are a professional assistant drafting replies on
behalf of the user. Reply in the same language as the incoming email.
Be concise (3-6 sentences). Use a friendly but professional tone.
End with a signature line: 'Best regards,\\nThe Assistant (draft)'.
Never send the reply - it will be reviewed before sending."""

def get_unread_emails(limit=10):
    m = imaplib.IMAP4_SSL(IMAP_HOST)
    m.login(IMAP_USER, IMAP_PASS)
    m.select("INBOX")
    _, data = m.search(None, "UNSEEN")
    ids = data[0].split()[:limit]
    messages = []
    for i in ids:
        _, raw = m.fetch(i, "(RFC822)")
        msg = email.message_from_bytes(raw[0][1])
        body = ""
        if msg.is_multipart():
            for part in msg.walk():
                if part.get_content_type() == "text/plain":
                    body = part.get_payload(decode=True).decode(errors="ignore")
                    break
        else:
            body = msg.get_payload(decode=True).decode(errors="ignore")
        messages.append({
            "from": msg["From"], "subject": msg["Subject"],
            "body": body, "id": i
        })
    m.close()
    m.logout()
    return messages

def draft_reply(msg):
    client = ollama.Client()
    user_content = f"From: {msg['from']}\nSubject: {msg['subject']}\n\n{msg['body']}"
    response = client.chat(
        model="qwen2.5:14b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_content},
        ],
        options={"temperature": 0.3, "num_ctx": 8192, "num_predict": 400}
    )
    return response.message.content

def save_draft(reply_text, original):
    draft = EmailMessage()
    draft["From"] = IMAP_USER
    draft["To"] = original["from"]
    draft["Subject"] = "Re: " + (original["subject"] or "")
    draft.set_content(reply_text)
    m = imaplib.IMAP4_SSL(IMAP_HOST)
    m.login(IMAP_USER, IMAP_PASS)
    m.append("Drafts", "", imaplib.Time2Internaldate(time.time()), draft.as_bytes())
    m.logout()

if __name__ == "__main__":
    import time
    for msg in get_unread_emails(limit=10):
        print(f"Drafting reply to: {msg['subject']}")
        reply = draft_reply(msg)
        save_draft(reply, msg)
        print(f"  Saved to Drafts ({len(reply)} chars)")

Ce même squelette se plie à tout ce que tu as. Pointe-le vers une API de CRM au lieu d'IMAP et il fait des tickets de support. Des invitations calendrier via CalDAV. Tout ce qui se résume à lire un truc, écrire une réponse, la garer pour un humain. Personne ne te prévient de cette partie d'entrée. Le modèle est le bout pas cher et ennuyeux. C'est l'intégration autour de lui que tu vas materner pendant des années, et je ne crois pas que ça change jamais vraiment.

Terminal lançant ollama pull et ollama run contre qwen2.5, puis un script Python qui rédige des réponses aux mails et les enregistre dans les Brouillons.
Télécharge le modèle, vérifie-le dans le terminal, puis laisse le script rédiger dans ton dossier Brouillons. PNG

Réglages de performance et benchmarks

Quand l'inférence locale traîne, c'est en général l'un de trois réglages qui fait ça. Vérifie ceux-là avant d'aller accuser le modèle :

  • Niveau de quantization. Q4_K_M est le défaut pour une raison. Tu gardes environ 90 % de la qualité et tu rabotes la taille d'un facteur 4. Monte en Q5_K_M ou Q6_K et tu rachètes un peu de qualité sur le même modèle, mais tu payes en VRAM. Q8_0 est en gros sans perte et double à peu près l'empreinte, ce qui fait beaucoup à dépenser. Commence en Q4_K_M. Ne monte qu'une fois que tu as vraiment mesuré la qualité qui mord, pas parce qu'un chiffre plus gros fait plus joli.
  • Fenêtre de contexte (num_ctx). Ollama te démarre à 2048. C'est minuscule dès la seconde où tu lui files un vrai historique ou des morceaux de document, donc pousse num_ctx à 8192 ou 16384. Le coût mémoire grimpe plus ou moins du même pas, ce qui veut dire garder nvidia-smi ouvert et surveiller ta marge pendant que ça tourne. C'est là que la VRAM disparaît en douce.
  • Couches GPU (num_gpu). Ollama essaie de deviner tout seul combien de couches rentrent en VRAM, et la plupart du temps il tape juste. Mais sur une machine avec à la fois un GPU intégré et un GPU dédié ? Je l'ai vu miser sur le mauvais cheval. Quand ça arrive, force l'offload. OLLAMA_NUM_GPU=99 balance tout sur le GPU, 0 garde tout sur le CPU.

Des chiffres approximatifs auxquels je me fierais pour qwen2.5:14b en Q4_K_M, sur le matériel que les gens possèdent vraiment en 2026. Ordre de grandeur, pas parole d'évangile :

MatérielTokens/sec (sortie)
RTX 4090 (24 GB)~75 tok/s
RTX 4070 Ti Super (16 GB)~55 tok/s
Apple M3 Max 64 GB~38 tok/s
RTX 3060 (12 GB)~28 tok/s
Apple M2 16 GB (CPU+GPU)~14 tok/s
Intel i9-13900K CPU only (DDR5-6000)~6 tok/s

Sources et pour aller plus loin

Questions fréquentes

Pourquoi Qwen 2.5 et pas Llama 4 ou Mistral ?

En mai 2026, Qwen 2.5 se place juste devant sur les benchmarks indépendants (MMLU-Pro, HumanEval, MT-Bench) dès que tu es dans la tranche 7B-14B. Il creuse encore l'écart sur le multilingue et sur le code. Llama 4 405B est le meilleur modèle dans l'absolu, aucun débat là-dessus, mais il ne rentrera sur rien qui tienne sous ton bureau ; le 8B est dans la course mais traîne quand même derrière Qwen 2.5 7B sur le code. Mistral Large 3 est très bien et pas open-weight, ce qui pour moi clôt la discussion. Repasse dans six mois cela dit. Je me suis trompé sur quel modèle l'emporte plus de fois que je n'ose l'admettre.

Puis-je faire tourner Ollama sur un laptop sans GPU dédié ?

Oui, tu peux. Le CPU-only marche très bien pour le 0.5B, le 1.5B et le 3B sur une puce Intel ou AMD récente avec 16 GB de RAM ou plus. Le débit est parfaitement vivable. Apple Silicon est un régal ici : à partir du M1, la mémoire unifiée et le GPU Metal prennent le relais, et même un simple M2 fait tourner le 7B à une vitesse qui ne te fera pas jurer. Le 14B sur CPU par contre ? Ça passera techniquement. Mais tu es sur 3-6 tokens par seconde sur un desktop haut de gamme, le genre de lenteur où tu vas te faire un café et c'est encore en train de taper quand tu te rassois.

Comment exposer Ollama de façon sûre au réseau du bureau ?

Trois gestes, dans l'ordre. D'abord, mets OLLAMA_HOST=0.0.0.0:11434 pour qu'il écoute sur toutes les interfaces. Ensuite verrouille le pare-feu de la machine pour que le port 11434 ne s'ouvre qu'au sous-réseau du bureau (192.168.1.0/24, ou la plage de ton VPN selon le cas). Puis dresse un reverse proxy devant, Caddy si tu me demandes, nginx si c'est ta maison, pour terminer le TLS et boulonner du basic auth ou un contrôle de token d'API. Et celui qui compte le plus ? Ne jamais, au grand jamais, pendre le port 11434 nu directement sur Internet. L'API arrive avec zéro auth. Quiconque la trouve la possède.

Quel est le coût mémoire d'un long contexte ?

Règle approximative que je garde en tête : environ 2 MB de VRAM par 1 000 tokens de contexte sur un 7B en Q4_K_M. Compte le double sur un 14B. Donc une pleine fenêtre 32k avec le 14B te coûte à peu près 1 GB en plus des poids eux-mêmes. Ne prends pas mon calcul pour définitif cela dit. Lance un appel réaliste, surveille nvidia-smi pendant qu'il bosse vraiment, et règle ton plafond sur ce que tu vois.

Comment utiliser le function calling avec Qwen 2.5 ?

Qwen 2.5 fait le tool calling d'origine, sans astuce. File-lui un tableau tools dans la requête chat en utilisant le schéma OpenAI ; Ollama 0.5 et plus le transmet proprement, et quand le modèle décide qu'il veut un outil tu trouveras message.tool_calls qui t'attend dans la réponse. Toute la danse multi-tours (appeler l'outil, lui renvoyer le résultat, le laisser appeler le suivant) tourne exactement comme contre l'API OpenAI. Si tu l'as fait là-bas, tu sais déjà.