Skip to main content
Build a working browser voice agent with LiveKit transport, OpenAI transcription and responses, and Rime speech. The completed agent handles turn-taking, speech recognition, agent logic, and streaming TTS. Demo of a voice agent conversation using LiveKit and Rime

Step 1: Prerequisites

Gather the following API keys and tools before starting.

1.1 Rime API Key

Sign up for a Rime account and copy your API key from the API Tokens page. This enables access to the Rime API for text-to-speech (TTS).

1.2 OpenAI API Key

Create an OpenAI account and generate an API key from the API keys page. This key enables speech-to-text (STT) and LLM responses.

1.3 LiveKit Cloud

Create a LiveKit Cloud account for real-time audio transport:
  1. Create a new project called rime-agent
  2. Go to SettingsAPI keysCreate key
  3. Copy your WebSocket URL, API key, and API secret. You need all three.

1.4 Python

Install Python 3.10 or later. Verify your installation by running python --version in your terminal.
  • A Room is a virtual space where participants connect and share media in real time.
  • An Agent is a server-side participant that processes media streams and interacts with users.
  • LiveKit Cloud transports real-time audio between participants.
The agent sends user audio through LiveKit to OpenAI for transcription and response generation, then returns Rime speech through the same room:Voice agent architecture showing audio flowing from user through LiveKit, OpenAI, and Rime

Step 2: Project setup

Set up your project folder, environment variables, and dependencies.

2.1 Create the project folder

Create a new folder for your project and navigate into it:

2.2 Set up environment variables

In the new directory, create a file called .env and add the keys that you created in Step 1:
Replace the placeholder values with your actual API keys and credentials.

2.3 Configure dependencies

Create a virtual environment and activate it:
Next, install the uv package manager:
This helps with LiveKit’s complex dependencies. Create a file called pyproject.toml and add the following dependencies:
These packages add the following:
  • openai plugin: Connects to OpenAI for STT and LLM
  • rime plugin: Connects to Rime for text-to-speech
  • silero plugin: Voice Activity Detection (knows when you start/stop speaking)
  • turn-detector plugin: Detects when you’ve finished your turn in the conversation
  • noise-cancellation plugin: Filters out background noise
  • python-dotenv: Loads your API keys from the .env file
Then, install the dependencies by running:

Step 3: Create the agent

Create a file called agent.py for all the code that gets your agent talking. If you’re in a rush and just want to run it, skip to Step 3.6: Full agent code. Otherwise, continue reading to code the agent step-by-step.

3.1 Load environment variables

Add the following imports and initialization code to agent.py:
This loads the API keys from your .env file so they’re available throughout the application. Don’t skip this step: the LiveKit agents CLI doesn’t load .env files automatically, so without load_dotenv() the worker won’t find your LiveKit and API credentials.

3.2 Define an Agent class

Add the following class definition to agent.py:
This creates a class that extends the Agent base class, defining your agent’s personality through a system prompt. The prompt can be as simple or complex as you like. Later in the guide you’ll see an example of a detailed system prompt that fully customizes the agent’s behavior. Import the Agent class at the top of the the script. For convenience, below are all the rest of the required imports. Add these imports to the top of agent.py as well:
These provide access to the LiveKit Agents SDK and the plugins for STT, LLM, TTS, and VAD (voice activity detection).

3.3 Code the conversation pipeline

Add the following entrypoint function to agent.py:
This function runs each time a user connects and does the following:
  • Connects to the LiveKit room and waits for a participant to join
  • Creates an AgentSession that wires together the voice pipeline components: OpenAI for STT and LLM, Rime for TTS, and LiveKit for VAD and turn detecting
  • Starts the session with noise cancellation enabled to filter out background noise from the user’s microphone
  • Greets the user with an initial message

3.4 Initialize the VAD plugin

Add the following prewarm function below the entrypoint function:
This function loads the VAD plugin once when the worker starts, rather than for each new conversation.

3.5 Create the main entrypoint

Add the following __main__ block to agent.py:
This starts the agent server that listens for incoming connections from LiveKit. WorkerOptions is configured with the two functions you created above: prewarm_fnc runs once per worker process to preload models, and entrypoint_fnc runs each time a user connects to a room.

3.6 Full agent code

At this point, your agent.py should look like the complete example below:

Step 4: Test your agent

4.1 Start the agent

Start your agent by running:
The dev argument starts the agent in development mode. You’ll see output like:

4.2 Connect to your agent

Open the LiveKit Agents Playground in your browser.
  • Select your project and click Use [project_name]
  • In the top right of the Playground, click Connect
  • Allow microphone access when prompted
If everything is set up correctly, you should hear your agent say the greeting that you configured above:
You can now talk to your agent using your microphone or by typing in the chat section.

Step 5: Customize your agent

Now that your agent is running, you can experiment with different voices and personalities.

5.1 Change the voice

Update the tts line in your AgentSession to try a different voice:
Rime offers many voices with different personalities. See the full list on the Voices page.

5.2 Fine-tune agent personalities

Create a new file called personality.py with the following content:
Update your agent.py to import and use this prompt:
Update the greeting at the end of entrypoint:
Keeping the system prompt in a separate file lets you change the character without editing the agent logic.

5.3 Adjust TTS chunking

By default, rime.TTS(...) uses Rime’s HTTP synthesis path. LiveKit wraps non-streaming TTS providers so streamed LLM output can be sent to TTS in sentence-aligned chunks. If you want to tune those chunks, wrap Rime explicitly:
Chunking options:
  • min_token_len: Batches sentences until the chunk reaches this size. Increase it for smoother multi-sentence prosody.
  • max_token_len: Caps chunk size. Use it to avoid very large TTS requests.
  • retain_format: Keeps original whitespace and newlines. True matches LiveKit’s default wrapper behavior.
Tuning chunk size is a prosody/latency tradeoff: larger chunks usually sound better, while smaller chunks usually start faster.

Troubleshooting

If something is not behaving as expected, check out the quick fixes below.

Agent doesn’t respond to speech

  • Check microphone permissions: Ensure your browser has microphone access enabled.
  • Verify VAD is working: Look for speech detected logs in the terminal. If missing, check your Silero plugin installation.
  • Test with text input: Use the chat input in the Playground to confirm the agent logic works.

”Connection refused” or agent won’t start

  • Check environment variables: Ensure all keys in .env are set correctly with no extra spaces.
  • Verify LiveKit credentials: Confirm your LIVEKIT_URL, LIVEKIT_API_KEY, and LIVEKIT_API_SECRET match your LiveKit Cloud project.

Incorrect voice detection

  • Enable noise cancellation: Verify noise_cancellation.BVC() is included in your RoomInputOptions.
  • Check your microphone: Test with a different input device or headset
  • Reduce background noise: The VAD may struggle to detect speech in noisy environments.