Skip to content
Episode 115 · Design the booking agent

Design a hotel booking agent end to end

Monday, 9:00: Karim's brief fits on one slide. StayHub's booking agent goes live on WhatsApp in 6 weeks, in 6 languages, for 40,000 conversations a day, at no more than €0.15 each, with zero double bookings and no card number ever in a prompt.

Put it all together: design a real hotel booking agent where the AI is one part among many, and most of the safety lives around it.

30 min advancedEnd-to-end agent system designTracing and monitoring agentsEvaluating agents on tasks and trajectoriesApproval gates for side effectsStep limits and stopping conditionsIdempotency keys & dedupe tables
  1. Problem

    A hotel group wants guests to search, book, change and cancel stays by chatting, on the website and WhatsApp, in six languages, 24/7, without double bookings, leaked data or surprise bills.

  2. Why the simple system fails

    Wiring a model to the booking API with a long prompt works in a demo. In production it double-books on retries, quotes prices it invented, stores card numbers in chat logs, can't be debugged when a guest complains, and costs far more per booking than anyone estimated.

  3. Engineering concept

    Design the agent like any system: requirements and non-goals first, narrow intent-level tools, policies and approvals in code, scoped memory, deterministic money and inventory handling, and evals, traces and cost budgets from day one.

  4. Technology

    AI gateway with model routing, an agent runtime with budgets, typed tools over PMS and payment APIs, inventory holds and idempotency keys, policy RAG with citations, a policy engine, session and profile memory with consent, OpenTelemetry-style traces, and offline task suites with a simulated PMS.

  5. Trade-offs

    Autonomy vs control, conversion vs safety, latency vs model quality, cost per conversation vs helpfulness, and personalisation vs privacy. Each is a dial you set from requirements, not a default.

01

The problem

2 min
Monday, 9:00. Karim's one-slide brief.
  1. Karim · CTO
    Booking agent on web and WhatsApp, 6 languages, live in 6 weeks. 40,000 conversations a day.
  2. Karim · CTO
    Hard limits: ≤ €0.15 per conversation, zero double bookings, no card number ever in a prompt, log or trace.
  3. Lina · Senior engineer, your mentor
    You lead this one, end to end. I'll only check your answers.
02

The big idea

4 min
One slide, every lesson
The big idea

The model decides what to ask for; deterministic systems decide prices, availability, permissions and money.

Every episode of this module added a piece: cost control, grounded answers, the agent loop, gates. Here they meet, and every hard limit gets an owner in code.

03

How it works

5 min
StayHub's booking agent, by requirement
  1. 1
    Requirements and non-goals

    In: search, policy answers with citations, book with confirmation, change and cancel in policy, hand off the rest. A non-goal is something v1 deliberately won't do: group bookings, loyalty transfers, rate negotiation.

  2. 2
    Estimates

    8 turns × (5,400 in, 250 out) on the large model, uncached: ≈ €0.26 per conversation. Prompt caching plus 70% of turns on a small model: ≈ €0.05; ≈ €0.09 with agent runs and RAG. Under €0.15.

  3. 3
    Narrow tools

    search_stays, get_quote, hold_room(quote_id), confirm_booking(hold_id), start_checkout, policy_search, handoff. Intent-level, validated, permission-checked. Changes and cancellations stay workflows.

  4. 4
    Quotes and holds

    A quote is a price our pricing system calculated, with an id. A hold reserves the room for 15 minutes; one per conversation. The guest's YES is bound to the hold id; every write carries an .

  5. 5
    Card data out

    Hosted checkout: the payment provider's page takes the card, so it never touches chat, model or logs. Card numbers typed in chat are redacted at the gateway, before anything else sees them.

  6. 6
    Observability

    A trace per conversation, cost per conversation and per booking, and 250 scripted conversations in 6 languages run on every change.

04

Watch a decision being made

4 min
Worked example

You turn the brief into a design; Lina checks each limit

Meet every hard limit: ≤ €0.15 per conversation, zero double bookings, no card numbers in AI systems.

  1. 1Price it before building

    Uncached large model: ≈ €0.26, over budget. Caching the 3,000-token stable prefix + routing 70% of turns to the small model: ≈ €0.05.

    python
    large = (2400*5 + 3000*0.5 + 250*25) / 1e6   # ≈ €0.0198 per turn, cached
    small = (2400*0.2 + 3000*0.02 + 250*0.8) / 1e6 # ≈ €0.0007 per turn, cached
    print(8 * (0.3*large + 0.7*small))            # ≈ €0.05 per conversation

    Why: The budget is only reachable with caching and routing, so they're in the design from day one.

  2. 2Make money and inventory deterministic

    Prices only from quotes; confirm_booking takes a hold id the guest said YES to; expired hold → new quote shown first.

    Why: These rules in code make "zero double bookings" and "no invented prices" true whatever the model says.

  3. 3Keep card data out

    Redact at the gateway; pay on a hosted page.

    Why: The safest card number is one the agent never receives.

  4. 4Make it testable

    Traces, cost dashboards and a 250-conversation task suite. Lina: "Checked. Every limit has an owner."

    Why: When a guest complains, the trace shows what happened; when a prompt changes, the suite shows what broke.

The whole thing in one line: Each hard limit is owned by code: the gateway for cost, quotes and holds for money and rooms, hosted checkout for cards, traces and a task suite for debugging. None by the prompt.
05

In real life

3 min
How far before handing control back?

Booking.com AI Trip Planner: plan, then normal checkout

  • Launched in 2023 to explore destinations and stays in conversation
  • Booking completes in the regular flow
  • Low risk; the conversation ends before the transaction

Fits a first version that proves demand.

OpenAI Operator: acts, hands back for sensitive steps

  • Launched in 2025 as an agent that carries out tasks like bookings on websites
  • Publicly described handing control back for logins and payment details

Acts for the user, keeps payment in the user's hands.

06

What goes wrong

3 min
Letting the model state prices or availability

It rounds, averages or invents, and prices change between turns.

Instead

Prices and rooms only from tools; bookings reference quote and hold ids.

Exposing raw backend APIs as tools

A generic request tool can reach anything, including other guests' data.

Instead

Intent-level tools with schemas and ownership checks.

Shipping without traces and a task suite

Complaints can't be debugged; prompt changes break things silently.

Instead

Trace every conversation; run scripted conversations on every change.

07

Trade-offs

3 min
DesignChoose whenYou pay
Assistant, then normal checkoutProving demandGuests leave the chat to book
One transactional agent with gatesClear booking tasks, strong backend guaranteesA tool list that grows with features
Multi-agent systemMany capabilities and teams, a measured problemMore calls and cost; context lost in handoffs
Wednesday, 14:00. Architecture review.
  1. Maya · Product manager
    Make it multi-agent: search, booking and support agents, plus an orchestrator. Easier to grow.
  2. Karim · CTO
    Four agents in six weeks? One agent with narrow tools, plus our existing workflows.
  3. Maya · Product manager
    One agent with every tool will get confused as we add features.
08

Your job as tech lead

4 min

Claude Code can write the code for this. You still own the decisions, and you have to know what good looks like to accept or reject its work.

Decisions you own
  • The scope and non-goals: search, quote, hold, book on web and WhatsApp in 6 languages; no group bookings, no rate negotiation.
  • Which system owns each fact: prices from get_quote, rooms from the PMS, policies from cited RAG. The model computes none of them.
  • The budgets: ≤ €0.15 per conversation, first token < 2 s, zero double bookings.
Tell Claude Code
Before writing code, write `docs/booking-agent.md` for StayHub's booking agent (web + WhatsApp, 40,000 conversations a day): the tools, which are reads and writes, and where the guest confirms. Rules: prices only from `get_quote`, 15-minute holds, one active hold per conversation, idempotency keys on every write, hosted checkout, card numbers redacted before the model, logs or traces. Include a cost estimate per conversation against €0.15 and the evals you'll run. Don't touch PMS or payment code.
Check before you accept
  • Follow one booking: search → quote → hold → guest confirms the exact total → checkout → confirm_booking. Every write is after the confirmation.
  • The total in the confirmation comes from the quote id, never a number the model computed.
  • A fake card number pasted in a test chat is absent from the prompt, logs and traces.
Red flags
  • The model adds up nightly rates, taxes and fees itself.
  • Raw guest messages with card numbers kept in logs "for debugging".
  • A generic "call any backend endpoint" tool.
09

Check yourself

2 min
Q1/3Design
How should the total price shown in the confirmation step be produced?
How confident are you?

Next: the next part of the course opens up tool calling itself, starting with 41 guests who arrived holding a "Booked!" message for bookings that never existed.

Finished?

Mark it complete to update your skill map.

Go deeper (optional)You don't need this to understand the lesson. Open it when a project needs the details: Technical deep dive, Interactive simulation, Visual diagram, Analogy, Why it matters, Check your understanding, Practice ladder, Explain it yourself.
10

Technical deep dive

From search to a confirmed booking
Worked example

You design the booking agent end to end

Turn Karim's one-slide brief into an architecture that meets every hard limit: ≤ €0.15 per conversation, zero double bookings, no card numbers in prompts, logs or traces, in 6 languages on web and WhatsApp.

  1. 1Write requirements and non-goals

    In: search, policy Q&A with citations, book with confirmation, change and cancel in policy, handoff. Out (v1): group bookings, loyalty transfers, rate negotiation, other companies' inventory.

    Why: Requirements decide every later choice; non-goals remove whole failure classes before any code exists.

  2. 2Estimate cost and latency

    8 turns × (5,400 in / 250 out). Large, uncached: ≈ €0.26 per conversation, over budget. Prompt caching on the stable 3,000-token prefix + 70% of turns on the small model: ≈ €0.05; with agent runs, RAG and reranking ≈ €0.09. Stream replies for a first token < 2 s.

    python
    large = (2400*5 + 3000*0.5 + 250*25) / 1e6   # ≈ €0.0198 per turn, cached
    small = (2400*0.2 + 3000*0.02 + 250*0.8) / 1e6 # ≈ €0.0007 per turn, cached
    turn = 0.3*large + 0.7*small                   # ≈ €0.0065
    print(8 * turn)                                 # ≈ €0.05 per conversation

    Why: Estimating before building shows the budget is only reachable with caching and routing, so they're in the design from day one.

  3. 3Design narrow tools

    search_stays, get_quote, hold_room(quote_id), confirm_booking(hold_id), start_checkout(booking_id), policy_search, handoff. Changes and cancellations run as workflows. Every argument is schema-validated; ownership is checked by the policy engine.

    Why: Intent-level tools expose only what the agent needs. A generic "call any API" tool would let it reach other guests' data.

  4. 4Make money and inventory deterministic

    Prices only from quotes. Holds last 15 minutes, one active hold per conversation. confirm_booking needs the guest's YES bound to the hold id. Every write has an idempotency key. Expired hold → new quote shown before booking.

    Why: These rules, in code, are what make "zero double bookings" and "no invented prices" true, regardless of what the model says.

  5. 5Protect data and gate risk

    Redact card numbers and other sensitive data at the gateway, before the model, logs and traces. Payment only on a hosted checkout page. Policy answers grounded with citations; out-of-policy refunds go to staff.

    Why: The safest card number is one the agent never receives. Redaction at the edge protects every system downstream.

  6. 6Make it observable and testable

    A trace per conversation (model calls, tools, costs, stop reasons); dashboards for cost per conversation and per booking; a task suite of 250 scripted conversations against a simulated booking system in 6 languages, run on every change. Lina: "Checked. Every limit has an owner."

    Why: When a guest complains, the trace shows what happened; when you change a prompt or model, the suite shows what broke.

The whole thing in one line: You turned the brief into requirements and non-goals, priced it (≈ €0.09 per conversation with caching and routing), exposed only narrow tools, made prices, holds and bookings deterministic, kept card data out of every AI system, and made the whole thing traceable and testable.
Hard limitOwned byHow
≤ €0.15 per conversationAI gateway + runtimeModel routing, prompt caching, step budgets, cost metered per conversation
Zero double bookingsBooking toolsOne active hold, idempotency keys, confirmation bound to hold id
No invented pricesPricing systemPrices only from get_quote; bookings reference quotes
No card numbers in AI systemsGateway + hosted checkoutRedaction before model, logs, traces; payment on a hosted page
Correct policy answersPolicy RAGFiltered retrieval, citations, verification, refusal + handoff
DebuggableObservabilityTrace per conversation, task suite, sampled reviews
Every hard limit has an owner in code. None of them is owned by the prompt.
11

