Avancé 10 minMulti-modèles

LLM Council : faire délibérer plusieurs modèles locaux

LLM Council est un petit projet publié par Andrej Karpathy fin 2025 : au lieu d'envoyer une question à un seul modèle, on la soumet à plusieurs, chacun classe ensuite les réponses des autres sans savoir qui les a écrites, et un modèle « président » rédige la synthèse finale. Le dépôt vise des modèles cloud via OpenRouter, mais le patron tient en une centaine de lignes et se transpose à des modèles locaux servis par Ollama. Ce guide explique les trois étapes, montre comment les reproduire sur une machine personnelle, détaille ce que cela coûte en mémoire et en temps, et pourquoi il ne faut pas supposer que le conseil répond mieux qu'un bon modèle seul.

Par Léa B.·Màj 2026-10-12·Testé sur Windows, macOS, Linux

#LLM Council : le patron en trois étapes

Le dépôt décrit un flux fixe en trois temps. Chaque temps est un appel de modèle ordinaire, sans outil ni mémoire : la seule astuce est la façon dont les sorties du premier temps nourrissent les deux suivants.

  1. 01
    Premières opinions
    La question de l'utilisateur est envoyée telle quelle à chaque membre du conseil, séparément. Chacun répond sans voir les autres. Dans l'interface d'origine, ces réponses s'affichent dans des onglets, une par modèle.
  2. 02
    Relecture et classement
    Chaque membre reçoit ensuite les réponses des autres, anonymisées (étiquetées « Réponse A », « Réponse B »...), et doit les classer de la meilleure à la moins bonne en jugeant la justesse et la profondeur. L'anonymisation vise à éviter qu'un modèle favorise ou défavorise un concurrent connu.
  3. 03
    Synthèse du président
    Un modèle désigné comme président reçoit la question, toutes les réponses et tous les classements, puis rédige la réponse finale unique présentée à l'utilisateur.

Rien dans ce schéma n'exige des modèles différents, mais c'est tout l'intérêt : on compte sur la diversité des entraînements pour que les erreurs d'un modèle soient repérées par un autre. Le président peut être l'un des membres ou un modèle à part, en général le plus capable de la liste.

i
Un projet d'exploration, pas un produit
Dans son message d'annonce, Karpathy présente LLM Council comme un projet de week-end écrit en grande partie par des assistants de code, qu'il ne prévoit pas de maintenir. Les impressions qu'il partage sur les modèles qui se classent bien ou mal entre eux sont qualitatives et datées. Aucune évaluation chiffrée n'accompagne le dépôt : ce guide n'en ajoute pas.

#Ce que contient le dépôt de Karpathy

Le kit Agents Locaux

Des agents qui agissent sur ta machine : Cline agentique, MCP, n8n + Ollama, automatisations locales.

  • Espace en ligne à vie
  • PDF + fichiers
  • Mises à jour à vie

Le dépôt github.com/karpathy/llm-council est une application web locale qui ressemble à une interface de chat classique. D'après son README et ses fichiers de configuration au moment de la rédaction, il se compose de :

Un backend Python (FastAPI)
Dans le dossier backend/ : la logique des trois étapes, un client HTTP vers l'API d'OpenRouter, et le stockage des conversations en fichiers JSON dans un dossier data/. Les dépendances sont gérées avec uv.
Un frontend React (Vite)
Dans le dossier frontend/ : l'interface qui affiche les réponses individuelles, les classements et la synthèse.
Un fichier de configuration
backend/config.py liste les membres du conseil (COUNCIL_MODELS) et le président (CHAIRMAN_MODEL) sous forme d'identifiants OpenRouter, ainsi que l'adresse de l'API appelée.
Un script de lancement
start.sh démarre le backend et le frontend ensemble. Une clé OPENROUTER_API_KEY est attendue dans un fichier .env.

Les modèles configurés par défaut sont des modèles cloud fermés (familles GPT, Gemini, Claude et Grok dans la version publiée). C'est le point à changer pour une version locale : le reste du code ne se soucie pas de qui répond, tant que l'API parle le format « chat completions » popularisé par OpenAI. Relisez le README et config.py avant de suivre ce guide, le projet peut avoir évolué depuis le 12 octobre 2026.

#Prérequis pour une version locale

