Production-grade LLM tool calling requires more than asking a model to use a function. This guide provides a reusable workflow for defining tools, validating arguments, handling retries and timeouts, controlling permissions, and routing risky actions to human approval before an AI application changes data or triggers an external API.
Overview
LLM tool calling, also called function calling or tool use, lets a model return a structured request for an application function. The application—not the model—then decides whether to execute that function, with which credentials, and under what conditions. The result is sent back to the model so it can continue the conversation or produce a final response.
A safe implementation separates language understanding from execution. Treat the model's output as an untrusted proposal rather than an authorized command. Your application should validate the proposed tool name and arguments, enforce identity and permission rules, apply timeouts and retry limits, record the decision, and return a controlled result.
A practical flow looks like this:
- Define a small tool with a clear purpose and a strict input schema.
- Present only the tools relevant to the current task and user.
- Receive the model's tool request and parse it defensively.
- Validate types, formats, ranges, ownership, and business rules.
- Check authorization separately from schema validation.
- Ask for approval when the operation is consequential, irreversible, or outside a pre-approved policy.
- Execute the function with least-privilege credentials and bounded time.
- Return a minimal, structured result and log the complete decision path.
Tool calling also belongs in a broader AI development process. Use an evaluation set to test normal requests, ambiguous requests, malformed arguments, unauthorized actions, and prompt-injection attempts. The LLM evaluation guide can help you organize those cases. If tools are used inside a retrieval-augmented generation workflow, keep retrieval, reasoning, and execution as separate stages; the RAG tutorial provides useful architectural context.
Checklist by scenario
Read-only tools
Examples include searching a knowledge base, checking order status, retrieving a calendar entry, or calculating a value. These tools are usually lower risk, but they can still expose private data or consume resources.
- Limit results to data the signed-in user is allowed to see.
- Validate filters, identifiers, pagination, and date ranges.
- Set result-size and execution-time limits.
- Remove secrets and unnecessary personal data from the tool result.
- Return an explicit “no result” state instead of encouraging the model to guess.
Data-changing tools
Examples include updating a ticket, editing a record, sending a message, or changing a configuration. These functions need stronger controls because a valid request can still produce an unwanted outcome.
- Use a narrowly named function such as
update_ticket_statusrather than a broadmodify_recordfunction. - Require the target identifier and the exact fields to change.
- Reject unknown fields and unexpected state transitions.
- Check that the resource belongs to the current user or authorized workspace.
- Prefer idempotency keys for operations that may be retried.
- Show a confirmation step for messages, deletions, purchases, and other consequential actions.
External API tools
For third-party integrations, define the boundary before writing the prompt. The model should never receive reusable credentials or decide which account, tenant, or permission scope to use.
- Resolve credentials on the server from the authenticated session.
- Allowlist hosts, endpoints, HTTP methods, and permitted parameters.
- Normalize provider errors into stable application-level error types.
- Use a timeout and a maximum response size.
- Decide whether a failed call is safe to retry; do not retry every error.
High-impact or irreversible tools
Deletion, financial transactions, access changes, production deployments, and messages sent to external audiences should normally use explicit approval. A simple approval record can contain:
Approval request
Action: [plain-language description]
Target: [resource and account]
Changes: [exact fields or amount]
Reason: [user request or workflow step]
Risk: [reversible / difficult to reverse / irreversible]
Approver: [authenticated user or assigned reviewer]
Expires: [short approval window]
Approval should be tied to the exact arguments that will execute. Do not approve a general intention and then let the model substitute a different target later.
What to double-check
Schema design
Keep each schema precise and understandable. Mark required fields, constrain enumerated values, define formats for dates and identifiers, and provide descriptions for fields whose meaning is not obvious. Avoid accepting a free-form blob when a structured object can express the operation safely.
For example, a ticket update tool might use a contract like this:
{
"name": "update_ticket_status",
"description": "Change the status of one support ticket",
"parameters": {
"type": "object",
"additionalProperties": false,
"required": ["ticket_id", "new_status"],
"properties": {
"ticket_id": {"type": "string", "pattern": "^T-[0-9]+$"},
"new_status": {"type": "string", "enum": ["open", "pending", "resolved"]}
}
}
}
Schema keywords and strictness options differ across model platforms and SDK versions. Verify the current provider documentation, test unsupported features, and keep application-side validation even when the platform advertises strict structured output.
Validation and authorization
Use two separate checks. Schema validation asks whether the arguments have the correct shape. Authorization asks whether this user, service, or workflow may perform the requested action on this target. Both must pass.
- Confirm the tool name is in an application-side allowlist.
- Parse JSON with a bounded input size and handle invalid syntax.
- Validate identifiers against the current tenant or workspace.
- Apply business rules, such as allowed status transitions or maximum amounts.
- Reject missing context instead of inferring sensitive values.
- Re-check permissions immediately before execution.
Retries and timeouts
| Condition | Typical handling | Safety check |
|---|---|---|
| Temporary network failure | Bounded retry with backoff | Use an idempotency key or confirm no action completed |
| Rate limit | Respect the returned delay when available | Cap total waiting time and surface a clear status |
| Invalid arguments | Do not retry unchanged arguments | Return a validation error and request correction |
| Authentication or permission failure | Stop execution | Do not ask the model to work around access controls |
| Provider or service error | Retry only when documented as transient | Avoid duplicate side effects |
Set separate limits for the tool request, external API call, total workflow, and number of model-tool turns. A model can otherwise continue a loop that is technically valid but operationally wasteful.
Common mistakes
- Trusting the schema as authorization. A correctly shaped request can still target another user's record. Perform resource-level permission checks in application code.
- Giving the model overly broad tools. Replace generic database, shell, or HTTP tools with narrowly scoped business functions and explicit allowlists.
- Retrying side effects automatically. A timeout does not prove that an update failed. Use idempotency, status lookup, or a reconciliation step before repeating it.
- Hiding tool errors. Return structured error categories so the model can explain what happened without inventing success.
- Putting secrets in prompts or tool arguments. Keep credentials in the server-side integration layer and redact them from logs.
- Skipping adversarial tests. Include instructions inside retrieved documents, tool results, and user messages that attempt to change the workflow. The prompt injection prevention checklist offers a focused review path.
- Changing a function without regression tests. When a schema changes, test old conversations, malformed inputs, permission boundaries, and approval behavior before deployment.
Good system instructions can clarify when tools are appropriate, but they are not a replacement for execution controls. For guidance on separating behavioral instructions from application safeguards, see how to write system prompts for reliable AI assistants.
When to revisit
Review this checklist before adding a tool, changing an API contract, modifying a permission model, switching model providers, or introducing a new workflow. Provider-specific schema behavior, SDK interfaces, supported structured-output features, and error formats can change, so verify those details against current documentation rather than copying an older example unchanged.
Revisit the implementation during seasonal planning cycles or whenever usage patterns change. A tool that was read-only may become data-changing; a low-volume integration may need tighter rate and cost controls; and a new tenant or role may expose an authorization gap. Review logs for repeated validation failures, unnecessary retries, approval bypass attempts, and tool calls that produce no useful result.
Use this final pre-release checklist:
- List every tool, its exact side effect, required permissions, and data exposure.
- Test valid, missing, extra, malformed, out-of-range, and cross-tenant arguments.
- Confirm timeouts, retry rules, idempotency behavior, and loop limits.
- Run approval tests using the exact arguments that will execute.
- Verify that logs contain enough context for debugging but exclude secrets and unnecessary sensitive data.
- Record the model, prompt, schema, tool version, and execution outcome needed for a later investigation.
- Schedule the next review when the workflow, provider, API, or permission model changes.
Safe AI function calling is an application architecture problem as much as a prompt engineering problem. Keep the model useful but bounded, keep execution deterministic where possible, and make every consequential action observable and reviewable.