# CLI Serve

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

> [!TIP]
> Для крупных производственных развёртываний используйте vLLM или SGLang с моделью Transformer в качестве бэкенда. Подробнее — в руководстве [Бэкенды инференса](../community_integrations/transformers_as_backend).

Команда `transformers serve` запускает локальный сервер, совместимый с [OpenAI SDK](https://platform.openai.com/docs/overview). Сервер работает со многими сторонними приложениями и поддерживает перечисленные ниже REST API.

- `/v1/chat/completions` для запросов с текстом, изображениями, аудио и видео
- `/v1/completions` для устаревших текстовых дополнений из произвольного промпта
- `/v1/responses` поддерживает [Responses API](https://platform.openai.com/docs/api-reference/responses)
- `/v1/audio/transcriptions` для транскрипции аудио
- `/v1/systemone` отвечает на вопросы с заданными вариантами (выбор, оценка, да/нет), указывая вероятность для каждого допустимого ответа
- `/v1/models` — список доступных моделей для интеграций сторонних сервисов
- `/load_model` транслирует прогресс загрузки модели через SSE

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

```bash
pip install transformers[serving]
```

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

```shell
transformers serve
```

## v1/chat/completions

API `v1/chat/completions` основан на [Chat Completions API](https://platform.openai.com/docs/api-reference/chat). Он поддерживает запросы с текстом, изображениями, аудио и видео для LLM, VLM и мультимодальных моделей. Используйте его с `curl`, [InferenceClient](https://huggingface.co/docs/huggingface_hub/v2.4.0/en/package_reference/inference_client#huggingface_hub.InferenceClient) или клиентом [OpenAI](https://platform.openai.com/docs/quickstart).

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

```python
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](https://huggingface.co/docs/huggingface_hub/v2.4.0/en/package_reference/inference_client#huggingface_hub.InferenceClient) возвращает напечатанную строку.

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

```python
from huggingface_hub import InferenceClient

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

stream = client.chat_completion(messages, model="Qwen/Qwen2.5-0.5B-Instruct", max_tokens=256, stream=True)
for chunk in stream:
    token = chunk.choices[0].delta.content
    if token:
        print(token, end="")
```

Объект [InferenceClient](https://huggingface.co/docs/huggingface_hub/v2.4.0/en/package_reference/inference_client#huggingface_hub.InferenceClient) возвращает напечатанную строку.

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

```python
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 Transformers library known for?"
        }
    ],
)
print(completion.choices[0].message.content)
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

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

```python
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 Transformers library known for?"
        }
    ],
    stream=True,
)

for chunk in completion:
    token = chunk.choices[0].delta.content
    if token:
        print(token, end="")
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

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

```shell
curl -X POST http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-0.5B-Instruct",
    "messages": [{"role": "user", "content": "What is the Transformers library known for?"}],
    "temperature": 0.9,
    "max_tokens": 256
  }'
```

Команда возвращает строку в формате JSON.

```json
{
  "id": "ade3578d-e2c3-47ed-b651-c014991a92f6",
  "choices": [
    {
      "finish_reason": "length",
      "index": 0,
      "message": {
        "content": "The Transformers library is primarily known for its ability to create and manipulate large-scale language models [...]",
        "role": "assistant"
      }
    }
  ],
  "created": 1776184004,
  "model": "Qwen/Qwen2.5-0.5B-Instruct@main",
  "object": "chat.completion",
  "usage": {
    "completion_tokens": 256,
    "prompt_tokens": 37,
    "total_tokens": 293
  }
}
```

```shell
curl -X POST http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-0.5B-Instruct",
    "messages": [{"role": "user", "content": "What is the Transformers library known for?"}],
    "temperature": 0.9,
    "max_tokens": 256,
    "stream": true
  }'
```

Команда возвращает поток фрагментов.

```shell
data: {"id":"596d3941-754d-43b4-8773-9bf9940049f5","choices":[{"delta":{"role":"assistant"},"index":0}],"created":1776183469,"model":"Qwen/Qwen2.5-0.5B-Instruct@main","object":"chat.completion.chunk","system_fingerprint":""}

