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

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

Для Qwen3 в SGLang включите совместимый с шаблоном модели парсер `--tool-call-parser qwen25` и проверьте ответ локального `/v1/chat/completions` с `tool_choice=auto`. Нужен объект `tool_calls` с разрешённым именем и проверенными аргументами; реальное действие выполняет клиентское приложение, а не сам факт ответа сервера. Короткий тест на Qwen3-0.6B не гарантирует надёжность инструмента на ваших задачах.

**Срез исходников — 6 октября 2026 года.** Этот протокол основан на Git-ревизии SGLang `f3b5a28` и HF-ревизии Qwen3-0.6B `c1899de`; номер новой установленной сборки и окружение читателя могут отличаться. Modelium не запускал модель, не измерял память или качество и не исполнял инструмент. [s1](#src-s1) [s6](#src-s6)

## Когда SGLang возвращает инструмент, а когда выполняет действие?

В OpenAI-совместимом `/v1/chat/completions` клиент отправляет схему функции в `tools`; модель может вернуть структурированный `message.tool_calls`. Это **предложение действия**, а не вызов вашей CRM или базы: обработчик в собственном приложении должен проверить имя функции, аргументы и права, исполнить безопасное действие и вернуть результат в продолжение диалога. В примере SGLang после ответа с `tool_calls` функция вызывается отдельно, а её ответ передаётся сообщением `role=tool` с соответствующим `tool_call_id`. [s1](#src-s1) [s3](#src-s3)

Практический маршрут для прототипа: тестовый тикет без персональных данных → Qwen3-0.6B → совместимое локальное GPU-окружение → сервер SGLang на loopback → `qwen25` parser → разбор `tool_calls` → разрешённая фиктивная функция статуса. Малая модель удобна как проверка протокола, но не как доказательство качества планирования на рабочих процессах. Если сам сервер ещё не запускается, сначала откройте [общий гайд SGLang](/zhurnal/sglang/). [s1](#src-s1) [s2](#src-s2) [s6](#src-s6)

## Как выбрать парсер под конкретную модель?

Для обычной Qwen3 в закреплённом cookbook SGLang указан **tool parser **`**qwen25**`, тогда как `qwen3` в той же команде — **reasoning parser**. Это не два взаимозаменяемых названия одного флага. В `tokenizer_config.json` Qwen3-0.6B схема инструментов запрашивает JSON с `name` и `arguments` внутри тегов `<tool_call>`, а SGLang `Qwen25Detector` распознаёт такие теги; его реестр привязывает `qwen25` к этому детектору. [s1](#src-s1) [s4](#src-s4) [s5](#src-s5) [s7](#src-s7)

Не переносите `qwen25` на любую модель по слову «tool calling». SGLang перечисляет другие форматы (`hermes`, `deepseekv3`, `gpt-oss`, `qwen3_coder` и др.) и предлагает `auto` для распознавания по шаблону, но конкретную пару проверяйте по закреплённому токенизатору и фактическому ответу. Неподходящий парсер может оставить XML-подобный текст в `content` вместо структурированного `tool_calls` или не разобрать аргументы; это диагностическая возможность, а не универсальный код ошибки. [s2](#src-s2) [s4](#src-s4) [s5](#src-s5)

Карточка автора Qwen3-0.6B описывает instruction-модель и заявляет возможность работы с инструментами для семейства Qwen3. Репозиторий этого **конкретного** варианта содержит Apache License 2.0; лицензии других размеров, сторонних GGUF и условий эксплуатации чужой инфраструктуры здесь не проверены. Ни размер модели, ни размер файла с весами не служат гарантией доступной VRAM или правильного выбора функции. [s6](#src-s6) [s8](#src-s8)

## Что подготовить до запроса к локальному API?

Используйте установленный по [руководству SGLang](/zhurnal/sglang/) runtime и поддерживаемый для него GPU; сначала подтвердите обычный ответ без `tools`. При необходимости изолированного запуска сопоставьте параметры [Docker-гайда SGLang](/zhurnal/sglang-v-docker/). Проверьте доступную память на собственной машине и свободное место под скачиваемые файлы, не выводите минимум памяти из объёма весов. Версию кода SGLang устанавливайте и фиксируйте отдельно: приведённая ниже Git-ревизия фиксирует **документацию**, а не автоматически установленный бинарник. [s2](#src-s2) [s3](#src-s3) [s6](#src-s6)

На совместимом тестовом стенде пример запуска: `python3 -m sglang.launch_server --model-path Qwen/Qwen3-0.6B --revision c1899de289a04d12100db370d81485cdf75e47ca --reasoning-parser qwen3 --tool-call-parser qwen25 --host 127.0.0.1 --port 30000`. Флаги и модельная ревизия взяты из закреплённых документов; загрузка модели может обратиться к Hugging Face. Loopback нужен, чтобы не выставлять незащищённый HTTP API наружу. При ошибке сверяйте `--help` своей установленной версии и лог сервера, а не удаляйте флаг парсера наугад. [s1](#src-s1) [s2](#src-s2) [s6](#src-s6)

После готовности сервера проверьте `curl -fsS http://127.0.0.1:30000/v1/models` и подставьте полученный `id`, если он не совпал с названием репозитория. Затем проверьте обычный `/v1/chat/completions` без инструментов и сохраните ответ; это разделяет сбой запуска модели и ошибку парсера инструментов. Никаких производительных замеров Modelium здесь не проводил. [s3](#src-s3)

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

Передайте безопасную функцию `lookup_status` с одним строковым аргументом `ticket`; попросите проверить фиктивный `DEMO-1` и задайте `tool_choice: "auto"`. Компактный пример для `127.0.0.1` (одна строка, чтобы CMS не разрушила отступы): `curl -fsS http://127.0.0.1:30000/v1/chat/completions -H 'Content-Type: application/json' -d '{"model":"Qwen/Qwen3-0.6B","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","chat_template_kwargs":{"enable_thinking":false},"temperature":0.7}'`. Настройка `enable_thinking=false` взята из документации режима Qwen3; качество ответа маленькой модели не гарантировано. Если `/v1/models` вернул иной ID, замените только значение `model`. [s1](#src-s1) [s3](#src-s3) [s6](#src-s6) [s7](#src-s7)

**Критерий первого этапа:** сохранённый ответ содержит непустой `choices[0].message.tool_calls`, имя `lookup_status` и аргументы, разбираемые как JSON с `ticket == "DEMO-1"`; сохраните также `finish_reason` и ID вызова. Просто фраза «вызвал функцию» в `content` не проходит проверку. Не подставляйте реальные тикеты, токены и документы в учебный тест. Если модель вместо вызова отвечает текстом, это не успех: сохраните сырой JSON и перепроверьте шаблон и парсер. [s1](#src-s1) [s4](#src-s4) [s5](#src-s5) [s7](#src-s7)

**Критерий второго этапа:** клиентский код после проверки allowlist, типа аргумента и прав отдельно вызывает *локальный фиктивный* обработчик `lookup_status("DEMO-1")`, возвращающий заранее заданный статус; журнал клиента должен зафиксировать это действие. Только затем можно послать ответ функции с исходным `tool_call_id` и повторно спросить модель. Пример вывода в документации — не результат нашего прогона. Обработчик не должен выполнять произвольный shell, HTTP-вызов или доступ к данным лишь потому, что модель указала функцию в тексте. [s1](#src-s1) [s3](#src-s3)

Для отрицательного контроля повторите запрос с `tool_choice: "none"`: в этой конфигурации вызов инструмента не ожидается. Режим `required` принуждает к структурированному вызову и потому не заменяет проверку **самостоятельного** выбора в `auto`. Проверьте также некорректный или запрещённый аргумент: действие должно быть отклонено в клиентском коде независимо от красоты JSON. [s4](#src-s4) [s5](#src-s5)

## Что делать, если ответ выглядит как вызов, но инструмента нет?

При пустом `tool_calls` сравните фактическое имя модели из `/v1/models`, содержимое `content`, версию SGLang, ревизию `tokenizer_config.json`, оба флага парсеров и лог сервера. Теги `<tool_call>` в `content` или сообщение об ошибке парсинга не дают права исполнять текст вручную. В детекторе есть отдельный разбор JSON внутри тегов и обработка ошибочного JSON, поэтому отсутствие структурированного объекта — значимый отрицательный результат проверки данной конфигурации. [s2](#src-s2) [s4](#src-s4) [s5](#src-s5) [s7](#src-s7)

Если `tool_calls` есть, но имя или аргументы неожиданны, не «исправляйте» их тихо и не считайте успехом. Зафиксируйте запрос/ответ без секретов, смените модель или тестовый промпт и повторите проверку на реальных сценариях только после безопасного демонстрационного теста. Парсер распознаёт синтаксис; он не проверяет полномочия пользователя и не гарантирует истинность внешнего статуса. [s1](#src-s1) [s4](#src-s4) [s5](#src-s5)

Основной следующий шаг — [поднять локальный SGLang](/zhurnal/sglang/) и сохранить структурированный `tool_calls` вместе с **отдельным** подтверждением исполнения разрешённой тестовой функции. Если задача требует устойчивого бизнес-агента, оцените ошибки выбора на своих обезличенных примерах до подключения действий к системе. [s1](#src-s1) [s3](#src-s3)

## Источники

1. [SGLang: Qwen3 cookbook, tool calling](https://github.com/sgl-project/sglang/blob/f3b5a28f4315767261d439baf4705f2049d8871f/docs/cookbook/autoregressive/Qwen/Qwen3.mdx) — получено 2026-10-06
2. [SGLang: аргументы сервера и выбор парсера](https://github.com/sgl-project/sglang/blob/f3b5a28f4315767261d439baf4705f2049d8871f/docs/docs/advanced_features/server_arguments.mdx) — получено 2026-10-06
3. [SGLang: OpenAI-compatible Chat Completions](https://github.com/sgl-project/sglang/blob/f3b5a28f4315767261d439baf4705f2049d8871f/docs/docs/basic_usage/openai_api_completions.mdx) — получено 2026-10-06
4. [SGLang: реестр и логика function call parser](https://github.com/sgl-project/sglang/blob/f3b5a28f4315767261d439baf4705f2049d8871f/python/sglang/srt/function_call/function_call_parser.py) — получено 2026-10-06
5. [SGLang: Qwen25Detector для Qwen2.5 и Qwen3](https://github.com/sgl-project/sglang/blob/f3b5a28f4315767261d439baf4705f2049d8871f/python/sglang/srt/function_call/qwen25_detector.py) — получено 2026-10-06
6. [Qwen3-0.6B: карточка автора](https://huggingface.co/Qwen/Qwen3-0.6B/blob/c1899de289a04d12100db370d81485cdf75e47ca/README.md) — получено 2026-10-06
7. [Qwen3-0.6B: закреплённый chat template](https://huggingface.co/Qwen/Qwen3-0.6B/blob/c1899de289a04d12100db370d81485cdf75e47ca/tokenizer_config.json) — получено 2026-10-06
8. [Qwen3-0.6B: текст лицензии](https://huggingface.co/Qwen/Qwen3-0.6B/blob/c1899de289a04d12100db370d81485cdf75e47ca/LICENSE) — получено 2026-10-06
