Aylem LiveKit-Agent (Cartesia-Voice, Streaming-Pipeline)
Worker-Prozess der den Aylem-Voice-Bot ueber LiveKit + Cartesia rendert. Pendant zum ElevenLabs-ConvAI-Stack (elevenlabs.html) — gleiche Persona, gleiche Tools, andere Voice-Pipeline.
Stand 2026-05-12: Emotion-Tag-Adaption ist deaktiviert — der frühere
tts_node-Override hat den gesamten LLM-Output gebuffert und damit Cartesias
First-Byte-Latenz von ~90 ms ausgehebelt (~1 s Aufschlag pro Antwort).
Zusätzlich waren das Cartesia-Attribut und das Tag-Schema in der aktiven
api_version inkompatibel — die Steuerung hat de facto nichts gemacht. Re-Add
später entweder via Sonic-2-Snapshot model="sonic-2-2025-03-07" +
api_version="2024-11-13" (Named Emotion Controls) oder Sonic-3 mit
Voice-Switching.
Architektur
Browser /cartesia (LiveKit Web SDK)
↓ WebRTC + Token vom Flask-Backend
LiveKit Cloud Room (Region "Germany 2")
↑↓ Audio
Python Worker (dieser Code)
├─ silero VAD
├─ Deepgram nova-3 (de) — STT
├─ Bedrock Claude Haiku 4.5 EU (eu-central-1, T 0.0, cache_system) — LLM
└─ Cartesia Sonic 2 (de Voice) — TTS, Streaming (kein Buffering)
Latenz-Tuning aktiv: preemptive_generation, min_endpointing_delay=0.2,
max_endpointing_delay=2.0, min_consecutive_speech_delay=0.1.
DSGVO-Status: LiveKit-Room in DE-Region, Bedrock-LLM ueber EU-only-Inference-Profile
(`eu.anthropic.*`) — Audio-Ingest + LLM bleiben in EU. Deepgram (STT) und Cartesia
(TTS) sind US-Anbieter, Audio-Bytes gehen dafuer ueber US. Fuer voll-EU spaeter
auf EU-STT (z.B. Speechmatics EU, Bedrock-Transcribe) und EU-TTS (z.B. Polly,
ElevenLabs Enterprise mit EU-Region, oder OpenAI EU) umstellbar.
Setup (einmalig)
1. Accounts anlegen (5–10 Min)
- LiveKit Cloud: https://cloud.livekit.io — Project anlegen, URL + API-Key + Secret notieren
- Deepgram: https://console.deepgram.com — Sign-up, API-Key generieren
- Cartesia: https://play.cartesia.ai — Sign-up, API-Key generieren
- OpenAI: Key hast du vermutlich schon — sonst https://platform.openai.com/api-keys
2. .env.local fuellen
cd intern/projekte/telefon-assistent-aws/livekit-agent
cp .env.example .env.local
# Vier Keys eintragen3. venv + Install
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# Modelle lokal vorbereiten (silero VAD herunterladen)
python agent.py download-filesRun
In einem Terminal — Worker startet und wartet auf Room-Joins:
source .venv/bin/activate
python agent.py devDu siehst Logs wie:
INFO: registered worker worker_id=... region=...
Im zweiten Terminal — Flask-Webapp starten (gleiches venv-Setup wie bisher):
cd ../webapp
source .venv/bin/activate
python server.pyBrowser oeffnen: http://localhost:5050/cartesia
Klick auf “Verbinden”, Mikrofon erlauben — der Browser joined einen LiveKit-Room, der Worker wird automatisch gematcht und antwortet als Aylem-Bot.
Cartesia Voice wechseln
Default ist Viktoria - Phone Conversationalist (b9de4a89-2257-424b-94c2-db18ba68c81a),
explizit fuer telefonische Customer-Care designed. Cartesia hat aktuell
6 DE-Voices in der Standard-Library:
| Voice | ID | Profil |
|---|---|---|
| Viktoria - Phone Conversationalist | b9de4a89-2257-424b-94c2-db18ba68c81a | feminine, Phone-optimiert (Default) |
| Alina - Engaging Assistant | 38aabb6a-f52b-4fb0-a3d1-988518f4dc06 | feminine, Assistant-Vibe |
| Marlene - Elegant Speaker | 9b4d08b6-0494-4301-ab92-9150f4ee2718 | feminine, formeller |
| Moritz - Modern Communicator | 4ad22058-7cb6-402c-a115-196cbfc25dce | masculine, modern |
| Sebastian - Orator | b7187e84-fe22-4344-ba4a-bc013fcb533e | masculine, narrator |
| Henrik - Steady Analyst | d1cbea67-e4d3-47cd-be2a-2bd4e646b002 | masculine, ruhig-sachlich |
Andere wechseln:
# in .env.local
CARTESIA_VOICE_ID=<andere-id>Worker neustarten.
Emotion-Tags — deaktiviert (2026-05-12)
Frueher hat der LLM-Output jede Antwort mit [friendly]/[empathetic]/…
begonnen, ein tts_node-Override hat den Tag geparst und Cartesia-Controls
gesetzt. Das Setup hatte zwei Probleme:
- Buffering kostete ~1 s Latenz pro Antwort — der Override hat den gesamten LLM-Stream konsumiert bevor Cartesia auch nur das erste Audio-Byte bekommen hat. Cartesias First-Byte von ~90 ms war damit verloren.
- Die Controls haben gar nicht gegriffen. Gesetzt wurde
tts._opts.experimental_controls— dieses Feld existiert in_TTSOptionsnicht. Ausserdem akzeptiert Cartesia das altepositivity:medium-Schema nur unterapi_version="2024-11-13"+model="sonic-2-2025-03-07", beide nicht im aktiven Standard.
Re-Add-Pfad wenn dynamische Emotion wieder gewuenscht ist:
- Saubere Variante A:
cartesia.TTS(model="sonic-2-2025-03-07", api_version="2024-11-13", ...)plus EMOTION_MAP mit Named-Cartesia-Emotionen aus models.py (Happy,Apologetic,Sympathetic, …) — setzen viatts._opts.speedundtts._opts.emotiondirekt am Plugin (vor Stream-Open). - Saubere Variante B: Sonic-3 mit Voice-Switching — pro Stimmung eine
vorab eingestellte Voice-ID; LLM tagt nur „warm/empathetic/…”, Worker
ruft
tts.update_options(voice=...)bevor er den Stream öffnet. - Wichtig: jede Variante braucht Streaming-kompatibles Setzen — keine Buffering-Loops um Tags zu strippen. Entweder Tag im LLM-Output rauslassen und Stimmung per Tool-Call oder Metadaten signalisieren, oder Tag im ersten Chunk parsen und ab Chunk 2 durchstreamen.
Tools (Phase 0.7 — MCP-basiert)
Tools werden seit 2026-05-09 nicht mehr inline im Worker-Code definiert,
sondern via MCP-Server geladen — siehe ../tools-mcp/ und ADR
keine-eigene-plattform.
Der Worker startet tools-mcp/server.py als Subprocess (stdio-MCP) und übergibt
die Tool-Liste automatisch ans LLM. Die @function_tool-Decorators in
AylemAgent sind weg.
Tools heute:
book_reservation(date, time, guests, name, phone, notes?)— Reservierungtake_order(items, customer_name, phone, address?, pickup_time?)— Bestellungget_services()— Service-Katalog (heute Aylem-spezifisch)
Calls werden im MCP-Server geloggt und liefern Mock-Bestaetigungs-Strings zurück. Echte Backend-Anbindung (Cal.com etc.) kommt in Phase B.
Voraussetzung beim ersten Run:
cd ../tools-mcp
python3 -m venv .venv
.venv/bin/pip install -r requirements.txtWorker startet den MCP-Subprocess automatisch — der Pfad wird in
agent.py aufgelöst (TOOLS_MCP_DIR).
Run in Production
python agent.py start (statt dev) startet als persistent worker mit
Auto-Restart und Multi-Worker-Support (LiveKit verteilt Jobs auf alle
verbundenen Worker).
Hosting-Optionen fuer den Worker: AWS Fargate, Hetzner Cloud, Railway, Fly.io — braucht nur Outbound-Internet zum LiveKit-Cloud-WSS-Endpoint.
Cross-Refs
- ElevenLabs-Variante: elevenlabs.html
- Polly-Variante (Phase 0): index.html
- Plan-File: _index.md
- Tonalitaet/Persona-Pattern: voice-bot-de-pattern.md