TAI BUI
Back to curriculum
BuildPython

Tool Use and Function Calling

Single-turn function calling is solved. The hard part now is memory, dynamic decisions, and long tool chains, which is exactly where BFCL V4 (Patil et al., 2025) puts its weight: 40% agentic, 30% multi-turn, 10% live, 10% non-live, 10% hallucination. Toolformer (Schick et al., 2023) is where self-supervised tool use started.

TIME: ~60 minutesPREREQUISITES: Phase 14 · 01 (Agent Loop), Phase 13 · 01 (Function Calling Deep Dive)

Learning Objectives

  • Explain Toolformer's self-supervised training signal: keep tool annotations only when execution reduces next-token loss.
  • Name BFCL V4's five evaluation categories and what each measures.
  • Implement a stdlib tool registry with schema validation, argument coercion, and execution sandboxing.
  • Diagnose the four 2026 open problems: long-horizon tool chaining, dynamic decision-making, memory, and hallucination detection.

The Problem

Function calling means the model emits a structured request (a tool name plus arguments), your runtime validates and executes it, and the result goes back into the conversation. Early work asked whether a model could predict a correct call. Production asks something harder: can it chain tools across 40 steps, with memory and partial observability, recover when a tool fails, and never invent a tool that doesn't exist?

Toolformer set the baseline by showing that models can learn when to call tools with self-supervision. BFCL V4 defines the 2026 target. The distance between the two is where production agents live.

Warm-up0/3
1. What happens next in an agent loop after the model requests a tool call and your runtime executes it?Warm-up
2. Why do function-calling APIs ask you to give each tool a name, a description, and an argument spec?Warm-up
3. A web form sends the string "42" for a field your code treats as an integer. What is the sensible way to handle it?Warm-up
Check: The Problem0/1
1. What is function calling?Define

The Concept

Toolformer (Schick et al., NeurIPS 2023)

Toolformer is a training method where the model annotates its own pretraining corpus with candidate API calls and keeps only the ones that help. For each candidate, you execute the call. If including the result reduces loss on the next token, the annotation stays. Then you fine-tune on the filtered corpus.

The tools covered were a calculator, a QA system, search engines, a translator, and a calendar. The signal is purely whether the tool helps predict text, with no human labels.

The scale result matters: tool use emerges at scale. Smaller models get hurt by tool annotations, larger models gain. That's why 2026 frontier models have strong tool use baked in, while most 7B models need explicit tool-use fine-tuning before they're reliable.

Berkeley Function Calling Leaderboard V4 (Patil et al., ICML 2025)

BFCL is the benchmark that became the 2026 standard for evaluating function calling. V4 is weighted like this:

  • Agentic (40%): full agent trajectories covering memory, multi-turn, and dynamic decisions.
  • Multi-Turn (30%): interactive conversations with tool chains.
  • Live (10%): real prompts submitted by users, a harder distribution.
  • Non-Live (10%): synthetic test cases.
  • Hallucination (10%): detecting when no tool should be called.

V3 introduced state-based evaluation: after a tool sequence, check the API's actual state (is the file created?) instead of matching the AST of the calls. V4 added web search, memory, and format sensitivity categories.

The headline 2026 finding is that single-turn function calling is nearly solved. Failures concentrate in four places: memory (carrying context across turns), dynamic decision-making (choosing tools based on prior results), long-horizon chains (drift after 20+ steps), and hallucination detection (declining to call when no tool fits).

Tool schema

A tool schema is the description of a tool that you hand to the model: a name, a description, and a JSON Schema for the arguments. Every provider has one, and they differ in details but share the same shape:

name: string
description: string (what it does, when to use it)
input_schema: JSON Schema (properties, required, types, enums)

Anthropic uses input_schema directly. OpenAI uses function.parameters. Both accept JSON Schema. The description is load-bearing because the model reads it to pick the tool, and bad descriptions are the number one root cause of wrong-tool-picked failures.

Argument validation

Trust no tool call. Before executing, check four things:

  1. Type coercion. The model may return the string "5" where the schema says int. Coerce if the meaning is unambiguous, reject if not.
  2. Enum validation. If the schema says status in {"open", "closed"} and the model emits "in_progress", reject with a descriptive error.
  3. Required fields. A missing required field becomes an immediate error observation back to the model, not a crash.
  4. Format validation. Dates, emails, URLs: validate with concrete parsers, not regex.

Every failure should come back as a structured observation so the model can retry with the right shape.

Parallel tool calls

Modern providers let the model emit several tool calls in one assistant turn. The loop:

  1. The model emits 3 tool calls with distinct tool_use_ids.
  2. The runtime executes them, in parallel if they're independent.
  3. Each result goes back as a tool_result block correlated by tool_use_id.

Treat correlation IDs as load-bearing. Swap them and results get routed to the wrong calls.

Sandboxing

Tool execution is the sandbox boundary (Lesson 09 covers it in detail). The short version: every tool should declare its read/write surface, network access, timeout, and memory cap. A generic run_shell(cmd) is a red flag. A specific git_status() is much safer.

