メインコンテンツまでスキップ

LLM プロバイダーの拡張方法

このドキュメントでは、新しいプリセットテンプレートの追加、新しい API 形式の追加、プロバイダーへの検索機能設定という 3 つの一般的な拡張シナリオについて、手順を追って説明します。


ファイルの場所

ファイルパス
Provider テンプレートpackages/desktop/app/shared/llm-config.ts
Provider プリセットpackages/desktop/app/shared/provider-presets.ts
ProviderManagerpackages/desktop/app/main/services/capabilities/llm/config-service/ProviderManager.ts
URL Builderpackages/desktop/app/main/services/capabilities/llm/completion/url-builder.ts
Header Builderpackages/desktop/app/main/services/capabilities/llm/completion/header-builder.ts
Message Converterpackages/desktop/app/main/services/capabilities/llm/completion/message-converter.ts
DirectApiHandlerpackages/desktop/app/main/services/capabilities/llm/completion/DirectApiHandler.ts
StreamHandlerpackages/desktop/app/main/services/capabilities/llm/completion/StreamHandler.ts
CompletionServicepackages/desktop/app/main/services/capabilities/llm/completion/CompletionService.ts
Typespackages/desktop/app/main/services/capabilities/llm/completion/types.ts
ProviderSearchInjectorpackages/desktop/app/main/services/capabilities/llm/completion/ProviderSearchInjector.ts
NativeSearchInjectorpackages/desktop/app/main/services/capabilities/llm/completion/NativeSearchInjector.ts
IPC Router Schemaspackages/desktop/app/main/services/routers/llm/schemas.ts
フロントエンド i18npackages/renderer/src/locales/{en,zh,ja}/providers/llm.json

アーキテクチャ上の位置づけ

graph TB
subgraph ExtensionPoints ["Extension Points"]
direction TB
A["(1) New preset template<br/>provider-presets.ts"]
B["(2) New API format<br/>types + handlers"]
C["(3) Search config<br/>PROVIDER_SEARCH_CONFIGS"]
end

subgraph AffectedLayers ["Affected Layers"]
direction TB
Shared[shared layer<br/>types + presets]
Completion[completion layer<br/>Handlers + URL]
Config[config-service layer<br/>ProviderManager]
Router[router layer<br/>IPC Schemas]
Frontend[renderer layer<br/>UI + i18n]
end

A --> Shared
A --> Config
A --> Frontend

B --> Shared
B --> Completion
B --> Router

C --> Shared
C --> Completion

シナリオ 1: 新しいプリセットテンプレートを追加する

新しい LLM プロバイダー(新しいクラウドベンダーや海外プロバイダーなど)をサポートする必要がある場合、ユーザーが UI からワンクリックで追加できるように、プリセットテンプレートを作成します。

データ構造

// Full interface for a preset template
interface PresetProviderTemplate {
id: string; // Unique ID (lowercase, e.g. 'minimax')
name: string; // Display name
apiFormat: ApiFormat; // API format
baseUrl: string; // Base URL
modelsEndpoint?: string; // Model discovery endpoint
models: string[]; // List of supported model IDs
modelConfigs: ModelConfig[]; // Per-model detailed config
features: string[]; // Feature tags
icon?: string; // Icon
website?: string; // Official website
docsUrl?: string; // API documentation
defaultSettings?: CompletionSettings; // Default completion parameters
}

手順

ステップ 1: プリセットテンプレートを定義する

packages/desktop/app/shared/provider-presets.tsPROVIDER_PRESETS 配列にエントリを追加します。

// Pseudocode — adding a new preset
{
id: 'newprovider',
name: 'NewProvider AI',
apiFormat: 'openai', // Most Chinese vendors are OpenAI-compatible
baseUrl: 'https://api.newprovider.com/v1',
modelsEndpoint: '/models',
models: ['np-large', 'np-lite', 'np-vision'],
modelConfigs: [
{
id: 'np-large',
name: 'NP Large',
enabled: true,
category: 'chat',
contextLength: 128000,
maxTokens: 8192,
vision: false,
functionCall: true,
reasoning: false,
},
{
id: 'np-lite',
name: 'NP Lite',
enabled: true,
category: 'chat',
contextLength: 32000,
maxTokens: 4096,
},
{
id: 'np-vision',
name: 'NP Vision',
enabled: true,
category: 'chat',
contextLength: 64000,
maxTokens: 4096,
vision: true,
},
],
features: ['chat', 'function_call'],
website: 'https://newprovider.com',
docsUrl: 'https://docs.newprovider.com/api',
}

