> ## Documentation index
> Fetch the complete documentation index at: https://dify-docs.docs7.io/llms.txt
> Ask it with GET https://dify-docs.docs7.io/ask?q=<keywords or question>. Short keywords rank best.
> Use these to discover all available pages before exploring further.

# モデル API インターフェース

> Dify モデルプラグインを実装する際のインターフェースとデータ構造。LLM、TextEmbedding、Rerank、Speech2Text、Text2Speech、Moderation モデルを対象とします

> このドキュメントは AI によって自動翻訳されています。不正確な部分がある場合は、[英語版](/en/develop-plugin/features-and-specs/plugin-types/model-schema) を参照してください。

## はじめに

このページは、モデルプラグインを通じて AI モデルを Dify と統合する際に実装するインターフェースとデータ構造の技術リファレンスです。

<Note>
この API リファレンスに入る前に、概念モデルについては [モデル設計ルール](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules) を、手順を追った解説については [新しいモデルプロバイダーの作成](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider) を読むことをお勧めします。
</Note>

### クイック判断: どのメソッドを実装すべきか

| モデルの種類 | 実装するもの |
| :--- | :--- |
| チャット/補完 LLM | `LargeLanguageModel._invoke`、`_get_num_tokens` |
| 埋め込みモデル | `TextEmbeddingModel._invoke`、`_get_num_tokens` |
| 音声認識 | `Speech2TextModel._invoke` |
| 音声合成 | `Text2SpeechModel._invoke` |
| モデレーション | `ModerationModel._invoke` |

すべてのプロバイダーは `validate_provider_credentials`（プロバイダーレベルの認証）も実装します。モデルがユーザーによって設定可能な場合は、モデルタイプごとに `validate_credentials` も実装します。

<CardGroup cols={2}>
  <Card title="プロバイダー実装" icon="plug" href="#モデルプロバイダー">
    さまざまな AI サービスプロバイダー向けにモデルプロバイダークラスを実装する方法を学びます
  </Card>
  <Card title="モデルタイプ" icon="layer-group" href="#モデル">
    サポートされている 5 つのモデルタイプ（LLM、Embedding、Rerank、Speech2Text、Text2Speech）の実装の詳細
  </Card>
  <Card title="データ構造" icon="database" href="#エンティティ">
    モデル API で使用されるすべてのデータ構造の包括的なリファレンス
  </Card>
  <Card title="エラーハンドリング" icon="triangle-exclamation" href="#共通インターフェース">
    適切なエラーマッピングと例外処理のガイドライン
  </Card>
</CardGroup>

## モデルプロバイダー

すべてのモデルプロバイダーは `__base.model_provider.ModelProvider` 基底クラスを継承し、認証情報検証インターフェースを実装する必要があります。

### プロバイダー認証情報検証

<CodeGroup>
```python Core Implementation
def validate_provider_credentials(self, credentials: dict) -> None:
    """
    Validate provider credentials by making a test API call
    
    Parameters:
        credentials: Provider credentials as defined in `provider_credential_schema`
        
    Raises:
        CredentialsValidateFailedError: If validation fails
    """
    try:
        # Example implementation: validate using an LLM model instance
        model_instance = self.get_model_instance(ModelType.LLM)
        model_instance.validate_credentials(
            model="example-model", 
            credentials=credentials
        )
    except Exception as ex:
        logger.exception(f"Credential validation failed")
        raise CredentialsValidateFailedError(f"Invalid credentials: {str(ex)}")
```

```python Custom Model Provider
class XinferenceProvider(Provider):
    def validate_provider_credentials(self, credentials: dict) -> None:
        """
        For custom-only model providers, a simple implementation is sufficient
        as validation happens at the model level
        """
        pass
```
</CodeGroup>

<ParamField path="credentials" type="dict">
  プロバイダーの YAML 設定の `provider_credential_schema` で定義された認証情報。通常は `api_key` や `organization_id` などのフィールドです。
</ParamField>

<Warning>
検証が失敗した場合、実装は `CredentialsValidateFailedError` 例外をスローする必要があります。これにより、Dify UI で適切なエラーハンドリングが行われます。
</Warning>

<Tip>
事前定義されたモデルプロバイダーの場合は、認証情報を API に対して検証する徹底した検証メソッドを実装してください。カスタムモデルプロバイダー（各モデルが独自の認証情報を持つ場合）では、簡略化された実装で十分です。
</Tip>

## モデル

Dify は 5 つの異なるモデルタイプをサポートしており、それぞれに独自のインターフェースがあります。すべてのモデルタイプは、以下の共通要件を満たします。

### 共通インターフェース

タイプに関係なく、すべてのモデル実装はこれら 2 つの基本メソッドを実装する必要があります。

#### 1. モデル認証情報検証

<CodeGroup>
```python Implementation
def validate_credentials(self, model: str, credentials: dict) -> None:
    """
    Validate that the provided credentials work with the specified model
    
    Parameters:
        model: The specific model identifier (e.g., "gpt-4")
        credentials: Authentication details for the model
        
    Raises:
        CredentialsValidateFailedError: If validation fails
    """
    try:
        # Make a lightweight API call to verify credentials
        # Example: List available models or check account status
        response = self._api_client.validate_api_key(credentials["api_key"])
        
        # Verify the specific model is available if applicable
        if model not in response.get("available_models", []):
            raise CredentialsValidateFailedError(f"Model {model} is not available")
            
    except ApiException as e:
        raise CredentialsValidateFailedError(str(e))
```
</CodeGroup>

<ParamField path="model" type="string" required>
  検証する特定のモデル識別子（例: "gpt-4"、"claude-3-opus"）
</ParamField>

<ParamField path="credentials" type="dict" required>
  プロバイダーの設定で定義された認証情報
</ParamField>

#### 2. エラーマッピング

<CodeGroup>
```python Implementation
@property
def _invoke_error_mapping(self) -> dict[type[InvokeError], list[type[Exception]]]:
    """
    Map provider-specific exceptions to standardized Dify error types
    
    Returns:
        Dictionary mapping Dify error types to lists of provider exception types
    """
    return {
        InvokeConnectionError: [
            requests.exceptions.ConnectionError,
            requests.exceptions.Timeout,
            ConnectionRefusedError
        ],
        InvokeServerUnavailableError: [
            ServiceUnavailableError,
            HTTPStatusError
        ],
        InvokeRateLimitError: [
            RateLimitExceededError,
            QuotaExceededError
        ],
        InvokeAuthorizationError: [
            AuthenticationError,
            InvalidAPIKeyError,
            PermissionDeniedError
        ],
        InvokeBadRequestError: [
            InvalidRequestError,
            ValidationError
        ]
    }
```
</CodeGroup>

<Accordion title="利用可能なエラータイプ">
  <ParamField path="InvokeConnectionError" type="class">
    ネットワーク接続の失敗、タイムアウト
  </ParamField>
  <ParamField path="InvokeServerUnavailableError" type="class">
    サービスプロバイダーがダウンまたは利用不可
  </ParamField>
  <ParamField path="InvokeRateLimitError" type="class">
    レート制限またはクォータ制限に到達
  </ParamField>
  <ParamField path="InvokeAuthorizationError" type="class">
    認証または権限の問題
  </ParamField>
  <ParamField path="InvokeBadRequestError" type="class">
    無効なパラメータまたはリクエスト
  </ParamField>
</Accordion>

<Tip>
エラーマッピングに頼る代わりに、これらの標準化されたエラータイプをコード内で直接スローすることもできます。この方法では、エラーメッセージをより細かく制御できます。
</Tip>

### LLM 実装

大規模言語モデルプロバイダーを実装するには、`__base.large_language_model.LargeLanguageModel` 基底クラスを継承し、これらのメソッドを実装します。

#### 1. モデル呼び出し

このコアメソッドは、言語モデルへのストリーミングおよび非ストリーミング API 呼び出しの両方を処理します。

<CodeGroup>
```python Core Implementation
def _invoke(
    self, 
    model: str, 
    credentials: dict,
    prompt_messages: list[PromptMessage], 
    model_parameters: dict,
    tools: Optional[list[PromptMessageTool]] = None, 
    stop: Optional[list[str]] = None,
    stream: bool = True, 
    user: Optional[str] = None
) -> Union[LLMResult, Generator[LLMResultChunk, None, None]]:
    """
    Invoke the language model
    """
    # Prepare API parameters
    api_params = self._prepare_api_parameters(
        model, 
        credentials, 
        prompt_messages, 
        model_parameters,
        tools, 
        stop
    )
    
    try:
        # Choose between streaming and non-streaming implementation
        if stream:
            return self._invoke_stream(model, api_params, user)
        else:
            return self._invoke_sync(model, api_params, user)
            
    except Exception as e:
        # Map errors using the error mapping property
        self._handle_api_error(e)

# Helper methods for streaming and non-streaming calls
def _invoke_stream(self, model, api_params, user):
    # Implement streaming call and yield chunks
    pass
    
def _invoke_sync(self, model, api_params, user):
    # Implement synchronous call and return complete result
    pass
```
</CodeGroup>

<Accordion title="パラメータ">
  <ParamField path="model" type="string" required>
    モデル識別子（例: "gpt-4"、"claude-3"）
  </ParamField>
  
  <ParamField path="credentials" type="dict" required>
    API の認証情報
  </ParamField>
  
  <ParamField path="prompt_messages" type="list[PromptMessage]" required>
    Dify の標準化された形式のメッセージリスト:

    - `completion` モデルの場合: 単一の `UserPromptMessage` を含めます。
    - `chat` モデルの場合: 必要に応じて `SystemPromptMessage`、`UserPromptMessage`、`AssistantPromptMessage`、`ToolPromptMessage` を含めます。
  </ParamField>
  
  <ParamField path="model_parameters" type="dict" required>
    モデルの YAML 設定で定義されたモデル固有のパラメータ（temperature、top_p など）
  </ParamField>
  
  <ParamField path="tools" type="list[PromptMessageTool]">
    関数呼び出し機能のためのツール定義
  </ParamField>
  
  <ParamField path="stop" type="list[string]">
    検出されるとモデルの生成を停止するストップシーケンス
  </ParamField>
  
  <ParamField path="stream" type="boolean" default={true}>
    ストリーミングレスポンスを返すかどうか
  </ParamField>
  
  <ParamField path="user" type="string">
    API 監視用のユーザー識別子
  </ParamField>
</Accordion>

<Accordion title="戻り値">
  <ParamField path="stream=True" type="Generator[LLMResultChunk, None, None]">
    レスポンスが利用可能になるたびにチャンクを yield するジェネレータ
  </ParamField>
  
  <ParamField path="stream=False" type="LLMResult">
    生成されたテキスト全体を含む完全なレスポンスオブジェクト
  </ParamField>
</Accordion>

<Tip>
コードを整理し、保守しやすく保つために、ストリーミング呼び出しと非ストリーミング呼び出しで別々のヘルパーメソッドを実装することをお勧めします。
</Tip>

#### 2. トークンカウント

<CodeGroup>
```python Implementation
def get_num_tokens(
    self, 
    model: str, 
    credentials: dict, 
    prompt_messages: list[PromptMessage],
    tools: Optional[list[PromptMessageTool]] = None
) -> int:
    """
    Calculate the number of tokens in the prompt
    """
    # Convert prompt_messages to the format expected by the tokenizer
    text = self._convert_messages_to_text(prompt_messages)
    
    try:
        # Use the appropriate tokenizer for this model
        tokenizer = self._get_tokenizer(model)
        return len(tokenizer.encode(text))
    except Exception:
        # Fall back to a generic tokenizer
        return self._get_num_tokens_by_gpt2(text)
```
</CodeGroup>

<Info>
モデルがトークナイザーを提供していない場合は、基底クラスの `_get_num_tokens_by_gpt2(text)` メソッドを使用して妥当な近似値を求めることができます。
</Info>

#### 3. カスタムモデルスキーマ（オプション）

<CodeGroup>
```python Implementation
def get_customizable_model_schema(
    self, 
    model: str, 
    credentials: dict
) -> Optional[AIModelEntity]:
    """
    Get parameter schema for custom models
    """
    # For fine-tuned models, you might return the base model's schema
    if model.startswith("ft:"):
        base_model = self._extract_base_model(model)
        return self._get_predefined_model_schema(base_model)
    
    # For standard models, return None to use the predefined schema
    return None
```
</CodeGroup>

<Info>
このメソッドは、カスタムモデルをサポートするプロバイダーにのみ必要です。カスタムモデルが基本モデルからパラメータルールを継承できるようにします。
</Info>

### TextEmbedding 実装

<Info>
テキスト埋め込みモデルは、テキストを意味を捉えた高次元ベクトルに変換します。検索、類似性検索、分類に役立ちます。
</Info>

テキスト埋め込みプロバイダーを実装するには、`__base.text_embedding_model.TextEmbeddingModel` 基底クラスを継承します。

#### 1. コア埋め込みメソッド

<CodeGroup>
```python Implementation
def _invoke(
    self, 
    model: str, 
    credentials: dict,
    texts: list[str], 
    user: Optional[str] = None
) -> TextEmbeddingResult:
    """
    Generate embedding vectors for multiple texts
    """
    # Set up API client with credentials
    client = self._get_client(credentials)
    
    # Handle batching if needed
    batch_size = self._get_batch_size(model)
    all_embeddings = []
    total_tokens = 0
    start_time = time.time()
    
    # Process in batches to avoid API limits
    for i in range(0, len(texts), batch_size):
        batch = texts[i:i+batch_size]
        
        # Make API call to the embeddings endpoint
        response = client.embeddings.create(
            model=model,
            input=batch,
            user=user
        )
        
        # Extract embeddings from response
        batch_embeddings = [item.embedding for item in response.data]
        all_embeddings.extend(batch_embeddings)
        
        # Track token usage
        total_tokens += response.usage.total_tokens
    
    # Calculate usage metrics
    elapsed_time = time.time() - start_time
    usage = self._create_embedding_usage(
        model=model,
        tokens=total_tokens,
        latency=elapsed_time
    )
    
    return TextEmbeddingResult(
        model=model,
        embeddings=all_embeddings,
        usage=usage
    )
```
</CodeGroup>

