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.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Serve CLI

transformers serve CLIは、ローカルまたはセルフホスト環境向けの軽量なオプションです。vLLMのような専用推論エンジンに伴う追加のランタイムや運用上のオーバーヘッドを回避できます。評価、実験、中程度の負荷のデプロイメントに適しています。continuous batchingなどの機能により、スループットが向上し、レイテンシが低減されます。

大規模な本番環境でのデプロイには、Transformer モデルをバックエンドとして使用し、vLLM または SGLang を利用してください。詳細は 推論バックエンド ガイドを参照してください。

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

v1/chat/completions API は Chat Completions API に基づいています。LLM、VLM、マルチモーダルモデルのテキスト、画像、音声、動画のリクエストをサポートしています。curl、InferenceClient、または OpenAI クライアントと組み合わせて使用できます。

テキストベースの補完

huggingface_hub
huggingface_hub (ストリーム)
openai
openai (stream)
curl
curl (ストリーム)
from huggingface_hub import InferenceClient

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

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

InferenceClient は、印刷された文字列を返します。

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

画像ベースの補完

huggingface_hub
huggingface_hub (ストリーム)
openai
openai (stream)
curl
curl (ストリーム)
from huggingface_hub import InferenceClient

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

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

InferenceClient は、印刷された文字列を返します。

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

オーディオベースの補完

Gemma 4 や Qwen2.5-Omni のようなマルチモーダルモデルは、OpenAIのinput_audioコンテンツタイプを通じて音声入力を受け入れます。音声をBase64エンコードし、形式(mp3またはwav)を指定してください。

huggingface_hub
huggingface_hub (ストリーム)
openai
openai (stream)
curl
curl (ストリーム)
import base64
from huggingface_hub.utils import httpx
from huggingface_hub import InferenceClient

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

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

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

InferenceClient は、印刷された文字列を返します。

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

audio_urlコンテンツタイプはOpenAI標準の一部ではない拡張機能であり、将来のバージョンで変更される可能性があります。

audio_url コンテンツタイプを指定して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ベースの補完

video_urlコンテンツタイプはOpenAI標準の一部ではない拡張機能であり、将来のバージョンで変更される可能性があります。

動画の入力には、video_urlコンテンツタイプを使用します。モデルがオーディオをサポートしている場合(例: Gemma 4、Qwen2.5-Omni)、サーバーは動画からオーディオトラックを抽出し、ビジュアルフレームとともに処理します。

Video処理にはtorchcodecが必要です。pip install torchcodecでインストールしてください。

huggingface_hub
huggingface_hub (ストリーム)
openai
openai (stream)
curl
curl (ストリーム)
from huggingface_hub import InferenceClient

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

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

InferenceClient は、印刷された文字列を返します。

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

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

マルチターン会話

マルチターン会話を行うには、messagesリストに、userとassistantのロールが交互に並ぶ完全な会話履歴を含めてください。OpenAI互換のサーバーと同様に、このAPIはステートレスであるため、すべてのリクエストに完全な会話履歴を含める必要があります。

from openai import OpenAI

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

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

「そこに住んでいる人は何人ですか?」という追問は、それまでの文脈に依存しているため、モデルはパリについて回答します。

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

v1/completions

v1/completions API は、レガシーの Completions API に基づいています。/v1/chat/completions とは異なり、チャットメッセージではなく自由形式のテキストである prompt を受け取り、生成されたテキストを choices[].text に返します。これは、チャットテンプレートが不要なベース(非インストラクト)モデルやテキスト補完タスクに有用です。また、fill-in-the-middle によるテキスト挿入のための suffix もサポートしています。

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

このコマンドは、以下のレスポンスを返します。

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

v1/responses

Responses APIは、OpenAIの生成用の最新APIエンドポイントです。状態を保持したインタラクションをサポートし、組み込みツールを統合してモデルの機能を拡張します。OpenAIは、新規プロジェクトではChat Completions APIよりもResponses APIの使用を推奨しています。

v1/responses API は、curl コマンドおよび OpenAI クライアントを通じて、テキスト、画像、音声、動画のリクエストをサポートしています。

テキストベースの応答

openai
openai (stream)
curl
curl (ストリーム)
from openai import OpenAI

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

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

OpenAIクライアントは、印刷された文字列を返します。

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

画像ベースの応答

Responses API は、画像、音声、動画の入力もサポートしています。

openai
openai (stream)
curl
curl (ストリーム)
from openai import OpenAI

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

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

OpenAIクライアントは、印刷された文字列を返します。

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

音声ベースの応答

openai
openai (stream)
curl
curl (ストリーム)
import base64
from huggingface_hub.utils import httpx
from openai import OpenAI

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

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

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

OpenAIクライアントは、印刷された文字列を返します。

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

audio_urlコンテンツタイプはOpenAI標準の一部ではない拡張機能であり、将来のバージョンで変更される可能性があります。

audio_url コンテンツタイプを指定して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標準の一部ではない拡張機能であり、将来のバージョンで変更される可能性があります。

Video処理にはtorchcodecが必要です。pip install torchcodecでインストールしてください。

openai
openai (stream)
curl
curl (ストリーム)
from openai import OpenAI

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

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

OpenAIクライアントは、印刷された文字列を返します。

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

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

マルチターン会話

マルチターン会話では、inputフィールドにroleキーを持つメッセージのリストを渡します。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 エンドポイントは、TypeSafe の System One API に従い、共有された state に関する型付きの質問に回答します。サポートチケットのルーティング、緊急性の評価、アクションの選択などの判断に使用します。

モデルは、テキストを生成せずに、1回のバッチ化されたフォワードパスで許可された回答にスコアを付けます。このエンドポイントは、チャットテンプレートを持つ自己回帰モデルをサポートしています。

モデル、評価する状態、および名前をキーとする質問を送信します:

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

回答には同じ質問名が使用されます。例:

{
  "model": "Qwen/Qwen2.5-1.5B-Instruct",
  "answers": {
    "team": {"type": "choice", "choice": "technical", "probabilities": {"billing": 0.000006962256520637311, "technical": 0.999993085861206}, "confidence": 0.9999861717224121},
    "urgency": {"type": "score", "score": 1.6739138662815094, "legend": {"0": "low", "1": "medium", "2": "high"}, "probabilities": {"0": 0.0031353600788861513, "1": 0.31981542706489563, "2": 0.6770492196083069}, "confidence": 0.5108707791659981},
    "upset": {"type": "noul", "noul": 0.851952850818634}
  },
  "usage": {"input_tokens": 213, "output_tokens": 0}
}
質問の種類criteria回答
choice説明にマッピングされたオプション名。nullの場合もあります。最も可能性の高い選択肢、各選択肢の確率、および信頼度。
scoreレベルの説明を、低いものから高いものへ順に並べたものです。確率重み付きレベルインデックス、確率、凡例、および信頼度。
noultrue と false に対する任意の説明。trueである確率。

state、任意のinstructions、および説明には、テキストまたは JSON オブジェクトと配列を含めることができます。各リクエストは最大 64 個の質問を受け入れ、質問ごとに 1〜26 個の選択肢またはスコアレベルを指定できます。

ビジョン対応モデルでは、images 配列に最大 4 つの data:image/...;base64,... URL を追加します。すべての質問に同じ画像が渡されます。モデルのプロセッサーとチャットテンプレートが画像をサポートしている必要があります。リモートの画像 URL は受け付けられません。

決定設定

Decisionモデルには、プロンプト、回答ラベル、キャリブレーション設定を保存するための標準はまだ存在しません。これらはモデルの実装によって異なるため、--decision-config を使用して明示的に指定できます。カスタムの decision head を持つモデルには、互換性のある実装が引き続き必要です。このファイルは、プロンプトのフォーマットと next-token スコアリングの設定のみを行います。

デフォルトでは、質問にはフォールバックプロンプトと、思考機能が無効化されたモデルのチャットテンプレートが使用されます。選択肢およびスコアの回答ラベルはA〜Z、ブール値の場合はYes/Noです。確率は、これらのラベルに対する温度1のsoftmaxです。

モデルのこれらのデフォルトを上書きするには、--decision-config を渡します:

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

JSONファイルには、3つの任意フィールドがサポートされています。

フィールド意味
labelsnoul の場合は、選択肢の順序に従って(true、次に false)、問題タイプごとに回答ラベルを指定します。各ラベルは、互いに異なる既知の単一トークンである必要があります。
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 を公開します。options、labels、descriptions は同じ順序を共有します。これらのフィールドを使用してフォールバックの文言を置き換え、構造化された値をレンダリングするには tojson を使用します。画像入力のテンプレートには、モデルの画像プレースホルダーを含める必要があります。

このファイルは起動時に読み込まれ、/v1/systemone にのみ適用されます。省略された設定はデフォルト値が維持され、チェックポイントから決定設定が自動的に読み込まれることはありません。

v1/audio/transcriptions

v1/audio/transcriptions エンドポイントは、音声認識モデルを使用して音声を文字起こしします。Audio transcription 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) を介して進捗をストリーミングします。transformers chat CLI はこれを自動的に使用するため、ユーザーはハングしたプロンプトの代わりに、ダウンロードおよびロードの進捗を確認できます。推論リクエストを送信する前にモデルをウォームアップするために使用してください。

リクエスト

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)。revision を省略した場合、デフォルトで main が使用されます。

応答

レスポンスは SSE ストリーム(Content-Type: text/event-stream)です。各フレームは data: 行に配置された JSON オブジェクトです。

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

すべてのイベントには、最低限statusとmodelフィールドが含まれます。追加のフィールドは、ステータスによって異なります。

フィールド存在する場合説明
status常にloading、ready、または error
model常に正規のmodel_id@revision
stagestatus == "loading"processor、config、download、weights のいずれか(以下のステージを参照)
progressdownload ステージと weights ステージcurrent と total(整数または null)を持つオブジェクト
cachedstatus == "ready"モデルがすでにメモリ内に存在していた場合はtrue
messagestatus == "error"エラーの説明

ステージ

読み込みはこれらのステージの順に進みます。一部のステージはスキップされる場合があります(downloadは、ファイルがローカルにキャッシュ済みの場合にスキップされます)。

ステージ進捗はありますか?説明
processorいいえトークナイザ/プロセッサの読み込み
configいいえモデル設定の読み込み
downloadはい(バイト)モデルファイルのダウンロード
weightsはい(項目)重みテンソルをメモリに読み込む

ストリームは、必ず1つのターミナルイベント、ready(成功)またはerror(失敗)で終了します。

タイムアウト

transformers serve は、すべてのモデルのリクエストを処理します。各モデルはオンデマンドで読み込まれ、GPU メモリに保持されます。300 秒間アクティブでないと、GPU メモリを解放するためにモデルは自動的にアンロードされます。--model-timeout を別の秒数に設定するか、-1 を指定してアンロードを無効にできます。

transformers serve --model-timeout 400

例の読み込み

以下の例は、新規にダウンロードしたモデル、ローカルキャッシュから読み込まれたモデル(ダウンロード段階をスキップ)、そしてメモリに既に存在するモデルに対する応答を示しています。

フレッシュロード
キャッシュされたファイル
メモリ内
data: {"status": "loading", "model": "org/model@main", "stage": "processor"}
data: {"status": "loading", "model": "org/model@main", "stage": "config"}
data: {"status": "loading", "model": "org/model@main", "stage": "download", "progress": {"current": 0, "total": 269100000}}
data: {"status": "loading", "model": "org/model@main", "stage": "download", "progress": {"current": 134600000, "total": 269100000}}
data: {"status": "loading", "model": "org/model@main", "stage": "download", "progress": {"current": 269100000, "total": 269100000}}
data: {"status": "loading", "model": "org/model@main", "stage": "weights", "progress": {"current": 1, "total": 272}}
data: {"status": "loading", "model": "org/model@main", "stage": "weights", "progress": {"current": 272, "total": 272}}
data: {"status": "ready", "model": "org/model@main", "cached": false}

ツール呼び出し

transformers serveサーバーは、OpenAIスタイルの関数呼び出しをサポートしています。ツール使用のために学習されたモデルは、アプリケーションが実行する構造化された関数呼び出しを生成します。

