Aller au contenu principal
GiwiSoft
05

Agent IA local : jusqu'où peut-on aller avec Ollama ?

Giwi 13 min de lecture DevOps, IA

Dans mes précédents articles sur les agents autonomes et le RAG, j’utilisais Ollama en local sans vraiment me poser la question des limites. Pourtant, dès que l’on parle d’agent 100 % local, on bute rapidement sur des choix concrets: quel modèle, quelle taille, quelle mémoire, quelles fonctionnalités je perds par rapport au cloud, et est-ce que ça vaut vraiment le coup? Cet article fait le point, sans enjoliver, sur ce qui est réellement faisable avec un agent IA local sous Ollama.

Ce que “100 % local” signifie réellement

Quand on dit qu’un agent tourne localement, on veut dire que tout le cycle d’IA se déroule sur votre machine ou votre infrastructure: l’exécution du modèle de langage, les embeddings de vos documents, et éventuellement le rag. Aucune requête ne sort de votre réseau. C’est un point de séparation fort avec le cloud, et il a des implications de sécurité et de confidentialité importantes.

flowchart LR U[Utilisateur] --> A subgraph B["Votre machine / serveur"] A[Agent<br/>Node.js ou autre logique] O[Ollama<br/>LLM + embeddings] T[Outils locaux<br/>terminal, fichiers, docs, DB locale] D[(Données privées)] A -->|"requêtes LLM"| O A -->|"appels d'outils"| T O --> D T --> D end

Le terme “local” recouvre en réalité plusieurs scénarios que je vais distinguer tout au long de l’article:

  • Local pur: sur ma machine de travail (laptop ou desktop), pour un usage personnel.
  • Local auto-hébergé: sur un serveur ou un lab maison (un Raspberry Pi, un petit serveur), accessible sur le réseau local ou même public avec Tailscale.
  • Hybride: le LLM en local mais certaines capacités (recherche web, services externes) restent dans le cloud.

Chacun de ces scénarios a des compromis différents, et il vaut la peine de connaître ses limites avant de se lancer.

Ce qui est réellement faisable en local

Confidentialité totale

C’est le premier argument, et il est solide. Mon terminal, mes emails, mes documents de travail, mes logs, rien ne quitte mon réseau. Pour des données soumises au RGPD, des documents clients, ou simplement du travail personnel sensible, c’est un avantage qui dépasse largement la question de la performance.

Quand on utilise un modèle cloud, chaque interaction peut être utilisée pour l’entraînement ou stockée par le fournisseur. Même si les gros fournisseurs proposent des options “zero retention”, on fait un acte de confiance. Avec Ollama, il n’y a pas de fournisseur, il n’y a que votre matériel.

RAG sur des documents locaux

Le RAG (Retrieval-Augmented Generation) fonctionne très bien en local avec PGVector, surtout si vos documents sont déjà sur votre machine: documentation technique, notes, PDF, code. Le flux est identique à celui du cloud, mais les embeddings et la génération ne quittent jamais le réseau.

import ollama from 'ollama';
import { search } from './documents.js';

async function askAgent(question) {
const docs = await search(question); // recherche locale dans pgvector
const context = docs.map(d => d.content).join('\n\n');

const res = await ollama.chat({
model: 'llama3.1:8b',
messages: [
{ role: 'system', content: `Réponds en français en t'appuyant sur ce contexte:\n\n${context}` },
{ role: 'user', content: question },
],
});
return res.message.content;
}

Pas de différence structurelle avec le cloud. La seule vraie différence est la qualité des résultats, qui dépend du modèle choisi, donc de votre matériel.

Function calling avec des modèles locaux

Ollama expose l’API de fonctionnalité calling des modèles qui la supportent. De nombreux modèles compatibles (llama-based, mistral-based, qwen-based) peuvent émettre des appels d’outils structurés. Je décris ce mécanisme en détail dans mon article sur les agents autonomes, mais en résumé, voici le flux:

import ollama from 'ollama';

const tools = [{
type: 'function',
function: {
name: 'read_file',
description: 'Lit le contenu d un fichier',
parameters: {
type: 'object',
properties: { path: { type: 'string' } },
required: ['path'],
},
},
}];

const res = await ollama.chat({
model: 'qwen2.5:7b',
messages: [{ role: 'user', content: 'Montre le début du README' }],
tools,
});

