LlamaIndex Tutorial (Python): adding tool use for advanced developers

By Cyprian AaronsUpdated 2026-04-21
llamaindexadding-tool-use-for-advanced-developerspython

This tutorial shows how to add tool use to a LlamaIndex Python agent so it can call external functions, not just answer from indexed data. You need this when your assistant has to fetch live data, run business logic, or interact with internal systems like pricing, policy lookup, or claims status.

What You'll Need

  • Python 3.10+
  • llama-index
  • An OpenAI API key set as OPENAI_API_KEY
  • Optional: python-dotenv if you want to load env vars from a .env file
  • Basic familiarity with LlamaIndex Settings, QueryEngine, and Tool concepts

Install the packages:

pip install llama-index llama-index-llms-openai python-dotenv

Step-by-Step

  1. Start by configuring LlamaIndex to use an OpenAI chat model. For tool use, the agent needs a function-calling capable model, so keep the setup explicit and simple.
import os
from llama_index.core import Settings
from llama_index.llms.openai import OpenAI

os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY", "")

Settings.llm = OpenAI(model="gpt-4o-mini", temperature=0)
  1. Define a real Python function that the agent can call. In production, this is where you wrap a database lookup, internal API call, or rules engine; here we’ll use a deterministic example that is safe to run locally.
from typing import Literal

def calculate_policy_premium(
    age: int,
    smoker: bool,
    coverage_amount: int,
    plan: Literal["basic", "standard", "premium"],
) -> str:
    base_rate = {"basic": 0.012, "standard": 0.018, "premium": 0.025}[plan]
    risk_multiplier = 1.4 if smoker else 1.0
    age_multiplier = 1.2 if age >= 50 else 1.0
    monthly_premium = coverage_amount * base_rate * risk_multiplier * age_multiplier / 12
    return f"Estimated monthly premium: ${monthly_premium:.2f}"
  1. Wrap that function as a LlamaIndex tool using FunctionTool. This gives the agent metadata it can inspect and a callable interface it can invoke during reasoning.
from llama_index.core.tools import FunctionTool

premium_tool = FunctionTool.from_defaults(
    fn=calculate_policy_premium,
    name="calculate_policy_premium",
    description=(
        "Calculate an estimated insurance premium from age, smoking status, "
        "coverage amount, and plan."
    ),
)
  1. Build an agent that can choose between tools and normal reasoning. ReActAgent is the straightforward option when you want transparent tool calls and step-by-step traces.
from llama_index.core.agent import ReActAgent

agent = ReActAgent.from_tools(
    tools=[premium_tool],
    llm=Settings.llm,
    verbose=True,
)
  1. Send a prompt that forces the model to use the tool instead of guessing. Keep the query structured so the agent has enough information to map arguments cleanly into your function signature.
response = agent.chat(
    "Use the premium calculator for a 52-year-old smoker requesting "
    "250000 coverage on the standard plan."
)

print(response)
  1. If you want stronger control in production, validate inputs before exposing them as tools. That prevents bad calls from reaching downstream systems and makes failures easier to debug.
def safe_calculate_policy_premium(age: int, smoker: bool, coverage_amount: int, plan: str) -> str:
    if age < 18 or age > 100:
        raise ValueError("age must be between 18 and 100")
    if coverage_amount <= 0:
        raise ValueError("coverage_amount must be positive")
    if plan not in {"basic", "standard", "premium"}:
        raise ValueError("plan must be basic, standard, or premium")

    return calculate_policy_premium(age, smoker, coverage_amount, plan)  # type: ignore[arg-type]

Testing It

Run the script and inspect the verbose trace first. You should see the agent decide to call calculate_policy_premium, pass structured arguments into it, then return a final answer based on the function output.

Test at least three prompts:

  • one clean request with all fields present
  • one request with ambiguous wording like “cheap plan” or “non-smoker”
  • one invalid request with missing or malformed values

If the tool wiring is correct, valid prompts will produce deterministic results and invalid prompts will either trigger validation errors or force the agent to ask for clarification. In production, that distinction matters because you want predictable tool behavior before connecting anything sensitive.

Next Steps

  • Add multiple tools and let the agent choose between them for claims lookup, policy pricing, and document search.
  • Replace the toy function with a real service wrapper around your internal API or database.
  • Add input schemas with Pydantic when your tool arguments get more complex than a few primitives.

Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides