Claude Opus 4.6 vs Codex GPT-5.4: сравнение AI-кодеров на Go-задачах
Последние месяцы я использую два AI-инструмента для повседневной разработки: Claude Code (Anthropic, текущая модель Opus 4.6) и Codex CLI (OpenAI, текущая модель GPT-5.4). Оба работают в терминале, оба умеют читать файлы, запускать тесты и писать код. Но ведут себя по-разному.
На реальной задаче в рабочем проекте я заметил, что Codex на medium effort быстрее находит root cause бага и предлагает более короткий фикс, чем Claude на high effort с контекстом в миллион токенов. Это показалось неожиданным — и я решил проверить наблюдение на контролируемых задачах.
Сразу оговорюсь: два бенчмарка — не статистика. Выводы ниже — наблюдения, а не доказательства. Для полноценного сравнения нужно больше задач, разные типы (диагностика, рефакторинг, работа с большой кодовой базой) и повторные запуски. Тем не менее, даже два эксперимента показали интересные паттерны.
Методология
Обе модели получают одинаковый промпт с описанием задачи. Работают в изолированных директориях, параллельно. Замеряю wall time, количество tool calls, размер финального кода и прохождение тестов.
| Параметр | Claude | Codex |
|---|---|---|
| Модель | claude-opus-4-6 (1M context) | gpt-5.4 |
| Effort | high (subagent) | medium |
| Режим | Claude Code Agent (feature-implementer) | codex exec (full-auto) |
Задачи взяты из Exercism Go track — готовые тесты, чёткая спецификация, самодостаточность.
Задача 1: Tournament (средняя сложность)
Реализовать функцию Tally(io.Reader, io.Writer) error — парсинг результатов
футбольного турнира, подсчёт статистики, вывод форматированной таблицы.
Обработка комментариев, пустых строк, невалидного ввода.
Результаты
| Метрика | Claude | Codex |
|---|---|---|
| Время | ~38 сек | ~60 сек |
| Тесты | 17/17 | 17/17 |
| Размер кода | 111 строк | 113 строк |
| С первой попытки | Да | Да |
Оба решения используют один и тот же подход: bufio.Scanner +
map[string]*struct + sort.Slice. Различия косметические:
- Codex выделил helper-функции (
recordWin,recordDraw,standingsFor), использовалswitchвместоif/else if, обернул ошибки через%w - Claude добавил явную валидацию спецсимволов в именах команд
Вердикт: ничья. Задача слишком проста, чтобы выявить разницу — оба решают её с первой попытки за минуту.
Задача 2: React (высокая сложность)
Реализовать reactive system: input cells с изменяемым значением, compute cells с зависимостями от других ячеек, автоматическое распространение изменений по графу зависимостей, callbacks с возможностью отмены. Включая diamond dependency problem — callback должен сработать один раз, даже если ячейка зависит от изменённого input через несколько путей.
Это уже архитектурная задача: нужно спроектировать граф зависимостей, topological sort для пропагации, механизм callbacks.
Результаты
| Метрика | Claude | Codex |
|---|---|---|
| Время | ~148 сек | ~84 сек |
| Тесты | 14/14 | 14/14 |
| Размер кода | 221 строка | 165 строк (-26%) |
| Tool calls | 30 | ~12 |
| Токены | 68K | 23K |
Оба решения корректны — все 14 тестов проходят с -race. Но архитектура
принципиально отличается.
Как решил Claude (221 строка)
Четыре типа: reactor, cell (базовый), inputCell (embedding), computeCell
(расширенный). Отдельные baseDependencies и computeDependencies. Две функции
вычисления: compute1 и compute2. Пропагация — итеративная: собрать все
зависимые ячейки, затем в цикле обновлять те, чьи зависимости уже обновлены,
пока не останется необновлённых. В худшем случае O(n^2).
Helper getBaseCell() с type switch извлекает базовый *cell из inputCell
или computeCell. Canceler использует self-referencing pointer trick — хранит
указатель на себя как ключ map.
Как решил Codex (165 строк)
Три типа: reactor, cell (единый для input и compute), canceler. Input от
compute отличается наличием compute func() int — closure, которая захватывает
зависимости при создании. Никаких compute1/compute2, никакого getBaseCell.
Пропагация — DFS для сбора достижимых ячеек, затем сортировка по ID создания. Поскольку зависимости всегда создаются раньше зависимых ячеек, сортировка по ID гарантирует правильный порядок — элегантная замена полноценного topological sort. O(n log n).
Callbacks откладываются: сначала полная пропагация всех значений, потом вызов callbacks. Это гарантирует, что callback видит стабильное состояние системы.
Canceler — простой nil-check: Cancel() обнуляет ссылку на cell, повторный
вызов безопасен.
Ключевые различия
| Аспект | Claude | Codex |
|---|---|---|
| Типы | 4 (cell, inputCell, computeCell, canceler) | 3 (reactor, cell, canceler) |
| Compute function | Отдельные compute1/compute2 | Единая closure func() int |
| Topological sort | Итеративная convergence O(n^2) | Sort by creation ID O(n log n) |
| Callbacks | Во время пропагации | После полной пропагации |
| Type assertions | getBaseCell() type switch | Прямой dep.(*cell) |
Решение Codex проще, короче и алгоритмически лучше. Трюк с сортировкой по ID создания — красивое решение, которое Claude не нашёл, выбрав более “академический” подход с итеративной convergence.
Что я думаю
Два бенчмарка — недостаточно для выводов. Это exploratory эксперимент, не научное исследование. Нужны задачи на диагностику багов, работу с большими кодовыми базами, рефакторинг, iterative refinement. Возможно, на других типах задач расклад будет обратным.
Тем не менее, наблюдения совпадают с моим опытом на реальных проектах:
Codex на medium effort тратит меньше токенов на compliance и больше — на задачу. У моей конфигурации Claude Code загружено ~900 строк правил и чеклистов. Это полезно для production-кода, но на бенчмарке означает, что модель тратит ресурсы на соблюдение TDD-цикла, pattern-first алгоритма, pre-commit чеклиста — вместо того чтобы просто писать код. Codex получает минимальный системный промпт и тратит все токены на решение.
Codex склонен к более простым архитектурным решениям. Единый тип вместо иерархии, closure вместо отдельных полей, sort by ID вместо iterative convergence. Это может быть свойством модели, а может — следствием medium effort: меньше “думает”, меньше over-engineers.
Claude более “defensive” и формальный. Отдельные типы для input и compute, explicit type safety, больше комментариев. Для большого проекта с командой это может быть преимуществом. Для решения задачи — overhead.
После этого эксперимента я упростил свои rule-файлы для Claude Code (с 777 до 436 строк) и добавил “Fast Path” в workflow — для багфиксов и задач с понятной реализацией модель пропускает обязательный TDD-цикл и code review loop. Посмотрим, как это повлияет на скорость.
Воспроизведение
Задачи из Exercism Go track : Tournament , React .
Запуск Claude Code:
# Через Agent (feature-implementer subagent)
# Промпт с описанием задачи + "run go test -v -race ./..."
Запуск Codex:
codex exec -m gpt-5.4 \
--dangerously-bypass-approvals-and-sandbox \
-C /path/to/exercise \
"описание задачи"