if (res.message.tool_calls) {
console.log('L agent veut appeler:', res.message.tool_calls);
}

Le modèle local peut donc décider d’appeler un outil, et votre code exécute l’outil puis retourne le résultat au modèle pour la suite. C’est exactement le mécanisme qui permet de construire un agent qui agit, pas seulement un modèle qui répond.

sequenceDiagram autonumber participant A as Agent (Node.js) participant M as Modèle local (Ollama) participant T as Outil (file, terminal, DB) A->>M: chat(messages, tools) Note over M: Le modèle décide<br/>d'appeler un outil M-->>A: tool_calls [{ name: "read_file", path: "..." }] A->>T: Exécute l'outil demandé T-->>A: Résultat de l'outil A->>M: chat(messages + résultat, tools) M-->>A: Réponse finale A-->>A: Validation + retry<br/>si JSON invalide

Assistant de codage moins cher

C’est là que le local brille. Pour de l’auto-complétion, de la génération de tests, du refactoring, des explications de code, un modèle local de 7B à 13B suffit souvent, et le coût est nul à l’usage (une fois le matériel acheté). Je l’utilise tous les jours pour du code que je ne voudrais pas envoyer à un service cloud.

Les limites honnêtes

Maintenant que j’ai listé ce qui est faisable, il faut parler des vraies limites. Parce qu’un agent 100 % local, ce n’est pas un agent GPT-4 copié en local. C’est un compromis assumé.

Taille du modèle vs qualité

C’est le compromis central. La qualité d’un LLM croît fortement avec sa taille, surtout pour le raisonnement, le dev et les tâches complexes. Les modèles de 7B et 13B sont remarquables pour leur taille, mais ils restent en deçà des modèles de 70B+ ou des références cloud sur les tâches de raisonnement avancé.

Modèle Taille Usage adapté Usage limite
3B (phi-3, qwen2.5:3b) ~2 Go Résumé court, classement Raisonnement, code complexe
7B-8B (llama3.1:8b, qwen2.5:7b) ~4-5 Go RAG, chat, code simple, function calling basique Code complexe, raisonnement multi-étapes
13B (llama3:13b, qwen2.5:14b) ~8 Go Meilleur compromis, code correct Raisonnement très avancé
70B (llama3.3:70b) ~40 Go Proche du cloud pour beaucoup de tâches Coût matériel, latence

La ligne “usage limite” est importante: un modèle 7B peut réussir 70 % des tâches de raisonnement qu’un 70B réussit, mais c’est précisément les 30 % qui restent qui font toute la différence dans un agent autonome. Un agent qui délègue une action à un mauvais raisonnement peut produire des résultats dangereux (une commande shell erronée, un calcul faux).

Contrainte de fenêtre de contexte

Les modèles locaux ont souvent des fenêtres de contexte plus limitées que les géants cloud (qui atteignent 128K, 200K ou plus). Avec Ollama, la fenêtre par défaut est souvent 4096 tokens, configurable jusqu’à ce que la mémoire le permette. Or, un agent qui lit des fichiers, accumule l’historique et appelle des outils consomme du contexte très vite.

# Augmenter la fenêtre de contexte à l invocation
ollama run llama3.1:8b --num-ctx 32768

# Ou dans une configuration Ollama
# /home/giwi/.ollama/... via la variable OLLAMA_CONTEXT_LENGTH

Plus de contexte signifie plus de VRAM. Une fenêtre de 32K tokens avec un modèle 8B peut déjà saturer une carte de 8 Go qui tenait la 4K facilement. C’est un compromis entre profondeur de l’historique et capacité du modèle.

Inférence plus lente

Un modèle local tourne sur votre GPU (ou CPU si pas de GPU), pas sur les dizaines de GPUs d’un fournisseur cloud. La latence de génération est plus élevée, surtout pour les gros modèles. Où le cloud fait du 50-100 tokens/s sur un gros modèle, un local fait souvent 20-40 tokens/s sur un 7B avec une bonne carte, et quelques tokens/s sur un 70B en CPU.

Pour un chat interactif, c’est tolérable. Pour un agent qui doit itérer sur plusieurs appels d’outils, chaque étape multiplie la latence, et l’expérience devient frustrante.

Fiabilité du function calling

C’est la limite la plus subtile. Les modèles locaux supportent le function calling, mais la fiabilité du format JSON en sortie est inférieure au cloud. Un modèle local peut parfois produire du JSON invalide, oublier un argument obligatoire, ou inventer un outil qui n’existe pas. Il faut donc une couche de validation et de retry dans votre agent.

async function callWithRetry(fn, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const res = await fn();
const content = res.message.tool_calls ? JSON.parse(JSON.stringify(res.message.tool_calls)) : null;
if (isValidToolCall(content)) return content;
} catch (err) {
console.warn(`Appel invalide (tentative ${attempt + 1}):`, err.message);
}
}
throw new Error('Function calling: echec apres plusieurs tentatives');
}

Qualité des embeddings

Pour le RAG, la qualité des embeddings détermine la pertinence de la recherche. nomic-embed-text en local (768 dims) est correct, mais reste en deçà de modèles d’embedding cloud spécialisés en termes de précision sur des données spécifiques et multilingues. Pour une documentation technique, un blog, ça suffit. Pour un corpus très spécialisé, le cloud peut faire mieux.

Le matériel nécessaire

C’est la question que tout le monde pose en premier, et c’est légitime: les besoins matériels conditionnent tout. Voici une table réaliste basée sur mon expérience, en supposant que le modèle tienne entièrement dans la VRAM (quantification Q4, GPU):

Configuration VRAM / RAM Modèles compatibles Usages
Raspberry Pi 5 (16 Go) 0 VRAM, 16 Go RAM 1-3B en CPU Chat simple, résumé
GPU 8 Go 8 Go VRAM 7B-8B (Q4), 13B (Q4) RAG, function calling, code simple
GPU 12-16 Go 12-16 Go VRAM 13B (Q4), 32B (Q4 partiel) Meilleur compromis
GPU 24 Go+ 24 Go+ VRAM 70B (Q4), gros contextes Proche du cloud
Multi-GPU / serveur 48 Go+ 70B Q4, mixtures Usage avancé

Règle simple à retenir: un modèle nécessite environ un octet de VRAM par paramètre avec une quantification Q4. Un 7B = ~4-5 Go, un 13B = ~8 Go, un 70B = ~40 Go (avant même de compter le contexte). Si votre VRAM est insuffisante, Ollama déborde en RAM puis en RAM partagée (swap), et la performance chute à quelques tokens/s, souvent inutilisable pour un agent.

Un setup local complet et réaliste

Voici le setup que j’utilise sur une machine GPU 16 Go, qui me donne un agent local fonctionnel pour du RAG et du function calling.

1. Installation et récupération des modèles

# Installer Ollama (Linux, macOS)
curl -fsSL https://ollama.com/install.sh | sh

# Récupérer le modèle de chat principal
ollama pull llama3.1:8b

# Récupérer le modèle d embedding pour le RAG
ollama pull nomic-embed-text

J’ai choisi llama3.1:8b comme modèle de chat (bon compromis qualité/ressources) et nomic-embed-text pour les embeddings (768 dims, compatible avec mon pipeline pgvector).

2. Vérifier que tout fonctionne

ollama list
# NAME ID SIZE MODIFIED
# llama3.1:8b ... 4.9 GB ...
# nomic-embed-text ... 274 MB ...

# Test rapide
ollama run llama3.1:8b "En une phrase, explique le principe d un agent IA."

3. Câbler l’agent local

Le code de l’agent se branche sur l’API HTTP par défaut d’Ollama (http://localhost:11434) ou via le SDK officiel. Voici un agent minimal avec function calling et RAG combinés:

import ollama from 'ollama';
import { search } from './retrieval.js'; // mon pipeline pgvector

const tools = [
{
type: 'function',
function: {
name: 'search_docs',
description: 'Recherche dans la base de documents technique interne',
parameters: {
type: 'object',
properties: { query: { type: 'string' } },
required: ['query'],
},
},
},
{
type: 'function',
function: {
name: 'read_log',
description: 'Lit les derniers logs d un service',
parameters: {
type: 'object',
properties: { service: { type: 'string' } },
required: ['service'],
},
},
},
];

const toolImplementations = {
search_docs: async (q) => (await search(q)).slice(0, 5).map(d => d.content).join('\n'),
read_log: async (service) => `logs de ${service}:\n${readServiceLog(service)}`,
};

async function runAgent(userQuestion) {
let messages = [{ role: 'user', content: userQuestion }];

for (let step = 0; step < 5; step++) {
const res = await ollama.chat({ model: 'llama3.1:8b', messages, tools });

if (res.message.tool_calls) {
// Exécuter les outils demandés
for (const call of res.message.tool_calls) {
const name = call.function?.name;
const args = call.function?.arguments || {};
if (toolImplementations[name]) {
const result = await toolImplementations[name](args);
messages.push({ role: 'tool', content: JSON.stringify(result) });
}
}
continue; // boucle pour laisser le modèle utiliser le résultat
}

return res.message.content; // réponse finale
}

return 'Trop d iterations, j ai besoin de clarifier.';
}
flowchart TD A[Question utilisateur] --> B[Agent appelle Ollama<br/>llama3.1:8b + tools] B --> C{Le modèle demande<br/>un outil ?} C -->|Oui| D[Exécute search_docs / read_log<br/>en local] D --> E[Ajoute le résultat<br/>au contexte] E --> B C -->|Non| F[Réponse finale en local] F --> G{Itérations < 5 ?} G -->|Non| H["Trop d'itérations,<br/>demande une clarification"]

C’est un agent fonctionnel: il décide d’appeler la recherche ou de lire les logs, récupère les résultats, puis synthétise une réponse en local. Aucune donnée ne sort de ma machine.

4. L’intégration avec mes habitudes

Ce setup me permet d’avoir un assistant de codage local, un assistant pour ma doc technique via RAG, et un agent capable d’appeler des outils locaux (lire des fichiers, consulter des logs, interroger ma base). Quand j’ai besoin de ce que le local ne sait pas faire, je bascule sur le cloud pour une tâche ponctuelle, mais l’essentiel reste en local.

Quand le local est-il suffisant ?

À la lumière de tout ce qui précède, voici un résumé de ce que mon expérience m’a appris.

Le local est nettement suffisant pour:

  • RAG sur documents privés: c’est l’usage roi du local. Confidentialité + volumes raisonnables + pertinence suffisante des modèles 7B-13B.
  • Assistant de codage quotidien: auto-complétion, génération de tests, explication de code, refactoring. Un 13B fait un travail correct.
  • Agents avec function calling simple: appels d’outils bien paramétrés, flux courts, actions vérifiables.
  • Tout usage sur données sensibles: emails, documents clients, logs d’infra. La confidentialité l’emporte sur la qualité.
  • Prototypage: avant de payer pour du cloud, valider qu’un agent fonctionne conceptuellement.

Le local est insuffisant pour:

  • Raisonnement avancé: mathématiques, logique multi-étapes, planification complexe. Les modèles lourds (70B+) ou cloud font nettement mieux.
  • Gros volumes de contexte: traiter des documents très longs ou de longs historiques impose une VRAM importante.
  • Tâches sensibles à la latence: un agent interactif qui itère sur plusieurs outils devient pénible.
  • Function calling fiable à 100 %: les modèles locaux ont des taux d’erreur JSON plus élevés, il faut des retries et une validation.

La frontière évolue vite

Ce qui était réservé au cloud il y a deux ans (function calling, agents, RAG de qualité) est maintenant faisable en local. La tendance se poursuit: les modèles locaux de 2026 dépassent sur certaines tâches ce que le cloud faisait il y a 18 mois. La frontière “local vs cloud” est une ligne qui recule, mais elle reste présente.

Mon verdict

Un agent 100% local avec Ollama est un choix réaliste et de plus en plus pertinent pour une grande partie des usages, à condition de choisir le bon modèle pour la bonne tâche, d’avoir le matériel adapté, et d’accepter les compromis sur le raisonnement avancé et la latence.

Pour la confidentialité, rien ne bat le local. Pour le RAG sur documents privés, c’est le choix évident. Et pour un agent qui agit principalement sur des données et des outils locaux, c’est souvent largement suffisant. Il faut simplement connaître la ligne au-delà de laquelle on perd trop, et basculer alors sur le cloud pour cette tâche précise.

En 2026, pour un développeur qui veut un agent IA sur ses propres données sans envoyer quoi que ce soit dehors, Ollama est à ma connaissance le meilleur rapport simplicité/privé/qualité.

Pour aller plus loin