Уроки миграции с OpenAI на Anthropic: что мы не ожидали
2025-11-05 · Алексей Волков
Уроки миграции с OpenAI на Anthropic
В августе мы начали постепенный перевод части трафика с OpenAI на Anthropic — cost, latency, и набор фич, которых у нас не хватало. Через 6 недель примерно половина production запросов уехала на Claude. По дороге наступили на интересные грабли.
Что мотивировало
- Prompt caching (у OpenAI на тот момент работал не для всех моделей)
- Более длинный context window
- Стабильно более предсказуемый output на structured tasks
- ~30% экономия на сопоставимой модели
Технически: одна строка, но не совсем
Если вы уже через абстракцию (LangChain, LiteLLM, свой shim), смена модели — одна строка. Но дьявол в деталях.
1. Message format
OpenAI принимает system как роль внутри messages, Anthropic — отдельным параметром:
# OpenAI
messages = [{"role": "system", "content": "..."}, {"role": "user", "content": "..."}]
# Anthropic
response = client.messages.create(
system="...",
messages=[{"role": "user", "content": "..."}],
)
Любая библиотека, которая пишет «claim-agnostic», это знает. Но свои внутренние парсеры пришлось править.
2. Tool use
Формат schema отличается, и Claude строже к обязательным полям. У нас 30% инструментов слетело в ошибки валидации после миграции — пришлось вычищать опциональные поля, которые OpenAI молча игнорировал.
3. Stop sequences ведут себя по-разному
Claude останавливается на stop sequence и не включает его в output. GPT-4 включает. Нашли это на проде через расхождение в парсере.
Качественные различия
| Задача | Winner |
|---|---|
| Structured extraction (JSON) | Claude 3 Sonnet |
| Instruction following в длинных промптах | Claude |
| Creative generation (короткие) | GPT-4 |
| Многошаговое reasoning с tool use | ≈ (зависит от схемы) |
| Русский язык | GPT-4 (на тот момент) |
Для наших задач (в основном extraction + classification + generation в корпоративном стиле) Claude выигрывал стабильно.
Что сломалось в тестах
- Snapshot-тесты на точный текст — ожидаемо, пришлось переписать в семантические (embedding similarity + judge).
- Regex-парсеры output — Claude чаще использует
—вместо-, разные кавычки, список с•вместо*. Починили нормализатором на входе в парсер. - Temperature=0 всё равно не детерминирован — ни у одного провайдера. Если сильно зависите — кешируйте сами на уровне приложения.
Operational
- Rate limits калибруются дольше. У OpenAI мы давно имели высокий tier, у Anthropic пришлось заново писать запрос в поддержку. Первые 2 недели жили на retry logic.
- Latency немного стабильнее у Anthropic на europe-west регионах.
- Streaming API — принципиально похожи, но SSE format разный. Наш frontend-парсер пришлось подправить.
Вывод
Миграция между ведущими провайдерами — проект на 4–8 недель для среднего product с 50–100 prompt-ами. Две трети времени — не код, а переписывание eval-сетов, парсеров и инструментов. Если закладываете в архитектуру «будем менять провайдера» с самого начала — сделайте абстракцию тонкой, но предусмотрите именно эти места.
← Ко всем постам