Проблемы tool calling в VLLM и llama.cpp: strict параметр и его игнорирование | AiManual
AiManual Logo Ai / Manual.
21 Фев 2026 Гайд

Параметр strict в VLLM и llama.cpp: почему он ничего не делает и как с этим жить

Разбираемся, почему параметр strict в VLLM и llama.cpp не работает, как обойти проблемы с tool calling и заставить модели генерировать валидный JSON в 2026 году

Когда строгость - это всего лишь иллюзия

Вы настраиваете агента с вызовом инструментов. Пишете красивую JSON-схему. Указываете strict=True в надежде, что модель не будет генерировать мусор. А она генерирует. Потому что этот параметр - фикция в большинстве inference-движков на февраль 2026 года.

Факт: VLLM версии 0.5.6 (актуальная на февраль 2026) декларирует поддержку strict, но на практике он влияет только на валидацию входящего промпта, а не на генерацию.

Что обещают и что получаем

В документации всё выглядит логично. Параметр strict должен гарантировать, что модель будет строго следовать JSON-схеме. В реальности - это маркетинговая уловка для привлечения разработчиков, уставших от хаоса в tool calling.

Как работает (точнее, не работает) strict в VLLM

Откройте исходники VLLM. Найдите обработку structured outputs. Вы увидите примерно такую картину:

# Примерное поведение VLLM 0.5.6
def validate_schema(schema, strict=False):
    if strict:
        # Проверяет, что схема валидна
        # НЕ гарантирует, что модель её соблюдает
        pass

Параметр проверяет схему на корректность. Не более того. Модель всё равно может сгенерировать {"name": "get_weather", "arguments": "city: Москва"} вместо {"name": "get_weather", "arguments": {"city": "Москва"}}.

💡
Строгость в VLLM - это проверка входных данных, а не контроль выходных. Разработчики надеются, что модель обучена достаточно хорошо, чтобы соблюдать схему. Надежды часто не оправдываются.

llama.cpp: история с продолжением

В llama.cpp ситуация ещё интереснее. Там вообще нет параметра strict в классическом понимании. Вместо этого есть система грамматик, которая должна обеспечивать корректный синтаксис.

Но грамматики в llama.cpp работают на уровне токенов. Они гарантируют, что следующий токен будет синтаксически корректным. Не семантически. Модель может сгенерировать:

{
  "tool": "calculate",
  "args": {
    "operation": "add",
    "numbers": [1, 2, "три"]  # Ошибка типа, но синтаксис верный
  }
}

Почему так происходит?

  • Разработчики inference-движков фокусируются на скорости, а не на корректности
  • Реализация настоящего strict требует сложной валидации на лету, что замедляет генерацию
  • Модели сами по себе плохо обучены для точного следования схемам
  • Нет стандарта: каждый движок интерпретирует strict по-своему

Практические последствия для разработчиков

Вы создаёте агента для обработки заказов. Модель должна вызывать функцию create_order с определёнными полями. В 30% случаев она генерирует некорректный JSON, даже с strict=True. Ваш продакшен падает.

Типичные ошибки:

Ошибка Частота Влияние
Неправильные типы данных 25% Критические ошибки парсинга
Лишние поля 15% Нарушение контрактов API
Неполные объекты 20% Частичная работа функций
Строки вместо объектов 10% Полный отказ системы

Что делать, если strict не работает?

Не ждите, что движки исправятся. Берите ситуацию в свои руки.

1 Валидируйте выход модели самостоятельно

Добавьте слой пост-обработки. После каждого tool call проверяйте результат через JSON Schema валидатор. Если не проходит - пробуйте исправить или запрашивайте повторную генерацию.

import json
import jsonschema
from typing import Dict, Any

def validate_tool_call(response: str, schema: Dict) -> Dict[str, Any]:
    try:
        data = json.loads(response)
        jsonschema.validate(data, schema)
        return {"valid": True, "data": data}
    except (json.JSONDecodeError, jsonschema.ValidationError) as e:
        # Здесь можно попробовать исправить JSON
        # Или запросить регенерацию
        return {"valid": False, "error": str(e)}