<Accordion title="パラメータ">
  <ParamField path="model" type="string" required>
    埋め込みモデル識別子
  </ParamField>
  
  <ParamField path="credentials" type="dict" required>
    埋め込みサービスの認証情報
  </ParamField>
  
  <ParamField path="texts" type="list[string]" required>
    埋め込むテキスト入力のリスト
  </ParamField>
  
  <ParamField path="user" type="string">
    API 監視用のユーザー識別子
  </ParamField>
</Accordion>

<Accordion title="戻り値">
  <ParamField path="TextEmbeddingResult" type="object" required>
    以下を含む構造化されたレスポンス:

    - `model`: 埋め込みに使用したモデル。
    - `embeddings`: 入力テキストと同じ順序の埋め込みベクトル。
    - `usage`: トークン使用量とコストに関するメタデータ。
  </ParamField>
</Accordion>

#### 2. トークンカウントメソッド

<CodeGroup>
```python Implementation
def get_num_tokens(
    self, 
    model: str, 
    credentials: dict, 
    texts: list[str]
) -> int:
    """
    Calculate the number of tokens in the texts to be embedded
    """
    # Join all texts to estimate token count
    combined_text = " ".join(texts)
    
    try:
        # Use the appropriate tokenizer for this model
        tokenizer = self._get_tokenizer(model)
        return len(tokenizer.encode(combined_text))
    except Exception:
        # Fall back to a generic tokenizer
        return self._get_num_tokens_by_gpt2(combined_text)
```
</CodeGroup>

<Tip>
埋め込みモデルでは、正確なトークンカウントはコスト見積もりには重要ですが、機能上は重要ではありません。`_get_num_tokens_by_gpt2` メソッドは、ほとんどのモデルに対して妥当な近似値を提供します。
</Tip>

### Rerank 実装

<Info>
リランクモデルは、通常は初回の検索フェーズの後に、クエリとの関連性に基づいて候補ドキュメントのセットを並べ替えることで、検索品質の向上に役立ちます。
</Info>

リランクプロバイダーを実装するには、`__base.rerank_model.RerankModel` 基底クラスを継承します。

<CodeGroup>
```python Implementation
def _invoke(
    self, 
    model: str, 
    credentials: dict,
    query: str, 
    docs: list[str], 
    score_threshold: Optional[float] = None, 
    top_n: Optional[int] = None,
    user: Optional[str] = None
) -> RerankResult:
    """
    Rerank documents based on relevance to the query
    """
    # Set up API client with credentials
    client = self._get_client(credentials)
    
    # Prepare request data
    request_data = {
        "query": query,
        "documents": docs,
    }
    
    # Call reranking API endpoint
    response = client.rerank(
        model=model,
        **request_data,
        user=user
    )
    
    # Process results
    ranked_results = []
    for i, result in enumerate(response.results):
        # Create RerankDocument for each result
        doc = RerankDocument(
            index=result.document_index,  # Original index in docs list
            text=docs[result.document_index],  # Original text
            score=result.relevance_score  # Relevance score
        )
        ranked_results.append(doc)
    
    # Sort by score in descending order
    ranked_results.sort(key=lambda x: x.score, reverse=True)
    
    # Apply score threshold filtering if specified
    if score_threshold is not None:
        ranked_results = [doc for doc in ranked_results if doc.score >= score_threshold]
    
    # Apply top_n limit if specified
    if top_n is not None and top_n > 0:
        ranked_results = ranked_results[:top_n]
    
    return RerankResult(
        model=model,
        docs=ranked_results
    )
```
</CodeGroup>

<Accordion title="パラメータ">
  <ParamField path="model" type="string" required>
    リランクモデル識別子
  </ParamField>
  
  <ParamField path="credentials" type="dict" required>
    API の認証情報
  </ParamField>
  
  <ParamField path="query" type="string" required>
    検索クエリのテキスト
  </ParamField>
  
  <ParamField path="docs" type="list[string]" required>
    リランクするドキュメントテキストのリスト
  </ParamField>
  
  <ParamField path="score_threshold" type="float">
    結果に含めるためにドキュメントが達する必要のある最小スコア
  </ParamField>
  
  <ParamField path="top_n" type="int">
    返す結果の最大数
  </ParamField>
  
  <ParamField path="user" type="string">
    API 監視用のユーザー識別子
  </ParamField>
