Tool Use in AI Agents: Why Function Calling Changed Everything
By Diesel
ai-agentstool-usefunction-calling
Before function calling, LLMs could only talk about doing things. They could describe how to query a database, explain how to call an API, write the code that would make the HTTP request. But they couldn't actually do any of it. They were experts who couldn't touch the keyboard.
Function calling changed that in a way that's hard to overstate. The moment LLMs could invoke external tools, they went from impressive toys to legitimate components of production systems. Everything in the modern agent stack builds on this single capability.
## What Function Calling Actually Is
At its simplest: the model outputs a structured request to call a specific function with specific arguments, instead of (or in addition to) generating text. The runtime executes that function, feeds the result back to the model, and the model continues.
```json
{
"function": "search_database",
"arguments": {
"query": "customer orders last 30 days",
"limit": 10
}
}
```
That's it. The model says "I want to call this function with these arguments." Your code actually calls it. You send the result back. The model incorporates the result and decides what to do next.
It sounds trivial. It's not. This is the bridge between "AI that talks" and "AI that does."
## Why This Was the Inflection Point
Before tools, if you wanted an LLM to answer "How many orders did we process last month?" you had two options. Pre-load all the data into the context (expensive, often impossible), or have the LLM generate a query that a human would then run (slow, defeats the purpose).
With tools, the agent can call `query_database` itself, get the answer, and respond. In real time. Without a human in the loop for the data retrieval step.
Scale that up. An agent that can search documents, query databases, call APIs, read files, execute code, and send notifications isn't just answering questions. It's performing work. It's the difference between a consultant who gives you a PDF of recommendations and one who actually implements them.
## Designing Good Tools
The quality of your agent is directly proportional to the quality of its tools. I've seen this pattern repeatedly: teams spend weeks fine-tuning prompts when the real problem is that their tools are garbage.
### Clear, Specific Names
The model picks tools based on their names and descriptions. `process_data` tells the model nothing. `search_customer_orders_by_date_range` tells it exactly when to use this tool.
Bad tool names are the number one cause of agents picking the wrong tool. I'm not exaggerating. Before you debug your prompt, check your tool names.
### Minimal, Well-Typed Parameters
Every parameter the model has to fill in is a chance for it to get something wrong. If a tool takes 12 parameters, the model will hallucinate at least one of them eventually.
Design tools with the minimum required parameters. Use sensible defaults for everything optional. Type your parameters strictly. If it's a date, say it's a date with the expected format. If it's an enum, list the valid values.
```json
{
"name": "get_orders",
"description": "Retrieve customer orders within a date range",
"parameters": {
"customer_id": { "type": "string", "description": "The customer's unique ID" },
"start_date": { "type": "string", "format": "YYYY-MM-DD" },
"end_date": { "type": "string", "format": "YYYY-MM-DD" },
"status": {
"type": "string",
"enum": ["pending", "completed", "cancelled"],
"default": "all"
}
},
"required": ["customer_id", "start_date", "end_date"]
}
```
### Rich Return Values
When a tool returns "success," the model has no idea what actually happened. When it returns `{"orders_found": 47, "total_value": 12450.00, "date_range": "2026-02-01 to 2026-03-01"}`, the model can actually work with the result.
Return structured data. Include counts, summaries, and relevant metadata. If the tool read 500 records, don't dump all 500 into the context. Return a summary and let the agent request details if needed. The related post on [building an MCP server](/blog/building-mcp-server-custom-tools) goes further on this point.
### Meaningful Error Messages
"Error" is useless. "403 Forbidden: API key does not have read access to customer_orders table" is actionable. The model needs to reason about failures, and it can only do that if the error tells it what went wrong and, ideally, hints at how to fix it.
## The Tool Selection Problem
When an agent has access to 5 tools, tool selection is easy. When it has access to 50, things get interesting. The model has to read 50 tool descriptions, figure out which one applies to the current situation, and generate correct arguments for it.
This is harder than it sounds. I've watched agents with large tool sets consistently pick almost-right tools. The search tool that queries the wrong index. The update function that works on a similar but different resource type.
### Solutions That Work
**Categorize and scope.** Don't give the agent all 50 tools at once. Give it the tools relevant to the current phase of work. A customer service agent handling a billing question doesn't need access to the HR tools.
**Layered tool access.** Start with high-level tools. "search_knowledge_base" is better than exposing 12 individual index-specific search functions. If the high-level tool doesn't find what's needed, then expose the specific ones.
**Tool descriptions matter more than tool names.** Write descriptions like you're explaining the tool to a new team member. When should they use it? What does it return? What are the common gotchas? The model reads these descriptions. Make them count.
## Composability: Where Agents Get Powerful
The real magic isn't any single tool call. It's the agent composing multiple tool calls into a workflow that solves a problem. It is worth reading about [Model Context Protocol](/blog/model-context-protocol-mcp) alongside this.
"Find all customers who haven't ordered in 90 days, check their account status, draft a re-engagement email for each active account, and save the drafts for review."
That's four tools, sequenced intelligently, with data flowing between them. The agent decides the order. It handles the iteration. It adapts if one step produces unexpected results. No human authored that specific workflow. The agent composed it from the goal.
This is why tool design matters so much. Each tool is a building block. If the blocks are well-shaped, the agent can compose them into structures you never explicitly designed. If the blocks are awkward, the agent will struggle to fit them together.
## The Security Conversation You Need to Have
Every tool is an attack surface. If your agent can call `execute_sql`, it can call `DROP TABLE users`. If it can send emails, it can send emails to anyone. If it can read files, it can read your `.env`.
Tool permissions aren't an afterthought. They're the first conversation.
**Principle of least privilege.** The agent gets the minimum permissions required for the task. Read-only when it only needs to read. Scoped to specific tables, not the whole database. Restricted to specific email recipients, not the global address book.
**Input validation.** Don't trust the model's arguments. Validate them. Sanitize SQL. Check that file paths are within allowed directories. Verify that email recipients are on the approved list. The model can be prompt-injected, and its tool arguments are the injection vector. It is worth reading about [the ReAct reasoning loop](/blog/react-pattern-agents) alongside this.
**Audit logging.** Every tool call gets logged. What tool, what arguments, what result, what time, which agent. When something goes wrong (and it will), you need the forensics.
## The Model Context Protocol (MCP) Shift
MCP is worth mentioning because it's standardizing how tools are exposed to agents. Instead of every framework having its own tool definition format, MCP creates a common protocol. Tools become interoperable. An MCP server that exposes your database tools works with any MCP-compatible agent.
This matters because it means the tool ecosystem scales. Instead of building custom integrations for every agent framework, you build one MCP server and it works everywhere. The tool layer becomes infrastructure, not application code.
We're still early. But the direction is clear: tools are becoming a standard, composable layer that any agent can consume. And that's when things get really interesting.