LiveKit is a powerful platform for building real-time video, audio, and data applications. With Maxim’s integration, you can monitor and trace your LiveKit voice agents, capturing detailed insights into conversation flows, function calls, and performance metrics in real-time.
import loggingfrom maxim import Maximfrom maxim.logger.livekit import instrument_livekit# Initialize Maxim loggerlogger = Maxim().logger()# Automatically fetches MAXIM_API_KEY and MAXIM_LOG_REPO_ID from environment variables# Optional: Set up event handling for trace lifecycledef on_event(event: str, data: dict): if event == "maxim.trace.started": trace_id = data["trace_id"] trace = data["trace"] logging.info(f"Trace started - ID: {trace_id}") elif event == "maxim.trace.ended": trace_id = data["trace_id"] trace = data["trace"] logging.info(f"Trace ended - ID: {trace_id}")# Instrument LiveKit with Maxim observabilityinstrument_livekit(logger, on_event)
instrument_livekit: This function integrates Maxim’s observability features with LiveKit Agents . It allows you to automatically capture and send trace data to the platform:
logger = Maxim().logger() : This creates a Maxim logger instance that:
Connects to your Maxim project using the MAXIM_API_KEY and MAXIM_LOG_REPO_ID environment variables
Handles sending trace data to the Maxim platform
Provides the logging interface for capturing events, metrics, and traces
on_event : This is a callback function that gets triggered during trace lifecycle events:
event: A string indicating what happened ("maxim.trace.started" or "maxim.trace.ended")
data: A dictionary containing trace information:
trace_id: Unique identifier for the trace
trace: The actual trace object with metadata, timing, and other details
What it does:
When a new conversation or interaction starts → logs “Trace started”
When a conversation or interaction ends → logs “Trace ended”
Useful for debugging and monitoring trace lifecycle in real-time
import osimport uuidimport dotenvfrom livekit import agentsfrom livekit import api as livekit_apifrom livekit.agents import Agent, AgentSession, function_toolfrom livekit.api.room_service import CreateRoomRequestfrom livekit.plugins import googledotenv.load_dotenv(override=True)class Assistant(Agent): def __init__(self) -> None: super().__init__( instructions="You are a helpful voice AI assistant. You can search the web using the web_search tool." ) @function_tool() async def web_search(self, query: str) -> str: """ Performs a web search for the given query. Args: query: The search query string Returns: Search results as a formatted string """ # Your web search implementation here return f"Search results for: {query}"async def entrypoint(ctx: agents.JobContext): # Generate or use predefined room name room_name = os.getenv("LIVEKIT_ROOM_NAME") or f"assistant-room-{uuid.uuid4().hex}" # Initialize LiveKit API client lkapi = livekit_api.LiveKitAPI( url=os.getenv("LIVEKIT_URL"), api_key=os.getenv("LIVEKIT_API_KEY"), api_secret=os.getenv("LIVEKIT_API_SECRET"), ) try: # Create room with configuration req = CreateRoomRequest( name=room_name, empty_timeout=300, # Keep room alive 5 minutes after empty max_participants=10, # Adjust based on your needs ) room = await lkapi.room.create_room(req) print(f"Room created: {room.name}") # Create agent session with Gemini model session = AgentSession( llm=openai.realtime.RealtimeModel(voice="coral"), ) # Start the session await session.start(room=room, agent=Assistant()) await ctx.connect() # Generate initial greeting await session.generate_reply( instructions="Greet the user and offer your assistance." ) finally: await lkapi.aclose()# Run the agentif __name__ == "__main__": opts = agents.WorkerOptions(entrypoint_fnc=entrypoint) agents.cli.run_app(opts)
This code -
Creates a custom agent class:
Inherits from Agent: Base class for all LiveKit agents
instructions: System prompt that defines the agent’s personality and capabilities
Tells the agent: It’s a voice assistant that can use web search
Creates a callable tool:
@function_tool(): Decorator that registers this method as a tool the agent can call
async def: Asynchronous function (required for LiveKit agents)
Type hints: query: str -> str helps the AI understand input/output types
Docstring: Describes the function for the AI model
Current implementation: Placeholder that returns a formatted string
The main function that runs when the agent starts:
ctx: agents.JobContext: Contains information about the current job/session
Creates a unique room name:
First tries: Environment variable LIVEKIT_ROOM_NAME
Falls back to: Generated name like assistant-room-a1b2c3d4e5f6...
uuid.uuid4().hex: Creates a random hexadecimal string
Starts the agent and begins conversation:
session.start(): Connects the agent to the room
agent=Assistant(): Uses your custom Assistant class
ctx.connect(): Connects to the LiveKit infrastructure
generate_reply(): Makes the agent speak first with a greeting