Ollama installé et fonctionnel
Le serveur écoute par défaut sur http://localhost:11434. Vérifiez avec la commande ollama list que vos modèles apparaissent.
Trois à quatre modèles de familles différentes
Un conseil de modèles issus de la même famille perd l'intérêt de la diversité. Visez par exemple un Qwen, un Llama, un Mistral et un Gemma, dans des tailles proches.
Mémoire adaptée
En Q4_K_M, comptez environ 5 Go par modèle 7B et 9 Go par modèle 14B. Les membres n'ont pas besoin de tenir tous en mémoire en même temps, mais le confort en dépend (voir la section sur les coûts).
Python 3.10 ou plus
Pour le script minimal de ce guide, avec le paquet requests. Pour le dépôt original, uv et Node.js en plus.
Patience
Un tour de conseil coûte au moins deux fois plus de générations que le nombre de membres, plus une. Ce n'est pas un outil de chat instantané.

#Étape 1 : choisir le conseil et le président

Le choix des membres est une affaire d'équilibre entre diversité et mémoire. Le président, lui, doit surtout bien lire de longs contextes : il reçoit la question, toutes les réponses et tous les classements, ce qui représente facilement plusieurs milliers de tokens. Prenez pour ce rôle le modèle le plus capable que votre machine supporte, même s'il est plus lent, car il n'est appelé qu'une fois par tour.

Terminal
# Exemple de conseil pour une carte 12 Go (noms à vérifier avec `ollama search` ou sur ollama.com/library)
ollama pull qwen3:8b
ollama pull llama3.1:8b
ollama pull mistral:7b
ollama pull gemma3:12b   # président : plus gros, appelé une seule fois par tour
ollama list

Les tailles 7B à 8B conviennent aux membres sur une carte de 12 Go : un seul tient en mémoire avec une marge pour le contexte, et Ollama alterne entre eux. Avec 24 Go ou un Mac à mémoire unifiée de 48 Go, vous pouvez monter les membres en 14B ou garder deux à trois modèles chargés en même temps, ce qui supprime les rechargements.

→
Ajoutez un modèle de raisonnement si vous le pouvez
Un membre capable de « réfléchir » avant de répondre apporte souvent un angle différent des modèles directs. Pensez en revanche à désactiver ou limiter la phase de réflexion lors de l'étape de classement, sans quoi cette étape devient la plus longue du tour.

#Étape 2 : régler Ollama pour plusieurs modèles

Deux réglages d'Ollama comptent ici. Le premier est le nombre de modèles gardés en mémoire, fixé par la variable OLLAMA_MAX_LOADED_MODELS : si la mémoire le permet, garder tous les membres chargés évite un rechargement à chaque passage de l'un à l'autre. Le second est la fenêtre de contexte, num_ctx, qui par défaut est courte sur Ollama : l'étape de classement et la synthèse du président font lire plusieurs réponses complètes, et un contexte trop petit tronque silencieusement le début du prompt.

Terminal (Linux, service systemd)
sudo systemctl edit ollama
# puis dans le bloc [Service] :
# Environment="OLLAMA_MAX_LOADED_MODELS=2"
# Environment="OLLAMA_KEEP_ALIVE=30m"
sudo systemctl restart ollama

Sur macOS, les mêmes variables se posent avec launchctl setenv avant de relancer l'application. La valeur de OLLAMA_MAX_LOADED_MODELS doit rester cohérente avec votre mémoire : deux modèles 8B en Q4 occupent déjà une dizaine de Go avec leur contexte. Le contexte, lui, se règle par requête (champ options.num_ctx de l'API) ou dans un Modelfile dérivé ; la section suivante le passe à chaque appel.

!
Parallélisme : séquentiel par défaut
Le code original lance les membres en parallèle, ce qui est logique avec des API cloud. En local, envoyer quatre requêtes simultanées à quatre modèles différents force Ollama à les charger et décharger à tour de rôle, voire à repousser une partie sur le processeur. Sauf si tous les membres tiennent en mémoire, appelez-les l'un après l'autre.

#Étape 3 : un conseil minimal en Python

Le script ci-dessous reproduit les trois étapes du dépôt avec l'API native d'Ollama, sans interface. Il mélange l'ordre des réponses avant le classement pour que les étiquettes ne trahissent pas l'auteur, demande à chaque membre un classement court, puis confie le tout au président. Adaptez les noms de modèles à ceux de votre machine.

council.py
import random
import requests

OLLAMA = "http://localhost:11434/api/chat"
COUNCIL = ["qwen3:8b", "llama3.1:8b", "mistral:7b"]
CHAIRMAN = "gemma3:12b"
NUM_CTX = 16384


def ask(model, prompt):
    r = requests.post(OLLAMA, json={
        "model": model,
        "messages": [{"role": "user", "content": prompt}],
        "stream": False,
        "options": {"num_ctx": NUM_CTX, "temperature": 0.3},
    }, timeout=1800)
    r.raise_for_status()
    return r.json()["message"]["content"].strip()


def council(question):
    # Étape 1 : premières opinions, une par membre, sans se voir
    answers = {m: ask(m, question) for m in COUNCIL}

    # Anonymisation : ordre mélangé, étiquettes A, B, C...
    order = list(COUNCIL)
    random.shuffle(order)
    labels = {m: chr(65 + i) for i, m in enumerate(order)}
    packed = "\n\n".join(
        f"### Réponse {labels[m]}\n{answers[m]}" for m in order
    )

    # Étape 2 : chaque membre classe les réponses (les siennes incluses)
    rankings = {}
    for m in COUNCIL:
        rankings[m] = ask(m,
            f"Question : {question}\n\n{packed}\n\n"
            "Classe ces réponses de la meilleure à la moins bonne selon leur "
            "justesse et leur profondeur. Pour chacune, une ligne de justification. "
            "Termine par la ligne 'CLASSEMENT :' suivie des lettres dans l'ordre.")

    # Étape 3 : le président rédige la synthèse finale
    votes = "\n\n".join(
        f"### Avis du juge {labels[m]}\n{rankings[m]}" for m in COUNCIL
    )
    final = ask(CHAIRMAN,
        f"Question : {question}\n\n{packed}\n\n{votes}\n\n"
        "Tu présides ce conseil. En t'appuyant sur les réponses et les classements, "
        "rédige une réponse finale unique, précise et sans redite. Signale les points "
        "sur lesquels les réponses se contredisent.")
    return answers, labels, rankings, final


if __name__ == "__main__":
    import sys
    q = " ".join(sys.argv[1:]) or "Quelle quantification choisir pour un modèle 14B sur 12 Go de VRAM ?"
    answers, labels, rankings, final = council(q)
    for m in COUNCIL:
        print(f"\n===== {m} (Réponse {labels[m]}) =====\n{answers[m]}")
    for m in COUNCIL:
        print(f"\n===== Classement par {m} =====\n{rankings[m]}")
    print(f"\n===== Synthèse ({CHAIRMAN}) =====\n{final}")
Terminal
python3 -m venv .venv && source .venv/bin/activate
pip install requests
python council.py "Faut-il un reranker dans un pipeline RAG local ?"

Le dépôt original va un peu plus loin : il extrait la ligne de classement de chaque juge pour calculer un rang moyen par réponse et l'afficher à côté des onglets. Vous pouvez l'ajouter en quelques lignes en lisant la ligne « CLASSEMENT : » de chaque sortie. Gardez en tête que les petits modèles ne respectent pas toujours ce format : prévoyez un repli quand la ligne manque.

→
Le membre se juge lui-même
Dans ce script comme dans le dépôt, chaque juge voit sa propre réponse parmi les autres, sous une étiquette anonyme. C'est volontaire : cela permet de constater si un modèle reconnaît son style et se favorise. Si vous préférez l'exclure, retirez sa réponse du bloc envoyé à chaque juge, mais les classements ne porteront plus sur le même ensemble et la moyenne devient moins lisible.

#Étape 4 : adapter le dépôt original à Ollama

Si vous voulez l'interface web, le chemin le plus court consiste à utiliser le point d'accès compatible OpenAI d'Ollama, servi à l'adresse http://localhost:11434/v1/chat/completions. Le backend du dépôt envoie déjà des requêtes dans ce format vers OpenRouter : il suffit en principe de remplacer l'adresse de l'API et les identifiants de modèles dans backend/config.py, puis de renseigner une clé factice, Ollama ignorant l'en-tête d'autorisation.

Terminal
git clone https://github.com/karpathy/llm-council
cd llm-council
uv sync
cd frontend && npm install && cd ..
echo 'OPENROUTER_API_KEY=ollama' > .env
backend/config.py (extrait à adapter, noms de constantes à vérifier dans votre version)
COUNCIL_MODELS = [
    "qwen3:8b",
    "llama3.1:8b",
    "mistral:7b",
]
CHAIRMAN_MODEL = "gemma3:12b"

