Anthropic Migration Deep Dive
Overview
Migration strategies for switching to Claude from OpenAI, Google, or other LLM providers, including API mapping, prompt translation, and multi-provider abstraction.
OpenAI to Anthropic API Mapping
| OpenAI |
Anthropic |
Notes |
openai.ChatCompletion.create() |
anthropic.messages.create() |
Different response shape |
model: "gpt-4" |
model: "claude-sonnet-4-20250514" |
Different model IDs |
messages: [{role, content}] |
messages: [{role, content}] |
Same format |
functions / tools |
tools |
Similar but different schema key names |
function_call |
tool_choice |
Different naming |
response.choices[0].message.content |
response.content[0].text |
Different access path |
stream: true → yields chunks |
stream: true → SSE events |
Different event format |
System message in messages[] |
system parameter (separate) |
Claude separates system prompt |
n (multiple completions) |
Not supported |
Use multiple requests |
logprobs |
Not supported |
N/A |
Side-by-Side Code Comparison
# === OpenAI ===
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "You are helpful."},
{"role": "user", "content": "Hello"}
],
max_tokens=1024,
temperature=0.7
)
text = response.choices[0].message.content
# === Anthropic ===
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-20250514",
system="You are helpful.", # System prompt is separate
messages=[
{"role": "user", "content": "Hello"}
],
max_tokens=1024, # Required (not optional)
temperature=0.7
)
text = response.content[0].text
Tool Use Migration
# OpenAI tools format
openai_tools = [{
"type": "function",
"function": {
"name": "get_weather",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}}
}
}]
# Anthropic tools format — flatter structure
anthropic_tools = [{
"name": "get_weather",
"description": "Get weather for a city", # Required in Anthropic
"input_schema": {"type": "object", "properties": {"city": {"type": "string"}}}
}]
Multi-Provider Abstraction
from abc import ABC, abstractmethod
class LLMProvider(ABC):
@abstractmethod
def complete(self, prompt: str, system: str = "", **kwargs) -> str: ...
class AnthropicProvider(LLMProvider):
def __init__(self):
import anthropic
self.client = anthropic.Anthropic()
def complete(self, prompt: str, system: str = "", **kwargs) -> str:
msg = self.client.messages.create(
model=kwargs.get("model", "claude-sonnet-4-20250514"),
max_tokens=kwargs.get("max_tokens", 1024),
system=system,
messages=[{"role": "user", "content": prompt}]
)
return msg.content[0].text
class OpenAIProvider(LLMProvider):
def __init__(self):
from openai import OpenAI
self.client = OpenAI()
def complete(self, prompt: str, system: str = "", **kwargs) -> str:
messages = []
if system:
messages.append({"role": "system", "content": system})
messages.append({"role": "user", "content": prompt})
resp = self.client.chat.completions.create(
model=kwargs.get("model", "gpt-4"),
messages=messages,
max_tokens=kwargs.get("max_tokens", 1024)
)
return resp.choices[0].message.content
Migration Checklist
Prerequisites
- Inventory provider models, prompts, tools, response consumers, data flows, budgets, and retention rules. Obtain owner approval for the target model/workspace and rollback window.
- Define a provider-neutral contract with explicit fields for model, token budget, stop reason, tool calls, errors, usage, and correlation ID; keep provider-specific details behind the adapter.
- Prepare representative synthetic fixtures and a no-op tool registry in a sandbox. Configure redacted comparison logs and exclude prompts, completions, PII, credentials, and tool arguments.
Instructions
- Map request and response fields using the tables above, preserving semantics rather than assuming identical tokenization, tool behavior, stop reasons, or safety behavior.
- Move system instructions to the Anthropic
system parameter, make max_tokens explicit, and validate alternating message roles and tool schemas before calling the target provider.
- Run old and new providers in a shadow or replay lane with synthetic fixtures. Compare structured outcomes, latency, token/cost aggregates, refusal/guardrail decisions, and tool-call counts—not raw content in shared logs.
- Release behind a feature flag to a small canary with a bounded budget and authorized destinations. Monitor for scope, retention, error, or quality regressions.
- Promote only after acceptance evidence is approved. If any invariant fails, disable the flag and restore the prior provider adapter/configuration; delete temporary replay data.
Output
Return a migration receipt containing source/target provider classes, adapter version, mapped capabilities, fixture and comparison counts, aggregate parity metrics, canary decision, rollback reference, and cleanup/retention status. Redact all prompt, completion, tool, account, and credential values.
Error Handling
- If a source capability has no Anthropic equivalent (for example, multiple completions or logprobs), fail the compatibility check and choose an explicit product fallback; do not silently drop it.
- If tool schemas or role ordering are invalid, reject before the API call and report the field path without including user content.
- If shadow results diverge beyond the approved threshold, freeze rollout and keep the source provider active while the prompt/adapter is corrected.
- If rollback cannot be verified, do not widen the canary; preserve the last known-good deployment and escalate to the owner.
Examples
Replay a synthetic fixture with one system instruction, one user turn, and a no-op get_weather tool through both adapters. Record fixture_count=1; tool_side_effects=0; source_status=pass; target_status=pass; content_logged=0; canary=approved, while comparing content through an access-controlled evaluator rather than the receipt.
Resources
Next Steps
For advanced debugging, see anth-advanced-troubleshooting.
1---2name: anth-migration-deep-dive3description: Migrate to Claude API from OpenAI, Gemini, or other LLM providers. Use when switching from GPT-4 to Claude, migrating from Text Completions, or building a multi-provider abstraction layer. Trigger with phrases like "migrate to claude", "openai to anthropic", "switch from gpt to claude", "multi-provider llm".4license: MIT5---6# Anthropic Migration Deep Dive
7
8## Overview
9
10Migration strategies for switching to Claude from OpenAI, Google, or other LLM providers, including API mapping, prompt translation, and multi-provider abstraction.
11
12## OpenAI to Anthropic API Mapping
13
14| OpenAI | Anthropic | Notes |
15|--------|-----------|-------|
16| `openai.ChatCompletion.create()` | `anthropic.messages.create()` | Different response shape |
17| `model: "gpt-4"` | `model: "claude-sonnet-4-20250514"` | Different model IDs |
18| `messages: [{role, content}]` | `messages: [{role, content}]` | Same format |
19| `functions` / `tools` | `tools` | Similar but different schema key names |
20| `function_call` | `tool_choice` | Different naming |
21| `response.choices[0].message.content` | `response.content[0].text` | Different access path |
22| `stream: true` → yields chunks | `stream: true` → SSE events | Different event format |
23| System message in `messages[]` | `system` parameter (separate) | Claude separates system prompt |
24| `n` (multiple completions) | Not supported | Use multiple requests |
25| `logprobs` | Not supported | N/A |
26
27## Side-by-Side Code Comparison
28
29```python
30# === OpenAI ===
31from openai import OpenAI
32client = OpenAI()
33response = client.chat.completions.create(
34 model="gpt-4",
35 messages=[
36 {"role": "system", "content": "You are helpful."},
37 {"role": "user", "content": "Hello"}
38 ],
39 max_tokens=1024,
40 temperature=0.7
41)
42text = response.choices[0].message.content
43
44# === Anthropic ===
45import anthropic
46client = anthropic.Anthropic()
47response = client.messages.create(
48 model="claude-sonnet-4-20250514",
49 system="You are helpful.", # System prompt is separate
50 messages=[
51 {"role": "user", "content": "Hello"}
52 ],
53 max_tokens=1024, # Required (not optional)
54 temperature=0.7
55)
56text = response.content[0].text
57```
58
59## Tool Use Migration
60
61```python
62# OpenAI tools format
63openai_tools = [{
64 "type": "function",
65 "function": {
66 "name": "get_weather",
67 "parameters": {"type": "object", "properties": {"city": {"type": "string"}}}
68 }
69}]
70
71# Anthropic tools format — flatter structure
72anthropic_tools = [{
73 "name": "get_weather",
74 "description": "Get weather for a city", # Required in Anthropic
75 "input_schema": {"type": "object", "properties": {"city": {"type": "string"}}}
76}]
77```
78
79## Multi-Provider Abstraction
80
81```python
82from abc import ABC, abstractmethod
83
84class LLMProvider(ABC):
85 @abstractmethod
86 def complete(self, prompt: str, system: str = "", **kwargs) -> str: ...
87
88class AnthropicProvider(LLMProvider):
89 def __init__(self):
90 import anthropic
91 self.client = anthropic.Anthropic()
92
93 def complete(self, prompt: str, system: str = "", **kwargs) -> str:
94 msg = self.client.messages.create(
95 model=kwargs.get("model", "claude-sonnet-4-20250514"),
96 max_tokens=kwargs.get("max_tokens", 1024),
97 system=system,
98 messages=[{"role": "user", "content": prompt}]
99 )
100 return msg.content[0].text
101
102class OpenAIProvider(LLMProvider):
103 def __init__(self):
104 from openai import OpenAI
105 self.client = OpenAI()
106
107 def complete(self, prompt: str, system: str = "", **kwargs) -> str:
108 messages = []
109 if system:
110 messages.append({"role": "system", "content": system})
111 messages.append({"role": "user", "content": prompt})
112 resp = self.client.chat.completions.create(
113 model=kwargs.get("model", "gpt-4"),
114 messages=messages,
115 max_tokens=kwargs.get("max_tokens", 1024)
116 )
117 return resp.choices[0].message.content
118```
119
120## Migration Checklist
121
122- [ ] Map model names (GPT-4 → Claude Sonnet, GPT-3.5 → Claude Haiku)
123- [ ] Move system prompts from `messages[]` to `system` parameter
124- [ ] Update response access path (`.choices[0].message.content` → `.content[0].text`)
125- [ ] Make `max_tokens` explicit (required in Anthropic, optional in OpenAI)
126- [ ] Update tool definitions to Anthropic format
127- [ ] Test prompt behavior (Claude may respond differently to same prompts)
128- [ ] Update error handling for Anthropic error types
129
130## Prerequisites
131
132- Inventory provider models, prompts, tools, response consumers, data flows, budgets, and retention rules. Obtain owner approval for the target model/workspace and rollback window.
133- Define a provider-neutral contract with explicit fields for model, token budget, stop reason, tool calls, errors, usage, and correlation ID; keep provider-specific details behind the adapter.
134- Prepare representative synthetic fixtures and a no-op tool registry in a sandbox. Configure redacted comparison logs and exclude prompts, completions, PII, credentials, and tool arguments.
135
136## Instructions
137
1381. Map request and response fields using the tables above, preserving semantics rather than assuming identical tokenization, tool behavior, stop reasons, or safety behavior.
1392. Move system instructions to the Anthropic `system` parameter, make `max_tokens` explicit, and validate alternating message roles and tool schemas before calling the target provider.
1403. Run old and new providers in a shadow or replay lane with synthetic fixtures. Compare structured outcomes, latency, token/cost aggregates, refusal/guardrail decisions, and tool-call counts—not raw content in shared logs.
1414. Release behind a feature flag to a small canary with a bounded budget and authorized destinations. Monitor for scope, retention, error, or quality regressions.
1425. Promote only after acceptance evidence is approved. If any invariant fails, disable the flag and restore the prior provider adapter/configuration; delete temporary replay data.
143
144## Output
145
146Return a migration receipt containing source/target provider classes, adapter version, mapped capabilities, fixture and comparison counts, aggregate parity metrics, canary decision, rollback reference, and cleanup/retention status. Redact all prompt, completion, tool, account, and credential values.
147
148## Error Handling
149
150- If a source capability has no Anthropic equivalent (for example, multiple completions or logprobs), fail the compatibility check and choose an explicit product fallback; do not silently drop it.
151- If tool schemas or role ordering are invalid, reject before the API call and report the field path without including user content.
152- If shadow results diverge beyond the approved threshold, freeze rollout and keep the source provider active while the prompt/adapter is corrected.
153- If rollback cannot be verified, do not widen the canary; preserve the last known-good deployment and escalate to the owner.
154
155## Examples
156
157Replay a synthetic fixture with one system instruction, one user turn, and a no-op `get_weather` tool through both adapters. Record `fixture_count=1; tool_side_effects=0; source_status=pass; target_status=pass; content_logged=0; canary=approved`, while comparing content through an access-controlled evaluator rather than the receipt.
158
159## Resources
160
161- [Anthropic vs OpenAI Migration](https://docs.anthropic.com/en/docs/about-claude/models)
162- [Messages API Reference](https://docs.anthropic.com/en/api/messages)
163
164## Next Steps
165
166For advanced debugging, see `anth-advanced-troubleshooting`.