惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Google DeepMind News
Google DeepMind News
G
Google Developers Blog
博客园 - 三生石上(FineUI控件)
B
Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hugging Face - Blog
Hugging Face - Blog
C
Check Point Blog
V
V2EX
Vercel News
Vercel News
U
Unit 42
Recent Announcements
Recent Announcements
Last Week in AI
Last Week in AI
J
Java Code Geeks
WordPress大学
WordPress大学
罗磊的独立博客
I
InfoQ
阮一峰的网络日志
阮一峰的网络日志
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
小众软件
小众软件
M
MIT News - Artificial intelligence
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Apple Machine Learning Research
Apple Machine Learning Research
Martin Fowler
Martin Fowler
云风的 BLOG
云风的 BLOG

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания
Codex 5.3 vs Claude Opus 4.6 на реальном Java-монолите
NickAlister · 2026-05-15 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение9 мин

Охват и читатели2

Кейс

Дисклеймер

У меня всё никак не было времени довести эту статью до публикации и уже можно было бы делать новое сравнение на новых моделях (финальное сравнительное ревью я делал 19 апреля 2026 года). К тому же Opus 4.6 тогда был прямо перед запуском Opus 4.7, и у меня есть субъективное ощущение, что перед выходом новой версии старая начинает тупеть, потому мои результаты могут сильно отличаться от ваших. Нужно также понимать, что claude и codex могут работать по-разному в зависимости от времени суток, региона, нагрузки, текущей версии модели и фазы луны. Такое сравнение может устаревать буквально за час. Результат будет другим для других задач, языка программирования, набора тулов, MCP, промптов, документации, размера проекта.

Предыстория

В статье «Вайбкодинг — это гемблинг» я обещал, что расскажу больше про свои эксперименты при разработке многомодульного монолитного java-проекта https://github.com/NGirchev/open-daimon с разными AI-тулами. Купив подписку claude за 100 баксов для личного использования, я заметил, что поначалу он работал хорошо, а затем токены стали заканчиваться слишком быстро, и я хотел альтернатив. В это время рабочая codex подписка казалась экономнее, и я захотел сравнить 2 подписки на своём личном проекте с личными аккаунтами. К счастью, в этот момент OpenAI предложила мне месяц бесплатной базовой подписки ($20).

<cut />

В тот момент в моём проекте я уже частично перевёл логику агента из библиотеки Spring AI на самописную FSM и ReAct-паттерн. Я решил понемногу отказываться от Spring AI, потому что memory, которую они поставляют, меня не устраивает, саммаризацию пришлось делать самому, их агентский loop скрытый, кеширование промптов не работает, часть метаинформации не пробрасывается, но отказ от Spring AI я опишу в будущих статьях, не об этом сейчас.

Так вот, код всё ещё не работал как надо, было много багов. И я решил, раз claude не справляется, почему бы не дать шанс codex.

Что именно сравнивалось

Я сделал так: целиком скопировал проект в соседнюю папку, создал отдельные ветки opus_4_6 и codex_5_3 и запустил агентов с одинаковым не слишком подробным промптом - чистый вайбкодинг. Я не читал промежуточных результатов, всегда говорил ему: "делай как считаешь нужным", потом запускал ревью, потом просил починить и так до тех пор, пока сценарий не был успешен и не были устранены все замечания, кроме minor. Просто ждал результата и указал как единственный критерий - прохождение всех тестов, включая e2e, которые заранее были написаны и работали со Spring AI loop.

Cross review Opus и Codex

Область

opus_4_6

codex_5_3

Кто сильнее

Фильтрация thinking и <tool_call> в стриминговом выводе пользователю в Telegram

Отдельный StreamingAnswerFilter режет служебный мусор до отправки события в UI

Часть логики размазана по stream-обработке и post-processing

opus_4_6

Защита от зависшего AI-stream

Нет timeout и fallback

Есть timeout + fallback на обычный chatModel.call()

codex_5_3

Понятность Telegram-рендера: что отправить, отредактировать или откатить

Чистая модель RenderedUpdate, сначала решение, потом side effects

Больше мутаций прямо в context/actions

opus_4_6

Память после рестарта и длинные треды

Память проще, без нового recovery-сценария

Восстановление истории из БД поверх уже существующей summarization

codex_5_3

Разделение progress и final answer в проектном streaming-контракте

Регрессия PARTIAL_ANSWER вместо FINAL_ANSWER_CHUNK

Контракт FINAL_ANSWER_CHUNK сохранён

codex_5_3

Тесты на chunk'и, tool calls и Telegram updates

Больше streaming-oriented тестов

Больше тестов вокруг новых фич

opus_4_6

Готовность к merge по ./mvnw verify -P e2e

Зелёный

Падал в REST test slice

opus_4_6

Полезные фичи сверх самого streaming loop

Меньше

Больше: URL hygiene, history recovery, batching для Telegram progress

