Chapter CTools: when models need the outside worldPage 4 of 8

Tools: when models need the outside world

Worked flow: weather and calendar

Multi-tool work is reliable when each call answers one specific question, later calls use verified earlier results, and the application gates every side effect.

~15 minWorked example

Before you start

Why this matters

Consider this request: “Find a dry thirty-minute slot after 4 p.m. tomorrow and put a walk on my calendar.” It combines a preference, a calendar search, a weather lookup, a scheduling decision, and a calendar write.

The model cannot safely jump from the sentence to “Done.” It needs to resolve “tomorrow” in the user’s timezone, inspect availability, obtain a forecast granular enough to compare candidate times, propose a specific event, and create it only under the application’s confirmation policy.

1Learn the idea

Read

Define the available contracts

Assume the application advertises three narrow tools. list_calendar_events reads events in a bounded interval. get_hourly_forecast reads forecast periods. create_calendar_event writes one event after confirmation.

A compact representation might be:

{
  "tools": [
    {
      "name": "list_calendar_events",
      "required": ["starts_at", "ends_at", "timezone"]
    },
    {
      "name": "get_hourly_forecast",
      "required": ["latitude", "longitude", "date", "timezone"]
    },
    {
      "name": "create_calendar_event",
      "required": ["title", "starts_at", "ends_at", "timezone", "confirmation_token"]
    }
  ]
}

The location coordinates and timezone should come from trusted user settings or explicit clarification, not silent invention. If “after 4 p.m.” has no upper boundary, the application can apply a documented waking-hours policy, such as ending the search at 8 p.m., or the assistant can ask.

The confirmation token is not text the model can invent. It represents application evidence that the user approved the final event details.

Read

Read the calendar and weather

Suppose the trusted profile says Asia/Dubai and provides a saved location. The model proposes a calendar query:

{
  "name": "list_calendar_events",
  "arguments": {
    "starts_at": "2026-07-19T16:00:00+04:00",
    "ends_at": "2026-07-19T20:00:00+04:00",
    "timezone": "Asia/Dubai"
  }
}

After validation and execution, the application returns:

{
  "ok": true,
  "events": [
    {
      "starts_at": "2026-07-19T16:30:00+04:00",
      "ends_at": "2026-07-19T17:15:00+04:00",
      "busy": true
    },
    {
      "starts_at": "2026-07-19T18:00:00+04:00",
      "ends_at": "2026-07-19T18:30:00+04:00",
      "busy": true
    }
  ],
  "range_complete": true
}

Event titles are omitted because the scheduling decision only needs busy intervals. Data minimization reduces needless exposure.

The weather proposal covers the same date and trusted location. Its result says 4–5 p.m. is dry, 5–6 p.m. has a 70% chance of rain, 6–7 p.m. is dry, and 7–8 p.m. is dry. Now the model has evidence for both constraints.

Read

Join observations into candidates

The calendar reveals free intervals from 4:00–4:30, 5:15–6:00, 6:30–8:00. The forecast marks 4:00–5:00, 6:00–7:00, and 7:00–8:00 as dry. Their intersection yields multiple thirty-minute candidates: 4:00, 6:30, 7:00, and 7:30.

The assistant needs a tie-break rule. It could prefer the earliest matching slot if that policy is stated. It must not imply that 4:00 is uniquely correct. A truthful proposal is: “You are free and the forecast is dry from 4:00 to 4:30. I can add the walk then. Shall I create it?”

Notice that no write has occurred. The model used tool observations to form a proposal, but the application still owns execution. If the product policy permits low-risk calendar writes without confirmation, that should be an explicit policy choice, not an accidental consequence of the model’s wording.

Read

Confirm and execute the side effect

The user replies, “Yes, add it.” The application binds that confirmation to the proposed title, start, end, calendar, and conversation. It then issues a short-lived token. The model can propose:

{
  "name": "create_calendar_event",
  "arguments": {
    "title": "Walk",
    "starts_at": "2026-07-19T16:00:00+04:00",
    "ends_at": "2026-07-19T16:30:00+04:00",
    "timezone": "Asia/Dubai",
    "confirmation_token": "confirm_7f2a"
  }
}

Before execution, the application verifies that the token is authentic, unexpired, unused, owned by the current user, and bound to exactly those arguments. It rechecks calendar permissions and may recheck availability if enough time has passed.

The provider returns:

{
  "ok": true,
  "status": "created",
  "event_id": "evt_walk_309",
  "starts_at": "2026-07-19T16:00:00+04:00",
  "ends_at": "2026-07-19T16:30:00+04:00"
}

Only now should the final answer say, “Your walk was added tomorrow from 4:00 to 4:30 p.m.” The execution result, not the model’s proposal, licenses the claim.

Read

Handle branches without pretending

Real flows branch. If the weather service fails, the assistant can offer a calendar-only choice while clearly saying the forecast could not be checked. If the calendar read is incomplete, it should not claim the slot is free. If no dry free slot exists, it can report that constraint conflict and ask which requirement to relax.

If the create call reports conflict, the model should not repeat the same write automatically. It can refresh availability and propose another slot. If creation times out, the state may be unknown. The application should query by idempotency key or provider operation ID before retrying.

Parallel reads can reduce latency when their inputs are independent. Calendar and weather reads may run together after date, location, and timezone are known. The write cannot run in parallel because it depends on both observations, the selected slot, and any required confirmation.

Read

Review the full trace

A useful trace records the interpreted date and timezone, tools advertised, both read proposals, validation decisions, normalized observations, candidate-selection policy, confirmation evidence, write proposal, provider result, and final response. This allows a reviewer to distinguish a bad forecast from a scheduling error or an unauthorized write.

The trace should also show calls that were deliberately not made. For example, there was no need to expose event titles, invite attendees, or request location from free-form model arguments. Good multi-tool design is as much about limiting capability as chaining it.

Checking tutor…

Continue learning · glossary & guides