Transformers documentation

CLI Serve

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

CLI Serve

CLI transformers serve — это лёгкий вариант для локальных или self-hosted серверов. Он позволяет избежать дополнительного накладного расхода времени выполнения и операционных издержек, характерных для специализированных движков инференса, таких как vLLM. Используйте его для оценки, экспериментов и развёртываний с умеренной нагрузкой. Функции, такие как continuous batching, повышают пропускную способность и снижают задержку.

Для крупных производственных развёртываний используйте vLLM или SGLang с моделью Transformer в качестве бэкенда. Подробнее — в руководстве Бэкенды инференса.

Команда transformers serve запускает локальный сервер, совместимый с OpenAI SDK. Сервер работает со многими сторонними приложениями и поддерживает перечисленные ниже REST API.

  • /v1/chat/completions для запросов с текстом, изображениями, аудио и видео
  • /v1/completions для устаревших текстовых дополнений из произвольного промпта
  • /v1/responses поддерживает Responses API
  • /v1/audio/transcriptions для транскрипции аудио
  • /v1/systemone отвечает на вопросы с заданными вариантами (выбор, оценка, да/нет), указывая вероятность для каждого допустимого ответа
  • /v1/models — список доступных моделей для интеграций сторонних сервисов
  • /load_model транслирует прогресс загрузки модели через SSE

Установите зависимости для обслуживания.

pip install transformers[serving]

Запустите transformers serve, чтобы запустить сервер. Адрес сервера по умолчанию — http://localhost:8000.

transformers serve

v1/chat/completions

API v1/chat/completions основан на Chat Completions API. Он поддерживает запросы с текстом, изображениями, аудио и видео для LLM, VLM и мультимодальных моделей. Используйте его с curl, InferenceClient или клиентом OpenAI.

Текстовые дополнения

huggingface_hub
huggingface_hub (поток)
openai
openai (stream)
curl
curl (поток)
from huggingface_hub import InferenceClient

messages = [{"role": "user", "content": "What is the Transformers library known for?"}]
client = InferenceClient("http://localhost:8000")

result = client.chat_completion(messages, model="Qwen/Qwen2.5-0.5B-Instruct", max_tokens=256)
print(result.choices[0].message.content)

Объект InferenceClient возвращает напечатанную строку.

The Transformers library is primarily known for its ability to create and manipulate large-scale language models [...]

Завершения на основе изображений

huggingface_hub
huggingface_hub (поток)
openai
openai (stream)
curl
curl (поток)
from huggingface_hub import InferenceClient

messages = [
    {
        "role": "user",
        "content": [
            {"type": "text", "text": "What's in this image?"},
            {
                "type": "image_url",
                "image_url": {
                    "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/astronaut.jpg",
                }
            },
        ],
    }
]
client = InferenceClient("http://localhost:8000")

result = client.chat_completion(messages, model="Qwen/Qwen2.5-VL-7B-Instruct", max_tokens=256)
print(result.choices[0].message.content)

Объект InferenceClient возвращает напечатанную строку.

The image depicts an astronaut in a space suit standing on what appears to be the surface of the moon, given the barren, rocky landscape and the dark sky in the background. The astronaut is holding a large egg that has cracked open, revealing a small creature inside. The scene is imaginative and playful, combining elements of space exploration with a whimsical twist involving the egg and the creature.

Завершения на основе аудио

Мультимодальные модели, такие как Gemma 4 и Qwen2.5-Omni, принимают аудиовход через тип содержимого input_audio в OpenAI. Закодируйте аудио в Base64 и укажите формат (mp3 или wav).

huggingface_hub
huggingface_hub (поток)
openai
openai (stream)
curl
curl (поток)
import base64
from huggingface_hub.utils import httpx
from huggingface_hub import InferenceClient

audio_url = "https://huggingface.co/datasets/hf-internal-testing/dummy-audio-samples/resolve/main/obama_first_45_secs.mp3"
audio_b64 = base64.b64encode(httpx.get(audio_url, follow_redirects=True).content).decode()

messages = [
    {
        "role": "user",
        "content": [
            {"type": "text", "text": "Transcribe this audio."},
            {"type": "input_audio", "input_audio": {"data": audio_b64, "format": "mp3"}},
        ],
    }
]
client = InferenceClient("http://localhost:8000")

result = client.chat_completion(messages, model="google/gemma-4-E2B-it", max_tokens=256)
print(result.choices[0].message.content)

