BluePeriod Docs
開発

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.tsAPIキーを保存するための 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.tsAdit(編集ツール)用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 では baseURLhttp://localhost:11434 (Ollama) 等に設定する。
    • 注意: サーバーサイド (route.ts) から localhost を叩く場合、それは「Next.jsが動いているサーバーのローカル」を指します。開発環境なら自分のPCですが、Vercelにデプロイした場合はVercelサーバーのローカルになるため、Ollamaには繋がりません。
    • 対策: ローカルLLM対応は、Desktopアプリ版(Tauri)または ngrok 等でのトンネルが必要になります。

5. ツール実行におけるモデルの適合性と制約

エージェントがツール(特に artifact_editorAdit)を使用する場合、単純なチャットよりも高度な推論能力と構造化データの出力能力が要求されます。

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 エラーが頻発する場合、以下の対策を検討してください。

  1. Agent Settings で、Adit 用のモデルをより高性能なものに固定する。
  2. fallback: edit ツールが失敗した際、エージェントに対して「overwrite アクション(全文置換)を試す」ようシステムプロンプトで誘導する。

関連ドキュメント:

On this page