Interactive simulation

12

Visual diagram

Click a component

A production hotel booking agent. Click components for details, or follow one booking end to end.

13

Analogy

  • A new front-desk employeeLooks things up in the reservation systemThe booking agentRead-only tools
  • A new front-desk employeeQuotes prices from the system, not memoryThe booking agentPrices from the pricing service
  • A new front-desk employeeHolds a room while the guest decidesThe booking agentA short inventory hold
  • A new front-desk employeeGuest signs before any chargeThe booking agentExplicit guest approval
  • A new front-desk employeeCard goes through the terminal onlyThe booking agentPayment data never reaches the AI
  • A new front-desk employeeOdd cases go to the duty managerThe booking agentEscalation to staff

Where the analogy breaks: a new employee learns from each shift. The agent doesn't, so your team reviews traces and tests regularly and improves it themselves.

14

Why it matters

A booking agent is a great capstone because it has every hard part at once.

There's real money, so approvals and safe retries matter. There's live data, prices and availability that change by the minute, so the model must never answer from memory. There's fine print, so policy answers must be grounded and cited.

There's personal data, so memory needs limits and consent under rules like . And there are messy humans who change their minds mid-chat, so the agent must re-plan without losing the thread.

If you can design this one well, you can design most business agents: support, purchasing, scheduling, insurance claims.

15

Check your understanding

Q1/3Reasoning
Each conversation makes 8 model calls with 5,000 input and 250 output tokens per call. Prices: $1 per 1M input tokens, $5 per 1M output tokens. What is the model cost per day for 10,000 conversations?
$
How confident are you?
16

Practice ladder

Step 1 · Trace

Trace a booking conversation

Scenario Warm-up

A guest on WhatsApp, in Portuguese: "Two nights in Porto, 14–16 Nov, two adults, under €180, near the river."

Trace the conversation through the design: which component handles each step, which tools are called, and what the guest sees, up to a paid booking. Then trace what happens if she replies "SIM" (yes) 20 minutes after the hold was created.

Step 2 · Complete

Finish the tool table

Design Practice

Lina's tool table has gaps. For each tool, fill in its type (read / write), its key argument(s), and its guard (what code checks before running it).

ToolTypeKey argumentsGuard
search_staysreadcity, dates, guests, max_price___
get_quote___hotel_id, room_type, dates, guests—
hold_roomwrite______
confirm_bookingwritehold_id___
cancel_bookingwritebooking_id___
Step 3 · Solve

Fit the Japanese market in budget

Estimation Practice

StayHub launches the agent in Japanese. From an earlier episode, Japanese uses about 1.8× the tokens of English for the same conversation. Japanese conversations also average 10 turns instead of 8.

Using the English per-turn costs (cached large ≈ €0.0198, cached small ≈ €0.0007, 70% small routing ≈ €0.0065 per turn) and treating token counts as scaling cost linearly:

Estimate the cost per Japanese conversation (model calls only), compare it with the €0.15 budget (about €0.04 of the €0.09 total is agent runs, RAG and reranking, assume it scales the same way), and propose what to do if it's over.

Step 4 · Decide

Go or no-go for WhatsApp

Decision Stretch

It's week 6. Results from the WhatsApp pilot (2,000 conversations a day):

  • Cost per conversation: €0.11 (budget €0.15).
  • Double bookings: 0 (one hold rule + idempotency held up under 3 provider timeouts).
  • Card numbers reaching the model since redaction shipped in week 2: 0; 37 from week 1 purged.
  • Task suite: 96% pass in English, Portuguese, Spanish, French, German; 88% in Japanese (mostly wrong date formats).
  • Handoff rate: 9%; staff answer within 20 minutes in the daytime, 2 hours at night.

Write a short launch decision: "We chose X over Y because…, accepting the risk of…", including what you'd launch, where, and the conditions for the rest.

17

Explain it yourself

Walk an interviewer through your design for a hotel booking agent in five minutes: what's in it, where the safety lives, and how you'd know it works.

0 words