Объект InferenceClient возвращает напечатанную строку.

This week, I traveled to Chicago to deliver my final farewell address to the nation, following in the tradition of presidents before me. It was an opportunity to say thank you. Whether we've seen eye to eye or rarely agreed at all, my conversations with you, the American people, in living rooms and schools, at farms and on factory floors, at diners, and on distant military outposts, all these conversations are what have kept me honest.

Тип содержимого audio_url является расширением, не входящим в стандарт OpenAI, и может измениться в будущих версиях.

Также можно передать аудио по URL с типом содержимого audio_url, чтобы избежать кодирования в base64.

completion = client.chat.completions.create(
    model="google/gemma-4-E2B-it",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Transcribe this audio."},
                {"type": "audio_url", "audio_url": {"url": "https://huggingface.co/datasets/hf-internal-testing/dummy-audio-samples/resolve/main/obama_first_45_secs.mp3"}},
            ],
        }
    ],
)

Завершения на основе видео

Тип содержимого video_url является расширением, не входящим в стандарт OpenAI, и может измениться в будущих версиях.

Используйте тип содержимого video_url для ввода видео. Если модель поддерживает аудио (например, Gemma 4, Qwen2.5-Omni), сервер извлекает аудиодорожку из видео и обрабатывает её вместе с визуальными кадрами.

Для обработки видео требуется torchcodec. Установите его с помощью pip install torchcodec.

huggingface_hub
huggingface_hub (поток)
openai
openai (stream)
curl
curl (поток)
from huggingface_hub import InferenceClient

messages = [
    {
        "role": "user",
        "content": [
            {"type": "video_url", "video_url": {"url": "https://huggingface.co/datasets/merve/vlm_test_images/resolve/main/concert.mp4"}},
            {"type": "text", "text": "What is happening in the video and what is the song about?"},
        ],
    }
]
client = InferenceClient("http://localhost:8000")

result = client.chat_completion(messages, model="google/gemma-4-E2B-it", max_tokens=256)
print(result.choices[0].message.content)

Объект InferenceClient возвращает напечатанную строку.

The video captures a live music performance at a music festival or a large concert. There are several musicians on stage, including a central figure playing an acoustic guitar and singing. The foreground is filled with the backs of the audience, indicating a large crowd watching the show. The stage is dramatically lit with bright spotlights and blue and white stage lighting, with haze and smoke creating an immersive atmosphere.

The lyrics of the song are: "I don't care 'bout street, from that fresh street, 'cause there's no problem, another one I want to be, in the storm..."

Многоразовые диалоги

Чтобы вести многоходовый диалог, включайте полную историю разговора в список messages, чередуя роли user и assistant. Как и все серверы, совместимые с OpenAI, API не сохраняет состояние, поэтому каждый запрос должен содержать полную историю диалога.

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="<random_string>")

completion = client.chat.completions.create(
    model="Qwen/Qwen2.5-0.5B-Instruct",
    messages=[
        {"role": "user", "content": "What is the capital of France?"},
        {"role": "assistant", "content": "The capital of France is Paris."},
        {"role": "user", "content": "How many people live there?"},
    ],
)
print(completion.choices[0].message.content)

Вопрос-продолжение «Сколько людей там живёт?» опирается на предыдущий контекст, поэтому модель отвечает о Париже.

As of 2021, the population of Paris is approximately 2.2 million people.

v1/completions

API v1/completions основан на устаревшем API Completions. В отличие от /v1/chat/completions, он принимает текстовый prompt в свободной форме, а не сообщения чата, и возвращает сгенерированный текст в choices[].text. Это удобно для базовых (не instruct) моделей и задач текстового дополнения, где не требуется шаблон чата. Также поддерживается параметр suffix для вставки текста в середину (fill-in-the-middle).

curl
openai
curl -X POST http://localhost:8000/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-0.5B",
    "prompt": "The capital of France is",
    "max_tokens": 20
  }'

Команда возвращает следующий ответ.