data: {"id":"596d3941-754d-43b4-8773-9bf9940049f5","choices":[{"delta":{"content":"The"},"index":0}],"created":1776183469,"model":"Qwen/Qwen2.5-0.5B-Instruct@main","object":"chat.completion.chunk","system_fingerprint":""}

(...)
```

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

```python
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](https://huggingface.co/docs/huggingface_hub/v2.4.0/en/package_reference/inference_client#huggingface_hub.InferenceClient) возвращает напечатанную строку.

```xmp
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.
```

```python
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")

stream = client.chat_completion(messages, model="Qwen/Qwen2.5-VL-7B-Instruct", max_tokens=256, stream=True)
for chunk in stream:
    token = chunk.choices[0].delta.content
    if token:
        print(token, end="")
```

Объект [InferenceClient](https://huggingface.co/docs/huggingface_hub/v2.4.0/en/package_reference/inference_client#huggingface_hub.InferenceClient) возвращает напечатанную строку.

```xmp
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.
```

```python
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-VL-7B-Instruct",
    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",
                    }
                },
            ],
        }
    ],
)
print(completion.choices[0].message.content)
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```xmp
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.
```

```python
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-VL-7B-Instruct",
    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",
                    }
                },
            ],
        }
    ],
    stream=True,
)

for chunk in completion:
    token = chunk.choices[0].delta.content
    if token:
        print(token, end="")
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```xmp
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.
```

```shell
curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-VL-7B-Instruct",
    "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"
            }
          }
        ]
      }
    ],
    "max_tokens": 256
  }'
```

Команда возвращает строку в формате JSON.

```json
{
  "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "content": "The image depicts an astronaut in a space suit standing on what appears to be the surface of the moon [...]",
        "role": "assistant"
      }
    }
  ],
  "created": 1753366665,
  "model": "Qwen/Qwen2.5-VL-7B-Instruct@main",
  "object": "chat.completion",
  "usage": {
    "completion_tokens": 50,
    "prompt_tokens": 120,
    "total_tokens": 170
  }
}
```

```shell
curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-VL-7B-Instruct",
    "stream": true,
    "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"
            }
          }
        ]
      }
    ],
    "max_tokens": 256
  }'
```

Команда возвращает поток фрагментов.

```shell
data: {"id":"f47ac10b-58cc-4372-a567-0e02b2c3d479","choices":[{"delta":{"role":"assistant"},"index":0}],"created":1753366665,"model":"Qwen/Qwen2.5-VL-7B-Instruct@main","object":"chat.completion.chunk","system_fingerprint":""}

data: {"id":"f47ac10b-58cc-4372-a567-0e02b2c3d479","choices":[{"delta":{"content":"The "},"index":0}],"created":1753366701,"model":"Qwen/Qwen2.5-VL-7B-Instruct@main","object":"chat.completion.chunk","system_fingerprint":""}

(...)
```

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

Мультимодальные модели, такие как [Gemma 4](https://huggingface.co/google/gemma-4-E2B-it) и [Qwen2.5-Omni](https://huggingface.co/Qwen/Qwen2.5-Omni-3B), принимают аудиовход через тип содержимого `input_audio` в OpenAI. Закодируйте аудио в Base64 и укажите формат (`mp3` или `wav`).

```python
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](https://huggingface.co/docs/huggingface_hub/v2.4.0/en/package_reference/inference_client#huggingface_hub.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.
```

```python
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")

stream = client.chat_completion(messages, model="google/gemma-4-E2B-it", max_tokens=256, stream=True)
for chunk in stream:
    token = chunk.choices[0].delta.content
    if token:
        print(token, end="")
```

Объект [InferenceClient](https://huggingface.co/docs/huggingface_hub/v2.4.0/en/package_reference/inference_client#huggingface_hub.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.
```

```python
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()

completion = client.chat.completions.create(
    model="google/gemma-4-E2B-it",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Transcribe this audio."},
                {"type": "input_audio", "input_audio": {"data": audio_b64, "format": "mp3"}},
            ],
        }
    ],
)
print(completion.choices[0].message.content)
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```
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.
```

