プロバイダー検出
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。
解決順序:
- 明示的なプロバイダー(DB の
ModelConfig.providerフィールドから)— 最優先。プロバイダーが URL 内の既知ドメインと一致する場合、api_baseは返されません(LiteLLM はネイティブでルーティング)。それ以外の場合、api_baseはリレー URL に設定されます。 KNOWN_DOMAINSに対するドメイン一致 — 公式 API エンドポイントはホスト名で認識されます。PATH_PROVIDER_HINTSに対する URL パスヒント — UniAPI のようなリレープラットフォームで一般的です。パスに/claudeまたは/anthropicが含まれている場合、アップストリームプロトコルを示します。- フォールバック —
openai/プレフィックス(ジェネリック OpenAI 互換)。
プロバイダープレフィックスがネイティブプロトコル(anthropic、gemini など)で、URL が公式エンドポイントでない場合、LiteLLM はネイティブプロトコルを使用しますが、リレーの
api_base にリクエストを送信します。これは、プロバイダー固有の動作(以下で説明する Bedrock プリフィル問題を含む)がリクエストが公式 API に送信されるか、リレー経由で送信されるかに関わらず適用されることを意味します。
tool_choice — 4つのモード
tool_choice パラメータは OpenAI 形式で標準化されています。LiteLLM はリクエストを送信する前に、各プロバイダーのネイティブプロトコルに変換します。
"auto" と強制モード({"type":"function",...})の区別は、FIM One のあらゆる互換性問題の核心です。これら 2 つのモードは、異なる要件を持つまったく異なるサブシステムで使用されています。
tool_choiceが使用される場所
2つのサブシステムがtool_choiceを使用しており、それらは根本的に異なる方法でそれを使用しています。
ReAct エンジン — tool_choice=“auto”
ReAct ループでは、モデルが各イテレーションで以下を決定する必要があります: ツールを呼び出すか、最終的な回答を提供するか。ここで意味があるのは"auto" だけです — モデルは tool_calls を生成するか、テキスト コンテンツを生成するかを自由に選択します。これはすべてのプロバイダー、すべてのモデル、拡張思考を含むすべてのモードと互換性があります。
ReAct エンジンは、abilities["tool_call"] = True の場合にネイティブ関数呼び出し (_run_native) を使用し、それ以外の場合は JSON-in-content モード (_run_json) にフォールバックします。両方のモードで "auto" を使用します — 違いは、ツールが tools パラメータを介して渡されるか、システム プロンプトで説明されるかです。詳細は ReAct エンジン — デュアルモード実行 を参照してください。
structured_llm_call — tool_choice=forced
ワンショット構造化抽出(スキーマアノテーション、DAG計画、計画分析)。モデルに特定の仮想関数を呼び出すことを強制し、構造化JSON出力を保証します。これはプロバイダー固有のエラーをトリガーするコールサイトです。structured_llm_callは3レベルの劣化チェーンを実装します:
重要な設計上の違い: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 は開き括弧をアシスタント コンテンツとして先頭に追加することで近似します:
role: "assistant" を持つ会話を拒否します。これを「アシスタント メッセージ プリフィル」と呼び、以下をスローします:
- モデルが
anthropic/プレフィックスで解決されている(ドメイン マッチまたは URL パス ヒント経由)。 response_format={"type":"json_object"}が渡されている(structured_llm_callの json_mode コード パス)。- 実際のバックエンドが AWS Bedrock である(プリフィルを拒否)。
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
複数のプロバイダーは、拡張思考がアクティブな状態で強制tool_choice を拒否します。特定の関数呼び出しをピン留めすることが、モデルが最初に推論する自由と矛盾するという理由からです:
structured_llm_call はネイティブ FC レベルで reasoning_effort=None を渡すことで競合を自動的に解決し、その 1 つの呼び出しで思考をオフにします(structured.py::_call_llm)。構造化出力にはスキーマ準拠が必要であり、深い推論は不要なため、ここで思考を無効にすることは正しく、かつより安価です。
API を通じて思考をオフにできない場合、native_fc はすべての構造化呼び出しで 400 で失敗し、チェーンが json_mode にフォールスルーする前に約 10 秒かかります。Kimi が一般的なケースです。思考がオンの場合、auto のみがサポートされ、強制ツール選択には思考をオフにする必要があります。Moonshot はこれをモデル ID を通じてのみ公開しています(kimi-k2 はオフ、kimi-k2.5 と kimi-k2-thinking はオン)。FIM One にはそれを切り替えるパラメータがないため、以下の tool_choice_enabled フラグが対策です。
修正: 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"(モデルが自由に決定) を使用し、この設定に関係なくすべてのモデルで動作します。
tool_choice_enabled と tool_call は別の能力フラグです。tool_call (OpenAICompatibleLLM では常に True) は、ツールがモデルに渡されるかどうかを制御します — これを無効にすると ReAct エージェントが破損します。tool_choice は、構造化出力抽出のための強制ツール選択が試行されるかどうかのみを制御します。tool_choice="auto" は思考モードの影響を受けません。ReAct エンジンは "auto" のみを使用するため、思考が有効な場合でもエージェント実行は機能します。
プロバイダー移行に関する注記: 一部のサードパーティリレーは
reasoning_effort などのサポートされていないパラメータを静かにドロップします (drop_params=True)。そのため、設定されていても思考は決してアクティブ化されません。思考を適切にサポートするプロバイダー (Bedrock、直接 Anthropic API) に移行する場合、native_fc の reasoning_effort=None は一貫した動作を保証します。ユーザーアクションは不要です — 構造化出力はすべてのプロバイダーで同じように機能します。プロバイダー機能マトリックス
このセクションは、各プロバイダーが何をサポートしており、FIM Oneがそれについて何をするかの信頼できる記録です。すべての行は動作を実装する関数に名前を付けているため、ここでの主張はコードに対して確認できます。他のページはデータを繰り返す代わりにここにリンクしています。コードが変わると、このセクションも変わります。 行は単一のモデルではなく、プロバイダーのプロトコルを説明しています。1つのファミリー内のモデルが異なる場合(DeepSeek chatと推論器、Kimiは思考をオンにするかオフにするか)、セルはそのことを示しています。Table A: プロトコルルーティング
設定されたbase_url と model がどのように LiteLLM 呼び出しになるか、また最初に選択したインターフェースが利用できない場合に何が起こるかを示します。
GPT-5.x がプロトコルを選択する方法。
FIM_GPT5_RESPONSES_MODE がこれを選択します:native(デフォルト)は /v1/responses を litellm.aresponses 経由で直接使用し、bridge は LiteLLM のチャット完了翻訳を使用し、off は通常のチャット完了を強制します。ネイティブパスが存在するのは、ブリッジが重要な 1 つの場所で損失があるためです:推論項目を破棄するため、GPT-5.x エージェントはツールラウンドのたびに思考の連鎖を再導出します。プロトコルを直接使用すると、これらの項目を再生できます。reasoning_effort=None を明示的に渡す呼び出し(これは structured_llm_call と完了シグナルプローブが行うこと)は、チャット完了にとどまります。思考を望まない呼び出しには保持する推論状態がないためです。
そのネイティブリクエストの 2 つのプロパティは重要で、間違えやすいものです:
store=falseは会話をアップストリームでステートレスに保ち、include=["reasoning.encrypted_content"]は暗号化されたペイロードが返されるよう要求します。include がないと、推論項目は空で到着し、再生はサイレントに no-op になります。- 再生された推論項目は、サーバー側の
idを削除する必要があります。store=falseではアップストリームに何も保持されないため、id をエコーバックするとItem with id 'rs_...' not found. Items are not persisted when 'store' is set to falseが返されます。encrypted_contentブロブはそれ自体で状態を保持するため、id を削除しても何も失われません(sanitize_reasoning_item)。
anthropic/ ルーティングされたリレー経由でアクセスされると、LiteLLM の json-mode アシスタントプリフィルを含む Anthropic プロトコル動作を継承し、より新しい Bedrock バージョンはこれを拒否します。OpenAI 互換ゲートウェイ経由でアクセスされると、openai/ として解決され、プリフィルは注入されず、json_mode_enabled はオンのままにできます。
Table B: 競合と回避策
FIM Oneは4つのtool_choice状態のうち3つを発行します:ReACtループからのauto(react.py::_run_native)、構造化出力からの名前付き関数(structured.py::_call_llm)、および終了シグナル応答がツールペイロードを再生するときのnone。呼び出しサイトはrequiredを発行しません。その列はプロバイダーのauto以外のツール選択に対する制約を記録しており、requiredと名前付き関数の両方に適用されます。
Table C: 思考プロトコル
LLM_REASONING_EFFORTはlow、medium、highを受け入れます。その他の値は未設定として読み込まれます(deps.py::_reasoning_effort)。FIM Oneがワイヤに送信するのはプロバイダごとであり、このテーブルはそれを記録します。replayカラムはreasoning_replay_policyの戻り値で、プロバイダごとのリストではなく、4つの状態の小さなクローズドセットです。
unsupportedとinformational_onlyはワイヤ上で同じバイトを生成します。どちらも発信履歴からreasoning_contentとsignatureを削除します。意図が異なるため、明らかに推論するがランディングがunsupportedのモデルは、ライブバグではなくフラグメントテーブルのギャップです。
Relay/proxy gotchas
Third-party gateways fail in ways a direct provider does not, and most of those failures are silent. Each row below pairs the symptom with its mechanism and with what FIM One already does about it.Support boundary. FIM One guarantees the behaviour documented on this page for first-party endpoints: OpenAI’s own API, Anthropic, Google, and any vendor serving its own models directly. Third-party relays are supported on a best-effort basis and are not covered by that guarantee, because what a relay does to a request is outside our control and frequently outside its own documentation. A relay can drop a parameter, rewrite history, strip a cache breakpoint, or answer a protocol it only partially implements, and in most of those cases it returns a
200 rather than an error.This is a statement about what we promise, not a restriction on what runs. FIM One does not maintain an allowlist of approved hosts, and nothing here is gated on a domain. Capability is decided by what an endpoint actually does: a missing route answers 404 and is remembered, an ignored include yields empty reasoning items and the replay becomes a no-op, and a rejected request falls back for that call. Probing the endpoint is more accurate than inferring its capabilities from its hostname, and it is the only approach that keeps working for Azure OpenAI, enterprise gateways, and self-hosted proxies that implement the protocol correctly.If a relay misbehaves in a way the fallbacks do not catch, pin the protocol yourself with FIM_GPT5_RESPONSES_MODE (bridge or off) or the per-model tool_choice_enabled and json_mode_enabled toggles, and reproduce against the first-party endpoint before filing it as a FIM One bug.モデルごとの推奨設定
tool_choice_enabledとjson_mode_enabledは、Admin → Models → Advanced settingsでモデルごとにトグル切り替えできます。デフォルト値はどちらもTRUEで、ほとんどのプロバイダーに適切です。エラーやレイテンシーの無駄が見られる場合のみ調整してください。調整が必要なプロバイダーは上記の表Bに記載されており、オペレーターが入力するモデルごとのビューはModel Managementにあります。
ENV レベルのオーバーライド は、環境変数経由で設定されたすべてのモデルに適用されます(Admin UIではなく):
推理努力度と思考設定
FIM Oneは、拡張思考/推理を制御するための2つの環境変数を公開しています:
思考がオンになると、以下の2つの動作が自動的に実行され、ユーザー設定は不要です:
- 温度は自動的に処理されます。 思考がアクティブな
anthropic/ルートでは、_build_request_kwargsはtemperatureを1.0に固定します。これはBedrockが要求する値です。サンプリングパラメータを完全に拒否するモデル(Opus 4.7および4.8、Fable 5、Mythos 5)は、思考の有無にかかわらず、リクエストからtemperatureが削除されます。このためにLLM_TEMPERATURE=1を手動で設定しないでください。 - GPT-5.xは可能な限りツールと推理を一緒に保ちます。 FIM Oneは、GPT-5.xの場合、Responses ブリッジを最初にプローブします。これが2つが組み合わさる唯一のサーフェスだからです。使用可能な
/v1/responsesルートがないエンドポイントはチャット補完にフォールバックし、判定はエンドポイントごとにキャッシュされます。そのパスでtoolsを含むリクエストは、明示的なreasoning_effortとしてnoneを送信します。フィールドを省略することは同等ではありません。サーバーのデフォルトがnoneではないからです。
構造化出力の防御的パース
native_fcが正しく動作している場合でも、構造化出力パイプラインには、任意のプロバイダーまたは互換性レイヤーからのエッジケースを処理するための防御的パース層が含まれています。 DAGプランナーの_dict_to_stepsパーサーは、3つの一般的なエッジケースを処理します:
-
配列の代わりに単一オブジェクト。 一部のモデルは
{"steps": [{"id": "1", "task": "..."}]}(配列)の代わりに{"steps": {"id": "1", "task": "..."}}(単一ステップオブジェクト)を返します。パーサーはidまたはtaskキーをチェックしてこれを検出し、オブジェクトをリストでラップします。 -
ダブルエンコードされたJSON文字列。 構造化出力がスキーマ強制を欠くjson_modeにフォールバックする場合、一部のプロバイダーは
steps値をネイティブ配列ではなくJSON文字列として返します。例えば{"steps": "[{\"id\": \"1\", ...}]"}です。この文字列には、標準的なjson.loadsを破壊するモデルのフォーマットからのリテラル改行も含まれる場合があります。パーサーはextract_json_value()(_repair_json_stringsを含む)を使用して以下を処理します:- JSON文字列値内のリテラル改行
- 無効なエスケープシーケンス(LaTeXまたはコードコンテンツで一般的)
- 互換性レイヤーからの他のシリアライゼーション特性
-
stepsラッパーの欠落。 モデルはstepsラッパーキーなしでトップレベルオブジェクトとして単一ステップを返す場合があります。パーサーはルートレベルでidとtaskを検出し、それに応じてラップします。
通常の動作では、native_fcは適切に構造化されたツール呼び出し引数を返し、これらのエッジケースは発生しません。防御的パーサーは、カスタム
BaseLLMサブクラス、異常なプロバイダー動作、または構造化出力がjson_modeまたはplain_textに低下するフォールバックシナリオのための安全ネットとして存在します。プロンプトキャッシング(クロスプロバイダー)
FIM One は Anthropic の明示的なプロンプトキャッシング(cache_control ブレークポイント経由)を実装し、同時にプロンプトセクションレジストリを通じて他のすべてのプロバイダーの自動プレフィックスキャッシングの恩恵を受けます。目標は、呼び出しごとのプロンプト形状の相違なく、すべてのプロバイダーで機能する単一のプロンプト組立パスです。
アーキテクチャ
fim_one.core.prompt モジュールは3つのプリミティブを公開しています:
PromptSection— 静的なcontent: strまたは動的なcontent: Callableを持つ名前付きフラグメントPromptRegistry— メモ化されたストア(静的セクションは1回レンダリングされ、動的セクションはコール毎に再レンダリングされます)DYNAMIC_BOUNDARY— レジストリが最後の静的セクションと最初の動的セクションの間に挿入するセンチネルマーカー。呼び出し元がキャッシュ破断点でレンダリングされた提示词を分割できるようにします
- 静的プレフィックス(提示词の約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 エラーが発生するため、必要です。
クロスプロバイダーカバレッジ
PromptRegistry は、静的部分をコール間でバイト単位で同一に保つことで (現在の日時は動的サフィックスに存在し、プレフィックスには存在しない)、すべての自動キャッシュプロバイダーのハッシュが一致してキャッシュヒットするため、すべてのプロバイダーに「無料」で自動プレフィックスキャッシュの利点をもたらします。これが、Anthropic 固有の cache_control を検討する前でも、Registry が基礎的なモデルレスの勝利である理由です。
可観測性
すべてのchat/* レスポンスの done_payload に以下が含まれるようになりました:
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 ターンでデフォルトエージェント提示词で測定:
10 ツール付きの 10 イテレーション ReAct 実行は、最初のターン後、ターンあたり ~8,640 入力トークンを節約します (9 キャッシュヒット × 1067 トークン × 90%)。Anthropic は最初の呼び出しでキャッシュ書き込みに 1.25 倍の料金を請求するため、損益分岐点は2 番目の呼び出しです — シングルショットクエリは利益を得ません。
推論リプレイポリシー(モデルレス正確性)
拡張思考/推論ブロックはプロバイダー間で異なる動作をします。統一されたシリアライゼーションポリシーはプロトコルコントラクトと自動プレフィックスキャッシュの両方を破壊します。fim_one.core.prompt.reasoning.reasoning_replay_policy(model_id) は4つの値のいずれかを返し、OpenAICompatibleLLM._build_request_kwargs() 内の ChatMessage.to_openai_dict(replay_policy=...) をゲートします。
4つのポリシー
anthropic_thinking— Claude ファミリー(anthropic/、bedrock/anthropic、vertex_ai/claudeを含む)。思考ブロックはsignatureを付けて必ずリプレイする必要があります。Anthropic は署名がない場合または変更された場合、後続のターンを拒否します。informational_only— CoT を出力しますが、リプレイを期待しないモデル:DeepSeek 推論モード(V3.2 のdeepseek-reasoner、および古いdeepseek-r1と R1-Distill ID はフラグメントテーブルが一致)、Qwen QwQ、Gemini flash-thinking、OpenAI o1 / o3 / o4。ドキュメントでは明確に「メッセージ履歴にreasoning_contentを送信しないでください」と述べられています。それでも送信した場合:- プロバイダー契約に違反します(将来のバージョンで拒否を開始する可能性があります)
- 自動プレフィックスキャッシュを静かに無効化します — メッセージバイトはターンごとに変更され、ハッシュが破損します
openai_responses— GPT-5.x、gpt-5フラグメントでマッチします。その推論状態はテキストではなく、暗号化されたペイロードを含む不透明なアイテムのシーケンスであり、/v1/responsesだけがそれらのスロットを持ちます。そのプロトコルでは、アイテムはそのままリプレイされ、これがツールラウンド全体でモデルの思考の連鎖を保つものです。読み取り可能なサマリーは依然として送信リクエストから削除されるため、chat-completions フォールバックではこれはinformational_onlyと全く同じように動作します。汎用のreasoningエントリがプロキシタグ付き GPT-5 ID を吸収する可能性がある情報フラグメントの前にチェックされます。unsupported— キャッチオール:推論機能のないモデル(GPT-4o、Gemini 1.5、Mistral、Llama)、および ID がフラグメントと一致しない推論モデル(GLM、MiniMax、Kimi、Doubao)。どちらの方法でもフィールドをリプレイしないため、このポリシーはinformational_onlyと同じバイト列をワイヤに配置します。また、不明なモデル ID の安全なデフォルトでもあります。
reasoning_content と不透明な reasoning_items は ChatMessage 上の独立したフィールドです。to_openai_dict() はアイテムを全くシリアライズしないため、ポリシーが何を言おうとも、構造的に chat-completions リクエストにリークすることは不可能です。
実装
すべてのポリシー評価は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 や kimi-k2-thinking、deepseek-reasoner など API を通じて思考をオフにできない場合は、モデルの詳細設定で「Native Function Calling」を無効にするか、グローバルに LLM_TOOL_CHOICE_ENABLED=false を設定してください。劣化チェーンは native_fc をスキップし、代わりに json_mode または plain_text を使用して構造化出力を抽出します。思考モデルがこの問題を持つと仮定する前に、Provider Capability Matrix の表 B を確認してください。MiniMax はこの問題を持ちません。
“DAG pipeline failed: LLM ‘steps’ is not an array”
LLM が steps フィールドを文字列または単一オブジェクトとして返しました。これは通常、構造化出力が json_mode にフォールバックしたことを意味します(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 フォールバックを提供するため、このエラーは明示的にデフォルトを省略した呼び出しサイトからのみ伝播します。