# vLLM tool calling: выбрать парсер и проверить вызов инструмента

Источник: https://modelium.tech/zhurnal/vllm-tool-calling/

Для автоматического tool calling в vLLM согласуйте chat template модели и `--tool-call-parser`, затем включите `--enable-auto-tool-choice`. На локальном API проверьте структурированный `tool_calls`, разберите аргументы и только после валидации выполните разрешённую функцию в своём приложении. Текст модели, похожий на вызов, и принудительное `tool_choice=required` сами по себе не доказывают работоспособность автоматического выбора.

**Срез исходников — 6 октября 2026 года.** vLLM закреплён на Git-ревизии `ced6857`, Qwen2.5-1.5B-Instruct — на HF-ревизии `989aa79`. Modelium не запускал модель, не измерял производительность и не исполнял инструмент: ниже инструкция для проверки на вашей машине. [s1](#src-s1) [s5](#src-s5)

## Что именно считается вызовом инструмента?

В API chat completions инструмент — объявленная клиентом функция со схемой аргументов; модель может предложить вызов, но **исполнение остаётся обязанностью вашего приложения**. Для проверки ищите в ответе `choices[0].message.tool_calls` объект с ожидаемым именем функции и разбираемыми аргументами. Фраза в `content` вроде «вызвал функцию» не доказывает, что приложение что-либо выполнило. [s1](#src-s1)

Маршрут для небольшой закрытой задачи: запрос на проверку тестового статуса → Qwen2.5-1.5B-Instruct с шаблоном tool use → совместимый GPU и локальный vLLM → `hermes` parser → структурированный вызов → валидация и исполнение только разрешённой функции. Если нужен вводный запуск сервера до API, откройте [общий гайд vLLM](/zhurnal/vllm/). Это **проект теста**, а не утверждение, что эта модель всегда верно выберет инструмент. [s1](#src-s1) [s2](#src-s2) [s5](#src-s5) [s6](#src-s6)

## Какую модель и парсер сочетать?

Документация vLLM на этой ревизии перечисляет семейство Qwen2.5 с парсером `hermes`: его логика распознаёт блоки `<tool_call>`, которые присутствуют в шаблоне `tokenizer_config.json` выбранного варианта Qwen2.5-1.5B-Instruct. Не переносите этот флаг автоматически на Qwen3, DeepSeek или gpt-oss: для них документированы иные сочетания парсера, шаблона и иногда reasoning parser. Сверяйте **точный репозиторий и ревизию токенизатора**, а не только название семейства. [s1](#src-s1) [s4](#src-s4) [s6](#src-s6)

Карточка выбранного варианта описывает 1,5B instruction-модель; репозиторий содержит текст Apache License 2.0. Это не утверждение о лицензиях всех размеров Qwen2.5: например, решение о корпоративном применении любой другой ревизии требует проверки её собственного LICENSE. Небольшой размер модели также **не гарантирует** качественный выбор инструмента на ваших данных; размер файлов весов нельзя считать минимальной VRAM. [s5](#src-s5) [s7](#src-s7)

## Что подготовить на локальной машине?

Установите vLLM на поддерживаемом вами GPU по [инструкции сервера](/zhurnal/vllm/), обеспечьте место и доступ к конкретной ревизии модели и проверьте обычный ответ chat API прежде, чем добавлять инструменты. Запуск в контейнере подробно разобран [отдельно](/zhurnal/vllm-v-docker/). Ни документация, ни размер весов не заменяют измерения вашей доступной памяти и совместимости сборки. [s2](#src-s2) [s5](#src-s5)

Для теста привяжите HTTP-сервер к loopback: `vllm serve Qwen/Qwen2.5-1.5B-Instruct --revision 989aa7980e4cf806f80c7fef2b1adb7bc71aa306 --tokenizer-revision 989aa7980e4cf806f80c7fef2b1adb7bc71aa306 --host 127.0.0.1 --port 8000 --enable-auto-tool-choice --tool-call-parser hermes`. Это пример для совместимого локального стенда; команда может скачать веса. Не открывайте порт наружу: документация vLLM предупреждает, что `--api-key` защищает не все HTTP-маршруты. При иной версии CLI проверьте флаги в своей установленной версии до запуска. [s1](#src-s1) [s2](#src-s2) [s3](#src-s3) [s6](#src-s6)

Сначала получите список сервируемых моделей: `curl -fsS http://127.0.0.1:8000/v1/models`. Сверьте его `id` с полем `model` в последующих запросах; если id отличается, подставьте возвращённое значение. Для `auto` обязательны флаг включения и корректный парсер. [s1](#src-s1) [s2](#src-s2)

## Как проверить автоматический выбор и реальное действие?

Отправьте **безопасный тестовый запрос** к `/v1/chat/completions`: в `tools` объявите функцию `lookup_status` с одним обязательным строковым аргументом `ticket`, в `messages` попросите проверить заранее известный тестовый тикет `DEMO-1`, а `tool_choice` задайте `auto`. Документация vLLM использует именно этот API-паттерн; URL держите на `127.0.0.1`, без реальных секретов или персональных данных. [s1](#src-s1) [s3](#src-s3)

Один копируемый пример запроса (без переноса строк, чтобы сохранить синтаксис в текущем рендерере): `curl -fsS http://127.0.0.1:8000/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"Qwen/Qwen2.5-1.5B-Instruct","messages":[{"role":"user","content":"Проверь статус тестового тикета DEMO-1 через lookup_status"}],"tools":[{"type":"function","function":{"name":"lookup_status","description":"Статус тестового тикета","parameters":{"type":"object","properties":{"ticket":{"type":"string"}},"required":["ticket"],"additionalProperties":false}}}],"tool_choice":"auto","temperature":0}'`. Это **не реальный прогон Modelium** и не гарантированный ответ модели. [s1](#src-s1) [s2](#src-s2)

Успех первого этапа — непустой `choices[0].message.tool_calls`, `function.name == "lookup_status"`, аргументы являются JSON-объектом с `ticket == "DEMO-1"`. Сохраните полный ответ и `finish_reason`. Затем **отдельным кодом вашего приложения** сверьте имя по allowlist, тип и допустимое значение аргумента, разрешение пользователя; исполните только тестовую функцию, которая возвращает известный статус, и запишите отдельный факт её выполнения. Чтобы продолжить диалог, отправьте ответ функции с правильным `tool_call_id` как сообщение роли `tool`. Не давайте модели произвольное имя команды, путь к файлу или право сетевого вызова без отдельного подтверждения. [s1](#src-s1)

Для контрольного отрицательного запроса отправьте те же `messages` и `tools`, но `tool_choice: "none"`: в этой конфигурации вызов не должен появиться. `required` или вызов по имени заставляют схему выдавать структурированный вызов, **но не проверяют**, сможет ли модель самостоятельно выбрать инструмент при `auto`; тестируйте оба случая по отдельности. [s1](#src-s1)

## Почему парсер может создать ложный результат?

Парсер должен соответствовать фактическому формату вывода модели и её шаблону; несовместимое сочетание может дать пустой `tool_calls`, обычный текст с `<tool_call>` или ошибочные аргументы. Это диагностическая возможность, а не универсальная гарантия конкретного кода ошибки. Если структурированного вызова нет, **не исполняйте** извлечённые из текста команды: проверьте ревизию шаблона, флаги vLLM, реальные `model`/`tool_choice`, raw response и логи; повторите запрос после исправления пары модель–парсер. [s1](#src-s1) [s4](#src-s4) [s6](#src-s6)

В `auto` без `strict: true` аргументы обычно извлекаются из свободной генерации, и vLLM предупреждает о возможном нарушении JSON Schema. Даже со структурным ограничением требуется прикладная проверка прав, допустимых параметров и побочных эффектов. `required` обеспечивает форму вызова, а **не правдивость статуса тикета или безопасность действия**. Если промпт-инъекция в данных подсказывает вызвать иную функцию, действие должно остановиться на вашем allowlist; клиентский вызов API не равен выполнению инструмента. [s1](#src-s1)

Основной следующий шаг — [поднять локальный vLLM](/zhurnal/vllm/) на подходящем железе, получить сохранённый `tool_calls` на `auto` и отдельно подтвердить исполнение разрешённого тестового обработчика. При отказе сохраните исходный JSON и версии вместо заявления «инструменты работают». [s1](#src-s1) [s2](#src-s2)

## Источники

1. [vLLM: Tool Calling, закреплённая ревизия](https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/docs/features/tool_calling.md) — получено 2026-10-06
2. [vLLM: Quickstart и локальный сервер](https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/docs/getting_started/quickstart.md) — получено 2026-10-06
3. [vLLM: ограничения безопасности HTTP API](https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/docs/usage/security.md) — получено 2026-10-06
4. [vLLM: реализация Hermes tool parser](https://github.com/vllm-project/vllm/blob/ced6857afa0ea7b2e3f0846a62e1394e90f15607/vllm/tool_parsers/hermes_tool_parser.py) — получено 2026-10-06
5. [Qwen2.5-1.5B-Instruct: карточка модели](https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct/blob/989aa7980e4cf806f80c7fef2b1adb7bc71aa306/README.md) — получено 2026-10-06
6. [Qwen2.5-1.5B-Instruct: шаблон токенизатора](https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct/blob/989aa7980e4cf806f80c7fef2b1adb7bc71aa306/tokenizer_config.json) — получено 2026-10-06
7. [Qwen2.5-1.5B-Instruct: текст лицензии](https://huggingface.co/Qwen/Qwen2.5-1.5B-Instruct/blob/989aa7980e4cf806f80c7fef2b1adb7bc71aa306/LICENSE) — получено 2026-10-06
