🤖 Agents IA

agent-voice-agent-builder

Construction d'agents vocaux conversationnels avec STT, TTS et gestion du dialogue.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- agent-voice-agent-builder --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } agent-voice-agent-builder -Launch"

🚀 Déjà installé ?

claude "/agent-voice-agent-builder"

Ou tapez /agent-voice-agent-builder dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

voice agentagent vocaltéléphone IAvoice botSTTTTSspeech to textconversational AIIVR intelligentVapiLiveKit

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/agent-voice-agent-builder ~/.claude/skills/

Payload du plugin : skills/agent-voice-agent-builder · source éditable : agent-skills/voice-agent-builder

đź“– Manuel

Voice Agent Builder

Quand utiliser ce skill

Conception ou implémentation d'un agent vocal interactif : bot téléphonique, IVR intelligent, assistant vocal webapp, agent conversationnel WebRTC/SIP. Couvre le pipeline complet STT → LLM → TTS et la gestion du dialogue.


Workflow en étapes

1. Choix d'architecture

Décision clé : synchrone vs streaming end-to-end.

CritèreSynchrone (simple)Streaming E2E (recommandé prod)
Latence typique2–4 s< 1 s
ComplexitéFaibleÉlevée
Cas d'usagePoC, flux courtsProduction, conversations longues

Pipeline cible :

Micro → VAD → STT (stream) → LLM (stream) → TTS (stream) → Haut-parleur
                ↑ barge-in détecté → interrompre TTS

Stack recommandée 2026 pour démarrer vite :


2. Speech-to-Text (STT)

Critères de sélection :

MoteurLatence streamLanguesCoût/minCas d'usage
Deepgram Nova-3~200 ms36 langues$0.0043Production générale
Whisper large-v3~500 ms (local)99 languesGratuit (GPU)Multi-langue, RGPD strict
Azure Speech~250 ms100+$0.016Intégration Microsoft
Google STT v2~300 ms125$0.016Écosystème GCP

Configuration VAD incontournable :

# Deepgram avec VAD + barge-in
dg_config = {
    "model": "nova-3",
    "language": "fr",
    "interim_results": True,      # transcription partielle pour barge-in
    "endpointing": 300,           # ms de silence avant fin d'énoncé
    "utterance_end_ms": 1000,     # timeout si silence prolongé
    "vad_events": True,           # événements speech_started / speech_ended
    "smart_format": True,         # formatage nombres, dates auto
}

Barge-in (interruption utilisateur) :

async def on_speech_started():
    if tts_is_playing:
        await tts_client.stop()       # couper TTS immédiatement
        await cancel_pending_llm()    # annuler génération en cours si possible
        conversation.add_interruption_marker()

3. Gestion du dialogue

Choisir le bon modèle de gestion d'état :

# Exemple system prompt voice-optimized
SYSTEM_PROMPT = """
Tu es l'assistant vocal de {company}. Règles strictes :
- Réponds en 1 à 2 phrases maximum. Les réponses longues sont coupées par l'utilisateur.
- N'utilise jamais de listes à puces, markdown, ou caractères spéciaux.
- Dis les nombres Ă  l'oral ("vingt-trois" pas "23").
- Si tu ne comprends pas, dis : "Pouvez-vous reformuler ?"
- Si tu ne peux pas aider : "Je vous transfère à un conseiller."
État actuel : {state}
Contexte : {context}
"""

Gestion des silences :

SILENCE_TIMEOUT_MS = 5000
REPROMPT_MESSAGE = "Je suis toujours lĂ , vous pouvez parler."
MAX_REPROMPTS = 2  # au-delà → transfert humain ou fin d'appel

4. Text-to-Speech (TTS)

Sélection moteur :

MoteurLatence TTFBQualitéStreamingClonage vocal
ElevenLabs Turbo v2.5~200 msExcellentâś…âś…
OpenAI TTS-1~300 msBon✅❌
Azure Neural TTS~200 msTrès bon✅Limité
Cartesia Sonic~90 msBonâś…âś…

SSML pour les cas spéciaux :

<!-- Pause naturelle + prononciation métier -->
<speak>
  Votre numéro de dossier est
  <say-as interpret-as="characters">ABC123</say-as>.
  <break time="500ms"/>
  Souhaitez-vous que je répète ?
</speak>

Filler words pour masquer la latence LLM :