{
  "id": "chatcmpl-abc123",
  "object": "text_completion",
  "created": 1234567890,
  "model": "Qwen/Qwen2.5-0.5B@main",
  "choices": [
    {
      "text": " Paris, and the capital of the United States is Washington, D.C.",
      "index": 0,
      "logprobs": null,
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 5,
    "completion_tokens": 16,
    "total_tokens": 21
  }
}

v1/responses

Responses API — это новейший API-эндпоинт OpenAI для генерации. Он поддерживает взаимодействия с состоянием и интегрирует встроенные инструменты для расширения возможностей модели. OpenAI рекомендует использовать Responses API вместо Chat Completions API в новых проектах.

API v1/responses поддерживает запросы с текстом, изображениями, аудио и видео через команду curl и клиент OpenAI.

Текстовые ответы

openai
openai (stream)
curl
curl (поток)
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="<random_string>")

response = client.responses.create(
    model="Qwen/Qwen2.5-0.5B-Instruct",
    input="Tell me a three sentence bedtime story about a unicorn.",
    max_output_tokens=256,
    stream=False,
)
print(response.output[0].content[0].text)

Клиент OpenAI возвращает напечатанную строку.

Once upon a time, in a faraway land, there lived a beautiful unicorn named Luna [...]

Ответы на основе изображений

API Responses также поддерживает входные данные в формате изображений, аудио и видео.

openai
openai (stream)
curl
curl (поток)
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="<random_string>")

response = client.responses.create(
    model="Qwen/Qwen2.5-VL-7B-Instruct",
    input=[
        {"type": "input_text", "text": "What's in this image?"},
        {
            "type": "input_image",
            "image_url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/astronaut.jpg",
        },
    ],
    max_output_tokens=256,
    stream=False,
)
print(response.output[0].content[0].text)

Клиент OpenAI возвращает напечатанную строку.

The image depicts an astronaut in a space suit standing on what appears to be the surface of the moon, given the barren, rocky landscape and the dark sky in the background. The astronaut is holding a large egg that has cracked open, revealing a small creature inside. The scene is imaginative and playful, combining elements of space exploration with a whimsical twist involving the egg and the creature.

Ответы на основе аудио

openai
openai (stream)
curl
curl (поток)
import base64
from huggingface_hub.utils import httpx
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="<random_string>")

audio_url = "https://huggingface.co/datasets/hf-internal-testing/dummy-audio-samples/resolve/main/obama_first_45_secs.mp3"
audio_b64 = base64.b64encode(httpx.get(audio_url, follow_redirects=True).content).decode()

response = client.responses.create(
    model="google/gemma-4-E2B-it",
    input=[
        {"type": "input_text", "text": "Transcribe this audio."},
        {"type": "input_audio", "input_audio": {"data": audio_b64, "format": "mp3"}},
    ],
    max_output_tokens=256,
    stream=False,
)
print(response.output[0].content[0].text)

Клиент OpenAI возвращает напечатанную строку.

This week, I traveled to Chicago to deliver my final farewell address to the nation, following in the tradition of presidents before me. It was an opportunity to say thank you. Whether we've seen eye to eye or rarely agreed at all, my conversations with you, the American people, in living rooms and schools, at farms and on factory floors, at diners, and on distant military outposts, all these conversations are what have kept me honest.

Тип содержимого audio_url является расширением, не входящим в стандарт OpenAI, и может измениться в будущих версиях.

Также можно передать аудио по URL с типом содержимого audio_url, чтобы избежать кодирования в base64.

response = client.responses.create(
    model="google/gemma-4-E2B-it",
    input=[
        {"type": "input_text", "text": "Transcribe this audio."},
        {"type": "audio_url", "audio_url": {"url": "https://huggingface.co/datasets/hf-internal-testing/dummy-audio-samples/resolve/main/obama_first_45_secs.mp3"}},
    ],
    max_output_tokens=256,
    stream=False,
)

Ответы на основе видео

Тип содержимого video_url является расширением, не входящим в стандарт OpenAI, и может измениться в будущих версиях.

Для обработки видео требуется torchcodec. Установите его с помощью pip install torchcodec.

openai
openai (stream)
curl
curl (поток)
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="<random_string>")

response = client.responses.create(
    model="google/gemma-4-E2B-it",
    input=[
        {"type": "input_text", "text": "What is happening in the video and what is the song about?"},
        {"type": "video_url", "video_url": {"url": "https://huggingface.co/datasets/merve/vlm_test_images/resolve/main/concert.mp4"}},
    ],
    max_output_tokens=256,
    stream=False,
)
print(response.output[0].content[0].text)

Клиент OpenAI возвращает напечатанную строку.