Check: The Concept0/23
1. What is Toolformer?Define
2. What is BFCL V4?Define
3. What does a tool schema contain?Define
4. What is a tool_use_id?Define
5. In BFCL V4, what does the hallucination category check?Define
6. What is argument coercion in a tool registry?Define
7. What does sandboxing a tool mean here?Define
8. Which of these is NOT one of the argument-validation checks the lesson recommends?Define
9. How do Anthropic and OpenAI name the arguments portion of a tool schema?Define
10. Which problem does the lesson NOT list among the open 2026 problems for function calling?Define
11. Why is a tool's description load-bearing?Explain
12. Your agent emits two parallel tool calls and the results come back out of order. What lets the runtime route each result correctly?Explain
13. Which class of failure does V3 state-based evaluation try to catch?Explain
14. What does Toolformer's scale result show about tool-use annotations?Explain
15. Why does Toolformer execute each candidate API call before deciding whether to keep it?Explain
16. How does BFCL V4's Live category differ from its Non-Live category?Explain
17. Why should a validation failure come back as a descriptive observation instead of a crash or a bare "Invalid input"?Explain
18. Why should coercion be limited to cases where the meaning is unambiguous?Explain
19. A teammate wants to keep a generic run_shell(cmd) tool in your agent. What is the lesson's objection?Analyze
20. A user asks "What is the capital of France?" and the agent only has a get_weather tool. It calls get_weather anyway with invented arguments. Which BFCL V4 category targets this failure?Analyze
21. Your agent keeps calling search_docs when it should call search_tickets, and both tools run fine. Where should you look first?Analyze
22. You must give an agent the ability to delete records. Which design follows the lesson's validation and sandboxing ideas?Design
23. You need to verify that your agent leaves a system in the correct state after a multi-step task, even when it reaches the goal with different calls. Which evaluation fits?Design

Build It

code/main.py implements a production-shaped tool registry:

  • A JSON Schema subset validator (stdlib only).
  • Tool registration with description, input schema, timeout, and executor.
  • Argument coercion and enum validation.
  • Parallel tool dispatch with correlation IDs.
  • Error observations as structured strings.

Run it:

python3 code/main.py

The trace shows a mini agent dispatching five calls in one turn. Three succeed (one after coercing the string "4" to an integer), and two are deliberately bad: an enum value outside the schema and a tool that doesn't exist. The registry rejects each with a descriptive error the model can act on.

Check: Build It0/7
1. The registry dispatches multiply with args {"a": "4", "b": 5}, where both a and b are schema type integer. What does it return?Apply
2. The trace dispatches five calls in one turn: u01 add(2,3), u02 multiply("4",5), u03 classify("in_progress"), u04 classify("open"), u05 subtract(1,2). Which come back as errors?Apply
3. In main.py, classify is registered with the enum ["open", "closed", "pending"]. What content does the call classify(status="in_progress") return?Apply
4. In main.py, add requires both a and b. What does dispatch return for add with args {"a": 7}?Apply
5. In main.ts, add takes integer arguments. What does dispatch return for add with args {a: "4.5", b: 1}?Apply
6. In either port, classify has one property, status. What does dispatch return for classify with {status: "closed", priority: "high"}?Apply
7. In main.py, a registered executor raises ZeroDivisionError("division by zero") on arguments that passed validation. What does dispatch do?Apply

Use It

Every provider (Anthropic, OpenAI, Gemini, Bedrock) has its own tool schema. If you need to support more than one, put a translation layer in front: the OpenAI Agents SDK, the Vercel AI SDK, or a LangChain tool adapter. BFCL is the reference benchmark, so if tool use is central to your product, run it against your agent before you ship.

Check: Use It0/1
1. Your product must work with both Anthropic and OpenAI models. Which design fits the lesson?Design

Ship It

outputs/skill-tool-registry.md generates a tool catalog, schema, and registry for a given task domain. It includes description-quality checks: does each tool's description tell the model when to use it?

Author's Note

When an agent picks the wrong tool, read the tool descriptions before you read the prompt. It's the cheapest fix and the most common cause, and people skip it because it feels too small to matter. Write each description as "what this does, and when to reach for it instead of the other tools," then reread the whole catalog as if you were the model seeing it cold.

The second habit is what the validator says when it rejects a call. "Invalid input" teaches the model nothing. "status must be one of open, closed; got in_progress" lets it fix the call on the next turn. Most of what looks like a model failing at tool use turns out to be a registry giving it nothing to learn from.

Exercises

  1. Add a "no-op" tool that lets the model explicitly refuse to use any other tool. Measure it on a BFCL-like hallucination test.
  2. Implement argument coercion for int-as-string and float-as-string. Where does coercion start to hide real bugs?
  3. Add a per-tool timeout and a circuit breaker (refuse the tool for 60s after 3 consecutive failures). What does this change about how the model recovers?
  4. Read the BFCL V4 description. Pick one category (say, "multi-turn"), run 10 example prompts through your agent, and report the pass rate.
  5. Port the stdlib validator to Pydantic or Zod. What did Pydantic or Zod catch that the toy missed?

Key Terms

TermWhat people sayWhat it actually means
Function calling"Tool use"Structured-output tool invocation with a validated schema
Toolformer"Self-supervised tool annotation"Schick 2023: keep tool calls whose results reduce next-token loss
BFCL"Berkeley Function Calling Leaderboard"2026 benchmark: 40% agentic, 30% multi-turn, 10% live, 10% non-live, 10% hallucination
Tool schema"Function signature for the model"name, description, JSON Schema of arguments
tool_use_id"Correlation ID"Ties a tool call to its result; essential for parallel dispatch
Hallucination detection"Know when not to call"V4 category: refuse to call when no tool fits
Argument coercion"String-to-int repair"Narrow fixes for predictable schema mismatches; reject if ambiguous
Sandboxing"Tool execution boundary"Per-tool read/write surface, network, timeout, memory cap

Further Reading

Code

Ships With