# Ollama expose une API compatible OpenAI sur /v1
OPENROUTER_API_URL = "http://localhost:11434/v1/chat/completions"
Terminal
./start.sh
# backend sur le port 8001, interface Vite sur http://localhost:5173 (valeurs du README à vérifier)

Deux points restent à traiter à la main. D'abord le contexte : le point d'accès compatible OpenAI n'a pas de champ num_ctx, il faut donc soit créer des variantes de modèles avec un Modelfile fixant le contexte, soit basculer le client sur l'API native /api/chat qui accepte les options. Ensuite le parallélisme évoqué plus haut : la première étape lance les appels en même temps, ce qui vaut un passage en séquentiel si vos membres ne tiennent pas tous en mémoire.

Terminal (variante avec contexte fixé)
cat > Modelfile.qwen-council <<'EOF'
FROM qwen3:8b
PARAMETER num_ctx 16384
EOF
ollama create qwen3-council -f Modelfile.qwen-council

Plusieurs forks communautaires ont fait ces modifications pour Ollama ou pour d'autres serveurs locaux. Avant d'en adopter un, regardez la date du dernier commit, le nombre de fichiers touchés par rapport au dépôt d'origine, et lisez le code qui appelle le modèle : c'est court, et c'est là que se logent les différences. Ce guide ne recommande aucun fork en particulier, leur état change trop vite.


#Coût en mémoire et en temps

Le compte est simple et vaut la peine d'être posé avant de s'engager. Pour un conseil de N membres, un tour complet demande N générations à l'étape 1, N générations à l'étape 2 et une pour le président, soit 2N + 1 appels. Les appels de l'étape 2 et celui du président sont plus longs à traiter que le premier, car le prompt contient toutes les réponses : le temps de lecture du prompt s'ajoute au temps de génération.

Trois membres
Sept générations par question. Si chaque réponse prend de l'ordre d'une demi-minute sur votre machine, un tour dépasse les trois minutes, sans compter les rechargements.
Mémoire minimale
Le plus gros modèle du conseil plus son contexte. Avec des membres 8B en Q4 et un contexte de 16 000 tokens, une carte de 12 Go tient, à condition de ne garder qu'un modèle chargé.
Mémoire confortable
Tous les membres chargés en même temps : la somme de leurs tailles, plus un cache de contexte par modèle. Trois modèles 8B en Q4 réclament un GPU de 24 Go ou un Mac de 32 Go unifiés au minimum.
Rechargements
Quand les membres ne tiennent pas ensemble, chaque changement de modèle coûte quelques secondes de chargement depuis le disque. Sur un tour, cela arrive jusqu'à 2N fois. Un SSD NVMe rend ce coût supportable ; un disque lent le rend pénible.

Ces ordres de grandeur dépendent de votre matériel, de la quantification et de la longueur des réponses : nous n'avons pas mesuré de temps de tour pour cet article et les chiffres ci-dessus sont des règles de calcul, pas des résultats. Pour évaluer votre cas, chronométrez une génération simple avec chacun de vos membres et appliquez la formule.

#Limites et biais du conseil

Le patron est séduisant parce qu'il ressemble à une relecture par les pairs. Il faut pourtant résister à l'idée qu'il est forcément plus juste qu'un bon modèle seul : le dépôt n'apporte aucune mesure dans ce sens, et plusieurs biais connus des modèles juges jouent contre lui.

Anonymisation imparfaite
Les étiquettes masquent le nom, pas le style. Un modèle peut reconnaître sa propre façon d'écrire, ou celle d'une famille qu'il connaît, et classer en conséquence. Karpathy note lui-même, de façon qualitative, que les modèles ont souvent préféré la réponse d'un autre à la leur : c'est une observation, pas une garantie.
Biais de position et de longueur
Les travaux sur les modèles juges, par exemple l'article MT-Bench de Zheng et al. (2023), documentent une préférence pour la première réponse lue et pour les réponses longues. Mélanger l'ordre atténue le premier biais ; le second se corrige mal.
Erreurs corrélées
Des modèles entraînés sur des corpus proches se trompent souvent de la même manière. Un conseil de petits modèles peut voter à l'unanimité pour une réponse fausse, et le président la retiendra.
Le président reste seul
La synthèse dépend entièrement du modèle président : s'il hallucine, le conseil n'y change rien. Lisez les réponses individuelles quand le sujet compte, c'est d'ailleurs l'intérêt des onglets de l'interface originale.
Petits modèles, instructions longues
Le prompt de classement est exigeant : lire trois ou quatre textes, juger, justifier, respecter un format. En dessous de 7B, les sorties deviennent irrégulières et le classement moyen perd son sens.
!
Pas de mesure, pas de promesse
Si vous voulez savoir si le conseil améliore vos résultats, construisez un petit jeu de questions dont vous connaissez les réponses, faites tourner le meilleur modèle seul puis le conseil, et comparez à l'aveugle. Sans ce test sur vos propres cas, l'intuition « plusieurs avis valent mieux qu'un » n'est qu'une hypothèse.

