LLM Council: having multiple models deliberate locaux
LLM Council is a small project published by Andrej Karpathy in late 2025: instead of sending a question to a single model, you submit it to several; each then ranks the others' responses without knowing who wrote them, and a “president” model writes the final synthesis. The repository targets cloud models through OpenRouter, but the pattern fits in about one hundred lines and can be adapted to local models served by Ollama. This guide explains the three steps, shows how to reproduce them on a personal machine, details the memory and time costs, and explains why you should not assume the council answers better than a good single model.
#LLM Council: the three-step pattern
The repository describes a fixed three-stage flow. Each stage is an ordinary model call, with no tools or memory: the only trick is how the outputs from the first stage feed the next two.
- 01Initial opinionsThe user's question is sent as-is to each council member separately. Each one responds without seeing the others. In the original interface, these responses appear in tabs, one per model.
- 02Review and rankingEach member then receives the other responses, anonymized (labeled “Response A,” “Response B,” ...), and must rank them from best to worst based on accuracy and depth. The anonymization is intended to prevent a model from favoring or disadvantaging a known competitor.
- 03President's synthesisA model designated as president receives the question, all the responses, and all the rankings, then writes the single final answer presented to the user.
Nothing in this design requires different models, but that is the whole point: it relies on training diversity so that one model’s errors are spotted by another. The chair can be one of the members or a separate model, generally the most capable one on the list.
#What's in Karpathy's repository
Agents that act on your machine: agentic Cline, MCP, n8n + Ollama, local automations.
- Lifetime online access
- PDF + files
- Lifetime updates
The github.com/karpathy/llm-council repository is a local web application that resembles a traditional chat interface. According to its README and configuration files at the time of writing, it consists of:
- A Python backend (FastAPI)
- In the backend/ directory: the logic for the three steps, an HTTP client for the OpenRouter API, and conversation storage in JSON files in a data/ directory. Dependencies are managed with uv.
- A React frontend (Vite)
- In the frontend/ directory: the interface that displays individual responses, rankings, and the summary.
- A configuration file
- backend/config.py lists the council members (COUNCIL_MODELS) and the chair (CHAIRMAN_MODEL) as OpenRouter identifiers, along with the address of the API being called.
- A launch script
- start.sh starts the backend and frontend together. An OPENROUTER_API_KEY is expected in a .env file.
The default-configured models are closed cloud models (the GPT, Gemini, Claude, and Grok families in the published version). This is what you need to change for a local version: the rest of the code does not care who responds, as long as the API speaks the “chat completions” format popularized by OpenAI. Review the README and config.py before following this guide; the project may have changed since October 12, 2026.
#Prerequisites for a local version
- Ollama installed and working
- The server listens on http://localhost:11434 by default. Run the ollama list command to verify that your models appear.
- Three to four models from different families
- A council of models from the same family loses the benefit of diversity. For example, aim for a Qwen, a Llama, a Mistral, and a Gemma, in similar sizes.
- Adequate memory
- With Q4_K_M, allow about 5 GB per 7B model and 9 GB per 14B model. The members do not all need to fit in memory at the same time, but your experience depends on it (see the section on costs).
- Python 3.10 or later
- For this guide’s minimal script, with the requests package. For the original repository, uv and Node.js as well.
- Patience
- One council round costs at least twice as many generations as the number of members, plus one. This is not an instant chat tool.
#Step 1: choose the council and president
Choosing the members is a balancing act between diversity and memory. The president, meanwhile, mainly needs to read long contexts well: it receives the question, all the responses, and all the rankings, which can easily amount to several thousand tokens. Choose the most capable model your machine can support for this role, even if it is slower, because it is called only once per round.
7B to 8B models work well for members on a 12 GB card: one fits in memory with room for the context, and Ollama alternates between them. With 24 GB or a Mac with 48 GB of unified memory, you can move members up to 14B or keep two to three models loaded at the same time, eliminating reloads.
#Step 2: configure Ollama for multiple models
Two Ollama settings matter here. The first is the number of models kept in memory, set by the OLLAMA_MAX_LOADED_MODELS variable: if memory allows, keeping all members loaded avoids reloading them each time you switch between them. The second is the context window, num_ctx, which is short by default on Ollama: the ranking step and the president's synthesis must read several complete responses, and a context that is too small silently truncates the beginning of the prompt.
On macOS, set the same variables with launchctl setenv before restarting the application. The value of OLLAMA_MAX_LOADED_MODELS must remain consistent with your available memory: two 8B models in Q4 already use about ten GB with their context. The context itself is configured per request (the API's options.num_ctx field) or in a derived Modelfile; the next section passes it with every call.
#Step 3: a minimal council in Python
The script below reproduces the repository’s three steps using the native API of Ollama, without an interface. It shuffles the response order before ranking so the labels do not reveal the author, asks each member for a short ranking, then hands everything to the chair. Adapt the model names to those on your machine.
The original repository goes a bit further: it extracts each judge's ranking line to calculate an average rank for each response and display it next to the tabs. You can add this in a few lines by reading the “RANKING:” line from each output. Keep in mind that smaller models do not always follow this format: provide a fallback for when the line is missing.
#Step 4: adapt the original repository to Ollama
If you want the web interface, the shortest path is to use the OpenAI-compatible endpoint from Ollama, served at http://localhost:11434/v1/chat/completions. The repository backend already sends requests in this format to OpenRouter: in principle, you only need to replace the API address and model identifiers in backend/config.py, then provide a dummy key, with Ollama ignoring the authorization header.
Two points still need to be handled manually. First, context: the OpenAI-compatible endpoint has no num_ctx field, so you must either create model variants with a Modelfile that sets the context or switch the client to the native /api/chat API, which accepts options. Second, the parallelism mentioned above: the first step launches calls at the same time, which means switching to sequential execution if your members do not all fit in memory.
Several community forks have made these changes for Ollama or for other local servers. Before adopting one, check the date of the latest commit, the number of files changed compared with the original repository, and read the code that calls the model: it’s short, and that’s where the differences lie. This guide does not recommend any particular fork; their status changes too quickly.
#Memory and time cost
The calculation is simple and worth laying out before committing. For a council of N members, a complete round requires N generations in stage 1, N generations in stage 2, and one for the chair, for a total of 2N + 1 calls. The stage 2 calls and the chair’s call take longer to process than the first, because the prompt contains all the responses: prompt reading time is added to generation time.
- Three members
- Seven generations per question. If each response takes about half a minute on your machine, a round takes more than three minutes, not counting reloads.
- Minimum memory
- The council’s largest model plus its context. With 8B members in Q4 and a context of 16,000 tokens, a 12 GB card is enough, provided you keep only one model loaded.
- Comfortable memory
- All members loaded at the same time: the sum of their sizes, plus a context cache for each model. Three 8B models in Q4 require a 24 GB GPU or a Mac with 32 GB of unified memory at minimum.
- Rechargements
- When the members do not fit together, each model change costs a few seconds to load from disk. Over one round, this can happen up to 2N times. An NVMe SSD makes the cost tolerable; a slow drive makes it painful.
These rough estimates depend on your hardware, quantization, and response length: we did not measure round times for this article, and the figures above are calculation rules, not results. To evaluate your case, time a simple generation with each of your members and apply the formula.
#Council limitations and biases
The pattern is appealing because it resembles peer review. Still, resist the idea that it is necessarily more accurate than a good model on its own: the repository provides no measurement to support that, and several known biases of judge models work against it.
- Imperfect anonymization
- Labels hide the name, not the style. A model may recognize its own writing style, or that of a family it knows, and rank accordingly. Karpathy himself notes, qualitatively, that models have often preferred another model’s response to their own: this is an observation, not a guarantee.
- Position and length bias
- Research on judge models, such as Zheng et al.’s MT-Bench paper (2023), documents a preference for the first response read and for longer responses. Shuffling the order reduces the first bias; the second is harder to correct.
- Correlated errors
- Models trained on similar corpora often make the same mistakes. A council of small models can unanimously vote for a wrong answer, and the president will retain it.
- The chair remains alone
- The synthesis depends entirely on the chair model: if it hallucinates, the council cannot change that. Read the individual responses when the subject matters; that is, in fact, the purpose of the original interface’s tabs.
- Small models, long instructions
- The ranking prompt is demanding: read three or four texts, judge them, justify the decision, and follow a format. Below 7B, outputs become inconsistent and the average ranking loses its meaning.
#Real-world use cases for a local LLM Council
The overhead of 2N + 1 generations is justified when the question is rare and important, not for casual chatter. Three situations stand out among people who have adapted the pattern locally.
- Reviewing sensitive text or code
- A contract letter, a procedure, a critical function: members identify different problems, and the president consolidates them into a list. Here, the ranking matters less than the diversity of the feedback.
- Reasoned technical decision
- “Should we migrate this database?”, “what format should we use for this export?”: divergent answers are information in themselves. Ask the president to make disagreements visible instead of smoothing them over.
- Quality control for a single model
- Use the council as a jury to compare two prompt versions or two quantizations of the same model by asking it to rank outputs you produced elsewhere. This is a direct application of stage 2, without stage 1.
In all these cases, privacy is the real argument for the local version: the documents being reviewed never leave the machine, whereas the original version sends them to four different providers through OpenRouter. That is what makes the pattern interesting for a team handling internal data, provided it accepts the minutes of waiting.
#Troubleshooting
- The ranking skips a response
- The context is too short and the beginning of the prompt was truncated. Increase num_ctx (or the Modelfile) and check the Ollama logs to ensure no truncation warning appears.
- Stage 1 calls are very slow
- The members are called in parallel and compete for memory. Switch to sequential execution or reduce the council to what fits in VRAM at the same time.
- The chair answers beside the point
- Its context is the most loaded of the round. Give it a larger model or summarize the rankings before passing them on.
- Ranking format missing
- Small models forget the “RANKING:” line. Repeat the format at the end of the prompt, lower the temperature, or accept manually reading the justifications.
- Empty or English member responses
- Check that the model does not return only its reasoning phase, and specify the expected language in the question.
- Memory full after a few rounds
- OLLAMA_MAX_LOADED_MODELS is too high for the machine. Set it to 1 and let Ollama alternate.
#Go further
LLM Council is a deliberation pattern, not an agent framework: it handles neither tools, roles, nor memory. If your needs go beyond synthesizing opinions, these site guides cover the neighboring building blocks.
- CrewAI with Ollama
- When models need to divide roles and chain tasks rather than judge the same response. https://quelllm.fr/guide/crewai-ollama-multi-agents
- LiteLLM as a local gateway
- To expose multiple model servers behind a single OpenAI-compatible API, for example a council distributed across two machines. https://quelllm.fr/guide/litellm-proxy-gateway-local
- Architecture of a local AI agent
- The components to assemble around a model when you want to give it tools and memory. https://quelllm.fr/guide/agent-ia-local-architecture
- Share a Ollama server on the local network
- Host the council members on a larger machine and call them from your workstation. https://quelllm.fr/guide/ollama-serveur-reseau-local-partage
Guide written on October 12, 2026, based on Karpathy’s GitHub repository and the documentation for Ollama. No timing or quality measurements were conducted for this article; the memory figures are rough estimates in Q4_K_M. Constant, port, and model names change over time: review the sources below before copying the commands.
- GitHub repository karpathy/llm-council (README, backend/config.py, start.sh)
- Documentation Ollama (native API /api/chat, OpenAI compatibility, environment variables)
- Zheng et al., 2023: Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena (judge-model bias)
Feedback, an error, or a clarification? Let us know—it improves the guide for everyone.