Fragments of verbose memory

冗長な記憶の断片 - Web技術のメモをほぼ毎日更新

Dec 14, 2025 - 日記

週末ハックから学ぶ「LLM Council」- 複数AIモデルの集合知を活用する新しいアプローチ

llm-council-weekend-hack cover image

Andrej Karpathy 氏が週末に"vibe code"(勢いでコーディング)したプロジェクト「LLM Council 」が面白かったので紹介します。

これは、複数の大規模言語モデル(LLM)に同じ質問を投げ、お互いの回答を匿名で評価させ、最終的に議長役のLLMが統合回答を生成するという、合議制の意思決定システムです。

単一のLLMに頼るのは、バイアスや幻覚(ハルシネーション)のリスクがあります。複数モデルの「多様な視点」を組み合わせることで、より信頼性の高い回答を得られる――そんな実験的アプローチを、シンプルなコードで実装した点が興味深いプロジェクトです。

LLM Councilとは

LLM Councilは、以下の3段階のプロセスで動作します:

  1. 質問の投げかけ: 複数のLLM(GPT、Claude、Gemini、Grokなど)に同じ質問を送信
  2. 相互評価: 各モデルの回答を他のモデルが匿名で評価(1-10点でスコアリング)
  3. 統合回答の生成: 議長役のLLMが全ての回答と評価を見て、最終的な統合回答を作成

この仕組みにより、単一モデルの偏りを減らし、複数の視点からより妥当な回答を導き出すことを目指しています。

擬人化されたLLMたちが議論している様子 異なるLLMモデルが協議し、集合知を形成するイメージ

アーキテクチャの特徴

LLM Councilの実装は非常にシンプルです:

  • バックエンド: FastAPI(Python)
  • フロントエンド: React(TypeScript)
  • LLMアクセス: OpenRouter 経由で複数のモデルに統一的にアクセス

OpenRouterは、複数のLLMプロバイダー(OpenAI、Anthropic、Google、xAIなど)のAPIを統一インターフェースで扱えるサービスです。これにより、個別にAPIキーを管理する必要がなく、コードもシンプルに保てます。

実装のポイント

コードベースは数百行程度で、主要なロジックは以下の通りです:

1. 質問の同時送信

1
2
3
4
5
6
async def get_initial_responses(question: str, models: list[str]):
    tasks = [
        call_llm(model, question)
        for model in models
    ]
    return await asyncio.gather(*tasks)

複数のLLMに対して並列でリクエストを送信し、それぞれの回答を収集します。

2. 匿名評価プロセス

各モデルは、他のモデルの回答を(モデル名を伏せた状態で)評価します。これにより、ブランドバイアスを排除できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
async def evaluate_responses(responses: list[dict], evaluator_model: str):
    # 匿名化された回答リストを作成
    anonymous_responses = [r["content"] for r in responses]
    
    # 評価プロンプトを構築
    evaluation_prompt = f"""
    以下の回答を1-10点で評価してください:
    {anonymous_responses}
    """
    
    return await call_llm(evaluator_model, evaluation_prompt)

3. 議長による統合

最後に、議長役のLLM(デフォルトではClaude)が全ての回答と評価を見て、統合回答を生成します。

1
2
3
4
5
6
7
8
9
async def generate_final_answer(question: str, responses: list[dict], evaluations: list[dict]):
    context = f"""
    質問: {question}
    
    各モデルの回答と評価:
    {format_responses_and_evaluations(responses, evaluations)}
    """
    
    return await call_llm("claude-3-opus", context + "\n最終的な回答を生成してください")

実際に動かしてみた

私も実際に動かしてみました。セットアップは以下の手順で完了します:

1. リポジトリのクローン

1
2
git clone https://github.com/karpathy/llm-council.git
cd llm-council

2. 環境変数の設定

OpenRouter でアカウントを作成し、APIキーを取得します。その後、.envファイルに設定します:

1
OPENROUTER_API_KEY=your_api_key_here

3. バックエンドの起動

1
2
3
cd backend
pip install -r requirements.txt
uvicorn main:app --reload

4. フロントエンドの起動

1
2
3
cd frontend
npm install
npm start

ブラウザで http://localhost:3000 にアクセスすると、UIが表示されます。質問を入力すると、複数のLLMの回答と評価、そして最終的な統合回答が表示されます。

実験結果から見えたこと

実際に使ってみて、以下のような気づきがありました:

多様性のメリット

同じ技術的な質問でも、各モデルで回答のアプローチが微妙に異なります。例えば、「Pythonで非同期処理を実装するベストプラクティスは?」という質問に対して:

  • GPT-4: 汎用的なパターンと理論的背景を重視
  • Claude: 実践的なコード例を多く提示
  • Gemini: エラーハンドリングやエッジケースに詳しい

これらを統合することで、より包括的な回答が得られました。

評価の公平性

匿名評価により、モデル名に左右されない評価が行われます。実際、有名なモデルでも低評価を受けることがあり、純粋に回答の質で判断されていることが分かります。

コストと速度のトレードオフ

複数のLLMを呼び出すため、当然ながらコストと時間がかかります。簡単な質問には向いていませんが、重要な意思決定や複雑な問題解決には価値があると感じました。

週末ハックの価値

このプロジェクトの素晴らしい点は、シンプルな実装で本質的なアイデアを検証していることです。

  • 数百行のコードで動作する
  • 既存のサービス(OpenRouter)を活用
  • UIも含めて完全に動作するプロトタイプ

「単一のLLMに頼るのはリスキー」というアイデアを、週末で形にして公開する――このスピード感とオープンな姿勢は、実験的プロジェクトの理想形だと思います。

実用化への課題

もちろん、実用化にはいくつかの課題があります:

コスト管理

複数のLLMを呼び出すため、APIコストが高くなります。質問の重要度に応じて、使用するモデル数を調整する仕組みが必要でしょう。

レスポンス時間

直列処理(回答収集 → 評価 → 統合)のため、時間がかかります。並列化の工夫や、評価ステップの簡略化などが考えられます。

プロンプトの最適化

議長役のLLMが生成する統合回答の質は、プロンプトの設計に大きく依存します。より効果的な統合手法の研究が必要です。

まとめ

LLM Councilは、複数のAIモデルの「集合知」を活用する面白いアプローチです。バイアスや幻覚のリスクを減らし、より信頼性の高い回答を得るという発想は、今後のAI活用において重要な視点だと思います。

コードもシンプルで、週末プロジェクトとして真似しやすい内容です。興味のある方は、ぜひGitHubリポジトリ をチェックして、実際に動かしてみてください。

単一のLLMに全てを委ねるのではなく、複数の視点を組み合わせる――この考え方は、AIとの付き合い方を再考するきっかけになるかもしれません。

参考リンク