# レスポンスの解析

チャットモデルが単一の応答文字列だけでなく、構造化された出力を生成することがますます一般的になっています。例えば、[推論モデル](https://huggingface.co/reasoning-course)は推論のトレースを含む思考の連鎖を出力し、[ツール呼び出し](./chat_extras)モデルは関数名と引数を出力することがあります。

ただし、構造化出力の問題は、LLMの出力が本質的に構造化されていない点にあります。LLM APIは通常、`role`や`content`、`reasoning_content`などのキーを持つメッセージの辞書を受け取り、返却します。しかし内部では、LLMは単一のトークンシーケンスを継続するだけです。ユーザー向けのAPIとモデルの実際のトークンストリームを接続するために、私たちは接着層（glue layer）を使用しています。入力からトークンストリームへの変換には、[`chat_templates`](./chat_templating)を使用しますが、これは他のドキュメントで説明されています。本ドキュメントでは、その接着層のもう半分の部分、すなわちモデルが生成したトークンを構造化されたレスポンス辞書へ変換するシステムである**Response templates**について説明します。

多くの点において、response templates は chat templates と逆の操作を行います。chat templates では、メッセージのリストを入力すると、モデルに入力できるトークンが得られます。一方、response templates では、モデルの生（raw）出力トークンを入力すると、構造化されたメッセージが得られます。chat templates と同様に、response templates は、モデルが特定のフォーマットや制御トークンをどのように期待しているかという煩雑な詳細をユーザーが気にする必要なく、あらゆるモデルで動作するメッセージ dict の汎用的な API を使用できるようにします。

レスポンステンプレートの理解に最も良い方法は、実際の動作を見ることです。主なエントリポイントは[parse_response()](/docs/transformers/main/ja/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.parse_response)メソッドで、単一のシーケンスまたはバッチのどちらを受け入れることもできます:

```python
from transformers import AutoModelForCausalLM, AutoTokenizer

checkpoint = "HuggingFaceTB/SmolLM3-3B"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForCausalLM.from_pretrained(checkpoint, dtype="auto", device_map="auto")

messages = [{"role": "user", "content": "Summarize the end of the Cold War, very briefly."}]
input_ids = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt")["input_ids"].to(model.device)
outputs = model.generate(input_ids, max_new_tokens=1024)[0, input_ids.shape[1]:]
out_text = tokenizer.decode(outputs)
print(tokenizer.parse_response(out_text, prefix=input_ids[0]))
# Outputs a structured dict: {"role": "assistant", "reasoning_content": "...", "content": "..."}
```

トークナイザに`response_template`がある場合、`parse_response`メソッドは出力メッセージを構造化されたdictにきれいに変換し、チャットに追加できる状態にします。なお、このメソッドには`prefix`（プロンプトのトークン）も渡す必要があります。これは、多くのチャットテンプレートがモデルの応答を開始する前にメッセージを開始したり、思考ブロックを開いたりするため、パーサーがメッセージを理解するにはプロンプトを見る必要があるからです。最終ターン以前のすべてのprefixは破棄されます。一度に1つのメッセージのみを解析します。prefixは、最終メッセージ全体を確認し、事前入力されたフィールドを見逃さないようにするために必要です。

プレフィックスの欠落は、事前入力済みのメッセージの解析を静かに誤らせる可能性があるため、`prefix` は必須です。省略するとエラーが発生します。生成済みテキストに完全なメッセージが含まれており、プレフィックスのコンテキストが不要であると確信できる稀なケースでは、`prefix=""`（またはトークン ID の空のリスト）を渡して明示的に除外してください。

トークナイザーにレスポンステンプレートが設定されていない場合、`parse_response`はエラーを発生させます。より多くのモデルにテンプレートを追加できるよう、最速で対応を進めています。

## ストリーミングレスポンスの解析

上記の例では、生成が完了した後にモデルの応答を一度にパースしています。しかし、多くの場合、メッセージが生成されるにつれて部分的なメッセージをリアルタイムでパースしたいことがあります。特に、モデルの生成が完了するまで1〜2分間静的なページを表示するだけで済ませたくない、ユーザー向けのアプリケーションではその傾向が顕著です。

ストリーミング解析が必要な場合は、`tokenizer.get_response_parser()`を呼び出します。これにより`ResponseParser`が返されます。`parse_response`と同様に、チャットテンプレートによって事前入力されたメッセージの部分をパーサーに認識させるため、チャットプロンプトを`prefix=`として渡します。返されるオブジェクトは状態を持つパーサーであり、モデルがテキストを生成するにつれて、そのテキストを投入していくことができます。

```python
parser = tokenizer.get_response_parser(prefix=input_ids[0])
for event in parser.initial_events:
    render(event)  # Display the partial message to the user however you want to
for chunk in model_output:
    for event in parser.feed(chunk):
        render(event)
message, final_events = parser.finalize()
for event in final_events:
    render(event)
```

リクエストにツールが含まれている場合は、それらも渡します(`get_response_parser(..., tools=tools)`)。これにより、各リージョンがクローズするたびに、呼び出し元のツールの JSON Schema に基づいてツール呼び出しの引数が型付けされるため、ストリーミングのコンシューマーは`finalize()`の後にのみではなく、`region_close`の時点でスキーマ型付け済みの引数を参照できます。詳細は[ツール呼び出し引数の型付け](#typing-tool-call-arguments)を参照してください。

パーサーは、生成プロセスからテキストが投入されるにつれて**イベント**を出力します。これにより、現在どの領域が生成中であるかが示されます。領域の生成が完了すると、完全にパースされた内容を含む別のイベントとして出力されます。生成が終了すると、`finalize()`メソッドが残りテキストをフラッシュし、最終的なイベントおよび完全なメッセージ辞書を出力します。

`parse_response` はバッチを受け取れますが、ストリーミング解析は常に単一シーケンスです。各 `ResponseParser` は1つの生成の状態を追跡します。複数の生成を同時にストリーミングしたい場合は、シーケンスごとに1つの `ResponseParser` を作成してください。

## ストリーミングイベント

ストリーミング解析の各イベントは、`type`キーを持つ辞書です。3つの種類があります。

| 型           | 説明                                                                         | 目次                                                                                                                        |
|----------------|-------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
| `region_open`  | `content`や`reasoning_content`など、モデルが新しい領域を開始したことを示します。 | `field` (str): フィールド名。                                                                                                  |
| `region_chunk` | 現在の領域のテキストチャンク。                                             | `field` (str): フィールド名。`text` (str): 新しいチャンク。`dirty` (bool): チャンクがパースが必要な生テキストの場合に`True`。 |
| `region_close` | リージョンが完了し、そのキーが確定したことを示します。                | `field` (str): フィールド名。`value` (any): リージョンの完全に解析された値。                                             |

`region_chunk` イベントは、バイトが到着するたびにすべての region に対して発行されるため、構造化された region でも、ストリーミング UI が進行状況をレンダリングできます。テキストのような region（`text`、`int`、`float`、`bool`）では、チャンクに `dirty=False` が付与されます。各チャンクはすでに最終値の一部です（クローズ時に末尾の空白が除去されることを除いて）。JSON 形式のツール呼び出しなどの構造化された region では、チャンクに `dirty=True` が付与されます。つまり、text は未パースの生データであり、増分表示は安全ですが、*parsed* 値（dict、list など）は、対応する `region_close` イベントでのみ届きます。いずれにせよ、region の確定値は常に `region_close` によって運ばれるため、中間レンダリングを気にしないコンシューマーは、`region_chunk` イベントを単に無視すればよいです。

チャット`prefix`がメッセージに何かを書き込んだ場合（テンプレートが思考ブロックを開いた、またはモデルに引き継ぐ前にアシスタントのプリフィルが応答を開始した、など）、パーサーはそれらのイベントを`parser.initial_events`として公開します。これは、モデルの出力をレンダラーに渡す前に、レンダラーに再生できるリストです。プレフィックス内で開かれ*かつ*閉じられたリージョンは、`region_open` / `region_chunk` / `region_close`の完全なシーケンスを生成し、その解析値は出力辞書に格納されます。これは、モデル自体がそれらを書き込んだ場合とまったく同じです。

典型的なイベントストリームは、次のようになります。

```python
{"type": "region_open",  "field": "reasoning_content"}
{"type": "region_chunk", "field": "reasoning_content", "text": "I should ", "dirty": False}
{"type": "region_chunk", "field": "reasoning_content", "text": "greet the user", "dirty": False}
{"type": "region_close", "field": "reasoning_content", "value": "I should greet the user"}
{"type": "region_open",  "field": "tool_calls"}
{"type": "region_chunk", "field": "tool_calls", "text": '{"name": "greet_user", ', "dirty": True}
{"type": "region_chunk", "field": "tool_calls", "text": '"arguments": {"greeting": "Hi!"}}', "dirty": True}
{"type": "region_close", "field": "tool_calls", "value": {"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}}}
```

`reasoning_content` が `dirty=False` で出力される点に注目してください。`reasoning_content` や `content` のようなフィールドは通常、生のテキストに過ぎないためです。つまり、チャンクを有効な「部分的な出力」として扱えます。一方、`tool_calls` は `dirty` とフラグ付けされます。生のテキストには大幅なクリーンアップが必要であり、ツールコールは JSON または他の形式としてパースされた後、最終的なツールコールの dict を生成するために再構築されることが多いからです。その結果、これらの領域の最終出力は、生のテキストとは非常に大きく異なることがよくあります。この最終的なパースは、`region_close` に到達した時点でのみ行われます。それまでの `dirty` チャンクをどう扱うかはあなた次第です。ユーザーに「生の」出力を表示するためにそのまま表示することも、表示できるクリーンなデータが揃うまで待つこともできます。

これで、response templates を利用するために必要な知識の大部分は終了です。このドキュメントの残りの部分は、parsing システムの内部構造と response templates の作成方法に焦点を当てています。これは主に開発者やモデル作成者に関連する内容です。ほとんどの人は、ここで安心して読み終えて大丈夫です！

## 高度なトピック: レスポンステンプレートの作成

レスポンステンプレートの書き方を理解する最善の方法は、具体的な例を挙げることです。`SmolLM`からの生の応答は、次のようになる可能性があります。

```txt
<think>
I should greet the user
</think>

<tool_call>{"name": "greet_user", "arguments": {"greeting": "Hi!"}}</tool_call>
```

この出力を標準的なメッセージ辞書形式でパースすると、次のようになります。

```json
{
    "role": "assistant",
    "reasoning_content": "I should greet the user",
    "tool_calls": [
        {"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}}
    ]
}
```

そして、これを解析するテンプレートがこちらです。難しく考えすぎないでください。多くの部分は、かなり自明です!

```python
{
    "defaults": {"role": "assistant"},
    "start_anchor": "<|im_start|>assistant\n",
    "fields": {
        "reasoning_content": {"open": "<think>", "close": "</think>", "content": "text"},
        "tool_calls": {
            "open": "<tool_call>",
            "close": "</tool_call>",
            "repeats": True,
            "content": "json",
            "transform": {"type": "function", "function": "{content}"},
        },
        "content": {
            "close": "<|im_end|>",
            "content": "text",
        },
    },
}
```

本質的に、テンプレートは**フィールド**と**区切り文字**を定義します。各フィールドは出力辞書のキーに対応します。フィールドには、その区切り文字内のテキストをパースするための情報も含まれます。1つの微妙な点があります。`content`フィールドには`open`がありません。これは、SmolLM（およびいくつかの他のモデル）では、特別なトークンでマークされていないためです。代わりに、`content`は他の領域の後のスペースに保存されますが、シーケンスの終了前です。私たちのテンプレートでは、これを他のどの領域にも割り当てられていないテキストを拾い上げる**暗黙の / 残り**フィールドとして表現しています。

フィールド名は、モデルのチャットテンプレートが読み取るキーと一致させる必要があります。これにより、解析されたメッセージをチャットに追加し、再度レンダリングすることが可能になります。特に、推論フィールドの名前は`reasoning_content`にしてください。これはメッセージの辞書における推論の標準的なキーであり、ほぼすべてのチャットテンプレートが推論を読み取る際に使用するキーです。

`fields`に加えて、テンプレートは2つのトップレベルのキーをサポートしています:

- `defaults`（任意）— 出力に事前設定される値の辞書（例: `{"role": "assistant"}`）。この辞書のキーは、フィールドが何も書き込まなくても、解析済み出力に常に保持されます。その他のキーは、対応するフィールドが何も取得しなかった場合に削除されます。
- `start_anchor` (str) / `start_anchor_pattern` (str regex) — チャットプロンプト内で現在のアシスタントメッセージが開始する位置を示します。`prefix=` を `parse_response` または `get_response_parser` に渡すと、パーサーはこのアンカーの**最後の**出現位置以降のプレフィックスを右側から切り捨ててから処理を行います。これにより、マルチターン会話における以前のターンが、現在のメッセージの状態を汚染することがなくなります。アンカーは `prefix` にのみ適用され、解析対象のレスポンス/生成物には決して適用されません。一部のフォーマットでは、メッセージの途中でアンカーが正当に再出力されることがあるためです（gpt-oss harmony の出力では、すべてのチャネルが `<|start|>assistant` で始まります）。そのため、レスポンスをアンカー以降で切り捨てると、モデル自身の推論やツール呼び出しが失われてしまいます。これが、生成物だけでは履歴の混入を防げない理由です。プロンプトを `prefix=` として渡してください。ChatML 形式のモデルでは、アンカーは通常 `"<|im_start|>assistant\n"` です。`start_anchor` と `start_anchor_pattern` のうち、ちょうど 1 つを設定する必要があります。

例えば、このマルチターンプレフィックス（**2回**のアシスタントターンに注意）が与えられた場合:

```txt
<|im_start|>user
Hi<|im_end|>
<|im_start|>assistant
Hello!<|im_end|>
<|im_start|>user
Again?<|im_end|>
<|im_start|>assistant
```

パーサーは最後の`<|im_start|>assistant\n`までの**すべて**を切り捨て、それ以前の`"Hello!"`ターンを破棄します。ルールは、_最後のアシスタントターンを除くすべてが常に破棄される_ことです。

チャットテンプレートと同様に、レスポンステンプレートはトークナイザーの属性として保存され、トークナイザーとともに保存されます。チャットテンプレートとは異なり、Jinjaスクリプトとは異なりJSONに自然に収まる形式であるため、`tokenizer_config.json`内に保存され、別ファイルとして保存されることはありません。

```python
tokenizer.response_template = template
tokenizer.save_pretrained(...)  # Written as a key in tokenizer_config.json
```

## 詳細: フィールド API リファレンス

各フィールドは複数のキーをサポートしています。これらは2つのタイプに分類できます。まず、フィールドのキャプチャ方法を定義するキーがあります。

| キー             | 型               | 目的                                                                                       |
|-----------------|--------------------|-----------------------------------------------------------------------------------------------|
| `open`          | str or list[str]   | この領域を開始するリテラル文字列。文字列のリストを指定すると、「これらのいずれかに一致する」ことを意味します。          |
| `open_pattern`  | str (正規表現)        | `open`の正規表現版です。名前付きグループは、`transform`で利用可能なキャプチャ変数になります。  |
| `close`         | str or list[str]   | この領域を閉じるリテラル文字列（または文字列のリスト）。省略すると、ストリームの最後まで実行されます。    |
| `close_pattern` | str (正規表現)        | `close`の正規表現による代替手段です。名前付きグループは、`transform`で利用可能なキャプチャ変数になります。 |
| `repeats`       | bool               | trueの場合、フィールドはリストとなり、各一致が追加されます。デフォルトは`false`です。                         |
| `join`          | str                | `repeats` を使用すると、リストの代わりに、この区切り文字で一致箇所を1つの文字列に連結します。    |
| `optional`      | bool               | If false and the region never matches, we raise an error. Default `true`.                     |

フィールドには`open`または`open_pattern`の**いずれか一方**のみを指定する必要があり、両方を指定することはできません。`close`と`close_pattern`についても同様です。

フィールドでは、`close`/`close_pattern`を完全に省略できます。その場合、領域は生成テキストの末尾まで開いた状態のままになります。これは、メッセージの末尾まで続く最後のフィールドに便利です。

A field with **neither** `open` nor `open_pattern` is the **implicit** field: it's active whenever no explicit region is open, so it captures leftover text. At most one field can be implicit. This is most often used when `content` does not have special token tags, it's just written as plaintext after the other fields.

開きと閉じのデリミターに加えて、`repeats`を指定することもできます。これはフィールドがリストであることを示し、デリミターが複数回一致することを意味します。これは、モデルが複数のツール呼び出しを同時に発行する並列ツール呼び出しで最も一般的です:

```python
'<tool_call>{"name": "a", ...}</tool_call><tool_call>{"name": "b", ...}</tool_call>'
# Returns `"tool_calls": [{... "a" ...}, {... "b" ...}]` in a template with repeats: true
```

ただし、すべての繰り返しフィールドをリストに変換すべきではありません。一部のモデルは、1つのメッセージ内で複数の`reasoning_content`または`content`ブロックを出力します。これらの自然な出力は、1つの連結された文字列です。`join`(区切り文字列、通常は`""`のみ)を設定すると、`repeats`フィールドの動作が、リストを収集することから、一致した内容を連結することに変更されます:

```python
field = {"reasoning_content": {"open": "<think>", "close": "</think>", "repeats": True, "join": "\n"}}
input = "<think>first</think>...<think>second</think>"
# Returns: {"reasoning_content": "first\nsecond"}
```

`join`フィールドの各一致は、文字列としてパースされなければなりません。ストリーミングの場合、`region_close`は依然として各ブロック自身の値を保持します。区切り文字は、最終的なメッセージ辞書にのみ出現します。

最後に、必須のフィールドには`optional: false`を指定できます。このようなフィールドが欠落している場合、メッセージの辞書からそのフィールドを省略して返すのではなく、エラーを発生させます。

生成が終了すると、閉じ区切り文字が検出されていなくても、開いているすべての領域は閉じられ、確定されます。

### フィールドの内容を解析する

フィールドのキャプチャ方法を定義した後、そのキャプチャ内の生テキストをどのようにパースするかも指定する必要があります。これを制御するキーは4つあります。

| キー              | 型         | 目的                                                                                  |
|------------------|--------------|------------------------------------------------------------------------------------------|
| `content`        | str          | この領域内のコンテンツタイプです。デフォルトは`"text"`です。各タイプには独自のパーサーがあります。 |
| `content_args`   | dict         | この領域のコンテンツパーサーに渡す引数。                            |
| `transform`      | dict/list    | 解析済みボディの形状を変更するための任意のポストパーステンプレート（**Transform**を参照）。          |
| `transform_each` | bool         | true の場合、解析されたコンテンツはリストである必要があり、`transform` が要素ごとに適用されます。       |

最初の（そして最も重要な）キーは`content`です。これはフィールドのコンテンツタイプを示し、フィールド内で取得された生テキストを最終的な出力に変換するために使用されるパーサーを決定します。`content_args`はパーサーを設定するために使用され、カスタムコードを必要とせずにさまざまなフォーマットの特殊性に対応できます。以下では、各パーサーの種類とその引数について順に見ていきます。

#### 基本型
`text`、`int`、`float`、`bool` は基本型です。これらのコンテンツタイプは、すべて空白を除去し、必要に応じて単純な型変換を行うだけです。`content_args` は持ちませんが、`text` だけは引数 `strip` をサポートしており、これは取得したテキストの先頭と末尾の空白を除去します。デフォルト値は `true` です。

```python
field = {"count": {"open": "<n>", "close": "</n>", "content": "int"}}
input = "<n> 42 </n>"
# Returns: {"count": 42}
```

#### json

`json` パーサーは、キャプチャされたテキストを JSON として解析します。ツール呼び出しの引数や、その他のネスト構造を持つデータ処理の主力として機能します。実環境でモデルが JSON を変形させる様々なケースに対応するため、いくつかの任意の `content_args` を受け取ります。

- `unquoted_keys` (bool, デフォルト `false`): キー名が引用符なしの生データである場合に有効にします (例: `{name: "foo"}`)。厳密な JSON ではなく、Javascript スタイルのオブジェクトリテラルを出力するモデルに有用です。
- `string_delims`（`[open, close]` のペアのリスト、省略可）: `"..."` の代わりに独自の区切り文字で文字列値を囲むモデル向けです。各ペアは開始マーカーと終了マーカーを指定します。
- `allow_non_json` (bool, デフォルト `false`): パースに失敗した場合、例外を送出する代わりに、トリムされた生テキストを返します。モデルが*通常*は JSON を出力するものの、稀にプレーンテキストに切り替わるフィールドのフォールバックとして有用です。

`unquoted_keys` と `string_delims` は、非標準で JSON に近いが完全ではない出力を生成するモデルを処理するために存在するため、ごく少数のモデルでのみ必要になるはずです。

```python
field = {"args": {"open": "<args>", "close": "</args>", "content": "json", "content_args": {"unquoted_keys": True}}}
input = '<args>{city: "London"}</args>'
# Returns: {"args": {"city": "London"}}
```

#### xml-inline

`xml-inline` パーサーは、フラットなシーケンスで構成される XML 風のタグの領域向けです。各タグが dict の 1 エントリになります。`tool_calls` フィールド内で、JSON ブロックではなく各引数を個別のタグとして出力するモデルに最もよく使用されます。

- `tag_pattern` (str, **必須**): 単一のタグに一致する正規表現。`key` (結果の dict のキー) と `value` (dict の値となる生テキスト) という名前付きグループを含める必要があります。
- `value_parser` (dict, 省略可): 各キャプチャされた `value` に適用されるネストされたコンテンツパーサー。`name` (パーサー、例: `"json"`、`"int"`) と、任意の `args` (その `content_args`) を持つ dict です。省略した場合、値は生の文字列のままになります。
- `merge_duplicates` (bool, デフォルトは `false`): 同じキーが複数回出現した場合、後続の一致が先行するものを上書きするのを防ぐため、値をリストに集約します。

例えば、Qwen3 は各ツール呼び出しの引数をそれぞれ独立した `<parameter>` タグとして出力し、以下のようにパースします。

```python
"tool_calls": {
    "open_pattern": r"<tool_call>\s*<function=(?P<name>\w+)>",
    "close": "</tool_call>",
    "repeats": True,
    "content": "xml-inline",
    "content_args": {
        "tag_pattern": r"<parameter=(?P<key>\w+)>\s*(?P<value>.*?)\s*</parameter>",
        "value_parser": {"name": "json", "args": {"allow_non_json": True}},
    },
    "transform": {"type": "function", "function": {"name": "{name}", "arguments": "{content}"}},
}
```

ネストされた`value_parser`に注意してください。各パラメータの値は、`json`パーサー（プレーンな文字列がそのまま通るように`allow_non_json`を指定）で処理されます。上記の`tool_calls`フィールドにこの入力を渡すと:

```python
input = "<tool_call><function=get_weather><parameter=city>London</parameter><parameter=units>celsius</parameter></function></tool_call>"
# Returns: {"tool_calls": [{"type": "function", "function": {"name": "get_weather", "arguments": {"city": "London", "units": "celsius"}}}]}
```

#### kv-lines

`kv-lines`パーサーは、行区切り形式の`key: value`ペア（YAML風のメタデータや`.env`ファイルなど）を処理します。各行が結果の辞書内の1つのエントリになります。すべての引数は省略可能です。

- `line_sep` (str, デフォルト `"\n"`): ペア間の区切り文字。
- `kv_sep` (str, デフォルトは `":"`): 1行の中でキーと値を区切る区切り文字です。分割点として最初の出現箇所のみが使用されるため、値自体が区切り文字を含むことも可能です。
- `strip` (bool、デフォルトは`true`): 各キーと値の前後にある空白を除去します。
- `value_parser` (dict, 省略可): 各値に適用されるネストされたコンテンツパーサーです。`xml-inline` と同じ `{"name": ..., "args": ...}` 形式で指定します。省略した場合、値は生の文字列のままになります。

空行であるか、`kv_sep` を含まない行は、黙ってスキップされるため、キャプチャされた領域内の余分な空行は許容されます。

```python
field = {"metadata": {"open": "<meta>", "close": "</meta>", "content": "kv-lines"}}
input = "<meta>name: alice\nage: 30</meta>"
# Returns: {"metadata": {"name": "alice", "age": "30"}}
```

`age` は `"30"` を文字列のまま保持します。`30` に変換するには、`value_parser` に `{"name": "int"}` を追加してください。

### ツール呼び出し引数の型付け

ときどき、レスポンスパーサーは誤った型でモデルの出力をパースする可能性があります。例えば、浮動小数点数`1.5`を"1.50"としてパースする場合があります。これは、ツールが特定の型の引数を期待しているのに別の型で受け取ってしまう場合、ツール呼び出しで問題を引き起こす可能性があります。これを回避するために、リクエストの`tools`を[parse_response()](/docs/transformers/main/ja/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.parse_response)または`ResponseParser`に渡すことで、各ツールのJSONスキーマの`parameters`を使用してキャストできます。ツールは、[apply_chat_template()](/docs/transformers/main/ja/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.apply_chat_template)と同じ形式で受け入れられます。JSONスキーマ、または型ヒントとドキュメント文字列を備えたPython関数（スキーマに自動変換されます）です。

```python
tools = [{
    "type": "function",
    "function": {
        "name": "set_alarm",
        "parameters": {
            "type": "object",
            "properties": {
                "hour": {"type": "integer"},
                "enabled": {"type": "boolean"},
                "label": {"type": "string"},
            },
        },
    },
}]
message = parse_response(model_out, template, prefix="", tools=tools)
# message["tool_calls"][0]["function"]["arguments"] ==
# {"hour": 7, "enabled": True, "label": "wake up"}
```

### 変換

ほとんどのフィールドでは、`transform` キーは不要です。解析されたボディを最終的な出力に整形する必要がある場合、または区切り文字からの情報を結果にマージする必要がある場合に使用されます。`tool_calls` フィールドでは、構造が複雑なことが多いため、最も頻繁に使用されます。

`transform` は **テンプレート**です。出力の形状を記述する dict（または list）であり、`"{name}"` という形式の文字列は対応する値に置き換えられます。値は `content`（この領域の解析済みボディ）および `open_pattern` / `close_pattern` でキャプチャされた名前付きグループからアクセスできます。非常に一般的なユースケースとして、標準的なツール呼び出し形式の一部である `function` キーを持つ外側の dict で、ツール呼び出しの dict をラップすることが挙げられます。

```python
"tool_calls": {
    "open": "<tool_call>",
    "close": "</tool_call>",
    "repeats": True,
    "content": "json",
    "transform": {"type": "function", "function": "{content}"},
},
```

つまり、この生の出力は:

```txt
<tool_call>{"name": "greet_user", "arguments": {"greeting": "Hi!"}}</tool_call>
```

becomes (`repeats: True` を指定すると、`tool_calls` はリストになります):

```json
[{"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}}]
```

`"{content}"` のような文字列全体を占めるプレースホルダーは、参照された値を型を保持したまま返します。したがって、上記の例では、パースされた JSON の dict が `function` の値としてそのまま挿入されます。プレースホルダーは文字列全体を占める必要があります。テキストとプレースホルダーを混在させること（`"abc {name} def"`）は許可されていません。これらは f-string ではありません。

プレースホルダーには、`"{content.args}"` のようなドット区切りパスも指定できます。これにより、`content` を参照した上で、解析された辞書の `args` キーに降下します。キー名が標準形式と一致しないツールコールの本体を整形する場合に、この方法を使用します。例えば、`{"name": ..., "args": ...}` を出力するモデルでは、`args` を `arguments` にリネームする必要があります。

```python
"tool_calls": {
    "open": "<tool>",
    "close": "</tool>",
    "repeats": True,
    "content": "json",
    "transform": {"type": "function", "function": {"name": "{content.name}", "arguments": "{content.args}"}},
},
```

解決できないパス（ここでは、`args` が欠落しているツール呼び出し）は、不正なツール呼び出しを出力するのではなく、エラーを発生させます。

`transform` は非常に多機能であり、モデルの出力が標準 API の形式と大きく異なる場合に必要になります。GPT-OSS がその良い例です。GPT-OSS は JSON ボディではなくチャネルヘッダーに関数名を埋め込むため、`open_pattern` 内の名前付きグループでそれをキャプチャし、transform 内で `content` にマージする必要があります。`open_pattern` と `close_pattern` 内のすべての名前付きグループは、`content` と並んで変数として利用可能になります。

```python
"tool_calls": {
    "open_pattern": r"<\|channel\|>commentary to=functions\.(?P<name>\w+).*?<\|message\|>",
    "close": "<|call|>",
    "repeats": True,
    "content": "json",
    "transform": {"type": "function", "function": {"name": "{name}", "arguments": "{content}"}},
},
```

関数名はJSONボディではなくチャネルヘッダーに格納されているため、これ:

```txt
<|channel|>commentary to=functions.get_current_weather <|constrain|>json<|message|>{"location": "San Francisco, CA"}<|call|>
```

次のようになります:

```json
[{"type": "function", "function": {"name": "get_current_weather", "arguments": {"location": "San Francisco, CA"}}}]
```

フィールドの解析済みコンテンツが*それ自体*がレコードのリストであり、各要素をリシェイプしたい場合があります。Cohere テンプレートはその良い例です。すべてのツール呼び出しを単一の JSON 配列内に出力するため、`transform_each: True`を設定して、変換を要素ごとに適用します。配列の各要素のキーはテンプレートのスコープに展開されるため、`"{tool_name}"`は現在の要素内の`tool_name`を参照します。

```python
"tool_calls": {
    "open": "<|START_ACTION|>",
    "close": "<|END_ACTION|>",
    "content": "json",
    "transform_each": True,
    "transform": {"type": "function", "function": {"name": "{tool_name}", "arguments": "{parameters}"}},
},
```

これにより、次のような出力が変換されます:

```json
[
    {"tool_name": "greet_user", "parameters": {"greeting": "Hi!"}},
    {"tool_name": "search", "parameters": {"query": "weather tomorrow"}}
]
```

標準的なAPIに適合する、次のような出力に変換します:

```json
[
    {"type": "function", "function": {"name": "greet_user", "arguments": {"greeting": "Hi!"}}},
    {"type": "function", "function": {"name": "search", "arguments": {"query": "weather tomorrow"}}}
]
```

`transform_each` フラグは、`content` がすでにリストである場合にのみ必要です。より一般的なケース、つまり各マッチが1つの要素を寄与し（`repeats: True` がそれらを蓄積する）、変換がデフォルトで各要素に適用される場合は、このフラグは不要です。

## フレームワーク開発者: レギュラー表現の移植可能性

`open_pattern`、`close_pattern`、`start_anchor_pattern` は正規表現の文字列です。ほとんどのユーザー、さらにはほとんどのモデル作成者にとっても問題にはなりませんが、別の言語でレスポンス解析の実装を書いている開発者の方は、私たちの実装詳細について知っておく必要があります。このセクションは、Python 以外のチャットテンプレートリングを動作させるために、Jinja パーサー全体を実装しなければならなかったすべての方向けです。以下のシンプルなガイドラインに従っていただければ、レスポンステンプレートの処理がはるかに楽になることを願っています。

- チャット解析で使用されるすべての正規表現には、Pythonの[`regex`](https://pypi.org/project/regex/)モジュールを使用しています。Python3の文字列はすべてUnicodeであるため、**すべての正規表現のマッチングはUnicode対応です**。これは`\w`のような一般的な文字に特に影響を与えます。エンジンで関連するUnicodeフラグを設定してください。
- すべての正規表現は`re.DOTALL`を有効にし、`re.MULTILINE`を無効にしてコンパイルされるため、`.`は`\n`にマッチしますが、`^`と`$`は改行ではなく、入力全体のはじまり/おわりにのみマッチします。
- 名前付きグループには`(?P<name>...)`構文を使用します。他の正規表現実装では、名前付きキャプチャグループの構文が大きく異なるため、正規表現内のこのパターンを検索して、ローカルの実装に合わせて書き直す必要がある場合があります。
- データの出力タイミングを判断するために、部分正規表現マッチングを使用しています。これは、リージョンの末尾が複数のトークンで構成される場合があり、そのリージョン末尾の区切り文字を出力したくないためです。そのため、トークンがリージョン内部にあり境界の一部ではないと確信できるまで、トークンの出力を保留します。つまり、リージョン末尾の正規表現が部分一致した場合、正規表現が完全に一致するか失敗するまで、データの出力を保留します。正規表現エンジンが部分マッチングをサポートしていない場合でも、レスポンステンプレートの実装は可能ですが、この問題に対処するために別の解決策を見つける必要があるかもしれません。単純なアプローチとしては、末尾の区切り文字が明確に確認できるまで、これらのリージョンを保留するか、`dirty` として出力する方法があります。
- 正規表現エンジンが、`(?!...)` などのルックアラウンドをサポートしていない場合があります（稀ですが）。これらの構文はレスポンステンプレートでは一般的ではありませんが、出現する可能性があり、当方ではサポートしています。そのため、該当する場合はエラーを送出するか、正規表現エンジンが一致候補を検出した際にルックアラウンドを手動で抽出し、コード内でその条件を強制する必要があるかもしれません。
- バックリファレンス、アトミックグループ、ポゼッシブ量子子、再帰などの他の高度な機能は、応答テンプレートでは一般的に使用されません。モデル作成者がこれらを使用しないよう促すため、おそらく安全に無視して問題ありません。

