Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Dify の Provider 抽象層設計:なぜ数十の LLM を同時にサポートしながら疎結合を維持できるのか

はじめに

エンタープライズ AI プラットフォームにとって、「どの LLM を使うか」は一度きりの決定ではない。コスト最適化、性能要件の変化、新モデルの登場、規制対応によるベンダー変更など、モデルの切り替えは継続的に発生する。

Dify の Provider 抽象層は、この現実に対する構造的な回答である。本稿では、Dify がどのように LLM Provider を抽象化し、アプリケーション層とモデル層の疎結合を実現しているかを、アーキテクチャ設計の観点から解説する。


1. Provider 抽象層とは何か

1.1 問題の定義

LLM を直接呼び出すアプリケーションは、以下の問題を抱える:

# 抽象層がない場合の典型的なコード
import openai

# OpenAI に直接依存
response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=[{"role": "user", "content": prompt}],
    temperature=0.7,
)

この実装は以下の点で脆弱である:

  • モデル変更時にアプリケーションコード全体の修正が必要
  • API キー管理がアプリケーション内に散在
  • 各プロバイダーの API 仕様差異(パラメータ名、レスポンス形式)をアプリケーション側で吸収
  • レート制限、リトライ、フォールバックの統一的な処理が困難

1.2 Dify の解決策:Provider 層の分離

Dify は、アプリケーション層(Workflow / Agent / Chat)とモデル呼び出し層の間に Provider 抽象層を配置する:

graph TB
    subgraph "Application Layer"
        W[Workflow]
        AG[Agent]
        CH[Chat App]
    end
    
    subgraph "Provider Abstraction Layer"
        direction TB
        MI[Model Interface<br/>統一 API]
        MC[Model Configuration<br/>Workspace レベル管理]
        MR[Model Runtime<br/>実行・リトライ・制御]
    end
    
    subgraph "Model Providers"
        OP[OpenAI]
        AZ[Azure OpenAI]
        AN[Anthropic]
        GG[Google Gemini]
        OL[Ollama / Local]
        CU[Custom Provider]
    end
    
    W --> MI
    AG --> MI
    CH --> MI
    MI --> MC
    MC --> MR
    MR --> OP
    MR --> AZ
    MR --> AN
    MR --> GG
    MR --> OL
    MR --> CU
    
    style MI fill:#69b,stroke:#333,color:#fff

2. アーキテクチャの詳細

2.1 Model Provider の登録構造

Dify の公開ドキュメントによると、各 Model Provider は以下のスキーマに従って定義される:

# Provider 定義の概念モデル(公式 schema に基づく)
provider:
  name: "openai"
  label: "OpenAI"
  supported_model_types:
    - llm
    - text-embedding
    - speech2text
    - tts
  credential_schema:
    - name: api_key
      type: secret
      required: true
    - name: organization_id
      type: string
      required: false
  models:
    - name: "gpt-4o"
      type: llm
      features:
        - function_calling
        - vision
      context_length: 128000
      pricing:
        input: 0.005   # per 1K tokens
        output: 0.015

この設計には以下の意図がある:

設計要素目的
supported_model_types同一プロバイダーが提供する異なる能力(LLM、Embedding、TTS)を統一管理
credential_schemaAPI キーの管理方法をプロバイダーごとに定義し、Workspace レベルで一元管理
featuresFunction Calling、Vision などの能力宣言により、アプリケーション層が互換性を判断可能
context_lengthコンテキスト長をメタデータとして公開し、Workflow の設計時に制約を可視化
pricingコスト見積もりを可能にし、企業のモデル選定判断を支援

2.2 Model Interface の統一

Provider 抽象層の核心は、異なるプロバイダーの API を統一インターフェースで呼び出せることにある:

# Dify の Model Interface 概念モデル
class ModelInterface:
    """全 LLM Provider に共通のインターフェース"""
    
    def invoke(
        self,
        model: str,
        credentials: dict,
        prompt_messages: list[PromptMessage],
        model_parameters: dict,
        tools: list[Tool] | None = None,
        stop: list[str] | None = None,
        stream: bool = False,
        user: str | None = None,
    ) -> LLMResult | Generator[LLMResultChunk]:
        """
        統一的なモデル呼び出しインターフェース。
        プロバイダー固有のパラメータ変換は内部で処理される。
        """
        pass
    
    def get_num_tokens(
        self,
        model: str,
        credentials: dict,
        prompt_messages: list[PromptMessage],
    ) -> int:
        """トークン数の事前計算"""
        pass
    
    def validate_credentials(
        self,
        model: str,
        credentials: dict,
    ) -> None:
        """クレデンシャルの事前検証"""
        pass

2.3 パラメータマッピングの実態

各プロバイダーの API は微妙に異なるパラメータ名・形式を使用する。Provider 抽象層はこれを透過的に変換する:

Dify 統一パラメータOpenAIAnthropicAzure OpenAIOllama
temperaturetemperaturetemperaturetemperaturetemperature
max_tokensmax_tokensmax_tokensmax_tokensnum_predict
stopstopstop_sequencesstopstop
toolstoolstoolstoolstools
streamstreamstreamstreamstream
response_formatresponse_formatN/A (別手法)response_formatformat

3. Workspace レベルのモデル管理

3.1 なぜ Workspace レベルなのか

Dify では、Model Provider の設定はアプリケーション単位ではなく Workspace 単位で管理される。この設計判断には明確な理由がある:

graph TB
    subgraph "Workspace A(営業部門)"
        APP1[顧客対応 Bot]
        APP2[提案書生成]
        APP3[FAQ 検索]
        
        subgraph "Workspace A の Model Config"
            M1[OpenAI GPT-4o<br/>API Key: ****]
            M2[Azure OpenAI<br/>Endpoint: jpeast]
        end
    end
    
    subgraph "Workspace B(開発部門)"
        APP4[コードレビュー]
        APP5[ドキュメント生成]
        
        subgraph "Workspace B の Model Config"
            M3[Anthropic Claude<br/>API Key: ****]
            M4[Ollama Llama3<br/>Local]
        end
    end
    
    APP1 --> M1
    APP2 --> M2
    APP3 --> M1
    APP4 --> M3
    APP5 --> M4
設計意図説明
API キーの集約管理各アプリに散在させず、Workspace 管理者が一元管理
コスト可視化Workspace 単位でのトークン消費量・費用の把握
部門別ガバナンス部門ごとに利用可能なモデルを制限可能
モデル切り替えの効率化Workspace 設定を変更するだけで全アプリに反映

3.2 モデル切り替えのユースケース

企業が実際にモデルを切り替える典型的なシナリオ:

  1. コスト最適化: GPT-4o から GPT-4o-mini への切り替え(精度を許容しつつコスト削減)
  2. 規制対応: 外部 API からオンプレミスローカル LLM への移行
  3. 性能向上: 新モデルリリース時の段階的移行
  4. 障害対応: 特定プロバイダーの障害時にフォールバック先への切り替え
  5. マルチモデル戦略: タスク種別に応じた最適モデルの使い分け

4. Plugin Architecture:拡張性の設計

4.1 Plugin によるカスタム Provider の追加

Dify は Plugin 機構を通じて、標準でサポートされていない Model Provider を追加できる:

graph LR
    subgraph "Dify Core"
        PA[Plugin Architecture]
        MR[Model Runtime]
    end
    
    subgraph "Built-in Providers"
        OP[OpenAI]
        AN[Anthropic]
        AZ[Azure]
    end
    
    subgraph "Custom Plugins"
        CP1[社内 LLM Gateway]
        CP2[国産 LLM<br/>ELYZA / PLaMo]
        CP3[vLLM Cluster]
    end
    
    PA --> OP
    PA --> AN
    PA --> AZ
    PA --> CP1
    PA --> CP2
    PA --> CP3
    PA --> MR

4.2 Model Designing Rules

公式ドキュメントで公開されている Model Designing Rules は、Plugin 開発者が従うべきインターフェース規約を定義している:

# Model Plugin の必須実装項目
model_plugin:
  # 1. Provider 定義
  provider_manifest:
    - プロバイダー名・アイコン・説明
    - サポートするモデルタイプ
    - クレデンシャルスキーマ
  
  # 2. モデル定義
  model_manifest:
    - モデル名・バージョン
    - 能力宣言 (features)
    - パラメータ制約 (context_length, max_tokens)
    - 価格情報(任意)
  
  # 3. Runtime 実装
  runtime:
    - invoke(): 同期/ストリーミング呼び出し
    - get_num_tokens(): トークン計算
    - validate_credentials(): 認証情報検証

この規約に従うことで、カスタム Provider は Dify のすべての機能(Workflow ノードでのモデル選択、Agent のモデル指定、Knowledge Base の Embedding モデル選択など)と自動的に統合される。

4.3 Plugin の分離による安定性

Plugin は独立したプロセスとして実行されるため、カスタム Provider のバグや障害が Dify コアに影響しない:

アーキテクチャ特性効果
プロセス分離Plugin のクラッシュがコアに波及しない
バージョン独立Plugin と Dify Core を独立にアップデート可能
リソース制限Plugin ごとにメモリ・CPU を制限可能
セキュリティ境界Plugin のクレデンシャルがコアと分離

5. 設計上のトレードオフ

5.1 抽象化の限界

Provider 抽象層は多くの差異を吸収するが、すべてを透過的にすることはできない:

差異の種類抽象化の可否対応方法
基本的な Chat Completion完全に抽象化可能統一インターフェース
Function Callingほぼ抽象化可能ツール定義の統一フォーマット
Vision(画像入力)条件付きで抽象化Feature フラグによる能力宣言
コンテキスト長メタデータとして管理アプリ側で制約を確認
レート制限プロバイダー依存Runtime 層でリトライ/キューイング
JSON Modeプロバイダーにより実装が異なる部分的な抽象化 + フォールバック
Multimodal(音声・動画)プロバイダー間で大きな差異モデルタイプ別の個別対応
Fine-tuning APIプロバイダーごとに全く異なる抽象化対象外

5.2 「最小公約数」問題への対処

抽象層の典型的なリスクは、「最小公約数」的な API しか提供できず、各プロバイダーの固有機能を活用できなくなることだ。Dify はこれを Feature フラグ + モデルパラメータの拡張で解決している:

# Feature フラグによる能力の動的チェック
model_config = get_model_config("gpt-4o")

if "function_calling" in model_config.features:
    # Function Calling 対応のフローを実行
    result = invoke_with_tools(model, tools, prompt)
elif "vision" in model_config.features:
    # Vision 対応のフローを実行
    result = invoke_with_images(model, images, prompt)
else:
    # 基本的な Text Completion のみ
    result = invoke_text(model, prompt)

6. エンタープライズにおける Provider 抽象層の戦略的価値

6.1 ベンダーロックイン回避

graph TB
    subgraph "ベンダーロックインの比較"
        direction LR
        subgraph "直接統合"
            A1[App] -->|"OpenAI SDK"| B1[OpenAI]
            A1 -.->|"移行コスト: 高"| C1[Anthropic]
        end
        
        subgraph "Dify Provider 抽象層"
            A2[App] --> D2[Provider Layer]
            D2 -->|"設定変更のみ"| B2[OpenAI]
            D2 -->|"設定変更のみ"| C2[Anthropic]
            D2 -->|"設定変更のみ"| E2[Azure]
        end
    end

6.2 マルチモデル戦略の実現

先進的な企業は、単一モデルではなくタスク種別に応じたマルチモデル戦略を採用しつつある:

タスク種別推奨モデル選定理由
複雑な推論・分析GPT-4o / Claude Opus高精度が必要
大量の定型処理GPT-4o-mini / Claude Haikuコスト効率
日本語特化タスク国産 LLM / Qwen日本語性能
機密データ処理Ollama (ローカル)データ外部送信不可
Embeddingtext-embedding-3-smallコストと精度のバランス
画像認識GPT-4o / Gemini Pro Visionマルチモーダル対応

Dify の Provider 抽象層は、同一 Workflow 内で異なるノードに異なるモデルを指定することを可能にしている。これにより、上記のマルチモデル戦略を Workflow の設計レベルで実現できる。

6.3 コスト管理とガバナンス

Workspace レベルでの Provider 管理は、以下のガバナンス機能を自然に提供する:

  • 利用量の可視化: Workspace / アプリケーション / ユーザー単位でのトークン消費量追跡
  • 予算制御: Workspace ごとの利用上限設定
  • モデル利用ポリシー: 特定の Workspace では特定のモデルのみ利用可能にする制限
  • 監査証跡: どのユーザーがどのモデルにどのようなクエリを送ったかのログ

7. 他プラットフォームとの比較

項目DifyLangChainAmazon BedrockAzure AI Studio
抽象層の粒度Provider + ModelChain / LLM クラスAPI GatewayHub + Endpoint
GUI でのモデル管理ありなしありあり
カスタム ProviderPlugin で追加可能Python クラス実装Custom Model Importカスタムエンドポイント
Workspace 単位管理ありなしAccount 単位Resource Group 単位
Feature フラグモデル単位で宣言なし(コードで判定)モデル単位モデル単位
OSSYesYesNoNo
運用コスト中(Self-Host)低(フレームワーク)高(AWS 課金)高(Azure 課金)

まとめ

Dify の Provider 抽象層は「多くのモデルに対応している」という表面的な特徴の裏に、以下の設計哲学を持つ:

  1. アプリケーション層とモデル層の明確な分離: アプリケーションのビジネスロジックがモデル選択に依存しない
  2. Workspace レベルの統一管理: API キー管理、コスト管理、ガバナンスを一箇所に集約
  3. Plugin による拡張性: 標準でサポートされないモデルを、同一インターフェースで追加可能
  4. Feature フラグによる柔軟性: 抽象化と各モデル固有機能の活用を両立

エンタープライズにとって、Provider 抽象層の価値は「接続できるモデルの数」ではなく、モデルの選択・切り替え・併用がビジネス判断としてできるようになることにある。Dify はその判断を、コード変更なしに、管理画面上で完結させる設計を実現している。


参考資料