```python
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()

completion = client.chat.completions.create(
    model="google/gemma-4-E2B-it",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Transcribe this audio."},
                {"type": "input_audio", "input_audio": {"data": audio_b64, "format": "mp3"}},
            ],
        }
    ],
    stream=True,
)

for chunk in completion:
    token = chunk.choices[0].delta.content
    if token:
        print(token, end="")
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```
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.
```

```shell
# First, base64-encode the audio file and build the JSON payload
AUDIO_B64=$(curl -sL https://huggingface.co/datasets/hf-internal-testing/dummy-audio-samples/resolve/main/obama_first_45_secs.mp3 | base64 -w 0)

cat <<EOF > /tmp/audio_request.json
{
  "model": "google/gemma-4-E2B-it",
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "text", "text": "Transcribe this audio."},
        {"type": "input_audio", "input_audio": {"data": "$AUDIO_B64", "format": "mp3"}}
      ]
    }
  ]
}
EOF

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d @/tmp/audio_request.json
```

Команда возвращает строку в формате JSON.

```json
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "choices": [
    {
      "finish_reason": "stop",
      "index": 0,
      "message": {
        "content": "This week, I traveled to Chicago to deliver my final farewell address to the nation [...]",
        "role": "assistant"
      }
    }
  ],
  "created": 1753366665,
  "model": "google/gemma-4-E2B-it@main",
  "object": "chat.completion",
  "usage": {
    "completion_tokens": 85,
    "prompt_tokens": 200,
    "total_tokens": 285
  }
}
```

```shell
# First, base64-encode the audio file and build the JSON payload
AUDIO_B64=$(curl -sL https://huggingface.co/datasets/hf-internal-testing/dummy-audio-samples/resolve/main/obama_first_45_secs.mp3 | base64 -w 0)

cat <<EOF > /tmp/audio_request.json
{
  "model": "google/gemma-4-E2B-it",
  "stream": true,
  "messages": [
    {
      "role": "user",
      "content": [
        {"type": "text", "text": "Transcribe this audio."},
        {"type": "input_audio", "input_audio": {"data": "$AUDIO_B64", "format": "mp3"}}
      ]
    }
  ]
}
EOF

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d @/tmp/audio_request.json
```

Команда возвращает поток фрагментов.

```shell
data: {"id":"cb997e1d-98b9-414a-be89-1880288610ef","choices":[{"delta":{"role":"assistant"},"index":0}],"created":1776254856,"model":"google/gemma-4-E2B-it@main","object":"chat.completion.chunk","system_fingerprint":""}

data: {"id":"cb997e1d-98b9-414a-be89-1880288610ef","choices":[{"delta":{"content":"This"},"index":0}],"created":1776254856,"model":"google/gemma-4-E2B-it@main","object":"chat.completion.chunk","system_fingerprint":""}

(...)
```

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

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

```python
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"}},
            ],
        }
    ],
)
```

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

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

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

> [!TIP]
> Для обработки видео требуется [torchcodec](https://github.com/pytorch/torchcodec). Установите его с помощью `pip install torchcodec`.

```python
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](https://huggingface.co/docs/huggingface_hub/v2.4.0/en/package_reference/inference_client#huggingface_hub.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..."
```

```python
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")

stream = client.chat_completion(messages, model="google/gemma-4-E2B-it", max_tokens=256, stream=True)
for chunk in stream:
    token = chunk.choices[0].delta.content
    if token:
        print(token, end="")
```

Объект [InferenceClient](https://huggingface.co/docs/huggingface_hub/v2.4.0/en/package_reference/inference_client#huggingface_hub.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..."
```

```python
from openai import OpenAI

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

completion = client.chat.completions.create(
    model="google/gemma-4-E2B-it",
    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?"},
            ],
        }
    ],
    max_tokens=256,
)
print(completion.choices[0].message.content)
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```
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..."
```

```python
from openai import OpenAI

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

completion = client.chat.completions.create(
    model="google/gemma-4-E2B-it",
    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?"},
            ],
        }
    ],
    max_tokens=256,
    stream=True,
)

for chunk in completion:
    token = chunk.choices[0].delta.content
    if token:
        print(token, end="")
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```
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..."
```

```shell
curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemma-4-E2B-it",
    "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?"}
        ]
      }
    ],
    "max_tokens": 256
  }'
```

Команда возвращает строку в формате JSON.

