> ## Documentation Index
> Fetch the complete documentation index at: https://docs.responsibleailabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# ミドルウェア

> すべての AI レスポンスをインターセプトし、RAIL スコアを自動的に付与するドロップインのプロバイダラッパー。

ミドルウェアは、すべての AI レスポンスをインターセプトし、アプリケーションの他の部分に届く前に RAIL スコアを付与するパターンです。AI クライアントを RAIL ラッパーに置き換えます。ラッパーはモデルを呼び出し、レスポンスを評価し、コンテンツとスコアの両方を 1 つのオブジェクトで返します。

<Info>
  **Python SDK:** [インテグレーションリファレンス](/integrations/overview) | **API:** [評価エンドポイント](/api-reference/evaluation)
</Info>

## 解決する課題

ミドルウェアがないと、すべての AI 呼び出しに責任ある AI のチェックを追加するには、モデルを呼び出すすべての箇所に評価コードを書くことになり、ロジックの重複、カバレッジの抜け、アプリケーションコードの煩雑化を招きます:

<CodeGroup>
  ```python Without middleware theme={null}
  # Eval code scattered everywhere
  async def get_response(user_message):
      response = await openai_client.chat.completions.create(
          model="gpt-4o", messages=[{"role": "user", "content": user_message}]
      )
      content = response.choices[0].message.content

      # Must remember to eval in every function
      score = rail_client.eval(content=content, mode="basic")
      if score.rail_score.score < 7.0:
          raise ValueError("Response below quality threshold")

      return content
  ```

  ```python With middleware theme={null}
  # Scoring is automatic - set up once, forget about it
  from rail_score_sdk.integrations import RAILOpenAI

  client = RAILOpenAI(
      openai_api_key="...",
      rail_api_key="YOUR_RAIL_API_KEY",
      eval_mode="basic",
      threshold=7.0,
  )

  async def get_response(user_message):
      response = await client.chat(messages=[{"role": "user", "content": user_message}])
      return response.content  # .rail_score and .threshold_met are also available
  ```
</CodeGroup>

## 仕組み

```mermaid theme={null}
flowchart LR
    App["Your Application"] --> Wrapper["RAIL Wrapper"]
    Wrapper -->|"1. Forward request"| Model["Model API\n(OpenAI / Gemini / Anthropic)"]
    Model -->|"2. Response content"| Wrapper
    Wrapper -->|"3. Evaluate"| RAIL["RAIL Score API"]
    RAIL -->|"Score + dimensions"| Wrapper
    Wrapper -->|"content + rail_score\n+ threshold_met"| App
```

RAIL ラッパーのメソッドを呼び出すと、3 つのことが透過的に行われます:

1. メッセージは通常の API 呼び出しとして、基盤となるモデルの API へ転送されます。
2. モデルのレスポンスは、設定したモードで RAIL 評価エンドポイントに送信されます。
3. 元のコンテンツ、RAIL スコア、次元ごとのスコア、`threshold_met` のブール値をすべて 1 つの戻り値に含む、ラップされたレスポンスオブジェクトが返されます。

## サポートされているプロバイダ

| ラッパー            | ラップ対象                   | Python | JavaScript |
| --------------- | ----------------------- | ------ | ---------- |
| `RAILOpenAI`    | OpenAI chat completions | はい     | はい         |
| `RAILGemini`    | Google Gemini           | はい     | はい         |
| `RAILAnthropic` | Anthropic Claude        | はい     | はい         |
| `RAILLangChain` | 任意の LangChain モデル       | はい     | —          |
| カスタムラッパー        | 任意の HTTP ベースのモデル        | はい     | はい         |

## 観察モードとエンフォースモード

<Tabs>
  <Tab title="観察のみ">
    すべてのレスポンスをスコアリングしますが、ブロックはしません。レスポンスのフローを中断せずに品質を測定したいときに使います。

    ```python theme={null}
    client = RAILOpenAI(
        openai_api_key="...",
        rail_api_key="...",
        eval_mode="basic",
        # No threshold — always returns response
    )

    response = await client.chat(messages=[...])
    print(response.content)        # The model's response
    print(response.rail_score)     # RAIL score (always present)
    print(response.threshold_met)  # None — no threshold configured
    ```
  </Tab>

  <Tab title="しきい値のエンフォース">
    レスポンスが基準を満たさない場合に `ThresholdError` を発生させます。

    ```python theme={null}
    client = RAILOpenAI(
        openai_api_key="...",
        rail_api_key="...",
        eval_mode="basic",
        threshold=7.0,
    )

    try:
        response = await client.chat(messages=[...])
        return response.content
    except ThresholdError as e:
        # e.rail_score and e.failed_dimensions are available
        return fallback_response()
    ```
  </Tab>

  <Tab title="自動再生成">
    レスポンスがしきい値を下回ったときに、安全な再生成を自動的にトリガーします。

    ```python theme={null}
    client = RAILOpenAI(
        openai_api_key="...",
        rail_api_key="...",
        eval_mode="basic",
        threshold=7.0,
        on_fail="regenerate",
        max_iterations=3,
    )

    # Returns the best content — original or regenerated
    response = await client.chat(messages=[...])
    print(response.content)
    print(response.iterations_taken)  # 1 if original passed
    ```
  </Tab>
</Tabs>

## カスタムミドルウェアの作成

組み込みラッパーのないモデルプロバイダを使う場合は、コアの `eval()` 呼び出しを使って独自のミドルウェアを構築します:

```python theme={null}
from rail_score_sdk import RailScoreClient

rail = RailScoreClient(api_key="...")

async def rail_middleware(model_call, messages, threshold=7.0):
    """Generic RAIL middleware for any async model call."""
    content = await model_call(messages)

    result = rail.eval(content=content, mode="basic")

    if result.rail_score.score < threshold:
        raise ValueError(
            f"Response scored {result.rail_score.score:.1f} — below threshold {threshold}. "
            f"Failed: {[d for d, s in result.dimension_scores.items() if s.score < threshold]}"
        )

    return content, result

# Use with any model:
content, score = await rail_middleware(my_model_call, messages, threshold=7.5)
```

## 次のステップ

<CardGroup cols={2}>
  <Card title="コンセプト: ポリシーエンジン" icon="gavel" href="/concepts/policy-engine">
    セッション全体でスコアに基づきアクションを取る宣言的ルール。
  </Card>

  <Card title="Python: インテグレーション" icon="python" href="/integrations/overview">
    プロバイダラッパーの完全なドキュメントとオプション。
  </Card>

  <Card title="JavaScript: プロバイダ" icon="js" href="/sdk/javascript/overview">
    OpenAI、Gemini、Anthropic 用の TypeScript ラッパー。
  </Card>

  <Card title="Python: ミドルウェア SDK" icon="layer-group" href="/sdk/python/middleware">
    RAILMiddleware — 任意のモデル関数をラップします。
  </Card>
</CardGroup>