ステップ 2(任意): デフォルトプロバイダーにする

新しいプロバイダーをすべてのユーザーの初期リストに表示したい場合:

ProviderManager.getDefaultProviders()defaultTemplateIds 配列に ID を追加します。

あわせて packages/desktop/app/shared/llm-config.tsPROVIDER_TEMPLATES に対応する ProviderTemplate を追加します。

ステップ 3(任意): Coding Plan サポートを追加する

そのプロバイダーに専用の Coding Plan API がある場合:

// Add to CODING_PLAN_URL_PRESETS
CODING_PLAN_URL_PRESETS['newprovider'] = {
baseUrl: 'https://api.newprovider.com/coding/v1',
separateApiKey: false, // Whether a separate API Key is needed
};

ステップ 4(任意): Follow-Provider のモデルマッピングを追加する

同じプロバイダーのバックグラウンド/vision モデルを自動選択したい場合:

// Add to PROVIDER_MODEL_MAPPINGS
PROVIDER_MODEL_MAPPINGS['newprovider'] = {
primary: 'np-large',
background: 'np-lite',
vision: 'np-vision', // Set to null if no vision model exists
};

ステップ 5: フロントエンド i18n を追加する

packages/renderer/src/locales/ 配下の en/zh/ja の providers/llm.json に、プロバイダー名の翻訳を追加します。


シナリオ 2: 新しい API 形式を追加する

既存形式(openai/anthropic/google/azure-openai/openai-response)と互換性のないプロバイダー API に遭遇した場合、新しい API 形式を追加する必要があります。

手順の概要

flowchart TD
S1["(1) Define format identifier<br/>types.ts"] --> S2["(2) URL builder<br/>url-builder.ts"]
S2 --> S3["(3) Header builder<br/>header-builder.ts"]
S3 --> S4["(4) Message conversion<br/>message-converter.ts"]
S4 --> S5["(5) Non-streaming handler<br/>DirectApiHandler.ts"]
S5 --> S6["(6) Streaming handler<br/>StreamHandler.ts"]
S6 --> S7["(7) Register dispatch<br/>CompletionService.ts"]
S7 --> S8["(8) Schema update<br/>schemas.ts"]

ステップ 1: 形式識別子を定義する

packages/desktop/app/main/services/capabilities/llm/completion/types.tsApiFormat に新しい値を追加します。

// Before
type ApiFormat = 'openai' | 'anthropic' | 'google' | 'azure-openai' | 'openai-response';

// After
type ApiFormat = 'openai' | 'anthropic' | 'google' | 'azure-openai' | 'openai-response' | 'newformat';

packages/desktop/app/main/services/capabilities/llm/config-service/schemas.tsApiFormatSchema も更新します。

const ApiFormatSchema = z.enum([
'openai', 'anthropic', 'google', 'azure-openai', 'openai-response', 'newformat'
]);

さらに packages/desktop/app/main/services/routers/llm/schemas.tsllmProviderCreateSchema も更新します。

ステップ 2: URL Builder

url-builder.ts にビルダー関数を追加します。

// Pseudocode
function buildNewFormatApiUrl(baseUrl: string): string {
// Build the correct endpoint URL according to the provider's API docs
// Handle various baseUrl input formats
}

apiType から推論する必要がある場合は)resolveApiFormat() に新形式の認識ロジックを追加します。

buildProviderApiUrl() に新形式の分岐を追加します。

ステップ 3: Header Builder

header-builder.tsgetProviderHeaders() で新形式の認証ヘッダーを処理します。

// Pseudocode — different providers use different auth schemes
// OpenAI: Authorization: Bearer <key>
// Anthropic: x-api-key: <key>
// New format may use different headers

ステップ 4: メッセージ形式変換

message-converter.ts に変換関数を追加します。

// Pseudocode
function convertMessageToNewFormat(message: SimpleChatMessage): NewFormatMessage {
// Convert the generic message format to the provider-specific format
// Handle role mapping, content structure, images, tool calls, etc.
}

ステップ 5: 非ストリーミング Handler

DirectApiHandler.ts に追加します。