```json
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "choices": [
    {
      "finish_reason": "length",
      "index": 0,
      "message": {
        "content": "The video captures a live music performance at a music festival or a large concert [...]",
        "role": "assistant"
      }
    }
  ],
  "created": 1753366665,
  "model": "google/gemma-4-E2B-it@main",
  "object": "chat.completion",
  "usage": {
    "completion_tokens": 256,
    "prompt_tokens": 350,
    "total_tokens": 606
  }
}
```

```shell
curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemma-4-E2B-it",
    "stream": true,
    "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?"}
        ]
      }
    ],
    "max_tokens": 256
  }'
```

Команда возвращает поток фрагментов.

```shell
data: {"id":"cb997e1d-98b9-414a-be89-1880288610ef","choices":[{"delta":{"role":"assistant"},"index":0}],"created":1776254856,"model":"google/gemma-4-E2B-it@main","object":"chat.completion.chunk","system_fingerprint":""}

data: {"id":"cb997e1d-98b9-414a-be89-1880288610ef","choices":[{"delta":{"content":"Based"},"index":0}],"created":1776254856,"model":"google/gemma-4-E2B-it@main","object":"chat.completion.chunk","system_fingerprint":""}

(...)
```

### Многоразовые диалоги[[completions]]

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

```python
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](https://platform.openai.com/docs/api-reference/completions). В отличие от `/v1/chat/completions`, он принимает текстовый `prompt` в свободной форме, а не сообщения чата, и возвращает сгенерированный текст в `choices[].text`. Это удобно для базовых (не instruct) моделей и задач текстового дополнения, где не требуется шаблон чата. Также поддерживается параметр `suffix` для вставки текста в середину (fill-in-the-middle).

```shell
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
  }'
```

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

```json
{
  "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
  }
}
```

```python
from openai import OpenAI

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

# Non-streaming
completion = client.completions.create(
    model="Qwen/Qwen2.5-0.5B",
    prompt="The capital of France is",
    max_tokens=20,
)
print(completion.choices[0].text)
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает следующее.

```shell
 Paris, and the capital of the United States is Washington, D.C.
```

Также поддерживается потоковая передача.

```python
stream = client.completions.create(
    model="Qwen/Qwen2.5-0.5B",
    prompt="The capital of France is",
    max_tokens=20,
    stream=True,
)
for chunk in stream:
    print(chunk.choices[0].text, end="")
```

## v1/responses

[Responses API](https://platform.openai.com/docs/api-reference/responses) — это новейший API-эндпоинт OpenAI для генерации. Он поддерживает взаимодействия с состоянием и интегрирует встроенные инструменты для расширения возможностей модели. OpenAI [рекомендует](https://platform.openai.com/docs/guides/migrate-to-responses) использовать Responses API вместо Chat Completions API для новых проектов.

API `v1/responses` поддерживает запросы с текстом, изображениями, аудио и видео через команду `curl` и клиент [OpenAI](https://platform.openai.com/docs/quickstart).

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

```python
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](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

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

```python
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=True,
)

for event in response:
    if hasattr(event, "delta") and event.delta:
        print(event.delta, end="")
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

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

```shell
curl http://localhost:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-0.5B-Instruct",
    "input": "Tell me a three sentence bedtime story about a unicorn.",
    "max_output_tokens": 256,
    "stream": false
  }'
```

Команда возвращает строку в формате JSON.

```json
{
  "id": "resp_8693af9b-b561-4267-bd1a-22d1b43284cb",
  "created_at": 1776258580.7114341,
  "model": "Qwen/Qwen2.5-0.5B-Instruct@main",
  "object": "response",
  "output": [
    {
      "id": "msg_8693af9b-b561-4267-bd1a-22d1b43284cb",
      "content": [
        {
          "annotations": [],
          "text": "Once upon a time, in a faraway land, there lived a beautiful unicorn named Luna [...]",
          "type": "output_text"
        }
      ],
      "role": "assistant",
      "status": "completed",
      "type": "message"
    }
  ],
  "status": "completed"
}
```

```shell
curl http://localhost:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-0.5B-Instruct",
    "stream": true,
    "input": "Tell me a three sentence bedtime story about a unicorn.",
    "max_output_tokens": 256
  }'
```

Команда возвращает поток фрагментов.

```shell
data: {"response":{"id":"resp_req_0","created_at":1754059817.783648,"model":"Qwen/Qwen2.5-0.5B-Instruct@main","object":"response","output":[],"status":"queued"},"sequence_number":0,"type":"response.created"}

data: {"content_index":0,"delta":"Once ","item_id":"msg_req_0","output_index":0,"sequence_number":5,"type":"response.output_text.delta"}

data: {"content_index":0,"delta":"upon ","item_id":"msg_req_0","output_index":0,"sequence_number":6,"type":"response.output_text.delta"}

(...)
```

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

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

```python
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](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```xmp
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.
```

```python
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=True,
)