#Cas d'usage réels d'un LLM Council local

Le surcoût de 2N + 1 générations se justifie quand la question est rare et importante, pas pour du bavardage. Trois situations ressortent chez les personnes qui ont repris le patron en local.

Relecture d'un texte ou d'un code sensible
Un courrier contractuel, une procédure, une fonction critique : les membres relèvent des problèmes différents, le président les consolide en une liste. Le classement sert ici moins que la diversité des remarques.
Décision technique argumentée
« Faut-il migrer cette base », « quel format pour cet export » : les réponses divergentes sont une information en soi. Demandez au président de rendre les désaccords visibles plutôt que de les lisser.
Contrôle qualité d'un seul modèle
Utiliser le conseil comme jury pour comparer deux versions de prompt ou deux quantifications du même modèle, en lui demandant de classer des sorties que vous avez produites ailleurs. C'est une application directe de l'étape 2, sans l'étape 1.

Dans tous ces cas, la confidentialité est le vrai argument de la version locale : les documents relus ne quittent pas la machine, là où la version originale les envoie à quatre fournisseurs différents via OpenRouter. C'est ce qui rend le patron intéressant pour une équipe qui traite des données internes, à condition d'accepter les minutes d'attente.

#Dépannage

Le classement ignore une réponse
Le contexte est trop court et le début du prompt a été tronqué. Augmentez num_ctx (ou le Modelfile) et vérifiez dans les journaux d'Ollama qu'aucun avertissement de troncature n'apparaît.
Les appels de l'étape 1 sont très lents
Les membres sont appelés en parallèle et se bousculent en mémoire. Passez en séquentiel ou réduisez le conseil à ce qui tient en VRAM ensemble.
Le président répond à côté
Son contexte est le plus chargé du tour. Donnez-lui un modèle plus gros ou résumez les classements avant de les lui transmettre.
Format de classement absent
Les petits modèles oublient la ligne « CLASSEMENT : ». Rappelez le format en fin de prompt, baissez la température, ou acceptez une lecture manuelle des justifications.
Réponses d'un membre vides ou en anglais
Vérifiez que le modèle ne renvoie pas uniquement sa phase de réflexion, et précisez la langue attendue dans la question.
Mémoire saturée après quelques tours
OLLAMA_MAX_LOADED_MODELS trop haut pour la machine. Ramenez-le à 1 et laissez Ollama alterner.

#Pour aller plus loin

LLM Council est un patron de délibération, pas un cadre d'agents : il ne gère ni outils, ni rôles, ni mémoire. Si votre besoin dépasse la synthèse d'avis, ces guides du site couvrent les briques voisines.

CrewAI avec Ollama
Quand les modèles doivent se répartir des rôles et enchaîner des tâches plutôt que juger une même réponse. https://quelllm.fr/guide/crewai-ollama-multi-agents
LiteLLM en passerelle locale
Pour exposer plusieurs serveurs de modèles derrière une seule API compatible OpenAI, par exemple un conseil réparti sur deux machines. https://quelllm.fr/guide/litellm-proxy-gateway-local
Architecture d'un agent IA local
Les composants à assembler autour d'un modèle quand on veut lui donner des outils et une mémoire. https://quelllm.fr/guide/agent-ia-local-architecture
Partager un serveur Ollama sur le réseau local
Héberger les membres du conseil sur une machine plus grosse et les appeler depuis votre poste. https://quelllm.fr/guide/ollama-serveur-reseau-local-partage

Guide rédigé le 12 octobre 2026 à partir du dépôt GitHub de Karpathy et de la documentation d'Ollama. Aucune mesure de temps ni de qualité n'a été réalisée pour cet article ; les repères de mémoire sont des ordres de grandeur en Q4_K_M. Les noms de constantes, de ports et de modèles évoluent : relisez les sources ci-dessous avant de copier les commandes.

Ce guide vous a aidé ?

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