Transformers documentation

Serve CLI

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

and get access to the augmented documentation experience

to get started

Serve CLI

La CLI transformers serve est une option légère pour les serveurs locaux ou auto-hébergés. Elle évite les surcoûts d’exécution et d’exploitation supplémentaires des moteurs d’inférence dédiés comme vLLM. Utilisez-la pour l’évaluation, l’expérimentation et les déploiements à charge modérée. Des fonctionnalités comme le continuous batching augmentent le débit et réduisent la latence.

Pour les déploiements de production à grande échelle, utilisez vLLM ou SGLang avec un modèle Transformer en tant que backend. En savoir plus dans le guide Backends d'inférence.

La commande transformers serve démarre un serveur local compatible avec le OpenAI SDK. Ce serveur fonctionne avec de nombreuses applications tierces et prend en charge les API REST suivantes.

  • /v1/chat/completions pour les requêtes texte, image, audio et vidéo
  • /v1/completions pour les complétions de texte héritées à partir d'un prompt libre
  • /v1/responses prend en charge la Responses API
  • /v1/audio/transcriptions pour les transcriptions audio
  • /v1/systemone répond aux questions à choix multiples, de notation ou de type oui/non, en fournissant une probabilité pour chaque réponse autorisée
  • /v1/models répertorie les modèles disponibles pour les intégrations tierces
  • /load_model transmet la progression du chargement du modèle via SSE

Installez les dépendances de service.

pip install transformers[serving]

Lancez un serveur en exécutant transformers serve. L'adresse du serveur par défaut est http://localhost:8000.

transformers serve

v1/chat/completions

L’API v1/chat/completions est basée sur l’API Chat Completions. Elle prend en charge les requêtes texte, image, audio et vidéo pour les LLM, les VLM et les modèles multimodaux. Utilisez-la avec curl, le InferenceClient ou le client OpenAI.

Complétions basées sur le texte

huggingface_hub
huggingface_hub (flux)
openai
openai (stream)
curl
curl (flux)
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 renvoie une chaîne imprimée.

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

Complétions basées sur des images

huggingface_hub
huggingface_hub (flux)
openai
openai (stream)
curl
curl (flux)
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 renvoie une chaîne imprimée.

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.

Complétions basées sur l'audio

Les modèles multimodaux comme Gemma 4 et Qwen2.5-Omni acceptent l'entrée audio via le type de contenu input_audio d'OpenAI. Encodagez l'audio en Base64 et spécifiez le format (mp3 ou wav).

huggingface_hub
huggingface_hub (flux)
openai
openai (stream)
curl
curl (flux)
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 renvoie une chaîne imprimée.

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.

Le type de contenu audio_url est une extension qui ne fait pas partie de la norme OpenAI et peut évoluer dans les versions futures.

Vous pouvez également passer l’audio par URL avec le type de contenu audio_url pour éviter l’encodage 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"}},
            ],
        }
    ],
)

Complétions basées sur la vidéo

Le type de contenu video_url est une extension qui ne fait pas partie de la norme OpenAI et peut évoluer dans les versions futures.

Utilisez le type de contenu video_url pour l’entrée vidéo. Si le modèle prend en charge l’audio (par ex. Gemma 4, Qwen2.5-Omni), le serveur extrait la piste audio de la vidéo et la traite avec les images visuelles.

Le traitement vidéo nécessite torchcodec. Installez-le avec pip install torchcodec.

huggingface_hub
huggingface_hub (flux)
openai
openai (stream)
curl
curl (flux)
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 renvoie une chaîne imprimée.

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

Conversations multi-tours

Pour mener une conversation multi-tours, incluez l’historique complet de la conversation dans la liste messages en alternant les rôles user et assistant. Comme tous les serveurs compatibles OpenAI, l’API est sans état : chaque requête doit donc contenir l’historique complet de la conversation.

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)

La question de suivi « Combien de personnes y vivent ? » s’appuie sur le contexte précédent, de sorte que le modèle répond en parlant de Paris.

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

v1/completions

L’API v1/completions est basée sur l’API Completions legacy. Contrairement à /v1/chat/completions, elle prend en entrée un prompt de texte libre plutôt que des messages de chat, et renvoie le texte généré dans choices[].text. Elle est utile pour les modèles de base (non instruct) et les tâches de complétion de texte où un gabarit de chat n’est pas nécessaire. Elle prend également en charge suffix pour l’insertion de texte en milieu de séquence (fill-in-the-middle).

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

