n4nAI

Migrating from Claude 3.5 Sonnet to Claude 4

Practical step-by-step guide to migrating from Claude 3.5 Sonnet to Claude 4: inventory, config changes, testing, and verification for engineers.

n4n Team4 min read954 words

Audio narration

Coming soon — every post will get a voice note here.

Migrating from Claude 3.5 Sonnet to Claude 4 is not a simple model string swap. The new major version changes default context limits, tool-use contracts, and possibly rate limits that will break silent assumptions in your codebase. This guide walks through a hardened migration path you can execute without downtime.

Step 1: Inventory Your Current Claude 3.5 Sonnet Integrations

Before changing anything, find every place that pins the old model. In a typical Python service this is a constant, an environment variable, or a hardcoded string in a request builder.

grep -rn "claude-3-5-sonnet" ./src ./config
grep -rn "claude_3_5_sonnet" ./src ./config

Record the exact model IDs in use (e.g., claude-3-5-sonnet-20241022). Note any logic that branches on model name—timeout tuning, retry budgets, or prompt templates keyed by version. If you call Anthropic through a gateway, check the routing directives you send. When migrating from Claude 3.5 Sonnet to Claude 4, you must also capture the max_tokens and system handling per call site, because those are the first things to drift.

Document the call sites in a table: file, function, model ID, max_tokens, system prompt source. This takes an hour and prevents the classic “we missed the batch job” outage.

Step 2: Update Model Identifiers and Client Configuration

Replace the pinned ID with the Claude 4 snapshot string published by Anthropic. Do not guess the date suffix; pull it from the docs or your provider’s model list. Centralize the value:

# config/models.py
ANTHROPIC_MODEL = "claude-3-5-sonnet-20241022"  # old
CLAUDE_4_MODEL = "claude-4-2025-01-01"          # verify exact ID from Anthropic

If you route through an OpenAI-compatible endpoint such as n4n.ai, the same /v1/chat/completions shape works—just change the model field. The gateway forwards provider cache-control hints and applies fallback if Anthropic is degraded, so a single env var flip is safe behind a flag.

import os
MODEL = os.getenv("ANTHROPIC_MODEL", CLAUDE_4_MODEL)

Run a syntax check and unit tests that mock the client. Confirm no test asserts the old model string. Bump the anthropic SDK to the latest minor version; older clients may not send the required anthropic-version header for the new model family.

Step 3: Reconcile Parameter and Capability Differences

Claude 4 may default to a larger context window, but that does not mean your max_tokens ceiling should stay fixed. Anthropic’s messages.create requires max_tokens for every call; if you previously set 1024 because Sonnet truncated, Claude 4 might need a higher bound for the same task.

response = client.messages.create(
    model=MODEL,
    max_tokens=2048,  # was 1024 on 3.5 Sonnet
    temperature=0.2,
    messages=[{"role": "user", "content": prompt}],
)

Check anthropic-version header compatibility. Older SDKs may warn; upgrade to the latest anthropic package. If you rely on streaming, verify the SSE event shape hasn’t changed—Claude 4 should keep the same content_block_delta format, but write a parser test that fails on unknown fields.

If you use prompt caching via cache_control on system blocks, confirm the breakpoint behavior. Major version bumps sometimes alter how prefixes are hashed; re-send the exact cached prefix and assert the cache_read_input_tokens field appears in the response usage.

Step 4: Adapt System Prompts and Tool Use Schemas

Anthropic keeps system prompts as a top-level parameter, not a role: "system" message. When migrating from Claude 3.5 Sonnet to Claude 4, re-evaluate any prompt that exploited Sonnet’s specific phrasing tolerance. Claude 4 may follow instructions more strictly, so ambiguous directives can regress.

Tool use is the other common break. The tools array expects input_schema as JSON Schema. If you used loose types, tighten them:

{
  "name": "get_weather",
  "description": "Fetch current weather",
  "input_schema": {
    "type": "object",
    "properties": {
      "location": {"type": "string"},
      "unit": {"type": "string", "enum": ["c", "f"]}
    },
    "required": ["location"]
  }
}

Run a schema validator against recorded tool calls. Claude 4 might emit arguments that 3.5 accepted but your validator rejected; fix the schema before production. Also check that multi-turn tool result handling hasn’t changed: the tool_result content block must carry the same tool_use_id referencing the prior assistant turn.

Step 5: Implement a Shadow Testing Harness

Shadow testing catches behavior drift without user impact. Record a sample of production prompts (strip PII) and replay them against both models in a batch job.

def replay(prompt, model):
    return client.messages.create(
        model=model,
        max_tokens=2048,
        messages=[{"role": "user", "content": prompt}],
    ).content

for p in sampled_prompts:
    old = replay(p, ANTHROPIC_MODEL)
    new = replay(p, CLAUDE_4_MODEL)
    assert old and new  # basic non-empty
    log_diff(p, old, new)

Score outputs with your existing eval suite—exact match, JSON validity, or LLM-as-judge. If Claude 4 fails more than a threshold (say >2% regression on critical tasks), pause the cutover. Migrating from Claude 3.5 Sonnet to Claude 4 should improve or hold quality, not silently drop it.

Capture latency distributions in the shadow run. A 30% slowdown on long contexts is a signal to tune max_tokens or enable streaming earlier, not to abort—but you need the number before users feel it.

Step 6: Cut Over with Feature Flags and Fallback

Ship the new model behind a flag. Use a simple ratio or per-tenant toggle:

import random
def pick_model(user_id):
    if flag_enabled("claude4_rollout") and random.random() < 0.1:
        return CLAUDE_4_MODEL
    return ANTHROPIC_MODEL

Wrap calls in a retry that falls back to 3.5 Sonnet on 429 or 5xx from Anthropic. If you use a gateway with automatic fallback, this is redundant but still useful for app-level logging. Monitor error rates per model tag.

Ramp from 1% to 10% to 50% over three days, watching the dashboards from Step 5. Keep the old model ID in the binary; do not delete the constant until the migration is declared complete.

Step 7: Verify Success and Monitor Production

Verification is concrete: within 24 hours of full cutover, check three signals. First, request success rate per model should be >99.9% (or your baseline). Second, median time_to_first_token should not exceed your Sonnet baseline by more than your SLA margin. Third, business metrics (task completion, eval pass rate) should be flat or better.

curl -s https://your-metrics/api/query?q=sum(rate(llm_requests{model="claude-4-2025-01-01"}[1h]))

If metrics dip, flip the flag back. Keep the old model ID in code for at least one release cycle; Anthropic typically supports prior majors for months, but your rollback path must be instant.

Verification Checklist

  • All grep hits for old model ID removed or behind flag
  • Unit tests pass with mocked Claude 4 response shape
  • Shadow test diff shows no critical regressions
  • Flag rollout at 100% with fallback disabled after soak
  • Dashboards show stable latency and error rates
  • Cache read tokens present if caching is used

Migrating from Claude 3.5 Sonnet to Claude 4 is routine if you treat it as a controlled change rather than a string edit. Inventory, centralize, test against real traffic, and keep the escape hatch open.

Tagsclaudeanthropicmodel-migrationsonnet

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All model deprecation & version migration posts →