How to Build a fraud detection Agent Using LlamaIndex in TypeScript for wealth management
A fraud detection agent for wealth management screens transactions, account activity, and client instructions for suspicious patterns, then routes high-risk cases to compliance or operations with evidence attached. It matters because the cost of a missed alert is not just financial loss; it can trigger regulatory issues, client churn, and audit findings that are expensive to unwind.
Architecture
- •
Data ingestion layer
- •Pulls from transaction feeds, CRM notes, case management systems, and advisor activity logs.
- •Normalizes records into a consistent schema before they reach the agent.
- •
Policy and rules layer
- •Encodes wealth-management-specific controls like wire transfer thresholds, beneficiary changes, address changes, and unusual trading behavior.
- •Keeps deterministic checks separate from LLM reasoning.
- •
LlamaIndex query engine
- •Uses
VectorStoreIndex,Document, andQueryEngineto retrieve relevant historical cases, policies, and client context. - •Grounds the agent in firm-approved documents instead of free-form guessing.
- •Uses
- •
Risk scoring and decision layer
- •Combines rule hits with LLM analysis to produce a fraud risk score and explanation.
- •Outputs structured results for downstream case management.
- •
Audit logging layer
- •Stores prompts, retrieved sources, model outputs, and final decisions.
- •Supports compliance review and post-incident investigation.
- •
Human escalation workflow
- •Routes medium/high-risk alerts to an analyst queue.
- •Prevents automated action on sensitive events like account freezes or wire holds without review.
Implementation
1) Install dependencies and load approved documents
Start with policy docs, prior fraud typologies, and internal procedures. In wealth management, only index approved material that is safe to expose to the model.
npm install llamaindex zod dotenv
import "dotenv/config";
import {
Document,
VectorStoreIndex,
Settings,
OpenAI,
} from "llamaindex";
Settings.llm = new OpenAI({
model: "gpt-4o-mini",
});
const policyDocs = [
new Document({
text: `
Wire transfer red flags:
- New beneficiary added within last 24 hours
- Transfer exceeds client's historical median by >3x
- Instruction received outside normal advisor-client channel
- Name mismatch between sender and account holder
`,
metadata: { source: "wire-policy", version: "2025.01" },
}),
new Document({
text: `
Escalate immediately if:
- Client requests urgent wire to offshore jurisdiction
- Account holder email changed within last 7 days
- Advisor notes indicate pressure or impersonation
`,
metadata: { source: "escalation-policy", version: "2025.01" },
}),
];
const index = await VectorStoreIndex.fromDocuments(policyDocs);
const queryEngine = index.asQueryEngine();
2) Build a fraud assessment function
The pattern is simple: run deterministic checks first, then ask the LlamaIndex query engine to ground the response in policy. That keeps the agent explainable and easier to defend in audit.
type TransactionEvent = {
clientId: string;
amountUsd: number;
beneficiaryAddedHoursAgo?: number;
channel: "advisor_portal" | "email" | "phone" | "branch";
accountAgeDays: number;
emailChangedDaysAgo?: number;
};
function ruleScore(event: TransactionEvent): number {
let score = 0;
if (event.amountUsd > 250000) score += 30;
if ((event.beneficiaryAddedHoursAgo ?? Infinity) < 24) score += 35;
if (event.channel === "email") score += 15;
if ((event.emailChangedDaysAgo ?? Infinity) < 7) score += 25;
return Math.min(score, 100);
}
async function assessFraud(event: TransactionEvent) {
const ruleBasedScore = ruleScore(event);
const prompt = `
You are assisting a wealth management fraud analyst.
Assess this event against internal policy only.
Return:
1) risk level (low/medium/high)
2) concise rationale
3) policy references used
Event:
${JSON.stringify(event, null, 2)}
`;
const response = await queryEngine.query({ query: prompt });
return {
clientId: event.clientId,
ruleBasedScore,
llmAssessment: response.toString(),
finalDecision:
ruleBasedScore >= 70 ? "escalate" :
ruleBasedScore >=50 ? "review" : "allow",
};
}
const result = await assessFraud({
clientId: "C-10291",
amountUsd:250000,
beneficiaryAddedHoursAgo:6,
channel:"email",
accountAgeDays:900,
emailChangedDaysAgo:3,
});
console.log(result);
3) Add structured output for downstream systems
Wealth platforms need machine-readable decisions. Don’t pass raw text into case management when you can validate a schema first.
import { z } from "zod";
const FraudDecisionSchema = z.object({
riskLevel: z.enum(["low", "medium", "high"]),
rationale: z.string(),
policyReferences: z.array(z.string()),
});
async function assessWithStructure(eventText:string){
const resp = await queryEngine.query({
query:`Analyze this event and return JSON with riskLevel,rationale,policyReferences.\n\n${eventText}`,
});
const parsed = JSON.parse(resp.toString());
return FraudDecisionSchema.parse(parsed);
}
Why this pattern works
| Layer | Responsibility | Why it matters |
|---|---|---|
| Rules | Fast deterministic screening | Easy to audit and tune |
| Retrieval | Grounding in approved policy | Reduces hallucinations |
| Structured output | Integration with case tools | Prevents brittle parsing |
| Human review | Final approval on sensitive actions | Required for high-impact decisions |
Production Considerations
- •
Deploy in-region
Keep embeddings, vector stores, logs, and model traffic inside approved data residency boundaries. Wealth firms often have strict regional constraints for client data and cross-border processing.
- •
Log everything needed for audit
Persist input event payloads, retrieved policy chunks, model output, final decision, timestamp, and operator override. If you cannot reconstruct why a wire was escalated six months later, your control failed.
- •
Add hard guardrails
Never let the agent freeze accounts or approve transfers directly. Restrict it to recommend/review/escalate actions only; execution should stay behind human approval or separate workflow controls.
- •
Monitor drift by segment
Track false positives by client tier, geography, product type, advisor desk, and channel. Fraud patterns in private banking look different from retail brokerage or trust accounts.
Common Pitfalls
- •
Using the LLM as the primary detector
The model should explain and correlate signals after rules fire. If you rely on pure prompting for detection logic, you’ll get inconsistent outcomes and poor auditability.
- •
Indexing raw sensitive data without controls
Don’t dump full statements or PII into your vector store unless access control is already solved. Mask account numbers, redact unnecessary fields, and limit retrieval scope by tenant or desk.
- •
Skipping explainability artifacts
A risk score without supporting evidence is weak in a regulated environment. Store retrieved policy snippets and the exact prompt used so compliance can review the decision path end to end.
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