Полгода назад я начал писать веб-лист персонажа для D&D 5e. Сейчас это D1MANYCH/dnd-app: ванильный JS без сборщика, 44 модуля, ~70 000 строк, 597 коммитов, версия 3.91.0. Код в нём почти целиком написан Claude Code — я держу архитектуру, ревью и решения по контенту. Текст этой статьи тоже написан ей — по моим замерам, структуре и правкам. Раз уж за такое иногда прилетает, говорю сразу, в первом абзаце.
Проблема, ради которой всё затевалось: лимиты подписки заканчивались к обеду. Не потому, что я много просил, а потому, что просил неправильно. Ниже — как я это измерил, что нашёл и что поменял.
Сначала замер, потом выводы
Ощущения тут бесполезны: «кажется, много читаю» — не диагноз. У Claude Code все сессии лежат в ~/.claude/projects/**/*.jsonl, и в каждой строке ассистента есть message.usage с реальным биллингом. Тридцать строк на Node дают полную картину:
// usage.js — расход по всем транскриптам: node usage.js const fs = require('fs'), path = require('path'); const root = path.join(require('os').homedir(), '.claude', 'projects'); const files = []; (function walk(d) { for (const e of fs.readdirSync(d, { withFileTypes: true })) { const p = path.join(d, e.name); if (e.isDirectory()) walk(p); else if (e.name.endsWith('.jsonl')) files.push(p); } })(root); let req = 0, read = 0, write = 0, out = 0, sessions = 0; const bySession = []; for (const f of files) { let n = 0, r = 0; for (const line of fs.readFileSync(f, 'utf8').split('\n')) { if (!line.includes('"cache_read_input_tokens"')) continue; if (line.includes('"isSidechain":true')) continue; // сабагенты — отдельный контекст let u; try { u = JSON.parse(line).message.usage; } catch (e) { continue; } if (!u) continue; n++; r += u.cache_read_input_tokens || 0; read += u.cache_read_input_tokens || 0; write += u.cache_creation_input_tokens || 0; out += u.output_tokens || 0; } if (n) { sessions++; req += n; bySession.push({ n, r }); } } bySession.sort((a, b) => b.n - a.n); const long = bySession.filter(s => s.n > 300); console.log('сессий:', sessions, '| запросов:', req); console.log('кеш-чтение:', (read / 1e9).toFixed(2) + 'B', '| вывод:', (out / 1e9).toFixed(2) + 'B'); console.log('средний контекст запроса:', Math.round(read / req / 1000) + 'k'); console.log('сессий >300 запросов:', long.length, '| их доля расхода:', Math.round(long.reduce((a, s) => a + s.r, 0) / read * 100) + '%');
Что он мне выдал:
Метрика |
Значение |
|---|---|
Сессий / запросов к модели |
169 / 28 649 |
Чтение из кеша |
5,75 млрд токенов |
Из них на этот проект |
3,64 млрд (63%) |
Запись в кеш |
0,20 млрд |
Выход (ответы модели) |
0,03 млрд |
Средний контекст одного запроса |
201k |
Сессий длиннее 300 запросов |
22 штуки — 67% всего расхода |
Самая длинная сессия |
886 запросов |
Если выложить сессии в ряд, отсортировав по расходу, картина становится неприличной:

Хвост из полутора сотен нормальных сессий — треть расхода. Слева — два десятка марафонов, которые съели остальное.
Первая же строчка таблицы отменяет половину советов из интернета. Выход — 0,03B против 5,75B входа, это полпроцента. Всё, что можно выгадать, укорачивая свои промпты и прося «отвечать кратко», лежит в этих полпроцента. Деньги — во входе, то есть в том, что тащится в каждый запрос.
UPD. В комментариях справедливо поправили: полпроцента — это доля в токенах, а не в деньгах. Чтение кеша стоит десятую часть обычного входа, запись в кеш — дороже входа, выход — впятеро дороже. По тарифам Opus 5 ($5 / $25 за Mtok, чтение кеша $0,50, запись $6,25) расклад такой:
Статья расхода |
Токены |
Стоимость |
Доля счёта |
|---|---|---|---|
Чтение кеша |
5,75 млрд |
$2875 |
59% |
Запись в кеш |
0,20 млрд |
$1250 |
26% |
Выход |
0,03 млрд |
$750 |
15% |
То есть на ответы модели приходится не полпроцента счёта, а около 15%. Вывод статьи это не меняет — 85% стоимости всё равно вход, и режется он длиной сессии, а не длиной ответов, — но у выхода есть и вторая цена: всё написанное ложится в контекст и потом читается заново на каждом следующем шаге. Суммы в таблице — пересчёт моего расхода по тарифам API: работаю я по подписке, никаких $4875 в реальности не платил, но соотношение статей расхода от способа оплаты не зависит.
Почему длинная сессия дороже нескольких коротких
Механика простая, но неинтуитивная. Каждый запрос к модели отправляет весь диалог заново: системный промпт, CLAUDE.md, все прочитанные файлы, все результаты команд, всю переписку. Prompt caching делает это дешевле, но не бесплатно — вы платите за чтение кеша, и платите за него на каждом шагу.
Контекст при этом только растёт. Если считать грубо, что каждый вызов добавляет d токенов к контексту S на старте, стоимость сессии из N запросов — это площадь под прямой:
Стоимость ≈ N·S + d·N²/2
Квадрат — вот вся суть. Сессия на 800 запросов стоит не вдвое, а вчетверо дороже четырёх сессий по 200 при том же объёме сделанной работы. Мои 22 «марафонские» сессии съели две трети всего, что я потратил, — ровно поэтому.
Второе следствие того же неравенства — слагаемое N·S. Стартовый контекст умножается на количество запросов. Каждая лишняя тысяча токенов в CLAUDE.md — это тысяча, умноженная на 150 запросов сессии, умноженная на все сессии. Мой CLAUDE.md ужат до 74 строк и написан по-английски (на 15–20% короче того же текста по-русски), при том что весь проект, UI, коммиты и чат — русские.
Куда конкретно уходил контекст
Отдельным проходом я разложил накопленный контекст по источникам:
Источник |
Доля |
|---|---|
Стартовый контекст × число запросов |
39% |
Результаты инструментов |
32% |
Сама переписка |
28% |
Внутри инструментов: чтение файлов — 43%, команды оболочки — 25%, картинки — 13%. Дальше пошли неприятные подробности.
32% всего объёма чтения — повторные чтения одного и того же файла в одной сессии. style.css (647 КБ, 16 123 строки) был прочитан 266 раз. Модель читает файл, что-то делает, через двадцать шагов «на всякий случай» читает снова — хотя первое чтение никуда не делось, оно лежит в контексте и оплачивается на каждом запросе. За второй Read я плачу дважды: за сам факт и за то, что он теперь навсегда в этой сессии.
459 скриншотов, около 130 миллионов токенов. Я проверял вёрстку через браузерное превью прямо в основном чате. Один скриншот — это единицы тысяч токенов, но он остаётся в контексте до конца сессии и едет в каждый следующий запрос.
Что я поменял
1. Жёсткий лимит сессии и Stop-хук, который о нём напоминает
Правило: 150 запросов или 200k контекста — и сессию режем, даже посреди задачи. Соблюдать это на глазок нельзя, поэтому счётчик повесил на Stop-хук — он срабатывает, когда модель закончила ход:
// tools/check-session-size-hook.js (сокращённо) const WARN_REQ = 120, HARD_REQ = 150, WARN_CTX = 150000, HARD_CTX = 200000; const lines = fs.readFileSync(input.transcript_path, 'utf8').split('\n'); let req = 0; for (const l of lines) { if (!l.includes('"cache_read_input_tokens"')) continue; if (l.includes('"isSidechain":true')) continue; // сабагенты не влияют на цену главной сессии req++; } // контекст — из последней строки с usage const u = JSON.parse(last).message.usage; const ctx = (u.input_tokens || 0) + (u.cache_read_input_tokens || 0) + (u.cache_creation_input_tokens || 0); if (req >= HARD_REQ || ctx >= HARD_CTX) console.error('⛔ Сессия разрослась: ' + req + ' запросов, контекст ' + Math.round(ctx / 1000) + 'k. Закрыть: /carry → /clear.');
Хук ничего не блокирует (exit 0), просто печатает строку на пороге. Этого достаточно: раньше я не знал, что сижу в 600-запросной сессии, теперь узнаю на 120-й.
2. /carry — ручная передача смены вместо автосуммаризации
Автоматическое сжатие контекста спасает от переполнения, но это не экономия: до момента сжатия вы уже оплатили всю дорогу. Поэтому у меня своя слэш-команда /carry: модель пишет пять строк — что сделано, в каком состоянии файлы, следующий шаг, открытые вопросы, — я делаю /clear и начинаю новую сессию с этих пяти строк вместо ста тысяч токенов истории.
Это же лечит и другую болезнь. Работа нарезана на фазы, каждая начинается с «начать фазу X-N» и заканчивается /carry. Одна задача — одна сессия.
3. Карта кода вместо разведки грепом
Классический сценарий: «поправь отступ в шапке» → три Grep, чтение 400 строк не туда, потом ещё 400 туда. Всё это остаётся в контексте до конца сессии.
Решается генератором: node tools/gen-map.js строит docs/map.md — 259 строк, где перечислены секции style.css с диапазонами строк, блоки верхнего уровня index.html, индекс функций по файлам и индекс констант в файлах данных. Правило в CLAUDE.md: перед правкой большого файла сначала оглавление карты (первые 20 строк), потом нужный раздел карты, потом чтение файла с точным offset/limit. Вместо тысячи строк разведки — сорок.
Это стоит делать, только если в проекте есть монстры вроде моих: style.css 647 КБ, data.js 610 КБ, spells.js 562 КБ, build-notes-data.js 545 КБ. На проекте из аккуратных файлов по 300 строк карта не окупится.
4. Прямой запрет на повторное чтение
Формулировка в CLAUDE.md: «Никогда не читай один файл дважды за сессию. Прочитанное всё ещё в контексте — прокрути назад. Если файл изменился, читай только изменённый диапазон». Звучит как очевидность, но без явного запрета модель перечитывает — ей так надёжнее, а цену этой надёжности видит только владелец аккаунта.
5. Скриншоты и браузер — только в сабагенте
Ключевое свойство сабагента: у него свой контекст, а в главную сессию возвращается только финальный ответ. Вся визуальная проверка ушла в отдельного агента verifier — он поднимает превью, кликает, читает консоль и сеть, делает скриншоты, а мне отдаёт пять строк вердикта. 459 картинок больше не оседают в главном треде.
Та же логика для широкого поиска по репозиторию: пусть агент прочитает двадцать файлов у себя и вернёт «вот эти три места».
6. Рутину — дешёвым моделям
Основной тред я веду на Opus, но релизная рутина в Opus не нуждается. Модель сабагента задаётся во фронтматтере .claude/agents/*.md:
Агент |
Модель |
Что делает |
|---|---|---|
|
Sonnet |
тесты → бамп версии → проверка инвариантов → коммит → пуш → ожидание CI |
|
Haiku |
собирает текст анонса релиза |
|
Sonnet |
добавляет игровой контент по готовому шаблону |
|
Sonnet |
проверка UI в браузере |
Планирование, архитектура, разбор багов остаются в главном чате на старшей модели. Смысл разделения в том, что механическая работа по написанной инструкции не становится лучше от более умной модели, а стоит заметно дороже.
7. Батчинг вызовов и фон вместо polling
Цена растёт с количеством запросов, а не с количеством слов в них. Значит, независимые действия надо складывать в один ход: три чтения и два грепа в одном сообщении — это один запрос вместо пяти, и пять раз по 200k превращаются в 200k один раз.
Из того же: длинные команды — в фон, и ни в коем случае не «поспать и проверить». Каждый цикл «sleep → проверил → ещё не готово» — это полноценный оплаченный запрос с полным контекстом.
8. Детерминированные проверки — хуками, а не моделью
Всё, что можно проверить программой, проверяет программа, а не модель, которая для этого читает файлы. На PostToolUse у меня висят пять хуков: два блокирующих (exit 2) — «правил sw.js, но не бампнул CACHE_NAME» и рассинхрон версии с чейнджлогом, плюс node --check на любой изменённый JS; два предупреждающих — тесты и контраст темы.
Хук стоит ноль токенов и ловит ошибку в ту же секунду. Тот же класс проблем, пойманный моделью через три хода, стоит трёх полных контекстов.
Что не сработало
Сабагент ради одной команды. Агент стартует холодным: заново читает CLAUDE.md, заново ищет файлы. На короткой задаче это дороже, чем сделать самому. Сабагент окупается там, где он прочитает много, а вернёт мало.
Локальные модели как замена сабагентам. У меня RTX 4060 Ti на 8 ГБ — влезает 7–8B в четырёхбитном кванте. Для рутины в реальном коде этого мало, а Claude Code к локальным моделям и не подключается.
Просить «отвечай короче». Выход — 0,5% расхода. Экономить на нём — это торговаться за копейки, пока в соседней комнате горит проводка.
Чеклист
Приём |
Что лечит |
|---|---|
Лимит 150 запросов / 200k + |
квадратичный рост стоимости сессии |
|
оплату всей истории до момента сжатия |
Короткий |
стартовый контекст × число запросов |
Карта кода с диапазонами строк |
разведочные |
Запрет повторного чтения |
32% объёма чтения |
Браузер и скриншоты — в сабагента |
картинки, оседающие в главном треде |
Рутина на Sonnet/Haiku |
переплату за механику |
Батчинг независимых вызовов, фон вместо polling |
лишние запросы, каждый с полным контекстом |
Проверки хуками, а не моделью |
циклы «ошибся — прочитал — исправил» |
Честный финал
Цифр «после» у меня пока нет: правила и хуки введены недавно, а сравнивать надо на дистанции в пару недель работы, иначе намеряешь шум. Перезамерю тем же скриптом; цель — средний контекст запроса ниже 150k и полное отсутствие сессий длиннее 300 запросов.
Но одну вещь можно сказать, не дожидаясь замера. Работа с кодовым агентом — это не «попросил и получил». Это управление одним-единственным ресурсом: тем, что модель тащит с собой на каждом шагу. Всё остальное — производные.
Если у вас есть свои приёмы — особенно если вы дошли до цифр, а не ощущений, — напишите в комментариях, интересно сравнить методики замера.
Комментарии (22)

spirit1984
02.09.2026 12:11Отличная статья, а во сколько вы оцениваете вам бы обошлось это не по подписке, а по api pricing? 5.7 миллиардов токенов - не уверен, что у вас там за модель, но по ходу пару десятков тысяч долларов пришлось бы отдать?

D1MANYCH Автор
02.09.2026 12:11Я использую приложение от claude, в нём же и пишу код. По api не пробовал, просто слишком удобный интерфейс в claude code. Я использую обычную про версию, перешёл с бесплатной версии так как мои запросы уже даже в один чат не могли быть реализованы из-за лимита.

AZ_92
02.09.2026 12:11Страшно бесят эти лимиты на про тарифе. Вчера решил купить про тариф и попробовать клауд, в целом действительно интересно работает, но даже часа не уходит, чтобы поработать на нем нормально, лимит через полчаса слетает даже на соннете. Может я что-то не так делаю, но огромная загадка как все им пользуются. Неужели все на максе, а точнее как токены докупаются и как часто? Пока не разобрался что и как преимущество пока у ChatGPT.

AlexSky
02.09.2026 12:11Pro аккаунт действительно плохо подходит крупным задачам, если использовать его в режиме вайбкодинга, но за полчаса у меня ни разу не получалось израсходовать.
Чтобы снизить расходы, надо чаще очищать контекст.
Обычнно для крупных проектов пишу краткий ТЗ, прошу расписать подробно - сделать общий файл и отдельные файлы на каждый шаг. Потом проверяю, правлю (чаще всего не вручную, а с помощью Клода). А дальше прошу выполнить по одному шагу за раз, перед каждым шагом делаю /clear.

Annsky
02.09.2026 12:11Я смотрела, я трачу около миллиарда токенов... в день. Упс.)
Я скоро напишу вторую статью обновление, как я это делаю.
D1MANYCH Автор
02.09.2026 12:11О_О это на про подписке или макс?

Annsky
02.09.2026 12:11Если вкратце.
GPT 5.6 Luna - 20$
Minimax M3 - 20$
Qwen 3.8 flash next - 18$
Когда мне нужен GPT 5.6 Sol, я иду в веб версию, там у меня десятки проектов, и есть интеграция с Google Drive, на котором у меня тоже организованы папки проектов. В локальном агенте у меня тоже есть скилл google drive. Я общаюсь с GPT 5.6 Sol в вебе, прошу его сделать гугл доку, иду в локальный агент и кидаю ссылку на гугл доку.
D1MANYCH Автор
02.09.2026 12:11Очень круто. Тоже хотелось бы попробовать chatgpt платный и другие для сравнения, но я уже так слился с Claude.

funca
02.09.2026 12:11Выход — 0,03B против 5,75B входа, это полпроцента.
Не совсем так. Чтение из кеша стоит копейки - этим амортизируется разрастание истории. У вас чистый вход это запись в кеш - 0,20B. То есть соотношение выход/вход около 15%. Выход стоит в несколько раз дороже входа.

D1MANYCH Автор
02.09.2026 12:11Справедливо, спасибо — «полпроцента» это доля в токенах, а не в деньгах, и в статье я это не развёл.
По тарифам Opus 5 ($5/$25 за Mtok, чтение кеша $0.50, запись $6.25) выходит: чтение 5,75B → $2875 (59%), запись 0,20B → $1250 (26%), выход 0,03B → $750 (15%). Ваша цифра сходится.
Вывод от этого не меняется, но становится точнее: 85% стоимости — вход, и режется он не длиной ответов, а длиной сессии. Плюс у выхода есть вторая цена, которой нет у ответа как такового: всё, что модель написала, ложится в контекст и потом читается заново на каждом следующем шаге. Так что «короче отвечать» помогает, но пока сессия живёт 800 запросов, эти 15% не там, где горит.
Добавлю пересчёт в статью как UPD.

Revertis
02.09.2026 12:11Эту статью модель тоже вычитала.
А судя по тексту она полностью её написала!

D1MANYCH Автор
02.09.2026 12:11Написала, по моим замерам и правкам — в статье это сказано первым абзацем. Скрипт, цифры и решения о том, что менять в работе, мои; текст её. Учитывая тему статьи, писать её вручную было бы странно.

Innesiya
02.09.2026 12:11Вывод «выход — полпроцента» держится на том, что токены в таблице сложены без веса, а тарифицируются они по-разному: чтение кеша идет по 0.1 базовой ставки за вход, запись — по 1.25, выход — по 5. Пересчитала вашу же таблицу в этих единицах: 5.75B чтения дают 0.58, 0.20B записи — 0.25, 0.03B выхода — 0.15, то есть выход не полпроцента, а около четверти от стоимости чтения, а запись кеша — почти половина. На квадратичный вывод про марафонские сессии это никак не влияет, а вот «просить отвечать короче бессмысленно» из этих цифр уже не следует. Ваш скрипт умеет складывать расход по тарифам, или в нем везде сырые токены?

D1MANYCH Автор
02.09.2026 12:11Всё верно, и это уже поправлено в статье — UPD в конце раздела с таблицей, цифры сходятся с вашими до второго знака.
Скрипт в статье складывает сырые токены. Взвешенный вариант — три строки поверх него:
const W = {read: 0.1, write: 1.25, out: 5};const cost = read*W.read+ write*W.write + out*W.out;По моим данным получается: чтение 60,2%, запись 26,3%, выход 13,5%. Заодно пересчитал главный вывод в тех же единицах: сессии длиннее 300 запросов дают 62,5% стоимости вместо 67% в токенах — просадка есть, но вывод держится.
Про «просить отвечать короче»: соглашусь, что формулировка была слишком широкой, но конкретно у меня этот рычаг маленький не из-за тарифа, а из-за объёма. Средний ответ — 895 токенов на запрос: это агентная работа, где модель в основном читает и правит файлы, а не пишет текст. Сократить его вдвое — это 7% счёта, и то если инструкция «покороче» не добавит лишний шаг: каждый лишний шаг тянет полный контекст, а он у меня был 201k. На чат-нагрузке, где ответы длинные, ваш вывод был бы верен и без оговорок.

dsrk_dev
02.09.2026 12:11Жесткая остановка сессии скорее вредна. В текущей сесси у модели есть контекст, в новой сессии модель пойдёт снова перечитывать и изучать всё что ей нужно, что тоже стоит денег

D1MANYCH Автор
02.09.2026 12:11Цена у перезапуска действительно есть, вопрос в том, с чем её сравнивать.
Новая сессия у меня стартует не с нуля: есть конспект предыдущей на пять строк и карта кода с диапазонами строк, так что модель читает один-два нужных фрагмента, а не изучает проект заново. Стартовый контекст выходит 50–65k плюс 10–20k на чтение — разово. А на 150-м шаге старой сессии каждый следующий запрос идёт от 200k и выше. Разница ~140k на запрос, то есть перезапуск окупается за три-пять шагов.
Где вы правы: режу не «через 150 шагов посреди мысли», а на границе задачи, и если задача одна большая и не делится — рвать её смысла нет, дороже выйдет. Правило работает ровно потому, что работа заранее нарезана на куски, каждый из которых закрывается за одну сессию.

IrinaWW
Тоже есть проблемы с токенами, попробую, может поможет.