#大模型#AI Agent

Function Calling Deep Dive: From Tool Invocation to Reliable Execution

Function Calling is how an Agent affects the real world, but several engineering gates separate “the model wants to call a tool” from reliable completion. This article explains the mechanism, parallel and multi-round calls, argument validation, error recovery, and its relationship with MCP, taking function calling from working to production-ready.

Key Points

  • Topic Focus: 大模型、AI Agent
  • Suitable for: indie hackers, full-stack engineers, AI application developers
  • Core value: quickly understand background, practical paths, common pitfalls, and engineering advice
Author @admin·Published July 26, 2026·Updated July 26, 2026

Function Calling (tool use) is the gateway that turns an LLM from something that can chat into something that can act. Instead of producing only text, the model can declare, “I want to call this function with these arguments.” Your code executes it and feeds the result back to the model. The entire Agent ecosystem is built on this mechanism.

But several engineering gates separate “the model wants to call a tool” from “the operation completed reliably.” This article explains each of them.

1. How It Works: One Complete Tool Call

A complete function-calling round trip looks like this:

text
1. Send the tool definitions + the user’s question to the model
2. The model decides to invoke a tool → returns tool_call: {name, arguments}
3. Your code executes the function and obtains the result
4. Feed the result back to the model as a tool message
5. The model continues reasoning from the result (either answering or calling another tool)

The code looks like this:

ts
const response = await client.messages.create({
  model, system, messages, tools,
});

// The model requests a tool call
if (response.stop_reason === "tool_use") {
  const toolCall = response.content.find(c => c.type === "tool_use");
  const result = await dispatch(toolCall.name, toolCall.input);  // Your executor
  messages.push({ role: "assistant", content: response.content });
  messages.push({ role: "user", content: [{ type: "tool_result",
    tool_use_id: toolCall.id, content: JSON.stringify(result) }] });
  // Second round: ask the model again with the result
  const final = await client.messages.create({ model, system, messages, tools });
}

The key insight is that the model only “declares” the call; your code performs the actual execution. That means security, authorization, and side effects are all your responsibility. This is the core of productionizing function calling and a critical battleground in prompt injection defense.

2. Parallel and Multi-Round Calls

Modern models can return multiple tool_call entries in one response for parallel execution. For example, if the user asks, “What is the weather in Beijing and Shanghai?”, the model can return two get_weather calls at once. Your executor runs them in parallel and feeds both results back together. This is much faster than checking Beijing first and Shanghai afterward.

Multi-round calls are different: the model calls A → examines the result → decides to call B → examines that result → provides an answer. This is the essential Agent loop: it autonomously decides what to invoke next until the task is complete.

Engineering considerations:

  • Wait for all parallel calls to finish and feed their results back together; do not feed back only a subset.
  • Multi-round loops must have limits on maximum rounds, tokens, and elapsed time. Otherwise, the model may enter a costly “call → failure → call again” loop.

3. Four Gates to Reliable Execution

The model saying “call transfer_money(from, to, amount)” does not mean you should blindly execute it. Four gates stand between declaration and execution:

1. Argument validation. The model may supply invalid arguments, such as a negative amount, a nonexistent account, or a malformed email address. Validate them against a schema with a validator such as zod before execution. If validation fails, feed the error back to the model so it can correct the arguments instead of returning the error directly to the user.

ts
const schema = z.object({ from: z.string(), to: z.string(), amount: z.number().positive() });
const parsed = schema.safeParse(args);
if (!parsed.success) {
  return { error: parsed.error.message };  // Feed it back so the model can correct the arguments and retry
}

2. Permissions and authorization. The model’s decision to invoke a tool ≠ authorization. Before execution, verify whether the current user may perform this operation on the resource and whether write operations require human confirmation. “Approved once” does not mean permanently authorized; changed arguments require renewed confirmation.

3. Side effects and idempotency. Tool calls can fail and may be retried. If create_order is not idempotent, a retry creates two orders. Design tools to be idempotent whenever possible by using an idempotency key, or distinguish between retryable and non-retryable operations.

4. Error feedback. When a tool fails, feed a readable error such as “insufficient balance” or “permission denied” back to the model instead of throwing an exception that terminates the flow. An Agent can often choose another approach based on the error, which makes it more flexible than a hard-coded workflow. Only genuine system errors should fall back to human intervention or rules.

4. Tool Definition Quality Determines Everything

Whether the model selects a tool and invokes it correctly depends about 90% on the quality of the tool definition:

  • The description is written for the model. Clearly explain when to use the tool, when not to use it and which alternative to choose, and how to fill in its arguments. Vague descriptions are the leading cause of Agents going off course.
  • The argument schema must be strict. Clearly mark required fields, list every enum value, and add descriptions. This is the model’s only basis for filling in arguments.
  • Use the right tool granularity. If a tool is too broad, such as one manage_users tool that does everything, the model will struggle to supply the correct arguments. If tools are too narrow, such as get_user_id → get_user_name → … requiring ten calls, execution becomes inefficient. Each tool should perform one clearly defined task.

Practical experience: time invested in tool definitions delivers far greater returns than tweaking prompts. Clear tool descriptions and strict schemas make model behavior noticeably more reliable.

5. The Relationship Between Function Calling and MCP

Many people confuse the two. In simple terms:

  • Function Calling is a model API capability that lets the model declare function calls.
  • MCP is a protocol standard for exposing capabilities, making toolsets reusable across clients.

Under the hood, MCP often relies on function calling. Tools exposed by an MCP Server are converted by clients such as Claude Code and Cursor into function definitions for the model, which then invokes them through function calling as usual. MCP is the distribution and standardization layer for tools, while function calling is the mechanism by which models invoke tools. They complement each other rather than compete.

Once you understand this relationship, the choice becomes clear: for a small custom Agent, direct function calling is enough. If you want the entire ecosystem to reuse your tools, package them as an MCP Server.

Summary

Function Calling is an Agent’s execution engine, but engineering separates “it works” from “it is reliable”:

  • Mechanism: the model declares → your code executes → the result is fed back.
  • Parallel/multi-round calls: parallel results must be fed back together, while multi-round loops require limits.
  • Four gates: argument validation, permissions and authorization, idempotent side effects, and error feedback.
  • Definition quality: descriptions + schemas determine tool-call accuracy.
  • Relationship with MCP: function calling is the mechanism; MCP is the distribution standard.

Implement these principles rigorously, and your Agent can move from “working once or twice in a demo” to “executing reliably ten million times in production.” Remember the central rule: the model is responsible only for declaring the call; you are responsible for everything about its execution. That is why function calling is both the source of an Agent’s power and its greatest engineering responsibility.

Related

Related Content