La commande renvoie la réponse suivante.

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

v1/responses

L'Responses API est le dernier point d'accès API d'OpenAI pour la génération. Il prend en charge les interactions avec état et intègre des outils intégrés pour étendre les capacités d'un modèle. OpenAI recommande d'utiliser la Responses API plutôt que la Chat Completions API pour les nouveaux projets.

L’API v1/responses prend en charge les requêtes texte, image, audio et vidéo via la commande curl et le client OpenAI.

Réponses basées sur le texte

openai
openai (stream)
curl
curl (flux)
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)

Le client OpenAI renvoie une chaîne imprimée.

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

Réponses basées sur des images

L'API Responses prend également en charge les entrées image, audio et vidéo.

openai
openai (stream)
curl
curl (flux)
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)

Le client OpenAI renvoie une chaîne imprimée.

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.

Réponses basées sur l'audio

openai
openai (stream)
curl
curl (flux)
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)

Le client OpenAI renvoie une chaîne imprimée.

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.

Le type de contenu audio_url est une extension qui ne fait pas partie de la norme OpenAI et peut évoluer dans les versions futures.

Vous pouvez également passer l’audio par URL avec le type de contenu audio_url pour éviter l’encodage 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,
)

Réponses basées sur la vidéo

Le type de contenu video_url est une extension qui ne fait pas partie de la norme OpenAI et peut évoluer dans les versions futures.

Le traitement vidéo nécessite torchcodec. Installez-le avec pip install torchcodec.

openai
openai (stream)
curl
curl (flux)
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)

Le client OpenAI renvoie une chaîne imprimée.

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

Conversations multi-tours

Pour les conversations multi-tours, passez une liste de messages avec des clés role dans le champ input. Comme tous les serveurs compatibles OpenAI, l’API est sans état, chaque requête doit donc contenir l’historique complet de la conversation.

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)

La question de suivi « Combien de personnes y vivent ? » s’appuie sur le contexte précédent, de sorte que le modèle répond en parlant de Paris.

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

v1/systemone

Le point d'accès v1/systemone répond à des questions typées concernant un state partagé, conformément à l'API System One de TypeSafe. Utilisez-le pour des décisions telles que l'aiguillage d'un ticket de support, l'évaluation de l'urgence ou le choix d'une action.

Le modèle évalue les réponses autorisées en un seul passage avant groupé, sans générer de texte. Ce point de terminaison prend en charge les modèles autorégressifs dotés d'un modèle de discussion ;

Envoyer un modèle, l'état à évaluer et des questions indexées par nom :

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

Les réponses utilisent les mêmes noms de questions. Par exemple :

{
  "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}
}
Type de questioncriteriaRéponse
choiceNoms des options mappés sur des descriptions, qui peuvent être null.L'option la plus probable, les probabilités des options et la confiance.
scoreDescriptions des niveaux, classées du plus bas au plus élevé.L'indice de niveau pondéré par la probabilité, les probabilités, une légende et la confiance.
noulDescriptions facultatives pour true et false.La probabilité de true.

state, des instructions facultatives, et les descriptions peuvent contenir du texte ou des objets et tableaux JSON. Chaque requête accepte jusqu'à 64 questions, avec 1 à 26 choix ou niveaux de score par question.

For vision-capable models, add an images array with up to four data:image/...;base64,... URLs. Every question receives the same images. The model’s processor and chat template must support images; remote image URLs are not accepted.

Configuration de la décision

Les modèles de décision ne partagent pas encore de standard pour le stockage des prompts, des étiquettes de réponse et des paramètres de calibration. Ces éléments varient d'une implémentation de modèle à l'autre, c'est pourquoi --decision-config vous permet de les fournir explicitement. Les modèles dotés de têtes de décision personnalisées nécessitent toujours une implémentation compatible ; ce fichier ne configure que le formatage des prompts et le score du jeton suivant.

Par défaut, les questions utilisent un prompt de secours et le modèle de chat du modèle avec la réflexion désactivée. Les étiquettes de réponse sont A–Z pour les choix et les scores, et Yes/No pour les booléens. Les probabilités sont le softmax sur ces étiquettes à une température de 1.

Passer --decision-config pour remplacer ces valeurs par défaut pour un modèle :

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

Le fichier JSON prend en charge trois champs facultatifs :

ChampSignification
labelsÉtiquettes de réponse par type de question, dans l'ordre des options (true, puis false pour noul). Chacune doit être un jeton unique et connu.
temperatureTempératures positives par type de question, appliquées sous la forme softmax(label_logits / temperature).
chat_templateUn modèle Jinja en ligne qui remplace le prompt complet, y compris le formatage de la conversation et le préfixe de l'assistant.

Par exemple, pour modifier les étiquettes et l'étalonnage tout en conservant le prompt par défaut :

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

Un modèle personnalisé reçoit les messages habituels, ainsi que les champs bruts state, images et question. Le champ question expose name, type, instructions, options, labels, descriptions et legend ; options, labels et descriptions partagent le même ordre. Utilisez ces champs pour remplacer la formulation par défaut, et tojson pour afficher les valeurs structurées. Les modèles destinés aux entrées d’image doivent inclure les espaces réservés d’image du modèle.

Le fichier est chargé au démarrage et ne s’applique qu’à /v1/systemone. Les paramètres omis conservent leurs valeurs par défaut ; aucune configuration de décision n’est lue automatiquement depuis le point de contrôle.

v1/audio/transcriptions

Le point de terminaison v1/audio/transcriptions transcrit l’audio à l’aide de modèles de conversion de la parole en texte. Il suit le format de l’API de transcription audio.

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"

La commande renvoie la réponse suivante.

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

v1/models

L'endpoint v1/models analyse votre cache local Hugging Face et renvoie une liste des modèles téléchargés au format compatible OpenAI. Les outils tiers utilisent cet endpoint pour découvrir les modèles disponibles.

Téléchargez un modèle avant d’exécuter transformers serve.

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

Une fois téléchargé, le modèle apparaît dans les réponses de /v1/models.

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

L'endpoint renvoie un objet JSON contenant les modèles disponibles.

Chargement des modèles

Le point de terminaison /load_model précharge un modèle et transmet la progression via Server-Sent Events (SSE). L'interface en ligne de commande transformers chat l'utilise automatiquement afin que les utilisateurs voient la progression du téléchargement et du chargement plutôt qu'un inviteur qui reste bloqué. Utilisez-le pour préchauffer un modèle avant d'envoyer des requêtes d'inférence.

Demande

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

Le champ model est un identifiant de modèle Hugging Face, facultativement suivi d'un suffixe @revision (Qwen/Qwen2.5-0.5B-Instruct@main). Si la révision est omise, la valeur par défaut est main.

Réponse

La réponse est un flux SSE (Content-Type: text/event-stream). Chaque trame est un objet JSON sur une ligne data:.

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

Chaque événement contient au minimum un champ status et un champ model. Les champs supplémentaires dépendent du statut.

ChampPrésent lorsqueDescription
statusToujoursloading, ready ou error
modelToujoursIdentifiant de modèle canonique model_id@revision
stagestatus == "loading"L'un des éléments suivants : processor, config, download, weights (voir les étapes ci-dessous)
progressétapes download et weightsObjet avec current et total (entier ou null)
cachedstatus == "ready"true si le modèle était déjà en mémoire
messagestatus == "error"Description de l'erreur

Stages

Le chargement progresse à travers ces étapes dans l'ordre. Certaines peuvent être ignorées (download est ignoré lorsque les fichiers sont déjà en cache localement).

StageDes progrès ?Description
processorNonChargement du tokenizer/processor
configNonChargement de la configuration du modèle
downloadOui (octets)Téléchargement des fichiers de modèle
weightsOui (éléments)Chargement des tenseurs de poids en mémoire

Le flux se termine par exactement un événement terminal, ready (succès) ou error (échec).

Délai d'attente

transformers serve gère les requêtes pour n’importe quel modèle. Chaque modèle est chargé à la demande et reste en mémoire GPU. Les modèles sont déchargés automatiquement après 300 secondes d’inactivité afin de libérer la mémoire GPU. Définissez --model-timeout sur une autre valeur en secondes, ou sur -1 pour désactiver le déchargement.

transformers serve --model-timeout 400

Chargement des exemples

Les exemples ci-dessous montrent les réponses pour un modèle fraîchement téléchargé, un modèle chargé depuis votre cache local (qui saute l'étape de téléchargement) et un modèle déjà en mémoire.

chargement complet
fichiers en cache
en mémoire
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}

Appel d'outils

Le serveur transformers serve prend en charge l'appel de fonctions au format OpenAI. Les modèles entraînés pour l'utilisation d'outils génèrent des appels de fonctions structurés que votre application exécute.

L'appel d'outils fonctionne avec tout modèle dont le tokenizer déclare des jetons d'appel d'outils. Qwen et Gemma 4 fonctionnent sans configuration supplémentaire. Ouvrez un issue pour demander la prise en charge d'un modèle spécifique.

