> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Speech Engine – Schnellstart

Diese Anleitung zeigt Ihnen, wie Sie mit Speech Engine einen sprachgesteuerten Agenten erstellen. Sie richten einen Server ein, der Ihr LLM mit ElevenLabs verbindet, und binden dann einen Browser-Client an, damit Nutzer Sprachgespräche mit Ihrem Agenten führen können.

> **Tip**
>
> Verwenden Sie den [ElevenLabs Speech Engine Skill](https://github.com/elevenlabs/skills/tree/main/speech-engine), um Ihrem Chat-Agenten eine Stimme hinzuzufügen:
>
> ```bash
> npx skills add elevenlabs/skills --skill speech-engine
> ```

## So funktioniert Speech Engine

Speech Engine verbindet Ihr LLM mit ElevenLabs, sodass Nutzer mit Ihrem Agenten sprechen und seine Antworten hören können. ElevenLabs übernimmt Speech to Text und Text to Speech, während Ihr Server die LLM-Logik bereitstellt.

```mermaid
sequenceDiagram
    participant Browser
    participant ElevenLabs

    box Your Server
        participant SDK as Speech Engine SDK
        participant LLM
    end

    Browser->>ElevenLabs: User speaks (audio)
    ElevenLabs->>SDK: Transcript (WebSocket)
    SDK->>LLM: Conversation history
    LLM->>SDK: Streamed response
    SDK->>ElevenLabs: Text chunks
    ElevenLabs->>Browser: Agent speaks (audio)
```

Jede WebSocket-Verbindung steht für ein Gespräch. Wenn der Nutzer spricht, transkribiert ElevenLabs das Audio und sendet das Transkript an Ihren Server. Ihr Server leitet es an Ihr LLM weiter und streamt die Antwort zurück. ElevenLabs wandelt den Text in Sprache um und spielt ihn im Browser ab. Das SDK übernimmt Verbindungsverwaltung, Sprecherwechsel und Unterbrechungserkennung.

## Voraussetzungen

Dieses Tutorial verwendet die API von OpenAI für das LLM. Sie benötigen einen OpenAI-API-Schlüssel, der in der Umgebungsvariable `OPENAI_API_KEY` gesetzt ist.

## Server einrichten

#### API-Schlüssel erstellen

[Erstellen Sie hier im Dashboard einen API-Schlüssel](https://elevenlabs.io/app/settings/api-keys), den Sie für den sicheren [Zugriff auf die API](/docs/de/api-reference/authentication) verwenden.

Speichern Sie den Schlüssel als verwaltetes Secret und übergeben Sie ihn je nach Präferenz an die SDKs entweder als Umgebungsvariable über eine `.env`-Datei oder direkt in der Konfiguration Ihrer App.

**`.env`**

```js title=".env"
ELEVENLABS_API_KEY=<your_api_key_here>
```

#### Abhängigkeiten installieren

```python
pip install elevenlabs openai python-dotenv
```

```typescript
npm install @elevenlabs/elevenlabs-js openai
```

#### Server öffentlich erreichbar machen

Speech Engine benötigt eine öffentlich erreichbare URL. Verwenden Sie [ngrok](https://ngrok.com), um Ihren lokalen Server öffentlich erreichbar zu machen. Der Server ist noch nicht erstellt, aber ngrok muss bereits laufen, damit Sie die URL für den nächsten Schritt haben.

```bash
ngrok http 3001
```

Kopieren Sie die Weiterleitungs-URL, z. B. `https://abc123.ngrok.io`.

#### Speech-Engine-Instanz erstellen

Verwenden Sie das SDK, um eine Speech-Engine-Instanz zu erstellen. Übergeben Sie dabei Ihre ngrok-URL mit angehängtem Pfad `/ws` als WebSocket-URL.

**`create_engine.py`**

```python title="create_engine.py"
import asyncio
from dotenv import load_dotenv
from elevenlabs import AsyncElevenLabs

load_dotenv()

elevenlabs = AsyncElevenLabs(
    api_key=os.getenv("ELEVENLABS_API_KEY"),
)


async def main():
    engine = await elevenlabs.speech_engine.create(
        name="My Speech Engine",
        speech_engine={
            # Note we use the wss protocol instead of https
            "ws_url": "wss://abc123.ngrok.io/ws",
        },
    )

    print(f"Speech Engine ID: {engine.engine_id}")


if __name__ == "__main__":
    asyncio.run(main())
```

**`create-engine.mts`**

```typescript title="create-engine.mts"
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import "dotenv/config";

const elevenlabs = new ElevenLabsClient({
  apiKey: process.env.ELEVENLABS_API_KEY,
});

const engine = await elevenlabs.speechEngine.create({
  name: "My Speech Engine",
  speechEngine: {
    // Note we use the wss protocol instead of https
    wsUrl: "wss://abc123.ngrok.io/ws",
  },
});

console.log("Speech Engine ID:", engine.engineId);
```

Führen Sie dieses Skript aus und kopieren Sie die Speech-Engine-ID, z. B. `seng_8k3m9xr4hjnfg983brhmhkd98n6`, für den nächsten Schritt.

#### Server erstellen

Erstellen Sie eine Datei namens `server.py` oder `server.mts` mit folgendem Inhalt. Dadurch wird ein Server eingerichtet, Speech Engine an den Pfad `/ws` angebunden und OpenAI zum Generieren von Antworten verwendet.

**`server.py`**

```python maxLines=0 title="server.py"
import asyncio
import os

from dotenv import load_dotenv
from openai import AsyncOpenAI
from elevenlabs import AsyncElevenLabs

load_dotenv()

# Replace with your Speech Engine ID from step 4
SPEECH_ENGINE_ID = "seng_8k3m9xr4hjnfg983brhmhkd98n6"

openai = AsyncOpenAI(
  api_key=os.getenv("OPENAI_API_KEY"),
)
elevenlabs = AsyncElevenLabs(
  api_key=os.getenv("ELEVENLABS_API_KEY"),
)


def on_init(conversation_id, session):
    print(f"Session started: {conversation_id}")


async def on_transcript(transcript, session):
    stream = await openai.responses.create(
        model="gpt-4o",
        instructions="You are a helpful voice assistant. Keep responses concise and conversational.",
        input=[
            {"role": "assistant" if m.role == "agent" else m.role, "content": m.content}
            for m in transcript
        ],
        stream=True,
    )

    await session.send_response(stream)


def on_close(session):
    print(f"Session ended: {session.conversation_id}")


def on_error(err, session):
    print(f"Error: {err}")


async def main():
    engine = await elevenlabs.speech_engine.get(SPEECH_ENGINE_ID)

    await engine.serve(
        port=3001,
        path="/ws",
        debug=True,
        on_init=on_init,
        on_transcript=on_transcript,
        on_close=on_close,
        on_error=on_error,
    )


if __name__ == "__main__":
    asyncio.run(main())
```

**`server.mts`**

```typescript maxLines=0 title="server.mts"
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import { createServer } from "node:http";
import OpenAI from "openai";
import "dotenv/config";

// Replace with your Speech Engine ID from step 4
const SPEECH_ENGINE_ID = "seng_8k3m9xr4hjnfg983brhmhkd98n6";

const elevenlabs = new ElevenLabsClient({
  apiKey: process.env.ELEVENLABS_API_KEY,
});
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const httpServer = createServer();

await elevenlabs.speechEngine.attach(SPEECH_ENGINE_ID, httpServer, "/ws", {
  debug: true,

  onInit(conversationId) {
    console.log("Session started:", conversationId);
  },

  async onTranscript(transcript, signal, session) {
    const response = await openai.responses.create(
      {
        model: "gpt-4o",
        instructions:
          "You are a helpful voice assistant. Keep responses concise and conversational.",
        input: transcript.map((m) => ({
          role: m.role === "agent" ? "assistant" : m.role,
          content: m.content,
        })),
        stream: true,
      },
      { signal },
    );

    session.sendResponse(response);
  },

  onClose(session) {
    console.log("Session ended:", session.conversationId);
  },

  onError(err) {
    console.error("Error:", err);
  },
});

httpServer.listen(3001, () => {
  console.log("Speech Engine server listening on port 3001");
});
```

Der Callback `onTranscript` / `on_transcript` empfängt den vollständigen Gesprächsverlauf und die aktuelle Sitzung. Das TypeScript SDK stellt außerdem ein `AbortSignal` bereit, das ausgelöst wird, wenn der Nutzer die Antwort unterbricht. Wenn Sie `signal` an den OpenAI-Aufruf übergeben, wird die LLM-Anfrage bei einer Unterbrechung automatisch abgebrochen.

`sendResponse()` / `send_response()` akzeptiert einen String, ein asynchrones Iterable oder einen Stream von OpenAI, Anthropic oder Google Gemini. Das SDK extrahiert den Textinhalt automatisch.

> **Warning**
>
> Im obigen Beispiel wird das vollständige Transkript des Nutzers an das LLM übergeben. In einer Produktionsumgebung sollten Sie Guardrails hinzufügen, um Prompt-Injection- oder Manipulationsversuche zu verhindern.

#### Server starten

```python
python server.py
```

```typescript
npx tsx server.mts
```

## Client einrichten

#### Client-SDK installieren

#### React

```bash
npm install @elevenlabs/react
```

#### JavaScript

```bash
npm install @elevenlabs/client
```

#### Token-Endpunkt erstellen

Fügen Sie einen serverseitigen Endpunkt hinzu, der ein Gesprächs-Token generiert. So bleibt Ihr API-Schlüssel außerhalb des Browsers, und WebRTC sorgt für die beste Audioqualität.

**`token_server.py`**

```python title="token_server.py"
import os

from dotenv import load_dotenv
from flask import Flask, jsonify
from elevenlabs import ElevenLabs

load_dotenv()

app = Flask(__name__)
elevenlabs = ElevenLabs(
    api_key=os.getenv("ELEVENLABS_API_KEY"),
)


@app.route("/api/token")
def get_token():
    # Replace with your Speech Engine ID from step 4 of the server setup
    speech_engine_id = "seng_8k3m9xr4hjnfg983brhmhkd98n6"

    response = elevenlabs.conversational_ai.conversations.get_webrtc_token(
        agent_id=speech_engine_id,
    )

    return jsonify(token=response.token)


if __name__ == "__main__":
    app.run(port=3002)
```

**`token-server.mts`**

```typescript title="token-server.mts"
import express from "express";
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import "dotenv/config";

const app = express();
const elevenlabs = new ElevenLabsClient({
  apiKey: process.env.ELEVENLABS_API_KEY,
});

app.get("/api/token", async (req, res) => {
  // Replace with your Speech Engine ID from step 4 of the server setup
  const speechEngineId = "seng_8k3m9xr4hjnfg983brhmhkd98n6";

  const response = await elevenlabs.conversationalAi.conversations.getWebrtcToken({
    agentId: speechEngineId,
  });

  res.json({ token: response.token });
});

app.listen(3002, () => {
  console.log("Token server listening on port 3002");
});
```

#### Gesprächs-UI erstellen

Rufen Sie das Gesprächs-Token von Ihrem Server ab und verwenden Sie es, um eine Sitzung zu starten.

#### React

**`App.tsx`**

```tsx title="App.tsx"
import { useConversation } from "@elevenlabs/react";
import { useCallback } from "react";

async function getToken(): Promise<string> {
  const response = await fetch("/api/token");
  if (!response.ok) {
    throw Error("Failed to get conversation token");
  }
  const data = await response.json();
  return data.token;
}

export default function App() {
  const conversation = useConversation({
    onConnect: () => console.log("Connected"),
    onDisconnect: () => console.log("Disconnected"),
    onError: (error: Error) => console.error("Error:", error),
  });

  const startConversation = useCallback(async () => {
    await navigator.mediaDevices.getUserMedia({ audio: true });
    const token = await getToken();
    await conversation.startSession({ conversationToken: token });
  }, [conversation]);

  const stopConversation = useCallback(async () => {
    await conversation.endSession();
  }, [conversation]);

  return (
    <div>
      <p>Status: {conversation.status}</p>
      <button onClick={startConversation} disabled={conversation.status === "connected"}>
        Start conversation
      </button>
      <button onClick={stopConversation} disabled={conversation.status !== "connected"}>
        End conversation
      </button>
    </div>
  );
}
```

#### JavaScript

**`main.ts`**

```typescript title="main.ts"
import { Conversation } from "@elevenlabs/client";

let conversation: Conversation | null = null;

async function getToken(): Promise<string> {
  const response = await fetch("/api/token");
  if (!response.ok) throw Error("Failed to get conversation token");
  const data = await response.json();
  return data.token;
}

document.getElementById("start")!.addEventListener("click", async () => {
  await navigator.mediaDevices.getUserMedia({ audio: true });
  const token = await getToken();

  conversation = await Conversation.startSession({
    conversationToken: token,
    onConnect: () => {
      document.getElementById("status")!.textContent = "Connected";
      (document.getElementById("start") as HTMLButtonElement).disabled = true;
      (document.getElementById("stop") as HTMLButtonElement).disabled = false;
    },
    onDisconnect: () => {
      document.getElementById("status")!.textContent = "Disconnected";
      (document.getElementById("start") as HTMLButtonElement).disabled = false;
      (document.getElementById("stop") as HTMLButtonElement).disabled = true;
    },
    onError: (error) => console.error("Error:", error),
  });
});

document.getElementById("stop")!.addEventListener("click", () => {
  if (conversation) conversation.endSession();
});
```

#### Ausprobieren

Stellen Sie sicher, dass drei Prozesse laufen:

1. **ngrok** – Weiterleitung an Port 3001
2. **Ihr Speech-Engine-Server** – `python server.py` oder `npx tsx server.mts`
3. **Der Token-Server** – `npx tsx token-server.mts` oder `python token_server.py`

Öffnen Sie Ihre Client-Anwendung im Browser und klicken Sie auf **Gespräch starten**. Erteilen Sie bei Aufforderung Mikrofonzugriff und sprechen Sie dann. Sie sollten die Antwort des Agenten über Ihre Lautsprecher hören.

Wenn auf dem Server `debug: true` aktiviert ist, sehen Sie eingehende Transkripte und ausgehende Antworten in der Konsole.

## Sitzungsereignisse

| Ereignis          | TypeScript-Callback | Python-Callback | Beschreibung                                                                                   |
| ----------------- | ------------------- | --------------- | ---------------------------------------------------------------------------------------------- |
| `user_transcript` | `onTranscript`      | `on_transcript` | Nutzersprache transkribiert. Enthält den vollständigen Gesprächsverlauf und ein Abbruchsignal. |
| `init`            | `onInit`            | `on_init`       | Sitzung mit einer Gesprächs-ID initialisiert.                                                  |
| `close`           | `onClose`           | `on_close`      | Ordnungsgemäße Trennung von ElevenLabs.                                                        |
| `disconnected`    | `onDisconnect`      | `on_disconnect` | WebSocket-Verbindung unerwartet getrennt.                                                      |
| `error`           | `onError`           | `on_error`      | Protokoll- oder WebSocket-Fehler.                                                              |

## Erste Agentennachricht konfigurieren

Standardmäßig wartet der Agent, bis der Nutzer zuerst spricht. Damit der Agent den Nutzer zu Beginn des Gesprächs begrüßt, legen Sie beim Starten der Sitzung in der Client-Option `overrides` eine erste Nachricht fest.

Damit der Agent zuerst sprechen kann, müssen wir die Speech-Engine-Ressource aktualisieren, um diese Einstellung vom Client aus zuzulassen.

```python
engine = await elevenlabs.speech_engine.update(
    speech_engine_id="seng_8k3m9xr4hjnfg983brhmhkd98n6",
    overrides={
      "first_message": True,
    },
)
```

```typescript
const engine = await elevenlabs.speechEngine.update("seng_8k3m9xr4hjnfg983brhmhkd98n6", {
  overrides: {
    firstMessage: true,
  },
});
```

Anschließend konfigurieren wir die erste Nachricht im Client SDK.

#### React

```tsx
conversation.startSession({
  conversationToken: token,
  overrides: {
    agent: {
      firstMessage: "Hello! How can I help you today?",
    },
  },
});
```

#### JavaScript

```typescript
const conversation = await Conversation.startSession({
  conversationToken: token,
  overrides: {
    agent: {
      firstMessage: "Hello! How can I help you today?",
    },
  },
});
```

Die erste Nachricht wird vom Agenten gesprochen, sobald die Verbindung hergestellt ist. Sie löst auf Ihrem Server keinen Callback `onTranscript` aus – sie wird vollständig auf der Seite von ElevenLabs verarbeitet.

## Maximale Gesprächsdauer konfigurieren

Standardmäßig endet ein Gespräch nach 600 Sekunden (10 Minuten). Speech Engine unterstützt Gespräche mit einer Dauer von bis zu 2.400 Sekunden (40 Minuten). Um längere Gespräche zu ermöglichen, aktualisieren Sie die Speech-Engine-Ressource mit einem höheren Wert für `max_duration_seconds`:

```python
engine = await elevenlabs.speech_engine.update(
    speech_engine_id="seng_8k3m9xr4hjnfg983brhmhkd98n6",
    conversation={
        "max_duration_seconds": 2400,
    },
)
```

```typescript
const engine = await elevenlabs.speechEngine.update("seng_8k3m9xr4hjnfg983brhmhkd98n6", {
  conversation: {
    maxDurationSeconds: 2400,
  },
});
```

Sie können dies auch im Dashboard festlegen: Öffnen Sie Ihre Speech Engine, wechseln Sie zum Tab **Erweitert** und legen Sie unter **Gesprächsverhalten** die **Maximale Gesprächsdauer** fest.

> **Warning**
>
> Gespräche, die länger als 40 Minuten dauern, werden nicht unterstützt und können getrennt werden, auch wenn
> `max_duration_seconds` auf einen höheren Wert gesetzt ist. Wenn Sie längere Gespräche benötigen, [kontaktieren Sie unser Team](https://elevenlabs.io/contact-sales).

## Nächste Schritte

#### [JavaScript-SDK-Referenz](/docs/de/eleven-api/resources/libraries/speech-engine/javascript-sdk-reference)

Klassen, Methoden und Ereignisse für das JavaScript SDK.

#### [Python-SDK-Referenz](/docs/de/eleven-api/resources/libraries/speech-engine/python-sdk-reference)

Klassen, Methoden und Ereignisse für das Python SDK.

#### [API-Referenz](/docs/de/api-reference/speech-engine/create)

Alle Speech-Engine-Parameter und Antwortformate erkunden.

#### [Next.js-Beispiel-App](https://github.com/elevenlabs/examples/tree/main/speech-engine/nextjs/quickstart)

Eine vollständige Speech-Engine-Schnellstart-App lokal ausführen.