LLM Council:让多个模型进行协商 locaux
LLM Council 是 Andrej Karpathy 于 2025 年底发布的一个小型项目:它不是把问题发送给单个模型,而是提交给多个模型;随后,每个模型在不知道回答作者身份的情况下,对其他模型的回答进行排名,再由一个“主席”模型撰写最终综合结果。该代码仓库面向通过 OpenRouter 提供服务的云端模型,但其核心模式只有约一百行代码,也可迁移到由 Ollama 提供服务的本地模型。本文介绍这三个步骤,展示如何在个人电脑上复现,详细说明其内存和时间成本,以及为什么不能假定委员会的回答一定比优秀的单模型更好。
#LLM Council:三步实现核心模式
该仓库描述了一个固定的三阶段流程。每个阶段都是一次普通的模型调用,不使用工具或记忆:唯一的技巧在于,第一阶段的输出如何为后两个阶段提供输入。
- 01初步意见用户的问题会原样分别发送给委员会的每位成员。每个成员在看不到其他回答的情况下独立作答。在原始界面中,这些回答会按模型分别显示在各个标签页中。
- 02复核与排名随后,每位成员都会收到其他成员的回答(已匿名处理,标记为“回答 A”“回答 B”……),并根据准确性和深度从最好到最差进行排名。匿名处理旨在避免模型偏袒或贬低一个已知的竞争模型。
- 03主席综合结果一名被指定为主席的模型会收到问题、全部回答和所有排名,然后撰写最终的唯一答案呈现给用户。
这一架构并不要求使用不同的模型,但这正是它的全部意义:我们依靠训练方式的多样性,让一个模型的错误能够被另一个模型发现。主席可以是成员之一,也可以是单独的模型,通常选择列表中能力最强的模型。
#Karpathy 的代码仓库包含哪些内容
在你的机器上执行操作的智能体:具备智能体能力的 Cline、MCP、n8n + Ollama、本地自动化。
- 在线空间,终身可用
- PDF + 文件
- 终身更新
github.com/karpathy/llm-council 仓库是一个本地 Web 应用,看起来像传统的聊天界面。根据撰写本文时的 README 和配置文件,它由以下部分组成:
- 一个 Python 后端(FastAPI)
- 在 backend/ 目录中:包含三个步骤的逻辑、一个连接 OpenRouter API 的 HTTP 客户端,以及将对话以 JSON 文件形式存储在 data/ 目录中的功能。依赖项使用 uv 管理。
- React 前端(Vite)
- 在 frontend/ 目录中:用于显示单独回答、排名和综合结果的界面。
- 一个配置文件
- backend/config.py 以 OpenRouter 标识符的形式列出评议会成员(COUNCIL_MODELS)和主席(CHAIRMAN_MODEL),以及所调用的 API 地址。
- 一个启动脚本
- start.sh 会同时启动后端和前端。文件 .env 中应包含一个 OPENROUTER_API_KEY。
默认配置的模型是封闭的云端模型(发布版本中的 GPT、Gemini、Claude 和 Grok 系列)。这是改成本地版本时需要更改的部分:只要 API 使用 OpenAI 推广的“chat completions”格式,其余代码并不关心是谁在回答。在按照本指南操作前,请重新阅读 README 和 config.py;项目自 2026 年 10 月 12 日以来可能已经发生变化。
#本地版本的前置条件
- Ollama 已安装并正常运行
- 服务器默认监听 http://localhost:11434。使用命令 ollama list 检查你的模型是否已显示。
- 来自不同系列的三到四个模型
- 由同一系列模型组成的委员会会失去多样性的价值。例如,可以选择一个 Qwen、一个 Llama、一个 Mistral 和一个 Gemma,并让它们的规模相近。
- 合适的内存容量
- 使用 Q4_K_M 时,每个 7B 模型约需 5 GB,每个 14B 模型约需 9 GB。成员不必同时全部驻留内存,但使用体验取决于此(参见成本一节)。
- Python 3.10 或更高版本
- 对于本指南中的最小脚本,需要 requests 包。对于原始仓库,还需要 uv 和 Node.js。
- Patience
- 一轮咨询至少需要成员数量两倍再加一次的生成次数。这不是即时聊天工具。
#第一步:选择委员会和主席
成员的选择需要在多样性和内存之间取得平衡。主席则主要需要良好地处理较长的上下文:它会收到问题、全部回答和所有排名,轻松就可能涉及数千个 token。因此,应选择机器所支持的能力最强的模型担任这一角色,即使它速度较慢也无妨,因为每轮只调用一次。
在 12 GB 显卡上,7B 到 8B 的大小适合作为成员:单个模型可以在内存中运行,并为上下文留出余量,而 Ollama 会在它们之间切换。拥有 24 GB 显存或 48 GB 统一内存的 Mac,可以将成员升级到 14B,或同时加载两到三个模型,从而消除重新加载。
#步骤 2:为多个模型配置 Ollama
这里有两个 Ollama 设置很重要。第一个是保留在内存中的模型数量,由变量 OLLAMA_MAX_LOADED_MODELS 设置:如果内存允许,让所有成员保持加载状态,可以避免每次从一个成员切换到另一个成员时重新加载。第二个是上下文窗口 num_ctx,在 Ollama 上默认较短:排名步骤和主席综合步骤都需要读取多份完整回答,过小的上下文会静默截断提示词的开头。
在 macOS 上,可以使用 launchctl setenv 设置相同的变量,然后重新启动应用程序。OLLAMA_MAX_LOADED_MODELS 的值必须与内存容量保持一致:两个采用 Q4 的 8B 模型连同上下文就已经占用大约十几 GB。上下文则可按请求设置(通过 API 的 options.num_ctx 字段),也可以在派生的 Modelfile 中设置;下一节会在每次调用时传入该值。
#第三步:用 Python 实现一个最小委员会
下面的脚本使用 Ollama 的原生 API、无需界面地复现提交的三个步骤。它会在排名前打乱回答顺序,使标签无法泄露作者身份;要求每位成员给出简短排名,然后将全部结果交给主席。请将模型名称调整为您机器上的名称。
原始代码仓库还更进一步:它会提取每位评审的排名行,为每个回答计算平均名次,并将其显示在标签页旁边。读取每个输出中的“CLASSEMENT:”行,只需几行代码即可添加此功能。但要注意,小模型并不总是遵守这种格式:如果缺少该行,应准备好备用处理逻辑。
#第四步:将原始代码仓库适配到 Ollama
如果你想要网页界面,最短路径是使用 Ollama 的 OpenAI 兼容端点,该端点在 http://localhost:11434/v1/chat/completions 提供服务。仓库后端已经以这种格式向 OpenRouter 发送请求:原则上只需在 backend/config.py 中替换 API 地址和模型标识符,然后填写一个虚拟密钥,Ollama 会忽略授权标头。
还有两点需要手动处理。首先是上下文:兼容 OpenAI 的访问端点没有 num_ctx 字段,因此必须创建使用 Modelfile 固定上下文的模型变体,或者将客户端切换到接受选项的原生 API /api/chat。其次是前面提到的并行性:第一步会同时发起调用;如果您的成员无法全部装入内存,就应改为顺序执行。
多个社区分支已经为 Ollama 或其他本地服务器进行了这些修改。在采用其中一个之前,请查看上次提交的日期、与原始仓库相比受影响的文件数量,并阅读调用模型的代码:代码很短,差异就藏在那里。本指南不推荐任何特定分支,因为它们的状态变化太快。
#内存和时间开销
这个计算很简单,开始之前值得先列出来。对于一个包含 N 名成员的咨询,一轮完整流程需要第一阶段 N 次生成、第二阶段 N 次生成,以及主席的一次生成,即 2N + 1 次调用。第二阶段的调用和主席的调用比第一次更难处理,因为提示词包含所有回答:读取提示词的时间会叠加到生成时间上。
- 三名成员
- 每个问题生成七次。如果每个回答在您的机器上大约需要半分钟,一轮就会超过三分钟,还不包括重新加载的时间。
- 最低内存
- 评议会中最大的模型及其上下文。对于采用 Q4 的 8B 成员和 16 000 个 token 的上下文,一张 12 GB 的显卡可以容纳它,前提是只保留一个已加载的模型。
- 内存充裕
- 所有成员同时加载:需要它们大小的总和,再加上每个模型的上下文缓存。三个采用 Q4 的 8B 模型至少需要一块 24 GB 的 GPU 或一台拥有 32 GB 统一内存的 Mac。
- Rechargements
- 当成员无法同时容纳时,每次切换模型都要花费几秒钟从磁盘加载。在一轮中,这种情况最多会发生 2N 次。NVMe SSD 可以让这一成本尚可接受;速度较慢的磁盘则会让它变得令人难受。
这些数量级取决于你的硬件、量化方式和回答长度:本文没有测量每轮耗时,上述数字只是估算规则,并非实测结果。要评估你的具体情况,请分别为每个成员进行一次简单生成计时,然后套用该公式。
#委员会的局限性与偏差
这种模式之所以吸引人,是因为它看起来像同行评审。然而,必须抵制认为它必然比单个优秀模型更准确的想法:该仓库没有提供任何支持这一点的测量结果,而且模型评判者的多种已知偏差也对它不利。
- 不完善的匿名化
- 标签隐藏的是名称,而不是风格。模型可能认出自己的写作方式,或认出它所熟悉的某个模型家族的写作方式,并据此进行排序。Karpathy 自己也定性地指出,模型往往更偏好另一个模型的回答,而不是自己的回答:这是观察结果,不是保证。
- 位置偏差与长度偏差
- 关于评审模型的研究,例如 Zheng 等人(2023 年)的 MT-Bench 论文,记录了人们偏好先读到的回答以及较长回答的倾向。打乱顺序可以减轻前一种偏差;后一种则很难纠正。
- 相关错误
- 在相近语料上训练的模型往往会以相同方式出错。由小模型组成的委员会可能会一致投票支持一个错误答案,而主席也会采纳它。
- 只剩主席
- 总结完全取决于主席模型:如果它产生幻觉,评议会也无法改变结果。当主题重要时,请阅读各个单独的回答;这正是原始界面选项卡的意义所在。
- 小模型,长指令
- 排名提示词要求很高:需要阅读三或四篇文本、进行判断、说明理由并遵守格式。在 7B 以下,输出会变得不稳定,平均排名也失去意义。
#本地 LLM Council 的实际使用场景
当问题少见且重要时,2N + 1 次生成所带来的额外开销是合理的;对于闲聊则不值得。在本地采用这一模式的人中,以下三种情况最为突出。
- 复核敏感文本或代码
- 一封合同函件、一套流程或一个关键函数:不同成员会发现不同的问题,主席再将它们整合成一份列表。这里,排名不如意见的多样性重要。
- 有理有据的技术决策
- “是否应迁移这个数据库”“这种导出应使用什么格式”:相互矛盾的回答本身就是一种信息。要求主席明确呈现分歧,而不是将其抹平。
- 单模型质量控制
- 将评议会用作评审员,以比较两个提示词版本或同一模型的两种量化版本,让它为您在其他地方生成的输出排名。这是步骤 2 的直接应用,不包含步骤 1。
在所有这些情况下,本地版本真正的优势在于隐私:重新阅读的文档不会离开机器,而原始版本会通过 OpenRouter 将其发送给四个不同的供应商。这使得该模式对处理内部数据的团队很有吸引力,但前提是能够接受数分钟的等待。
#故障排除
- 排名忽略了一个回答
- 上下文太短,提示词开头已被截断。请增大 num_ctx(或 Modelfile),并检查 Ollama 的日志中是否出现截断警告。
- 步骤 1 的调用非常慢
- 成员会并行调用,在内存中相互争抢。请改为顺序执行,或将评议会缩减到能够同时装入显存的规模。
- 主席答非所问
- 它的上下文在本轮中最为充实。为它提供一个更大的模型,或者在传递排名之前先将排名总结一下。
- 缺少排名格式
- 小型模型会忘记“CLASSEMENT:”这一行。请在提示词末尾重申格式、降低温度,或者接受手动阅读理由。
- 成员的回答为空或为英文
- 请确认模型不会只返回其思考阶段的内容,并在问题中明确指定所需语言。
- 运行几轮后内存已饱和
- OLLAMA_MAX_LOADED_MODELS 对这台机器来说设置得太高。将其调回 1,让 Ollama 交替运行。
#深入了解
LLM Council 是一种审议模式,而不是代理框架:它不管理工具、角色或记忆。如果您的需求超出了意见总结,这些网站指南涵盖了相邻的构建模块。
- 使用 Ollama 的 CrewAI
- 当模型需要分工并依次完成任务,而不是评判同一个回答时。https://quelllm.fr/guide/crewai-ollama-multi-agents
- 作为本地网关的 LiteLLM
- 用于让多个模型服务器通过一个兼容 OpenAI 的 API 对外提供服务,例如将评议会分布在两台机器上。https://quelllm.fr/guide/litellm-proxy-gateway-local
- 本地 AI 代理的架构
- 当希望为模型提供工具和记忆时,需要围绕模型组装的组件。https://quelllm.fr/guide/agent-ia-local-architecture
- 在本地网络上共享 Ollama 服务器
- 将评议会成员托管在更大的机器上,再从您的工作站调用它们。https://quelllm.fr/guide/ollama-serveur-reseau-local-partage
本指南于 2026 年 10 月 12 日根据 Karpathy 的 GitHub 仓库和 Ollama 的文档撰写。本文未进行任何时间或质量测量;记忆占用参考值是以 Q4_K_M 为基准的数量级估算。常量、端口和模型名称会变化:复制命令前请重新阅读下方的源代码。
- GitHub 仓库 karpathy/llm-council(README、backend/config.py、start.sh)
- Ollama 文档(原生 API /api/chat、OpenAI 兼容性、环境变量)
- Zheng 等人,2023 年:《Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena》(评审模型的偏差)
有反馈、发现了错误,或想补充说明?请告诉我们,让这份指南对每个人都更有帮助。