Почему одна сессия съела так много токенов
Сессия проекта TasK / codexcli, модель glm-5.2. Период активности: 2026-08-12 19:58 → 2026-08-13 21:45 (Asia/Novosibirsk). Отчёт построен по одному зафиксированному JSONL-снимку; сырые промпты, код, локальные пути и результаты production-запросов намеренно не встраиваются.
Главный вывод: длинный живущий контекст, а не output, стал основным источником расхода.
Состав расхода
Длина контекста
Средний raw расход на ответ вырос с 57.9K в первых 25 ответах до 396.4K в последних 104 — в 6.8×.
Медиана ответа: 258.2K; p90: 415.7K; максимум: 438.5K.
Время и паузы
Календарная длительность — 25.8 ч, суммарное время ответа модели — 1.69 ч.
Это не означает непрерывную работу: сессия возобновлялась после длительных пауз, а ожидание пользователя в active time не включено.
Наблюдение: что именно раздувало расход
- В среднем на один ответ пришлось 258.8K raw tokens, из них около 253.4K — кэшированный контекст.
- Свежий input и output вместе дали только 2.19M (2.1% raw), поэтому увеличение ответа или reasoning не объясняет основной объём.
- Первые 25 ответов в среднем стоили 57.9K, последние 104 — 396.4K. Это устойчивый сигнал накопления истории, а не единичного большого ответа.
Рост расхода по окнам
| Окно | Ответов | Raw | Среднее | Cache | Fresh + out |
|---|---|---|---|---|---|
| Первые 25 ответов | 25 | 1.45M | 57.9K | 1.35M | 94.5K |
| 26–100 | 75 | 9.91M | 132.1K | 9.77M | 135.2K |
| 101–200 | 100 | 22.23M | 222.3K | 22.09M | 143.3K |
| 201–300 | 100 | 29.77M | 297.7K | 29.25M | 519.9K |
| Последние 104 | 104 | 41.22M | 396.4K | 39.93M | 1.30M |
Сегменты пользовательской работы
Границы — пользовательские продолжения. Названия фаз — аналитическая классификация; тексты запросов не публикуются.
Инструменты и объём возвращаемых данных
В журнале зафиксировано 444 вызовов инструментов. Таблица показывает размер текста tool result в символах, а не токенах; это независимый индикатор того, какие операции наполняли контекст.
| Инструмент | Вызовов | Текст результата | Макс. один | Meta/details |
|---|---|---|---|---|
read | 99 | 294 859 | 26 132 | 377 518 |
grep | 19 | 125 594 | 17 346 | 161 352 |
bash | 201 | 122 939 | 4 138 | 11 712 |
edit | 66 | 33 197 | 1 410 | 613 546 |
glob | 17 | 23 490 | 9 779 | 40 639 |
todo | 18 | 19 667 | 1 855 | 19 721 |
ask | 7 | 2 202 | 1 613 | 3 706 |
write | 12 | 1 657 | 243 | 1 048 |
eval | 5 | 703 | 320 | 6 487 |
Инвентарь OMP tools
Зафиксированы фактические tool calls ассистента. Всего: 444.
| Tool | Вызовов |
|---|---|
bash | 201 |
read | 99 |
edit | 66 |
grep | 19 |
todo | 18 |
glob | 17 |
write | 12 |
ask | 7 |
eval | 5 |
CLI-утилиты
Команды в позициях запуска внутри вызовов bash. Счётчик консервативный: вложенные удалённые команды и текст grep не считаются.
| Утилита | Запусков |
|---|---|
tail | 117 |
head | 111 |
git | 86 |
grep | 78 |
make | 52 |
ssh | 43 |
docker | 17 |
php | 17 |
sed | 10 |
gh | 10 |
ls | 9 |
phpunit | 7 |
find | 7 |
scp | 5 |
sleep | 3 |
node | 2 |
wc | 2 |
cat | 2 |
getent | 2 |
podman | 1 |
date | 1 |
readlink | 1 |
which | 1 |
bun | 1 |
nslookup | 1 |
cut | 1 |
phpcbf | 1 |
awk | 1 |
Файлы и фрагменты, попавшие в контекст
read. Найдено 104 targets из результатов чтения.Таблица перечисляет полные относительные пути, число наблюдений, примерный диапазон строк и объём отображённого текста в символах. Число targets может быть больше числа read-вызовов, если один вызов вернул несколько файлов. Это не точная токенизация контекста: пропуски и обрезка обозначены явно.
| Файл | Targets | Фрагменты / строки | Символов |
|---|---|---|---|
| src/Module/Chat/Application/UseCase/Command/ChatMessage/Send/SendCommandHandler.php | 7 | 4–551 (несколько окон); с пропусками/обрезкой | 30 590 |
| tests/Unit/Module/Chat/Application/UseCase/Command/ChatMessage/Send/SendCommandHandlerTest.php | 6 | 1–813 (несколько окон); с пропусками/обрезкой | 24 160 |
| todo/EPIC-chat-quality-reliability.todo.md | 5 | 1–128 (несколько окон); с пропусками/обрезкой | 19 633 |
| apps/web/src/Module/Chat/Controller/ChatMessage/CreateController.php | 4 | 74–104 (несколько окон); с пропусками/обрезкой | 3 068 |
| apps/web/assets/controllers/chat/_messageSender.js | 3 | 12–207 (несколько окон); с пропусками/обрезкой | 10 768 |
| apps/web/tests/E2E/Module/Chat/ChatSendErrorStateTest.php | 3 | 21–204 (несколько окон); с пропусками/обрезкой | 7 191 |
| src/Module/Chat/Domain/Entity/ChatMessageModel.php | 3 | 25–200 (несколько окон); с пропусками/обрезкой | 7 155 |
| todo/TASK-chat-citation-document-markdown-html.todo.md | 3 | 1–113; с пропусками/обрезкой | 7 131 |
| tests/Integration/Module/Chat/Application/UseCase/Command/ChatMessage/Create/CreateCommandHandlerTest.php | 3 | 38–382 (несколько окон); с пропусками/обрезкой | 6 022 |
| apps/web/src/Module/Chat/Resource/templates/chat-message/_message_user.html.twig | 3 | 1–62 (несколько окон) | 5 585 |
| apps/web/src/Module/Chat/Controller/ChatMessage/ShowController.php | 3 | 1–81 (несколько окон); с пропусками/обрезкой | 4 453 |
| apps/web/src/Module/Chat/Controller/ChatMessage/EditController.php | 3 | 20–117 (несколько окон); с пропусками/обрезкой | 1 970 |
| todo/TASK-chat-message-processing-error-state.todo.md | 2 | 1–118; с пропусками/обрезкой | 8 208 |
| todo/TASK-chat-response-prompt-contract.todo.md | 2 | 1–120 (несколько окон); с пропусками/обрезкой | 7 830 |
| apps/web/assets/controllers/chat_message/send_controller.js | 2 | 18–124; с пропусками/обрезкой | 4 406 |
| devops/make/tests.mk | 2 | 25–53; с пропусками/обрезкой | 4 320 |
| apps/web/src/Module/Chat/Controller/ChatMessage/Presenter/ChatErrorPayloadBuilder.php | 2 | 35–154; с пропусками/обрезкой | 4 179 |
| src/Module/Chat/Application/Mapper/ChatMessageDtoMapper.php | 2 | 1–52 (несколько окон); с пропусками/обрезкой | 3 553 |
| apps/web/src/Module/Chat/Controller/ChatMessage/Presenter/StreamedPresenter.php | 2 | 33–83; с пропусками/обрезкой | 3 508 |
| apps/web/src/Module/Chat/Controller/ChatMessage/ViewController.php | 2 | 1–55 (несколько окон) | 3 135 |
| src/Module/Chat/Application/Dto/ChatMessageDto.php | 2 | 1–42 (несколько окон); с пропусками/обрезкой | 1 748 |
| docs/architecture/infrastructure-containers.md | 1 | 1–193 | 11 359 |
| apps/web/src/Module/Chat/Resource/templates/chat-message/citation/document_context.html.twig | 1 | 1–116 | 8 277 |
| devops/make/compose.mk | 1 | 1–162 | 4 725 |
| apps/web/src/Module/Chat/Controller/ChatMessage/Citation/DocumentContextController.php | 1 | 1–82 | 3 226 |
| docs/agents/roles/team/team_lead_aragorn.ru.md | 1 | 1–49 | 3 073 |
| apps/web/src/Module/Billing/Route/TBusinessPaymentRoute.php | 1 | 1–73 | 2 988 |
| tests/Unit/Module/Chat/Application/Mapper/ChatMessageDtoMapperTest.php | 1 | 1–66 | 2 757 |
| apps/web/src/Module/Chat/Controller/ChatMessage/SendController.php | 1 | 1–61 | 2 237 |
| apps/web/src/Module/Chat/Controller/ChatMessage/Citation/Presenter/DocumentContextPresenter.php | 1 | метаданные/сводка; с пропусками/обрезкой | 2 185 |
| src/Module/Chat/Infrastructure/Service/ChatRender/ChatRendererAsHtmlService.php | 1 | 1–60 | 2 158 |
| tests/Unit/Module/Chat/Domain/Entity/ChatMessageModelTest.php | 1 | 1–62 | 1 998 |
| src/Component/Test/IntegrationTestCase.php | 1 | 1–64 | 1 988 |
| apps/web/assets/controllers/chat/_showChatError.js | 1 | метаданные/сводка; с пропусками/обрезкой | 1 982 |
| devops/make/e2e.mk | 1 | 82–118 | 1 740 |
| src/Module/Chat/Application/Factory/ChatPreconditionExceptionFactory.php | 1 | 1–52 | 1 723 |
| apps/web/tests/Support/Trait/ChatMessageModelTrait.php | 1 | 1–61 | 1 698 |
| migrations/2026/08/Version20260802035943.php | 1 | 1–40 | 1 585 |
| apps/web/tests/Support/Stub/Module/Chat/Controller/ChatMessage/Presenter/StreamedPresenterStub.php | 1 | 1–47 | 1 570 |
| apps/web/tests/Integration/Module/Chat/Controller/ChatMessage/SendControllerTest.php | 1 | метаданные/сводка; с пропусками/обрезкой | 1 448 |
| удалённый prompt-файл (путь скрыт) | 1 | 1–23 | 1 330 |
| todo/TASK-chat-agent-run-lifecycle.todo.md | 1 | 78–107; с пропусками/обрезкой | 1 249 |
| src/Module/Chat/Application/UseCase/Query/ChatMessage/GetById/GetByIdQueryHandler.php | 1 | 1–36 | 1 214 |
| Makefile | 1 | 179–199 | 1 186 |
| src/Module/Chat/Application/Exception/ChatPreconditionException.php | 1 | 1–48 | 1 043 |
| apps/web/src/Module/Chat/Controller/ChatMessage/AskController.php | 1 | 28–179; с пропусками/обрезкой | 1 033 |
| src/Infrastructure/Component/CommandBus/CommandBusComponent.php | 1 | 1–34 | 1 000 |
| apps/web/tests/Integration/Module/Chat/Controller/ChatMessage/ShowControllerTest.php | 1 | 19–52; с пропусками/обрезкой | 983 |
| src/Component/Test/KernelTestCase.php | 1 | 1–31 | 923 |
| tests/Integration/Module/Chat/Application/UseCase/Command/ChatMessage/Send/SendCommandHandlerTest.php | 1 | 13–25 | 753 |
| apps/web/src/Module/Chat/Controller/ChatMessage/Presenter/StreamedPresenterInterface.php | 1 | 1–18 | 489 |
| .env | 1 | 430–438 | 418 |
| src/Module/Chat/Application/Exception/UserFacingChatExceptionInterface.php | 1 | 1–19 | 369 |
| apps/web/src/Module/Chat/Resource/templates/chat-message/_turbo_frame_messages.html.twig | 1 | 1–9 | 330 |
| apps/web/src/Module/Chat/Resource/templates/chat-message/_messages.html.twig | 1 | 1–7 | 268 |
| reports/chat-quality-evidence/README.md | 1 | метаданные/сводка | 0 |
| reports/chat-quality-evidence/U1-C1.md | 1 | метаданные/сводка | 0 |
| reports/chat-quality-evidence/U2-C1.md | 1 | метаданные/сводка | 0 |
| reports/chat-quality-evidence/U3-C2.md | 1 | метаданные/сводка | 0 |
| reports/chat-quality-evidence/U4-C1.md | 1 | метаданные/сводка | 0 |
| src/Module/Chat/Application/UseCase/Query/ChatMessage/GetById | 1 | метаданные/сводка | 0 |
Методика: результаты grep и glob намеренно не включены в эту таблицу: они отражали поиск/перечень путей, а не прочитанные файловые фрагменты. Тексты кода, промптов и конфигурации в отчёт не копируются; содержимое .env и удалённого prompt-файла исключено.
Ошибки, тупики и лишний контекст
isError=true; кроме них были неудачные тестовые и инфраструктурные команды, часть которых скрывала ненулевой exit code из-за shell-пайплайнов.Самые затратные по объёму участки — начальная реализация и поздний рефакторинг маршрута: вместе они дали около 72.9% всего tool-result body + details. Это не точная токенизация, а оценка объёма транскрипта; tool-output символы не равны usage tokens.
| Эпизод | Наблюдение | Влияние на расход / ход работы |
|---|---|---|
| Широкий поиск | В нескольких местах использовались широкие glob/grep-scope по дереву приложения, включая vendor, source maps и большие каталоги. | В модель попадали большие списки кандидатов и повторяющиеся совпадения; полезный scope сужался поздно. |
| Неверная гипотеза | Для задачи подсветки сначала разбиралась сложная схема offsets → DOM; позже выяснилось, что нужная сегментная логика уже была в коде. | Лишние чтения и обсуждение; отдельная задача была отменена без изменения кода. |
| Разведка окружения | Сначала проверялись внешние хосты, IP и порты; после уточнения использовались локальные aserv/nserv. | Порядка 25 bash-проверок и их выводов оказались нерелевантными для локального сценария. |
| Цепочка редактирования | Автоматические последовательные правки временно повредили контроллеры: терялись queryBus/messages/import, появлялся дублирующий маршрут. | Интеграционные тесты проходили через 8 → 5 → 2 ошибки; потребовались повторные чтения и восстановление. |
| Проверки shell | Часть команд завершалась диагностикой внутри tail/grep-пайплайнов, скрывавших исходный exit code. | Ошибка обнаруживалась позднее и требовала повторного запуска с явной проверкой статуса. |
| Ошибки инструментов | В snapshot зафиксировано 9 toolResult с isError=true: неверные пути, stale hash/conflict, невалидный ask, неудачные edit/write и один неоткрывшийся PHP-файл. | Повторные read/edit/ask и дополнительные циклы диагностики. |
| Неуспешные проверки | Помимо isError были несовместимый конструктор в unit-тесте, отсутствующая DB-колонка/fixture, ошибки E2E, DI/Twig/import и удалённый доступ; в конце проверки были исправлены. | Раздувание поздней фазы: не только исправление, но и повторная проверка после каждого промежуточного регресса. |
Вывод: основной резерв — начинать с узкого scope, не проверять удалённую инфраструктуру до подтверждения топологии, читать файл перед edit/write и отделять исправление от независимой проверки. Таблица файлов выше по-прежнему содержит только targets из read; grep/glob здесь упоминаются как источники лишнего tool output, но не считаются прочитанными файлами.
Сабагенты и skills
В tool payload не найдено вызовов
subagent, spawn или delegate. Количество: 0.Загрузок
SKILL.md или tool calls навыков не найдено. Упоминания слова «skill» внутри прочитанных файлов не считаются вызовом.Технические сигналы
- Модель/provider: glm-5.2 / zai во всех ответах с usage.
- Распределение остановок: toolUse 387stop 12aborted 2error 3.
- В 15 пользовательских продолжениях — в среднем 26.9 ответа модели на одно продолжение.
- Наблюдался отдельный ответ после долгой паузы с 415.8K свежего input; точную внутреннюю причину реконструкции контекста по журналу утверждать нельзя.
Что не следует заключать
- 97.9% cacheRead не означает 97.9% бесполезного расхода: кэш — механизм переиспользования и обычно дешевле свежего input.
- Raw total нельзя напрямую трактовать как фактическую сумму по подписке; $30.41 — значение cost из OMP usage.
- Количество tool calls само по себе не измеряет результативность. Для эффективности нужны принятые изменения, тесты и качество результата.
- Причину одного конкретного запроса нельзя доказать только агрегированными счётчиками; выводы выше — наблюдения и операционные гипотезы.
Рекомендации для следующего запуска
1. Разделять по логическим задачам
Один epic, PR-консолидация, production-evidence и последующий рефакторинг — отдельные сессии с коротким handoff. В этой сессии на первые и последние крупные фазы пришлось 39.2% raw расхода.
2. Перезапускать сессию при росте контекста
Практический триггер — когда обычный вызов стабильно превышает 200–250K raw или нужно вернуться после длительной паузы. Перед стартом новой сессии сохранить краткое резюме, список изменённых файлов и команды проверки.
3. Ограничивать чтение и поиск
Для read/grep задавать узкий путь, лимит строк и исключения для vendor, map, cache и generated файлов. Сначала получать структуру/символы, затем читать только нужные фрагменты.
4. Собирать production-факты отдельно
Сходить за данными, вернуть компактную таблицу с периодом и запросом, затем продолжить в свежем контексте. Не таскать полные ответы инфраструктурных команд через весь epic.
Методика и воспроизводимость
- Источник: один OMP JSONL session snapshot; абсолютный путь источника намеренно не указан.
- Для каждого assistant message суммированы поля
usage.input,usage.cacheRead,usage.output,usage.totalTokensиusage.cost.total. - В OMP-схеме
inputуже не включает cacheRead, поэтомуtotalTokens = input + cacheRead + outputдля этого снимка. - Фазы разделены по времени пользовательских сообщений; exact prompt text и tool output text не сохранялись в отчёте.
- Явные ошибки считаются по
toolResult.isError. Командные сбои, видимые только в stdout/stderr, приведены консервативно: shell-пайплайны могли скрывать их exit code. - Числа относятся к моменту окончания снимка: 2026-08-13 21:45. Если сессия была продолжена позже, отчёт не обновляется автоматически.