ГлавнаяБлогАудит токенов: как исправить баг и проверить данные
Алгоритмы

Аудит токенов: как исправить баг и проверить данные

Разбираем аудит токенов в Clawdmeter: как найти баг, исправить его и проверить данные. Практические советы для разработчиков.

Al
Редакция Algolitalgolit.ru
8 мин чтения9 августа 2026 г.

Аудит токенов: как найти и исправить баг в трекере расхода токенов

Вы когда-нибудь задумывались, почему счётчик токенов в вашем инструменте показывает цифры, которые не сходятся с реальностью? Мы разобрали баг в Clawdmeter — приложении для отслеживания расхода токенов Claude Code. Оказалось, что все числа были завышены в 2.34 раза из-за неправильного суммирования записей в JSONL-файлах. В этой статье вы узнаете, как находить такие ошибки, почему важно запускать код автора, а не свою модель, и как проверять чужие исправления.

Суть бага: почему счётчик завышал токены

Проблема в том, что Claude Code записывает одно сообщение ассистента в несколько JSONL-записей — по одной на каждый блок контента. Каждая запись содержит одинаковый message.id и одинаковый объект usage. В src/transcript.py суммировались токены для каждой записи, а не для каждого сообщения. Это приводило к завышению в 2.34 раза. Мы проверили три функции: подсчёт токенов для баров 5ч/7д, цены на странице Stats и итоги сессии. Все три дали завышенные результаты.

Как мы воспроизвели ошибку

Вместо того чтобы переписывать логику приложения, мы импортировали его собственный модуль transcript.py и вызвали его функции. Для этого понадобился всего лишь двенадцатистрочный стаб для PySide6:

import types, sys

pkg = types.ModuleType("PySide6")
qtcore = types.ModuleType("PySide6.QtCore")
qtcore.QObject = ...  # три no-op класса
sys.modules["PySide6"] = pkg
sys.modules["PySide6.QtCore"] = qtcore
sys.path.insert(0, str(clawdmeter_clone / "src"))
import transcript as T  # его модуль, без изменений
T._file_token_events(path)  # его функции, его числа

Такой подход устраняет любые споры о том, что мы неправильно поняли код. Мы получаем числа из его собственных функций, и остаётся только вопрос о честности входных данных. Мы использовали синтетический корпус с известным манифестом, что делает проверку однозначной.

Исправление за три дня

Мейнтейнер подтвердил баг 6 августа, а 8 августа вышел релиз v3.0.1 с исправлением. В примечании к релизу он написал: "Ваши числа токенов и стоимости упадут примерно в 2.5 раза. Это исправление, а не регрессия". Важно отметить, что мейнтейнер не использовал наш скрипт для воспроизведения — он проверил проблему самостоятельно. Это даже лучше, потому что подтверждение не зависит от нашего кода.

Ответный аудит: что нашёл мейнтейнер

В своём комментарии мейнтейнер не только подтвердил баг, но и указал на два наших недочёта. Во-первых, повторяющиеся объекты usage не всегда идентичны. В его корпусе 3799 групп отличаются, и в каждой output_tokens — это накопительный итог. Например, сообщение может иметь 5, 5, 5, 328 токенов в четырёх записях. Если брать первую запись, получится 5 токенов вместо 328. Правильно — брать максимум по каждому бакету. Во-вторых, дедупликация по файлу недостаточна: 1094 идентификатора сообщений встречаются в нескольких файлах из-за возобновления сессий. Нужно дедуплицировать на уровне всего аккаунта, а не только файла.

Наш ответ: поле, а не версия

Мы перепроверили свои данные и обнаружили, что наше утверждение о 100% идентичных записях было верным только для основного пути разговора. В побочных цепочках (сабагентах) только 20.82% записей идентичны. Различие определяется полем isSidechain, а не версией Claude Code, как предположил мейнтейнер. Мы проверили: гипотеза о версии предсказывала бы различия в основном пути, но их нет. Гипотеза о поле предсказывает различия только в побочных цепочках — что и наблюдается.

Ловушка, которую мы чуть не пропустили

Если группировать записи только по message.id, то в нашем корпусе появляются 560 групп с немонотонными счётчиками — это артефакт из-за перемешивания записей из разных файлов. Группировка по паре (файл, message.id) устраняет все 560. Это предупреждение для тех, кто захочет написать проверку: не группируйте только по id, иначе получите ложные результаты.

Проверка исправления: зелёный свет

После выхода v3.0.1 мы запустили наш харнесс против обеих версий. На v3.0.0 — красный, как и ожидалось: 2.338×, 2.338×, 2.373×. На v3.0.1 — зелёный, все числа точные до цифры: 1,108,697 и 732,191, 540 строк для 540 сообщений. Пришлось адаптировать проверку, потому что _file_token_events теперь возвращает несвёрнутые события с ключами записи и сообщения. Это подтверждает, что исправление реализовано именно так, как мы рекомендовали.

Что мы узнали и что советуем вам

Главный вывод: запускайте код автора, а не свою модель. Это устраняет целый класс споров. Второе: относитесь к отчёту об исправлении как к набору данных — в нём может быть больше измерений, чем в самом баге. Третье: публикуйте инварианты с указанием области применимости. Наше "100%" было верным для основного пути, но мы не указали это. Четвёртое: когда два корпуса расходятся, ищите поле, а не версию. Поле isSidechain объясняет форму данных лучше, чем версия.

Практические шаги для вас

Если вы аудируете трекеры токенов или пишете свои, вот что делать прямо сейчас:

  • Импортируйте модули приложения и вызывайте его функции, а не переписывайте логику.
  • Проверяйте, не суммируются ли записи вместо сообщений — это частая ошибка.
  • Группируйте по паре (файл, message.id), а не только по id.
  • Для повторяющихся usage-объектов берите максимум по каждому бакету, а не первую запись.
  • Указывайте область применимости своих измерений, чтобы не вводить в заблуждение.

Аудит токенов — это не разовая задача, а постоянный процесс. Используйте эти уроки, чтобы находить и исправлять ошибки быстрее и точнее.

#аудит токенов#JSONL#отладка#Python#Claude Code
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →