This example demonstrates a voice assistant that allows real-time switching between different Text-to-Speech providers to compare voice quality, latency, and characteristics. Each provider has its own agent class, and function tools allow seamless switching mid-conversation.
Prerequisites
- Add a
.env.localin this directory with your LiveKit credentials and API keys for each TTS provider:LIVEKIT_URL=your_livekit_urlLIVEKIT_API_KEY=your_api_keyLIVEKIT_API_SECRET=your_api_secretOPENAI_API_KEY=your_openai_keyDEEPGRAM_API_KEY=your_deepgram_keyRIME_API_KEY=your_rime_keyELEVENLABS_API_KEY=your_elevenlabs_keyCARTESIA_API_KEY=your_cartesia_keyPLAYAI_API_KEY=your_playai_key - Install dependencies:pip install "livekit-agents[deepgram,openai,rime,elevenlabs,playai,cartesia]" python-dotenv
Load environment and create the AgentServer
Import the necessary modules, load environment variables, and create an AgentServer.
import loggingfrom dotenv import load_dotenvfrom livekit.agents import JobContext, AgentServer, cli, Agent, AgentSession, function_toolfrom livekit.plugins import deepgram, openai, rime, elevenlabs, cartesia, playailogger = logging.getLogger("tts-comparison")logger.setLevel(logging.INFO)load_dotenv(".env.local")server = AgentServer()
Define agents for each TTS provider
Each agent class configures a different TTS provider while sharing the same STT and LLM. Function tools return new agent instances to enable switching.
class RimeAgent(Agent):def __init__(self) -> None:super().__init__(instructions="""You are a helpful assistant communicating through voice.You are currently using the Rime TTS provider.You can switch to a different TTS provider if asked.Don't use any unpronouncable characters.""",stt=deepgram.STT(),llm=openai.responses.LLM(),tts=rime.TTS(),)async def on_enter(self) -> None:await self.session.say("Hello! I'm now using the Rime TTS voice. How does it sound?")@function_toolasync def switch_to_elevenlabs(self):"""Switch to ElevenLabs TTS voice"""return ElevenLabsAgent()@function_toolasync def switch_to_cartesia(self):"""Switch to Cartesia TTS voice"""return CartesiaAgent()@function_toolasync def switch_to_playai(self):"""Switch to PlayAI TTS voice"""return PlayAIAgent()
Additional TTS provider agents
The ElevenLabs, Cartesia, and PlayAI agents follow the same pattern — each configures its own TTS provider and provides function tools to switch to the other providers.
class ElevenLabsAgent(Agent):def __init__(self) -> None:super().__init__(instructions="...",stt=deepgram.STT(),llm=openai.responses.LLM(),tts=elevenlabs.TTS(),)# ... on_enter and switch functions
Create the RTC session entrypoint
Start with the Rime agent. The session handles agent transfers automatically when function tools return new agents.
@server.rtc_session(agent_name="my-agent")async def entrypoint(ctx: JobContext):ctx.log_context_fields = {"room": ctx.room.name}session = AgentSession()await session.start(agent=RimeAgent(),room=ctx.room)await ctx.connect()
Run it
lk agent dev tts_comparison.py
Try these commands to switch between providers:
- "Switch to ElevenLabs"
- "Use the Cartesia voice"
- "Let me hear PlayAI"
- "Go back to Rime"
How it works
- Session starts with the Rime TTS provider.
- Agent introduces itself using the current voice.
- User can request to switch providers (e.g., "Switch to ElevenLabs").
- Function tool returns a new agent instance with the requested TTS.
- Session transfers to the new agent and
on_enter()provides audio confirmation.
Full example
import loggingfrom dotenv import load_dotenvfrom livekit.agents import JobContext, AgentServer, cli, Agent, AgentSession, function_toolfrom livekit.plugins import deepgram, openai, rime, elevenlabs, cartesia, playailogger = logging.getLogger("tts-comparison")logger.setLevel(logging.INFO)load_dotenv(".env.local")class RimeAgent(Agent):def __init__(self) -> None:super().__init__(instructions="""You are a helpful assistant communicating through voice.You are currently using the Rime TTS provider.You can switch to a different TTS provider if asked.Don't use any unpronouncable characters.""",stt=deepgram.STT(),llm=openai.responses.LLM(),tts=rime.TTS(),)async def on_enter(self) -> None:await self.session.say("Hello! I'm now using the Rime TTS voice. How does it sound?")@function_toolasync def switch_to_elevenlabs(self):"""Switch to ElevenLabs TTS voice"""return ElevenLabsAgent()@function_toolasync def switch_to_cartesia(self):"""Switch to Cartesia TTS voice"""return CartesiaAgent()@function_toolasync def switch_to_playai(self):"""Switch to PlayAI TTS voice"""return PlayAIAgent()class ElevenLabsAgent(Agent):def __init__(self) -> None:super().__init__(instructions="""You are a helpful assistant communicating through voice.You are currently using the ElevenLabs TTS provider.You can switch to a different TTS provider if asked.Don't use any unpronouncable characters.""",stt=deepgram.STT(),llm=openai.responses.LLM(),tts=elevenlabs.TTS(),)async def on_enter(self) -> None:await self.session.say("Hello! I'm now using the ElevenLabs TTS voice. What do you think of how I sound?")@function_toolasync def switch_to_rime(self):"""Switch to Rime TTS voice"""return RimeAgent()@function_toolasync def switch_to_cartesia(self):"""Switch to Cartesia TTS voice"""return CartesiaAgent()@function_toolasync def switch_to_playai(self):"""Switch to PlayAI TTS voice"""return PlayAIAgent()class CartesiaAgent(Agent):def __init__(self) -> None:super().__init__(instructions="""You are a helpful assistant communicating through voice.You are currently using the Cartesia TTS provider.You can switch to a different TTS provider if asked.Don't use any unpronouncable characters.""",stt=deepgram.STT(),llm=openai.responses.LLM(),tts=cartesia.TTS(),)async def on_enter(self) -> None:await self.session.say("Hello! I'm now using the Cartesia TTS voice. How do I sound to you?")@function_toolasync def switch_to_rime(self):"""Switch to Rime TTS voice"""return RimeAgent()@function_toolasync def switch_to_elevenlabs(self):"""Switch to ElevenLabs TTS voice"""return ElevenLabsAgent()@function_toolasync def switch_to_playai(self):"""Switch to PlayAI TTS voice"""return PlayAIAgent()class PlayAIAgent(Agent):def __init__(self) -> None:super().__init__(instructions="""You are a helpful assistant communicating through voice.You are currently using the PlayAI TTS provider.You can switch to a different TTS provider if asked.Don't use any unpronouncable characters.""",stt=deepgram.STT(),llm=openai.responses.LLM(),tts=playai.TTS(),)async def on_enter(self) -> None:await self.session.say("Hello! I'm now using the PlayAI TTS voice. What are your thoughts on how I sound?")@function_toolasync def switch_to_rime(self):"""Switch to Rime TTS voice"""return RimeAgent()@function_toolasync def switch_to_elevenlabs(self):"""Switch to ElevenLabs TTS voice"""return ElevenLabsAgent()@function_toolasync def switch_to_cartesia(self):"""Switch to Cartesia TTS voice"""return CartesiaAgent()server = AgentServer()@server.rtc_session(agent_name="my-agent")async def entrypoint(ctx: JobContext):ctx.log_context_fields = {"room": ctx.room.name}session = AgentSession()await session.start(agent=RimeAgent(),room=ctx.room)await ctx.connect()if __name__ == "__main__":cli.run_app(server)