2 Используйте модели с лучшей поддержкой tool calling

Не все модели одинаковы. Некоторые специально дообучаются для работы с инструментами. В нашем обзоре лучших LLM с поддержкой Tool Calling мы сравнивали, какие модели действительно умеют работать со схемами.

На февраль 2026 года лучшие результаты показывают:

  • Claude 3.7 Sonnet Thinking (но он не локальный)
  • GPT-4o Mini с дообучением
  • Llama 3.2 90B Instruct с fine-tuning под tool calling
  • Qwen 2.5 72B с расширенным контекстом

3 Настройте грамматики в llama.cpp правильно

Грамматики - мощный инструмент, если понимать их ограничения. Они не гарантируют семантическую корректность, но могут предотвратить синтаксические ошибки.

# Пример запуска с грамматикой для tool calling
./llama-cli -m model.gguf \
  --grammar-file tool_call.gbnf \
  --prompt "Какая погода в Москве?"

Грамматика должна описывать ВСЕ возможные инструменты и их параметры. Это громоздко, но эффективно против синтаксического мусора.

4 Добавьте ретраи и fallback-логику

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

Практический совет: ограничьте количество ретраев тремя. Больше - трата ресурсов. Если после трёх попыток модель не генерирует валидный JSON, переходите к fallback-действию.

Почему разработчики движков не фиксят проблему?

Спросите любого разработчика VLLM или llama.cpp про strict. Они пожмут плечами. Проблема в фундаментальном несоответствии ожиданий и реальности.

Разработчики думают: "Мы добавили параметр strict, теперь всё будет строго". Пользователи думают: "Теперь модель точно будет следовать схеме". Ни те, ни другие не правы.

Настоящая реализация strict потребовала бы:

  1. Валидации на лету во время генерации
  2. Отката некорректных токенов
  3. Перегенерации с учётом ошибок
  4. Сложной логики обработки типов данных

Всё это убивает производительность. А inference-движки заточены на скорость. Вот и получаем компромисс: быстрая генерация с возможными ошибками вместо медленной, но точной.

Будущее tool calling: что нас ждёт?

К концу 2026 года ситуация может измениться. Появляются специализированные модели для tool calling, которые из коробки понимают JSON-схемы. Движки начинают добавлять настоящую валидацию через внешние валидаторы.

Но пока - рассчитывайте только на себя. Стройте системы с предположением, что модель будет ошибаться. Добавляйте слои защиты. Тестируйте на разнообразных сценариях. Как правильно тестировать такие системы, мы разбирали в статье про тестирование недетерминированных LLM.

Чеклист для продакшена

  • Не доверяйте параметру strict - проверяйте всё сами
  • Добавьте JSON Schema валидацию после каждой генерации
  • Используйте модели, специально обученные для tool calling
  • Настройте грамматики для синтаксической защиты
  • Добавьте логирование всех ошибок валидации
  • Реализуйте ретраи с экспоненциальной задержкой
  • Создайте fallback-стратегии на случай повторных ошибок
  • Мониторьте процент успешных tool calls (должен быть >95%)

И помните: проблема не в вашем коде. Она системная. Все разработчики агентов сталкиваются с тем же. Разница лишь в том, как быстро они это осознают и начинают строить защитные механизмы.

Последний совет: если ваша система критически зависит от точности tool calling, рассмотрите использование специализированных сервисов вроде OpenAI's structured outputs (если они доступны в вашем регионе) или локальных моделей с доказанной точностью выше 98%.

Что почитать дальше

Если вы только начинаете работать с локальными LLM, посмотрите практический гайд по избежанию основных ошибок. Для тонкой настройки llama.cpp есть материал про сборку и оптимизацию под ваше железо.

А если столкнулись с тем, что модель постоянно отказывается выполнять запросы, изучите техники удаления "отказов" через Refusal Steering.

Tool calling - это будущее LLM-приложений. Но настоящее этого будущего пока сырое. Придётся дорабатывать напильником.