The video captures a live music performance at a music festival or a large concert. There are several musicians on stage, including a central figure playing an acoustic guitar and singing. The foreground is filled with the backs of the audience, indicating a large crowd watching the show. The stage is dramatically lit with bright spotlights and blue and white stage lighting, with haze and smoke creating an immersive atmosphere.

The lyrics of the song are: "I don't care 'bout street, from that fresh street, 'cause there's no problem, another one I want to be, in the storm..."

Многоразовые диалоги

Для многоходовых диалогов передавайте список сообщений с ключами role в поле input. Как и все серверы, совместимые с OpenAI, API не сохраняет состояние, поэтому каждый запрос должен содержать полную историю диалога.

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="<random_string>")

response = client.responses.create(
    model="Qwen/Qwen2.5-0.5B-Instruct",
    input=[
        {"role": "user", "content": "What is the capital of France?"},
        {"role": "assistant", "content": "The capital of France is Paris."},
        {"role": "user", "content": "How many people live there?"},
    ],
    max_output_tokens=256,
    stream=False,
)
print(response.output[0].content[0].text)

Вопрос-продолжение «Сколько людей там живёт?» опирается на предыдущий контекст, поэтому модель отвечает о Париже.

As of 2021, Paris has a population of approximately 2.8 million people.

v1/systemone

Эндпоинт v1/systemone отвечает на типизированные вопросы о разделяемом state в соответствии с System One API от TypeSafe. Используйте его для принятия решений, например, маршрутизации тикета поддержки, оценки срочности или выбора действия.

Модель оценивает допустимые ответы за один пакетный прямой проход без генерации текста. Этот эндпоинт поддерживает авторегрессионные модели с шаблоном чата;

Отправьте модель, состояние для оценки и вопросы, привязанные к именам:

curl
TypeSafe (TypeScript)
curl http://localhost:8000/v1/systemone \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-1.5B-Instruct",
    "state": "Our integration has been failing for 3 days and we are losing sales!",
    "questions": {
      "team": {
        "type": "choice",
        "instructions": "Which team handles this?",
        "criteria": {"billing": null, "technical": "Bugs or integration problems"}
      },
      "urgency": {
        "type": "score",
        "instructions": "How urgent is this ticket?",
        "criteria": ["low", "medium", "high"]
      },
      "upset": {"type": "noul", "instructions": "Is the customer upset?"}
    }
  }'

Ответы используют те же имена вопросов. Например:

{
  "model": "Qwen/Qwen2.5-1.5B-Instruct",
  "answers": {
    "team": {"type": "choice", "choice": "technical", "probabilities": {"billing": 0.000006962256520637311, "technical": 0.999993085861206}, "confidence": 0.9999861717224121},
    "urgency": {"type": "score", "score": 1.6739138662815094, "legend": {"0": "low", "1": "medium", "2": "high"}, "probabilities": {"0": 0.0031353600788861513, "1": 0.31981542706489563, "2": 0.6770492196083069}, "confidence": 0.5108707791659981},
    "upset": {"type": "noul", "noul": 0.851952850818634}
  },
  "usage": {"input_tokens": 213, "output_tokens": 0}
}
Тип вопросаcriteriaОтвет
choiceИмена опций, сопоставленные с описаниями, которые могут быть null.Наиболее вероятный вариант, вероятности вариантов и уверенность.
scoreОписания уровней, расположенные от наименьшего к наибольшему.Индекс уровня с весами вероятности, вероятности, легенда и уверенность.
noulНеобязательные описания для true и false.Вероятность true.

state, необязательные instructions и описания могут содержать текст или JSON-объекты и массивы. Каждый запрос принимает до 64 вопросов, по 1–26 вариантов ответа или уровней оценки на вопрос.

Для моделей с поддержкой изображений добавьте массив images с не более чем четырьмя URL в формате data:image/...;base64,.... Каждому вопросу передаются одни и те же изображения. Процессор и шаблон чата модели должны поддерживать изображения; удалённые URL изображений не принимаются.

Конфигурация принятия решений

Модели принятия решений пока не имеют единого стандарта для хранения промптов, меток ответов и настроек калибровки. Эти параметры различаются в зависимости от реализации модели, поэтому --decision-config позволяет указать их явно. Модели с кастомными decision heads по-прежнему требуют совместимой реализации; данный файл лишь настраивает форматирование промпта и оценку следующего токена.

По умолчанию для вопросов используется резервный промпт и шаблон чата модели с отключённым режимом размышлений. Метки ответов — A–Z для вариантов и оценок, а также Yes/No для булевых значений. Вероятности вычисляются как softmax по этим меткам при температуре 1.

