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ペイロードをログに記録します。複雑なアプリケーションコード内よりも、生のログの方が重複するロールを特定しやすいことが多いです。

