How to Build a transaction monitoring Agent Using LlamaIndex in TypeScript for retail banking
A transaction monitoring agent in retail banking watches customer activity, scores transactions for suspicious patterns, and prepares analyst-ready summaries for review. It matters because you need to catch fraud, mule activity, structuring, and unusual behavior early without flooding compliance teams with false positives.
Architecture
- •
Transaction ingestion layer
- •Pulls card, ACH, wire, and internal transfer events from your core banking or streaming system.
- •Normalizes fields like amount, merchant, channel, counterparty, timestamp, and customer profile.
- •
Risk feature builder
- •Converts raw transactions into features the agent can reason over:
- •velocity counts
- •amount spikes
- •geolocation mismatch
- •new beneficiary usage
- •cash-like merchant categories
- •Converts raw transactions into features the agent can reason over:
- •
LlamaIndex retrieval layer
- •Stores policy docs, AML typologies, SAR guidance, and internal playbooks.
- •Uses
VectorStoreIndexandasRetriever()to fetch relevant policy context for each alert.
- •
Agent reasoning layer
- •Uses a
ReActAgentor tool-driven workflow to combine transaction data with retrieved policy context. - •Produces a structured assessment: risk level, rationale, and next action.
- •Uses a
- •
Case management output
- •Writes the result into your alert queue or case system.
- •Keeps an audit trail with input features, retrieved documents, model output, and final disposition.
- •
Controls and governance
- •Enforces PII redaction, data residency boundaries, approval gates, and human review for adverse decisions.
Implementation
1. Install dependencies and define your document corpus
For a banking use case, keep policy content separate from customer data. The agent should retrieve AML rules, fraud typologies, and internal procedures from approved documents only.
npm install llamaindex zod
import {
Document,
VectorStoreIndex,
Settings,
OpenAIEmbedding,
} from "llamaindex";
Settings.embedModel = new OpenAIEmbedding({
model: "text-embedding-3-small",
});
const policyDocs = [
new Document({
text: `
Retail banking AML policy:
- Escalate if there are rapid transfers across multiple beneficiaries.
- Escalate if cash-like transactions exceed normal customer behavior.
- Review transactions that show structuring below reporting thresholds.
- Require analyst review before any SAR recommendation.
`,
metadata: { source: "aml_policy_v3", jurisdiction: "US" },
}),
new Document({
text: `
Fraud typologies:
- Account takeover often shows new device + unusual payee + high-value transfer.
- Mule activity often shows inbound funds followed by quick outbound movement.
- Card testing often shows many small authorizations in a short time window.
`,
metadata: { source: "fraud_typologies_2025", jurisdiction: "US" },
}),
];
const index = await VectorStoreIndex.fromDocuments(policyDocs);
const retriever = index.asRetriever({ similarityTopK: 3 });
2. Build a transaction risk summarizer
Do not send raw full account histories into the model. Precompute a compact event summary with only the fields needed for review.
type TransactionEvent = {
transactionId: string;
customerId: string;
amount: number;
currency: string;
channel: "ACH" | "WIRE" | "CARD" | "INTERNAL";
merchantCategory?: string;
beneficiaryCount24h: number;
newBeneficiaryUsed: boolean;
crossBorder: boolean;
velocityCount1h: number;
};
function buildRiskSummary(txn: TransactionEvent) {
return [
`transactionId=${txn.transactionId}`,
`customerId=${txn.customerId}`,
`amount=${txn.amount} ${txn.currency}`,
`channel=${txn.channel}`,
`merchantCategory=${txn.merchantCategory ?? "n/a"}`,
`beneficiaryCount24h=${txn.beneficiaryCount24h}`,
`newBeneficiaryUsed=${txn.newBeneficiaryUsed}`,
`crossBorder=${txn.crossBorder}`,
`velocityCount1h=${txn.velocityCount1h}`,
].join("\n");
}
3. Create an agent that retrieves policy context and writes an analyst note
This pattern uses LlamaIndex’s actual ReActAgent API with a retrieval tool. The agent reads the transaction summary plus relevant policy snippets and produces a concise alert note.
import {
OpenAI,
ReActAgent,
} from "llamaindex";
const llm = new OpenAI({
model: "gpt-4o-mini",
});
const retrievePolicyTool = {
type: "function" as const,
function: {
name: "retrieve_policy_context",
description:
"Retrieve AML/fraud policy context relevant to a retail banking transaction.",
parameters: {
type: "object",
properties: {
query: { type: "string" },
},
required: ["query"],
additionalProperties: false,
},
},
};
const agent = new ReActAgent({
llm,
tools: [
{
...retrievePolicyTool,
call: async ({ query }: { query?: string }) => {
const nodes = await retriever.retrieve(query ?? "");
return nodes.map((n) => n.node.getContent()).join("\n---\n");
},
} as any,
],
});
export async function scoreTransaction(txn: TransactionEvent) {
const summary = buildRiskSummary(txn);
const prompt = `
You are assisting a retail banking financial crime analyst.
Task:
1. Assess whether this transaction is suspicious based on the provided summary.
2. Retrieve relevant AML/fraud policy context before answering.
3. Return a short analyst note with:
- risk_level
- key_factors
- recommended_action
Transaction summary:
${summary}
Important constraints:
- Do not make final SAR decisions.
- Do not mention protected attributes.
- Keep output suitable for audit logging.
`;
const response = await agent.chat(prompt);
return response.message.content;
}
Step through the flow
- •The transaction event is normalized into a compact summary.
- •The agent retrieves relevant AML or fraud guidance using
retrieve_policy_context. - •The model combines live event features with approved policy text.
- •The output becomes an analyst note for case management or queue triage.
Production Considerations
- •
Data residency
- •Keep embeddings, vector stores, and LLM endpoints in-region when regulations require it.
- •For EU or country-specific deployments, do not route customer data to cross-border hosted services unless legal approval exists.
- •
Auditability
- •Log the exact transaction summary, retrieved document IDs, prompt version, model version, and final output.
- •Store immutable traces so compliance can reconstruct why an alert was generated.
- •
Guardrails
- •Redact PII before prompting where possible.
- •Block unsupported outputs like “close case automatically” or “file SAR now” unless a human approves it.
- •
Monitoring
- •Track precision/recall on confirmed cases, analyst override rate, retrieval quality, and latency per alert.
- •Watch for drift in typologies; fraud patterns change faster than most models do.
Common Pitfalls
- •Sending raw customer histories into the prompt
At retail-banking scale this creates privacy risk and noisy prompts. Summarize only what the model needs for triage and keep sensitive identifiers out of the prompt body.
- •Using retrieval without document governance
If your vector store contains stale policies or draft procedures, the agent will cite bad guidance confidently. Version documents tightly and index only approved content.
- •Treating the agent as the decision-maker
The agent should assist analysts, not replace them. Final disposition on suspicious activity must stay under human control with clear escalation rules.
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