« 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: arguments is often a JSON string inside the JSON.
  • Tool design: few well-scoped tools, clear names/descriptions, model-actionable errors.

The lab

LabYou buildProves you understand
01 — Tool-Calling Engine & Repair Loopa from-scratch JSON-Schema validator, native-tool-call parsing (incl. double-encoded args), validate-before-execute dispatch, a bounded repair loop, and structured-output coercionthat 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 pytest and your own lab.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.