Tool calling lets an LLM application request actions such as looking up an account, querying a database, or creating a support ticket, while your application remains responsible for execution. This tool calling tutorial provides a reusable checklist for designing schemas, validating arguments, enforcing permissions, handling retries, preventing duplicate actions, and returning clear results. Use it when building a new integration, adding an AI agent tool, migrating providers, or reviewing production behavior.
Overview
LLM function calling is best treated as a controlled handoff, not as permission for a model to run arbitrary code. The model selects from tools that you describe, proposes structured arguments, and may receive a result to use in its next response. Your server or client must still validate the request, decide whether the action is allowed, execute it safely, and report success or failure.
A dependable flow usually looks like this:
- Define a small tool with a precise purpose.
- Publish a strict function calling schema.
- Ask the model for a response that may include a tool call.
- Validate the tool name and every argument.
- Apply authentication, authorization, confirmation, and business rules.
- Execute the action with timeouts and bounded retries.
- Record an idempotency key and the execution outcome.
- Return a minimal, useful result to the model.
- Let the model continue or provide a final response.
This separation is central to secure tool execution. A system prompt can explain behavior, but it should not be the only control protecting an external action. Use server-side checks for access, input constraints, rate limits, and irreversible operations. For related guidance on dependable model behavior, see the LLM application reliability checklist and structured output prompts guide.
Checklist by scenario
When designing a new tool
- Give it one clear job. Prefer
get_order_statusover a broadmanage_orderstool that combines reading, editing, and deletion. - Use a specific name and description. State what the tool does, what it does not do, and when it should be used.
- Make arguments explicit. Use typed fields, enumerated values, maximum lengths, bounded numbers, and required fields wherever the provider schema supports them.
- Separate identifiers from display text. A customer name is not a safe substitute for a verified account ID.
- Return stable results. Define a compact result shape that includes status, relevant data, and an actionable error category.
- Classify the action. Mark each tool as read-only, reversible write, irreversible write, or administrative. This classification should influence confirmation and permission requirements.
A tool schema is an interface contract between the model and your application. Keep it versioned alongside the dispatcher and tests. If your application already uses prompt templates or system instructions, document tool-selection rules there, but enforce them in code as well.
When an action changes data
- Authenticate the user or service identity before dispatch.
- Authorize the exact resource and operation, not merely access to the general feature.
- Require confirmation for purchases, deletion, publication, messages, permission changes, or other consequential actions.
- Use an idempotency key so a timeout or repeated model request does not create duplicate effects.
- Show the user the material details before confirmation: target, scope, amount or quantity, and intended change.
- Record who requested the action, which tool version ran, and whether it succeeded.
When a tool calls another service
- Set a connection timeout and an overall execution deadline.
- Retry only failures that are safe to retry, and cap the number of attempts.
- Do not send secrets, full records, or unnecessary personal data in tool arguments.
- Normalize provider errors into categories such as validation failure, permission failure, not found, rate limit, timeout, and unavailable service.
- Return enough context for the model to explain the outcome without exposing internal stack traces or credentials.
Choosing an execution pattern
| Pattern | Typical use | Strengths | Risks to control |
|---|---|---|---|
| Client-side execution | Browser or desktop actions that require local context | Can access local state and provide immediate user confirmation | Never trust client-only authorization; protect tokens and validate again on the server |
| Server-side execution | Databases, private APIs, account operations, and scheduled workflows | Centralized secrets, policy checks, logging, and consistent validation | Requires careful isolation, access control, timeouts, and data minimization |
| Human-approved execution | High-impact or irreversible operations | Creates an explicit review point before side effects | Avoid ambiguous approval states and ensure an approval cannot be replayed |
What to double-check
Schema and provider compatibility
Before deployment, compare your schema with the current API or SDK documentation for the provider you use. Tool-calling formats, supported JSON Schema features, response fields, and streaming behavior can differ or change over time. Do not assume that a schema accepted by one provider will be interpreted identically by another. Pin compatible SDK versions where appropriate, write an adapter around provider-specific request and response formats, and test the actual serialized payload.
Check whether the model can return multiple tool calls in one response, whether calls arrive incrementally during streaming, how malformed arguments are represented, and how tool results must be appended to the conversation. These details affect dispatch logic and replay protection.
Validation and permissions
Validate twice when the risk justifies it: first at the transport boundary and again in the tool implementation. Reject unknown tool names, missing required fields, unexpected fields when strictness is important, invalid enum values, oversized strings, malformed IDs, and out-of-range quantities. Then verify that the authenticated principal can perform the requested operation on the requested resource.
Keep tool arguments separate from executable code. Never construct a shell command, SQL statement, URL, or template by directly interpolating model-provided text. Use parameterized queries, allowlists, dedicated SDK methods, and restricted service accounts. For prompt and model selection considerations, the LLM selection guide can help frame capability and reliability trade-offs without treating tool use as a model-only feature.
Retries, timeouts, and duplicate execution
A model may repeat a call after receiving an unclear result, and your application may retry after a network timeout even though the remote service completed the operation. Design for this possibility. Generate a request or idempotency key before the first side effect, persist its status, and make repeated requests return the original outcome when supported.
Use different policies for read and write tools. A read can often tolerate a bounded retry, while a write should require an idempotent operation or an explicit reconciliation step. If the result is unknown, report that state rather than claiming failure and automatically performing the action again.
Observability and testing
Log tool selection, schema validation outcome, authorization outcome, latency, retry count, and a redacted result. Avoid logging raw secrets or sensitive arguments. Add tests for malformed JSON, wrong resource ownership, expired credentials, duplicate requests, provider timeouts, partial failures, and prompt injection inside retrieved content.
Test the full loop with realistic conversations, not only isolated schema validation. Include cases where the model should answer without a tool, ask for missing information, decline an unauthorized action, or request confirmation. The prompt debugging guide offers a useful companion process for separating prompt problems from application-control problems.
Common mistakes
- Making one tool do everything: Broad tools produce ambiguous arguments and make authorization difficult. Split capabilities by operation and risk.
- Trusting the model to enforce policy: Instructions can guide tool choice, but code must enforce identity, ownership, limits, and approval.
- Returning raw backend errors: Internal URLs, SQL details, stack traces, and secret-bearing messages do not belong in model-visible results. Map them to safe categories.
- Retrying every failure: Retries can amplify outages and duplicate writes. Use bounded, operation-specific policies.
- Ignoring stale context: A model may act on an old price, status, or permission. Recheck critical state immediately before execution.
- Skipping confirmation for convenience: If an action has meaningful consequences, make the approval step explicit and auditable.
- Assuming structured arguments are safe: Valid JSON can still contain an unauthorized account ID, dangerous URL, or excessive quantity. Syntax validation is not business validation.
- Failing silently: Every tool result should communicate success, a safe failure category, or an unknown outcome so the model and user can respond appropriately.
When to revisit
Revisit this checklist before each seasonal planning cycle, major release, provider migration, or workflow change. It is especially important when adding a write-capable tool, changing permissions, introducing streaming, enabling multi-tool orchestration, connecting a new external API, or changing the model used for tool selection.
At each review, inspect the current provider schema requirements, SDK behavior, supported structured-output features, authentication flow, and security guidance. Re-run tests for malformed arguments, duplicate execution, confirmation bypasses, timeout handling, and unauthorized resource access. Review logs for unexplained retries, frequent validation failures, tools that are selected when a normal answer would suffice, and results that leave the model uncertain.
For a practical release gate, confirm that you can answer yes to these questions:
- Does every tool have a narrow purpose and versioned schema?
- Are all arguments validated independently of the model?
- Are permissions checked against the current user and resource?
- Are consequential actions confirmed and idempotent?
- Are timeouts, retries, and unknown outcomes explicit?
- Are logs useful without exposing sensitive data?
- Can a failed tool call be explained without pretending it succeeded?
Tool calling becomes dependable when the model is treated as a planner and your application remains the authority over execution. Keep the interface small, make every side effect deliberate, and update the checklist whenever the tools, workflows, or provider behavior change.