Tool use stack: schema -> validation -> dispatch -> structured observation
tool catalog (as seen by the model)
add(a int, b int) -- Add two integers a and b. Use for any integer addition.
multiply(a int, b int) -- Multiply two integers. Prefer multiplication over looped addition.
argument validation
type coercion
"5" -> 5 if unambiguous
enum check
status in {open,closed,pending}
required fields
missing -> structured error observation
range / min / max
numeric bounds checked
sandbox policy
per-tool timeout, fs surface, network
never raise to the loop -- every failure
becomes an observation the model reads
dispatch
parallel tool calls
assistant turn emits N tool_use blocks
each has distinct tool_use_id
runtime executes independents in parallel
results correlated back by tool_use_id
swap the id and routing goes wrong
Anthropic, OpenAI, Bedrock all require it
execution
exceptions caught
timeouts enforced
results stringified with shape hints
structured JSON preferred over prose
circuit breaker on repeat failures
span emitted (OTel GenAI tool_call)
audit trail for post-mortems
BFCL V4 composition
Agentic 40%
Multi-turn 30%
Live 10%
Non-Live 10%
Hallucination 10%
single-turn solved; memory, dynamic
decisions, long chains remain open
gorilla.cs.berkeley.edu/leaderboard.html