Опубликовано
Подстановка решений в агенте: что даёт приёмка
Автор: Гусев Николай [портфолио]
Темы: ai-agents, token-efficiency, harness
В начале ноября в трекере Hermes Agent появился issue с предложением снимать часть вызовов модели на границе инструмента. Я отправил туда свой замер и отдельный issue про метрику, которой в проекте нет.
Расскажу, что вы получите, если это примут, и почему выгода в токенах вас, скорее всего, разочарует.
Про что речь
Агент после каждого результата инструмента снова зовёт модель. Отдаёт ей всю историю целиком, получает рассуждение и следующее действие. Часть таких вызовов ничего нового не решает: если предыдущее рассуждение уже зафиксировало и команду, и её аргументы, то результат нужен только чтобы понять, можно ли эту команду выполнять.
Статья HarnessMM (arXiv 2610.32813, Tsinghua и MSRA) делит неопределённость на две части. Что делать - это семантическая, её снимает только модель. А можно ли это делать сейчас - исполнительная, и её снимает сам результат инструмента. Харнесс же платит за обе каждый раз, потому что не различает их.
Механизм состоит из трёх частей. Модель на медленном шаге выдаёт текущее действие и заодно банк будущих, у каждого записаны литеральные аргументы, предшественник и условие допуска. Дальше банк переживает переходы: после каждого результата считается, какие узлы допустимы, и условие проверяется по фактическому результату, а не по догадке. Допустимое действие исполняется ровно с записанными аргументами, без обращения к модели, и на этот шаг выписывается сертификат: какой узел, какой предшественник, какие аргументы, какой ответ инструмента.
Что я померил у себя
Свою статью я читал не как рецензент, а как человек, который собрался это внедрять. Поэтому первое, что сделал, полез в свой журнал вызовов. Там 3246 сессий, 183 961 вызов модели и 2.97 млрд токенов за всё время.
Вход в этом расходе занимает 96.2%, выход 3.8%. Средний вызов отправляет 15 509 входных токенов и получает 621 выходной. Попаданий в кэш провайдера в 10.6 раза больше, чем платного входа.
Дальше главное. 89.1% ходов ассистента стоят сразу после результата инструмента. Из них 55.1% вообще без текста, только вызов инструмента, и 54.8% - ровно один вызов. То есть та популяция, которую механизм и адресует, в моём журнале огромна.
Где выгода оказалась маленькой
Дальше я попробовал ответить на вопрос, который в issue не задан: а сколько из этих ходов действительно уже решены. Действие, объявленное в тексте предыдущего шага, нашлось в 0.3% случаев. При мягком пороге в одно общее слово - 9.4%. Точный повтор команды с теми же байтами аргументов в той же сессии - 2.98% из 104 534 вызовов инструментов, а со сравнением по нормализованному JSON - 5.21%.
Верхняя граница экономии от простой дедупликации решений вышла 1.79% всего расхода, и это до учёта стоимости авторства банка. На нормализованном основании 3.15%.
Ещё один прогон, синтетический, на 98 эпизодах с четырьмя шагами. При доле уже решённых действий 0.55 механизм даёт минус 9.69% токенов. При 0.20 он даёт плюс 7.96%, то есть убыток: авторство банка и работа селектора дороже снятых вызовов. Точка безубыточности около 0.36.
Вывод, который я и отправил в трекер: на моей нагрузке это не экономия в 30 или 88%, а маленькая экономия. Заголовочные числа статьи получаются, когда рядом с механизмом стоит ещё настройка промптов и сжатие контекста. Их собственная аблация без этих надстроек даёт 26.91% на повторном использовании банка и 19.52% на снятии обратного вызова.
Что тогда даёт приёмка
Если выгода в токенах маленькая, зачем это вообще нужно. Вот четыре вещи, которых сейчас нет ни в Hermes, ни у меня.
Число вместо мнения. В проекте у метрики токенов есть только разделение на основной и вспомогательный вызов. Отличить вызов, который ответил на вопрос человека, от вызова, который выдал следующую команду, нечем. Я открыл отдельный issue (#148373) с предложением добавить измерение границы и секцию в отчёт об использовании. Польза тут не в механизме: это база, против которой можно проверять любую оптимизацию, включая уже отгруженную подсказку про параллельные вызовы, эффект которой сейчас никто не знает.
Удостоверение автономии. Сертификат связывает узел решения, ответ инструмента и точные аргументы. Это не приём для экономии токенов, это аудиторский артефакт, который отвечает на вопрос, какие шаги агент решил сам, а какие лишь буквально исполнил. Для регламентированных процессов, где нужно показать прослеживаемость решений, ценность здесь выше, чем вся экономия.
Регрессионные прогоны без модели. Снятый с боевого эпизода банк действий есть детерминированный сценарий: литеральные аргументы плюс условия, читаемые из ответов инструментов. Его можно переигрывать на каждом изменении промпта или инструмента, не тратя ни одного токена. Статья этого применения не упоминает, но оно следует прямо из её контракта.
Потолок цены эпизода. Полный учёт даёт верхнюю границу стоимости задачи. Если все шаги подменяемы, цена равна авторству плюс число шагов, умноженное на селектор. Для продукта с фиксированной ценой это твёрдый потолок расхода вместо среднего по больнице.
Почему приёмка дешёвая
Сильная часть моего комментария не про пользу, а про то, что делать почти нечего. Механизм «выполнить вызов инструмента без обращения к модели» в Hermes уже есть и покрыт тестами: скриптовая прелюдия проигрывает заготовленные шаги через обычный раунд инструментов, хуки срабатывают, строка пишется до побочного эффекта, вызов модели не считается. Подключена она ровно к одному месту и работает только до хода.
Там же лежит и поверхность наблюдений: защита от зацикливания уже считает сигнатуры вида «инструмент, аргументы, результат» и держит серию повторов, но использует это только чтобы предупредить о петле. Нужен не новый подсистемный слой, а обобщение двух существующих мест.
Цена ошибки стража
Условие допуска проверяет факт, а не смысл. Страж может подтвердить, что файл существует, а сборка упала с известным кодом. Он не может подтвердить, что повторять запись безопасно.
Мой прогон это показывает в числах. При доле ложных допусков 0.10 стоимость эпизода растёт с 6.160 до 7.183 тысяч токенов, и в эпизод попадают неверные действия. Ложный допуск дороже снятого вызова, потому что за ним идёт откат.
Отсюда ограничение, которое я добавил в список требований: подменять только идемпотентные и читающие действия. Запись, удаление и перезапуск боевого узла идут через модель, даже если условие выполнено.
Что осталось непроверенным
Числа авторов я не воспроизводил: нужны их рантаймы, их бэкбоны и их бюджеты вызовов. Мой прогон проверяет механику и учёт, а не их замеры.
Деньги я не считал. В моём журнале кэш в 10.6 раза больше платного входа, значит снятый токен входа стоит меньше номинала, и переводить 29% токенов в 29% счёта нельзя.
И маленькая честность про себя. Долю «действие было объявлено заранее» я мерил по пересечению слов, а текст плана пуст перед 47.5% таких ходов. Значит 0.3% это нижняя граница дисциплины объявлений, а не доля решённого. Мерить точнее можно только на размеченном корпусе, которого у меня нет.
Что дальше
Комментарий и issue опубликованы, ссылки живые, оба текста я перечитал после отправки. Следующий шаг не мой: нужен ответ мейнтейнера, интересен ли хук. Если интересен, я готов собрать плагинную часть и приложить прогон с негативным контролем, где обратный вызов остаётся на месте. Такой контроль отделяет подмену от сопутствующей настройки, и без него любая цифра экономии ничего не доказывает.
Если хотите повторить перепись на своём журнале, вот запрос. Он считает ту самую долю ходов на границе.
with m as (
select session_id, id, role, content, tool_calls,
lag(role) over (partition by session_id order by id) prev_role
from messages where active = 1
)
select count(*) turns,
sum(case when prev_role = 'tool' then 1 else 0 end) post_tool,
sum(case when prev_role = 'tool'
and (content is null or trim(content) = '')
then 1 else 0 end) silent_post,
sum(case when prev_role = 'tool'
and (content is null or trim(content) = '')
and trim(coalesce(tool_calls,'')) <> ''
then 1 else 0 end) silent_with_call
from m where role = 'assistant';
Мой ответ на вопрос «сколько тут можно сэкономить» получился скучным. Зато вопрос «сколько мне это будет стоить в худшем случае» наконец имеет ответ.