К содержимому
Claude Code с 0:полный курс
Новости ClaudeАвтор: Михаил Кузьмицкий

Как Claude Code взорвал CI в Anthropic — и как это починили

Русская адаптация материала Anthropic — подготовлена с участием AI, проверена автором.

Коротко

Объём CI-задач в Anthropic вырос в 25 раз за полгода из-за агентного кода. Рассказываем, как три быстрых патча продержались 70, 29 и меньше одного дня — и что помогло в итоге.

Когда пишет код не человек, а агент — ломаются не только привычки, но и инфраструктура. В Anthropic это почувствовали на себе: система, которая решала, какие тесты запускать при каждом изменении кода, начала захлёбываться под нагрузкой, выросшей в 25 раз за полгода. Об этом честно и подробно рассказал инженер Anthropic Сачин Малхотра — и это отличная иллюстрация того, что «CI трещит по швам» — не метафора, а реальная инженерная проблема эпохи агентного кода.

Конвейер с постоянно умножающимися коробками

Почему CI стал бутылочным горлышком

Раньше самым узким местом в разработке было написание кода: человек думал, писал, тестировал — и это занимало время. Сейчас, если код в основном пишет Claude, а он же во многом ревьюит и одобряет пул-реквесты (PR — это предложение изменений в код, которое команда просматривает перед тем, как принять в проект), скорость написания и проверки кода резко выросла. Из блога известно: инженеры Anthropic в среднем стали выпускать в 8 раз больше кода за квартал, чем в 2021–2025 годах, и 80% этого кода написано Claude.

Когда исчезает бутылочное горлышко на входе, вся нагрузка переезжает дальше по конвейеру — на CI (Continuous Integration, «непрерывная интеграция» — процесс автоматической проверки и тестирования каждого изменения кода). Плюс количество тестов в кодовой базе Anthropic выросло в 10 раз, а число инженеров — лишь незначительно. В сумме за полгода это дало 25-кратный рост числа CI-задач. И не потому что каждый тест теперь гоняют на каждый PR — наоборот, именно умный выбор тестов спас команду от полного коллапса, но даже он не выдержал такой нагрузки без переделки.

Заметка

CI-задача — это, грубо говоря, один прогон тестов на одном изменении кода. Чем больше PR и чем больше тестов в проекте, тем больше таких прогонов нужно выполнить за единицу времени.

Как устроен отбор тестов в Anthropic

У большинства команд каждый тест запускается на каждое изменение — это просто и надёжно, пока проект небольшой. Но с ростом кодовой базы CI-гейты (проверки, которые должны пройти, прежде чем код попадёт в основную ветку) становятся всё длиннее, дороже и менее заслуживающими доверия. Anthropic решила эту проблему детерминированной службой test impact analysis («анализ влияния изменений на тесты») — она сама решает, какие тесты релевантны для конкретного PR, опираясь на историю прогонов и связи между пакетами кода.

Сервис держится на двух компонентах, которые обязаны оставаться синхронизированными:

КомпонентЧто делает
Listener («слушатель»)Записывает результаты тестов с каждого прогона CI
Selector («отборщик»)Читает историю результатов и решает, какие тесты запускать на новом PR

Проблема в том, что если CI-задачи прилетают каждую секунду, слушатель начинает отставать от очереди PR. И даже небольшое отставание — критично для «AI-native» цикла разработки: 20 минут задержки листенера могут означать, что десятки тысяч результатов тестов просто не попали в отборщик. Последствия предсказуемо неприятные: плохое изменение мержится и ломает тест для всех остальных, флакующая (нестабильная) зависимость начинает блокировать мерджи «красными» ложными провалами, а исправленный или новый тест не подключается вовремя — и риск регрессии растёт.

Всё это работало как один процесс, потому что для сохранения истории по каждому тесту требовался единственный «писатель» результатов — и именно это не давало горизонтально шардировать систему с самого начала.

Патч 1: просто больше железа