</Accordion>

<Accordion title="戻り値">
  <ParamField path="RerankResult" type="object" required>
    以下を含む構造化されたレスポンス:

    - `model`: リランクに使用したモデル。
    - `docs`: index、text、score を持つ `RerankDocument` オブジェクトのリスト。
  </ParamField>
</Accordion>

<Warning>
リランクは計算コストが高くなることがあり、特に大規模なドキュメントセットでは顕著です。タイムアウトや過度なリソース消費を避けるため、大規模なドキュメントコレクションにはバッチ処理を実装してください。
</Warning>

### Speech2Text 実装

<Info>
音声認識モデルは、音声ファイル内の話し言葉を書き起こしテキストに変換します。文字起こしサービス、音声コマンド、アクセシビリティ機能などのアプリケーションを実現します。
</Info>

音声認識プロバイダーを実装するには、`__base.speech2text_model.Speech2TextModel` 基底クラスを継承します。

<CodeGroup>
```python Implementation
def _invoke(
    self, 
    model: str, 
    credentials: dict,
    file: IO[bytes], 
    user: Optional[str] = None
) -> str:
    """
    Convert speech audio to text
    """
    # Set up API client with credentials
    client = self._get_client(credentials)
    
    try:
        # Determine the file format
        file_format = self._detect_audio_format(file)
        
        # Prepare the file for API submission
        # Most APIs require either a file path or binary data
        audio_data = file.read()
        
        # Call the speech-to-text API
        response = client.audio.transcriptions.create(
            model=model,
            file=("audio.mp3", audio_data),  # Adjust filename based on actual format
            user=user
        )
        
        # Extract and return the transcribed text
        return response.text
        
    except Exception as e:
        # Map to appropriate error type
        self._handle_api_error(e)
        
    finally:
        # Reset file pointer for potential reuse
        file.seek(0)
```

```python Helper Methods
def _detect_audio_format(self, file: IO[bytes]) -> str:
    """
    Detect the audio format based on file header
    """
    # Read the first few bytes to check the file signature
    header = file.read(12)
    file.seek(0)  # Reset file pointer
    
    # Check for common audio format signatures
    if header.startswith(b'RIFF') and header[8:12] == b'WAVE':
        return 'wav'
    elif header.startswith(b'ID3') or header.startswith(b'\xFF\xFB'):
        return 'mp3'
    elif header.startswith(b'OggS'):
        return 'ogg'
    elif header.startswith(b'fLaC'):
        return 'flac'
    else:
        # Default or additional format checks
        return 'mp3'  # Default assumption
```
</CodeGroup>

<Accordion title="パラメータ">
  <ParamField path="model" type="string" required>
    音声認識モデル識別子
  </ParamField>
  
  <ParamField path="credentials" type="dict" required>
    API の認証情報
  </ParamField>
  
  <ParamField path="file" type="IO[bytes]" required>
    文字起こしする音声を含むバイナリファイルオブジェクト
  </ParamField>
  
  <ParamField path="user" type="string">
    API 監視用のユーザー識別子
  </ParamField>
</Accordion>

<Accordion title="戻り値">
  <ParamField path="text" type="string" required>
    音声ファイルから書き起こされたテキスト
  </ParamField>
</Accordion>

<Tip>
さまざまなファイルタイプを適切に処理するには、音声フォーマットの検出が重要です。例に示すように、ファイルヘッダーからフォーマットを検出するヘルパーメソッドの実装を検討してください。
</Tip>

<Warning>
一部の音声認識 API にはファイルサイズの制限があります。必要に応じて、大きな音声ファイルにはチャンク処理の実装を検討してください。
</Warning>

### Text2Speech 実装

<Info>
音声合成モデルは、書かれたテキストを自然な音声に変換します。音声アシスタント、スクリーンリーダー、音声コンテンツ生成などのアプリケーションを実現します。
</Info>

音声合成プロバイダーを実装するには、`__base.text2speech_model.Text2SpeechModel` 基底クラスを継承します。

<CodeGroup>
```python Implementation
def _invoke(
    self, 
    model: str, 
    credentials: dict, 
    content_text: str, 
    streaming: bool,
    user: Optional[str] = None
) -> Union[bytes, Generator[bytes, None, None]]:
    """
    Convert text to speech audio
    """
    # Set up API client with credentials
    client = self._get_client(credentials)
    
    # Get voice settings based on model
    voice = self._get_voice_for_model(model)
    
    try:
        # Choose implementation based on streaming preference
        if streaming:
            return self._stream_audio(
                client=client,
                model=model,
                text=content_text,
                voice=voice,
                user=user
            )
        else:
            return self._generate_complete_audio(
                client=client,
                model=model,
                text=content_text,
                voice=voice,
                user=user
            )
    except Exception as e:
        self._handle_api_error(e)
```

