Высокое место LLM в публичном лидерборде ещё не означает, что она корректно вызовет функцию вашего CRM, платёжного шлюза или системы управления заявками. Ошибка может возникнуть на любом этапе: модель выберет похожий инструмент, пропустит обязательный аргумент, подставит строку вместо числа или выполнит действие, хотя запрос пользователя этого не требует.
Такие сбои трудно заметить в обычном диалоге. Ответ модели выглядит убедительно, JSON успешно разбирается, а проблема обнаруживается уже после обращения к внешней системе. Поэтому качество tool calling следует измерять отдельно от общего качества текста.
Berkeley Function Calling Leaderboard, или BFCL, даёт полезную основу для такой проверки. Однако для продакшена его методику нужно дополнить собственными функциями, русскоязычными запросами и сценариями отказа. Ниже — практическая схема, позволяющая сравнить GPT, Claude, Gemini, Llama, Qwen, Mistral и другие модели на одинаковом наборе задач.
Что именно проверяет BFCL
Berkeley Function Calling Leaderboard создан исследователями UC Berkeley в рамках проекта Gorilla. Бенчмарк оценивает способность языковой модели работать с описаниями функций: выбирать подходящий инструмент и формировать аргументы в требуемом формате.
Это более узкая задача, чем оценка рассуждений или качества ответа. Модель может хорошо объяснять программный код и одновременно допускать систематические ошибки при построении вызовов.
В BFCL используются несколько классов заданий:
- простой вызов одной функции;
- выбор одной функции из доступного набора;
- параллельные вызовы нескольких функций;
- комбинации параллельных и множественных вызовов;
- обработка вложенных типов и структур;
- распознавание запросов, для которых подходящей функции нет;
- многошаговые сценарии, если они входят в используемую версию набора;
- вызовы, которые можно проверить через исполнение, а не через сравнение строк.
Состав категорий менялся вместе с версиями BFCL. Поэтому цифру из публикации или карточки модели нельзя сравнивать с новым результатом без проверки версии набора, даты запуска и правил подсчёта.
Актуальный лидерборд и описание категорий опубликованы на сайте проекта:
https://gorilla.cs.berkeley.edu/leaderboard.html
Код и данные Gorilla доступны в репозитории:
https://github.com/ShishirPatil/gorilla
Почему место в лидерборде нельзя переносить в продакшен
BFCL удобен для первичного отбора моделей, но его итоговая оценка не является гарантией качества конкретного AI-агента. Причина — разница между стандартизированным тестом и реальным набором инструментов.
Во внутреннем API встречаются неоднозначные названия, устаревшие поля, длинные описания и доменные типы. Например, агенту могут одновременно передать функции `create_support_case`, `update_support_case` и `close_support_case`. Для человека различие очевидно, а модель может ориентироваться на отдельные слова и выбрать неправильное действие.
Влияют и другие факторы:
- язык пользовательского запроса;
- формулировки описаний функций;
- число доступных инструментов;
- длина контекста;
- системная инструкция;
- параметры генерации;
- версия модели и API;
- формат передачи схемы;
- наличие истории диалога;
- обработка результата предыдущего вызова.
Отдельная проблема — обновляемые модели, доступные по плавающему имени. Поведение такого эндпоинта может измениться без правок в приложении. Для воспроизводимого теста следует сохранять точный идентификатор модели, дату запуска, параметры запроса и полученный сырой ответ.
По этой причине публиковать таблицу с «актуальными» процентами без привязки к версии BFCL рискованно. Лидерборд обновляется, а разные поколения теста могут использовать отличающиеся категории и правила оценки. Надёжнее проверять текущие результаты на официальной странице и запускать внутренний набор отдельно.
Какие ошибки нужно разделять
Единая метрика accuracy скрывает причину сбоя. Для диагностики полезно разделить ошибки по этапам.
| Метрика | Что проверяет | Пример ошибки | Риск для системы |
|---|---|---|---|
| Function Selection Accuracy | Выбрана ли правильная функция | Вместо создания заявки модель обновляет существующую | Выполняется неверное действие |
| Required Parameter Accuracy | Переданы ли обязательные поля | В вызове отсутствует `customer_id` | API отклоняет запрос |
| Type and Schema Accuracy | Соответствуют ли значения JSON Schema | Число передано строкой, enum содержит неизвестное значение | Ошибка валидации или некорректная обработка |
| Rejection Accuracy | Воздержалась ли модель от вызова при отсутствии подходящего инструмента | Модель придумывает функцию или выбирает ближайшую по смыслу | Ложное срабатывание |
| Parallel Call Accuracy | Корректно ли сформирован набор независимых вызовов | Один вызов пропущен или аргументы перепутаны | Сценарий выполняется частично |
Полностью корректным стоит считать ответ, в котором совпали имя функции, набор обязательных аргументов, типы и значения. Если требуется несколько вызовов, нужно проверить весь набор. Частичный успех полезно фиксировать отдельно, но не следует выдавать его за успешно выполненную задачу.
Для действий с внешними последствиями имеет смысл считать ещё две прикладные метрики:
- Execution Success Rate — доля вызовов, прошедших валидацию и успешно выполненных тестовым сервисом;
- Unsafe Call Rate — доля ответов, которые могли привести к нежелательному действию без дополнительного подтверждения.
Вторая метрика особенно важна для удаления данных, изменения прав доступа, финансовых операций и отправки сообщений от имени пользователя.
Как собрать собственный тестовый набор
Начать можно с 50–100 примеров, но они должны отражать реальные обращения, а не удобные демонстрационные команды. Если агент уже работает, основу набора лучше собрать из обезличенных журналов. Персональные данные, токены, адреса и внутренние идентификаторы необходимо удалить или заменить синтетическими значениями.
Для каждого примера сохраните:
- текст запроса;
- список доступных функций;
- ожидаемое имя функции;
- ожидаемые аргументы;
- допустимые варианты значений;
- признак «вызов не требуется»;
- уровень риска;
- краткое объяснение эталона.
Пример записи в JSONL:
json
{
«id»: «support-017»,
«input»: «Закрой обращение 4812: клиент подтвердил решение»,
«tools»: [«create_support_case», «update_support_case», «close_support_case»],
«expected»: {
«name»: «close_support_case»,
«arguments»: {
«case_id»: 4812,
«resolution_confirmed»: true
}
},
«risk»: «medium»
}
Не ограничивайтесь прямыми командами. Добавьте перефразировки, опечатки, разговорные выражения и неоднозначные запросы. Отдельно нужны негативные примеры, где ни один инструмент применять нельзя.
Полезная пропорция для первого набора:
- 35% — обычные вызовы одной функции;
- 20% — выбор между похожими функциями;
- 15% — сложные или вложенные аргументы;
- 15% — запросы без подходящей функции;
- 10% — несколько независимых вызовов;
- 5% — опасные действия, требующие подтверждения.
Это не универсальный стандарт. Пропорции следует менять под устройство агента. Если большая часть сбоев связана с отказом от действия, долю негативных примеров стоит увеличить.
Как подготовить функции к честному сравнению
Одна и та же модель может показать разные результаты при небольшом изменении описания инструмента. Поэтому перед сравнением моделей нужно зафиксировать схемы и не редактировать их между запусками.
Хорошее описание функции отвечает на три вопроса:
Когда функцию следует вызывать?
Когда её вызывать нельзя?
3. Что означает каждый параметр?
Плохой вариант:
json
{
«name»: «update_case»,
«description»: «Обновляет обращение»
}
Более проверяемый вариант:
json
{
«name»: «update_support_case»,
«description»: «Изменяет поля существующего обращения. Не создаёт и не закрывает обращение.»,
«parameters»: {
«type»: «object»,
«properties»: {
«case_id»: {
«type»: «integer»,
«description»: «Числовой идентификатор существующего обращения»
},
«priority»: {
«type»: «string»,
«enum»: [«low», «normal», «high»]
}
},
«required»: [«case_id»],
«additionalProperties»: false
}
}
Ограничение `additionalProperties: false` помогает обнаруживать выдуманные поля. Перечисление `enum` уменьшает число произвольных значений. Описание запрета на создание и закрытие снижает путаницу с соседними инструментами.
При этом нельзя улучшать схему специально под одну модель после просмотра её ошибок. Иначе сравнение перестанет быть честным. Изменённую схему нужно считать новой версией теста и прогнать на всех кандидатах заново.
Официальные требования к форматам вызова различаются между платформами. Перед реализацией стоит свериться с документацией:
- OpenAI function calling: https://platform.openai.com/docs/guides/function-calling
- Anthropic tool use: https://docs.anthropic.com/en/docs/build-with-claude/tool-use
- Google Gemini function calling: https://ai.google.dev/gemini-api/docs/function-calling
Как автоматизировать проверку ответов
Сравнение JSON как обычной строки даёт ложные ошибки: порядок ключей в объекте не должен влиять на результат. Перед оценкой ответ следует разобрать, нормализовать и проверить по схеме.
Минимальный конвейер выглядит так:
Получить структурированный ответ модели.
Проверить, был ли вызов вообще.
3. Сопоставить имя функции с эталоном.
4. Провалидировать аргументы через JSON Schema.
5. Нормализовать значения там, где это разрешено правилами теста.
6. Сравнить значения с эталоном.
7. Для нескольких вызовов проверить состав и кратность.
8. Записать тип ошибки и сырой ответ.
Нормализация требует осторожности. Если приложение действительно принимает `»4812″` вместо `4812`, можно вести две оценки: строгую и прикладную. Строгая показывает соблюдение схемы, прикладная — вероятность успешного выполнения после безопасного преобразования.
Не стоит автоматически исправлять:
- неизвестные значения enum;
- отсутствующие обязательные поля;
- выдуманные идентификаторы;
- дополнительный вызов опасной функции;
- замену одного инструмента другим.
Такое «исправление» маскирует ошибку выбора и завышает качество модели.
Формула полной точности проста:
text
Exact Accuracy = полностью корректные примеры / все примеры
Для корректного отказа:
text
Rejection Accuracy = правильные отказы / примеры без подходящей функции
Дополнительно полезно считать доверительный интервал. На наборе из 50 примеров разница в несколько успешных ответов может быть случайной. Для серьёзного решения набор следует расширять и повторять прогон, особенно если генерация недетерминирована.
Как проводить сравнение GPT, Claude, Gemini и локальных LLM
Чтобы результаты можно было интерпретировать, условия запуска должны совпадать настолько, насколько это допускают API.
Зафиксируйте:
- точное имя и версию модели;
- системную инструкцию;
- набор и порядок функций;
- temperature и связанные параметры;
- лимит токенов;
- формат структурированного вывода;
- число повторов каждого примера;
- дату теста;
- задержку и стоимость запросов.
Порядок функций тоже способен влиять на выбор. Для дополнительной проверки можно выполнить второй прогон со случайной перестановкой инструментов. Если результат заметно меняется, агент слишком чувствителен к позиции функции в списке.
Каждый пример желательно запустить минимум три раза при тех настройках, которые будут использоваться в приложении. Тогда появится показатель стабильности:
text
Consistency = примеры с одинаковым результатом во всех повторах / все примеры
Модель с немного меньшей средней точностью, но стабильным поведением иногда удобнее лидера, чьи ответы заметно меняются между запусками. Решение зависит от цены ошибки и возможности повторного запроса.
Локальные модели нужно тестировать с конкретным шаблоном чата и версией движка. Обновление vLLM, llama.cpp, Transformers или шаблона токенизации способно изменить формат вызовов даже при неизменных весах.
Почему корректный JSON ещё не означает безопасный вызов
Валидная структура подтверждает лишь соответствие формату. Она не доказывает, что действие разрешено, уместно и безопасно.
Перед исполнением функция должна пройти отдельный слой контроля:
- проверку типов по схеме;
- проверку прав пользователя;
- проверку существования объектов;
- ограничение допустимых значений;
- защиту от повторного выполнения;
- подтверждение для необратимых действий;
- журналирование решения и результата.
Модель не должна напрямую определять полномочия. Если она передала `role: «admin»`, сервер обязан проверить, имеет ли инициатор право назначать такую роль. Аналогично идентификатор записи следует сопоставлять с доступным пользователю пространством данных.
Для функций с побочными эффектами полезен режим dry run. Инструмент возвращает планируемое изменение, а выполнение происходит после проверки политик или явного подтверждения. Такой подход уменьшает последствия ошибок выбора и аргументации.
В тестовый набор стоит включить атаки на описание инструментов: просьбы игнорировать ограничения, подменять идентификаторы, раскрывать скрытые поля или вызывать функцию от чужого имени. Эти примеры выходят за рамки обычной точности, зато отражают реальные риски агентных систем.
Как разобрать ошибки после прогона
Общий процент нужен для сравнения, но улучшения начинаются с матрицы ошибок. Каждому неудачному примеру присвойте одну основную причину:
- неверно выбрана функция;
- пропущен обязательный аргумент;
- неверный тип;
- неверное значение;
- добавлено лишнее поле;
- лишний вызов;
- пропущен вызов;
- ошибочный отказ;
- отсутствует необходимый отказ;
- повреждён формат ответа.
Затем сгруппируйте ошибки по функциям и формулировкам. Если одна функция отвечает за значительную долю проблем, причина может быть в её названии или описании, а не в самой модели.
Полезно проводить исправления по очереди:
Уточнить схему проблемной функции.
Повторить весь тест.
3. Сравнить изменение по каждой категории.
4. Проверить, не ухудшились ли соседние функции.
5. Зафиксировать новую версию схемы.
Добавление примеров в системную инструкцию тоже способно повысить точность, но увеличивает контекст и стоимость. Кроме того, примеры могут переобучить поведение под тестовый набор. Контрольную часть данных лучше скрыть от разработчика, который редактирует инструкции.
Практический порог для выпуска агента
Универсального проходного балла нет. Требование зависит от последствий ошибки.
Для функции чтения справочной информации допустим повторный запрос или сообщение пользователю. Для удаления записи даже редкая ошибка может быть неприемлемой. Поэтому пороги следует задавать по уровню риска, а не одной цифрой для всего агента.
Перед выпуском проверьте четыре условия:
- на опасных функциях нет ложных вызовов в контрольном наборе;
- обязательные аргументы валидируются до исполнения;
- запросы без подходящего инструмента представлены отдельной категорией;
- версия модели и схем инструментов закреплена в журнале теста.
После запуска сохраняйте обезличенные данные о выборе функции, результате валидации, коде ответа инструмента и подтверждении пользователя. Новые сбои нужно добавлять в регрессионный набор. При смене модели, системной инструкции или схемы функций тест запускается заново.
Первый практический шаг — выгрузить 50 реальных запросов к агенту, удалить чувствительные данные и вручную назначить ожидаемые вызовы. Уже такой набор покажет больше о пригодности модели для вашего проекта, чем отдельная позиция в публичном лидерборде. BFCL при этом остаётся полезной внешней точкой отсчёта: он помогает сравнить кандидатов, проверить методику и не свести оценку tool calling к нескольким удачным демонстрациям.