В октябре прошлого года сервис начал явно трещать, инженеров пейджили (получали автоматические уведомления о сбоях) два дня подряд. Первое решение было максимально простым — удвоили количество ядер, на которых крутился сервис. Команда сразу понимала, что это временная мера.

Реконструированный диалог о том, кто должен владеть проблемой инфраструктуры. Источник: Anthropic

Даже когда тренд роста нагрузки был очевиден на графиках, никто не хотел брать на себя ответственность за ещё один кусок инфраструктуры — у команды CI и без того хватало более острых проблем. Патч с увеличением железа продержался 70 дней.

Патч 2: шардирование по пакетам

Когда пейджи посыпались снова, Малхотра запустил долгоживущую сессию в внутренней версии Claude Tag, специально следящую за сервисом: как только отставание листенера превышало 50 000 задач, Claude писал ему и предлагал следующие шаги. Это продолжалось месяцами — и оказалось удобно, что не нужно каждый раз объяснять модели контекст с нуля. Claude регулярно настаивал на полном переделывании архитектуры, но команда чаще всего соглашалась на очередной патч.

Фрагмент переписки с внутренней версией Claude Tag о состоянии сервиса. Источник: Anthropic

В феврале экспоненциальный рост CI-задач снова начал давить на систему, и на этот раз решили параллелизовать процесс. Оказалось, что листенеру не нужен один писатель на всю систему — достаточно одного писателя на пакет кода, чтобы правильно упорядочивать результаты тестов для каждой части кодовой базы. Claude сгенерировал код для разбиения состояния каждого пакета на отдельный шард со своим воркером. Команда снова знала, что фикс временный, но не ожидала, что он проработает лишь 29 дней.

Патч 3: ежедневные перезапуски

В марте процесс начал упираться в лимит памяти уже к середине большинства рабочих дней. Команда искала быстрые решения — нашли только четыре мелких бага, а замена аллокатора памяти как попытка оптимизировать сборку мусора ничего не дала. Профилировать память у singleton-процесса под тяжёлой нагрузкой казалось слишком рискованным, поэтому остановились на банальном перезапуске сервиса.

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

Настоящее решение: убрать состояние из процесса

Стало ясно, что пора не патчить, а пересобирать сервис заново — и в этот раз команда прислушалась к совету Claude: дали сервису отбора тестов базу данных, точнее in-memory хранилище (данные хранятся в оперативной памяти для скорости доступа). Это позволило снять с singleton-процесса огромный кусок обработки, который раньше держался в памяти одного экземпляра.

Теперь любой воркер-листенер может обработать любой результат, дописать его в журнал в этом хранилище и пойти дальше — ничего не удерживая в памяти. Процесс стал stateless (без внутреннего состояния) и, следовательно, горизонтально масштабируемым. Небольшой отдельный процесс-«консюмер» каждые несколько секунд сворачивает журнал в историю по каждому тесту, а отборщик быстро обращается к этой истории при необходимости.

График очереди необработанных результатов до и после редизайна: было — рост неделя от недели, стало — плоская линия. Источник: Anthropic

Такая распределённая архитектура обходится дороже в эксплуатации, но её значительно проще масштабировать и профилировать по памяти, чем хрупкий singleton. На весь проект ушло три недели работы одного инженера — годом ранее на такое ушла бы примерно четверть года. Часть тонкой настройки — подбор размера журнала и числа воркеров — Claude выполнил в значительной мере самостоятельно, и с тех пор сервис остаётся стабильным.

Три патча в сравнении

Наглядно видно, как быстро сокращалось время жизни временных решений — и почему в какой-то момент патчить перестало иметь смысл вообще:

ПатчЧто сделалиСколько продержался
1. Больше железаУдвоили количество ядер70 дней
2. ШардированиеРазбили состояние по пакетам, свой воркер на каждый29 дней
3. Ежедневные перезапускиПерезапускали процесс при упоре в лимит памятименьше 1 дня
РедизайнStateless-архитектура с in-memory хранилищемстабильно с момента внедрения

Главный урок

Каждая быстрая заплатка со временем покупает всё меньше времени. А вот полный редизайн архитектуры теперь, наоборот, обходится дешевле по времени — потому что писать и тестировать код больше не бутылочное горлышко.

Что автор сделал бы иначе

Если бы Малхотра мог вернуться в октябрь и начать заново, он бы сразу закладывал экспоненциальный рост. Число CI-задач растёт экспоненциально по мере того, как на каждого инженера приходится всё больше агентов, а ускоренное согласование PR становится всё более отточенным процессом. Это, кстати, изменило и форму самих PR в Anthropic: Claude предпочитает делать более маленькие и гранулярные изменения — ещё одна причина не гонять все тесты на каждый PR подряд, но и ещё один источник роста числа CI-задач в день. Заодно поднялся «пол» активности — агенты пушат код ночью и по выходным, хотя пики всё равно неравномерные, потому что люди продолжают вести и одобрять значительную часть PR.

Совет инженерным командам простой: планируй архитектуру, которая выдержит 25-кратный рост нагрузки в течение двух кварталов — независимо от того, строишь ты систему сама или покупаешь готовую. Идея «избыточного проектирования — это плохо» постепенно уходит в прошлое, или хотя бы планка того, что считается избыточным, сильно поднялась. Если бюджет позволяет, закладывай в архитектуру запас 10-20x от того, что кажется реалистичной нагрузкой сегодня.

Ещё два практических совета: инструментируй свои сервисы так, чтобы они стали «глазами и ушами» Claude — это позволяет модели самостоятельно находить и постепенно устранять проблемы намного быстрее, чем это могла бы сделать команда вручную. И держи состояние подальше от процесса с самого начала — не запускай критичный сервис в единственном экземпляре, если не можешь измерять его нагрузку и безопасно тестировать изменения на canary-версии (небольшая тестовая версия сервиса, на которой сначала проверяют изменения). CI сейчас развивается слишком быстро, чтобы позволить себе иной подход.

Если тебе интересно, как агентный код меняет повседневную работу с git и пул-реквестами, посмотри также разбор ревью с Claude и то, как Claude Code ориентируется в большом проекте — а базовые навыки терминала и командной строки, без которых сложно разобраться во всей этой инфраструктуре, можно получить на бесплатном курсе zero2claude.

Частые вопросы

Что такое test impact analysis (анализ влияния на тесты)?

Это сервис, который решает, какие именно тесты нужно запускать при конкретном изменении кода, вместо того чтобы гонять абсолютно все тесты на каждый пул-реквест. Он опирается на историю прошлых прогонов и на то, какие пакеты кода затронуты изменением.

Почему CI-задачи выросли в 25 раз именно из-за агентов?

Claude пишет около 80% кода в Anthropic и активно участвует в ревью PR, поэтому скорость создания и одобрения изменений резко выросла. Одновременно количество тестов в кодовой базе увеличилось в 10 раз — в сумме это дало 25-кратный рост числа CI-задач за полгода.

Почему нельзя было просто добавить ещё серверов?

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

Что в итоге решило проблему?

Полный редизайн: команда убрала состояние из процесса и перенесла его в отдельное in-memory хранилище. Воркеры-листенеры стали stateless и могут обрабатывать любые результаты параллельно, а отдельный процесс сворачивает журнал в историю тестов. Это сделало сервис горизонтально масштабируемым и стабильным.

Если хочешь попробовать всё это руками — начни с бесплатного курса «Claude Code и терминал: с 0».

Источник

По мотивам статьи Anthropic «Agentic coding is straining CI. Here's how we scaled test impact analysis at Anthropic». Пересказали по-русски для новичков.

Читайте также

Попробуй на практике

Бесплатные интерактивные курсы по теме — прямо в браузере, с нуля.