« Track Overview · Warmup · Hitchhiker's · Deep Dive · Principal Deep Dive · Core Contributor · Staff Notes
Phase 02 — Tool Calling & Structured Output: JSON Schema, Validation & the Repair Loop
Answers these JD lines: "tool calling" / "function calling" / "structured output" appears in every role in jd.md — it is the mechanism by which an agent does anything. Docker's "agent tool interfaces," Citi's "tool usage," Temporal's SDK tool contracts, and every "agents with tools" line resolve to this phase.
Why this phase exists
Phase 01 parsed the model's tool call out of free text with a regex. Production doesn't work that way: modern models emit native tool calls — structured JSON in a dedicated field — and the entire reliability of the agent depends on what your code does with that JSON on the trusted side of the boundary. Tool calling is the load-bearing mechanism of every agent, and it is where the trust boundary (Phase 00) is enforced in code: the model proposes a call, and your JSON-Schema validator decides whether to honor it.
The subtle, interview-critical truth this phase drills: a syntactically valid tool call can still be semantically wrong. Constrained/grammar decoding can guarantee the model emits well-formed JSON, but it cannot guarantee the arguments make sense. So you validate against a schema, and when validation fails you don't crash — you run a repair loop that feeds the error back and asks for a fix. "Constrained ≠ correct" is the phrase to remember.
Concept map
- Native tool calling: the model returns
{"name": ..., "arguments": {...}}; your app parses, validates, executes. (Upgrade of Phase 01's text format.) - JSON Schema as the contract:
type,required,properties,enum, ranges,items,additionalProperties— the machine-checkable spec of a tool's inputs (and of structured output). - Validate before execute: schema-check arguments before the function runs; a failure is a structured error, never a crash — the reliability lever from Phase 00.
- The repair loop: invalid output → feed errors back → re-emit → re-validate, bounded.
- JSON mode vs tool mode vs constrained decoding: three routes to structured output, with different guarantees (syntactic vs nothing about semantics).
- The double-encoded-arguments gotcha:
argumentsis often a JSON string inside the JSON. - Tool design: few well-scoped tools, clear names/descriptions, model-actionable errors.
The lab
| Lab | You build | Proves you understand |
|---|---|---|
| 01 — Tool-Calling Engine & Repair Loop | a from-scratch JSON-Schema validator, native-tool-call parsing (incl. double-encoded args), validate-before-execute dispatch, a bounded repair loop, and structured-output coercion | that tool calling is validation on the trusted side, and that valid JSON ≠ correct arguments |
Integrated scenario
An agent must issue a refund by calling issue_refund(order_id, amount_cents, reason). The
model, primed by a customer's message, emits amount_cents: "5000" (a string) and omits
reason. Without a schema, that string flows into your payment code and either crashes or —
worse — silently coerces. With this phase's engine, the validator rejects it with a precise
error ("amount_cents must be integer, got string; reason is required"), the repair loop
feeds that back, the model corrects it in one round, and only then does your code touch the
payment API. The schema is not paperwork — it is the authorization surface (forward-ref Phase
10) and the reliability gate.
Deliverables checklist
-
Lab 01 green under
LAB_MODULE=solution pytestand your ownlab.py. - You can write a JSON Schema for a tool and explain what each keyword guarantees.
- You can explain why constrained decoding gives syntactic but not semantic validity.
- You can describe the repair loop and when to stop retrying.
Key takeaways
- The tool schema is where the trust boundary is enforced in code — validate before you execute.
- Valid JSON is not correct JSON; validate semantics and repair, don't assume.
- Good tool design (few, well-named, well-described, with actionable errors) raises per-step reliability, which compounds (Phase 00).
- Everything downstream — MCP tools (P03), sandboxed execution (P09), authz (P13) — sits on top of a validated tool call.