LlamaIndex Tutorial (Python): building custom tools for beginners
This tutorial shows you how to build a custom tool in LlamaIndex, wire it into an agent, and call it from Python. You need this when the built-in tools are not enough and your agent has to hit your own business logic, internal APIs, or a specific workflow.
What You'll Need
- •Python 3.10+
- •
llama-index - •An OpenAI API key
- •
OPENAI_API_KEYset in your environment - •A terminal and a Python file to run the example
- •Basic familiarity with LlamaIndex agents and tools
Install the package:
pip install llama-index
Set your API key:
export OPENAI_API_KEY="your-key-here"
Step-by-Step
- •Start with a simple function that represents your business logic. In real projects, this could query a database, validate a policy number, or fetch account status from an internal service.
from typing import Literal
def get_policy_status(policy_id: str) -> str:
mock_db = {
"POL123": "active",
"POL456": "pending renewal",
"POL789": "cancelled",
}
return mock_db.get(policy_id, "policy not found")
print(get_policy_status("POL123"))
- •Wrap that function as a LlamaIndex tool using
FunctionTool. This is the cleanest starting point for beginners because it keeps your Python function intact while making it callable by an agent.
from llama_index.core.tools import FunctionTool
def get_policy_status(policy_id: str) -> str:
mock_db = {
"POL123": "active",
"POL456": "pending renewal",
"POL789": "cancelled",
}
return mock_db.get(policy_id, "policy not found")
policy_tool = FunctionTool.from_defaults(
fn=get_policy_status,
name="get_policy_status",
description="Get the current status of an insurance policy by policy ID.",
)
- •Create an agent and pass the tool into it. This gives the model a structured way to decide when to call your function instead of guessing from its own knowledge.
from llama_index.core.agent import ReActAgent
from llama_index.llms.openai import OpenAI
llm = OpenAI(model="gpt-4o-mini")
agent = ReActAgent.from_tools(
tools=[policy_tool],
llm=llm,
verbose=True,
)
- •Ask the agent a question that should trigger the tool. Keep the prompt specific so it has enough context to choose the right action.
response = agent.chat("What is the status of policy POL456?")
print(response)
- •If you want more control, define a custom tool class instead of wrapping a plain function. This is useful when you need state, validation, or access to multiple helper methods.
from llama_index.core.tools.types import BaseToolSpec
class PolicyToolSpec(BaseToolSpec):
spec_functions = ["get_policy_status"]
def get_policy_status(self, policy_id: str) -> str:
mock_db = {
"POL123": "active",
"POL456": "pending renewal",
"POL789": "cancelled",
}
return mock_db.get(policy_id, "policy not found")
tool_spec = PolicyToolSpec()
tools = tool_spec.to_tool_list()
print([tool.metadata.name for tool in tools])
- •Use that custom tool spec in the same agent flow. This pattern scales better when you later add more functions like claim lookup, premium calculation, or document retrieval.
from llama_index.core.agent import ReActAgent
from llama_index.llms.openai import OpenAI
llm = OpenAI(model="gpt-4o-mini")
tool_spec = PolicyToolSpec()
tools = tool_spec.to_tool_list()
agent = ReActAgent.from_tools(tools=tools, llm=llm, verbose=True)
response = agent.chat("Check policy POL789 and tell me its status.")
print(response)
Testing It
Run the script and confirm that the agent prints a response based on your mocked policy data. If verbose mode is enabled, you should also see the agent deciding to call get_policy_status before returning an answer.
Test at least three inputs: one existing policy ID like POL123, one unknown ID like POL000, and one natural-language request such as “Is policy POL456 active?” The point is to verify both direct lookup behavior and how well the agent routes user intent into the tool.
If the model does not call the tool, tighten the prompt and make sure your tool description is clear. Tool names and descriptions matter because they are part of how LLMs decide what to use.
Next Steps
- •Add input validation with Pydantic before calling external systems
- •Replace the mock dictionary with a real REST API or database query
- •Build multiple tools and compare
FunctionToolvsBaseToolSpecfor maintainability
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
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