オープンモデルでの実行
モデル層をエージェント層から切り離しておく仕組み — 能力のプローブ、マルチバックエンドのルーティング、そして小さなオープンモデルがツール呼び出しで壊れる4つのパターンをゲートウェイが肩代わりする方法。
ここでのエージェントは、特定のモデルに合わせて書かれていません。エージェント層が必要とするもの — チャット、埋め込み、ツール呼び出し — はすべて、OpenAI互換のHTTPの形をしゃべるゲートウェイを経由します。だからその背後のモデルは、ホスト型のフロンティアAPIでも、あなた自身が動かすオープンモデルでも、あるいは複数を同時に使うこともできます。
このページは、その主張の裏にあるエンジニアリングの詳細です。「オープンモデルに対応」と言うのは簡単でも検証するのは難しく、プラットフォームを評価する人がそれを問うのは正当だからこそ、このページがあります。
ゲートウェイ
バックエンドはテーブルの行であり、テナントごとにスコープされます。それぞれがベースURL、APIキー、モデル名、種別(chat または embedding)、そして重みを持ちます。追加や差し替えは設定変更であり、デプロイもエージェントの書き換えも不要です。
依存関係ツリーのどこにもベンダーSDKはありません。ゲートウェイはOpenAI互換の表面に対して素のHTTPを発行します。だからその表面を実装するもの — vLLM、Ollama、llama.cppサーバー、大半の商用API — はアダプターコードなしで動きます。
能力は仮定せず、プローブする
起動時、ゲートウェイは有効なバックエンドの /v1/models を呼び、そのモデルが実際に何を提供するのか — コンテキストウィンドウ、埋め込み次元、宣言された能力 — を読み戻します。
モデルについて何一つハードコードされていません。これは聞こえる以上に重要です。フロンティア級のコンテキストウィンドウを仮定するプラットフォームは、32Kウィンドウのオープンモデルを静かにオーバーフローさせ、その失敗はエラーではなく、切り詰められた、あるいは意味をなさない回答として表面化します。
バックエンドがプローブに応答しないとき、ゲートウェイはウィンドウを不明として記録し、小さな数を推測するのではなくトリミングを見送ります。誤った推測は、モデルが使えたはずのコンテキストを静かに削除します。試みて失敗するほうが、少なくとも目に見えます。
小さなオープンモデルが壊れる4つのパターン
これらは仮定の話ではありません。それぞれが実際に現れたからこそ、対処されています。
1. ツール呼び出しがテキストとして届く
多くのオープンモデルは構造化された tool_calls フィールドを無視し、呼び出しを返答の本文に書き込みます。これまでに本番で届いた形は 9 種類あり、この数そのものがこの節の正直な部分です。どれも、まずい形で出てしまった回答を読んで見つけたものであって、コードを読んで見つけたものは一つもありません。だから 9 番目が最後だと考える理由はありません。よくあるのは 2 つです。
<tool_call>
<function=search_docs>
<parameter=query>refund policy</parameter>
</function>
</tool_call><tool_call>
{"name": "search_docs", "arguments": {"query": "refund policy"}}
</tool_call>残る 7 つは囲いすらありません。裸の JSON オブジェクト、doc_update_section({"key": …}) のように 1 行のコードとして書かれた呼び出し、call: または call:名前空間:ツール名 の接頭辞、トークン上限で途中まで切れた JSON、そして最も新しいものとして、{{ query_knowledge_table }} という 7 文字だけからなる返答全体です。
未処理のままだと何も実行されず、エンドユーザーはチャットで生のマークアップを目にします。ツールループはこれらの形をパースして通常どおりツールをディスパッチし、さらに最後の砦として、送り出す前にテキストから残存する呼び出し構文を取り除きます。生のツール呼び出し構文がエンドユーザーに届いてはなりません — たとえパースに失敗しても、です。
この最後の砦がそれ自体のバグにならないよう、規則が 2 つあります。どちらも破って学びました。剥がす前にパースする:1 行のコードとして書かれた呼び出しは実行できるもので、初期の版はそれを残骸として剥がしていました。その結果、文書は一文字も変わらないのに、モデルは変更済みだと快活に報告していました。剥がして空になったら答え直す:構文を取り除いて何も残らないなら、そのターンは空のまま送らず、もう一度書かせます。
2. ストリーミングされるツール呼び出しが断片で届く
OpenAI互換のサーバーは、ツール呼び出しをストリーミングチャンクにどう分割するかで意見が分かれます。1つの呼び出しが複数の部分的なデルタとして届くことがあり、モデルが複数のツールを要求するとインターリーブされることもあります。断片はインデックスによって蓄積され、どのツールが走る前にも、丸ごとの呼び出しへと再構成されます。
3. コンテキスト予算は実際のウィンドウから来なければならない
利用可能な入力予算は、設定されるのではなく導出されます。
input_budget =
probed_context_window − output_reservation − safety_marginそしてフロアを設けることで、過度な予約でも予算がゼロになることは決してありません。32Kのモデルでは、100万トークンのモデルとはまったく異なる予算になります。それがまさに要点です — 同じエージェント定義が両方で正しく動きます。
4. 推論が回答を食いつぶす
最終回答の前に推論を出力するモデルでは、回答だけを想定した出力予算が推論に食われ、ユーザーは切り詰められた返答を受け取ります。推論トークンを見込んで出力の許容量を引き上げることで、回答そのものが生き残ります。
ルーティングとフェイルオーバー
同じ種別のバックエンドは重みで選択されるので、トラフィックを分配できます。たとえば大半のリクエストを小さなセルフホストのモデルへ、残りをより強力なホスト型モデルへ、という具合です。リクエストがリトライ可能な形で失敗すると、ゲートウェイは、手元のバックエンドに対する指数バックオフにフォールバックする前に、他の適格なバックエンドを試します。
実務的なパターンは、難易度ではなく結果の重大さで分けることです。読み取り専用で低リスクの作業は安いモデルへ、書き込みやコミットを伴うものはより強力なモデルへ回します。
これがしないこと
端の部分について正直であることは、長い機能リストより役に立ちます。
- 小さなモデルを大きなモデルと同じくらい有能にはしません。 ツールの選択 — 込み入った多段階の状況で、どのツールをどんな引数で呼ぶか決めること — こそ、モデルの品質が最も現れる部分です。重大な結果を伴う作業を小さなモデルに移す前に、自分のタスクでテストしてください。
- あなたの推論インフラを管理しません。 セルフホストするなら、GPUのキャパシティ、モデルサーバー、その稼働時間はあなたのものです。ゲートウェイはダウンしたバックエンドを迂回してルーティングしますが、あるバックエンドを速くすることはできません。
- 特定のモデルを認証しません。 互換性の作業は、モデルが生成する形についてのものであり、テスト済みのリストではありません。どんなOpenAI互換エンドポイントも動くことが期待されます。あなたのワークロードにどのモデルが適しているかは、あなたが行うべき評価です。