> ## 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.

# Middleware

> Einsteckbare Anbieter-Wrapper, die jede KI-Antwort abfangen und automatisch einen RAIL-Score anhängen.

Middleware ist das Muster, jede KI-Antwort abzufangen und einen RAIL-Score anzuhängen, bevor sie den Rest Ihrer Anwendung erreicht. Sie ersetzen Ihren Modell-Client durch einen RAIL-Wrapper. Der Wrapper ruft das Modell auf, bewertet die Antwort und gibt sowohl den Inhalt als auch die Scores in einem einzigen Objekt zurück.

<Info>
  **Python SDK:** [Integrationsreferenz](/integrations/overview) | **API:** [Bewertungs-Endpunkt](/api-reference/evaluation)
</Info>

## Das Problem, das es löst

Ohne Middleware bedeutet das Hinzufügen von Prüfungen für verantwortungsvolle KI zu jedem Modellaufruf, dass Sie Bewertungscode an jeder Stelle schreiben, an der Sie das Modell aufrufen, Logik duplizieren, Abdeckungslücken riskieren und Ihren Anwendungscode überfrachten:

<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>

## Funktionsweise

```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
```

Wenn Sie eine Methode auf dem RAIL-Wrapper aufrufen, geschehen drei Dinge transparent:

1. Ihre Nachrichten werden als normaler API-Aufruf an die zugrunde liegende Modell-API weitergeleitet.
2. Die Antwort des Modells wird im konfigurierten Modus an den RAIL-Bewertungs-Endpunkt übermittelt.
3. Ein umhülltes Antwortobjekt wird zurückgegeben, das den ursprünglichen Inhalt, den RAIL-Score, die Scores pro Dimension und einen `threshold_met`-Boolean enthält, alles in einem einzigen Rückgabewert.

## Unterstützte Anbieter

| Wrapper         | Umhüllt                    | Python | JavaScript |
| --------------- | -------------------------- | ------ | ---------- |
| `RAILOpenAI`    | OpenAI Chat Completions    | Ja     | Ja         |
| `RAILGemini`    | Google Gemini              | Ja     | Ja         |
| `RAILAnthropic` | Anthropic Claude           | Ja     | Ja         |
| `RAILLangChain` | Jedes LangChain-Modell     | Ja     | —          |
| Custom wrapper  | Jedes HTTP-basierte Modell | Ja     | Ja         |

## Beobachtungsmodus vs. Durchsetzungsmodus

<Tabs>
  <Tab title="Nur beobachten">
    Bewerten Sie jede Antwort, blockieren Sie nie. Verwenden Sie dies, um Qualität zu messen, ohne den Antwortfluss zu unterbrechen.

    ```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="Schwellenwert durchsetzen">
    Lösen Sie `ThresholdError` aus, wenn eine Antwort die Vorgabe nicht erfüllt.

    ```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="Automatisch neu generieren">
    Lösen Sie automatisch die sichere Regeneration aus, wenn eine Antwort unter den Schwellenwert fällt.

    ```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>

## Eigene Middleware schreiben

Wenn Sie einen Modellanbieter ohne integrierten Wrapper verwenden, bauen Sie Ihre eigene Middleware mit dem zentralen `eval()`-Aufruf:

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

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

async def rail_middleware(llm_call, messages, threshold=7.0):
    """Generic RAIL middleware for any async LLM call."""
    content = await llm_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 LLM:
content, score = await rail_middleware(my_llm_call, messages, threshold=7.5)
```

## Wie geht es weiter

<CardGroup cols={2}>
  <Card title="Konzepte: Richtlinien-Engine" icon="gavel" href="/concepts/policy-engine">
    Deklarative Regeln, um über eine Session hinweg auf Scores zu reagieren.
  </Card>

  <Card title="Python: Integrationen" icon="python" href="/integrations/overview">
    Vollständige Dokumentation und Optionen der Anbieter-Wrapper.
  </Card>

  <Card title="JavaScript: Anbieter" icon="js" href="/sdk/javascript/overview">
    TypeScript-Wrapper für OpenAI, Gemini, Anthropic.
  </Card>

  <Card title="Python: Middleware SDK" icon="layer-group" href="/sdk/python/middleware">
    RAILMiddleware - jede Modellfunktion umhüllen.
  </Card>
</CardGroup>
