Files
2026-07-13 13:39:38 +08:00

65 lines
3.8 KiB
Markdown

# Front Desk Example
A front desk agent demonstrating customer service with calendar integration and appointment management.
For setup instructions and more details, see the [main examples README](../README.md).
## Overview
In this example, you will be able to schedule appointments (optionally with cal.com's API if `CAL_API_KEY` is set) and evaluate the agent's performance using `JudgeGroup`. The session will always begin with the agent saying "Hello, I can help you schedule an appointment!"
### Scheduling appointments
The LLM will call list_available_slots before `schedule_appointment`, since `slot_id` is a required argument.
`list_available_slots` will return slots like:
```bash
ST_abc123 - Saturday, January 1, 2000 at 14:00 PDT (in 5 days)
```
The slots are also cached as a lookup table for `schedule_appointment`.
https://github.com/livekit/agents/blob/8283a5a5c9863a07bcf030ee90e8ab780e1e569b/examples/frontdesk/frontdesk_agent.py#L184
If the slot is invalid, we raise a `ToolError` to allow the LLM to self correct, which prevents the LLM from passing a hallucinated answer.
https://github.com/livekit/agents/blob/8283a5a5c9863a07bcf030ee90e8ab780e1e569b/examples/frontdesk/frontdesk_agent.py#L94-L95
The user's email is then collected via `GetEmailTask()`. If the agent is interrupted after the task completes, `schedule_appointment` is aborted before an API call is made to book the slot. After the task, the function is uninterruptible.
https://github.com/livekit/agents/blob/8283a5a5c9863a07bcf030ee90e8ab780e1e569b/examples/frontdesk/frontdesk_agent.py#L97-L119
### Evaluations
After the session ends, we use a `JudgeGroup` with pre-built judges to score the conversation.
https://github.com/livekit/agents/blob/8283a5a5c9863a07bcf030ee90e8ab780e1e569b/examples/frontdesk/frontdesk_agent.py#L200-L214
When the success criteria for an agent is clear, using judges can complete the evaluation by measuring the performance quality.
### Simulations
`scenarios.yaml` contains 10 scenarios (happy paths and adversarial callers) that run the agent against a simulated user. All simulation glue lives in `simulation.py`; the agent code itself stays production-shaped.
Each scenario's `userdata` drives the whole run:
- `available_slots`: ISO datetimes seeding a deterministic `FakeCalendar` for that scenario. The entrypoint detects a simulated run via `ctx.simulation_context()` and swaps the data source.
- `expected_booking`: grades the run on final calendar state in `on_simulation_end`: the single slot the agent must have booked, `null` when the agent must not book anything, or omitted to grade on the conversation alone. This check can only veto a run the simulator passed (the effective result is the AND of both verdicts).
- `now`: an optional ISO datetime overriding the scenario clock (defaults to `simulation.SIMULATION_NOW`, `2026-06-12`).
The scenarios reference absolute dates, so under simulation the `FakeCalendar` runs on that fixed clock (`simulation.SIMULATION_NOW`, or a per-scenario `now`), keeping availability and expected bookings deterministic without any environment setup.
#### Tool mocking
Under simulation the agent's tools always run mocked, using the same `mock_tools` helper the tests use, but as a plain call targeting the live session instead of a context manager:
```python
mock_tools(FrontDeskAgent, simulation.tool_mocks(cal, tz), session=session)
```
The LLM keeps seeing the real tool schemas; only execution is intercepted, and a mock may declare any subset of the real tool's parameters. The mocks are dynamic: both close over the same `FakeCalendar`, so booking through the mocked `schedule_appointment` changes what the mocked `list_available_slots` returns on the next call (the "Booked slot disappears from later listings" scenario asserts exactly that). Passing a new dict replaces a session's mocks at any time; `{}` removes them.