for event in response:
    if hasattr(event, "delta") and event.delta:
        print(event.delta, end="")
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```xmp
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.
```

```shell
curl http://localhost:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d '{
    "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
  }'
```

Команда возвращает строку в формате JSON.

```json
{
  "id": "resp_f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "created_at": 1776258580.7114341,
  "model": "Qwen/Qwen2.5-VL-7B-Instruct@main",
  "object": "response",
  "output": [
    {
      "id": "msg_f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "content": [
        {
          "annotations": [],
          "text": "The image depicts an astronaut in a space suit standing on what appears to be the surface of the moon [...]",
          "type": "output_text"
        }
      ],
      "role": "assistant",
      "status": "completed",
      "type": "message"
    }
  ],
  "status": "completed"
}
```

```shell
curl http://localhost:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-VL-7B-Instruct",
    "stream": true,
    "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
  }'
```

Команда возвращает поток фрагментов.

```shell
data: {"response":{"id":"resp_f47ac10b-58cc-4372-a567-0e02b2c3d479","created_at":1776258580.7114341,"model":"Qwen/Qwen2.5-VL-7B-Instruct@main","object":"response","output":[],"status":"queued"},"sequence_number":0,"type":"response.created"}

data: {"content_index":0,"delta":"The ","item_id":"msg_f47ac10b","output_index":0,"sequence_number":5,"type":"response.output_text.delta"}

(...)
```

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

```python
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](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```
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.
```

```python
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=True,
)

for event in response:
    if hasattr(event, "delta") and event.delta:
        print(event.delta, end="")
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```
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.
```

```shell
# First, base64-encode the audio file and build the JSON payload
AUDIO_B64=$(curl -sL https://huggingface.co/datasets/hf-internal-testing/dummy-audio-samples/resolve/main/obama_first_45_secs.mp3 | base64 -w 0)

cat <<EOF > /tmp/audio_request.json
{
  "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
}
EOF

curl http://localhost:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d @/tmp/audio_request.json
```

Команда возвращает строку в формате JSON.

```json
{
  "id": "resp_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "created_at": 1776258580.7114341,
  "model": "google/gemma-4-E2B-it@main",
  "object": "response",
  "output": [
    {
      "id": "msg_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "content": [
        {
          "annotations": [],
          "text": "This week, I traveled to Chicago to deliver my final farewell address to the nation [...]",
          "type": "output_text"
        }
      ],
      "role": "assistant",
      "status": "completed",
      "type": "message"
    }
  ],
  "status": "completed"
}
```

```shell
# First, base64-encode the audio file and build the JSON payload
AUDIO_B64=$(curl -sL https://huggingface.co/datasets/hf-internal-testing/dummy-audio-samples/resolve/main/obama_first_45_secs.mp3 | base64 -w 0)

cat <<EOF > /tmp/audio_request.json
{
  "model": "google/gemma-4-E2B-it",
  "stream": true,
  "input": [
    {"type": "input_text", "text": "Transcribe this audio."},
    {"type": "input_audio", "input_audio": {"data": "$AUDIO_B64", "format": "mp3"}}
  ],
  "max_output_tokens": 256
}
EOF

curl http://localhost:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d @/tmp/audio_request.json
```

Команда возвращает поток фрагментов.

```shell
data: {"response":{"id":"resp_a1b2c3d4-e5f6-7890-abcd-ef1234567890","created_at":1776258580.7114341,"model":"google/gemma-4-E2B-it@main","object":"response","output":[],"status":"queued"},"sequence_number":0,"type":"response.created"}

data: {"content_index":0,"delta":"This ","item_id":"msg_a1b2c3d4","output_index":0,"sequence_number":5,"type":"response.output_text.delta"}

(...)
```

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

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

```python
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,
)
```

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

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

> [!TIP]
> Для обработки видео требуется [torchcodec](https://github.com/pytorch/torchcodec). Установите его с помощью `pip install torchcodec`.

```python
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](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```
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..."
```

```python
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=True,
)

for event in response:
    if hasattr(event, "delta") and event.delta:
        print(event.delta, end="")
```

Клиент [OpenAI](https://platform.openai.com/docs/quickstart) возвращает напечатанную строку.

```
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..."
```

```shell
curl http://localhost:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d '{
    "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
  }'
```

Команда возвращает строку в формате JSON.

```json
{
  "id": "resp_b2c3d4e5-f6a7-8901-bcde-f12345678901",
  "created_at": 1776258580.7114341,
  "model": "google/gemma-4-E2B-it@main",
  "object": "response",
  "output": [
    {
      "id": "msg_b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "content": [
        {
          "annotations": [],
          "text": "The video captures a live music performance at a music festival or a large concert [...]",
          "type": "output_text"
        }
      ],
      "role": "assistant",
      "status": "completed",
      "type": "message"
    }
  ],
  "status": "completed"
}
```

```shell
curl http://localhost:8000/v1/responses \
  -H "Content-Type: application/json" \
  -d '{
    "model": "google/gemma-4-E2B-it",
    "stream": true,
    "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
  }'
```

Команда возвращает поток фрагментов.

```shell
data: {"response":{"id":"resp_b2c3d4e5-f6a7-8901-bcde-f12345678901","created_at":1776258580.7114341,"model":"google/gemma-4-E2B-it@main","object":"response","output":[],"status":"queued"},"sequence_number":0,"type":"response.created"}

data: {"content_index":0,"delta":"Based ","item_id":"msg_b2c3d4e5","output_index":0,"sequence_number":5,"type":"response.output_text.delta"}

