Frontend Labs
⋯

Chapter 48 — Tools, structured output, and agents

Structured output: making the model return parseable data

Asking nicely for JSON works ~90–98% of the time — which is a failure every 20 requests. Three levels of reliability:

Level 1 — Ask and validate.

prompt = 'Extract the fields. Return ONLY JSON: {"name": str, "amount": float}'
# then json.loads() in a try/except, and retry on failure

Level 2 — JSON mode. A provider flag that forces syntactically valid JSON (though not necessarily your schema).

Level 3 — Schema-constrained decoding. At each step, the sampler is only allowed to pick tokens that keep the output valid against your schema. For the supported schema, invalid output becomes impossible at the decoder level, not merely unlikely — assuming the schema and constrained-decoding implementation are correct.

from pydantic import BaseModel

class Expense(BaseModel):
    item: str
    amount_eur: float
    approved: bool
    reason: str

# Supported natively by many providers (structured outputs / response_format)
# and by local servers via libraries like Outlines, XGrammar, or llama.cpp grammars.

Tip: if you need an explanation, ask for a short user-visible field like evidence or rationale_summary, not hidden chain-of-thought. Constrained decoding forces field order, so put fields in the order the answer should be assembled: evidence first, then the final structured values.

Tools (function calling)

Give the model a menu of functions. It decides when to call one and with what arguments; your code executes it and returns the result.

tools = [{
    "type": "function",
    "function": {
        "name": "get_holiday_balance",
        "description": "Get an employee's remaining holiday days for this year.",
        "parameters": {
            "type": "object",
            "properties": {"employee_id": {"type": "string"}},
            "required": ["employee_id"],
        },
    },
}]

# The loop:
#  1. send messages + tools
#  2. if the model returns a tool call -> run YOUR function
#  3. append the result as a "tool" message
#  4. send again -> the model writes the final answer

This is how you fix the model's weaknesses:

Weakness Tool that fixes it
Arithmetic errors a calculator / code execution
Knowledge cutoff web search
Doesn't know your data database query, internal API
Hallucinated specifics any system of record
Can't act in the world send email, create a ticket, call an API

The mental model from Part 2 returns: the LLM handles language and decisions; deterministic code handles facts and actions. Neither half is sufficient alone.

Agents: models that loop

An agent is an LLM in a loop with tools and a goal:

   goal
     |
     v
   +-------------------------------------+
   |  1. LLM decides the next action     |
   |  2. your code executes the tool     |
   |  3. result is appended to context   |<---+
   |  4. repeat until done or budget out |    |
   +-------------------------------------+----+
     |
     v
   answer

Agents are powerful and fragile. The safety rules are non-negotiable:

  1. Least privilege. Read-only by default. Give the minimum set of tools.
  2. Human approval for consequential actions — sending, paying, deleting, deploying. This is the single most effective control.
  3. Hard limits. Max iterations, max tokens, max spend, timeouts. Always.
  4. Sandbox any code execution. No secrets, no network unless allowlisted, ephemeral filesystem.
  5. Validate every tool argument in your code before executing. Never trust model-generated paths, URLs, recipients, or SQL.
  6. Log every tool call and alert on anomalies.

Practice (30 min)

Extend your RAG app from Chapter 47 with one tool — for example get_holiday_balance(employee_id) returning a hardcoded number. Then ask "How many holiday days do I have left, and what's the policy on carrying them over?" — a question requiring both the tool (personal data) and RAG (policy). Watch the model orchestrate both.

Check yourself

  1. Why is schema-constrained decoding stronger than "please return JSON"?
  2. Name three weaknesses that tools fix.
  3. List three safety rules for agents.

Further reading

  • Docs: the function-calling / tool-use guides from OpenAI, Anthropic, and Google — read at least one end to end.
  • Docs: modelcontextprotocol.io — MCP, an open standard for connecting models to tools and data sources.
  • Library: github.com/dottxt-ai/outlines — structured generation with guaranteed-valid output.
  • Article: "Building Effective Agents" (Anthropic engineering blog) — a refreshingly practical, hype-free guide to when agents help and when a simple chain is better.

Generated from real-life-ai-example-v1.md · 8 Oct 2026 16:36