```python Helper Methods
def _stream_audio(self, client, model, text, voice, user=None):
    """
    Implementation for streaming audio output
    """
    # Make API request with stream=True
    response = client.audio.speech.create(
        model=model,
        voice=voice,
        input=text,
        stream=True,
        user=user
    )
    
    # Yield chunks as they arrive
    for chunk in response:
        if chunk:
            yield chunk
            
def _generate_complete_audio(self, client, model, text, voice, user=None):
    """
    Implementation for complete audio file generation
    """
    # Make API request for complete audio
    response = client.audio.speech.create(
        model=model,
        voice=voice,
        input=text,
        user=user
    )
    
    # Get audio data as bytes
    audio_data = response.content
    return audio_data
```
</CodeGroup>

<Accordion title="パラメータ">
  <ParamField path="model" type="string" required>
    音声合成モデル識別子
  </ParamField>
  
  <ParamField path="credentials" type="dict" required>
    API の認証情報
  </ParamField>
  
  <ParamField path="content_text" type="string" required>
    音声に変換するテキストコンテンツ
  </ParamField>
  
  <ParamField path="streaming" type="boolean" required>
    ストリーミング音声を返すか、完全なファイルを返すか
  </ParamField>
  
  <ParamField path="user" type="string">
    API 監視用のユーザー識別子
  </ParamField>
</Accordion>

<Accordion title="戻り値">
  <ParamField path="streaming=True" type="Generator[bytes, None, None]">
    音声チャンクが利用可能になるたびに yield するジェネレータ
  </ParamField>
  
  <ParamField path="streaming=False" type="bytes">
    バイトとしての完全な音声データ
  </ParamField>
</Accordion>

<Tip>
ほとんどの音声合成 API では、モデルと一緒に音声を指定する必要があります。Dify のモデル識別子とプロバイダーの音声オプションを対応付けるマッピングの実装を検討してください。
</Tip>

<Warning>
長いテキスト入力は、音声合成の品質を高めるためにチャンク分割が必要になる場合があります。句読点、数字、特殊文字を適切に処理するため、テキストの前処理の実装を検討してください。
</Warning>

### Moderation 実装

<Info>
モデレーションモデルは、有害、不適切、または安全でない可能性のある素材についてコンテンツを分析し、プラットフォームの安全性とコンテンツポリシーの維持に役立ちます。
</Info>

モデレーションプロバイダーを実装するには、`__base.moderation_model.ModerationModel` 基底クラスを継承します。

<CodeGroup>
```python Implementation
def _invoke(
    self, 
    model: str, 
    credentials: dict,
    text: str, 
    user: Optional[str] = None
) -> bool:
    """
    Analyze text for harmful content
    
    Returns:
        bool: False if the text is safe, True if it contains harmful content
    """
    # Set up API client with credentials
    client = self._get_client(credentials)
    
    try:
        # Call moderation API
        response = client.moderations.create(
            model=model,
            input=text,
            user=user
        )
        
        # Check if any categories were flagged
        result = response.results[0]
        
        # Return True if flagged in any category, False if safe
        return result.flagged
        
    except Exception as e:
        # Log the error but default to safe if there's an API issue.
        # This is a conservative approach; production systems might want
        # different fallback behavior.
        logger.error(f"Moderation API error: {str(e)}")
        return False
```

```python Detailed Implementation
def _invoke(
    self, 
    model: str, 
    credentials: dict,
    text: str, 
    user: Optional[str] = None
) -> bool:
    """
    Analyze text for harmful content with detailed category checking
    """
    # Set up API client with credentials
    client = self._get_client(credentials)
    
    try:
        # Call moderation API
        response = client.moderations.create(
            model=model,
            input=text,
            user=user
        )
        
        # Get detailed category results
        result = response.results[0]
        categories = result.categories
        
        # Check specific categories based on your application's needs
        # For example, you might want to flag certain categories but not others
        critical_violations = [
            categories.harassment,
            categories.hate,
            categories.self_harm,
            categories.sexual,
            categories.violence
        ]
        
        # Flag content if any critical category is violated
        return any(critical_violations)
        
    except Exception as e:
        self._handle_api_error(e)
        # Default to safe in case of error
        return False
```
</CodeGroup>

<Accordion title="パラメータ">
  <ParamField path="model" type="string" required>
    モデレーションモデル識別子
  </ParamField>
  
  <ParamField path="credentials" type="dict" required>
    API の認証情報
  </ParamField>
  
  <ParamField path="text" type="string" required>
    分析するテキストコンテンツ
  </ParamField>
  
  <ParamField path="user" type="string">
    API 監視用のユーザー識別子
  </ParamField>
