Before the model
Policy pre-routing
Emergencies, opening hours, and handoff to a human are decided by policy, not by the LLM. These cases cost zero tokens and behave the same every time.
A tool-calling LLM agent for appointment-based businesses, built as an engineering exercise in making an agent predictable: cited answers, guarded output, a deterministic fallback, and latency and cost I can measure.
Appointment businesses need answers that are fast and correct, not just fluent.
A front-desk agent for a hotel or a dental practice is a small, high-stakes domain. A wrong opening hour, an invented service, or a casual reply to an emergency is worse than no answer. A plain "LLM plus prompt" can do all three.
I built Agent Receptionist to see how far an LLM agent can be pushed toward reliable behaviour: ground answers in the business's own documents and cite them, handle the predictable cases without the model at all, check every sentence before it reaches the user, keep a deterministic path for booking, and measure latency and cost instead of guessing.
The two demo businesses, a hotel and a dental practice, are fictional. They exist to exercise the same engine against different documents, hours, and policies. Switch between them with ?biz=hotel and ?biz=dental.
Cheap, deterministic decisions come first. The model is called only when it is needed, and its output is checked before it streams.
?biz=). Renders streamed text, citations, and the latency/cost panel.No secrets in the clientopenai/gpt-oss-120b. Calls tools and answers from retrieved context.RAG with cited sourcesStack: React, Vite, TypeScript on the client; Node and Express with SSE on the server; deployed on Vercel.
Layers around the model, each cheaper and more predictable than the model itself.
Before the model
Emergencies, opening hours, and handoff to a human are decided by policy, not by the LLM. These cases cost zero tokens and behave the same every time.
Grounding
Answers come from the business's own documents and carry their sources, so a reader can check where a claim came from instead of trusting the model.
After the model
Fallback
Booking does not have to depend on model behaviour. A deterministic engine is kept as the fallback path, so the agent is not the only thing standing between a user and a booking.
Security
Delivery
Replies stream over SSE with real token streaming, and a latency and cost panel makes each question's timing and token usage visible rather than assumed.
From my own test runs. Live runs were on 2026-10-24.
| Check | Result | Notes |
|---|---|---|
| Deterministic eval | 44/44 | Hotel 23/23, dental 21/21. |
| Live Groq eval | 43/44 | 2026-10-24. One eval-regex miss: the check's regex was too narrow; the reply itself was right. |
| Live 20-question test | 19/20 | 2026-10-24. One eval-regex miss, same cause: too-narrow regex, correct reply. |
| Streaming events | 11 median | Real token streaming, not a single buffered response. |
| Time to first text | ~550 ms | Of ~610 ms total, in tests. |
| Live public-URL check | ~840 ms first token | 563 prompt + 251 completion tokens, about $0.0002 per question. A single check, not a benchmark. |
| Policy-routed replies | 0 tokens | Emergencies, hours, and handoff never reach the model. |
Small suites on fictional businesses: these numbers show the engine behaves as designed, not how it would perform on a real business's traffic. The latency and cost figures come from a handful of runs and one live check.
What this design gives up, and what I would do next.
Tradeoffs
Next
Try it on either fictional business.
Open the dashboard and ask a question, then look at the citations and the latency/cost panel. Try asking about an emergency or opening hours to see policy pre-routing.
Source code is private. Available on request or in interviews: usmamalik346@gmail.com.