OMP token usage audit · PR #2829

160M токенов за один PR — и где они осели

Одна OMP-сессия проекта TasK / codexcli, модель glm-5.2. Период активности: 2026-08-12 19:582026-08-14 10:19 (Asia/Novosibirsk). Работа над EPIC chat-quality-reliability и merge-PR #2829. Отчёт построен по одному зафиксированному JSONL-снимку; сырые промпты, исходный код, приватные пути и результаты production-запросов намеренно не встраиваются.

Главный вывод: 98.2% raw-токенов — это пере-чтение накопленного контекста (cacheRead). Свежий ввод и ответ модели вместе — 1.8%.

Raw total
160.18M
input + cacheRead + output = totalTokens
Стоимость OMP
$46.34
встроенная оценка usage; не фактический счёт подписки
Ответы модели
723
все с ненулевым usage; 42 пользовательских продолжения
Tool calls
752
bash / read / edit / grep / eval / glob / todo / write / ask

Состав расхода

cacheRead 98.2% · 157.23Mfresh input 1.6% · 2.50Moutput 0.3% · 0.44M

Полезной «новой» работы (fresh input + output) — 2.94M токенов. Остальные 157.2M — повторное учёние уже накопленной истории на каждом из 723 вызовов.

Длина контекста

Средний raw на ответ — 221.4K. Контекст дошёл до 438.5K, после чего сработали две авто-компактизации (на 438K и 323K), и он снова отрастал.

Медиана ответа: 219.6K; p90: 390.7K; максимум: 438.5K.

Время и паузы

Календарная длительность — 38.3 ч; оценка активной работы агента (без межсессионных пауз) — 4.96 ч.

Сессия возобновлялась 42 раза; основная масса raw пришлась на возобновления при уже большом контексте.

Наблюдение: что именно раздувало расход

98.2% raw tokens — это cacheRead. Кэш удешевляет каждый входной токен, но не отменяет того, что на вызове №700 модель по-прежнему «переваривает» контекст, собранный на вызовах №1–699. За 723 вызова это и дало 157M токенов пере-чтения.

Рост/сброс расхода по окнам

Среднее на ответ росло до ~298K, падало на компактизациях и снова отрастало. Это не монотонный рост, а «накопил → сбросил → накопил».

ОкноОтветовRawСреднееCacheFresh + out
Первые 25251.45M57.9K1.35M94.5K
26–100759.91M132.1K9.77M135.2K
101–20010022.23M222.3K22.09M143.3K
201–30010029.77M297.7K29.25M519.9K
301–500 (после compact.)20050.29M251.5K48.84M1.45M
Последние 22322346.53M208.7K45.94M598.8K

Макро-фазы работы

Границы — по пользовательским продолжениям и таймлайну PR; названия — аналитическая классификация. Тексты запросов не публикуются.

M1 · Запуск EPIC и задача №1 (error-state)08-12 19:58
60.45M raw · 292 ответа · 335 tool calls · 44 edit37.7%
M2 · Открытие PR #2829 + задача №4 (prompt-contract, eval/candidate)08-13 10:20
44.08M raw · 111 ответов · 109 tool calls · 22 edit27.5%
M3 · Шлифовка системного промпта (правила 1–6)08-13 21:42
23.12M raw · 175 ответов · 162 tool calls · 38 edit14.4%
M4 · Финал: sync master, LlmManager refactor, merge08-14 08:32
32.53M raw · 145 ответов · 146 tool calls · 17 edit20.3%

PR смержен 08-14 09:53 (Nsk). M4 включает вторую компактизацию (09:56, на 323K).

Токены vs строки кода: что реально принес PR #2829

