Design reliable LLM function-calling interfaces with schema validation, retry logic, and parallel tool execution.
Function calling is the mechanism by which an AI agent invokes a pre-defined, reusable computational unit—typically a service, script, or library function—to perform a task, retrieve data, or transform information. It matters when a system must delegate work to external tools, especially when the agent’s knowledge is limited to a model’s context window and the task requires access to data, APIs, or stateful processes not natively available in the model.
To call a function, the agent sends a request with a JSON object that specifies the function name and its arguments. The input must match the function’s schema exactly. A misnamed field or incorrect type causes silent failures.
{
"name": "search_user_profiles",
"arguments": {
"query": "active users in engineering department",
"limit": 10,
"sort_by": "last_login",
"filters": {
"department": "Engineering",
"status": "active"
}
}
}
The function is identified by a unique name string. The arguments object must contain all required fields and may include optional ones. The function signature—defined in a shared schema, often in OpenAPI or JSON Schema—dictates the expected structure. A common failure mode is passing sortBy instead of sort_by, where the function expects sort_by but receives sortBy, and the argument is ignored.
The function returns a result as a JSON object. The agent expects a result key in the response, and may optionally include error and metadata.
{
"result": [
{
"user_id": 123,
"name": "Alice Chen",
"last_login": "2023-10-05T12:34:56Z",
"department": "Engineering"
}
],
"error": null,
"metadata": {
"query_time_ms": 142,
"cache_hit": true,
"source": "database"
}
}
If the function fails, it returns an error object with code, message, and details.
{
"result": null,
"error": {
"code": "4001",
"message": "Invalid query parameter: 'status' must be one of ['active', 'inactive', 'pending']",
"details": {
"invalid_value": "activee",
"expected": ["active", "inactive", "pending"]
}
}
}
The agent must handle null results, missing result keys, and nested errors.
When one function’s output becomes the input of another, the agent orchestrates a data pipeline. The key challenge is aligning the output schema of one function with the input schema of the next.
A typical pattern is retrieving a dataset, transforming it, and then uploading it.
{
"name": "fetch_sales_report",
"arguments": {
"period": "Q3-2023",
"format": "csv"
}
}
The fetch_sales_report returns:
{
"result": {
"data": [
{ "product": "Widget A", "revenue": 15000, "units_sold": 300 },
{ "product": "Widget B", "revenue": 22000, "units_sold": 450 }
],
"total_revenue": 37000
}
}
The next function, generate_sales_summary, expects:
{
"name": "generate_sales_summary",
"arguments": {
"sales_data": [
{ "product": "Widget A", "revenue": 15000, "units_sold": 300 },
{ "product": "Widget B", "revenue": 22000, "units_sold": 450 }
],
"summary_type": "high-level"
}
}
The agent must extract data from the result object and flatten it into the expected sales_data array. If the output includes result.data but the next function expects sales_data at the top level, the agent must map the fields explicitly.
A common failure is misalignment in nested structures. For example, if generate_sales_summary expects sales_data[0].product.name but the input has sales_data[0].product as an object, the function fails silently—name is missing and the agent logs no error.
Functions often define optional arguments with default values. The agent must understand when to include optional arguments and how to override defaults.
Consider a function send_notification:
{
"name": "send_notification",
"arguments": {
"recipient": "[email protected]",
"message": "Your report is ready.",
"priority": "high",
"template_id": "welcome-email-v3"
}
}
The function’s schema defines:
recipient (required)message (required)priority (optional, default: "normal")template_id (optional, default: "default-template")metadata (optional, default: {})If the agent omits priority, the function uses "normal". If it sends priority: "urgent", the function uses that. If it sends priority: "low" but the function expects "high", "medium", "low", or "urgent", the agent must validate the string value.
The agent can override defaults explicitly.
{
"name": "send_notification",
"arguments": {
"recipient": "[email protected]",
"message": "Daily digest ready.",
"priority": "urgent",
"template_id": "digest-template-v2",
"metadata": {
"source": "ai-agent",
"context_id": "20231005-08"
}
}
}
When a function has many optional fields, the agent may use a config object to pass all optional values.
{
"name": "process_order",
"arguments": {
"order_id": 4567,
"config": {
"validate_payment": true,
"send_confirmation": false,
"apply_discount": true,
"discount_rate": 0.15,
"max_retries": 3
}
}
}
The function parses config and applies the settings. A failure occurs when the agent sends config.applyDiscount instead of config.apply_discount, or when discount_rate is a string "0.15" instead of a number.
For long-running functions, the agent must handle asynchronous execution. The function returns an id immediately, and the agent polls for completion.
The function analyze_video starts processing a video and returns:
{
"result": {
"job_id": "v12345",
"status": "pending",
"submitted_at": "2023-10-05T14:22:00Z"
}
}
The agent schedules a follow-up call to get_job_status with the job_id.
{
"name": "get_job_status",
"arguments": {
"job_id": "v12345"
}
}
The get_job_status function returns:
{
"result": {
"job_id": "v12345",
"status": "running",
"progress": 0.65,
"logs": [
"Video loaded",
"Feature extraction started",
"Face detection in progress"
],
"updated_at": "2023-10-05T14:23:30Z"
}
}
The agent polls every 5 seconds until status is "completed" or "failed". It may include a max_polls limit to avoid infinite waits.
A common failure mode is polling too frequently or too infrequently. Too frequent polling leads to unnecessary load; too infrequent polling increases latency. The agent must balance this based on expected job duration.
When a job fails, the response includes error and failure_details.
{
"result": null,
"error": {
"code": "VIDEO_PROCESSING_FAILED",
"message": "Video frame rate too high for model.",
"details": {
"expected_fps": 30,
"actual_fps": 60,
"model_max_fps": 45
}
}
}
The agent must handle the error and possibly retry the job or notify a human.
When a function call fails, the agent must decide how to recover. The pattern is to define a primary function and fallbacks.
The agent calls update_user_profile:
{
"name": "update_user_profile",
"arguments": {
"user_id": 1001,
"field_updates": {
"email": "[email protected]",
"preferences": { "theme": "dark", "notifications": true }
}
}
}
The function returns error if the user does not exist.
{
"result": null,
"error": {
"code": "USER_NOT_FOUND",
"message": "User with ID 1001 not found in database.",
"details": {
"requested_id": 1001,
"available_ids": [1000, 1002, 1003]
}
}
}
The agent can fall back to create_user_profile with the same field_updates.
{
"name": "create_user_profile",
"arguments": {
"user_id": 1001,
"email": "[email protected]",
"preferences": { "theme": "dark", "notifications": true }
}
}
The agent may also try multiple fallbacks in sequence, or use a retry policy.
The function may return metadata to guide future calls. For example, create_user_profile may return:
{
"result": {
"user_id": 1001,
"created_at": "2023-10-05T14:30:00Z"
},
"metadata": {
"initial_setup_required": true,
"onboarding_steps": [
"welcome_email_sent",
"profile_complete",
"preferences_set"
]
}
}
The agent uses metadata to determine the next steps.
When the agent calls a function multiple times with similar arguments, caching improves performance. The agent can store results keyed by function name and argument set.
A common pattern is batching multiple function calls into a single request.
Instead of calling get_user_stats once per user, the agent sends:
{
"name": "get_user_stats_batch",
"arguments": {
"user_ids": [1001, 1002, 1003],
"metrics": ["login_count", "avg_session_duration"]
}
}
The function returns:
{
"result": [
{
"user_id": 1001,
"metrics": {
"login_count": 42,
"avg_session_duration": 120
}
},
{
"user_id": 1002,
"metrics": {
"login_count": 18,
"avg_session_duration": 85
}
}
]
}
The agent can use this to reduce round trips and load on the function service.
Caching is effective when the same function call appears multiple times. The agent uses a hash of the arguments to generate a cache key. A mismatch in argument order or field name leads to cache misses.
For example, calling get_user_stats with:
{
"user_id": 1001,
"metrics": ["login_count", "avg_session_duration"]
}
and later with:
{
"user_id": 1001,
"metrics": [ "avg_session_duration", "login_count" ]
}
The function sees different metrics arrays, even though the content is the same. The agent must normalize the structure—sort arrays, order keys alphabetically, or use a canonical JSON representation.
A failure mode is caching with inconsistent time-to-live (TTL) values. A function updates a user’s stats every 15 minutes, but the agent caches the result for 5 minutes. The agent returns stale data, and the user sees outdated values.
error but the agent does not handle it. The agent must validate the input schema before calling.int for limit, but the agent sends string "10". The function may fail silently or coerce the type, but the agent must document the expected types.job_id-based polling or fallbacks.error, the agent may wrap it in a new error object, losing the original structure.snake_case for arguments; PascalCase for function names.name, arguments, result, error, duration, and metadata.version field to the function call.metadata for context: Include source, context_id, timestamp, caller, and trace_id.Function calling is not just a mechanism—it is the foundation of agent-driven systems. Mastering it means building agents that are precise, resilient, and adaptive.
This page was rewritten on 17 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy