ElevenLabs Conversational-AI-Agent fuer DE-Voice-Bots

Wiederholbares Pattern fuer „Kunde will einen Voice-Bot, der im Browser laeuft, Reservierungen oder Bestellungen aufnimmt, in deutscher Customer-Care-Stimme spricht — und das in einer Session”. Komplette Pipeline ohne Telefonnummer, ohne Twilio, ohne Backend-Server fuer den Voice-Pfad. Tool-Calls gehen per Webhook raus.

Erste Anwendung: 2026-05-09, Aylem Eat & Meet POC (telefon-assistent-aws) — A/B parallel zum AWS-Polly-Stack.

Wann nutzen

  • Kunden-Pitch / Sales-Demo wo „echte natuerliche Stimme” mehr ueberzeugt als „funktioniert technisch”
  • POC vor der Telefonnummer-Investition: erst Persona + Stimme + Tools im Browser pruefen, dann Twilio drancanyon
  • A/B-Vergleich gegen AWS-Polly-Stack (gleicher System-Prompt, anderer Voice-Stack)
  • DACH-Customer-Care-Use-Cases (Restaurant, Praxis, Service-Hotline) — ElevenLabs hat hier deutlich bessere Voice-Qualitaet als Polly Generative

Nicht nutzen wenn:

  • Daten muessen EU-only bleiben (ElevenLabs-Datenpfad pruefen, ggf. Polly + Bedrock EU)
  • Kunde ist auf Subscription-Vermeidung — ConvAI ist paid feature, Free-Tier nur 10k credits
  • Reine FAQ-Chat-Use-Cases ohne Voice — overkill, normaler LLM-Chat reicht

Voraussetzungen

  • ElevenLabs-API-Key in .env.local (Vault-Root) als ELEVENLABS_API_KEY
  • ElevenLabs-MCP registriert (elevenlabs)
  • Browser mit Mikrofon-Zugriff (Chrome / Safari getestet)

Schritte

1. Voice-Auswahl: shared library durchsuchen

Eigene Library hat anfangs nur generierte Voices, fuer DE-Native Customer-Care nimmt man Voices aus dem shared pool. Tool: mcp__elevenlabs__search_voice_library.

Such-Begriffe die gut treffen:

  • german female warm / german male warm — guter Mix aus Stimm-Charakter
  • deutsch friendly — engerer DACH-Filter
  • Ziel: Use Case: conversational (nicht narrative_story — das klingt nach Hoerbuch)

Top-Stimmen aus dem Pool (Stand 2026-05):

VoiceIDProfil
Johanna – Warm, Clear & Professional SupportcoPfQIqaxowKv5u2s2bVExplizit fuer DACH customer care, mittlere Lage, Default-Empfehlung
Ela – Empathetic & WarmSJJe86Va82zRzg6zi2dXJunge Stimme, supportive flow, fuer freundlichere Brands
Martin – Warm, Conversational & FriendlyztKVRvw89zjvli0JDeZRMaennlich, conversational AI / phone support / IVR

2. Voice in eigene Library kopieren

Shared-library-voices kann der Account erst nutzen, wenn sie in die eigene Library kopiert sind. Endpoint: POST /v1/voices/add/{public_owner_id}/{voice_id} mit body {"new_name": "..."}.

set -a; source .env.local; set +a
 
# 1) public_owner_id finden — der voice_id-Filter im /v1/shared-voices greift NICHT,
#    daher per ?search=<name>&language=de und lokal nach voice_id filtern
curl -sS "https://api.elevenlabs.io/v1/shared-voices?search=Johanna&language=de" \
  -H "xi-api-key: $ELEVENLABS_API_KEY" \
  | python3 -c "import sys,json; [print(v.get('voice_id'), v.get('public_owner_id'), v.get('name')) for v in json.load(sys.stdin).get('voices',[])]"
 
# 2) in eigene Library adden — voice_id bleibt gleich!
curl -sS -X POST "https://api.elevenlabs.io/v1/voices/add/$OWNER/$VOICE_ID" \
  -H "xi-api-key: $ELEVENLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"new_name":"Aylem-Johanna"}'

Wichtig: nach Add bleibt die voice_id identisch. Antwort gibt {"voice_id": "<same>"} zurueck — das ist kein Bug.

3. Conversational-AI-Agent anlegen

Per MCP-Tool mcp__elevenlabs__create_agent:

mcp__elevenlabs__create_agent(
    name="Aylem Voice Agent (POC)",
    first_message="Hallo, hier ist Aylem Eat & Meet. Was kann ich fuer Sie tun?",
    system_prompt="<persona prompt>",
    voice_id="coPfQIqaxowKv5u2s2bV",
    language="de",
    llm="gpt-4o-mini",          # Latenz-optimiert; Claude per Custom-LLM ggf. spaeter
    temperature=0.4,
    max_tokens=200,
    model_id="eleven_flash_v2_5",  # 32-Sprachen, schnellstes ElevenLabs-Modell
    stability=0.45, similarity_boost=0.8,
    turn_timeout=7,
    max_duration_seconds=300,
    record_voice=True,
    retention_days=30,           # POC: 30 statt 730
)

Antwort enthaelt Agent ID: agent_<id> — die merken.

TTS-Defaults die sich bewaehrt haben: stability=0.45, similarity_boost=0.8, style=0.15 — gibt natuerlich-warmen Sound ohne in Stoerlauten zu kippen.

4. Webhook-Tools erstellen

Tools sind seit ConvAI v2 eigene Resourcen (nicht inline am Agent). Endpoint: POST /v1/convai/tools mit tool_config.

curl -sS -X POST "https://api.elevenlabs.io/v1/convai/tools" \
  -H "xi-api-key: $ELEVENLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tool_config": {
      "type": "webhook",
      "name": "book_reservation",
      "description": "Buche eine Tischreservierung. Nutze dieses Tool wenn der Anrufer einen Tisch reservieren moechte. Erfrage vorher alle Felder.",
      "api_schema": {
        "url": "https://placeholder.example.com/tools/book_reservation",
        "method": "POST",
        "request_body_schema": {
          "type": "object",
          "description": "Reservierungs-Daten",
          "properties": {
            "date": {"type": "string", "description": "YYYY-MM-DD"},
            "time": {"type": "string", "description": "HH:MM (24h)"},
            "guests": {"type": "integer", "description": "Anzahl Personen"},
            "name": {"type": "string", "description": "Name des Anrufers"},
            "phone": {"type": "string", "description": "Telefon Rueckruf"}
          },
          "required": ["date","time","guests","name","phone"]
        }
      },
      "response_timeout_secs": 20
    }
  }'

Antwort enthaelt id: tool_<id> — pro Tool merken.

5. Tools an Agent haengen

Tools werden ueber tool_ids: [...] am Agent referenziert (nicht inline). Endpoint: PATCH /v1/convai/agents/{agent_id}.

curl -sS -X PATCH "https://api.elevenlabs.io/v1/convai/agents/$AGENT_ID" \
  -H "xi-api-key: $ELEVENLABS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation_config": {
      "agent": {
        "prompt": {
          "tool_ids": ["tool_<book>", "tool_<order>"]
        }
      }
    }
  }'

end_call ist ein System-Tool und immer automatisch aktiv — nicht doppelt anlegen.

6. Auth/Embed-Mode setzen (Browser-Public oder Signed URL)

Fuer Browser-POC ohne Backend: enable_auth: false (Default bei neuem Agent — siehe platform_settings.auth). Damit darf jeder mit der Agent-ID per WebRTC verbinden.

