> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fim.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# LLMプロバイダーの互換性

> FIM OneがLLM呼び出しをルーティングする方法、tool_choice アーキテクチャ、およびプロバイダー固有の落とし穴（特にAnthropicの思考とAWS Bedrockについて）。

## プロバイダー検出

FIM Oneはユニバーサルアダプターとして LiteLLM を使用します。`core/model/openai_compatible.py` の `_resolve_litellm_model()` 関数は、ユーザーの `LLM_BASE_URL` + `LLM_MODEL` を、プロバイダープレフィックス付きの LiteLLM モデル識別子にマッピングします。プレフィックスは、LiteLLM がリクエストをどのようにルーティングするかを決定します — ネイティブ API プロトコル（Anthropic Messages API、Gemini など）またはジェネリック OpenAI 互換の `/v1/chat/completions`。

解決順序：

1. **明示的なプロバイダー**（DB の `ModelConfig.provider` フィールドから）— 最優先。プロバイダーが URL 内の既知ドメインと一致する場合、`api_base` は返されません（LiteLLM はネイティブでルーティング）。それ以外の場合、`api_base` はリレー URL に設定されます。
2. **`KNOWN_DOMAINS` に対するドメイン一致** — 公式 API エンドポイントはホスト名で認識されます。
3. **`PATH_PROVIDER_HINTS` に対する URL パスヒント** — UniAPI のようなリレープラットフォームで一般的です。パスに `/claude` または `/anthropic` が含まれている場合、アップストリームプロトコルを示します。
4. **フォールバック** — `openai/` プレフィックス（ジェネリック OpenAI 互換）。

| ドメイン / パス                           | プロバイダープレフィックス | プロトコル                         |
| ----------------------------------- | ------------- | ----------------------------- |
| `api.openai.com`                    | `openai/`     | OpenAI Chat Completions       |
| `anthropic.com`                     | `anthropic/`  | Anthropic Messages API        |
| `generativelanguage.googleapis.com` | `gemini/`     | Google Gemini                 |
| `api.deepseek.com`                  | `deepseek/`   | DeepSeek（OpenAI 互換）           |
| `api.mistral.ai`                    | `mistral/`    | Mistral                       |
| パスに `/claude` または `/anthropic` を含む  | `anthropic/`  | Anthropic Messages API（リレー経由） |
| パスに `/gemini` を含む                   | `gemini/`     | Google Gemini（リレー経由）          |
| その他すべて                              | `openai/`     | ジェネリック OpenAI 互換              |

プロバイダープレフィックスがネイティブプロトコル（anthropic、gemini など）で、URL が公式エンドポイントでない場合、LiteLLM はネイティブプロトコルを使用しますが、リレーの `api_base` にリクエストを送信します。これは、プロバイダー固有の動作（以下で説明する Bedrock プリフィル問題を含む）がリクエストが公式 API に送信されるか、リレー経由で送信されるかに関わらず適用されることを意味します。

<Warning>
  リレー URL のパスに `/claude` が含まれている場合、FIM One は自動的に Anthropic のネイティブプロトコル経由でルーティングします。これは通常正しい選択です（ストリーミングとシンキングサポートが向上）が、プロバイダー固有の動作が適用されることを意味します — 以下で説明する Bedrock プリフィル問題を含みます。
</Warning>

## tool\_choice — 4つのモード

`tool_choice` パラメータは OpenAI 形式で標準化されています。LiteLLM はリクエストを送信する前に、各プロバイダーのネイティブプロトコルに変換します。

| モード                                           | 意味                      | プロバイダーサポート                                  |
| --------------------------------------------- | ----------------------- | ------------------------------------------- |
| `"auto"`                                      | モデルがツール呼び出しまたはテキスト応答を決定 | すべてのプロバイダー                                  |
| `"required"`                                  | ツール呼び出しが必須だが、モデルが選択     | ほとんどのプロバイダー                                 |
| `{"type":"function","function":{"name":"X"}}` | 関数 X の呼び出しが必須           | ほとんどのプロバイダー — **Anthropic thinking と互換性なし** |
| `"none"`                                      | ツール使用不可、テキストのみ          | すべてのプロバイダー                                  |

`"auto"` と強制モード（`{"type":"function",...}`）の区別は、FIM One のあらゆる互換性問題の核心です。これら 2 つのモードは、異なる要件を持つまったく異なるサブシステムで使用されています。

## tool\_choiceが使用される場所

2つのサブシステムが`tool_choice`を使用しており、それらは根本的に異なる方法でそれを使用しています。

### ReAct エンジン — tool\_choice="auto"

ReAct ループでは、モデルが各イテレーションで以下を決定する必要があります: ツールを呼び出すか、最終的な回答を提供するか。ここで意味があるのは `"auto"` だけです — モデルは `tool_calls` を生成するか、テキスト コンテンツを生成するかを自由に選択します。これはすべてのプロバイダー、すべてのモデル、拡張思考を含むすべてのモードと互換性があります。

```mermaid theme={null}
flowchart TD
    A["ReAct iteration"] --> B{"Model decides<br/>(tool_choice=auto)"}
    B -->|"tool_calls present"| C["Execute tool → next iteration"]
    B -->|"text content only"| D["Final answer"]
```

ReAct エンジンは、`abilities["tool_call"] = True` の場合にネイティブ関数呼び出し (`_run_native`) を使用し、それ以外の場合は JSON-in-content モード (`_run_json`) にフォールバックします。両方のモードで `"auto"` を使用します — 違いは、ツールが `tools` パラメータを介して渡されるか、システム プロンプトで説明されるかです。詳細は [ReAct エンジン — デュアルモード実行](/architecture/react-engine#dual-mode-execution) を参照してください。

### structured\_llm\_call — tool\_choice=forced

ワンショット構造化抽出（スキーマアノテーション、DAG計画、計画分析）。モデルに特定の仮想関数を呼び出すことを強制し、構造化JSON出力を保証します。これはプロバイダー固有のエラーをトリガーするコールサイトです。

`structured_llm_call`は3レベルの劣化チェーンを実装します：

```mermaid theme={null}
flowchart TD
    START["structured_llm_call()"] --> L1{"abilities.tool_call<br/>AND tool_choice?"}
    L1 -->|Both true| FC["Level 1: native_fc<br/>forced tool_choice"]
    L1 -->|Either false| L2
    FC -->|"Success"| DONE["Return StructuredCallResult"]
    FC -->|"Fail (catch Exception)"| L2{"abilities.json_mode?"}
    L2 -->|Yes| JM["Level 2: json_mode<br/>response_format=json_object"]
    L2 -->|No| PT["Level 3: plain_text<br/>extract JSON from free text"]
    JM -->|"Success"| DONE
    JM -->|"Fail → retry once"| PT
    PT -->|"Success"| DONE
    PT -->|"Fail → retry once"| ERR["StructuredOutputError<br/>or default_value"]
```

重要な設計上の違い：`structured_llm_call`のフォールバックは**ランタイム**です — 各レベルを動的に試行し、例外をキャッチしてフォールスルーします。ReActエンジンのモード選択は**ビルドタイム**です — 開始時に`_native_mode_active`を一度チェックし、ループ全体で1つのモードにコミットします。つまり、`structured_llm_call`はプロバイダー固有の400エラーから透過的に回復できますが、ReActは事前に正しくモードが選択されていることに依存しています。

## Bedrock プリフィル トラップ

`response_format={"type":"json_object"}` が `anthropic/` プレフィックスで解決されたモデルに渡される場合、LiteLLM は内部的にアシスタント プリフィル メッセージを挿入して JSON モードをシミュレートします。Anthropic Messages API には ネイティブな `response_format` パラメータがないため、LiteLLM は開き括弧をアシスタント コンテンツとして先頭に追加することで近似します：

```json theme={null}
{"role": "assistant", "content": "{"}
```

これは Anthropic の直接 API では機能します。ただし、より新しい AWS Bedrock モデル バージョンは、最後のメッセージが `role: "assistant"` を持つ会話を拒否します。これを「アシスタント メッセージ プリフィル」と呼び、以下をスローします：

```
ValidationException: This model does not support assistant message prefill.
The conversation must end with a user message.
```

このエラーは、**以下の 3 つの条件がすべて同時に満たされる場合**にのみ発生します：

1. モデルが `anthropic/` プレフィックスで解決されている（ドメイン マッチまたは URL パス ヒント経由）。
2. `response_format={"type":"json_object"}` が渡されている（`structured_llm_call` の json\_mode コード パス）。
3. 実際のバックエンドが AWS Bedrock である（プリフィルを拒否）。

<Tip>
  **OpenAI 互換エンドポイント経由の Bedrock？** Bedrock リレーが OpenAI 互換 `/v1/chat/completions` エンドポイント（AWS 独自の OpenAI 互換ゲートウェイまたはサードパーティ プロキシ）を公開し、URL パスに `/claude` または `/anthropic` が含まれていない場合、FIM One は `openai/` プレフィックスで解決します。LiteLLM はバックエンドを標準 OpenAI 互換サーバーとして扱い、プリフィルを挿入せずに `response_format` を直接渡し、サーバーが JSON 制約をネイティブに処理します。**プリフィル トラップは適用されません** — `json_mode_enabled=false` を設定する必要はありません。
</Tip>

<Warning>
  これはネイティブ ツール呼び出し（`tool_choice="auto"` と `tools=` パラメータ）には影響しません。プリフィル挿入は `response_format` に対してのみ発生します。ReAct エージェント実行は完全に影響を受けません。
</Warning>

Level 1（native\_fc）と Level 2（json\_mode）の両方が Bedrock で失敗した場合、システムは Level 3（plain\_text）で復旧します。以下で説明する `json_mode_enabled` フラグは、無駄な Level 2 呼び出しを排除します。

### 修正: json\_mode\_enabled

モデルごとの `json_mode_enabled` フラグは、Level 2 (json\_mode) が試行されるかどうかを制御します:

* **DB設定モデル**: Admin → Models → Advanced settings で切り替え。フラグは `ModelProviderModel.json_mode_enabled` に保存されます (デフォルト `TRUE`)。
* **ENV設定モデル**: 環境で `LLM_JSON_MODE_ENABLED=false` を設定。
* **効果**: 無効にすると、`abilities["json_mode"]` は `False` を返す → `response_format` は渡されない → プリフィルなし → Bedrock が動作。デグラデーションチェーンは `native_fc → plain_text` となり、失敗する json\_mode 呼び出しをスキップします。
* **品質低下なし**: システムプロンプトが JSON を返すよう指示するため、モデルは引き続き有効な JSON を返します。plain\_text レベルは `extract_json()` を使用して自由形式のコンテンツから JSON を解析し、最新のモデルで確実に動作します。

## 思考モデル + 強制 tool\_choice

一部のモデルには拡張思考（思考の連鎖）が永続的に有効になっています。これらの API は強制 `tool_choice` を拒否します。特定の関数呼び出しを強制することは、モデルが最初に推論する自由度と矛盾するためです：

```
tool_choice 'specified' is incompatible with thinking enabled
```

Anthropic はこの制約をプロトコルレベルで実装しており、他の一部のプロバイダー（例：Moonshot AI / Kimi K2.5）も同じパターンに従っています。

Anthropic モデルの場合、`structured_llm_call` は native\_fc を呼び出す際に `reasoning_effort=None` を渡すことで自動的にこれを処理し、その特定の呼び出しの拡張思考を無効にします。構造化出力呼び出しには**スキーマ準拠**が必要であり、深い推論は必要ありません。ここで思考を無効にすることは正しく、かつ有益です（レイテンシーが低く、コストが低い）。

ただし、一部のモデル（例：Kimi K2.5）は思考が永続的にオンになっており、外部から無効にする方法がありません。これらのモデルの場合、native\_fc は常に 400 エラーで失敗し、構造化呼び出しごとに約 10 秒の無駄なレイテンシーが追加されてから、劣化チェーンが json\_mode にフォールスルーします。

### 修正: tool\_choice\_enabled

モデルごとの `tool_choice_enabled` フラグは、Level 1 (native\_fc) が試行されるかどうかを制御します:

* **DB設定モデル**: Admin → Models → Advanced → "Native Function Calling" で切り替え。フラグは `ModelProviderModel.tool_choice_enabled` に保存されます (デフォルト `TRUE`)。
* **ENV設定モデル**: 環境で `LLM_TOOL_CHOICE_ENABLED=false` を設定。
* **効果**: 無効にすると、`abilities["tool_choice"]` は `False` を返す → 劣化チェーンは Level 2 (json\_mode) または Level 3 (plain\_text) から開始され、native\_fc は完全にスキップされます。これにより、互換性のないモデルの構造化呼び出しあたり約10秒のペナルティが排除されます。
* **ReAct エージェントは影響を受けない**: `tool_choice_enabled` は `structured_llm_call` での強制ツール選択のみを制御します。ReAct エンジンは `tool_choice="auto"` (モデルが自由に決定) を使用し、この設定に関係なくすべてのモデルで動作します。

<Note>
  `tool_choice_enabled` と `tool_call` は別の能力フラグです。`tool_call` (`OpenAICompatibleLLM` では常に `True`) は、ツールがモデルに渡されるかどうかを制御します — これを無効にすると ReAct エージェントが破損します。`tool_choice` は、構造化出力抽出のための**強制**ツール選択が試行されるかどうかのみを制御します。
</Note>

`tool_choice="auto"` は思考モードの影響を受けません。ReAct エンジンは `"auto"` のみを使用するため、思考が有効な場合でもエージェント実行は機能します。

<Warning>
  この制約を回避するために `abilities["tool_call"] = False` を設定しないでください。これにより ReAct の `_run_native` モード (`tool_choice="auto"` を使用し、思考で正常に動作) が無効になり、信頼性の低い `_run_json` モードに強制されます。
</Warning>

<Note>
  **プロバイダー移行に関する注記:** 一部のサードパーティリレーは `reasoning_effort` などのサポートされていないパラメータを静かにドロップします (`drop_params=True`)。そのため、設定されていても思考は決してアクティブ化されません。思考を適切にサポートするプロバイダー (Bedrock、直接 Anthropic API) に移行する場合、native\_fc の `reasoning_effort=None` は一貫した動作を保証します。ユーザーアクションは不要です — 構造化出力はすべてのプロバイダーで同じように機能します。
</Note>

## クイックリファレンス: どこで何が機能するか

| シナリオ                        | ReAct モード     | structured\_llm\_call パス                   | 注記                            |
| --------------------------- | ------------- | ------------------------------------------ | ----------------------------- |
| OpenAI（任意のモデル）              | `_run_native` | native\_fc                                 | 完全サポート                        |
| Anthropic（思考なし）             | `_run_native` | native\_fc                                 | 完全サポート                        |
| Anthropic + 思考              | `_run_native` | native\_fc（思考は自動無効）                        | 構造化出力の場合のみ思考を無効化              |
| Bedrock リレー（思考なし）           | `_run_native` | native\_fc                                 | 完全サポート                        |
| Bedrock リレー + 思考            | `_run_native` | native\_fc（思考は自動無効）                        | 構造化出力の場合のみ思考を無効化              |
| Bedrock via OpenAI互換エンドポイント | `_run_native` | native\_fc                                 | 完全サポート — プリフィルの問題なし。上記のヒントを参照 |
| Gemini                      | `_run_native` | native\_fc                                 | 完全サポート                        |
| DeepSeek（非思考）               | `_run_native` | native\_fc                                 | 完全サポート                        |
| DeepSeek R1（思考）             | `_run_native` | json\_mode（`tool_choice_enabled=false`を設定） | 思考は常時オン。native\_fcをスキップ       |
| Kimi K2（非思考）                | `_run_native` | native\_fc                                 | 完全サポート                        |
| Kimi K2.5（思考）               | `_run_native` | json\_mode（`tool_choice_enabled=false`を設定） | 思考は常時オン。native\_fcをスキップ       |
| 汎用 OpenAI互換                 | `_run_native` | native\_fc                                 | 完全サポート                        |
| `tool_call=false`を持つ任意のモデル  | `_run_json`   | json\_mode または plain\_text                 | ツール呼び出しをサポートしないモデルのフォールバック    |

## モデルごとの推奨設定

`tool_choice_enabled` と `json_mode_enabled` は、Admin → Models → Advanced settings でモデルごとにトグル切り替えできます。デフォルト（両方 `TRUE`）はほとんどのプロバイダーで機能します。エラーや不要なレイテンシーが発生した場合のみ調整してください。

| モデルタイプ                     | ネイティブ FC | JSON Mode | 理由                                        |
| -------------------------- | -------- | --------- | ----------------------------------------- |
| OpenAI GPT シリーズ            | ON       | ON        | 完全サポート — デフォルト設定が正しい                      |
| Anthropic Claude           | ON       | ON        | Thinking は native\_fc で自動無効化              |
| Google Gemini              | ON       | ON        | 完全サポート                                    |
| DeepSeek V3 / Coder        | ON       | ON        | 完全サポート                                    |
| **DeepSeek R1 (thinking)** | **OFF**  | ON        | Thinking は常時オン; native\_fc は拒否            |
| **Kimi K2.5 (thinking)**   | **OFF**  | ON        | Thinking は常時オン; native\_fc は拒否            |
| Kimi K2 (non-thinking)     | ON       | ON        | 完全サポート                                    |
| **AWS Bedrock リレー**        | ON       | **OFF**   | Bedrock は json\_mode でのアシスタント prefill を拒否 |
| 弱い / 小規模モデル                | OFF      | OFF       | plain\_text 抽出に直接進む                       |

<Tip>
  **変更時期：** ログに `structured_llm_call: native_fc call raised` 警告が表示され、その後 json\_mode 抽出が成功する場合、そのモデルは native\_fc の恩恵を受けていません。そのモデルの「Native Function Calling」を無効化して、無駄な API 呼び出し（構造化出力リクエストあたり約 10 秒）を排除してください。
</Tip>

**ENV レベルのオーバーライド** は、環境変数経由で設定されたすべてのモデルに適用されます（admin UI ではなく）:

```bash theme={null}
# Disable native_fc globally (for thinking-model-only deployments)
LLM_TOOL_CHOICE_ENABLED=false

# Disable json_mode globally (for Bedrock relay deployments)
LLM_JSON_MODE_ENABLED=false
```

## 推論努力と思考設定

FIM One は、拡張思考/推論を制御するための 2 つの環境変数を公開しています:

| 変数                            | 値                       | 効果                                                                                                                                           |
| ----------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `LLM_REASONING_EFFORT`        | `low`, `medium`, `high` | LiteLLM に `reasoning_effort` として渡されます。Anthropic: `thinking` パラメータにマップされます。OpenAI o シリーズ: そのまま渡されます。その他: サイレントにドロップされます (`drop_params=True`)。 |
| `LLM_REASONING_BUDGET_TOKENS` | 整数 (例: `10000`)         | Anthropic のみ: 明示的な `thinking.budget_tokens` キャップを設定し、LiteLLM の自動マッピングをバイパスします。Claude モデルのコスト制御に便利です。                                         |

`reasoning_effort` が設定され、モデルが `anthropic/` として解決される場合、以下の 2 つの追加動作が適用されます:

1. **温度は 1.0 に強制されます。** Bedrock は思考が有効な場合、`temperature != 1.0` を拒否します。FIM One はこれを自動的に処理します — ユーザーアクションは不要です。
2. **GPT-5.x とツール**: `tools` が存在する場合、`reasoning_effort` はサイレントにドロップされます。これは GPT-5 の `/v1/chat/completions` エンドポイントがこの組み合わせを拒否するためです。これは ReAct ツールループにのみ影響します。`tools` パラメータを持たない `structured_llm_call` 呼び出しは影響を受けません。

## 構造化出力の防御的パース

native\_fcが正しく動作している場合でも、構造化出力パイプラインには、任意のプロバイダーまたは互換性レイヤーからのエッジケースを処理するための防御的パース層が含まれています。

DAGプランナーの`_dict_to_steps`パーサーは、3つの一般的なエッジケースを処理します:

1. **配列の代わりに単一オブジェクト。** 一部のモデルは`{"steps": [{"id": "1", "task": "..."}]}`（配列）の代わりに`{"steps": {"id": "1", "task": "..."}}`（単一ステップオブジェクト）を返します。パーサーは`id`または`task`キーをチェックしてこれを検出し、オブジェクトをリストでラップします。

2. **ダブルエンコードされたJSON文字列。** 構造化出力がスキーマ強制を欠くjson\_modeにフォールバックする場合、一部のプロバイダーは`steps`値をネイティブ配列ではなくJSON文字列として返します。例えば`{"steps": "[{\"id\": \"1\", ...}]"}`です。この文字列には、標準的な`json.loads`を破壊するモデルのフォーマットからのリテラル改行も含まれる場合があります。パーサーは`extract_json_value()`（`_repair_json_strings`を含む）を使用して以下を処理します:
   * JSON文字列値内のリテラル改行
   * 無効なエスケープシーケンス（LaTeXまたはコードコンテンツで一般的）
   * 互換性レイヤーからの他のシリアライゼーション特性

3. **`steps`ラッパーの欠落。** モデルは`steps`ラッパーキーなしでトップレベルオブジェクトとして単一ステップを返す場合があります。パーサーはルートレベルで`id`と`task`を検出し、それに応じてラップします。

<Note>
  通常の動作では、native\_fcは適切に構造化されたツール呼び出し引数を返し、これらのエッジケースは発生しません。防御的パーサーは、カスタム`BaseLLM`サブクラス、異常なプロバイダー動作、または構造化出力がjson\_modeまたはplain\_textに低下するフォールバックシナリオのための安全ネットとして存在します。
</Note>

## プロンプトキャッシング（クロスプロバイダー）

FIM One は Anthropic の明示的なプロンプトキャッシング（`cache_control` ブレークポイント経由）を実装し、同時に**プロンプトセクションレジストリ**を通じて他のすべてのプロバイダーの自動プレフィックスキャッシングの恩恵を受けます。目標は、呼び出しごとのプロンプト形状の相違なく、すべてのプロバイダーで機能する単一のプロンプト組立パスです。

### アーキテクチャ

`fim_one.core.prompt` モジュールは3つのプリミティブを公開しています：

* **`PromptSection`** — 静的な `content: str` または動的な `content: Callable` を持つ名前付きフラグメント
* **`PromptRegistry`** — メモ化されたストア（静的セクションは1回レンダリングされ、動的セクションはコール毎に再レンダリングされます）
* **`DYNAMIC_BOUNDARY`** — レジストリが最後の静的セクションと最初の動的セクションの間に挿入するセンチネルマーカー。呼び出し元がキャッシュ破断点でレンダリングされた提示词を分割できるようにします

ReAct のシステム提示词（JSON モード、ネイティブ関数呼び出しモード、合成）は以下に分割されます：

* **静的プレフィックス**（提示词の約95%）— アイデンティティ、コアガイドライン、ツール説明
* **動的サフィックス** — 現在の日時、リクエスト毎の言語指示、ハンドオフコンテキスト

### キャパビリティ検出

`fim_one.core.prompt.caching.is_cache_capable(model_id)` は、モデル ID に `claude`、`anthropic`、`bedrock/anthropic`、`vertex_ai/claude` のいずれかが含まれている場合に `True` を返します。これらのプロバイダーは、最初の（静的な）メッセージに `cache_control: {"type": "ephemeral"}` を付けた **2 つ** の `role="system"` メッセージを受け取ります。

その他すべてのプロバイダーは、`cache_control` フィールドなしの **単一の** 連結されたシステムメッセージを受け取ります。これは、Anthropic 以外のエンドポイントがこのフィールドを拒否するか暗黙的に削除するため、また一部のリレーを通じて送信すると `400 unknown parameter` エラーが発生するため、必要です。

### クロスプロバイダーカバレッジ

| プロバイダー                           | メカニズム                          | 読み取り割引      | 当社の対応                                              |
| -------------------------------- | ------------------------------ | ----------- | -------------------------------------------------- |
| **Anthropic Claude** (3, 3.5, 4) | 明示的な `cache_control`           | 0.10×       | 一時的なブレークポイント付きの2つのシステムメッセージ                        |
| **AWS Bedrock Anthropic**        | Anthropic キャッシュをパススルー          | 0.10×       | Anthropic と同じ                                      |
| **GCP Vertex AI Claude**         | Anthropic キャッシュをパススルー          | 0.10×       | Anthropic と同じ                                      |
| **OpenAI GPT / o-series**        | 自動プレフィックスハッシュ (≥1024 tokens)   | 0.50×       | Section Registry 経由のバイト安定プレフィックス → 自動ヒット           |
| **DeepSeek (v3 / R1)**           | 自動ディスク バックアップ プレフィックスキャッシュ     | 0.10×       | OpenAI と同じ                                         |
| **Moonshot Kimi (K1/K2)**        | 自動プレフィックスキャッシュ                 | 0.10×/0.50× | 同じ                                                 |
| **ZhipuAI GLM-4.5+**             | 自動ロングコンテキストキャッシュ               | 0.20×       | 同じ                                                 |
| **Grok (xAI)**                   | 自動プレフィックスキャッシュ                 | 0.25×       | 同じ                                                 |
| **Google Gemini**                | 独立した `createCachedContent` API | 0.25×       | **未実装** — v0.9 ロードマップで `GeminiCacheAdapter` として追跡中 |
| **Mistral / Cohere**             | ネイティブキャッシュなし                   | N/A         | N/A                                                |

`PromptRegistry` は、静的部分をコール間でバイト単位で同一に保つことで (現在の日時は動的サフィックスに存在し、プレフィックスには存在しない)、すべての自動キャッシュプロバイダーのハッシュが一致してキャッシュヒットするため、すべてのプロバイダーに「無料」で自動プレフィックスキャッシュの利点をもたらします。これが、Anthropic 固有の `cache_control` を検討する前でも、Registry が基礎的なモデルレスの勝利である理由です。

### 可観測性

すべての `chat/*` レスポンスの `done_payload` に以下が含まれるようになりました:

```json theme={null}
"cache": {
  "read_tokens": 1067,
  "creation_tokens": 0
}
```

`TurnProfiler` はターンごとに構造化ログ行を出力します: `turn_cache summary | model=claude-sonnet-4-6 | read_tokens=1067 | create_tokens=0 | saved_input_tokens=961 (~90%)`。これは**リレー正直性プローブ**としても機能します — API リレーを経由してルーティングする場合、実際に請求された入力トークンと `read_tokens` を比較して、リレーが `cache_control` を削除しているか、0.10× の割引を保持しているかを検出できます。

LLM レイヤーではドル推定値は返されません — 価格設定とリレー マークアップはその上で適用されるため、LLM レイヤーは客観的なトークン数のみを返します。

### マルチターンキャッシュ ROI

Claude 4 ReAct ターンでデフォルトエージェント提示词で測定:

| モード                 | 静的プレフィックストークン | 動的サフィックストークン | キャッシュ比率 |
| ------------------- | ------------- | ------------ | ------- |
| JSON モード、ツールなし      | \~753         | \~46         | 94.2%   |
| JSON モード、\~10 ツール付き | \~1067        | \~46         | 95.9%   |
| ネイティブ関数呼び出し         | \~523         | \~46         | 91.9%   |

10 ツール付きの 10 イテレーション ReAct 実行は、最初のターン後、ターンあたり \~8,640 入力トークンを節約します (9 キャッシュヒット × 1067 トークン × 90%)。Anthropic は最初の呼び出しでキャッシュ書き込みに 1.25 倍の料金を請求するため、損益分岐点は**2 番目**の呼び出しです — シングルショットクエリは利益を得ません。

## 推理重放策略（无模型正确性）

Extended thinking / reasoning blocks 在不同提供商之间的行为不同。统一的序列化策略会破坏协议契约和自动前缀缓存。`fim_one.core.prompt.reasoning.reasoning_replay_policy(model_id)` 返回三个值之一，并在 `OpenAICompatibleLLM._build_request_kwargs()` 中控制 `ChatMessage.to_openai_dict(replay_policy=...)` 的行为。

### 3つのポリシー

* **`anthropic_thinking`** — Claude ファミリー（`anthropic/`、`bedrock/anthropic`、`vertex_ai/claude` を含む）。思考ブロックは `signature` を付けて再生する必要があります。Anthropic は署名が欠落または変更されている場合、後続のターンを拒否します。
* **`informational_only`** — CoT を出力しますが再生を期待しないモデル：DeepSeek R1 / R1-Distill、Qwen QwQ、Gemini 2.x thinking、OpenAI o1 / o3 / o4。これらのドキュメントは「メッセージ履歴に `reasoning_content` を送信しないでください」と明示しています。それでも送信する場合：
  * プロバイダー契約に違反します（将来のバージョンで拒否が開始される可能性があります）
  * **自動プレフィックスキャッシュをサイレントに無効化します** — メッセージバイトがターンごとに変更され、ハッシュが破損します
* **`unsupported`** — 推理機能のないモデル（GPT-4o、GPT-4 Turbo、Gemini 1.5、Mistral、Llama）。再生する CoT がなく、フィールドは表示されません。このポリシーは、未知のモデル ID に対しても安全なデフォルトです。

### 実装

すべてのポリシー評価は1つの場所（`_build_request_kwargs`）で行われます。`ChatMessage.to_openai_dict(replay_policy=None)`はA3の寛容なデフォルトを保持するため、調整されていない呼び出し元は回帰しません。クロスプロバイダーテストマトリックスは`tests/test_reasoning_replay_policy.py`に存在し、**逆アサーション**によって非Anthropicリクエストが`reasoning_content`をリークしないことを証明しています。

### ユーザー向け

機能とバグの動作は自動的です — 何も設定する必要はありません。ワークフローへの影響：

* **同じ会話内でClaudeとDeepSeekの間でエージェントを切り替える場合**、履歴は思考ブロックをそのまま保存されます。次のターンで、送信メッセージの形状は現在のモデルに適応します。
* **プロキシ / カスタム `BaseLLM` サブクラスを使用する場合**、そのモデルIDが認識可能であることを確認してください（フラグメントの1つを含む）。そうでない場合、デフォルトの `unsupported` ポリシーが適用されます — これは安全ですが、異常なプロキシの背後にあるClaudeが思考リプレイを失う可能性があります。モデルIDフラグメントを `_CACHE_CAPABLE_MODEL_FRAGMENTS`（`core/prompt/caching.py` 内）および/または推理ポリシー検索に追加してください。

## トラブルシューティング

**"This model does not support assistant message prefill"**
Bedrock + json\_mode。2つの修正方法があります：(1) `LLM_JSON_MODE_ENABLED=false` を設定するか、管理者モデル設定で JSON Mode を無効にする、または (2) Bedrock プロバイダーが OpenAI 互換の `/v1/chat/completions` エンドポイントを提供している場合は、それに切り替えてください——FIM One はそれを `openai/` として解決し、prefill インジェクションは発生しません。

**"Thinking may not be enabled when tool\_choice forces tool use"** / **"tool\_choice 'specified' is incompatible with thinking enabled"**
Anthropic モデルの場合、`structured_llm_call` は native\_fc 呼び出しの思考を自動的に無効にします。常時有効な思考を持つ他のプロバイダー（例：Kimi K2.5）の場合は、モデルの詳細設定で「Native Function Calling」を無効にするか、グローバルに `LLM_TOOL_CHOICE_ENABLED=false` を設定してください。劣化チェーンは native\_fc をスキップし、代わりに json\_mode または plain\_text を使用して構造化出力を抽出します。

**"DAG pipeline failed: LLM 'steps' is not an array"**
LLM が `steps` フィールドを文字列または単一オブジェクトとして返しました。これは通常、構造化出力が json\_mode にフォールバックしたことを意味します（スキーマ強制がありません）。ログで `structured_llm_call: level=xxx` を確認してください——`native_fc` ではなく `json_mode` が表示されている場合、native\_fc は無音で失敗しています。カスタム `BaseLLM` サブクラスを使用している場合は、`reasoning_effort` kwarg を受け入れることを確認してください。

**ReAct が予期せず JSON mode にフォールバックする**
モデルの `abilities["tool_call"]` が `True` であることを確認してください。これは `OpenAICompatibleLLM` では常に `True` ですが、カスタム `BaseLLM` サブクラスはそれをオーバーライドする可能性があります。管理者 API のモデル詳細エンドポイントで確認してください。

**structured\_llm\_call がすべてのレベルを消費して StructuredOutputError を発生させる**
モデルはどのレベルでも解析可能な JSON を生成できませんでした。これは最新のモデルではまれです。確認してください：(1) スキーマが有効な JSON Schema である、(2) モデルが完全な応答を生成するのに十分な `max_tokens` を持っている、(3) システムプロンプトがスキーマ指示と矛盾していない。DAG プランナーとアナライザーの両方が `default_value` フォールバックを提供するため、このエラーは明示的にデフォルトを省略した呼び出しサイトからのみ伝播します。