Передайте --decision-config, чтобы переопределить эти значения по умолчанию для модели:

transformers serve openjev/openjev --decision-config decision.json

JSON-файл поддерживает три необязательных поля:

ПолеЗначение
labelsМетки ответов по типу вопроса, в порядке вариантов (true, затем false для noul). Каждая должна быть отдельным известным одиночным токеном.
temperatureПоложительные температуры по типу вопроса, применяемые как softmax(label_logits / temperature).
chat_templateВстроенный шаблон Jinja, заменяющий полный промпт, включая форматирование чата и префикс ассистента.

Например, чтобы изменить метки и калибровку, сохранив при этом подсказку по умолчанию:

{
  "labels": {"noul": ["A", "B"]},
  "temperature": {"choice": 0.85, "score": 0.85, "noul": 1.5547129}
}

Пользовательский шаблон получает стандартные messages, а также необработанные поля state, images и question. Поле question предоставляет доступ к name, type, instructions, options, labels, descriptions и legend; варианты, метки и описания имеют одинаковый порядок. Используйте эти поля для замены текста по умолчанию, а tojson — для отображения структурированных значений. Шаблоны для входных изображений должны содержать плейсхолдеры изображений модели.

Файл загружается при запуске и применяется только к /v1/systemone. Пропущенные настройки сохраняют значения по умолчанию; конфигурация решений не читается автоматически из контрольной точки.

v1/audio/transcriptions

Эндпоинт v1/audio/transcriptions выполняет транскрибацию аудио с помощью моделей speech-to-text. Он соответствует формату API транскрибации аудио.

curl -X POST http://localhost:8000/v1/audio/transcriptions \
  -H "Content-Type: multipart/form-data" \
  -F "file=@/path/to/audio.wav" \
  -F "model=openai/whisper-large-v3"

Команда возвращает следующий ответ.

{
  "text": "Transcribed text from the audio file",
}

v1/models

Эндпоинт v1/models сканирует локальный кэш Hugging Face и возвращает список загруженных моделей в формате, совместимом с OpenAI. Сторонние инструменты используют этот эндпоинт для обнаружения доступных моделей.

Скачайте модель перед запуском transformers serve.

transformers download Qwen/Qwen2.5-0.5B-Instruct

После загрузки модель отображается в ответах /v1/models.

curl http://localhost:8000/v1/models

Эндпоинт возвращает JSON-объект с доступными моделями.

Загрузка моделей

Эндпоинт /load_model предварительно загружает модель и транслирует прогресс через Server-Sent Events (SSE). CLI transformers chat использует его автоматически, чтобы пользователи видели прогресс загрузки и инициализации, а не зависший промпт. Используйте его для предварительной загрузки модели перед отправкой запросов на инференс.

Запрос

curl -N -X POST http://localhost:8000/load_model \
  -H "Content-Type: application/json" \
  -d '{"model": "Qwen/Qwen2.5-0.5B-Instruct"}'

Поле model — это идентификатор модели Hugging Face, при необходимости с суффиксом @revision (Qwen/Qwen2.5-0.5B-Instruct@main). Если ревизия не указана, по умолчанию используется main.

Ответ

Ответ представляет собой SSE-поток (Content-Type: text/event-stream). Каждая фрейма — это JSON-объект на строке data:.

data: {"status": "loading", "model": "Qwen/Qwen2.5-0.5B-Instruct@main", "stage": "processor"}

Каждое событие содержит как минимум поля status и model. Дополнительные поля зависят от статуса.

ПолеПрисутствует, когдаОписание
statusВсегдаloading, ready или error
modelВсегдаКанонический model_id@revision
stagestatus == "loading"Один из processor, config, download, weights (см. этапы ниже)
progressстадии download и weightsОбъект с current и total (целое число или null)
cachedstatus == "ready"true, если модель уже находилась в памяти
messagestatus == "error"Описание ошибки

Этапы

Загрузка проходит через эти этапы последовательно. Некоторые из них могут быть пропущены (этап download пропускается, если файлы уже кэшированы локально).

ЭтапЕсть ли прогресс?Описание
processorНетЗагрузка токенизатора/процессора
configНетЗагрузка конфигурации модели
downloadДа (байты)Загрузка файлов модели
weightsДа (элементы)Загрузка тензоров весов в память

