TL;DR
- «90%» у Spotify это среднее по сценариям массового чтения, измеренное в оценочных входных токенах на Java-монорепозитории. В посте нет ни стоимости в долларах, ни оценки качества.
- Мы повторили схему на обычном Claude Code (один PreToolUse-хук, два дешёвых сабагента, правило маршрутизации из трёх строк) и измерили на Fastify: четыре сценария, 16 запусков. Контекст основной модели сократился на 59.6%, общая стоимость на 33.1%.
- Хуки-запреты не сработали ни разу за все измеренные запуски. Экономию дало правило маршрутизации в CLAUDE.md; хуки нужны как страховка на тот день, когда модель его проигнорирует.
- Делегирование каждый раз оказывалось медленнее: в среднем +65.3% по времени. На небольшом сценарии с написанием теста оно обошлось на 2.6% дороже.
- Две ловушки: хуки срабатывают и внутри сабагентов, поэтому исключите своих воркеров, а чтение диапазонов через
sed -nпроходит мимо хука, который следит только заcat,headиtail. - В сводке читателя на Haiku были фактические ошибки в двух из восьми делегированных запусков. Оставьте основной модели шаг проверки.
Что показывают измерения
Плагин Spotify, Shunt, уводит массовую работу от основной модели через два «режима»: bulk-reader и code-writer. В примерах оба работают на Gemini 2.5 Flash, а в поле model можно указать любую модель, настроенную в инстансе Portal s1. Маршрутизация состоит из трёх слоёв. Хук check-file-size срабатывает на каждый Read и блокирует файлы длиннее настраиваемого порога строк (по умолчанию 350), отправляя модель к навыку bulk-reader; хук check-bash-read ловит cat, head, tail, less и more на больших файлах, а команды с конвейером пропускает s1. Исходники хуков и оба навыка лежат в публичном репозитории s2, а проверку размера можно прочитать отдельно s3. Сами режимы живут в Portal, внутренней платформе Spotify, поэтому плагин в том виде, как он поставляется, нельзя запустить за пределами компании s4.
Основание для бенчмарка тонкое. Spotify проверила четыре сценария на Java-монорепозитории, «измеряя токены, которые Claude потратил бы при прямом чтении файлов, против токенов сводки bulk-reader», и сообщает о среднем выигрыше на массовом чтении около 90% s1. Сам пост признаёт, что сценарий записи кода труднее измерить в токенах, что в сводках воркера нет надёжных номеров строк, поэтому редактирование делегировать нельзя, что воркер пропустил тонкую ошибку потокобезопасности, которую поймала основная модель, и что каждое делегирование добавляет от 10 до 30 секунд, причём Portal ограничивает один вызов 30 секундами s1. Те же вопросы о том, что именно измеряют эти 90%, задали в обсуждении на Hacker News s7.
В нашей реконструкции режимы Portal заменены двумя сабагентами Claude Code, у которых модель закреплена в файле определения: читатель Explore на Haiku и писатель code-writer на Sonnet s6. Запрет реализован как PreToolUse-хук, возвращающий решение deny в актуальном JSON-формате хуков s5. Тестовый репозиторий: fastify/fastify, коммит ac28821d, 294 файла .js/.ts, 78270 строк, 63 файла длиннее 350 строк. Идентификаторы моделей из JSON сессии: основной диалог claude-opus-5[1m], читатель claude-haiku-4-5-20251001, писатель claude-sonnet-5. Каждый сценарий запускался по два раза на конфигурацию, всего 16 измеренных запусков, однооборотные сессии claude -p с настройками только из проекта, чтобы системный промпт у обеих сторон был одинаковым s5.
Где схема выиграла: S2, вопрос о графе вызовов по трём файлам lib/route.js (691 строка), lib/reply.js (1090) и lib/request.js (398), снизил средний основной контекст с 357165.5 токена до 73440.0 (-79.4%), а стоимость с 0.5810500000000001 USD до 0.21823605000000001 USD (-62.4%). Где не выиграла: S4, написание теста для источника в 45 строк по образцу в 19 строк, стоило 0.29465575 USD без делегирования и 0.3022213 USD с ним (+2.6%), потому что Sonnet это второй полный контекст (от 13004 до 18729 токенов cache-read), а основная модель всё равно перечитывала сгенерированный файл и запускала тест s6.
Три вывода важнее процентов. Первый: за 16 измеренных запусков хуки не сработали ни разу. При правиле маршрутизации в CLAUDE.md основная модель сама выполняла wc -l и делегировала. Единственный зафиксированный запрет случился в проверочном запуске без CLAUDE.md: модели отказали в Read, затем отказали в cat -n, и она ответила только по grep -n, ни разу не вызвав инструмент Agent s5. Второй: хуки работают и внутри сабагентов. В двух отброшенных запусках читателя на Haiku саму остановила проверка размера, и он перешёл на чтение кусками через offset/limit. Решение: в начало хука поставить выход case "$agent_type" in Explore|code-writer) exit 0, а имя поля подтвердить по залогированному stdin s5. Третий: в базовой конфигурации основная модель вообще не использовала инструмент Read. Она читала каждый файл через Bash (cat -n, sed -n '1,200p', sed -n '200,560p'), так что хук, следящий только за Read, ничего не ловит, а Bash-хук, который срабатывает только на cat, head и tail без конвейера, всё равно пропускает диапазоны sed -n s3.
Качество проверяли по исходникам через grep. В базовой конфигурации в одном запуске S2 получились неверные номера строк (файлы выводились через sed -n без номеров, и строки считались вручную). В делегированной конфигурации в другом запуске S2 нашлись три фактические ошибки, а в одном запуске S3 две, и все они сводились к тому, что сводку Haiku приняли на веру: неверные вызывающие для buildRequest/buildReply, неэкспортируемая константа в списке экспортов, покрытый итератор помечен как непокрытый. Там, где основная модель тратила выходные токены на перепроверку через grep (S3, от 4534 до 4738 выходных токенов), ответы были верными s6. В сценарии написания теста все сгенерированные файлы прошли: 12/12, 6/6, 7/7 и 10/10 тестов. Один отчёт на Reddit показывает родственный сбой: основная модель запускает воркеров на не той модели, когда ничего её не закрепляет s8, и от этого защищают хук require-model и поле model: в файлах агентов.
Измерения
Средние значения по 2 запускам на ячейку. «Main context» это токены input + cache_creation + cache_read, оплаченные основной моделью за сессию; именно эту величину можно сравнивать с «токенами в основном контексте» у Spotify. A = обычный Claude Code, B = хук + сабагенты + правило в CLAUDE.md.
| сценарий | основной контекст A | основной контекст B | изменение | вывод основной A | вывод основной B | изменение | общая стоимость A | общая стоимость B | изменение | время A, с | время B, с | изменение |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| S1 | 88693.0 | 51551.5 | -41.9% | 1424.5 | 1060.5 | -25.6% | 0.13910675 | 0.08653685 | -37.8% | 21.817500000000003 | 43.799499999999995 | +100.8% |
| S2 | 357165.5 | 73440.0 | -79.4% | 3835.0 | 2555.5 | -33.4% | 0.5810500000000001 | 0.21823605000000001 | -62.4% | 51.637 | 129.036 | +149.9% |
| S3 | 303807.5 | 114135.5 | -62.4% | 6192.0 | 4636.0 | -25.1% | 0.451037 | 0.3738534 | -17.1% | 93.321 | 124.64099999999999 | +33.6% |
| S4 | 143431.5 | 121818.0 | -15.1% | 5275.5 | 3340.0 | -36.7% | 0.29465575 | 0.3022213 | +2.6% | 65.7125 | 86.857 | +32.2% |
| все 4 | 223274.375 | 90236.25 | -59.6% | 4181.75 | 2898.0 | -30.7% | 0.366462375 | 0.2452119 | -33.1% | 58.122 | 96.08337499999999 | +65.3% |
Протокол: два побайтно идентичных неглубоких клона fastify/fastify на коммите ac28821d; в repo-shunt добавлены только .claude/ (настройки, два файла агентов, три хука) и правило маршрутизации в CLAUDE.md. Каждая сессия: claude -p "<prompt>" --output-format json --setting-sources project --strict-mcp-config с пустой конфигурацией MCP, без --model, таймаут 600 с. Четыре промпта, одинаковые для обеих сторон: S1 экспорты lib/reply.js, S2 граф вызовов по трём файлам lib, S3 методы lib/hooks.js и покрытие test/hooks.test.js, S4 написать test/head-route.test.js по образцу test/noop-set.test.js. Значения взяты из modelUsage и total_cost_usd в JSON сессии без округления. Ответы сверялись с исходниками через grep; сгенерированные тесты запускались через node --test.
Сделайте это в понедельник
- Выполните
wc -lпо репозиторию и посчитайте файлы длиннее 350 строк. Если их почти нет, остановитесь: порог существует потому, что на небольших файлах делегирование стоит дороже, чем экономит. - Добавьте в CLAUDE.md правило маршрутизации из трёх строк: файлы выше порога идут субагенту-читателю, код по образцу идёт субагенту-писателю, отладка и архитектура остаются у основной модели. В наших измерениях всю работу сделало именно это правило.
- Создайте
.claude/agents/Explore.mdсmodel: haikuи.claude/agents/code-writer.mdсmodel: sonnetво frontmatter, чтобы модель воркера была закреплена в файле, а не отдана на усмотрение оркестратора. - Напишите PreToolUse-хук на Read как страховку: он возвращает решение deny в актуальном JSON-формате хуков, а его первые строки делают exit 0, если
agent_typeсовпадает с одним из ваших воркеров. - Расширьте Bash-хук за пределы
cat,headиtail: ловите диапазоныsed -nиcat -nна больших файлах, а команды с конвейером и grep пропускайте. - Прогоните один реальный вопрос с папкой
.claude/и без неё черезclaude -p --output-format jsonи сравнитеtotal_cost_usdиduration_ms, а не один только столбец входных токенов. - Проверьте через grep по исходникам два делегированных ответа, прежде чем доверять сводке читателя; заложите шаг проверки основной модели в стоимость.
- Измерьте и многооборотную сессию: однооборотные результаты оставляют основной контекст на уровне от 50k до 119k токенов против от 84k до 414k без делегирования, так что второй вопрос должен начинаться дешевле, но это не измерялось.
Что почитать дальше
- Прочитайте формат хуков и поле
agent_typeв официальном справочнике, прежде чем копировать хук из блога: формат deny и поля в stdin делают возможным исключение для сабагентов s5. - Документация по сабагентам описывает поле frontmatter
modelи ограничения инструментов, с помощью которых читателя можно сделать дешёвым и доступным только для чтения s6. - Раздел «What doesn't work» в посте Spotify самое полезное в нём: никакого делегированного редактирования (в сводках нет надёжных номеров строк), никаких делегированных рассуждений (пропущена ошибка потокобезопасности), задержка от 10 до 30 секунд на каждый вызов s1.
- README плагина Shunt показывает трёхслойную структуру (хуки, скрипты, навыки) и тексты навыков, объясняющие модели, когда делегировать; адаптировать стоит именно прозу навыков, а не хук s2.
- Режимы Portal это слой конфигурации поверх модели и системного промпта; ту же идею можно выразить файлом агента Claude Code с полем
models4. - На Hacker News впервые прозвучали вопросы об измерении, и это хороший чек-лист того, что нужно спрашивать у любого заявления об экономии токенов s7.
- Тема на Reddit описывает оркестратор, который запустил пять воркеров на своей же дорогой модели; закрепите модель в файле агента и, если нужна жёсткая гарантия, запретите вызовы Agent без поля
models8.
Источники
- Portal by Spotify cut my Claude Code token usage by 90%, Spotify Engineering. Зачем читать: исходное заявление, трёхслойная схема и честный раздел об ограничениях, который подрывает заголовок.
- Shunt plugin (spotify/portal-ai-plugins), GitHub. Зачем читать: реальные хуки, скрипты и тексты навыков, достаточно короткие, чтобы прочитать целиком.
- check-file-size hook source, GitHub. Зачем читать: проверка на 350 строк в нескольких строках shell, шаблон для вашего собственного запрета.
- Portal Modes documentation, Spotify. Зачем читать: что такое «режим», чтобы понять, почему он ложится на файл сабагента.
- Claude Code hooks reference, Anthropic. Зачем читать: актуальный формат deny и поля stdin, включая то, что определяет сабагента.
- Claude Code subagents, Anthropic. Зачем читать: поле frontmatter
modelи списки разрешённых инструментов для дешёвого воркера только для чтения. - Hacker News discussion of the Spotify post, Hacker News. Зачем читать: вопросы о том, что измеряют 90%, заданные до того, как кто-либо перемерил.
- Fable spawned five Fable agents instead of Opus (r/ClaudeCode), Reddit. Зачем читать: сбой, который предотвращает закреплённое поле
model.
FAQ
Число 90% неверное?
Оно измеряет одну вещь: оценочные входные токены в основном контексте для сценариев массового чтения больших Java-файлов. По такой же метрике реконструкция показала от 41.9% до 79.4% на сценариях чтения. Оно ничего не говорит о стоимости, времени и качестве ответов, и пост этого и не утверждает.
Нужен ли мне Portal, чтобы получить такой результат?
Нет. Маршрутизация живёт в правиле CLAUDE.md, двух файлах агентов с закреплённой моделью и PreToolUse-хуке. Portal поставляет воркер-модели в Spotify; строка model: haiku делает ту же работу в обычном Claude Code.
Когда делегирование обходится дороже?
Когда файлы маленькие. Сценарий написания теста для 45 строк стоил на 2.6% больше с делегированием, потому что писатель это второй полный контекст, а основная модель всё равно перечитывала и тестировала результат. Каждый делегированный запуск был к тому же медленнее, в среднем на +65.3%.
Почему хук ни разу не сработал?
Потому что правило маршрутизации в CLAUDE.md заставляло основную модель сначала проверить wc -l и делегировать, не пытаясь читать самой. Хук важен только тогда, когда модель игнорирует правило, а это случилось в проверочном запуске без CLAUDE.md.
AIDive