Définissez les outils sous forme de liste de spécifications de fonctions suivant le format 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"]
      }
    }
  }
]

Personnalisez la génération en passant les paramètres de GenerationConfig à l'argument extra_body dans 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)

Appel d'outils multi-tours

Une fois que le modèle renvoie un appel d’outil, exécutez la fonction localement, puis renvoyez le résultat dans une requête de suivi pour obtenir la réponse finale du modèle. Le schéma varie légèrement d’une API à l’autre. Consultez le guide d’appel de fonctions OpenAI pour la spécification complète.

Les exemples ci-dessous réutilisent la liste tools définie ci-dessus.

v1/chat/completions
v1/responses

Transmettez le résultat de l'outil en tant que message role: "tool" avec l'tool_call_id correspondant.

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

Raisonnement

Les modèles de raisonnement émettent une chaîne de pensée cachée avant la réponse finale. Le serveur détecte ces segments de réflexion, supprime les délimiteurs de la réponse visible et expose le texte de raisonnement dans un champ dédié afin que les clients puissent l’afficher séparément.

  • Chat Completions renvoie le raisonnement sous la forme de reasoning_content sur le message de l'assistant.
  • L’API Responses renvoie le raisonnement sous forme d’un élément de sortie reasoning qui précède l’élément message.

La détection du raisonnement repose sur un modèle de réponse, qui indique au serveur où commence et où se termine un segment de réflexion. Le serveur recherche ce modèle dans deux endroits, dans l'ordre.

  1. L'attribut response_template du tokenizer, si le modèle en fournit un.
  2. Un repli intégré, sélectionné en fonction de l’architecture du modèle, pour les tokenizers qui ne fournissent pas encore de modèle.

Les modèles qui ne disposent d’aucun des deux sont servis sans analyse de la réponse. Le texte brut décodé est renvoyé en tant que content et aucun champ de raisonnement n’est exposé, même si le modèle émet des balises <think>...</think>.

Activer le raisonnement sur le serveur

Utilisez --reasoning pour contrôler si le modèle de conversation émet des jetons de raisonnement.

ValeurComportement
auto (par défaut)Se fier à la valeur par défaut du modèle de chat.
onActivez la réflexion en définissant enable_thinking=True dans les arguments du modèle de discussion.
offDésactivez la réflexion en définissant enable_thinking=False.
transformers serve Qwen/Qwen3-1.7B --reasoning on

Tous les modèles ne prennent pas en charge le raisonnement. --reasoning ne fonctionne que lorsque le modèle de chat du modèle gère la variable enable_thinking (ou lorsque son tokenizer déclare des délimiteurs de réflexion). Pour les autres modèles, l’indicateur est ignoré silencieusement.

--reasoning on et --reasoning off fonctionnent en définissant la variable de gabarit de discussion enable_thinking. Certains gabarits de discussion utilisent un nom de variable différent pour activer la réflexion, ou acceptent des variables supplémentaires qui modifient la façon dont le prompt est rendu. Transmettez toute variable de gabarit de discussion directement avec --chat-template-kwargs sous forme d'objet JSON.

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

Les clients peuvent également envoyer chat_template_kwargs dans le corps de la requête pour remplacer les valeurs par défaut du serveur pour une seule requête, sans redémarrer le serveur.

Chat Completions

Les réponses non en streaming incluent reasoning_content en plus de content sur le message de l'assistant.

openai
openai (stream)
curl
from openai import OpenAI

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

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

API des réponses

L’API Responses renvoie le raisonnement en tant qu’élément de sortie reasoning distinct, qui précède l’élément message.

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

Aller-retour multi-tours

Pour les conversations multi-tours, incluez le texte de raisonnement de la réponse précédente dans la requête suivante. Le serveur le transmet au modèle de chat, qui peut l’afficher comme faisant partie du tour précédent de l’assistant, afin que le modèle voie son propre processus de réflexion antérieur.

v1/chat/completions
v1/responses

Joindre reasoning_content au message assistant précédent.

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)

Redirection de port

Le transfert de port vous permet de servir des modèles depuis un serveur distant. Assurez-vous d'avoir un accès SSH au serveur, puis exécutez cette commande sur votre machine locale.

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

Reproductibilité

Transmettez un modèle en tant qu'argument positionnel afin d'éviter les indices de modèle par requête et de produire des exécutions stables et reproductibles.

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