Tool calling は、トークナイザーが tool call トークンを宣言しているモデルであればすべてで動作します。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"]
      }
    }
  }
]

create の extra_body 引数に GenerationConfig パラメータを渡すことで、生成をカスタマイズできます。

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)

マルチターンツール呼び出し

モデルがツール呼び出しを返した後、関数をローカルで実行し、その結果をフォローアップリクエストとして送信して、モデルの最終的な回答を取得します。このパターンは、2つのAPI間でわずかに異なります。完全な仕様については、OpenAI function calling guideを参照してください。

以下の例では、上記で定義されたtoolsリストを再利用します。

v1/chat/completions
v1/responses

ツール結果を、対応するtool_call_idを持つrole: "tool"メッセージとして渡します。

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

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

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

推論

推論モデルは、最終的な回答の前に隠された思考連鎖を出力します。サーバーはこれらの思考スパンを検出し、表示される回答から区切り記号を除去し、推論テキストを専用のフィールドに表示することで、クライアントがそれを別々にレンダリングできるようにします。

  • Chat Completions は、アシスタントメッセージの reasoning_content に推論を返します。
  • Responses API は、message アイテムの前に reasoning 出力アイテムとして推論を返します。

推論の検出はレスポンステンプレートに依存しており、これによりサーバーは思考区間の開始位置と終了位置を特定します。サーバーは、以下の2つの場所を順に確認します。

  1. モデルに同梱されている場合の、トークナイザーのresponse_template属性。
  2. モデルアーキテクチャに一致する組み込みのフォールバック。テンプレートがまだ同梱されていないトークナイザー向けです。

どちらの機能も持たないモデルは、レスポンスの解析なしで提供されます。生テキストがデコードされて content として返され、モデルが <think>...</think> タグを出力した場合でも、reasoning フィールドは表示されません。

サーバーで推論を有効にする

--reasoning を使用して、チャットテンプレートが思考トークンを出力するかどうかを制御します。

値動作
auto(デフォルト)チャットテンプレートのデフォルトに従います。
onチャットテンプレートの kwargs で enable_thinking=True を設定して、思考を強制オンにします。
offenable_thinking=False を設定して、思考を無効にします。
transformers serve Qwen/Qwen3-1.7B --reasoning on

すべてのモデルが推論に対応しているわけではありません。--reasoning は、モデルのチャットテンプレートが enable_thinking 変数を処理する場合(またはそのトークナイザーが思考区切り文字を宣言している場合)にのみ機能します。その他のモデルでは、このフラグは黙って無視されます。

--reasoning on と --reasoning off は、チャットテンプレートの変数 enable_thinking を設定することで動作します。一部のチャットテンプレートでは、思考の切り替えに異なる変数名を使用したり、プロンプトのレンダリング方法を変更する追加の変数を受け入れたりします。--chat-template-kwargs を JSON オブジェクトとして渡すことで、任意のチャットテンプレート変数を直接指定できます。

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

クライアントは、chat_template_kwargs をリクエストボディに含めることで、サーバーを再起動せずに、単一のリクエストに対してサーバーのデフォルト値を上書きできます。

Chat Completions

非ストリーミングレスポンスでは、アシスタントメッセージにreasoning_contentがcontentとともに含まれます。

openai
openai (stream)
curl
from openai import OpenAI

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

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

Responses API

Responses API は、message アイテムの前に配置される独立した reasoning 出力アイテムとして推論を返します。

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

マルチターン往復

マルチターン会話では、前の応答の推論テキストを次のリクエストに含めてください。サーバーはこれをチャットテンプレートに渡し、テンプレートが以前のアシスタントターンの一部としてレンダリングすることで、モデルが自身の以前の思考過程を確認できるようにします。

v1/chat/completions
v1/responses

reasoning_contentを直前のアシスタントメッセージに付与します。

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

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

ポートフォワーディング

ポートフォワーディングを使用すると、リモートサーバーからモデルを配信できます。サーバーへのSSHアクセスが可能であることを確認し、ローカルマシンでこのコマンドを実行してください。

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

再現性

モデルを位置引数として渡すことで、リクエストごとのモデルヒントを回避し、安定して再現可能な実行を実現できます。

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