(...)
```

### Многоразовые диалоги[[responses]]

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

```python
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](https://api.typesafe.ai/openapi.json). Используйте его для принятия решений, например, маршрутизации тикета поддержки, оценки срочности или выбора действия.

Запросы обрабатываются [DecisionPipeline](/docs/transformers/v5.23.0/ru/main_classes/pipelines#transformers.DecisionPipeline) вокруг обслуживаемой модели, поэтому конечная точка и конвейер формируют одинаковые промпты и возвращают одинаковые ответы. Модель оценивает допустимые ответы без генерации текста, выполняя один прямой проход на каждый промпт. Эта конечная точка поддерживает авторегрессионные модели с шаблоном чата;

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

```shell
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?"}
    }
  }'
```

Установите [TypeSafe SDK](https://github.com/typesafe-ai/typesafe-sdk-js) для Node.js 20 или более новой версии:

```shell
npm install @typesafe-ai/sdk
```

Укажите в `baseURL` корень сервера; SDK добавляет `/v1/systemone`. SDK требует API-ключ, но для локального сервера подойдёт заглушка.

```typescript
import { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk";

const client = new TypeSafeClient({
  baseURL: "http://localhost:8000",
  apiKey: "<random_string>",
});

const response = await client.systemOne({
  model: "Qwen/Qwen2.5-1.5B-Instruct",
  state: "Our integration has been failing for 3 days and we are losing sales!",
  questions: {
    team: choice("Which team handles this?", {
      billing: null,
      technical: "Bugs or integration problems",
    }),
    urgency: score("How urgent is this ticket?", ["low", "medium", "high"]),
    upset: noul("Is the customer upset?"),
  },
});

console.log(response.answers.team.choice);
console.log(response.answers.urgency.score);
console.log(response.answers.upset.noul);
```

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

```shell
technical
1.6739138662815094
0.851952850818634
```

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

```json
{
  "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 вопросов, при этом на каждый вопрос должно быть как минимум одно значение варианта ответа или уровня оценки и не более одного на метку ответа (26 при метках по умолчанию `A`–`Z`).

Вопросы валидируются так же, как и в [DecisionPipeline](/docs/transformers/v5.23.0/ru/main_classes/pipelines#transformers.DecisionPipeline), до загрузки модели. Недействительный запрос возвращает `422`, в сообщении которого перечислены все недействительные вопросы, для каждого приведён пример корректного, а для опечаток в типах и полях предложены ближайшие совпадения:

```text
Question 'team': expected a `type` among noul, choice, score, got type 'Choice'. Did you mean 'choice'?
Question 'upset': unknown field 'instruction'. Did you mean 'instructions'? A noul question looks like {"type": "noul", ...}
```

Для моделей с поддержкой изображений добавьте `assets`, как в System One API: до четырёх изображений, привязанных к плейсхолдерам на ваш выбор (надёжнее всего использовать UUID). В любом месте строки `state`, `instructions` или `criteria`, где встречается плейсхолдер, модель видит изображение именно там. Формат ассета — `{"type": "image", "format": "png", "data_base64": "..."}`; удалённые URL изображений не поддерживаются. Модели необходим процессор, обрабатывающий изображения.

```json
{
  "model": "Qwen/Qwen2.5-VL-3B-Instruct",
  "state": "The customer sent 6f1c0e2a and asks if it is damaged.",
  "assets": {"6f1c0e2a": {"type": "image", "format": "png", "data_base64": "iVBORw0..."}},
  "questions": {"damaged": {"type": "noul", "instructions": "Is the product in the photo damaged?"}}
}
```

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

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

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

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

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

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

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

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

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

Пользовательский шаблон, в данном случае для Gemma 3, формирует весь промпт и `<|mark|>`, где считывается ответ. Строки с изображениями поступают в виде списков текстовых и графических элементов:

```jinja
{%- macro text(x) -%}
{%- if x is string or x is none %}{{ x or "" }}{% elif x is mapping %}{{ x|tojson }}{% else -%}
{%- for part in x %}{% if part.type == "image" %}<start_of_image>{% else %}{{ part.text }}{% endif %}{% endfor -%}
{%- endif -%}
{%- endmacro -%}
<start_of_turn>user
{{ text(state) }}

{{ text(question.instructions) }}
{% for option in question.options %}{{ question.labels[loop.index0] }}. {{ option }}: {{ text(question.descriptions[loop.index0]) }}
{% endfor %}<end_of_turn>
<start_of_turn>model
<|mark|>
```

Вставьте его как `chat_template` в файл `--decision-config` или добавьте файл `decision_template.jinja` рядом с `decision.json` в репозитории модели.

## v1/audio/transcriptions

Эндпоинт `v1/audio/transcriptions` выполняет транскрибацию аудио с помощью моделей speech-to-text. Он соответствует формату [API транскрибации аудио](https://platform.openai.com/docs/api-reference/audio/createTranscription).

```shell
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"
```

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

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

## v1/models

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

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

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

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

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

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

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

Эндпоинт `/load_model` предварительно загружает модель и транслирует прогресс через [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) (SSE). CLI `transformers chat` использует его автоматически, чтобы пользователи видели прогресс загрузки и инициализации, а не зависший промпт. Используйте его для предварительной загрузки модели перед отправкой запросов на инференс.

### Запрос

```shell
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` |
| `stage` | `status == "loading"` | Один из `processor`, `config`, `download`, `weights` (см. этапы ниже) |
| `progress` | стадии `download` и `weights` | Объект с `current` и `total` (целое число или null) |
| `cached` | `status == "ready"` | `true`, если модель уже находилась в памяти |
| `message` | `status == "error"` | Описание ошибки |

### Этапы

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

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

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

## Тайм-аут

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

```shell
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}
```

```
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": "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}
```

```
data: {"status": "ready", "model": "org/model@main", "cached": true}
```

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

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

> [!NOTE]
> Функция вызова инструментов работает с любой моделью, токенизатор которой объявляет токены вызова инструментов. Qwen и Gemma 4 поддерживаются из коробки. Откройте [issue](https://github.com/huggingface/transformers/issues/new/choose), чтобы запросить поддержку конкретной модели.

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

```py
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](/docs/transformers/v5.23.0/ru/main_classes/text_generation#transformers.GenerationConfig) в аргумент `extra_body` в [create](https://platform.openai.com/docs/api-reference/responses/create).

```py
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](https://developers.openai.com/api/docs/guides/function-calling?api-mode=chat).

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

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

```py
# 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)
```

Передайте результат инструмента как элемент `function_call_output` в списке `input` последующего запроса.

```py
user_message = {"role": "user", "content": "What's the weather like in San Francisco?"}
response = client.responses.create(
    model="Qwen/Qwen2.5-7B-Instruct",
    input=[user_message],
    tools=tools,
    stream=False,
)
tool_call = next(item for item in response.output if item.type == "function_call")

result = {"temperature": 22, "condition": "sunny"}

final_response = client.responses.create(
    model="Qwen/Qwen2.5-7B-Instruct",
    input=[
        user_message,
        tool_call.model_dump(exclude_none=True),
        {"type": "function_call_output", "call_id": tool_call.call_id, "output": json.dumps(result)},
    ],
    tools=tools,
    stream=False,
)
print(final_response.output_text)
```

## Рассуждения

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

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

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

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

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

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

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

| Значение | Поведение |
|---|---|
| `auto` (по умолчанию) | Используйте значение по умолчанию из шаблона чата. |
| `on` | Чтобы принудительно включить режим размышлений, установите `enable_thinking=True` в аргументах шаблона чата. |
| `off` | Отключите режим размышлений, установив `enable_thinking=False`. |

```sh
transformers serve Qwen/Qwen3-1.7B --reasoning on
```

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

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

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

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

### Chat Completions

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

```python
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)
```

При потоковой передаче дельты `reasoning_content` выводятся до дельт `content`. Каждое поле нужно конкатенировать отдельно.

```python
chunks = list(
    client.chat.completions.create(
        model="Qwen/Qwen3-1.7B",
        messages=[{"role": "user", "content": "What is 17 * 23?"}],
        stream=True,
    )
)
reasoning = "".join(getattr(c.choices[0].delta, "reasoning_content", None) or "" for c in chunks)
content = "".join(c.choices[0].delta.content or "" for c in chunks)
```

```shell
curl -X POST http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen3-1.7B",
    "messages": [{"role": "user", "content": "What is 17 * 23?"}],
    "chat_template_kwargs": {"enable_thinking": true}
  }'
