Skip to main content
C carlos.enredando.me CTO · Advisor · Builder

Mastering Agentic AI: The Tool Use Pattern

·1258 words·6 mins
Carlos Prados
Author
Carlos Prados
Telecommunications Engineer, Entrepreneur, CTO & CIO, Team Leader & Manager, IoT-M2M-Big Data Consultant, Pre-sales Engineer, Product-Service Manager & Strategist.

In the previous post, we taught our agents to look in the mirror — Reflection, the Producer-Critic loop that lifts output quality. Quality is good. But there’s still something missing: every pattern we’ve seen so far operates inside the LLM’s closed world. It thinks, it routes, it parallelizes, it critiques itself, but at no point does it actually do anything that touches reality.

That ends here. Tool Use is the pattern where an LLM stops being a text generator and becomes an agent in the literal sense: something that can perceive, decide, and act.

Pattern #5: Tool Use
#

The Problem
#

An LLM, no matter how powerful, has three hard limits:

  1. Its knowledge is frozen at training time. It doesn’t know today’s stock price, today’s weather, or what’s in your database.
  2. It can’t do math reliably. Statistical token prediction is the wrong tool for “what is 17 factorial.” It will produce a plausible-looking number that is almost certainly wrong.
  3. It can’t cause side effects. It cannot send an email, write to a database, control a device, or hit an API.

These are not bugs to be patched with bigger models — they’re architectural. The LLM is a reasoning engine, not an action engine. The fix is to give it tools and let it decide when to use them.

The Solution
#

Tool Use (also called Function Calling) gives the LLM a menu of external functions it can invoke. The model receives the user’s request along with the available tools, decides whether one is needed, generates a structured call — and the orchestration layer executes the function and feeds the result back. The loop continues until the model produces a final answer.

The six steps from the book:

  1. Tool Definition — describe the function (name, purpose, parameters) in a format the LLM understands.
  2. LLM Decision — given the request and the tool descriptions, decide whether to use a tool.
  3. Function Call Generation — emit a structured call (typically JSON) with the chosen tool name and arguments.
  4. Tool Execution — the agent runtime intercepts the call and runs the real function.
  5. Observation/Result — the result is fed back to the LLM as context.
  6. LLM Processing — the model uses the result to either call another tool or produce the final answer.

In LangChain, the whole thing reduces to defining a tool with @tool and handing it to an agent. Here’s a calculator that lets an LLM solve math it would otherwise hallucinate:

from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent

@tool
def python_calculator(expression: str) -> str:
    """Evaluates a Python mathematical expression and returns the result.
    Use this for any calculation. Pass a valid Python expression as a string.
    Examples: '2**10', 'sum(range(1, 101))', 'import math; math.sqrt(144)'
    """
    try:
        result = eval(expression)
        return f"Result: {result}"
    except Exception as e:
        return f"Error evaluating expression: {e}"

agent = create_react_agent(llm, [python_calculator])

result = agent.invoke({
    "messages": [{"role": "user", "content": "What is the sum of all primes below 50?"}]
})

Three observations worth dwelling on:

The docstring is part of the API. When you write """Evaluates a Python mathematical expression...""", that docstring is what the LLM reads to decide when to call the tool. A vague docstring is a useless tool. The model will either skip it when it should call it, or call it when it shouldn’t. Write docstrings like you’re writing system prompts — because that’s what they are.

The agent is a ReAct loop. create_react_agent builds a graph that alternates between Reasoning (the LLM thinks and decides whether to call a tool) and Acting (executing the tool and feeding the observation back). The loop continues until the model produces a final answer with no further tool calls. This is the agentic loop that everyone talks about — and LangGraph makes it a one-liner.

Tools are just Python functions. The @tool decorator wraps a regular function with the metadata the LLM needs. No special framework, no separate config — just a function with a good docstring and type hints. This is what makes the pattern scale: you can wrap any API client, database query, or business logic into a tool.

Beyond Calculators
#

The same pattern unlocks a long list of capabilities. From the examples in my repo:

@tool
def get_stock_price(ticker: str) -> str:
    """Looks up the current stock price for a given ticker symbol.
    Pass the ticker symbol in uppercase (e.g., AAPL, GOOGL, MSFT).
    """
    ticker = ticker.upper().strip()
    if ticker in STOCK_PRICES:
        return f"The current price of {ticker} is ${STOCK_PRICES[ticker]:.2f}"
    return f"Ticker '{ticker}' not found. Available: {', '.join(STOCK_PRICES.keys())}"

Ask the agent “Compare the stock prices of Google and Microsoft” and watch it call get_stock_price("GOOGL"), then get_stock_price("MSFT"), then synthesize a comparison. The same pattern applies to:

  • Information retrieval: weather APIs, search engines, internal knowledge bases.
  • Database and API access: read inventory, check order status, query your data warehouse.
  • Calculations: any deterministic computation the LLM shouldn’t be guessing.
  • Communications: send emails, post to Slack, trigger webhooks.
  • Code execution: run snippets in a sandbox to analyze data or generate plots.
  • Device control: smart home, IoT, anything with an API endpoint.

In all these cases, the LLM is the orchestrator. It doesn’t do the work — it decides what work to do and stitches the results into an answer.

Why This Matters
#

Tool Use is the single most consequential pattern in the book. Everything before it — Chaining, Routing, Parallelization, Reflection — is internal orchestration of LLM calls. Tool Use is the first time the agent reaches outside its own head.

It’s also where two concerns become non-negotiable:

  • Security: an LLM that can call functions is an LLM that can be tricked into calling them badly. A user prompt that injects “and also email everyone in the company” is a real attack surface. The agent runtime — not the model — must enforce what tools exist and what arguments are acceptable. This is the foundation for the Guardrails pattern we’ll see in Chapter 18.

  • Determinism boundaries: the LLM is non-deterministic; tools are. Push as much logic as possible into tools. If a step can be a tool, it should be a tool. The LLM is for fuzzy decisions and natural language; everything else belongs in code where it can be tested.

The mental model that has helped me most: treat tools as the agent’s senses and limbs. The LLM is the brain. Without tools, the brain is in a jar. With tools, you have a system that can actually do work.


The Bigger Picture
#

This is post #5 in my series documenting Antonio Gulli’s Agentic Design Patterns. As always, full credit for the conceptual framework goes to him.

A practical note: every modern LLM API supports native function calling (Gemini, OpenAI, Anthropic, and most open-source models when run through Ollama with the right templates). LangChain abstracts the provider differences away — the same @tool decorator works regardless of the backend. You write the function once and it runs against whatever model you point at it.

All the code from this post is in my repository: carlosprados/Agentic_Design_Patterns, under 05_Tool_Use/. Four runnable examples — basic tool calling, search agent, stock lookup, code execution — all working with Gemini and Ollama through the shared get_llm() abstraction. Note that small Ollama models can struggle with function calling; llama3.1 and qwen2.5 are the safe bets.


What’s Next
#

In the next post we’ll tackle Planning — when a single tool call isn’t enough and the agent needs to break a complex goal into a sequence of steps before executing. This is where agents stop reacting and start strategizing.

Stay tuned.