Transformers documentation
CLI Serve
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.
Текстовые дополнения
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 [...]
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 возвращает напечатанную строку.
The Transformers library is primarily known for its ability to create and manipulate large-scale language models [...]
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 возвращает напечатанную строку.
The Transformers library is primarily known for its ability to create and manipulate large-scale language models [...]
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 возвращает напечатанную строку.
The Transformers library is primarily known for its ability to create and manipulate large-scale language models [...]
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.
{
"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
}
}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
}'Команда возвращает поток фрагментов.
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":""}
(...)Завершения на основе изображений
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.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 возвращает напечатанную строку.
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.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 возвращает напечатанную строку.
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.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 возвращает напечатанную строку.
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.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.
{
"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
}
}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
}'Команда возвращает поток фрагментов.
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 и Qwen2.5-Omni, принимают аудиовход через тип содержимого input_audio в OpenAI. Закодируйте аудио в Base64 и укажите формат (mp3 или wav).
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.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 возвращает напечатанную строку.
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.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 возвращает напечатанную строку.
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.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 возвращает напечатанную строку.
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.# 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.
{
"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
}
}# 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Команда возвращает поток фрагментов.
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":""}
(...)Тип содержимого
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.
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..."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 возвращает напечатанную строку.
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..."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 возвращает напечатанную строку.
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..."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 возвращает напечатанную строку.
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..."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.
{
"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
}
}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
}'Команда возвращает поток фрагментов.
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":""}
(...)Многоразовые диалоги
Чтобы вести многоходовый диалог, включайте полную историю разговора в список 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 -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
}
}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 возвращает следующее.
Paris, and the capital of the United States is Washington, D.C.
Также поддерживается потоковая передача.
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 — это новейший API-эндпоинт OpenAI для генерации. Он поддерживает взаимодействия с состоянием и интегрирует встроенные инструменты для расширения возможностей модели. OpenAI рекомендует использовать Responses API вместо Chat Completions API в новых проектах.
API v1/responses поддерживает запросы с текстом, изображениями, аудио и видео через команду curl и клиент OpenAI.
Текстовые ответы
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 [...]
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 возвращает напечатанную строку.
Once upon a time, in a faraway land, there lived a beautiful unicorn named Luna [...]
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.
{
"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"
}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
}'Команда возвращает поток фрагментов.
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 также поддерживает входные данные в формате изображений, аудио и видео.
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.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 возвращает напечатанную строку.
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.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.
{
"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"
}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
}'Команда возвращает поток фрагментов.
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"}
(...)Ответы на основе аудио
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.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 возвращает напечатанную строку.
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.# 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.
{
"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"
}# 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Команда возвращает поток фрагментов.
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"}
(...)Тип содержимого
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.
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..."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 возвращает напечатанную строку.
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..."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.
{
"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"
}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
}'Команда возвращает поток фрагментов.
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"}
(...)Многоразовые диалоги
Для многоходовых диалогов передавайте список сообщений с ключами 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 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 для Node.js 20 или более новой версии:
npm install @typesafe-ai/sdk
Укажите в baseURL корень сервера; SDK добавляет /v1/systemone. SDK требует API-ключ, но для локального сервера подойдёт заглушка.
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);Клиент выводит выбранную команду, оценку срочности и вероятность того, что клиент недоволен. Например:
technical 1.6739138662815094 0.851952850818634
Ответы используют те же имена вопросов. Например:
{
"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 |
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, чтобы отключить выгрузку.
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. Модели, обученные для использования инструментов, генерируют структурированные вызовы функций, которые выполняет ваше приложение.
Функция вызова инструментов работает с любой моделью, токенизатор которой объявляет токены вызова инструментов. 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, определённый выше.
Передайте результат инструмента как сообщение с 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)Передайте результат инструмента как элемент function_call_output в списке input последующего запроса.
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.
Обнаружение рассуждений опирается на шаблон ответа, который указывает серверу, где начинается и заканчивается блок размышлений. Сервер ищет его в двух местах, в указанном порядке.
- Атрибут
response_templateтокенизатора, если модель поставляется с ним. - Встроенный вариант по умолчанию, соответствующий архитектуре модели, для токенизаторов, у которых пока нет шаблона.
Модели, не имеющие ни того, ни другого, обслуживаются без разбора ответа. Сырой декодированный текст возвращается как 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 в сообщении ассистента.
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. Каждое поле нужно конкатенировать отдельно.
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)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 в сообщении ассистента.
{
"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.
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.
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 к предыдущему сообщению ассистента.
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 обратно в качестве входного элемента перед сообщением ассистента.
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, затем выполните эту команду на локальной машине.
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"