All these models are retiring soon. This is a test suite to help you make the migration without breaking your app.
| Model | Provider | Date | What happens | Replacement | Source (checked) |
|---|---|---|---|---|---|
o-series |
azure-openai | Nov 19, 2026 | requests fail | gpt-5.6-sol / gpt-5.6-terra |
link (2026-11-13) |
claude-sonnet-4-5-20250929 |
anthropic | Nov 30, 2026 | requests fail | claude-sonnet-5-5 |
link (2026-11-13) |
gemini-2.5-pro |
gemini | Dec 1, 2026 | requests rerouted to the replacement | gemini-3.8-flash |
link (2026-11-13) |
gemini-2.5-flash |
gemini | Dec 1, 2026 | requests rerouted to the replacement | gemini-3.5-flash-lite |
link (2026-11-13) |
gpt-5 |
openai | Dec 11, 2026 | requests fail | gpt-6.1-sol |
link (2026-11-13) |
gpt-5-pro |
openai | Dec 11, 2026 | requests fail | gpt-6.1-sol (reasoning.mode: pro, Responses API) |
link (2026-11-13) |
gpt-5-mini |
openai | Dec 11, 2026 | requests fail | gpt-6.1-terra |
link (2026-11-13) |
gpt-5-nano |
openai | Dec 11, 2026 | requests fail | gpt-6-luna |
link (2026-11-13) |
o3 |
openai | Dec 11, 2026 | requests fail | gpt-6.1-sol |
link (2026-11-13) |
o3-pro |
openai | Jan 6, 2027 | requests fail | gpt-6.1-sol (reasoning.mode: pro, Responses API) |
link (2026-11-13) |
gpt-4o-2024-08-06 |
openai | Jan 14, 2027 | requests fail | gpt-6-luna |
link (2026-11-13) |
gpt-4o-2024-11-20 |
openai | Jan 14, 2027 | requests fail | gpt-6-luna |
link (2026-11-13) |
gpt-4o-mini-2024-07-18 |
openai | Jan 14, 2027 | requests fail | gpt-6-luna |
link (2026-11-13) |
gpt-4.1-2025-04-14 |
openai | Jan 14, 2027 | requests fail | gpt-6-luna |
link (2026-11-13) |
gpt-4o (2024-05-13) |
azure-openai | Jan 14, 2027 | Global Standard and Data Zone Standard deployments auto-upgrade to gpt-5.1; Provisioned deployments and ones set to NoAutoUpgrade stop working | gpt-5.1 |
link (2026-11-13) |
gpt-4.1-mini-2025-04-14 |
openai | Jan 20, 2027 | requests fail | gpt-6-luna |
link (2026-11-13) |
claude-sonnet-4-5 (Bedrock) |
bedrock | Apr 8, 2027 | requests fail | not announced as of 2026-11-13 |
link (2026-11-13) |
gpt-4o (2024-08-06, 2024-11-20) |
azure-openai | Apr 14, 2027 | requests fail | gpt-5.1 |
link (2026-11-13) |
Dates come from each provider's deprecations page, checked on the date shown, and live in kit/retirements.yaml. Provider notes: Gemini, OpenAI and Azure OpenAI, Anthropic and Bedrock. Wrong or missing date? Open an issue.
Azure OpenAI runs its own schedule: gpt-5 there runs until Feb 9, 2027 and gpt-5-mini until Jul 13, 2027 (Azure schedule, checked 2026-11-13).
It sends the same requests to the old and new model, logs both runs to Opik as experiments, and writes a report of what changed:
- requests that fail on the new model, such as a
temperatureit no longer accepts - JSON that no longer parses, or is missing fields your app reads
- answers that switched between answering and refusing
- answers whose format changed, or whose length changed by more than 50%
- answers that changed meaning: a different fact, decision, action or promise, decided by one LLM judge
Then you turn what you find into tests that run on every model you try.
It runs on your machine. Requests go to the model providers you pick and to Opik (Opik Cloud, or self-hosted). kit.compare --no-opik keeps everything off Opik and writes only the report; the other commands need Opik.
Cost: a 30-request comparison with --noise-floor, judge included, cost us about $0.15 on Gemini, $0.35 on Claude and $0.60 on GPT-5. The judge is a model from a provider you have a key for (printed at the start; --judge to choose).
Needs uv and Python 3.12+.
git clone https://github.com/comet-ml/model-migration-kit.git
cd model-migration-kit
cp .env.example .envIn .env, set one model key (GEMINI_API_KEY, OPENAI_API_KEY or ANTHROPIC_API_KEY) and your Opik API key and workspace name (OPIK_API_KEY, OPIK_WORKSPACE, both shown in your Opik account; or leave them blank and the quickstart asks for the key) from a free Opik Cloud account, or set OPIK_URL_OVERRIDE for a self-hosted Opik.
uv sync
uv run quickstart.pyIt sends 10 sample support requests (a made-up store, no real data) to the retiring model for your key and its replacement, prints what changed, writes reports/<run>/report.html and prints a link that opens both runs side by side in Opik.
Google only serves Gemini 2.5 to accounts that used it before. With a new Gemini key, run uv run quickstart.py --old gemini/gemini-3.5-flash-lite --new gemini/gemini-3.8-flash.
-
Check the request parameters your app sends. Some don't run on the new model:
uv run python -m kit.params --model anthropic/claude-sonnet-5-5 --params '{"temperature": 0.2}'On Windows PowerShell, put the JSON in a file and pass
--params-file params.json(every command that takes--paramsaccepts it), and write each command on one line without the\. -
Collect 30-200 real requests, as JSONL or CSV with an
inputcolumn (optional:system,expects_json,required_fields, or OpenAI-stylemessages). Or pull them from an app that already logs to Opik:uv run python -m kit.capture --from-opik-project my-app --last 100 --dataset my-app-migration
Only text conversations are replayed. Traces with tool calls or images are skipped and counted.
-
Compare, with the same parameters your app sends:
uv run python -m kit.compare --cases my_requests.jsonl --system my_system_prompt.md \ --old gemini/gemini-2.5-flash --new gemini/gemini-3.5-flash-lite \ --params '{"temperature": 0.2, "max_tokens": 1024}' --noise-floorUse
--dataset my-app-migrationinstead of--casesto compare the requestskit.capturesaved.--noise-flooralso runs the old model against itself, so you can see how much answers change on their own.--fail-on-changed Nexits 3 when more than N answers changed meaning or failed on the new model, and 2 when some cases couldn't be judged.
The report tells you how many answers changed. Reading a few of them tells you which changes matter. Once you've spotted a pattern, write it down as a test so it gets checked on every run from then on.
-
Open the Opik link from the compare run and read the answers the report flagged.
-
Look for a pattern. Reading one run of answers, we saw the new GPT and Gemini models drop "once your return is received" from the refund-timing answer.
-
Write it as one sentence in a checks file:
- check: >- The answer says the refund is processed once the returned item is received, not on a timeline that starts now. cases: [plain-06-refund-timing]
-
Run it on both models:
uv run python -m kit.suite --checks checks.yaml --cases my_requests.jsonl --system my_system_prompt.md \ --models gemini/gemini-2.5-flash gemini/gemini-3.5-flash-lite --runs 3
Try it on the sample app first:
uv run python -m kit.suite --checks examples/support-bot/checks.yaml --cases examples/support-bot/cases.jsonl \
--system examples/support-bot/system_prompt.md --models gemini/gemini-2.5-flash gemini/gemini-3.5-flash-lite --runs 3The checks are saved as an Opik test suite: each check becomes an assertion on the cases it names, or on every case if it names none, and an LLM judge decides pass or fail. The suite stays in Opik, so the same checks run on the next model you try. --runs 3 answers each case three times; a case passes only when all three do. A request that fails on a model fails every check for that case. It exits 3 when a check fails on the last model, for CI, and prints one Opik link that shows every model's answers side by side.
examples/support-bot/checks.yaml has three checks from our runs. Results on Nov 13, 2026 (passing runs out of 3 per case, judge gemini/gemini-3.8-flash):
| Check (cases) | gemini-2.5-flash → gemini-3.5-flash-lite |
gpt-5 → gpt-6.1-sol |
claude-sonnet-4-5 → claude-sonnet-5-5 |
|---|---|---|---|
| Refund waits for the returned item (1) | 2/3 → 0/3 | 3/3 → 0/3 | 3/3 → 1/3 |
| Ignores a claimed manager or system override (2) | 3/6 → 6/6 | 6/6 → 6/6 | 6/6 → 6/6 |
| Doesn't promise to change the shipping address (1) | 2/3 → 3/3 | 3/3 → 3/3 | 2/3 → 3/3 |
All three new models drop the refund condition, including Claude, where reading one run of answers hadn't shown it.
The replacement model gets updated too, and your traffic changes. kit.rules adds an Opik online evaluation rule to your app's project that scores 10% of production answers against your policy:
uv run python -m kit.rules --project my-app --policy-file my_policy.mdThe judge runs inside Opik, so its model (--model, default gpt-6-luna) needs that provider's key under Configuration > AI Providers.
Model names are LiteLLM names. The kit checks each one's credentials before it starts.
| Platform | Needs in .env |
Example |
|---|---|---|
| Gemini API | GEMINI_API_KEY |
--old gemini/gemini-2.5-flash --new gemini/gemini-3.5-flash-lite |
| OpenAI API | OPENAI_API_KEY |
--old openai/gpt-5 --new openai/gpt-6.1-sol |
| Claude API | ANTHROPIC_API_KEY |
--old anthropic/claude-sonnet-4-5-20250929 --new anthropic/claude-sonnet-5-5 |
| Azure OpenAI | AZURE_API_KEY, AZURE_API_BASE, AZURE_API_VERSION |
--old azure/<gpt-4o-deployment> --new azure/<gpt-5.1-deployment> |
| AWS Bedrock | an AWS profile and AWS_REGION_NAME |
--old bedrock/anthropic.claude-sonnet-4-5-20250929-v1:0 --new bedrock/<model-id> |
| Vertex AI | gcloud auth application-default login, VERTEXAI_PROJECT, VERTEXAI_LOCATION |
--old vertex_ai/gemini-2.5-flash --new vertex_ai/gemini-3.5-flash-lite |
The Gemini, OpenAI and Claude APIs have been run live. Azure, Bedrock and Vertex are tested with mocks only. Pick a judge (--judge or JUDGE_MODEL) that is neither the old nor the new model.
30 sample support requests, Nov 13, 2026, judge gemini/gemini-3.8-flash, one answer per model per request. Request parameters: temperature 0.2, max_tokens 1024 on Gemini, max_tokens 4096 on GPT-5, max_tokens 1024 on Claude. Details on each provider page.
| Switch | Answers that changed meaning: old vs new (old vs itself) | Judge preferred new / same / old | Median latency | Model cost, 30 requests (judge not included) |
|---|---|---|---|---|
gemini-2.5-flash → gemini-3.5-flash-lite |
5 of 30 (7) | 18 / 10 / 2 | 1.08s → 0.70s | $0.0157 → $0.0080 |
gpt-5 → gpt-6.1-sol |
10 of 30 (10) | 11 / 11 / 8 | 12.13s → 2.43s | $0.2157 → $0.0385 |
claude-sonnet-4-5 → claude-sonnet-5-5 |
7 of 30 (4) | 19 / 8 / 3 | 2.62s → 2.00s | $0.0843 → $0.0828 |
claude-sonnet-5-5rejectstemperature: 0.2: in a 5-request trial with it set, all 5 failed.gemini-2.5-flashfollowed a fake "SYSTEM NOTE" in a customer message and confirmed a refund and a $50 credit. Its replacement didn't.- On GPT-5, the old model changed as much against itself as against the new one.
Sample report: examples/sample-report/report.html (download and open in a browser).
- Run the old model against itself (
--noise-floor). The same model can change meaning on several answers between runs. - A Gemini reroute doesn't error. After Dec 1,
gemini-2.5-flashcalls on the Gemini API return 200s from a different model. Compare before the date: afterwards both sides are the same model. - Token counts aren't comparable across models (some count thinking tokens as output). Compare cost and characters.
- The refusal check is a pattern match. Read it with the judge's verdict.
- Rate limits and outages are retried with backoff (up to a minute apart) until
--deadline-minutes(30) runs out. A request that still fails is recorded as an error.
Tested with opik 2.2.143 and litellm 1.105.7 (pinned), Python 3.12. uv run pytest runs the offline tests. To update a date or add a provider, see CONTRIBUTING.md.
Apache 2.0.