codex_5_3

Если совсем коротко по таблице: opus_4_6 лучше держит архитектуру streaming-пайплайна, а codex_5_3 быстрее делает прикладные фичи, но вместе с ними и дополнительную сложность, и concurrency-риски.

Но тут сразу важная и смешная оговорка. Когда я позже попросил вывести sequence diagram / цепочку вызовов, выяснилось, что часть красивого архитектурного кода в opus_4_6, которую он расхваливал в review, вообще не запускалась. Тесты проходили не потому, что новый ReAct/FSM streaming-flow был правильно встроен, а потому что старый Spring AI streaming всё ещё работал и закрывал e2e-сценарии.

Но давайте всё равно представим, что opus_4_6 смог бы найти свои проблемы вовремя и дописал бы свою классную архитектуру.

Рассмотрим подробнее, что же нашли ИИ на review.

Review opus_4_6 ветки

В opus_4_6 лучше всего получилась граница между сырым потоком от модели и текстом, который уже можно показывать человеку.

Вся история с <think> и <tool_call> должна быть удалена в некоторых режимах до того, как пользователь увидит текст. В таких режимах отображается только финальный ответ пользователю. И вот тут StreamingAnswerFilter был на правильном месте: перед эмитом события в Telegram.

LLM в stream mode не отдаёт аккуратные готовые предложения. Она может прислать <th, потом следующим чанком ink>, потом кусок внутреннего reasoning, потом закрывающий тег. Поэтому недостаточно просто в конце взять полный текст и удалить из него <think>. К этому моменту кусок уже мог улететь пользователю.

У opus_4_6 идея была примерно такая:

StreamingAnswerFilter filter = new StreamingAnswerFilter();

chatModel.stream(prompt)
        .map(chunk -> chunk.getResult().getOutput().getText())
        .map(filter::feed)
        .filter(visibleText -> !visibleText.isBlank())
        .doOnNext(visibleText ->
                ctx.emitEvent(AgentStreamEvent.partialAnswer(visibleText, iteration)))
        .blockLast();

String tail = filter.flush();
if (!tail.isBlank()) {
    ctx.emitEvent(AgentStreamEvent.partialAnswer(tail, iteration));
}

То есть дальше по цепочке идёт уже очищенный текст. Если модель прислала что-то такое:

"Ответ: "
"<th"
"ink>internal reasoning</think>"
" результат"
"<tool_call>...</tool_call>"

то Telegram/UI должен увидеть только:

Ответ:  результат

А в codex_5_3 часть логики была ближе к обработке stream chunk'ов и частично добивалась уже post-processing'ом. Упрощённо опасное место выглядит так:

StringBuilder fullText = new StringBuilder();

chatModel.stream(prompt)
        .map(chunk -> chunk.getResult().getOutput().getText())
        .doOnNext(delta -> {
            fullText.append(delta);
            ctx.emitEvent(AgentStreamEvent.partialAnswer(delta, iteration));
        })
        .blockLast();

String sanitized = sanitizeFinalAnswerText(fullText.toString());

sanitizeFinalAnswerText(...) потом может всё правильно вычистить, но для Telegram это уже поздно. delta уже могла попасть наружу.

opus_4_6 создал TelegramBuffer, построил renderer вокруг RenderedUpdate: сначала решаем, что надо сделать с сообщением, и только потом отдельный слой реально идёт в Telegram API.

RenderedUpdate update = renderer.render(event, context);
telegramActions.apply(update, context);

В codex_5_3 больше логики было завязано на мутацию context/actions. На таком streaming-flow оно быстрее становится местом, где ты боишься трогать один сценарий, потому что можешь сломать другой, а второй поток просто всё сломает.

Review codex_5_3 ветки

Первое - timeout для stream-вызова. В opus_4_6 был обычный blockLast(). Если LLM-провайдер начал stream и не завершил его нормально, обработка могла зависнуть. В codex_5_3 стоял blockLast(Duration.ofMinutes(10)), а если stream не успел отдать ни одного чанка, код уходил в обычный chatModel.call(...). Если часть чанков уже пришла, ситуация сложнее. Но для пустого или не стартовавшего stream это полезная страховка.

Второе - восстановление истории после рестарта. codex_5_3 добавил сценарий, где пустая in-memory ChatMemory восстанавливается из уже сохранённой истории разговора в БД. Для пользователя Telegram это выглядит просто: бот не должен забывать разговор только потому, что приложение перезапустилось. Пользователь пишет в тот же чат и ожидает, что агент хотя бы примерно помнит прошлый контекст. Т.е. история была и раньше, но могла не подтянуться из бд в некоторых сценариях. А ещё если при восстановлении истории сообщения могли задублироваться, кодекс добавил дедупликацию и гарантировал загрузку истории.

Третье - проверка ссылок. В codex_5_3 появился UrlLivenessCheckerImpl, который отсекает явно нерабочие URL перед показом пользователю. Это не решает проблему галлюцинированных ссылок полностью: живая ссылка всё ещё может быть нерелевантной, но мёртвые ссылки теперь можно вычистить.

Четвёртое - правила ReAct prompt'а были вынесены из основного agent loop, а для простых запросов появился отдельный путь без tools и итераций. Это давало больше контроля над тем, какие инструкции получает модель: язык ответа, обязательные аргументы tool calls, история предыдущих шагов. Правда, тесты на этот слой были минимальными.

Итого

opus_4_6 был лучше именно в архитектуре streaming pipeline: как идут чанки, где режутся теги, где принимается решение по Telegram-сообщению, где делится длинный текст. А codex_5_3 быстрее тащил новые возможности и исправлял баги, ничего не переусложнял, но, возможно, со временем код бы был менее поддерживаемым. Почему opus_4_6 не дошёл до всех этих проблем? Вероятно они просто не воспроизвелись, ведь код работал по старому и не вызывал новый код.

Баги, которые ИИ нашли друг у друга

Что могло сломаться

opus_4_6

codex_5_3

Риск

Stream может зависнуть без timeout, и пользователь просто не дождётся ответа

Да

Нет

Высокий

История диалога может побиться при параллельных обращениях

Нет

Да

Высокий

Telegram progress может потерять кусок ответа или показать его не в том порядке

Риск ниже

Риск выше

Высокий

Thinking/status и финальный ответ могут смешаться в одном streaming-flow

Да

Нет

Высокий

Полный ./mvnw verify -P e2e не проходит

Нет

Да

Блокер

Генерация слабо отменяется, даже если результат уже не нужен

Да

Да

Средний

Чем больше recovery, URL-checking и Telegram batching, тем больше нового состояния

Меньше

Больше

Средний

Вывод

Я не стал брать ни одну из двух веток целиком, а взял лучшее из обеих.

Второй эксперимент: codex_5_3 против gpt_5_5

После сравнения Codex и Claude я окончательно убедился, что Codex подходит для моих задач больше и выходит дешевле. Поэтому на следующем эксперименте я сфокусировался на сравнении двух моделей. К тому моменту вышла gpt_5_5, и раз уж codex_5_3 оказался неплох, то стоило сравнить его с новой моделью.

Я взял codex ветку после 1 эксперимента как основную, но тесты всё ещё были нестабильны: бот плохо справлялся со стримингом ответа в Telegram. Я снова целиком скопировал проект в соседнюю папку и сделал ветки codex_5_3 и gpt_5_5.

Review codex_5_3

codex_5_3 взялся за ту часть кода, которая принимает сообщение пользователя и отправляет ответ в Telegram. Поэтому результат был не самый аккуратный, но полезный.

В этой ветке бот уже не пытался редактировать Telegram-сообщение после каждого нового фрагмента мгновенно. Он копил промежуточный текст, отправлял обновления реже, а финальный ответ показывал отдельно, как и планировалось. Во второй итерации он ещё и начал обрабатывать часть случаев 429 Too Many Requests: если Telegram просил подождать несколько секунд, бот ждал и пробовал отправить сообщение снова, так как у Telegram есть лимиты.

Результат gpt_5_5

gpt_5_5 предложил более аккуратную идею: отделить ход работы, финальный ответ и ошибку от кода, выделяя абстракции. Но как и в прошлый раз, код считай не выполнялся и багов он не нашёл.

Вывод

Уже второй раз сильная модель создала бесполезный код за большее время, и это не просто так. Архитектурно эти модели мощнее, но так как подход был исключительно вайбкодерский, без нормального контроля модель скатывалась и не доводила дело до конца.

А codex_5_3, модель исключительно хорошая для разработческих задач, она шла и выполняла всё в цикле, как профессиональный разработчик, с фокусом на деталях. На работе я также использовал её в assistant coding и она также справлялась с большинством задач.

Так что сильная модель нужна для абстрактных задач, ресёрча, планинга, но сделать что-то рабочее без жёсткого контроля у неё получается хуже, несмотря на все тулы и документацию. С другой стороны, в моём другом frontend-проекте именно Opus создал работающий сайт без дополнительного контекста и контроля, а значит нужно больше экспериментов.

Это поведение, кстати, подтверждается документацией Anthropic opusplan-model-settingopusplan в Claude Code: Opus используется для plan mode, а для execution Claude Code переключается на Sonnet. Также они добавили /adviser на модели Opus. Потому скажу, что мой эксперимент был для достаточно специфичного условия - запускать агента автономно с минимальным числом самописных сабагентов. И лично для меня это показательно.

Codex-5-3, запущенный в телеграм-боте без доп. контроля исключительно для автономного development'a для java пет-проекта в моём сетапе, подходит лучше. Для всего остального придётся экспериментировать, писать тестовые harness'ы.