Fuer Produktion spaeter umstellen auf signed URL:

  • Backend macht POST /v1/convai/conversation/get_signed_url?agent_id=... mit API-Key
  • Returns kurzlebige URL die das Frontend benutzt
  • Verhindert dass Hobby-Sniffer dauerhaft auf den Agent verbinden und Credits verbrennen

7. Convai-Widget einbinden

Statische HTML reicht — das Widget ist komplett client-side. Snippet:

<elevenlabs-convai agent-id="agent_<id>"></elevenlabs-convai>
<script src="https://unpkg.com/@elevenlabs/convai-widget-embed" async type="text/javascript"></script>

Optional CSS um das Widget mittig zu halten:

elevenlabs-convai { display: block; width: 100%; max-width: 480px; margin: 0 auto; }

Default-Variant ist „bubble unten rechts”. Andere Varianten konfiguriert man am Agent unter platform_settings.widget (variant, placement, bg_color, border_radius etc.).

8. Optional: Knowledge-Base anhaengen

Wenn der Bot eine Speisekarte / Preisliste / FAQ kennen soll — mcp__elevenlabs__add_knowledge_base_to_agent mit URL, Datei (epub/pdf/docx/txt/html) oder Plain-Text. Wird zum Prompt-Kontext geadded.

Quirks die wir gelernt haben

  • voice_id und voice_name nicht beide angeben im MCP text_to_speech — sonst Fehler. Eines reicht.
  • shared-voices-Filter voice_id greift NICHT?voice_id= wird ignoriert, immer per ?search=<name>&language=de filtern und lokal nach voice_id suchen.
  • Free-Tier kann shared-library voices NICHT via TTS-API generieren (paid_plan_required). ConvAI-Pfad rendert die Voice aber problemlos, weil das LLM die Antwort liefert und die Voice direkt im ElevenLabs-Render-Loop benutzt wird, ohne explizite TTS-API. → Konsequenz: fuer Voice-Sample-Vorhoeren entweder Default-Premade-Voice nehmen, oder direkt das offizielle Preview-MP3 aus dem Public-Bucket downloaden (URL steht in search_voice_library-Output unter Preview URL).
  • Tool-request_body_schema-Properties brauchen IMMER description — auch in array.items. Ohne Description: 422 mit „Must set one of: description, dynamic_variable, is_system_provided, or constant_value”.
  • Voice-ID bleibt nach voices/add gleich — kein neuer ID-Roundtrip noetig. Was sich aendert: Voice ist jetzt im eigenen Account-Inventar sichtbar.
  • platform_settings.auth.enable_auth: false ist der Default bei neuen Agents — fuer schnellen POC ideal, fuer Produktion auf signed URLs umstellen.
  • API-Key-Header heisst xi-api-key (nicht Authorization: Bearer ...).

Latenz-Erwartung

  • eleven_flash_v2_5 + gpt-4o-mini + DE: Ende-zu-Ende-Antwortlatenz im Browser etwa 1.5–2.5 s (gemessen 2026-05-09 in Hamburg)
  • Mit Tool-Call (Webhook 200ms Roundtrip): plus 500ms–1s
  • Faellt deutlich besser aus als der Polly+Lex+Lambda+Bedrock-Stack (gemessen ~3–5s im Aylem-POC)

Kosten

  • ElevenLabs ConvAI ist paid feature, ab Creator-Tier (~0.10–0.15/Minute.
  • LLM-Kosten separat — gpt-4o-mini etwa $0.0001/Turn bei 200 Tokens, fuer Telefon-Use-Cases vernachlaessigbar.
  • Voice-Cloning + Premium-Voices ggf. zusaetzlich, aber fuer Library-Voices kein Aufpreis.

Cross-Refs

  • MCP-Setup: elevenlabs
  • Erste Anwendung: telefon-assistent-aws (Aylem Eat & Meet, Phase 0.5)
  • Anschluss-Pattern (noch zu schreiben): Tool-Webhook auf AWS Lambda hosten + signed URL fuer Produktion