// Pseudocode
async function callNewFormatCompletion(
provider: LLMProvider,
apiKey: string,
options: CompletionOptions,
logger: LoggerService
): Promise<CompletionResult> {
// Build request body
// Send request
// Parse response into CompletionResult
}

ステップ 6: ストリーミング Handler

StreamHandler.ts に追加します。

// Pseudocode
async function streamNewFormatCompletion(
provider: LLMProvider,
apiKey: string,
options: CompletionOptions,
messageId: string,
callbacks: StreamCallbacks,
logger: LoggerService
): Promise<void> {
// Build streaming request body
// Use streamSSEResponse() or custom stream parsing
// Call callbacks to deliver incremental content
}

ステップ 7: Dispatch に登録する

CompletionService に新形式を登録します。

// In the switch inside callDirectHandler
case 'newformat':
return callNewFormatCompletion(provider, apiKey, options, this.logger);

// In the switch inside callStreamHandler
case 'newformat':
await streamNewFormatCompletion(provider, apiKey, options, messageId, callbacks, this.logger);
return;

ステップ 8: Schema を更新する

ApiFormat enum を参照するすべての Zod schema が更新されていることを確認します。

  • capabilities/llm/config-service/schemas.tsApiFormatSchema
  • routers/llm/schemas.tsllmProviderCreateSchema.apiFormat

シナリオ 3: プロバイダーに検索設定を追加する

プロバイダーが Web 検索をサポートしている場合は、検索の注入方法を設定する必要があります。

検索タイプの判断

flowchart TD
Start[Provider supports search?] --> Type{Search implementation}
Type -->|Request parameter| ModelParam["model-param<br/>modify request body"]
Type -->|Built-in tool definition| BuiltinTool["builtin-tool<br/>inject into tools array"]
Type -->|MCP server| MCP["mcp<br/>external handling"]
Type -->|SDK native| SDKNative["sdk-native<br/>NativeSearchInjector"]
Type -->|Not supported| None["none<br/>no config needed"]

手順

ステップ 1: 検索タイプを決定する

検索実装判断基準
model-paramAPI がリクエストパラメーターで検索を有効化する(例: enable_search: trueDashScope, Baidu
builtin-toolAPI が tools 配列への特定ツール定義の注入を要求するKimi, Volcengine
mcp外部 MCP サーバーが検索を提供するカスタムデプロイ
sdk-nativeSDK が検索をネイティブに処理する(例: Anthropic server-side tools)Anthropic
none検索をサポートしないOllama

ステップ 2: 検索設定を追加する

packages/desktop/app/shared/provider-presets.tsPROVIDER_SEARCH_CONFIGS にエントリを追加します。

model-param 型(リクエストパラメーター):

// Pseudocode
PROVIDER_SEARCH_CONFIGS['newprovider'] = {
type: 'model-param',
paramName: 'enable_search', // parameter name
paramValue: true, // parameter value
extraParams: { // extra parameters (optional)
search_mode: 'auto',
},
applicableModels: null, // null means all models
};

builtin-tool 型(組み込みツール):

// Pseudocode
PROVIDER_SEARCH_CONFIGS['newprovider'] = {
type: 'builtin-tool',
toolDefinition: {
type: 'function',
function: {
name: 'web_search',
description: 'Search the web for information',
parameters: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search query' },
},
required: ['query'],
},
},
},
conflictsWithFC: false, // Whether it conflicts with function calling
applicableModels: ['np-large'], // Only certain models support it (null = all)
};

ステップ 3: 注入を確認する

ProviderSearchInjectorgetSearchConfig() でプロバイダーの検索設定を自動検出し、buildSearchAugmentation() で注入内容を構築します。追加のコード変更は不要です。


ファイル変更チェックリスト

シナリオ 1: 新しいプリセットテンプレート

ファイル変更内容必須
shared/provider-presets.tsPROVIDER_PRESETS エントリを追加はい
shared/llm-config.tsPROVIDER_TEMPLATES エントリを追加(デフォルトにする場合)任意
capabilities/llm/config-service/ProviderManager.tsdefaultTemplateIds に追加(デフォルトにする場合)任意
shared/provider-presets.tsCODING_PLAN_URL_PRESETS(必要な場合)任意
shared/provider-presets.tsPROVIDER_MODEL_MAPPINGS(必要な場合)任意
shared/provider-presets.tsPROVIDER_SEARCH_CONFIGS(検索が必要な場合)任意
i18n JSON ファイル(en/zh/ja)プロバイダー名の翻訳推奨

