Как мы сократили расходы на инференс на 68%, одержимо занимаясь оптимизацией
- После оптимизации проверка высокого уровня усилий стоит $0,77 вместо $2,43 за две самые дорогие недели — на 68% меньше.
- Медианное время проверки сократилось с 4 минут 9 секунд до 1 минуты 32 секунд.
- Около 40% экономии обеспечили изменения кода, остальное — эксперименты с моделями и уровнем усилий.
Когда в апреле мы впервые рассказали в блоге о нашем ИИ-рецензенте кода, средняя проверка обходилась в вполне приемлемые 1,19 доллара. К концу августа эта сумма подскочила примерно до 2,46 доллара. Существенных изменений в архитектуре мы не вносили: координатор по-прежнему распределял задачи между теми же специализированными рецензентами, а интенсивность проверки определялась теми же уровнями риска.
Примерно в середине сентября мы поручили агентам выяснить, куда уходят токены, и резко сократить их расход. Теперь средняя проверка при высоком уровне усилий для оценки качества кода обходится всего в 0,77 доллара — на 68% дешевле, чем средние 2,43 доллара за две самые дорогие недели до начала оптимизации. Наша главная цель заключалась в снижении затрат, но заодно нам удалось оптимизировать рецензента: теперь медианное время проверки составляет всего 1 мин 32 с вместо прежних 4 мин 9 с.
Около 40% экономии обеспечили изменения и оптимизация кода рецензента, а остальное — эксперименты с моделями и уровнем усилий, который они прикладывают.
Почему стоимость проверки удвоилась
На графике ниже показана стоимость средней проверки в каждый будний день начиная с марта. При этом соотношение уровней проверки зафиксировано, чтобы данные не искажались из-за того, что в какой-то день было больше крупных проверок.

Стоимость одной проверки неуклонно росла: с 1,22 доллара в марте до 1,44 доллара в июне, 1,74 доллара в июле и, наконец, 2,32 доллара в августе. Отчасти это объясняется тем, что доля проверок на самом дорогом уровне увеличилась: с 59% в марте до 65% в августе. Полагаем, ответ прост: модели становятся гораздо лучше и мощнее. Естественно, инженеры создают более крупные и сложные изменения, поэтому больше из них попадает в категорию «полная проверка». Однако мы выяснили, что основная часть роста затрат за эти месяцы на самом деле была связана с изменением моделей.
В начале августа мы перевели всех рецензентов на модели Anthropic, из-за чего стоимость одной задачи выросла с 1,38 до 2,03 доллара. Мы приняли такое решение, поскольку в ходе наших оценок модели Anthropic лучше других справлялись именно с этой задачей.
Наш внутренний рецензент стандартов, Codex, в итоге перешёл на Claude Opus 4.7 благодаря сочетанию производительности и надёжности. В августе стоимость одной проверки для него выросла примерно с 0,25 до 0,88 доллара — теперь он обходился дороже самого агента-координатора.
Доля попаданий в кэш тоже увеличилась: с 85,7% в апреле до 97% к сентябрю. При этом количество токенов на одну проверку выросло более чем втрое — с 0,91 до 2,99 млн. Даже при низкой стоимости чтения из кэша высокий процент попаданий для втрое большего количества токенов обходится намного дороже.
Что ещё изменилось с момента нашей прошлой публикации?
Одно из самых значительных изменений — теперь рецензент работает на OpenCode v2, который представляет собой полностью переписанную с нуля версию v1. Перед тем как перевести все проверки с v1 на v2, мы запускали каждую проверку в каждом тестовом репозитории параллельно на обеих версиях, в теневом режиме для сравнения. В 98% проверенных запросов на слияние обе версии одинаково решали, одобрять ли изменения, поэтому в начале октября мы разом перевели всех на v2 и удалили код v1. Если сравнить два дня работы на одних и тех же моделях, проверки на полном уровне в v2 выполняются примерно на 13% быстрее. Сейчас мы также экспериментируем с другими способами запуска нашего внутреннего ИИ-рецензента — например, исключительно на Durable Objects с использованием pi-durable. Надеемся, скоро расскажем об этом подробнее — следите за новостями!
Так куда же уходили токены?
Непосредственно перед тем, как мы сосредоточились на оптимизации затрат, расходы на ИИ-проверки распределялись так: около 23% приходилось на выходные токены, 43% — на запись в кэш и 34% — на чтение из кэша. Иными словами, большая часть денег уходила на контекст, который модель уже видела или вскоре должна была увидеть снова.
Это вполне логично, если рассмотреть отдельный сеанс работы. Рецензент качества кода в среднем делал 16,6 вызова большой языковой модели (LLM) за одну проверку и за эти вызовы записывал в кэш 72 тыс. токенов, а считывал оттуда 1,08 млн — каждый вызов передаёт в качестве контекста весь диалог. Стоимость сеанса растёт как с количеством вызовов, так и с размером контекста, а за последние несколько месяцев мы постепенно увеличили оба показателя.
Стоит потратить несколько минут и прочитать о том, как работает кэширование промптов Anthropic. Оно позволяет кэшировать части промпта, которые уже были обработаны большой языковой моделью (LLM). Они называются префиксами, поскольку охватывают только сообщения в начале диалога, а не в его середине или конце. Благодаря этому последующий запрос может повторно использовать ранее сохранённый префикс вплоть до той части диалога, которая отличается от закэшированной. В нашем случае инструменты среды выполнения, системный промпт и начальные сообщения в сеансах ИИ-рецензента редко меняются, поэтому они отлично подходят для кэширования префиксов. Префикс сохраняется только в том случае, если в конце него стоит контрольная точка кэша. Запись в кэш стоит в 1,25 раза дороже обычного ввода, а чтение — в 0,1 раза; запись истекает через пять минут, если к ней никто не обратился.
Значит, нам нужно было решить две задачи: заставить первый запрос каждого сеанса читать из кэша, а не записывать в него, и сократить число вызовов в каждом сеансе.
Общий кэшированный префикс для всех репозиториев
Начиная с 14 сентября рецензент записывал сведения об использовании токенов в первом вызове LLM каждого рецензента, а также хеш первого системного блока в том виде, в каком он отправлялся провайдеру.
Данные показали, что первый запрос сеанса находил кэшированный префикс лишь в 14–26% случаев. Каждый сеанс начинается с одинаковых определений инструментов и промпта агента — от 11 тыс. до 21 тыс. токенов, которые не меняются во всех проверяемых нами репозиториях. Значит, почти все такие запросы должны были попадать в кэш.
Проблема оказалась в том, как OpenCode v1 формировал системный промпт: он создавал единый блок, в котором сначала шёл промпт агента, а за ним — раздел с данными о среде, рабочей директории и дате, и ставил единственную контрольную точку кэша в конце всего блока. Общая часть никогда не сохранялась отдельно, поэтому проверка в одном репозитории не могла повторно использовать то, что рецензент записал во время работы с другим.
16 сентября мы добавили маркер в конец каждого промпта агента и хук плагина, который разделял блок надвое в этом месте. Теперь первая часть заканчивалась байтами, общими для всех задач, и для неё создавалась отдельная контрольная точка. Чтобы сохранить это устройство, нам пришлось убрать из начала блока всё, что зависело от конкретного репозитория. Поэтому список доступных навыков отключили, а описания инструментов сделали неизменными от задачи к задаче.

В тот же день мы также перенесли в промпт справочный индекс рецензента внутренних стандартов Codex: таблицу внутренних стандартов, файл навыка и список справочных файлов. До этого каждый сеанс тратил первые три хода на чтение этих файлов с помощью вызовов инструментов. Число вызовов LLM за один запуск сократилось с 15,9 до 9,6, а стоимость запуска — с 1,12 до 0,72 доллара.
В совокупности эти изменения снизили стоимость одной проверки с 2,47 до 2,02 доллара — результат стал заметен сразу после выпуска обновления.
Меньше вызовов — меньше расходов
Следующий набор изменений вышел 21 и 23 сентября. По отдельности ни одно из них не было особенно впечатляющим, но вместе они сэкономили около 0,20 доллара на каждой проверке.
Изменение | Что происходило | Эффект изменения |
Удаление инструментов, недоступных рецензентам | Подрецензенты видели инструмент для публикации итогового комментария. В 57–76% сеансов они пытались его вызвать, получали отказ от серверной проверки и тратили ещё один вызов на восстановление после ошибки. | Устранён один бесполезный вызов; в каждом запросе подрецензента стало примерно на 2,9 тыс. токенов меньше из-за определений инструментов |
Параллельное чтение файлов | В 64% ходов рецензента качества кода модель делала ровно один вызов инструмента — обычно для чтения одного файла. | Рецензенты считывают общий контекст и все свои патчи в первом ответе — до 150 КБ |
Пропуск рецензентов при повторных проверках | Около двух третей наших задач — это повторная или последующая проверка того же запроса на слияние. Нередко трём рецензентам просто нечего добавить. | При повторных проверках на полном уровне проверка AGENTS.md пропускается в 56% случаев, проверка производительности — в 23%, а документации — в 13%. |
Остановка после публикации проверки | OpenCode возвращал результат модели для ещё одного хода. Модель заново читала весь диалог, чтобы написать сводку, которую никто не видел. | Экономия около 0,07 доллара на задачу |
Разное отношение к медленной работе рецензента и сбою провайдера | Рецензент, исчерпавший отведённое ему время, считался случаем сбоя провайдера и запускался заново с тем же лимитом. | Вместе с увеличением лимитов времени и снижением уровня усилий доля тайм-аутов рецензента безопасности упала с 1,8% запусков почти до нуля |
Отмена отменённых задач | Исполнитель Kubernetes в GitLab не отправляет сигнал скрипту задачи, когда её отменяют. В выборке из 446 отменённых задач 358 продолжали работать до завершения проверки. | Задачи проверяют собственный статус каждые 15 секунд и останавливаются, если их отменили |
Самым трудоёмким изменением стало использование одного префикса тремя рецензентами. Рецензенты качества кода, безопасности и производительности теперь отправляют одинаковые первые запросы с одними и теми же инструментами и общим файлом правил, а затем — запрос на слияние со всеми патчами. После этого идут индивидуальные инструкции каждого рецензента. Мы следим за тем, чтобы один из них записывал данные в кэш, а двое других читали их оттуда.

Запись в кэше нельзя прочитать, пока не начнётся потоковая передача ответа, который её создал, а все три рецензента запускаются одновременно. Поэтому второй и третий ждут, пока начнёт поступать ответ первого, — до 20 секунд, прежде чем отправить собственный первый запрос. Это немного замедляет их работу, но экономит около девяти центов на рецензента.
Изменение моделей и уровня усилий
На следующем графике показана та же линия, начиная с начала сентября, с отметками каждого изменения.

Если разделить период по каждому выпуску и изменению конфигурации, окажется, что изменения кода дали меньшую часть экономии.

На изменения кода пришлось 0,65 доллара из общей экономии в 1,67 доллара, а на смену моделей и уровня усилий — 1,06 доллара. На каждом шаге мы сравниваем часы в будние дни до изменения с часами после него, поэтому это нельзя считать статистически корректным контролируемым экспериментом.
С августа координатор работал с тремя сочетаниями моделей и уровней усилий. При использовании одной и той же модели задачи на полном уровне и со средним уровнем усилий выполнялись на 20% быстрее, поэтому от двух других сочетаний мы отказались. Позже в ходе рандомизированного разделения мы выяснили, что Opus 5.5 со средним уровнем усилий не даёт измеримых изменений в результатах проверки или критических замечаниях по сравнению с Opus 5, поэтому мы перешли на новую модель. Opus 5.5 с высоким уровнем усилий обходился дороже, чем Opus 5.5 со средним, но не давал значимого прироста числа замечаний.
Токены Opus 5.5 обходятся дешевле, чем токены Opus 5, но разница в цене объясняет лишь около 0,20 доллара экономии. Остальное обеспечено сокращением числа отправляемых и генерируемых токенов. С начала сентября количество чтений из кэша на одну проверку снизилось на 82%, записей в кэш — на 54%, а выходных токенов — на 67%.
Последним изменением стала новая модель. 3 октября мы разделили всех рецензентов Sonnet поровну между Sonnet 5 и Sonnet 5.5. Через два с половиной дня выяснилось, что один запуск Sonnet 5.5 обходится на 62% дешевле при проверке качества кода, на 58% — при проверке производительности и на 47% — при проверке безопасности. Цена токена у обеих моделей одинаковая, поэтому вся экономия связана с сокращением числа токенов. При проверках на полном уровне рецензенты на версии 5.5 публиковали примерно столько же критических замечаний и предупреждений, сколько и рецензенты Sonnet 5. Поэтому 5 октября мы перевели всех на версию 5.5.
При использовании Sonnet 5.5 со средним уровнем усилий рецензент качества кода делает 1,7 вызова LLM за запуск вместо 6,2, причём более половины запусков заканчиваются после одного вызова. Это значит, что рецензент не открывает ни одного другого файла в репозитории. При высоком уровне усилий он делает 3,4 вызова за запуск. Мы опасались, что проверки из-за этого станут поверхностнее; ниже, в разделе о качестве, расскажем об этом подробнее.
Чтобы проверить, помогает ли более высокий уровень усилий находить больше проблем при проверках крупных изменений, с 5 октября мы распределяем проверки качества кода на версии 5.5 поровну между средним и высоким уровнями усилий. За первый день проверки на высоком уровне обходились на 61% дороже за запуск и выявляли на 58% больше критических замечаний и предупреждений. Это примерно два цента на проверку. Как показывает следующий раздел о качестве, дополнительные находки того стоят, поэтому мы переводим проверку качества кода на высокий уровень усилий. Приведённые в этой публикации данные о расходах учитывают это изменение.
Задержки
Мы не ставили целью ускорить проверки, но меньшее число вызовов означает меньше ожидания, а значит, более быстрые проверки и более довольных инженеров.

Больше всего улучшились самые медленные проверки. За четыре недели до 14 сентября более пяти минут занимали 37,9% проверок, а теперь таких всего 0,7%. Сегодняшний 99-й процентиль быстрее, чем были три четверти проверок в апреле. Все уровни стали быстрее: медианное время проверки на полном уровне сократилось с 5 мин 16 с до 1 мин 54 с, на облегчённом — с 2 мин 58 с до 1 мин 14 с, а на тривиальном — с 77 до 30 секунд.
К августу медианная проверка стала на 14% медленнее, чем в апрельском отчёте, а 99-й процентиль — на 48% медленнее. Значительная часть нашей работы просто вернула показатели на прежний уровень.
Качество проверок
Снижение стоимости проверки мало чего стоит, если она выявляет меньше проблем, и первый график, похоже, говорит именно об этом.

После перевода проверки качества кода на Sonnet 5.5 с высоким уровнем усилий количество критических замечаний и предупреждений сократилось на 40% по сравнению с концом августа. Рецензенты безопасности и производительности, которые остались на среднем уровне усилий, стали публиковать на 56% и 71% меньше таких замечаний соответственно. Само по себе снижение числа серьёзных замечаний не показывает, пропускаются ли реальные проблемы или отсекается лишний шум, поэтому мы изучили этот вопрос с двух сторон.
Сначала мы проверили, реагируют ли авторы на замечания рецензента. Для выборок критических замечаний и предупреждений мы сравнили проверенный коммит со следующим коммитом автора и считали, что на замечание отреагировали, если указанные строки изменились. Строки на расстоянии от 30 до 40 строк от каждого замечания менялись примерно в 15% случаев во все периоды — это базовый уровень изменений, происходящих случайно.

До изменений авторы исправляли 34% серьёзных замечаний рецензента качества кода. Теперь — 59%. Рецензент отмечает меньше проблем, но гораздо чаще его замечания приводят к изменениям, поэтому число замечаний, повлёкших изменения, в расчёте на 1 000 проверок осталось примерно прежним. Сейчас таких замечаний 132 против 145 раньше — разница укладывается в погрешность. Для всех четырёх рецензентов число серьёзных замечаний, приведших к изменениям, выросло с 229 до 321 на 1 000 проверок.
Затем мы поручили двум моделям от разных провайдеров оценить вслепую выборку из 657 замечаний трёх рецензентов Sonnet, вместе с диффами, к которым они относились, но без указания периода. Разногласия передавались третьей модели. Каждое замечание классифицировалось как важное, незначительное, дублирующее, ошибочное или непроверяемое, а его серьёзность оценивалась как соответствующая, завышенная или заниженная.

Исчезли главным образом незначительные замечания, а также некоторые дубликаты и замечания, которые проверяющие не смогли подтвердить по диффу. Число важных замечаний на одну проверку выросло с 0,28 до 0,30, причём интервалы перекрываются. Более заметные изменения произошли в оценке серьёзности. Раньше проверяющие считали, что 0,46 критического замечания или предупреждения на одну проверку были серьёзнее, чем следовало. Теперь таких 0,14 — снижение на 70%, это самый убедительный результат исследования. Во многом число критических замечаний упало потому, что рецензент перестал объявлять критичными незначительные проблемы.
Итак, ответ зависит от рецензента. При проверке качества кода на высоком уровне усилий исчезли главным образом шум и завышенные оценки серьёзности, а число реальных проблем, которые удаётся найти, осталось примерно таким же. При среднем уровне усилий часть реальных замечаний действительно потерялась. В рандомизированном сравнении проверка качества кода на среднем уровне приводила примерно вчетверо реже к исправлениям, чем на высоком, — поэтому мы и переводим её на высокий уровень. Рецензент производительности тоже стал пропускать реальные проблемы: по оценке проверяющих, число важных проблем с производительностью на одну проверку снизилось примерно на 64%. На практике это означает примерно на одно важное замечание меньше на каждые 24 проверки на полном уровне. Показатель для безопасности упал примерно на четверть, хотя статистически это незначимо. Оба рецензента пока работают на среднем уровне усилий; следующий шаг — проверить их на высоком.
Ни один из методов не идеален. Изменение автором отмеченных строк показывает, что он что-то сделал, но не доказывает, что замечание было верным. Проверяющие тоже являются моделями, а в каждой группе всего от 35 до 66 замечаний. Кроме того, период «сейчас» охватывает лишь один день. Тем не менее оба метода дают согласующиеся результаты, и ни один не указывает на то, что рецензент качества кода стал находить меньше реальных проблем.
Надёжность также сохранилась. Доля проверок, завершившихся без вердикта, снизилась с 0,79% до 0,27%, а доля повторных попыток рецензента безопасности — с 3,5% до 0,04%.
Итоги
Теперь средняя проверка обходится в 0,77 доллара вместо 2,43 доллара, а медианное время выполнения сократилось с 4 мин 9 с до 1 мин 32 с. Самую большую экономию дало изучение того, что именно отправлялось провайдеру в первом запросе каждого сеанса, и поиск способа упорядочить сообщения так, чтобы они как можно меньше отличались между коммитами, запросами на слияние и репозиториями. Остальной экономии удалось добиться благодаря постоянным экспериментам с моделями и сочетаниями уровней усилий — при этом мы старались не давать заранее сложившимся предпочтениям влиять на выбор моделей.
Снижение стоимости проверок не обязательно означает ухудшение качества, но и не гарантирует, что всё в порядке. При высоком уровне усилий рецензент качества кода находит примерно столько же реальных проблем, сколько раньше, но с гораздо меньшим количеством шума и значительно реже завышает серьёзность замечаний. На среднем уровне рецензент производительности стал пропускать реальные проблемы, и, возможно, то же произошло с рецензентом безопасности. Следующий шаг — проверить обоих на высоком уровне усилий. Если вы запускаете агентов в больших объёмах, в первую очередь стоит выяснить, читает ли первый запрос каждого сеанса данные из кэша и продолжают ли рецензенты находить реальные проблемы на том уровне усилий, за который вы платите.
Если вы будете на конференции Cloudflare Connect в Сан-Франциско, я расскажу о том, как мы создали рецензента вместо того, чтобы купить готовый, на своей сессии «Пора создавать, а не покупать» во вторник, 20 октября, в 12:30 по тихоокеанскому времени. С 13:10 я также буду в зоне Speaker Connection Lounge — приходите, если захотите обсудить любые цифры из этой публикации.
