Anthropic 400エラーの解決方法:ロールはuserとassistantを交互に指定する必要があります

beginner🧠 AI Tools2026-06-11| Python/Node.js, Anthropic SDK, Claude 3/3.5 モデル

Error Message

anthropic.BadRequestError: Error code: 400 - {'type': 'error', 'error': {'type': 'invalid_request_error', 'message': 'messages: roles must alternate between "user" and "assistant", but found multiple "user" roles in a row'}}
#anthropic#claude#messages#conversation-history#api

Anthropic APIが厳格な理由

Claudeは、完璧な交互のリズムを期待します。メッセージをスタック(累積)させることができる一部のLLMとは異なり、AnthropicのMessages APIは会話をテニスの試合のように扱います。あなたがメッセージを送り、Claudeが返信し、またあなたが送るという流れです。このuser → assistant → userのパターンを崩すと、APIは即座にリクエストを拒否します。

通常、この400エラーは以下の3つのケースのいずれかで発生します:

  • AIが応答する前に、ユーザーが2回連続でメッセージを送信した(連投)。
  • messages配列の中に「system」プロンプトを入れようとした。
  • 会話履歴が「user」プロンプトではなく「assistant」メッセージから始まっている。

ステップバイステップの修正方法

1. システムメッセージを配列の外に出す

OpenAIのエコシステムから移行してきた場合、これはよくある罠です。AnthropicのAPIでは、システムプロンプトはトップレベルのパラメータです。メッセージ履歴リスト内のオブジェクトとして含めてはいけません。

# 誤り: これは400エラーを引き起こします
client.messages.create(
    model="claude-3-5-sonnet-20240620",
    messages=[
        {"role": "system", "content": "あなたは有能なアシスタントです"},
        {"role": "user", "content": "こんにちは!"}
    ]
)

# 正解: 専用のsystemパラメータを使用します
client.messages.create(
    model="claude-3-5-sonnet-20240620",
    system="あなたは有能なアシスタントです",
    messages=[
        {"role": "user", "content": "こんにちは!"}
    ]
)

2. 同じロールの連続するメッセージを結合する

実際のチャットアプリでは、AIが応答する前にユーザーが複数のメッセージを送信することがよくあります。これらを単純にリストに追加することはできません。代わりに、APIを呼び出す前にそれらを1つのメッセージオブジェクトに結合する必要があります。

重複するロールをマージして履歴をクリーンにする、以下のPythonヘルパー関数を使用してください:

def merge_consecutive_messages(messages):
    if not messages:
        return []
    
    merged = []
    for msg in messages:
        # 現在のロールが最後に追加したものと一致するか確認
        if merged and merged[-1]["role"] == msg["role"]:
            prev_content = merged[-1]["content"]
            curr_content = msg["content"]
            
            # 文字列を二重改行で結合
            if isinstance(prev_content, str) and isinstance(curr_content, str):
                merged[-1]["content"] = f"{prev_content}\n\n{curr_content}"
            else:
                # 画像やテキストなどの複雑なコンテンツブロックをマージ
                if isinstance(prev_content, str):
                    merged[-1]["content"] = [{"type": "text", "text": prev_content}]
                if isinstance(curr_content, str):
                    curr_content = [{"type": "text", "text": curr_content}]
                merged[-1]["content"].extend(curr_content)
        else:
            merged.append(msg)
    return merged

3. 常に「user」メッセージから開始する

Anthropicは、すべての会話がuserロールで始まることを要求します。データベースから取得した履歴がキャッシュされたassistantの応答から始まっている場合、APIは失敗します。常にリストをスライスするか先頭に追加して、ユーザープロンプトが先頭にくるようにしてください。

検証

APIを呼び出す前に、messages配列をプリントして確認してください。クリーンな交互のシーケンスになっている必要があります。例えば、すべてのロールが[user, assistant, user, assistant]の順序に従っていなければなりません。同じロールが隣接している場合は、結合ロジックに問題がある可能性があります。

実践的なヒント

  • UIのスロットリング: アシスタントが思考している間は「送信」ボタンを無効にし、ユーザーがメッセージを連投できないようにします。
  • コンテンツブロック: テキストと画像を一緒に送信する場合、2つの別々のメッセージにするのではなく、複数のコンテンツブロックを持つ単一の「user」ロールを使用します。
  • デバッグ: リクエストのJSONペイロードをログに記録します。複雑なアプリケーションコード内よりも、生のログの方が重複するロールを特定しやすいことが多いです。

Related Error Notes