How to Build a fraud detection Agent Using LlamaIndex in TypeScript for investment banking
A fraud detection agent in investment banking is not a chatbot that “spots suspicious activity.” It is a decision-support layer that ingests transaction context, client metadata, policy rules, and investigation notes, then surfaces risk-ranked cases with evidence an analyst can audit. That matters because false negatives create regulatory exposure, and false positives burn analyst time on high-value desks.
Architecture
- •Data ingestion layer
- •Pulls trade records, payment events, KYC profiles, sanctions hits, and case notes from internal systems.
- •Document indexing layer
- •Normalizes policies, AML playbooks, escalation procedures, and historical investigations into retrievable nodes.
- •Risk scoring workflow
- •Uses deterministic rules first, then LLM-assisted reasoning for ambiguous cases.
- •Retrieval layer
- •Queries policy docs and prior cases with
VectorStoreIndexso the agent can cite internal evidence.
- •Queries policy docs and prior cases with
- •Agent orchestration layer
- •Uses LlamaIndex tools to inspect records, retrieve context, and generate an analyst-ready summary.
- •Audit and logging layer
- •Persists prompts, retrieved sources, scores, and final decisions for compliance review.
Implementation
- •Install the TypeScript packages and define your data model
Use the TypeScript SDK from LlamaIndex. For investment banking, keep transaction fields explicit so you can enforce controls around residency, retention, and auditability.
npm install llamaindex
import {
Document,
VectorStoreIndex,
Settings,
OpenAI,
} from "llamaindex";
type Transaction = {
id: string;
accountId: string;
counterparty: string;
amount: number;
currency: string;
country: string;
channel: "wire" | "swift" | "internal_transfer";
timestamp: string;
alertReason?: string;
};
const transactions: Transaction[] = [
{
id: "tx_001",
accountId: "acc_7781",
counterparty: "Blue Harbor Ltd",
amount: 950000,
currency: "USD",
country: "AE",
channel: "wire",
timestamp: "2026-04-20T10:12:00Z",
alertReason: "High-value wire to new counterparty",
},
];
Settings.llm = new OpenAI({
model: "gpt-4o-mini",
});
- •Index your compliance and investigation corpus
The agent needs retrieval over internal policies and prior case narratives. In banking, this is where you keep the model grounded in your actual control environment instead of generic fraud advice.
const policyDocs = [
new Document({
text:
"Escalate any wire transfer above USD 500k to a new counterparty when the beneficiary country is high-risk or the payment pattern deviates from historical behavior.",
metadata: { source: "AML_Wire_Policy", version: "v3" },
}),
new Document({
text:
"All suspicious activity decisions must include evidence references and be retained for audit review for seven years.",
metadata: { source: "Case_Retention_Standard", version: "v2" },
}),
];
const index = await VectorStoreIndex.fromDocuments(policyDocs);
const retriever = index.asRetriever({ similarityTopK: 2 });
- •Build the fraud triage function
This pattern combines deterministic checks with retrieval-backed reasoning. Use rules to catch obvious violations, then ask the LLM to explain why a case is risky using retrieved policy snippets.
async function triageTransaction(txn: Transaction) {
const ruleHits: string[] = [];
if (txn.amount >= 500000 && txn.channel === "wire") {
ruleHits.push("High-value wire");
}
if (txn.country === "AE" || txn.country === "NG" || txn.country === "KY") {
ruleHits.push("High-risk jurisdiction");
}
if (txn.alertReason) {
ruleHits.push(txn.alertReason);
}
const query = `
Transaction ${txn.id}
Account ${txn.accountId}
Counterparty ${txn.counterparty}
Amount ${txn.amount} ${txn.currency}
Country ${txn.country}
Channel ${txn.channel}
Rules triggered: ${ruleHits.join(", ") || "none"}
`;
const nodes = await retriever.retrieve({ query });
const context = nodes.map((n) => n.node.getContent()).join("\n---\n");
const response = await Settings.llm.complete({
prompt: `
You are assisting an investment banking fraud analyst.
Use only the provided policy context.
Return JSON with keys:
risk_level, rationale, recommended_action, evidence
Policy context:
${context}
Transaction:
${query}
`,
});
return {
transactionId: txn.id,
ruleHits,
llmOutput: response.text,
sources: nodes.map((n) => n.node.metadata),
};
}
const result = await triageTransaction(transactions[0]);
console.log(result);
- •Wrap it as an analyst-facing workflow
In production, don’t expose raw model output directly to users. Parse the response into a structured case object, store it in your case management system, and require human approval before escalation or SAR filing.
A practical output shape:
- •
risk_level:low | medium | high - •
recommended_action:monitor | escalate | freeze | request_documents - •
evidence: array of cited policy snippets - •
sources: document IDs and versions - •
decision_by: human reviewer ID if approved
Production Considerations
- •Data residency
- •Keep embeddings and raw transaction data in-region. If your bank operates under UK/EU constraints, don’t send sensitive customer data to a model endpoint outside approved jurisdictions.
- •Auditability
- •Persist every prompt, retrieved node ID, model version, and final decision. Regulators care about why a case was escalated more than how elegant your prompt was.
- •Guardrails
- •Use deterministic thresholds for hard stops like sanctions matches or blocked jurisdictions. Let the LLM explain edge cases; don’t let it override mandatory controls.
- •Monitoring
- •Track false positive rate by desk, geography, and product line. A fraud agent that floods prime brokerage with noisy alerts will get turned off by operations.
Common Pitfalls
- •
Using the LLM as the primary detector
- •Bad pattern. Fraud detection in banking starts with rules, anomaly signals, and sanctioned-party screening; the LLM should assist with triage and explanation.
- •
Indexing raw sensitive data without access controls
- •Don’t dump full client PII into your vector store. Redact account numbers where possible and enforce role-based access around both retrieval and logs.
- •
Skipping versioning on policies
- •If your model cites an outdated AML procedure during an audit review, you have a governance problem. Store document versions in metadata and rebuild indexes when policies change.
- •
Returning free-form answers to analysts
- •Analysts need structured outputs they can act on quickly. Convert the agent response into a fixed schema before it reaches case management or downstream automation.
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