シナリオ 2: 新しい API 形式

ファイル変更内容必須
capabilities/llm/completion/types.tsApiFormat 型はい
capabilities/llm/completion/url-builder.tsURL builder + resolveApiFormat + buildProviderApiUrlはい
capabilities/llm/completion/header-builder.ts認証ヘッダーはい
capabilities/llm/completion/message-converter.tsメッセージ形式変換はい
capabilities/llm/completion/DirectApiHandler.ts非ストリーミング handlerはい
capabilities/llm/completion/StreamHandler.tsストリーミング handlerはい
capabilities/llm/completion/CompletionService.tsswitch 分岐登録はい
capabilities/llm/config-service/schemas.tsApiFormatSchemaはい
routers/llm/schemas.tsllmProviderCreateSchemaはい

シナリオ 3: 検索設定を追加する

ファイル変更内容必須
shared/provider-presets.tsPROVIDER_SEARCH_CONFIGS エントリはい

テストガイド

プリセットテンプレートのテスト

  1. Unit tests: テンプレートデータの整合性を確認します

    • 必須フィールドがすべて存在し、有効であること
    • modelConfigs 内の各モデル ID が models 配列に存在すること
    • apiFormat の値が ApiFormat enum の範囲内であること
  2. Integration tests:

    • プリセットからプロバイダーを作成 → プロバイダーデータが正しいことを確認
    • プロバイダーを有効化 → 有効な API Key を設定 → テストメッセージを送信
    • モデル検出 → 返されたモデルリストを確認
  3. UI tests:

    • 新しいプリセットが設定ページのプリセット一覧に表示される
    • 「Add」をクリックするとプロバイダーが正しく作成される
    • プロバイダー設定ページに正しいフィールドが表示される

API 形式のテスト

  1. URL builder tests:

    • さまざまな baseUrl 入力形式 → 正しい API endpoint
    • パスプレフィックス付き URL → プレフィックスが失われない
  2. Message conversion tests:

    • プレーンテキストメッセージ → 正しい形式
    • 画像付きメッセージ → 正しく処理される
    • tool calls 付きメッセージ → 正しい形式
  3. Handler tests:

    • 非ストリーミング: リクエスト送信 → レスポンス解析 → CompletionResult
    • ストリーミング: SSE events → callbacks が正しく呼ばれる
    • エラー処理: ネットワークエラー、API エラー、形式エラー
  4. End-to-end tests:

    • testModel() を使用してパイプライン全体を確認
    • ストリーミング会話 → onDelta/onDone callbacks を確認

検索設定のテスト

  1. Injection tests:

    • getSearchConfig() が新しいプロバイダーを正しく認識する
    • buildSearchAugmentation() が正しい注入内容を生成する
    • model-param 型: リクエスト body に正しいパラメーターが含まれる
    • builtin-tool 型: tools 配列に正しいツール定義が含まれる
  2. Conflict tests:

    • conflictsWithFC が true の場合: 検索ツールと function calling が共存しない
    • applicableModels 制限: 非対象モデルでは検索が注入されない

関連ファイル

ファイル関係
shared/llm-config.tsPROVIDER_TEMPLATES、ApiFormat、コア型
shared/provider-presets.tsプリセットテンプレート、検索設定、Coding Plan URL、モデルマッピング
capabilities/llm/config-service/ProviderManager.tsデフォルトプロバイダーリスト、テンプレート作成ロジック
capabilities/llm/config-service/schemas.tsApiFormatSchema、バリデーション schema
capabilities/llm/completion/types.tsApiFormat 型定義
capabilities/llm/completion/url-builder.tsresolveApiFormat、URL builders
capabilities/llm/completion/header-builder.ts認証ヘッダー
capabilities/llm/completion/message-converter.tsメッセージ形式変換
capabilities/llm/completion/DirectApiHandler.ts非ストリーミング API handler
capabilities/llm/completion/StreamHandler.tsストリーミング API handler
capabilities/llm/completion/CompletionService.tsHandler dispatch 登録
capabilities/llm/completion/ProviderSearchInjector.ts検索注入ロジック
routers/llm/schemas.tsIPC パラメーターバリデーション schema
i18n JSON ファイルフロントエンド翻訳