How to Build a customer support Agent Using LlamaIndex in TypeScript for fintech
A customer support agent for fintech answers account, payments, card, and compliance questions using your internal knowledge base instead of guessing. That matters because in fintech, a bad answer is not just a bad UX issue; it can become a compliance incident, a chargeback dispute, or a trust problem.
Architecture
- •
Ingestion layer
- •Pulls policy docs, FAQ pages, dispute workflows, and product manuals from approved sources.
- •Normalizes content into chunks with metadata like
source,region,product, andlastReviewed.
- •
Vector index
- •Stores embeddings for semantic retrieval over support content.
- •Use this for “how do I…?” questions where exact keywords are unreliable.
- •
Retriever + reranker
- •Retrieves the top candidate chunks and optionally reranks them by relevance.
- •Critical for fintech because you want the answer grounded in the right policy version.
- •
Response synthesizer
- •Turns retrieved context into a concise support answer.
- •Should be constrained to cite sources and avoid inventing policy details.
- •
Escalation layer
- •Detects high-risk intents like disputes, fraud claims, chargebacks, KYC/AML issues, and account closure.
- •Routes to human agents or specialized workflows instead of answering directly.
- •
Audit logging
- •Records question, retrieved sources, model output, confidence signals, and escalation decisions.
- •Needed for compliance review and incident reconstruction.
Implementation
1) Install the core packages
Use LlamaIndex TS with an OpenAI embedding/model setup. In production you can swap the model provider later; the retrieval pattern stays the same.
npm install llamaindex dotenv
Set your environment variables:
export OPENAI_API_KEY="your-key"
2) Load support documents and build an index
This example uses Document, VectorStoreIndex, and Settings. The key pattern is to attach metadata that helps with filtering later: region, product line, and document type.
import "dotenv/config";
import { Document, Settings, VectorStoreIndex } from "llamaindex";
async function main() {
Settings.chunkSize = 800;
Settings.chunkOverlap = 120;
const docs = [
new Document({
text: `
Card replacement policy:
- Lost cards are blocked immediately.
- Replacement cards ship in 3-5 business days.
- Expedited shipping is available only for premium accounts.
`,
metadata: {
source: "support-policy",
product: "cards",
region: "us",
docType: "policy",
lastReviewed: "2025-01-10",
},
}),
new Document({
text: `
Chargeback timeline:
Customers must report unauthorized card transactions within 60 days.
We may request supporting evidence before opening a case.
`,
metadata: {
source: "support-policy",
product: "payments",
region: "us",
docType: "policy",
lastReviewed: "2025-01-12",
},
}),
new Document({
text: `
KYC review:
If identity verification fails twice, escalate to manual review.
Do not advise customers to submit altered documents.
`,
metadata: {
source: "compliance-handbook",
product: "onboarding",
region: "eu",
docType: "compliance",
lastReviewed: "2025-01-08",
},
}),
];
const index = await VectorStoreIndex.fromDocuments(docs);
}
main();
3) Build a retriever-driven support query flow
For fintech support you should not just call a chat model directly. Retrieve first, then answer from evidence. The code below uses asQueryEngine() so you get retrieval plus synthesis in one path.
import "dotenv/config";
import {
Document,
MetadataFilters,
MetadataFilter,
Settings,
VectorStoreIndex,
} from "llamaindex";
async function buildAgent() {
Settings.chunkSize = 800;
Settings.chunkOverlap = 120;
const docs = [
new Document({
text: "Customers can reset their PIN in the mobile app under Card Settings.",
metadata: { product: "cards", region: "us", docType: "faq" },
}),
new Document({
text:
"For disputed card charges older than 60 days, route the case to manual review.",
metadata: { product: "payments", region: "us", docType: "policy" },
}),
new Document({
text:
"If a user asks about closing an account while a balance remains open, escalate to operations.",
metadata: { product: "accounts", region: "eu", docType: "policy" },
}),
];
const index = await VectorStoreIndex.fromDocuments(docs);
const filters = new MetadataFilters({
filters: [
new MetadataFilter({ key: "region", value: "us" }),
new MetadataFilter({ key: "product", value: "cards" }),
],
});
const queryEngine = index.asQueryEngine({
similarityTopK: 3,
filters,
});
const response = await queryEngine.query({
query:
'How does a customer reset their PIN? Only answer using the provided support content.',
});
console.log(response.toString());
}
buildAgent();
4) Add escalation rules before generating an answer
This is where most fintech teams get it wrong. You need deterministic checks for regulated topics before letting retrieval synthesize a response. Use simple intent classification rules first; keep them explicit and auditable.
import { QueryEngineTool } from "llamaindex";
const riskyPatterns = [
/fraud/i,
/unauthorized/i,
/chargeback/i,
/aml/i,
/// truncated?
---
## Keep learning
- [The complete AI Agents Roadmap](/blog/ai-agents-roadmap-2026) — my full 8-step breakdown
- [Free: The AI Agent Starter Kit](/starter-kit) — PDF checklist + starter code
- [Work with me](/contact) — I build AI for banks and insurance companies
*By Cyprian Aarons, AI Consultant at [Topiax](https://topiax.xyz).*
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