Что такое tool-prune и зачем он нужен
tool-prune - это клиентский предварительный фильтр tool-схем. Он отбирает релевантные инструменты из 50+ доступных до вызова модели: вызов router.filter(userPrompt) возвращает массив topTools, и в промпт уходит только этот набор, а не весь каталог функций. Дополнительных обращений к LLM фильтрация не требует, то есть модель не тратит отдельный шаг генерации на выбор инструмента.
Задача выросла из практики локальных агентов. По описанию проекта, при запуске локальных моделей на 7B/8B параметров с инструментами наличие 50+ схем в контексте ухудшает внимание и провоцирует галлюцинации на отвлекающих факторах. Модель путает похожие описания функций, подставляет несуществующие параметры или вызывает инструмент, который к запросу отношения не имеет. Автор приводит эти наблюдения в обсуждении проекта на r/LocalLLaMA.
Альтернатива, встроенный прогрессивный поиск tool_search, устроена иначе: она требует целого дополнительного шага генерации LLM, что добавляет около 2 секунд. Плюс небольшие модели часто забывают вызвать поисковый инструмент или застревают в циклах обнаружения: ищут, не находят, формулируют запрос снова. Обе проблемы бьют именно по малому классу моделей, под который tool-prune и делался.
Экономия считается не в абстрактных процентах, а в нагрузке на контекст. Чем больше места занимают описания функций, тем меньше остаётся на историю диалога, результаты вызовов и рассуждения. Похожую логику сокращения входных токенов через архитектурные решения разбирают в материале про Deep Agents v0.7 и снижение входных токенов на 65%, только там речь о перестройке агентной обвязки, а здесь - об отборе схем на стороне клиента.
Как работает предварительный отбор схем
Весь цикл укладывается в одну строку перед основным запросом к модели. Клиент получает текст пользователя, прогоняет его через фильтр и передаёт модели суженный список инструментов.
Вызов router.filter(userPrompt) и получение topTools
const topTools = await router.filter(userPrompt);
// topTools - схемы, отобранные под конкретный запрос
const result = await model.chat(userPrompt, { tools: topTools });
Результат - массив topTools, который подставляется в запрос вместо полного набора схем. Фильтрация идёт до вызова LLM, поэтому дополнительный шаг генерации не расходуется: модель сразу работает с урезанным набором инструментов. По заявлению авторов, проект не имеет внешних зависимостей, код написан на чистых JS и Python, что упрощает подключение к существующему пайплайну без менеджера пакетов и нативных сборок.
Важно, что фильтр работает на клиенте. Это значит, что никакой API-вызов не уходит наружу ради выбора инструмента, а задержка отбора не смешивается с сетевой задержкой и временем генерации модели.
Роль FWHT в фильтрации за 0.4 мс
FWHT - быстрое преобразование Уолша - Адамара, алгоритм с линейной сложностью по длине вектора. По заявлению авторов, именно он лежит в основе офлайн-фильтрации: 0.4 мс на отбор, а с использованием SIMD - 23 мкс. Для сравнения, дополнительные 2 секунды, которые тратит tool_search на шаг генерации, превышают эту цифру на несколько порядков.
Детали реализации FWHT в исходных материалах не раскрыты. Не описано, какие признаки строятся для запроса и схем, как нормируются векторы и как калибруется порог отбора. Критерии релевантности, по которым topTools попадают в выборку, тоже не опубликованы. Пока это чёрный ящик с заявленной скоростью, и относиться к цифре 0.4 мс стоит как к ориентиру, а не как к измеренной константе.
Сравнение с tool_search: почему встроенный поиск проигрывает
Разница между подходами видна в структуре вызова, а не только в цифрах.
| Подход | Что происходит | Стоимость |
|---|---|---|
| tool_search (встроенный прогрессивный поиск) | Модель сначала генерирует вызов поискового инструмента, затем получает подходящие схемы и только потом отвечает | Дополнительный шаг генерации LLM, около +2 с; риск циклов обнаружения на малых моделях |
| tool-prune (предварительный фильтр) | Клиент отбирает topTools до вызова модели и передаёт готовый набор | 0 дополнительных обращений к LLM; по заявлению авторов, 0.4 мс офлайн |
Слабое место прогрессивного поиска в том, что он зависит от способности модели правильно сформулировать запрос на поиск. Модели на 7B/8B параметров регулярно пропускают этот шаг или повторяют его без прогресса. tool-prune убирает эту зависимость: решение о наборе инструментов принимает детерминированный код, а не генерация.
Авторы заявляют сокращение промпт-токенов на 92% при переходе от полного каталога к отобранным схемам. Сравнение подходов в исходном описании не сопровождается независимым тестом: цифры взяты из материалов создателей tool-prune. Для детерминированных запросов в проекте есть режим прямой отправки, который, по заявлению авторов, укладывается менее чем в 1 мс.
Практическая выгода: где tool-prune действительно экономит
Сценарии с 50+ инструментами и малыми моделями
Целевой кейс выглядит так: локальный агент на модели 7B/8B параметров, каталог из 50+ схем, ограниченный контекст. Каждая лишняя схема ест токены и размывает внимание. tool-prune отсеивает нерелевантное до вызова модели, и в промпт уходит только topTools. Если заявленные 92% экономии хотя бы близки к реальности, освободившееся место в контексте можно отдать истории диалога, результатам вызовов или более длинному системному промпту.
Вторая часть выгоды - предсказуемость задержки. Дополнительный шаг генерации в tool_search добавляет к каждому запросу фиксированные ~2 секунды, и на слабом железе эта цифра растёт. Клиентская фильтрация не зависит от загрузки GPU: она выполняется на CPU до того, как модель начнёт работу. Как честно измерять задержку локального инференса и почему средние значения вводят в заблуждение, разбирают в материале про тесты DeepSeek V4 Flash, Qwen3.8 Flash Next и Qwen3.8-27B на DGX Spark: там показано, что пиковые tok/s не заменяют p50 и p95.
Выгода падает в двух случаях. Если инструментов у вас пять-шесть, отсеивать почти нечего, а накладные расходы на сам фильтр остаются. Если модель работает с длинным контекстом и уверенно держит десятки схем, проблема размытого внимания выражена слабее. Крупные модели с большим окном реже страдают от лишних описаний инструментов, чем 7B/8B.
Режим прямой отправки для детерминированных запросов
Отдельная опция проекта - direct dispatch, режим прямой отправки для запросов, где выбор инструмента однозначен. По заявлению авторов, он укладывается менее чем в 1 мс. Логика такая: если запрос по структуре точно соответствует одному инструменту, этап выбора можно пропустить и вызвать функцию сразу.
Детали реализации в материалах не раскрыты: неизвестно, по каким правилам запрос признаётся детерминированным и что происходит при ложном срабатывании. Такой режим логично применять там, где входной формат контролируется, например в кнопках интерфейса, шаблонных командах бота или заранее известных пользовательских сценариях. Для свободного текста он подходит хуже.
Ограничения и открытые вопросы
Все количественные показатели проекта - 0.4 мс офлайн, 23 мкс с SIMD, минус 92% промпт-токенов, +2 с у tool_search, менее 1 мс на direct dispatch - приведены как заявления авторов, а не как независимо проверенные измерения. Никаких сторонних бенчмарков по tool-prune в исходных материалах нет.
Что остаётся неизвестным:
- детали реализации FWHT и способ построения признаков для запроса и схем;
- критерии релевантности, по которым формируется topTools, и что происходит при их изменении;
- модели, наборы инструментов и запросы, на которых получены заявленные цифры;
- поведение на неоднозначных и составных запросах, где одного инструмента недостаточно;
- поведение при отсутствии релевантных инструментов: вернёт ли фильтр пустой список или подставит ближайшие по смыслу схемы.
Отсюда практический вывод: считать 92% экономии гарантией нельзя. На вашем каталоге инструментов и вашем распределении запросов доля сокращения будет другой.
Отдельный риск - ошибка фильтрации. Если нужная схема не попала в topTools, модель физически не сможет вызвать инструмент и либо ответит текстом, либо начнёт импровизировать. У прогрессивного поиска такой провал хотя бы теоретически лечится повторным поиском, у одноразового предварительного отбора второй попытки нет, если вы не добавите её сами.
Как попробовать tool-prune
У проекта есть playground и GitHub-репозиторий, о которых упоминает автор в исходном посте. Прямых ссылок на площадки в приведённых материалах нет, поэтому искать их стоит от первоисточника.
Для базового знакомства достаточно двух шагов: вызвать router.filter(userPrompt) и передать полученный topTools в модель вместо полного каталога схем. Внешних зависимостей проект не требует, код на чистых JS и Python, так что подключение к существующему клиенту сводится к установке модуля и замене одного аргумента в вызове модели.
Дальше имеет смысл проверить заявленные показатели на своих данных: замерить время работы фильтра на вашем наборе схем, посчитать реальное сокращение промпт-токенов и, что важнее, посмотреть на долю запросов, где нужный инструмент не попал в topTools. Если вы уже оптимизируете локальный инференс на уровне движка, полезен разбор патчей MoE-инференса в llama.cpp на RTX 4080: там видно, что выигрыш от оптимизаций сильно зависит от конфигурации и не переносится автоматически на другое железо.
Практический критерий простои: если у вас меньше десяти инструментов, начинать с tool-prune смысла мало. Если каталог перевалил за тридцать схем, модель компактная, а контекст забит под завязку, предварительный фильтр на стороне клиента стоит проверить на нескольких десятках реальных запросов и сравнить с поведением встроенного tool_search.