</Accordion>

<Accordion title="戻り値">
  <ParamField path="result" type="boolean" required>
    コンテンツの安全性を示すブール値:

    - `False`: コンテンツは安全です。
    - `True`: コンテンツに有害な素材が含まれています。
  </ParamField>
</Accordion>

<Warning>
モデレーションは安全機構として使われることが多くあります。実装にあたっては、偽陰性（有害なコンテンツを通過させてしまう）と偽陽性（安全なコンテンツをブロックしてしまう）の影響を考慮してください。
</Warning>

<Tip>
多くのモデレーション API は、単なるバイナリ結果ではなく、詳細なカテゴリスコアを提供します。アプリケーションで必要な場合は、有害なコンテンツの特定のカテゴリに関するより詳細な情報を返すよう、この実装を拡張することを検討してください。
</Tip>

## エンティティ

### PromptMessageRole

会話におけるメッセージのロール。

```python
class PromptMessageRole(Enum):
    """
    Enum class for prompt message.
    """
    SYSTEM = "system"
    USER = "user"
    ASSISTANT = "assistant"
    TOOL = "tool"
```

### PromptMessageContentType

メッセージコンテンツのタイプ: プレーンテキストまたは画像。

```python
class PromptMessageContentType(Enum):
    """
    Enum class for prompt message content type.
    """
    TEXT = 'text'
    IMAGE = 'image'
```

### PromptMessageContent

メッセージコンテンツの基底クラス。型宣言のためにのみ存在し、直接インスタンス化しないでください。

```python
class PromptMessageContent(BaseModel):
    """
    Model class for prompt message content.
    """
    type: PromptMessageContentType
    data: str  # Content data
```

コンテンツは現在、テキストと画像の 2 つのタイプをサポートしており、1 つのメッセージでテキストと複数の画像を組み合わせることができます。代わりに `TextPromptMessageContent` と `ImagePromptMessageContent` をインスタンス化してください。

### TextPromptMessageContent

```python
class TextPromptMessageContent(PromptMessageContent):
    """
    Model class for text prompt message content.
    """
    type: PromptMessageContentType = PromptMessageContentType.TEXT
```

メッセージでテキストと画像を組み合わせる場合は、テキストをこのエンティティでラップして `content` リストに追加します。

### ImagePromptMessageContent

```python
class ImagePromptMessageContent(PromptMessageContent):
    """
    Model class for image prompt message content.
    """
    class DETAIL(Enum):
        LOW = 'low'
        HIGH = 'high'

    type: PromptMessageContentType = PromptMessageContentType.IMAGE
    detail: DETAIL = DETAIL.LOW  # Resolution
```

メッセージでテキストと画像を組み合わせる場合は、各画像をこのエンティティでラップして `content` リストに追加します。`data` には画像 URL または base64 エンコードされた画像文字列を指定できます。

### PromptMessage

すべてのロール固有メッセージの基底クラス。型宣言のためにのみ存在し、直接インスタンス化しないでください。

```python
class PromptMessage(ABC, BaseModel):
    """
    Model class for prompt message.
    """
    role: PromptMessageRole  # Message role
    content: Optional[str | list[PromptMessageContent]] = None  # Either a string or a content list; the list form supports multimodal input, see PromptMessageContent
    name: Optional[str] = None  # Optional name
```

### UserPromptMessage

ユーザーメッセージを表します。

```python
class UserPromptMessage(PromptMessage):
    """
    Model class for user prompt message.
    """
    role: PromptMessageRole = PromptMessageRole.USER
```

### AssistantPromptMessage

モデルの応答を表します。通常は few-shot の例やチャット履歴の入力に使用されます。

```python
class AssistantPromptMessage(PromptMessage):
    """
    Model class for assistant prompt message.
    """
    class ToolCall(BaseModel):
        """
        Model class for assistant prompt message tool call.
        """
        class ToolCallFunction(BaseModel):
            """
            Model class for assistant prompt message tool call function.
            """
            name: str  # Tool name
            arguments: str  # Tool parameters

        id: str  # Tool call ID; only meaningful for OpenAI tool calls. Uniquely identifies one invocation, since the same tool can be called multiple times
        type: str  # Defaults to "function"
        function: ToolCallFunction  # Tool call information

    role: PromptMessageRole = PromptMessageRole.ASSISTANT
    tool_calls: list[ToolCall] = []  # Model's tool call results (only returned when tools are passed in and the model decides to call them)
```

`tool_calls` は、リクエストに `tools` が含まれているときにモデルが返すツール呼び出しを保持します。

### SystemPromptMessage

システムメッセージを表します。通常はモデルのシステム指示を設定するために使用されます。

