# LLM モデル設定の再編 > **レビュー中** — 詳細は [`llm-model-config.review.md`](llm-model-config.review.md) > 主な指摘: 要件 6 の `ModelConfig.capability` override 未実装、`validate_config` の機能退化(OpenAI top_k warning 消失)。どちらも判断待ち。 ## 背景 決定済みの LLM プロバイダサポート方針(`docs/plan/llm_providers.md`)に従って llm-worker のプロバイダ層を再編する。Pod 側で「使う LLM モデル」を宣言する構造にし、共通の通信層 + scheme の組合せで任意のプロバイダを収容できるようにする。 ### 現状の問題 - `crates/llm-worker/src/llm_client/providers/{anthropic,openai,gemini,ollama}.rs` は各々 HTTP 骨格 + scheme 呼び出しの薄いアダプタで、構造が重複 - `providers/ollama.rs` (67行) は scheme 未分離で整合性が崩れている - OpenAI 互換ルーター系(xAI / Groq / OpenRouter / Together / BLACKBOX 等)を追加するたびに新ファイルを書く必要がある ## 要件 1. **Pod マニフェストで LLM モデルを宣言できる** ``` ModelConfig { scheme: Scheme, // Anthropic / OpenAIChat / OpenAIResponses / Gemini base_url: Url, model_id: String, auth: AuthRef, } ``` 継承(commit ebee0b9)と整合し、親 Pod の定義を子 Pod が override 可能。 2. **`providers/` 層の廃止**: llm-worker は `HttpTransport` 相当の汎用通信層 1 本を持ち、`ModelConfig` を食わせてインスタンス化する 3. **既存 scheme の再編**: - `scheme/openai` を `scheme/openai_chat` にリネーム - `scheme/anthropic` / `scheme/gemini` はそのまま - `scheme/openai_responses` は別チケット(llm-scheme-openai-responses)で新設 - Ollama は **scheme/anthropic を base_url 差し替えで流用**(独自 scheme は作らない) 4. **認証の分離**: `AuthRef` は `ApiKey(EnvVar | ConfigRef)` / `CodexOAuth` / `None` を表現でき、scheme とは直交する層で管理される。`CodexOAuth` の実装自体は別チケット(llm-auth-codex-oauth) 5. **決定済みプロバイダ方針との整合**: - 第一級: Ollama / Codex OAuth / Anthropic API - 二次: OpenAI 互換共通枠(`{ scheme: OpenAIChat, base_url: 各社, auth: ApiKey }` の宣言だけで収容) 6. **ModelCapability を分離**: モデルに紐づく機能差を別メタデータとして表現 ``` ModelCapability { tool_calling: ToolCallingSupport, // parallel 可否含む structured_output: StructuredOutput, // JsonObject / JsonSchema reasoning: Option, // effort / budget_tokens vision: bool, prompt_caching: CacheStrategy, // Explicit { max_breakpoints } / Auto } ``` `ReasoningControl { effort, budget_tokens }` は共通型、scheme アダプタで各社形式に投影。プロバイダ側高次ツール(web_search 等)は採用しないため軸から除外。 7. **Streaming は現状維持**: 既存 `BlockStart / BlockDelta / BlockStop / BlockAbort` + `DeltaContent::{Text, Thinking, InputJson}` を変更しない。Gemini や Ollama のように ToolCall 引数 delta を送らないプロバイダは scheme アダプタで「BlockStart → InputJson(全体 1 回) → BlockStop」の擬似ストリーム化で吸収 8. **Ollama 運用の注意点**: scheme/anthropic 流用前提で以下を守る - `cache_control` は送らない(`ModelCapability::prompt_caching = Auto`) - `tool_choice` / `metadata` / URL 画像は送らない(Ollama 側非対応) - `/v1/messages/count_tokens` は叩かない(issue #13949 でサーバ不安定化) - `/v1/chat/completions` は stream+tools バグ (#9092) のため使わない 9. **完了時の動作**: 既存の動作は変わらず、Pod マニフェストで `ModelConfig` を宣言するだけでモデル切替できる。OpenAI 互換の新規プロバイダは新コードなしで追加可能 ## 設計決定 ### 1. `Scheme` trait の境界(方針A: 全面抽象化) trait で URL 組立・認証要件・body 変換・SSE パースをすべて抽象化し、`HttpTransport` は 1 本にする。trait スケッチ: ```rust trait Scheme { fn path(&self, model: &str) -> String; // "/v1/messages" 等 fn required_auth(&self) -> AuthRequirement; // Bearer / XApiKey / QueryParam / None fn additional_headers(&self) -> Vec<(&str, String)>; // anthropic-version 等 fn build_request_body(&self, model: &str, req: &Request, cap: &ModelCapability) -> Value; fn parse_sse(&self, event_type: &str, data: &str) -> Result, ClientError>; fn default_base_url(&self) -> &'static str; } ``` `parse_sse` は `Vec` に統一(Anthropic は 1 要素 Vec で扱う)。 ### 2. `AuthRef` と `Scheme` の組合せ検証(方針B: 構築時検証) `Scheme::required_auth()` で要求する `AuthRequirement` を宣言し、`build_client` 時に `AuthRef` と照合。非対応組合せは構築エラーにする(実行時に落とさない)。 ### 3. `crates/provider/` の去就(方針A: 残す) `provider` クレートは保持。`build_client(ModelConfig) -> Box` は `(Scheme, AuthRef)` 照合 + `HttpTransport::new` の薄ラッパーに縮退する。`~/.codex/auth.json` 読み取り等の認証ストア解決は `provider` クレートに肉付けしていく(llm-worker は低レベル基盤に留める方針と整合)。 ### 4. `ModelCapability` の保持(方針: ハイブリッド) - scheme 実装側に `model_id → ModelCapability` の静的テーブルを持つ(既知モデル分) - `ModelConfig` で明示宣言すれば override - 未知モデルは scheme ごとの安全側デフォルト(`prompt_caching: Auto` 等)にフォールバック 今チケットのスコープ: - 型定義 + 既知モデルの固定値 - `CacheStrategy::Explicit` で `cache_control` マーカー挿入(既存実装を capability で分岐) - `ReasoningControl { effort, budget_tokens }` を scheme 側で各社形式に投影 - `CacheStrategy::Auto` は何もしない(Ollama で重要) ### 5. マニフェスト継承との統合(方針: フィールド単位 override) `ProviderConfigPartial` と同じ方針で、`ModelConfig` の全フィールド(`scheme` / `base_url` / `model_id` / `auth`)を `Option` で継承。子 Pod は `base_url` だけ差し替える等が可能。 ### 6. TOML 後方互換 旧 `[provider] kind = "..."` フォーマットは互換を切る。新 `[model]` セクションで `scheme` / `base_url` / `model_id` / `auth` を宣言する。 ## Scope 外 - OpenAI Responses scheme の新設(`tickets/llm-scheme-openai-responses.md`) - Codex OAuth 認証アダプタの実装(`tickets/llm-auth-codex-oauth.md`) - OpenAI 互換ルーター各社の動作確認 - プロバイダ選択 UI(将来の native GUI / TUI 拡張)