IVR & Contact Center Voice Agents

View as Markdown

Indian contact centers run at huge call volumes on infrastructure that’s still largely PSTN and IVR-menu based: outbound collections, order status, appointment reminders, first-line support. A Sarvam-powered voice agent can sit behind that IVR (or replace the menu entirely) and hold a real conversation in the caller’s language, instead of routing them through “press 1 for Hindi.”

This guide covers the architecture pattern common to IVR/contact-center bots, then walks through the Collection Agent example (a payment-reminder bot) as the concrete implementation. The same pattern (professional tone, structured account lookup, clean escalation to a human) applies whether you’re doing collections, order-status calls, or appointment reminders.

In short: stream everything (STT and TTS), keep the LLM turn short and on sarvam-30b by default, and build the human-escalation path before you build anything else.

Architecture

PSTN / SIP trunk → Telephony transport → STT (streaming) → LLM → TTS (streaming) → Telephony transport → Caller
  • DTMF / intent detection → escalate to human queue
  • Call recording (with consent) → batch STT for QA/analytics
1

Telephony ingress

Calls typically arrive over a SIP trunk. Both LiveKit and Pipecat support SIP/telephony transports that bridge PSTN audio into the same Agent/Pipeline you’d use for a WebRTC call. There’s no separate code path for phone vs. app.

2

Streaming STT

Use the WebSocket transport (or the LiveKit/Pipecat Sarvam plugins, which use it internally) so the agent starts processing speech before the caller finishes talking. Telephony audio is 8kHz, which Saaras v3 supports natively without upsampling.

3

Conversational turn

The LLM generates a response. Keep it short: contact-center callers are on hold, not reading an essay. Stream the reply into TTS rather than waiting for the full completion.

4

Escalation path

Detect explicit requests (“talk to a person,” repeated failed intents, DTMF 0) and transfer to a human queue rather than looping the caller through the bot. Every example agent in this series is written to acknowledge and offer transfer instead of stonewalling.

5

Recording & QA (optional)

If you record calls for compliance or quality review, run them through Sarvam’s Batch STT with diarization afterward. See the Call Analytics Pipeline cookbook for a full diarized-transcript-to-insights pipeline.

LayerSettingWhy
STTsaaras:v3, mode="transcribe", language="unknown"Auto-detect handles callers who code-mix Hindi/English mid-sentence, common in contact-center audio
LLMsarvam-30b, reasoning_effort=None, short max_tokens (e.g. 200–400)Contact-center turns are short Q&A/confirmation exchanges. You don’t need sarvam-105b’s depth, and you don’t want its latency
TTSbulbul:v3, WebSocket streaming, pace=1.1, temperature=0.4Matches the “IVR / Telephony” preset in TTS Best Practices: a slightly brisk, professional, consistent delivery
TTS formatmulaw at 8kHz for PSTN legs, linear16 at 16kHz for WebRTC/app legsMatches the telephony codec so there’s no resampling step in the media path
Turn detectionturn_detection="stt", min_endpointing_delay=0.07 (LiveKit)See Build a Voice Agent with LiveKit

Latency targets

WhatTargetHow to get there
STT processing~70msSet min_endpointing_delay=0.07 (matches the Sarvam LiveKit plugin’s documented processing latency) so the agent doesn’t wait longer than necessary before handing off to the LLM
LLM time-to-first-tokenAs low as the conversation allowsDefault to sarvam-30b, the lower-latency option for voice-agent pipelines. Reserve sarvam-105b for calls that need multi-step reasoning (e.g. explaining a complex billing dispute), not routine confirmations
TTS time-to-first-audioNear-instantAlways use WebSocket streaming on the live call leg (“audio starting within milliseconds of the first chunk” per TTS Best Practices). REST waits for full synthesis and is fine only for pre-generated static prompts (“Thank you for calling…”) that don’t change per call

There’s no official Sarvam round-trip SLA to quote here, so budget your own. Streaming STT plus sarvam-30b plus streaming TTS keeps each leg in the tens-to-low-hundreds of milliseconds, which is what makes barge-in and natural turn-taking possible over a phone line.

Pitfalls

Contact-center callers switch between Hindi, English, and their regional language within one sentence. language="unknown" on STT handles this. Hardcoding a single language code degrades transcription the moment a caller code-mixes.

A bot that can’t recognize “I want to speak to a person” and hand off cleanly will frustrate callers and generate complaints. Build the transfer/escalation branch first, not as an afterthought.

Account numbers, product codes, and abbreviations (e.g. “EMI,” “NAIC”) don’t always get read the way you’d expect. Use a pronunciation dictionary scoped per language rather than fighting it in the prompt.

REST returns the full audio only after synthesis completes, which reads as dead air to a caller on a phone line. Reserve REST for pre-generated, static prompts; use WebSocket streaming for anything generated per turn.

If you’re recording for QA, capture consent in the call flow itself, and pipe recordings through diarized batch STT so per-speaker talk-time and sentiment are queryable. Don’t just archive raw audio.

Full example

The Collection Agent guide has the complete, runnable code (LiveKit-based). The core of it:

1class CollectionAgent(Agent):
2 def __init__(self) -> None:
3 super().__init__(
4 instructions="""
5 You are a professional and empathetic collection agent working for ABC Bank.
6 ...
7 If customer requests to speak to a human, acknowledge and offer to transfer.
8 """,
9 stt=sarvam.STT(language="unknown", model="saaras:v3", mode="transcribe"),
10 llm=sarvam.LLM(model="sarvam-105b"),
11 tts=sarvam.TTS(target_language_code="en-IN", model="bulbul:v3", speaker="aditya"),
12 )

The example above uses sarvam-105b for a richer collections conversation with payment-plan negotiation. For simpler, high-volume flows (order status, appointment reminders, balance inquiries), swap in sarvam-30b per the recommended params to shave latency off every turn.

See also: BFSI Voice Bots for collections-specific compliance guardrails, and the Call Analytics Pipeline cookbook for post-call QA.