Поток завершается ровно одним терминальным событием: ready (успех) или error (сбой).

Тайм-аут

transformers serve обрабатывает запросы для любой модели. Каждая модель загружается по требованию и остаётся в памяти GPU. Модели автоматически выгружаются после 300 секунд простоя, чтобы освободить память GPU. Установите --model-timeout в другое значение в секундах или -1, чтобы отключить выгрузку.

transformers serve --model-timeout 400

Загрузка примеров

Приведённые ниже примеры показывают ответы для только что загруженной модели, модели, загруженной из локального кэша (этап скачивания пропускается), и модели, уже находящейся в памяти.

свежая загрузка
кэшированные файлы
в памяти
data: {"status": "loading", "model": "org/model@main", "stage": "processor"}
data: {"status": "loading", "model": "org/model@main", "stage": "config"}
data: {"status": "loading", "model": "org/model@main", "stage": "download", "progress": {"current": 0, "total": 269100000}}
data: {"status": "loading", "model": "org/model@main", "stage": "download", "progress": {"current": 134600000, "total": 269100000}}
data: {"status": "loading", "model": "org/model@main", "stage": "download", "progress": {"current": 269100000, "total": 269100000}}
data: {"status": "loading", "model": "org/model@main", "stage": "weights", "progress": {"current": 1, "total": 272}}
data: {"status": "loading", "model": "org/model@main", "stage": "weights", "progress": {"current": 272, "total": 272}}
data: {"status": "ready", "model": "org/model@main", "cached": false}

Вызов инструментов

Сервер transformers serve поддерживает вызов функций в стиле OpenAI. Модели, обученные для использования инструментов, генерируют структурированные вызовы функций, которые выполняет ваше приложение.

Функция вызова инструментов работает с любой моделью, токенизатор которой объявляет токены вызова инструментов. Qwen и Gemma 4 поддерживаются из коробки. Откройте issue, чтобы запросить поддержку конкретной модели.

Определите инструменты в виде списка спецификаций функций, соответствующих формату OpenAI.

import json
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="<KEY>")

tools = [
  {
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "Get the current weather in a location",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {
            "type": "string",
            "description": "The city name, e.g. San Francisco"
          },
          "unit": {
            "type": "string",
            "enum": ["celsius", "fahrenheit"],
            "description": "temperature unit"
          }
        },
        "required": ["location"]
      }
    }
  }
]

Настройте генерацию, передав параметры GenerationConfig в аргумент extra_body в create.

generation_config = {
  "max_new_tokens": 512,
  "temperature": 0.7,
  "top_p": 0.9,
  "top_k": 50,
  "do_sample": True,
  "repetition_penalty": 1.1,
  "no_repeat_ngram_size": 3,
}

response = client.responses.create(
  model="Qwen/Qwen2.5-7B-Instruct",
  instructions="You are a helpful weather assistant. Use the get_weather tool to answer questions.",
  input="What's the weather like in San Francisco?",
  tools=tools,
  stream=True,
  extra_body={"generation_config": json.dumps(generation_config)}
)

for event in response:
  print(event)

Многоходовое вызов инструментов

После того как модель возвращает вызов инструмента, выполните функцию локально, затем отправьте результат в последующем запросе, чтобы получить окончательный ответ модели. Этот паттерн немного различается в двух API. Полную спецификацию см. в руководстве по вызову функций OpenAI.

Приведённые ниже примеры повторно используют список tools, определённый выше.

v1/chat/completions
v1/responses

Передайте результат инструмента как сообщение с role: "tool" и соответствующим tool_call_id.

# Model returns a tool call
messages = [{"role": "user", "content": "What's the weather like in San Francisco?"}]
response = client.chat.completions.create(
    model="Qwen/Qwen2.5-7B-Instruct",
    messages=messages,
    tools=tools,
)
assistant_message = response.choices[0].message

# Execute the tool locally
tool_call = assistant_message.tool_calls[0]
result = {"temperature": 22, "condition": "sunny"}  # your actual function call here

# Send the tool result back
messages.append(assistant_message)
messages.append({
    "role": "tool",
    "tool_call_id": tool_call.id,
    "content": json.dumps(result),
})
final_response = client.chat.completions.create(
    model="Qwen/Qwen2.5-7B-Instruct",
    messages=messages,
    tools=tools,
)
print(final_response.choices[0].message.content)

Рассуждения

