AIコーディング 2026.04.29

AI同士を会話・討論させる実装ガイド【2026年版】Claude APIで自律エージェント対話を構築

タグ:マルチエージェント / Claude API / AI自動化 / 生成AI / Python

AI同士の対話とは

AI同士を「会話させる」とは、あるAIの出力を別のAIの入力として渡し続けることです。これにより:

  • 討論: 賛成AI vs 反対AIが交互に主張を交わす
  • 協調: 企画AIと実装AIが分担してドキュメントを作る
  • ゲーム: 審判AIがルールを管理しながらプレイヤーAI同士が対戦する

基本:AI討論システムの実装

# ai_debate.py
# 賛成派AI vs 反対派AIが討論する

import anthropic
import os

client = anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

def make_agent(role: str, stance: str) -> dict:
    """エージェントの設定を作成する"""
    return {
        "role": role,
        "system": f"""あなたは{role}として討論に参加しています。
立場: {stance}
ルール:
- 必ず{stance}の立場から論理的に主張してください
- 相手の意見を引用してから反論してください
- 200字以内で簡潔に
- 感情的にならず論理的に""",
        "messages": [],  # 各エージェントの会話履歴
    }

def agent_respond(agent: dict, opponent_message: str) -> str:
    """エージェントが相手の発言に対して返答する"""
    # 相手の発言を履歴に追加
    agent["messages"].append({
        "role": "user",
        "content": opponent_message
    })
    
    response = client.messages.create(
        model="claude-haiku-4-5-20251001",  # コスト節約でHaikuを使用
        max_tokens=256,
        system=agent["system"],
        messages=agent["messages"],
    )
    
    reply = response.content[0].text
    
    # 自分の返答も履歴に追加
    agent["messages"].append({
        "role": "assistant",
        "content": reply
    })
    
    return reply

def debate(topic: str, max_turns: int = 6) -> list[dict]:
    """指定したテーマでAI同士に討論させる"""
    # 2つのエージェントを作成
    agent_a = make_agent("賛成派", f"「{topic}」に賛成")
    agent_b = make_agent("反対派", f"「{topic}」に反対")
    
    transcript = []
    
    # 最初の発言
    opening = f"テーマ「{topic}」について議論を始めましょう。まず賛成派から主張をどうぞ。"
    current_message = opening
    current_speaker = agent_a
    
    for turn in range(max_turns):
        speaker_name = "賛成派" if current_speaker is agent_a else "反対派"
        
        reply = agent_respond(current_speaker, current_message)
        transcript.append({"speaker": speaker_name, "message": reply})
        
        print(f"\n{speaker_name}】")
        print(reply)
        
        # 次は相手の番
        current_message = reply
        current_speaker = agent_b if current_speaker is agent_a else agent_a
    
    return transcript

# 使用例
history = debate("AIが人間の仕事を奪う", max_turns=4)

協調型:企画+実装AIパターン

# collaborative_agents.py
# 2つのAIが協力してドキュメントを作成する

def planner_agent(task: str) -> str:
    """企画AI:タスクを分析して構成案を作る"""
    response = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=512,
        system="""あなたはコンテンツ企画担当AIです。
与えられたテーマに対して:
1. 対象読者
2. 記事の構成(見出し3〜5つ)
3. 各セクションの要点
を出力してください。実際の本文は書かないこと。""",
        messages=[{"role": "user", "content": f"テーマ: {task}"}]
    )
    return response.content[0].text

def writer_agent(plan: str, task: str) -> str:
    """ライターAI:企画に基づいて本文を書く"""
    response = client.messages.create(
        model="claude-haiku-4-5-20251001",  # ライティングはHaikuで十分
        max_tokens=1024,
        system="あなたはライターAIです。企画担当AIが作った構成案に従って、具体的な本文を書いてください。",
        messages=[{"role": "user", "content": f"""
## 元のテーマ
{task}

## 企画担当AIが作った構成案
{plan}

上記の構成案に従って、具体的な本文を書いてください。
"""}]
    )
    return response.content[0].text

# 実行例
topic = "Claude Codeを使った開発効率化"
plan = planner_agent(topic)
print("=== 企画案 ===")
print(plan)

article = writer_agent(plan, topic)
print("\n=== 本文 ===")
print(article)

コスト計算付き:トークン使用量を追跡

# metered_debate.py
# 各エージェントのトークン使用量とコストを追跡する

from dataclasses import dataclass, field

@dataclass
class CostTracker:
    model: str
    input_price: float   # $/1Mトークン
    output_price: float  # $/1Mトークン
    total_input: int = 0
    total_output: int = 0
    turns: int = 0
    
    @property
    def total_cost(self) -> float:
        return (self.total_input * self.input_price + self.total_output * self.output_price) / 1_000_000
    
    def record(self, usage: object) -> None:
        self.total_input += usage.input_tokens
        self.total_output += usage.output_tokens
        self.turns += 1

TRACKERS = {
    "claude-haiku-4-5-20251001": CostTracker("haiku", 0.80, 4.00),
    "claude-sonnet-4-5": CostTracker("sonnet", 3.00, 15.00),
}

def tracked_response(model: str, system: str, messages: list) -> str:
    response = client.messages.create(
        model=model, max_tokens=256, system=system, messages=messages
    )
    TRACKERS[model].record(response.usage)
    return response.content[0].text

def debate_with_cost(topic: str, max_turns: int = 4) -> None:
    """討論後にコストサマリーを表示"""
    # ... (debate()と同じロジックでtracked_responseを使う)
    
    # コスト表示
    print("\n=== コストサマリー ===")
    for model, tracker in TRACKERS.items():
        if tracker.turns > 0:
            print(f"{tracker.model}: ${tracker.total_cost:.5f} ({tracker.turns}ターン)")
    
    total = sum(t.total_cost for t in TRACKERS.values())
    print(f"合計: ${total:.5f} (約{int(total * 150)}円)")

debate_with_cost("生成AIの著作権問題", max_turns=4)
# 出力例:
# haiku: $0.00320 (8ターン)
# 合計: $0.00320 (約0.5円)

あわせて読みたい

参考ソース