FILLERS = {
    "thinking": ["Bien sûr...", "Laissez-moi vérifier...", "Un instant..."],
    "searching": ["Je consulte votre dossier...", "Je recherche..."],
}
# Jouer le filler dès la réception du 1er token LLM si délai > 600 ms
async def stream_with_filler(llm_stream):
    first_chunk = await asyncio.wait_for(llm_stream.__anext__(), timeout=0.6)
    yield first_chunk
    async for chunk in llm_stream:
        yield chunk
# Si timeout → jouer filler, puis continuer stream

5. Intégration téléphonie / WebRTC

Choisir la plateforme :

PlateformeTypeRecommandé pour
VapiSaaS clé en mainDémarrage rapide, PSTN, webhook simple
LiveKitSelf-hosted WebRTCContrĂ´le total, RGPD, faible latence
Twilio Voice + Media StreamsSaaS PSTNIntégration Twilio existante
Asterisk/FreeSWITCH + SIPSelf-hosted PBXEnterprise, on-premise strict

Exemple Vapi — démarrer un appel sortant :

curl -X POST https://api.vapi.ai/call/phone \
  -H "Authorization: Bearer $VAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phoneNumberId": "xxx",
    "customer": {"number": "+33600000000"},
    "assistant": {
      "model": {"provider": "anthropic", "model": "claude-sonnet-4-5"},
      "voice": {"provider": "elevenlabs", "voiceId": "yyy"},
      "firstMessage": "Bonjour, je suis votre assistant vocal.",
      "silenceTimeoutSeconds": 5
    }
  }'

Transfert vers humain (escalade) — toujours prévoir :

ESCALATION_TRIGGERS = [
    lambda ctx: ctx.failed_intents >= 3,        # incompréhensions répétées
    lambda ctx: ctx.sentiment_score < -0.6,      # frustration détectée
    lambda ctx: "conseiller" in ctx.last_user_text,
    lambda ctx: ctx.turn_count > 20,             # conversation trop longue
]

6. Optimisation latence

Cible : < 1,2 s end-to-end perçu par l'utilisateur.

Budget latence :
  STT first result    : 150–300 ms
  LLM first token     : 200–400 ms  (streaming requis)
  TTS first audio     : 100–250 ms  (streaming requis)
  Transport réseau    : 50–100 ms
  ─────────────────────────────────
  Total cible         : 500–1050 ms ✅

Optimisations prioritaires :

  1. Streaming à tous les niveaux — ne jamais attendre la fin d'une étape pour commencer la suivante.
  2. Truncation des réponses longues — couper après 60 mots si l'utilisateur peut interrompre.
  3. Cache TTS — pré-générer les phrases fixes (accueil, erreurs courantes) et les servir depuis le CDN.
  4. Modèle LLM léger — pour les tours simples (confirmation oui/non), utiliser un modèle rapide (GPT-4o-mini) plutôt que le modèle complet.
  5. Déploiement régional — héberger STT/LLM/TTS dans la même région cloud pour minimiser les RTT inter-services.

7. Tests et validation

# Test sans audio — text injection (CI/CD)
response = await agent.process_turn(
    text="Je voudrais annuler ma commande numéro 4521",
    session_id="test-001"
)
assert response.intent == "cancel_order"
assert "4521" in response.entities["order_id"]
assert len(response.tts_text.split()) <= 30  # réponse courte

# Benchmark latence end-to-end
import time
latencies = []
for audio_file in test_audio_samples:
    t0 = time.perf_counter()
    await agent.process_audio(audio_file)
    latencies.append(time.perf_counter() - t0)
assert statistics.quantiles(latencies, n=20)[18] < 1.5  # P95 < 1.5 s

Checklist avant mise en production :


Garde-fous / Anti-patterns / Pièges

Anti-patternConséquenceCorrection
Attendre la fin de transcription pour appeler le LLMLatence +800 msStreaming STT → LLM dès interim results stables
Réponses TTS > 3 phrasesInterruption, frustrationLimiter à 1–2 phrases par tour
Pas de VAD côté clientFaux déclenchements, échoIntégrer VAD (WebRTC VAD, Silero VAD)
Appeler le LLM à chaque mot interimaireSurcoût ×10, incohérenceAttendre endpointing (silence > 300 ms)
SSML avec balises non supportées par le moteur TTSLecture littérale des balisesTester le SSML sur chaque moteur cible
Aucun fallback si STT timeoutAppel bloqué indéfinimentTimeout + reprompt + escalade après 2 échecs
Stocker l'audio des conversations sans consentementNon-conformité RGPDConsentement explicite ou transcription-only
Pipeline monolithique non testable unitairementDebugging impossibleInterfaces mockables entre STT/LLM/TTS

Bonnes pratiques 2026