Один ход агента — 120 000 токенов. Разбираемся, куда они уходят и как мы это починили. ai.. ai. DevOps.. ai. DevOps. llm.. ai. DevOps. llm. Natural Language Processing.. ai. DevOps. llm. Natural Language Processing. openrouter.. ai. DevOps. llm. Natural Language Processing. openrouter. агентные системы.. ai. DevOps. llm. Natural Language Processing. openrouter. агентные системы. агенты.. ai. DevOps. llm. Natural Language Processing. openrouter. агентные системы. агенты. высоконагруженные системы.. ai. DevOps. llm. Natural Language Processing. openrouter. агентные системы. агенты. высоконагруженные системы. Машинное обучение.. ai. DevOps. llm. Natural Language Processing. openrouter. агентные системы. агенты. высоконагруженные системы. Машинное обучение. Облачные вычисления.. ai. DevOps. llm. Natural Language Processing. openrouter. агентные системы. агенты. высоконагруженные системы. Машинное обучение. Облачные вычисления. оптимизация.. ai. DevOps. llm. Natural Language Processing. openrouter. агентные системы. агенты. высоконагруженные системы. Машинное обучение. Облачные вычисления. оптимизация. токены.
Один ход агента — 120 000 токенов. Разбираемся, куда они уходят и как мы это починили - 1

Мы делаем Uma Computer – автономного агента, который умеет не отвечать, а делать: искать в сети, генерировать медиа, резать видео на клипы, публиковать результат. Под капотом – агентный цикл на базе hermes-agent, свои инструменты через MCP и оплата по токенам.

И вот приходит пользователь с вопросом, от которого неприятно холодеет: «Почему один мой запрос стоил 38 кредитов? Я посмотрел цены на OpenRouter – по факту это должно было стоить втрое меньше».

Он был прав. Дальше – как мы искали причину, что нашли (спойлер: не то, что ожидали) и что с этим сделали.

Первая гипотеза была неверной

Открываем биллинг за тот ход:

prompt_tokens: 119 208
completion_tokens: 1 018
total_tokens: 120 226

Соотношение говорит само за себя: почти всё – вход, а не выход. Модель не писала простыню, она её читала.

Первое, что приходит в голову любому, кто трогал агентов – длинная история диалога. Классика – мы отправляем последние n сообщений, среди них оказался транскрипт часового видео, и вот вам сто тысяч токенов.

Гипотеза красивая, и код её подтверждал. В сборке промпта было честное:

const conversationBlock = history
.slice(-30) // ← последние 30 сообщений
.map(m => ${role}: ${m.content})
.join(‘nn’);

slice(-30) без ограничения по объёму действительно бомба. Одно сообщение с транскриптом, и стоимость каждого следующего хода взлетает.

Мы почти начали это чинить. А потом посмотрели на конкретный диалог, где случились те 38 кредитов. В нём было два сообщения. Суммарно 530 символов.

История была ни при чем. Мы собирались оптимизировать то, что в этом случае вообще не влияло и, если бы не проверили, отчитались бы об «успешной оптимизации», не сдвинув счет ни на копейку.


Где на самом деле были токены

Замерили все, что уходит в промпт, по частям:

Один ход агента — 120 000 токенов. Разбираемся, куда они уходят и как мы это починили - 2

Для кириллицы делитель ~3 символа на токен (латиница экономнее, но у нас интерфейс русский).13 900 токенов. Считаем: 120 226 / 13 900 ≈ 8,6.Вот и ответ. Дело не в размере контекста, а в количестве его повторов.


Ключевой момент, который легко упустить

Агентный цикл – это не один запрос к модели. Это цикл: подумал → вызвал инструмент → получил результат → подумал снова. Каждая итерация – отдельный вызов LLM. И на каждом вызове заново отправляется весь контекст: системная инструкция, схемы всех инструментов, память, история.

То есть накладные расходы умножаются на число шагов.

1 ход пользователя
├── шаг 1: 13.9k токенов контекста + разбор задачи
├── шаг 2: 13.9k токенов контекста + вызов инструмента
├── шаг 3: 13.9k токенов контекста + разбор результата
├── …
└── шаг 9: 13.9k токенов контекста + финальный ответ

≈ 120k токенов за один «простой» вопрос

Восемь шагов – это не патология, это нормальная работа агента: скачать видео, проверить результат, обработать ошибку, попробовать иначе, ответить. Каждый шаг честный. Но каждый тащит за собой те же 13.9k.

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


Ещё одна засада: предоплатное резервирование

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

HTTP 402: This request requires more credits, or fewer max_tokens.
You requested up to 8192 tokens, but can only afford 875.

Формулировка сбивает с толку: баланс не пустой, а запрос не проходит.

Дело в том, что провайдер резервирует стоимость худшего случая до начала генерации: вход + max_tokens. Мы ставили max_tokens = 8192. Со раздутым до 120k входом резерв получался огромным – и на дорогой модели баланса на него не хватало, хотя фактический расход был бы в разы меньше.

То есть распухший контекст не просто дорого стоит. Он ещё и блокирует запросы, которые вы в состоянии оплатить.


Что мы сделали

Главный принцип, который мы для себя вывели: нельзя молча прятать контекст от модели.

Это звучит очевидно, но именно здесь ломается большинство «оптимизаций». Если просто выкинуть половину истории, агент об этом не узнает. Он будет уверен, что видит всё, и начнёт делать выводы на неполных данных – уверенно и неправильно. Сэкономленные токены вы оплатите вдвое: неверными действиями и повторными запросами.

Поэтому у нас две категории решений, и ни одна из них не «просто обрезать».

Первое: перенести объём из «всегда в промпте» в «доступно по запросу».

Часть контекста, которую мы предзагружали, была уже доступна агенту через инструменты. Профиль пользователя – 12 000 символов на каждом шаге при этом существует инструмент, который его читает. Получалось, что мы платим за предзагрузку того, что агент и сам может взять, когда понадобится.

Теперь для задач, где этот контекст явно не нужен, вместо него уходит короткая строка-указатель: данные есть, вот инструмент, вызови если понадобится. Возможности не теряются – меняется только момент оплаты.

Отдельно отмечу, как мы выбирали направление ошибки. Детектор релевантности намеренно широкий: лучше лишний раз приложить контекст и заплатить, чем не приложить и потерять качество. Ложное срабатывание стоит токенов, ложный пропуск стоит доверия к агенту. Асимметрия очевидная, и она должна быть заложена в код, а не в надежду.

Второе: бюджет в символах, а не в сообщениях.

slice(-30) считает «ок» на 40 символов и транскрипт на 60 000 равноценными. Это неверная единица измерения. Мы перешли на бюджет по объёму с приоритетами:

  • Последние несколько сообщений – всегда дословно: в них живёт текущая задача, и здесь потери недопустимы;

  • Первое сообщение пользователя – якорь цели: на длинной задаче агент не должен забыть, о чём его вообще просили;

  • Остальное – под остаток бюджета, и каждая обрезка помечена явно: «обрезано n символов», «опущено n сообщений».

Последний пункт – то самое отличие от «просто обрезать». Видимый маркер даёт агенту повод спросить или уточнить. Молчаливое сокращение – повод для уверенной ошибки.

Проверяли на четырёх формах диалога: короткий не меняется вообще (никаких маркеров, никакой деградации), 60k-транскрипт сжимается до бюджета с сохранением свежих сообщений и цели, тред из 200 сообщений держит и якорь, и последнее сообщение.

Третье: скорость как часть цены.

Побочный, но важный вывод. У нас есть бесплатные модели, и на них агент работает заметно медленнее – не потому что «модель плохая», а потому что бесплатный тариф провайдера стоит в очереди. Пользователь видит «агент тормозит» и не понимает почему.

Теперь в выборе модели честно показано, чего ожидать по скорости. Это не оптимизация токенов, но это та же болезнь: непрозрачность стоимости. Человек должен понимать, за что платит и чем платит – деньгами или временем.


Какой из этого стоит сделать вывод

Если вы строите агента на любом фреймворке, вот что мы бы проверили на вашем месте:

  1. Умножьте размер вашего промпта на число шагов цикла. Это и есть реальная цена хода, а не то, что вы видите в одном запросе. Большинство удивляется на этом шаге.

  2. Посчитайте схемы инструментов отдельно. У нас это 45% накладных. Каждый новый инструмент – это налог на каждый шаг каждого хода, навсегда. Инструменты не бесплатны, даже когда не вызываются.

  3. Проверьте, что вы не предзагружаете то, что доступно инструментом. Это самая безболезненная экономия из существующих.

  4. Не измеряйте историю в сообщениях. Измеряйте в объёме.

  5. Помечайте любую обрезку явно. Это разница между экономией и деградацией.

  6. Проверяйте гипотезу на конкретном случае, прежде чем чинить. Мы почти оптимизировали историю диалога в кейсе, где она составляла 530 символов из 120 000 токенов.


Зачем мы это рассказываем?

Честно: потому что это наше конкурентное преимущество, и мы предпочитаем говорить о нём вслух.

Uma Computer – не обёртка над чужим API. Мы держим свой агентный рантайм, и это значит, что такие вещи мы можем найти и починить. Агрегатор, который просто проксирует запросы, эту проблему даже не увидит – у него нет доступа к тому слою, где она возникает.

Мы не «сделали агента дешевле, урезав ему мозги». Мы убрали то, за что платили зря, оставив агенту всё, что ему нужно для работы. Разница принципиальная, и именно за неё стоит держаться.

Если интересно посмотреть, как это работает на живых задачах – Uma Computer. Оплата по расходу, без подписки: платите за то, что реально использовали. После этой правки – заметно меньше. Во второй части расскажу, как мы изолируем агентов друг от друга: один Docker-контейнер на пользователя, свой том, свои лимиты, и почему без этого автономного агента в продакшн выпускать нельзя.

Замеры делались на реальных прод-ранах, цифры в таблицеиз нашего биллинга, не из головы. Если у вас похожая архитектура и цифры сильно другие – расскажите в комментариях, интересно сравнить.

Если вам интересна тема AI‑агентов и внедрения нейросетей, заглядывайте в мой Telegram‑канал ДругОпенсурса. Там я публикую свежие новости и разборы инструментов в числе первых. |

Автор: Qwertcoser

Источник