LlamaIndex Tutorial (TypeScript): building custom tools for intermediate developers
This tutorial shows you how to build custom tools in LlamaIndex TypeScript and wire them into an agent that can call your own business logic. You need this when the built-in tools are not enough, like querying internal systems, validating policy rules, or wrapping a bank-specific API behind a safe interface.
What You'll Need
- •Node.js 18+
- •A TypeScript project with
ts-nodeortsx - •
llamaindexinstalled - •An OpenAI API key set in your environment
- •A working internet connection for model calls
- •Basic familiarity with async/await and TypeScript types
Install the package:
npm install llamaindex
Set your API key:
export OPENAI_API_KEY="your-key-here"
Step-by-Step
- •Start by creating a small TypeScript file and importing the pieces you need from LlamaIndex. The goal is to define one custom tool that the agent can call like any other function.
import { FunctionTool, ReActAgent, Settings } from "llamaindex";
Settings.llm = undefined;
- •Define a real tool function with explicit input and output types. Keep it deterministic and narrow: tools should do one thing well, not act like mini-agents.
type PolicyLookupInput = {
policyNumber: string;
};
async function lookupPolicy(input: PolicyLookupInput): Promise<string> {
const policies: Record<string, string> = {
"POL-1001": "Active | Premium paid | Renewal due in 21 days",
"POL-1002": "Lapsed | Payment overdue by 14 days",
};
return policies[input.policyNumber] ?? "Policy not found";
}
- •Wrap that function with
FunctionTool.from. This gives LlamaIndex the metadata it needs to decide when to call the tool and how to format arguments.
const policyLookupTool = FunctionTool.from(lookupPolicy, {
name: "policy_lookup",
description:
"Look up the current status of an insurance policy by policy number.",
parameters: {
type: "object",
properties: {
policyNumber: {
type: "string",
description: "The policy number, for example POL-1001",
},
},
required: ["policyNumber"],
},
});
- •Create a second tool so you can see how agents choose between multiple actions. In production, this is where you would wrap internal services like claim status checks, customer profile retrieval, or document classification.
type ClaimSummaryInput = {
claimId: string;
};
async function summarizeClaim(input: ClaimSummaryInput): Promise<string> {
const claims: Record<string, string> = {
"CLM-2001": "Open | Awaiting adjuster review | Estimated payout $4,200",
"CLM-2002": "Closed | Paid out $9,800 | No further action required",
};
return claims[input.claimId] ?? "Claim not found";
}
const claimSummaryTool = FunctionTool.from(summarizeClaim, {
name: "claim_summary",
description:
"Get a short summary of a claim by claim ID.",
parameters: {
type: "object",
properties: {
claimId: {
type: "string",
description: "The claim ID, for example CLM-2001",
},
},
required: ["claimId"],
},
});
- •Put both tools into a ReAct agent and ask it questions that require tool use. The agent will decide whether to answer directly or call your tools first.
async function main() {
const agent = new ReActAgent({
tools: [policyLookupTool, claimSummaryTool],
});
const response1 = await agent.chat({
message: "Check policy POL-1001 and tell me its status.",
});
console.log("Policy response:", response1.response);
const response2 = await agent.chat({
message: "Summarize claim CLM-2002.",
});
console.log("Claim response:", response2.response);
}
main().catch(console.error);
Testing It
Run the file with npx tsx your-file.ts or npx ts-node your-file.ts, depending on your setup. If everything is wired correctly, the agent should return the mocked policy and claim results instead of hallucinating answers.
Test edge cases too. Ask for an unknown policy number like POL-9999 and confirm the tool returns "Policy not found". Then verify that the agent passes that result through cleanly without crashing.
If you want stronger validation, log inside each tool function so you can see when the model actually invokes them. In a production system, that same pattern becomes your audit trail for tool usage.
Next Steps
- •Add Zod validation to enforce stricter input schemas before calling downstream systems
- •Replace the in-memory mock data with real HTTP calls to internal services
- •Add authorization checks inside each tool so the agent only exposes allowed data
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