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.
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.
Continue learning · glossary & guides
- Did every call answer one bounded question?
- Was the write delayed until its required observations and confirmation existed?
- Could the final success claim be traced to a verified creation result?
- Glossary: tool allowlist · How-to: add tool allowlist · Lesson: Human in the loop