AI Provider Integration Guide
複数AIプロバイダーの統合と新規プロバイダー追加手順
AI Provider Integration Guide
1. 概要
本プロジェクトでは、OpenAI, Google, Anthropic などの複数のAIプロバイダーをサポートしています。 新しいプロバイダー(例: DeepSeek, Ollama, LM Studio)を追加する際に、どのファイルを修正すべきかを体系的にまとめました。
実装箇所は「フロントエンド設定」「状態管理」「バックエンドAPI」「ツールAPI」の4層に分散しており、すべてに整合性を持たせる必要があります。
2. 影響範囲マップ (Impact Map)
プロバイダー追加時に修正が必要なファイル一覧です。上から順に対応することを推奨します。
| カテゴリ | ファイルパス | 役割 |
|---|---|---|
| 定義 (Core) | src/lib/llmProviders.ts | プロバイダーID、表示名、デフォルトモデル名の定義。 |
| 状態 (State) | src/stores/settingsAtoms.ts | APIキーを保存するための atomWithStorage 定義。 |
| UI (Settings) | src/components/ConfigurableApiSettingsPanel.tsx | 設定画面でのAPIキー入力欄とモデル選択UI。 |
| Agent (Logic) | src/stores/chat/agent.ts | エージェント実行時にAPIキーを収集するロジック。 |
| Backend (Chat) | src/app/api/chat/route.ts | チャットAPIエンドポイント。LangChainモデルの初期化。 |
| Backend (Tool) | src/app/api/tools/adit/route.ts | Adit(編集ツール)用API。LangChainモデルの初期化。 |
3. 実装ステップ (Step-by-Step)
Step 1: プロバイダー定義の追加
ファイル: src/lib/llmProviders.ts
STATIC_MODEL_LISTS にモデルリストを追加し、PROVIDERS オブジェクトに設定を追加します。
export const STATIC_MODEL_LISTS = {
// ...
deepseek: ["deepseek-chat", "deepseek-coder"], // 追加
};
export const PROVIDERS = {
// ...
deepseek: {
name: "DeepSeek",
apiKeyEnvVar: "DEEPSEEK_API_KEY",
apiKeyAtom: "deepseekApiKeyAtom", // Step 2で作成するAtom名
models: STATIC_MODEL_LISTS.deepseek,
},
} as const;Step 2: APIキー保存用Atomの作成
ファイル: src/stores/settingsAtoms.ts
LocalStorageにキーを保存するためのAtomを定義します。
export const deepseekApiKeyAtom = atomWithStorage<string>('settings.deepseekApiKey', '');Step 3: 設定画面UIの更新
ファイル: src/components/ConfigurableApiSettingsPanel.tsx
APIキー入力フォームを追加します。
// Import the new atom
import { deepseekApiKeyAtom } from '@/stores/settingsAtoms';
// In the component:
const [deepseekKey, setDeepseekKey] = useAtom(deepseekApiKeyAtom);
// In the render return:
<div className="space-y-2">
<Label>DeepSeek API Key</Label>
<Input type="password" value={deepseekKey} onChange={e => setDeepseekKey(e.target.value)} />
</div>Step 4: エージェントへのキー渡し
ファイル: src/stores/chat/agent.ts
executeAgentWorkflow 関数内の userApiKeys オブジェクトに、新しいキーを追加します。これを行わないと、エージェントがそのプロバイダーを使えません。
const userApiKeys = {
// ...
deepseek: getApiKey(get(deepseekApiKeyAtom), 'settings.deepseekApiKey'), // 追加
};Step 5: チャットAPIの実装
ファイル: src/app/api/chat/route.ts
POST 関数内の switch (provider) 文に分岐を追加し、LangChainモデルを初期化します。
※ LangChainがそのプロバイダーに対応していない場合は、ChatOpenAI を使い baseURL を指定することで対応可能な場合が多いです(OpenAI互換の場合)。
case "deepseek":
llm = new ChatOpenAI({
modelName: model,
apiKey: apiKey,
configuration: { baseURL: "https://api.deepseek.com/v1" },
// ...
});
break;Step 6: ツールAPI (Adit) の実装
ファイル: src/app/api/tools/adit/route.ts
Adit(高精度編集ツール)でもそのプロバイダーを使えるようにする場合、同様に switch 文に追加します。
case "deepseek":
llm = new ChatOpenAI({
modelName: modelName || "deepseek-coder",
apiKey: apiKey,
temperature: 0,
// ...
});
break;4. ローカルLLM (Ollama / LM Studio) の場合
ローカルLLMの場合も手順はほぼ同じですが、「APIキーが不要(またはダミー)」 である点と、「Base URLがローカルホスト」 である点が異なります。
apiKeyは任意入力とするか、ダミー値(lm-studioなど)を自動セットする。route.tsではbaseURLをhttp://localhost:11434(Ollama) 等に設定する。- 注意: サーバーサイド (
route.ts) からlocalhostを叩く場合、それは「Next.jsが動いているサーバーのローカル」を指します。開発環境なら自分のPCですが、Vercelにデプロイした場合はVercelサーバーのローカルになるため、Ollamaには繋がりません。 - 対策: ローカルLLM対応は、Desktopアプリ版(Tauri)または
ngrok等でのトンネルが必要になります。
- 注意: サーバーサイド (
5. ツール実行におけるモデルの適合性と制約
エージェントがツール(特に artifact_editor や Adit)を使用する場合、単純なチャットよりも高度な推論能力と構造化データの出力能力が要求されます。
5.1. モデル選定のガイドライン
- 推奨(高精度): GPT-4o, Claude 3.5 Sonnet, Gemini 1.5 Pro.
- Adit のような置換エンジンの指示(JSON 形式)を正確に生成するには、これらのモデルが最適です。
- 軽量モデル(Gemini Flash 等)の注意点:
stepfun/step-3.5-flash:freeのようなモデルは、複雑なツール定義(JSON Schema)を含むリクエストを受け取った際、プロバイダー側で 400 Provider returned error を返すことがあります。- これは、モデルの対応能力を超える複雑なスキーマが送られたことへの拒絶反応、あるいは OpenRouter 側のゲートウェイの制限です。
5.2. トラブルシューティング
もし特定のプロバイダーで 400 エラーが頻発する場合、以下の対策を検討してください。
- Agent Settings で、Adit 用のモデルをより高性能なものに固定する。
- fallback:
editツールが失敗した際、エージェントに対して「overwriteアクション(全文置換)を試す」ようシステムプロンプトで誘導する。
関連ドキュメント: