LlamaIndex Tutorial (TypeScript): building conditional routing for beginners

By Cyprian AaronsUpdated 2026-04-21
llamaindexbuilding-conditional-routing-for-beginnerstypescript

This tutorial shows you how to build a conditional router in TypeScript with LlamaIndex, so your app can send different user requests to different tools based on the request content. You need this when one model or one prompt is not enough and you want deterministic routing for things like support, billing, policy lookup, or general Q&A.

What You'll Need

  • Node.js 18+
  • A TypeScript project
  • llamaindex installed
  • An OpenAI API key
  • Basic familiarity with Document, VectorStoreIndex, and QueryEngineTool
  • A terminal that can run ts-node or tsx

Install the package:

npm install llamaindex
npm install -D typescript tsx @types/node

Set your API key:

export OPENAI_API_KEY="your-key-here"

Step-by-Step

  1. Start by creating two separate knowledge sources. In a real app, these could be two internal docs collections: one for billing and one for product support.
import { Document, VectorStoreIndex } from "llamaindex";

const billingDocs = [
  new Document({ text: "Billing support handles invoices, refunds, failed payments, and subscription changes." }),
  new Document({ text: "For refund requests, verify the transaction ID and check the refund policy window." }),
];

const supportDocs = [
  new Document({ text: "Product support handles login issues, feature usage, and account access problems." }),
  new Document({ text: "If a user cannot log in, ask them to reset their password before escalating." }),
];

const billingIndex = await VectorStoreIndex.fromDocuments(billingDocs);
const supportIndex = await VectorStoreIndex.fromDocuments(supportDocs);
  1. Turn each index into a query tool. These tools are what the router will choose between at runtime.
import { QueryEngineTool } from "llamaindex";

const billingTool = QueryEngineTool.from({
  queryEngine: billingIndex.asQueryEngine(),
  metadata: {
    name: "billing",
    description: "Use for invoices, refunds, failed payments, subscriptions, and other billing questions.",
  },
});

const supportTool = QueryEngineTool.from({
  queryEngine: supportIndex.asQueryEngine(),
  metadata: {
    name: "support",
    description: "Use for login issues, feature help, account access, and product usage questions.",
  },
});
  1. Add a router selector that decides which tool should handle each question. For beginners, the simplest useful pattern is a selector that looks at the user query and picks the best tool.
import { LLMSingleSelector } from "llamaindex";

const selector = new LLMSingleSelector({
  llm: undefined,
});
  1. Build a conditional routing function that uses the selector result to call the right engine. This keeps routing logic explicit and easy to test.
async function routeQuery(query: string) {
  const choice = await selector.select({
    choices: [billingTool.metadata.description!, supportTool.metadata.description!],
    query,
  });

  const selected = choice.selections[0]?.index === 0 ? billingTool : supportTool;
  const response = await selected.queryEngine.query({ query });

  return {
    routedTo: selected.metadata.name,
    answer: response.toString(),
  };
}
  1. Wire it up with a few sample queries so you can see the router in action. This is enough to confirm your app is sending requests to different backends based on intent.
async function main() {
  const queries = [
    "I was charged twice for my subscription",
    "How do I reset my password?",
    "Where is my invoice?",
  ];

  for (const query of queries) {
    const result = await routeQuery(query);
    console.log("\nQUERY:", query);
    console.log("ROUTED TO:", result.routedTo);
    console.log("ANSWER:", result.answer);
  }
}

main().catch(console.error);

Testing It

Run the file with tsx or ts-node and check that billing questions go to the billing tool while login or usage questions go to support. If routing is working correctly, you should see different ROUTED TO values for different inputs. Test borderline cases like “refund status” versus “password reset” to make sure your descriptions are specific enough. If everything gets routed to one tool, tighten your tool metadata descriptions before touching the code.

Next Steps

  • Add a third route for escalation or human handoff.
  • Replace single-selection routing with multi-selection when one query can hit multiple tools.
  • Log routing decisions so you can audit misroutes in production.

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