```python
class SystemPromptMessage(PromptMessage):
    """
    Model class for system prompt message.
    """
    role: PromptMessageRole = PromptMessageRole.SYSTEM
```

### ToolPromptMessage

ツールメッセージを表します。ツールの実行結果を次のステップの計画のためにモデルに渡します。

```python
class ToolPromptMessage(PromptMessage):
    """
    Model class for tool prompt message.
    """
    role: PromptMessageRole = PromptMessageRole.TOOL
    tool_call_id: str  # Tool call ID; if the provider doesn't support OpenAI tool calls, you can pass the tool name instead
```

ツールの実行結果は、継承した `content` フィールドを通じて渡します。

### PromptMessageTool

```python
class PromptMessageTool(BaseModel):
    """
    Model class for prompt message tool.
    """
    name: str  # Tool name
    description: str  # Tool description
    parameters: dict  # Tool parameters dict
```

### LLMResult

```python
class LLMResult(BaseModel):
    """
    Model class for llm result.
    """
    model: str  # Model actually used
    prompt_messages: list[PromptMessage]  # Prompt message list
    message: AssistantPromptMessage  # Reply message
    usage: LLMUsage  # Token usage and cost information
    system_fingerprint: Optional[str] = None  # Request fingerprint; see OpenAI's parameter definition
```

### LLMResultChunkDelta

ストリーミングレスポンスの各チャンク内の増分デルタ。

```python
class LLMResultChunkDelta(BaseModel):
    """
    Model class for llm result chunk delta.
    """
    index: int  # Sequence number
    message: AssistantPromptMessage  # Reply message
    usage: Optional[LLMUsage] = None  # Token usage and cost information; only returned in the last chunk
    finish_reason: Optional[str] = None  # Completion reason; only returned in the last chunk
```

### LLMResultChunk

ストリーミングレスポンス内の単一チャンク。

```python
class LLMResultChunk(BaseModel):
    """
    Model class for llm result chunk.
    """
    model: str  # Model actually used
    prompt_messages: list[PromptMessage]  # Prompt message list
    system_fingerprint: Optional[str] = None  # Request fingerprint; see OpenAI's parameter definition
    delta: LLMResultChunkDelta  # Content changes in this chunk
```

### LLMUsage

```python
class LLMUsage(ModelUsage):
    """
    Model class for llm usage.
    """
    prompt_tokens: int  # Tokens used by the prompt
    prompt_unit_price: Decimal  # Prompt unit price
    prompt_price_unit: Decimal  # Prompt price unit, i.e., the number of tokens the unit price applies to
    prompt_price: Decimal  # Prompt cost
    completion_tokens: int  # Tokens used by the completion
    completion_unit_price: Decimal  # Completion unit price
    completion_price_unit: Decimal  # Completion price unit, i.e., the number of tokens the unit price applies to
    completion_price: Decimal  # Completion cost
    total_tokens: int  # Total tokens used
    total_price: Decimal  # Total cost
    currency: str  # Currency unit
    latency: float  # Request latency in seconds
```

### TextEmbeddingResult

```python
class TextEmbeddingResult(BaseModel):
    """
    Model class for text embedding result.
    """
    model: str  # Model actually used
    embeddings: list[list[float]]  # Embedding vectors, in the same order as the input texts
    usage: EmbeddingUsage  # Usage information
```

### EmbeddingUsage

```python
class EmbeddingUsage(ModelUsage):
    """
    Model class for embedding usage.
    """
    tokens: int  # Tokens used
    total_tokens: int  # Total tokens used
    unit_price: Decimal  # Unit price
    price_unit: Decimal  # Price unit, i.e., the number of tokens the unit price applies to
    total_price: Decimal  # Total cost
    currency: str  # Currency unit
    latency: float  # Request latency in seconds
```

### RerankResult

```python
class RerankResult(BaseModel):
    """
    Model class for rerank result.
    """
    model: str  # Model actually used
    docs: list[RerankDocument]  # List of reranked documents
```

### RerankDocument

```python
class RerankDocument(BaseModel):
    """
    Model class for rerank document.
    """
    index: int  # Index in the original docs list
    text: str  # Document text
    score: float  # Relevance score
```

## 関連リソース

- [モデル設計ルール](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules): モデル設定の標準。
- [モデルプラグイン入門](/ja/develop-plugin/features-and-specs/plugin-types/model-designing-rules): モデルプラグインの基本概念。
- [新しいモデルを素早く統合する](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider): 既存のプロバイダーに新しいモデルを追加します。
- [新しいモデルプロバイダーを作成する](/ja/develop-plugin/dev-guides-and-walkthroughs/creating-new-model-provider): 新しいモデルプロバイダーをゼロから開発します。