```

Ответ содержит `reasoning_content` в сообщении ассистента.

```json
{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "17 * 23 = 391.",
        "reasoning_content": "Let me compute 17 * 23. 17 * 20 = 340, 17 * 3 = 51, so 340 + 51 = 391."
      },
      "finish_reason": "stop",
      "index": 0
    }
  ]
}
```

### Responses API

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

```python
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)
```

При потоковой передаче сначала открывается элемент рассуждения и излучаются события `response.reasoning_text.delta`, затем он закрывается, открывается элемент сообщения и излучаются события `response.output_text.delta`.

```python
stream = client.responses.create(
    model="Qwen/Qwen3-1.7B",
    input="What is 17 * 23?",
    stream=True,
)

for event in stream:
    if event.type == "response.reasoning_text.delta":
        print(event.delta, end="")
    elif event.type == "response.output_text.delta":
        print(event.delta, end="")
```

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

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

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

```python
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)
```

Передайте предыдущий элемент `reasoning` обратно в качестве входного элемента перед сообщением ассистента.

```python
first = client.responses.create(
    model="Qwen/Qwen3-1.7B",
    input="What is 17 * 23?",
    stream=False,
)
reasoning_item = next(i for i in first.output if i.type == "reasoning")
message_item = next(i for i in first.output if i.type == "message")

second = client.responses.create(
    model="Qwen/Qwen3-1.7B",
    input=[
        {"role": "user", "content": "What is 17 * 23?"},
        reasoning_item.model_dump(exclude_none=True),
        {"role": "assistant", "content": message_item.content[0].text},
        {"role": "user", "content": "Now multiply that result by 2."},
    ],
    stream=False,
)
print(second.output_text)
```

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

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

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

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

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

```sh
transformers serve Qwen/Qwen2.5-0.5B-Instruct \
  --continuous-batching \
  --dtype "bfloat16"
```

