Moving from Anthropic’s Messages API to OpenAI’s Chat Completions is a mechanical remap: the system prompt becomes a message, max_tokens stops being required, the response shape changes, and tool results go back as a role: "tool" message instead of a content block.
API concept mapping
| Concept | Anthropic | OpenAI |
|---|---|---|
| SDK | anthropic | openai |
| Auth | x-api-key + anthropic-version | Authorization: Bearer |
| Endpoint | /v1/messages | /v1/chat/completions |
| System prompt | top-level system param | messages[] with role: system |
| Max output | max_tokens (required) | max_tokens (optional) |
| Assistant text | content[0].text | choices[0].message.content |
| Stop reason | stop_reason (end_turn / max_tokens / tool_use) | finish_reason (stop / length / tool_calls) |
| Tool result | user msg with tool_result block | role: tool message |
Before / after
import anthropic
client = anthropic.Anthropic()
resp = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system="You are concise.",
messages=[{"role": "user", "content": "Explain rate limits in one line."}],
)
print(resp.content[0].text) from openai import OpenAI
client = OpenAI()
resp = client.chat.completions.create(
model="gpt-5.4",
messages=[
{"role": "system", "content": "You are concise."}, # was top-level
{"role": "user", "content": "Explain rate limits in one line."},
],
)
print(resp.choices[0].message.content) Watch for these
- System prompt moves into
messagesas arole: "system"entry. max_tokensis now optional — keep a sensible cap, but it won’t error if omitted.- Response path changes to
choices[0].message.content. - Tool calling differs: Claude’s
tool_useblock → OpenAItool_calls; return results as arole: "tool"message (withtool_call_id), not atool_resultcontent block. Portinput_schema→parameters. - Re-tune prompts — GPT models format and refuse differently than Claude.
What to do next
- Move the system prompt into the messages array; relax
max_tokens. - Update response parsing to
choices[0].message.contentand remap stop reasons. - Port tool schemas (
input_schema→parameters) and the result round-trip. - Re-price with the cost calculator; reverse route is OpenAI → Anthropic.
Frequently asked questions
What breaks most often going Anthropic → OpenAI?
Forgetting to move the top-level
system prompt into a role: system message, and reading the wrong response path — it's choices[0].message.content, not content[0].text.How do tools translate?
Claude's
tool_use content blocks become OpenAI tool_calls; tool schemas move from input_schema to parameters; and you return results as a role: tool message keyed by tool_call_id instead of a tool_result block.Is max_tokens still required?
No — it's optional on OpenAI (required on Anthropic). Keep a realistic cap to bound cost, but omitting it won't error.