One specialist, one job

A good agent has one job. The instructions describe who it is, what it handles, and what it refuses. When you try to make one agent do everything, the prompt becomes a wall of exceptions and the model starts guessing.

triage_agent.py
python
from livekit.agents.voice import Agent
from livekit.agents.llm import function_tool
from livekit.plugins import deepgram, silero
from utils.livekit_utils import get_livekit_llm
from prompt_utils import load_prompt

class SupportAgent(Agent):
    """Handles appointments, prescription refills, and medical records."""

    def __init__(self) -> None:
        super().__init__(
            instructions=load_prompt("support_prompt.yaml"),
            stt=deepgram.STT(),
            llm=get_livekit_llm(),
            tts=deepgram.TTS(model="aura-asteria-en"),
            vad=silero.VAD.load(),
        )

    @function_tool
    async def check_appointment_availability(self, day: str) -> str:
        """Return available appointment slots for the given day."""
        return f"We have 9am, 11am, and 2pm open on {day}."

The prompt lives in a YAML file so product can edit it without touching code. Function tools become callable actions the LLM can invoke by name, with typed arguments.

Matching exercise: Match each agent to its responsibility

Loading practice…

Prompts change more often than code. Keeping them in YAML lets non-engineers tune tone, edge cases, and escalation rules without touching Python. It also lets you diff prompt changes cleanly in code review and reuse prompt fragments across agents.

AI prompt: Try it: draft a specialist prompt

Loading practice…

Checkpoint: Single voice agent checkpoint

Loading practice…