How to Build a fraud detection Agent Using CrewAI in TypeScript for wealth management

By Cyprian AaronsUpdated 2026-04-21
fraud-detectioncrewaitypescriptwealth-management

A fraud detection agent for wealth management watches account activity, client instructions, transfer requests, and portfolio changes, then flags patterns that look like impersonation, unauthorized trading, account takeover, or social-engineering-driven wire fraud. In wealth management, the cost of missing one bad instruction is not just financial loss; it is regulatory exposure, client trust damage, and a messy audit trail.

Architecture

  • Input collector

    • Pulls in events from CRM notes, order management systems, wire request queues, email metadata, and authentication logs.
    • Normalizes each event into a single fraud-review payload.
  • Risk classification agent

    • Uses an LLM-backed Agent to score the request and explain why it looks suspicious.
    • Produces structured output: risk level, reasons, recommended action.
  • Policy and compliance layer

    • Enforces wealth-management rules before any recommendation is acted on.
    • Checks for KYC/AML flags, restricted jurisdictions, advisor-client mismatch, and approval thresholds.
  • Audit logger

    • Stores every input, model output, tool call, and final decision.
    • Required for internal review and regulator-facing evidence.
  • Escalation workflow

    • Routes high-risk cases to a human investigator or operations queue.
    • Prevents the agent from auto-blocking legitimate client activity without review.

Implementation

1) Install dependencies and define the fraud review schema

CrewAI’s TypeScript support is straightforward: define agents and tasks in code, then run them through a Crew. For fraud detection, keep outputs structured so downstream systems can consume them without parsing free-form text.

npm install crewai zod dotenv
import { z } from "zod";

export const FraudReviewSchema = z.object({
  riskLevel: z.enum(["low", "medium", "high"]),
  decision: z.enum(["approve", "review", "block"]),
  reasons: z.array(z.string()).min(1),
  recommendedActions: z.array(z.string()).min(1),
  auditSummary: z.string().min(20),
});

export type FraudReview = z.infer<typeof FraudReviewSchema>;

export interface WealthEvent {
  clientId: string;
  accountId: string;
  requestType: "wire" | "trade" | "address_change" | "beneficiary_update";
  amount?: number;
  currency?: string;
  channel: "advisor_portal" | "email" | "phone" | "mobile_app";
  ipRiskScore: number;
  geoMismatch: boolean;
  recentLoginFailures: number;
  kycStatus: "verified" | "pending" | "expired";
}

2) Build the agent with wealth-management guardrails

The agent should not be a generic fraud bot. It needs instructions that reflect wealth workflows: high-value transfers, advisor authorization chains, and strict auditability.

import "dotenv/config";
import { Agent } from "crewai";

export const fraudAgent = new Agent({
  name: "Wealth Fraud Detection Agent",
  role: "Detect suspicious client instructions and transaction patterns",
  goal:
    "Identify likely fraud in wealth management workflows and return a structured review recommendation",
  backstory:
    "You are a senior fraud analyst for a private wealth platform. You understand account takeover patterns, impersonation attempts, wire fraud red flags, advisor impersonation, and compliance constraints.",
  verbose: true,
});

3) Create a task that forces structured output

Use a Task with explicit output requirements. In production I prefer JSON-only responses because they are easier to validate and log.

import { Task } from "crewai";
import { FraudReviewSchema } from "./schema";
import type { WealthEvent } from "./schema";

export function buildFraudTask(event: WealthEvent) {
  return new Task({
    description: `
Review this wealth management event for fraud risk.

Event:
${JSON.stringify(event, null, 2)}

Rules:
- Flag wire requests with geo mismatch + login failures as high risk.
- Treat beneficiary changes followed by transfers as suspicious.
- Escalate expired KYC or advisor-channel mismatches.
- Do not approve if evidence suggests impersonation or account takeover.
- Return JSON only with keys:
riskLevel, decision, reasons, recommendedActions, auditSummary
`,
    expectedOutput:
      'Valid JSON matching { riskLevel, decision, reasons[], recommendedActions[], auditSummary }',
    agent: fraudAgent,
    async callback(result) {
      const parsed = FraudReviewSchema.parse(JSON.parse(result as string));
      return parsed;
    },
  });
}

4) Run the crew and persist the result for audit

For a single-review workflow you can use one agent plus one task. If you want stronger controls later, add a second agent for compliance validation or an explicit human-review routing step.

import { Crew } from "crewai";
import { buildFraudTask } from "./task";
import type { WealthEvent } from "./schema";

async function main() {
  const event: WealthEvent = {
    clientId: "C12345",
    accountId: "A99881",
    requestType: "wire",
    amount: 250000,
    currency: "USD",
    channel: "email",
    ipRiskScore: 92,
    geoMismatch: true,
    recentLoginFailures: 4,
    kycStatus: "verified",
  };

  const crew = new Crew({
    agents: [fraudAgent],
    tasks: [buildFraudTask(event)],
    verbose: true,
  });

  const result = await crew.kickoff();
  console.log("Fraud review:", result);
}

main().catch(console.error);

Production Considerations

  • Deploy close to your data boundary

    • Wealth data often has residency requirements.
    • Keep the agent in-region if client data cannot leave a specific jurisdiction.
  • Log everything needed for audit

    • Store input payloads, model version, prompt version, task output, timestamps, and final disposition.
    • Regulators care about why a decision was made months later.
  • Add hard guardrails before action

    • The agent should recommend; policy engines should decide whether to block or hold.
    • Use deterministic rules for thresholds like large wires after beneficiary changes.
  • Monitor false positives by segment

    • Private banking clients behave differently from retail brokerage clients. Track rates by region, advisor team, transaction type, and channel so you do not create operational noise.

Common Pitfalls

  1. Letting the LLM make final decisions

    • Don’t auto-block based only on model output.
    • Use the agent for triage; use policy rules and human review for enforcement.
  2. Sending raw sensitive data into prompts

    • Avoid dumping full account statements or personal identifiers into the model context.
    • Redact unnecessary PII and pass only fields required for risk analysis.
  3. Ignoring workflow context

    • A $500k wire is normal in some private wealth books and abnormal in others.
    • Include client profile context such as historical transfer size, advisor relationship length, and expected geography.
  4. Skipping schema validation

    • Free-form LLM output will break downstream systems.
    • Validate every response with zod before it reaches case management or alerting systems.

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