Модели рассуждения генерируют скрытую цепочку рассуждений перед финальным ответом. Сервер обнаруживает эти фрагменты размышлений, удаляет разделители из видимого ответа и выводит текст рассуждений в отдельное поле, чтобы клиенты могли отображать его независимо.

  • Chat Completions возвращает рассуждения в поле reasoning_content сообщения ассистента.
  • Responses API возвращает рассуждения в виде элемента вывода reasoning, который предшествует элементу message.

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

  1. Атрибут response_template токенизатора, если модель поставляется с ним.
  2. Встроенный вариант по умолчанию, соответствующий архитектуре модели, для токенизаторов, у которых пока нет шаблона.

Модели, не имеющие ни того, ни другого, обслуживаются без разбора ответа. Сырой декодированный текст возвращается как content, и поле рассуждений не выводится, даже если модель генерирует теги <think>...</think>.

Включение рассуждений на сервере

Используйте --reasoning, чтобы управлять выводом токенов размышлений в шаблоне чата.

ЗначениеПоведение
auto (по умолчанию)По умолчанию используется шаблон чата.
onЧтобы принудительно включить режим размышлений, установите enable_thinking=True в аргументах шаблона чата.
offОтключите режим размышлений, установив enable_thinking=False.
transformers serve Qwen/Qwen3-1.7B --reasoning on

Не все модели поддерживают рассуждения. Флаг --reasoning работает только в том случае, если шаблон чата модели обрабатывает переменную enable_thinking (или если её токенизатор объявляет разделители для рассуждений). Для других моделей этот флаг молча игнорируется.

--reasoning on и --reasoning off работают, устанавливая переменную шаблона чата enable_thinking. Некоторые шаблоны чата используют другое имя переменной для переключения режима размышлений или принимают дополнительные переменные, изменяющие способ рендеринга промпта. Передайте любую переменную шаблона чата напрямую с помощью --chat-template-kwargs в виде JSON-объекта.

transformers serve Qwen/Qwen3-1.7B \
  --chat-template-kwargs '{"enable_thinking": true}'

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

Chat Completions

Ответы без потоковой передачи содержат reasoning_content наряду с content в сообщении ассистента.

openai
openai (stream)
curl
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="<KEY>")

completion = client.chat.completions.create(
    model="Qwen/Qwen3-1.7B",
    messages=[{"role": "user", "content": "What is 17 * 23?"}],
)
message = completion.choices[0].message
print("reasoning:", message.reasoning_content)
print("answer:", message.content)

Responses API

Responses API возвращает рассуждения как отдельный элемент вывода reasoning, который предшествует элементу message.

openai
openai (stream)
response = client.responses.create(
    model="Qwen/Qwen3-1.7B",
    input="What is 17 * 23?",
    stream=False,
)
reasoning_item = next(i for i in response.output if i.type == "reasoning")
message_item = next(i for i in response.output if i.type == "message")
print("reasoning:", reasoning_item.content[0].text)
print("answer:", message_item.content[0].text)

Многоходовый обмен

Для многоходовых диалогов включайте текст рассуждений из предыдущего ответа в следующий запрос. Сервер передаёт его в шаблон чата, который может отобразить его как часть предыдущего хода ассистента, чтобы модель видела собственный предыдущий ход рассуждений.

v1/chat/completions
v1/responses

Добавьте reasoning_content к предыдущему сообщению ассистента.

first = client.chat.completions.create(
    model="Qwen/Qwen3-1.7B",
    messages=[{"role": "user", "content": "What is 17 * 23?"}],
).choices[0].message

second = client.chat.completions.create(
    model="Qwen/Qwen3-1.7B",
    messages=[
        {"role": "user", "content": "What is 17 * 23?"},
        {
            "role": "assistant",
            "content": first.content,
            "reasoning_content": first.reasoning_content,
        },
        {"role": "user", "content": "Now multiply that result by 2."},
    ],
)
print(second.choices[0].message.content)

Перенаправление портов

Пересылка портов позволяет обслуживать модели с удалённого сервера. Убедитесь, что у вас есть доступ к серверу по SSH, затем выполните эту команду на локальной машине.

ssh -N -f -L 8000:localhost:8000 your_server_account@your_server_IP -p port_to_ssh_into_your_server

Воспроизводимость

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

transformers serve Qwen/Qwen2.5-0.5B-Instruct \
  --continuous-batching \
  --dtype "bfloat16"
Update on GitHub