OpenAI と Anthropic API の主要差分#
OpenAI API と Anthropic API は多くの概念が共通するが、細かな仕様差がある。両方を扱う実装で引っかかるポイントを整理。
主要な差分マップ#
flowchart LR
subgraph OpenAI
O1[messages 配列]
O2[tools]
O3[response_format]
O4[stream]
end
subgraph Anthropic
A1[messages 配列<br/>+ system フィールド]
A2[tools]
A3[tool_use で構造化]
A4[stream + events]
end
API 構造の違い#
メッセージとシステムプロンプト
| 項目 | OpenAI | Anthropic |
|---|---|---|
| システムプロンプト | messages 内の role:"system" |
トップレベルの system フィールド |
| ユーザー・アシスタント | messages 内の role:"user"/"assistant" |
同じ |
| メッセージ順序 | 任意 | user と assistant が交互である必要 |
Anthropic では system を別フィールドに置く。コードを共通化するなら抽象化層で吸収する。
Tool Use / Function Calling
OpenAI:
{
"tools": [
{"type": "function", "function": {"name": "...", "parameters": {...}}}
]
}
Anthropic:
{
"tools": [
{"name": "...", "description": "...", "input_schema": {...}}
]
}
スキーマの書き方が違う。parameters vs input_schema。
構造化出力
- OpenAI:
response_format: {type: "json_object"}or{type: "json_schema", json_schema: {...}} - Anthropic: Tool Use を利用して、スキーマを満たす引数を返させる方式
Anthropic には JSON Mode 相当の直接機能は少ない(ツール経由で実現)。
ストリーミングのイベント形式#
OpenAI: SSE で data: {"choices": [{"delta": {"content": "..."}}]} を流し続ける。
Anthropic: より細かいイベントタイプが定義されている。
- message_start
- content_block_start
- content_block_delta
- content_block_stop
- message_delta
- message_stop
ストリーミング処理を書くときは、それぞれのイベントに応じた処理が必要。
料金モデル#
flowchart LR
P[価格] --> I[入力トークン単価]
P --> O[出力トークン単価]
P --> C[キャッシュ割引]
P --> B[バッチ割引]
- 出力単価は入力より高い(両社とも)
- Anthropic はプロンプトキャッシュを明示的にマークする仕組み(
cache_control) - OpenAI のキャッシュは自動(同じ先頭を再利用)
- バッチ API は両社 50% 割引
モデル特性の傾向#
| OpenAI(4o / o3) | Anthropic(Opus / Sonnet) | |
|---|---|---|
| 口調 | 簡潔寄り | 丁寧・冗長寄り |
| 指示追従 | 高い | 非常に高い |
| 創造性 | 高い | 高い |
| コード生成 | 高い | 高い |
| 日本語品質 | 高い | 高い |
細かな違いは用途で評価する必要がある。評価セットで測るべき。
実装のコツ#
1. 抽象化層を必ず置く
class LLMClient:
def generate(self, system, messages, tools=None): ...
class OpenAIClient(LLMClient): ...
class AnthropicClient(LLMClient): ...
プロバイダー依存のコードをラッパーに閉じ込める。切り替えが楽になる。
2. SDK の型にはまだ互換性がない
OpenAI SDK(openai)と Anthropic SDK(anthropic)は型が違う。共通化したいなら LangChain 等のラッパーを使うか、自前で型を定義する。
3. エラー応答の形式が違う
- OpenAI:
{error: {type, code, message}} - Anthropic:
{type: "error", error: {type, message}}
エラーハンドリングも抽象化層で吸収する。
参考にすべきドキュメント#
- OpenAI: https://platform.openai.com/docs
- Anthropic: https://docs.anthropic.com
まとめ#
共通概念が多いが、細部の仕様は必ず違う。並行運用するなら抽象化層を早めに入れ、SDK 差分を閉じ込める設計にする。