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.
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èle | VRAM min | Débit | Cas idéal |
|---|---|---|---|
qwen2.5:0.5b | 1.5 GB | ~150 tok/s | Appareils edge, autocomplétion, classification |
qwen2.5:1.5b | 2.5 GB | ~120 tok/s | Chat léger, extraction, sur laptops CPU-only |
qwen2.5:3b | 4 GB | ~90 tok/s | Résumé, usage simple d'outils, RAG |
qwen2.5:7b | 6 GB | ~70 tok/s | Agent polyvalent, complétion de code |
qwen2.5:14b | 10 GB | ~45 tok/s | Raisonnement complexe, agents multi-étapes (meilleur rapport qualité / coût sur RTX 3060 12GB et plus) |
qwen2.5:32b | 22 GB | ~22 tok/s | Qualité quasi-flagship, exige une RTX 3090 / 4090 / 5090 ou un Apple M3 Max+ |
qwen2.5:72b | 48 GB | ~12 tok/s | Qualité 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.
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 gardernvidia-smiouvert 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=99balance tout sur le GPU,0garde 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ériel | Tokens/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à.