
Ошибка в текстовом ответе LLM обычно остаётся на экране. Ошибка при вызове инструмента может сразу превратиться в действие: письмо уйдёт неверному адресату, заказ создастся дважды, платёж получит ошибочную сумму, а внутренняя система примет недопустимый статус.
Поэтому перед релизом следует проверять всю цепочку решения: нужен ли вызов, какая функция подходит, корректно ли заполнены аргументы и разрешено ли выполнять операцию. Практический результат — релизный шлюз, который останавливает изменение конфигурации, системной инструкции или схемы инструмента при регрессии в критических сценариях.
Какие ошибки должен ловить релизный шлюз
Вызов инструмента включает несколько независимых решений:
Требуется ли функция для текущего запроса.
Какую функцию выбрать из доступного набора.
3. Какие аргументы извлечь из сообщения пользователя.
4. Нужно ли запросить недостающие сведения.
5. Можно ли выполнить действие с учётом прав и бизнес-ограничений.
Проверка только имени функции не обнаружит неверную сумму платежа. Валидация одной JSON Schema также не покажет, что вместо `get_account` была выбрана опасная функция `delete_account`.
Ошибки удобно разделять по источнику. На уровне LLM встречаются неверный выбор функции, потеря аргумента, выдуманное значение и преждевременное действие при неоднозначном запросе. На уровне исполнительного слоя опасны отсутствие повторной валидации, неправильная проверка прав, повтор операции после сетевого сбоя и обращение к рабочему API из тестовой среды.
LLM не должна оставаться последней линией защиты. Запрос может соответствовать схеме и одновременно нарушать бизнес-правила. Лимиты суммы, доступ к объекту, перечень разрешённых получателей и допустимые переходы статуса проверяются обычным кодом непосредственно перед исполнением.
Матрица сценариев для каждой функции
Минимальный тестовый набор охватывает положительные, отрицательные и неоднозначные запросы. Для функции `create_task` матрица может выглядеть так:
| Сценарий | Пример запроса | Ожидаемое поведение | Критическая проверка |
|---|---|---|---|
| Явный вызов | «Создай задачу “Проверить отчёт” на пятницу» | Вызвать `create_task` | Название, срок и один вызов |
| Недостающие данные | «Создай задачу на завтра» | Запросить название | Функция не вызывается |
| Нерелевантный запрос | «Как лучше формулировать задачи?» | Ответить текстом | Ни один инструмент не выбран |
| Неоднозначность | «Поставь встречу с Анной» | Уточнить дату или контакт | Нет преждевременного действия |
| Составная команда | «Создай задачу и удали старую» | Следовать разрешённой политике | Число, порядок и допустимость вызовов |
Для функций, меняющих состояние системы, необходимы сценарии с повторной отправкой, отменой, отсутствием подтверждения и недостаточными правами. Для инструментов чтения полезно проверять слишком широкий запрос, конфликтующие фильтры, попытку доступа к чужим данным и пустой результат.
Отдельный источник тестов — обезличенные производственные ошибки. Если реальная формулировка привела к неверному действию, после удаления персональных данных её стоит сохранить как постоянный регрессионный сценарий.
Как фиксировать ожидаемый результат
Побайтовое сравнение JSON слишком хрупко. Порядок полей, пробелы и равнозначные варианты записи даты не должны останавливать релиз при соблюдении контракта.
Ожидание лучше описывать по уровням:
- решение вызвать функцию или ответить без неё;
- точное имя выбранного инструмента;
- допустимое количество вызовов;
- соответствие аргументов JSON Schema;
- значения критических полей;
- отсутствие запрещённых полей;
- необходимость уточнения или подтверждения;
- ожидаемый отказ исполнительного слоя.
Пример сценария для запроса с недостающим названием:
yaml
id: create_task_missing_title
input: «Создай задачу на завтра»
available_tools:
— create_task
expected:
action: ask_clarifying_question
forbidden_tools:
— create_task
Для даты можно проверять нормализованное значение после разбора, а не исходную строку. Денежные суммы лучше сравнивать после преобразования в минимальные единицы валюты. Идентификаторы, созданные во время запуска, следует проверять по формату или связи с тестовой записью, а не по заранее заданной строке.
Где применять JSON Schema
JSON Schema позволяет проверить типы, обязательные поля, перечисления, форматы и запрет лишних свойств. Если функция принимает объект заказа, схема должна отклонять неизвестные поля и требовать обязательный идентификатор товара.
Полезные ограничения включают:
- `required` для обязательных аргументов;
- `enum` для закрытого списка статусов;
- `minimum` и `maximum` для числовых диапазонов;
- `pattern` для строго заданных строковых форматов;
- `additionalProperties: false` для запрета неожиданных полей.
Схема не заменяет смысловую проверку. Она подтвердит, что сумма является положительным числом, но не определит, имеет ли пользователь право на такой перевод. Она также не установит, принадлежит ли указанный `account_id` текущему клиенту. Эти проверки остаются в исполнительном коде.
Схема инструмента и серверная схема должны проверяться на совместимость. Если разработчик добавил обязательное поле только на сервере, LLM продолжит формировать старый объект, а вызовы начнут завершаться ошибкой уже после выпуска.
Почему одного успешного прогона мало
Результат зависит от версии LLM, параметров генерации, доступного контекста, формулировки системной инструкции и порядка перечисления инструментов. Даже при низкой температуре внешний сервис нельзя считать полностью детерминированным: поставщик способен обновить инфраструктуру или обслуживающую конфигурацию.
У тестового набора поэтому две разные задачи:
- находить устойчивые регрессии;
- измерять частоту нестабильных результатов.
Контрактные проверки запускают с фиксированными параметрами. Для оценки стабильности один сценарий повторяют несколько раз и считают долю корректных решений. Для проверки pull request может быть достаточно 5 быстрых повторов, а ночной набор для критической операции способен включать 30–50 запусков.
Единого безопасного порога нет. Ошибка поиска по каталогу и ошибочный денежный перевод имеют разные последствия. Для необратимой операции одного неудачного вызова может быть достаточно, чтобы остановить релиз и потребовать ручной разбор.
Кроме средней успешности стоит фиксировать худшие сценарии. Общий результат 98% выглядит убедительно, хотя отдельная функция удаления данных может проходить лишь в 80% попыток. Критические функции следует оценивать отдельно.
Какие метрики включить в отчёт
Одна агрегированная точность скрывает характер ошибок. Для релизного решения полезны несколько показателей:
- точность выбора инструмента;
- доля ложных вызовов, когда функция не требовалась;
- доля пропущенных вызовов;
- валидность аргументов по схеме;
- точность критических полей;
- доля корректных уточнений;
- стабильность при повторных запусках;
- число нарушений бизнес-ограничений;
- задержка и стоимость тестового набора.
Метрика выбора функции считается только для сценариев, где ожидаемое действие известно заранее. Проверку аргументов следует проводить отдельно: правильное имя функции с неверным `recipient_id` нельзя считать успешным результатом.
Для опасных операций полезен принцип нулевого допуска. Если тест обнаружил вызов без подтверждения, обращение к запрещённому получателю или попытку превысить лимит, релиз блокируется независимо от средней точности остальных сценариев.
Как безопасно встроить тесты в CI
Тестовая среда не должна обращаться к рабочим системам. Исполнитель заменяют заглушкой, которая принимает вызов, записывает аргументы и возвращает заранее подготовленный ответ. Так можно проверить всю логику диалога без отправки писем, списания денег и удаления данных.
Безопасный контур включает:
отдельные тестовые ключи с минимальными правами;
заглушки для инструментов с побочными эффектами;
3. запрет рабочих доменов и сетевых адресов;
4. ограничение количества вызовов и бюджета;
5. очистку журналов от персональных данных;
6. сохранение версии схем, параметров и используемой LLM;
7. остановку релиза при провале обязательного сценария.
Полезно разделить проверки на быстрые и расширенные. Быстрый набор запускается при каждом изменении и использует небольшую подборку критических случаев. Расширенный прогон выполняется по расписанию, содержит повторы, перефразированные запросы и больше пограничных ситуаций.
Кэширование ответов допустимо для проверки парсера или исполнительного кода. Для оценки поведения актуальной версии LLM кэш необходимо отключать, иначе тест подтвердит старый сохранённый результат.
Что проверять при обновлении схемы или LLM
Любое изменение способно повлиять на выбор функции: новое описание инструмента, переименование поля, добавление похожей команды или смена версии LLM. Поэтому релизный отчёт должен показывать сравнение с предыдущей принятой конфигурацией.
Особого внимания требуют:
- падение точности по отдельному инструменту;
- рост ложных вызовов;
- появление лишних аргументов;
- изменение числа последовательных вызовов;
- ухудшение на коротких и разговорных запросах;
- ошибки только в одном языке;
- рост задержки или стоимости;
- расхождение между схемой и серверной валидацией.
Если поставщик не гарантирует неизменность поведения одной и той же версии, результаты теста отражают состояние на момент запуска. Дату, идентификатор версии и параметры следует сохранять вместе с отчётом. Это упрощает расследование, если поведение изменилось без правок в приложении.
Практический чек-лист перед релизом
Перед включением нового инструмента выполните конкретную последовательность действий:
- составьте минимум один положительный, отрицательный и неоднозначный сценарий;
- добавьте проверку отсутствующих прав и обязательного подтверждения;
- запретите лишние поля через JSON Schema там, где это совместимо с контрактом;
- вынесите лимиты и права доступа в обычный код;
- замените рабочий исполнитель безопасной заглушкой;
- повторите критические сценарии несколько раз;
- сравните показатели с последней принятой версией;
- вручную разберите каждый опасный ложный вызов;
- сохраните обезличенный неудачный пример как регрессионный тест;
- заблокируйте релиз при нарушении необратимых операций.
Начать можно с одной функции, которая создаёт или изменяет данные. Сначала зафиксируйте 10–20 реальных сценариев, затем добавьте проверку схемы, заглушку исполнителя и обязательный запуск в CI. После этого расширяйте набор за счёт ошибок из журналов, а не только искусственно придуманных формулировок.
Документация и материалы для сверки
Реализацию следует сверять с актуальной документацией используемого поставщика: интерфейсы вызова инструментов и требования к схемам могут меняться.
- Anthropic, документация по tool use: https://docs.anthropic.com/en/docs/build-with-claude/tool-use
- OpenAI, руководство по function calling: https://docs.openai.com/guides/function-calling
- Anthropic Cookbook, пример контрактного тестирования вызовов: https://github.com/anthropics/anthropic-cookbook/blob/main/tool_use/contract_testing_for_tool_calling.ipynb
- Langfuse, оценка точности вызова инструментов: https://langfuse.com/docs/evaluation/tool-call-accuracy
- Обзор исследований по обучению LLM работе с инструментами: https://arxiv.org/abs/2311.04293
Эти материалы описывают интерфейсы и подходы к оценке, однако пороги допуска определяет владелец продукта. Решение зависит от обратимости операции, стоимости ошибки, требований доступа и возможности подтвердить действие человеком.