160.18M raw-токенов принесли net +602 / −43 строк в 25 файлах (24 non-merge коммита). Это ~266K токенов на добавленную строку и $0.072 API-эквивалента на строку. Полезной «новой» работы (fresh+output) при этом всего ~4.6K токенов на строку — остальное пере-чтение контекста.
Net merged (PR #2829)
+602 / −43
25 файлов · 24 коммита · gh/git
Токенов на net-строку
266K
raw 160.18M ÷ 602 добавленных
$/строку (API-экв.)
$0.072
$46.34 ÷ 645 (add+del)

Состав 602 добавленных строк (по net-диффу merge):

КатегорияКуда≈ строк net
Продуктовый код + шаблонSendCommandHandler, ChatMessageModel, ChatProcessingErrorCodeResolver, 5 контроллеров, _message_user.twig~135
Тестыunit + integration (handler, resolver, mapper, entity)~196
Миграция БДVersion20260812130648 (lastProcessingErrorCode)26
Документы / отчёты / todoeval-report, EPIC-план, backlog, закрытые/отменённые задачи~220
Конфиг.env — candidate CHAT_SYSTEM_PROMPT~4
Сигнал холостого хода в ветке. По всем коммитам ветки кумулятивный churn — ~878 ins / 319 del по тем же файлам: .env и eval-report правились по 10–15 раз каждый (коммиты «refactor(chat): правило N»). То есть реальные правки промпта итерировались в git десятки раз, а в net-дифф почти не видны.

Инструменты и объём возвращаемых данных

Зафиксировано 752 tool call. Размер tool result — в символах, не токенах; это независимый индикатор того, что наполняло контекст.

ИнструментВызововТекст результатаМакс. одинОшибок (isError)
read174601 68340 0641
grep35225 62923 4161
bash324201 9316 9692
edit121111 9746 7795
glob2330 4349 7790
todo2125 7732 2511
eval243 5877180
ask93 3322 2872
write213 0152431
~85% тела tool results дали read + grep + bash. Часть read-вызовов — повторное чтение одних и тех же файлов (см. ниже); каждый такой рерид оплачивается ещё и полным контекстом на этот момент.

Инвентарь OMP tools

Фактические tool calls ассистента. Всего: 752.

ToolВызовов
bash324
read174
edit121
grep35
eval24
glob23
todo21
write21
ask9

CLI-утилиты

Команды верхнего уровня внутри bash (консервативный счётчик, после дедупа по whitelist утилит; cd/echo как обвязка не показаны).

УтилитаЗапусков
tail265
git210
head197
grep157
timeout134
php50
sed31
docker29
gh26
find20
psql17
ssh / scp / sleep5 / 5 / 5

tail+head+grep = 619 запусков: чаще всего пересрезка одних и тех же логов/выводов, что дополнительно наполняло контекст.

Файлы и фрагменты, попавшие в контекст

Что показано: содержательные цели из 174 вызовов read — ≈100 целей из ~90 путей. Пути приведены относительно корня проекта; абсолютный cwd намеренно убран.
Файл (относит.)НаблюденийСимволов
src/Module/Chat/Application/UseCase/Command/ChatMessage/Send/SendCommandHandler.php1552 475
reports/chat-quality-evidence/eval-2026-08-12-prompt-baseline-vs-candidate.md~1891 319
todo/EPIC-chat-quality-reliability.todo.md638 870
tests/Unit/Module/Chat/Application/UseCase/Command/ChatMessage/Send/SendCommandHandlerTest.php626 587
reports/chat-quality-evidence/{README,U1-C1,U2-C1,U3-C2,U4-C1}.md (бандл)1 (×5)40 064
todo/TASK-chat-response-prompt-contract.todo.md424 912
docs/architecture/infrastructure-containers.md116 784
todo/AGENTS.md115 027
apps/web/assets/controllers/chat/_messageSender.js312 209
todo/TASK-chat-message-processing-error-state.todo.md112 052
src/Module/Chat/Integration/Service/LlmManager/LlmManagerService.php611 871
apps/web/.../templates/chat-message/_message_assistant.html.twig19 560
Повторное чтение как множитель. SendCommandHandler.php читали 15 раз, eval-report — ~18 раз, EPIC-todo — 6 раз. Каждый рерид не просто добавлял символы — он оплачивался полным контекстом того вызова, то есть стоил тем дороже, чем дальше по сессии.

Ошибки, тупики и лишний контекст

Зафиксировано 13 tool results с isError=true (edit×5, ask×2, bash×2, по 1 у read/grep/todo/write), а также 3 ответа со stopReason=error и 4 aborted. Кроме явных ошибок часть сбоев команд маскировалась shell-пайплайнами.
ЭпизодНаблюдениеВлияние на расход
«Буря» шлифовки промпта (M3)175 ответов, 38 edit, 23.1M raw — на правку ~6 правил системного промпта. В net-дифф это несколько строк в .env и eval-report.~608K токенов на один edit в среднем; задача про «одно слово в правиле» решалась в возобновляемом контексте, а не пакетным eval-циклом.
Churn в ветке.env и eval-report правились по 10–15 раз (коммиты «refactor(chat): правило N»); net-вклад минимален.Каждая итерация = новое возобновление при большом контексте + git/read/edit на подтверждение.
Рериды одних файловSendCommandHandler×15, eval-report×~18, EPIC-todo×6, LlmManagerService×6.Полные рериды на поздних вызовах оплачивались контекстом ~200–400K.
Infra-разведка в главной нитиЧтение infrastructure-containers.md (17K), deploy-production.md (10K); ~56 infra-вызовов (ssh/docker/psql/scp).Эти данные таскались через весь EPIC и раздували каждый последующий ответ.
Поздние компактизацииТолько 2 авто-компактизации — на 438K и 323K, уже на излёте фаз.До сброса p90 успел дойти до ~391K; явный рестарт сессии помог бы раньше.

Как сделать ту же работу дешевле — с оценками

Базовый принцип: рычаг — контекст, а не объём ответа. Fresh input + output вместе — 1.8% расхода. Значит «писать меньше» почти ничего не даёт; экономит контроль за тем, что модель каждый раз пере-читает.

1. Разнести 4 фазы по 4 сессиям ≈ 3–5×

M1–M4 — логически независимы (реализация error-state, prompt-контракт, шлифовка промпта, финальный merge). Треугольная модель накопления кэша даёт: при старте каждой фазы с пустым контекстом raw-расход оценивается в ~40–53M вместо 160M. Перед стартом — короткий handoff (изменённые файлы + команды проверки).

2. Рестарт при p90 > 250K

Здесь p90 = 391K, и компактизации сработали поздно. Триггер «обычный вызов стабильно > 200–250K raw» → закрывать сессию и открывать новую с резюме. Это режет «хвост» из M3/M4, где ответ стоил ~200–300K ради правки пары строк.

3. Промпт-работу — в оффлайн-eval, не в чат

M3 потратил 23.1M на правку правил. Eval-report уже был; нужно было готовить candidate офлайн, прогонять eval, применять одну правку. Это убирает 19 возобновлений и ~десяток «refactor(chat)» коммитов.

4. Перестать перечитывать файлы целиком

Для read — узкий путь и диапазон строк один раз; для больших файлов держать компактное саммари, а не тянуть их повторно. SendCommandHandler×15 и eval-report×~18 — первые кандидаты.

5. Infra-разведку — в отдельной одноразовой сессии

Сходить за production-фактами (ssh/docker/psql), вернуть компактную таблицу с периодом и запросом, продолжить в свежем контексте. Не таскать 17–40K-бандлы containers/deploy-документов через весь EPIC.

6. Меньше пересрезки вывода

tail+head+grep = 619 запусков, часто по одним и тем же логам. Агрегировать на стороне shell/SQLite и возвращать короткий результат.

Итоговая модельная оценка: комбинация пп. 1–3 (разбиение + рестарты + eval-цикл для промпта) без потери результата могла бы привести raw-расход к ориентиру ~40–55M и стоимость — к ~$12–16 API-эквивалента (против $46.34). Это оценка по модели накопления кэша, а не гарантия.

Сабагенты и skills

Сабагенты: не запускались.
В tool payload не найдено вызовов subagent, spawn или delegate. Количество: 0.
Skills: не вызывались.
Загрузок SKILL.md или tool calls навыков не найдено. Упоминания слова «skill» внутри прочитанных файлов не считаются вызовом.

Технические сигналы

  • Модель/provider: glm-5.2 / zai во всех 723 ответах.
  • Распределение остановок: toolUse 679stop 37aborted 4error 3.
  • 42 пользовательских продолжения — в среднем 17.2 ответа модели на одно.
  • 2 авто-компактизации (на 438.5K и 323.0K tokensBefore).
  • Тело tool results: 1.21M символов; read+grep+bash — ~85%.

Что не следует заключать

  • 98.2% cacheRead ≠ 98.2% бесполезного расхода: кэш дешевле свежего input, это механизм переиспользования.
  • Raw total ≠ сумма по подписке; $46.34 — значение usage.cost.total из журнала OMP.
  • «266K токенов на строку» — не клеймёт результат: PR включал миграцию, тесты, eval-доказательство и отменённую задачу. Это индикатор цены контекста, а не ценности кода.
  • Число tool calls само по себе не измеряет результативность; для эффективности нужен принятый результат при меньшем raw-расходе.
  • Причину конкретного возобновления нельзя доказать агрегированными счётчиками — выводы выше это наблюдения и операционные гипотезы.

Методика и воспроизводимость