Track
Schema · Validate · Retry · Normalize
An agent is only as useful as the tools it can call. Without tools, an LLM is just a text generator — it can't look up the weather, run Python, query a database, or send an email. Tools are the bridge between the LLM's reasoning and the real world.
But giving an LLM access to arbitrary functions is dangerous. You need a contract: a schema that tells the LLM what parameters a tool expects, validation that catches bad calls before they execute, and retry logic that handles failures gracefully.
Every tool has a shape: a name, a description, a list of parameters with types, and rules about which parameters are required. This shape is what the LLM sees when deciding which tool to call and how to fill in the arguments.
The LLM reads this schema and produces structured output that matches it. Your job is to parse that output and dispatch it safely.
Tools fail. Networks drop, APIs rate-limit, timeouts happen. A well-built tool wrapper retries with exponential backoff rather than crashing the agent on the first error.
On failure, wait base * 2^attempt seconds (with jitter), then retry. If all attempts fail, re-raise the last exception. The jitter prevents multiple agents from retrying in lockstep — a pattern called 'thundering herd' avoidance.
Concrete Example
import inspect
from typing import get_type_hints
TYPE_MAP = {str: "string", int: "integer",
float: "number", bool: "boolean"}
def to_tool_schema(fn):
sig = inspect.signature(fn)
hints = get_type_hints(fn)
properties = {}
required = []
for name, param in sig.parameters.items():
typ = hints.get(name, str)
properties[name] = {"type": TYPE_MAP.get(typ, "string")}
if param.default is inspect.Parameter.empty:
required.append(name)
return {
"name": fn.__name__,
"description": fn.__doc__ or "",
"parameters": {
"type": "object",
"properties": properties,
"required": required,
},
}This takes any annotated Python function and produces an OpenAI-compatible JSON Schema. Parameters without defaults become required; Python types are mapped to JSON Schema types. The function's __name__ and __doc__ populate the name and description fields automatically.
Auto-derive tool contracts from function signatures so the LLM knows how to call them.
Map Python types to JSON Schema types; mark parameters without defaults as required.
Check arguments against the schema before calling the function.
Exponential wait times plus jitter make tool calls resilient to transient failures.
Standardize tool outputs so downstream logging sees a consistent format.
6 problems. Sign in to start solving.
Sign in to open a workspace and solve these problems.