Skip to main content
Voice agents are transforming business operations by introducing efficiencies and personalization for each customer interaction. While most use cases focus on agents receiving calls, this tutorial covers outbound voice AI agents and the use cases they unlock. Outbound agents handle tasks like appointment scheduling, lead qualification, and customer follow-ups while maintaining a human-like, conversational tone. They replace manual efforts with intelligent automation, improving customer engagement in sales, healthcare, hospitality, and collections. This tutorial sets up an outbound calling agent that does a warm transfer — handing off the call to a real person using LiveKit. A fitting example: a support center where an agent collects data before connecting to a real person. The final code implementation and complete example can be found in our examples Github repository here.

Cerebrium setup

Install the Cerebrium CLI and create a project:
This creates a folder with two files:
  • main.py - The entrypoint file where application code lives.
  • cerebrium.toml - A configuration file that contains all build and environment settings.
These files are populated later in the tutorial.

Livekit Setup

LiveKit is a platform for building real-time audio and video applications. Start by creating a LiveKit account. You can do this by signing up to an account here (they have a generous free tier). Once the account is created, run the following commands to install the CLI package (Homebrew can be installed from here).
Authenticate the CLI with the newly created account:
Create a .env file with LiveKit credentials. Get these from the LiveKit dashboard: click the Settings tab for the project URL, then the Keys tab to create a new key and copy the API key and secret:
LiveKit Dashboard The LiveKit instance is now set up as the transport layer for the agent.

Twilio Setup

Setting up an outbound calling agent requires a SIP trunk in Twilio. A SIP trunk is a virtual phone line that connects the app to the traditional phone network, enabling outbound calls to any phone number. It routes calls properly and reliably, acting as the bridge between the app and the global telephony system.
  1. Log in to your Twilio Console: Go to Twilio Console and log in with your credentials. If you don’t already have an account, create one.
  2. Add Phone Numbers: Under the “Develop” tab is the “Phone numbers” section. Navigate to “Active numbers” and purchase a number if you don’t already have one. Toll free numbers won’t work for our use case, so ensure that a “Local” number exists.
  3. Install the Twilio CLI and authenticate your CLI:
  4. Create a SIP trunk: The domain name for your SIP trunk must end in pstn.twilio.com. For example to create a trunk named My test trunk with the domain name my-test-trunk.pstn.twilio.com, run the following command:
  5. Create your credentials: To secure the SIP trunk, create a credential list in the Twilio console dashboard. Navigate to “Voice”, then “Manage”, then “Credential lists”. Click the plus icon and add a friendly name, username, and password. Save these credentials — they are required in a later step.
Twilio Dashboard
  1. Associate your SIP with your newly created credentials. Copy the values for your Account SID and Auth Token from the Twilio console.
With the trunk configured, register Twilio’s outbound trunk with LiveKit. SIP trunking providers typically require authentication when accepting outbound SIP requests to ensure only authorized users can make calls. Create a file named outbound-trunk.json using the Twilio phone number you purchased in the previous step, trunk domain name, and username and password.
Run the following in your CLI: lk sip outbound create outbound-trunk.json The output returns the trunk ID, which is required in a later step.

Services setup

The following services power the outbound AI agent: Each service offers a generous free tier:
  • Deepgram
You can signup for a Deepgram account here. Straight from the dashboard, you can create a API key. Store this value for later Deepgram Dashboard
  • OpenAI
You can signup for a OpenAI account here. You can then click “Dashboard” top right and then “API keys” in the left sidebar. Create an API key and store this value to use later. OpenAI Dashboard
  • Cartesia
You can signup for a Cartesia account here. Once you login, you can click, API keys in the left sidebar and create a new API key. Cartesia Dashboard Finally, let us then create a .env file that contains our environment variables from all the steps above.
Create a requirements.txt with the following Python packages:
Run pip install -r requirements.txt. FastAPI is explained later. Create a file called main.py for the agent code. The directory structure should look like this:
  • main.py
  • .env
  • requirements.txt
  • outbound-trunk.json
Add the following code to your main.py
This LiveKit setup does the following:
  • Specifies an initial system prompt to guide the AI agent
  • Lists the services and configures response timing settings
  • Collects and displays call metrics throughout, with a summary logged when the call ends
  • Starts the agent with an initial greeting
To connect the customer to a real person when a specific stage is reached or the user requests it, use function calling. Add the following code to the entrypoint:
The @ai_callable decorator tells the LLM this function is available, and the docstring describes when to use it. When triggered, the function makes an outbound call to a phone number and disconnects the agent from the room, leaving just the two users in the call. The create_sip_participant() function is defined in the next step. To create an outbound call and add a user to the call, add the following code to main.py above entrypoint():
To test locally, create a test.py file:
To test locally, run python main.py in one terminal. This keeps the agents running as an open process: LiveKit processes Once the job processes initialize, open a separate terminal and run python test.py. This initiates a call to the provided phone number. Note: calls are limited to the region the number is purchased from. With local testing working, deploy on Cerebrium for production-ready autoscaling.

Deploy on Cerebrium

Specify the Cerebrium environment using a Dockerfile:
Edit cerebrium.toml with the following:
This defines the hardware, scaling parameters, dependencies, and the port and Dockerfile for the application. In the Cerebrium dashboard, go to the Secrets tab in the left sidebar and upload the .env file. Cerebrium imports secrets as standard environment variables, making local and cloud testing seamless. Cerebrium Secrets Run the following command:
This installs all necessary packages and deploys the application. LiveKit workers run in the cloud — test by running the test.py script locally and checking logs on the Cerebrium dashboard.

Further Improvements:

To reduce latency, Cerebrium partners with Deepgram and Rime to run STT and TTS models locally alongside the LiveKit worker, reducing latency by ~400ms. This tutorial set up an outbound calling agent that performs warm transfers to live agents using LiveKit. The solution supports diverse use cases such as pre-call data collection, sales outreach, and customer follow-ups by integrating LiveKit, Twilio, and AI-driven STT, TTS, and LLM services. Find the final example on GitHub. Ask questions or give feedback in the Discord community.