How to Build a compliance checking Agent Using CrewAI in TypeScript for banking

By Cyprian AaronsUpdated 2026-04-21
compliance-checkingcrewaitypescriptbanking

A compliance checking agent reviews banking content, customer actions, or internal workflows against policy rules before anything goes live. In practice, that means catching KYC gaps, prohibited language, sanctions-risk phrases, missing disclosures, and policy violations early enough to reduce regulatory exposure and audit pain.

Architecture

  • Input adapter

    • Pulls the artifact to review: a draft email, chatbot response, loan note, or transaction summary.
    • Normalizes it into a structured payload with metadata like jurisdiction, product type, and customer segment.
  • Policy retrieval layer

    • Loads the relevant controls from your compliance library.
    • Keeps rules versioned by region: FCA, OCC, FINRA, GDPR, local banking secrecy laws.
  • Compliance agent

    • Uses CrewAI Agent to reason over the input against policy.
    • Produces a structured verdict: pass, fail, needs human review.
  • Task orchestration

    • Uses CrewAI Task and Crew to define the workflow.
    • Separates extraction, rule checking, and final decisioning so you can audit each step.
  • Audit logger

    • Persists prompts, outputs, rule versions, timestamps, and reviewer decisions.
    • This is non-negotiable in banking. If you cannot explain the decision later, it is not production-ready.
  • Human escalation path

    • Routes uncertain cases to a compliance officer.
    • Prevents false confidence on edge cases like cross-border marketing or sanctions-adjacent wording.

Implementation

1) Install dependencies and define the compliance schema

Use the TypeScript package for CrewAI plus a schema validator so outputs are machine-checkable. Banking workflows should never depend on free-form text alone.

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

export const ComplianceVerdictSchema = z.object({
  status: z.enum(["pass", "fail", "review"]),
  riskLevel: z.enum(["low", "medium", "high"]),
  findings: z.array(
    z.object({
      ruleId: z.string(),
      issue: z.string(),
      severity: z.enum(["minor", "major", "critical"]),
    })
  ),
  rationale: z.string(),
});

export type ComplianceVerdict = z.infer<typeof ComplianceVerdictSchema>;

2) Create an agent with banking-specific instructions

The agent should be narrow. Do not ask it to “be helpful” in general terms; ask it to check policy against specific controls and return structured output only.

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

export const complianceAgent = new Agent({
  role: "Banking Compliance Checker",
  goal:
    "Review banking content against internal policy and applicable regulatory rules.",
  backstory:
    "You are a strict compliance analyst for retail and commercial banking. You flag missing disclosures, prohibited claims, sanctions risk indicators, privacy issues, and jurisdictional conflicts.",
  verbose: true,
});

3) Define tasks for extraction and compliance review

A two-step workflow works better than one giant prompt. First extract the facts. Then check them against policy.

import { Task } from "@crewai/crewai";
import { complianceAgent } from "./agent.js";

const extractTask = new Task({
  description: `
Extract the relevant compliance facts from the input.
Return only JSON with fields:
- productType
- jurisdiction
- customerType
- containsPromotions
- containsPII
- mentionsSanctionsSensitiveTerms
`,
  expectedOutput: "Structured JSON facts for downstream compliance review.",
  agent: complianceAgent,
});

const reviewTask = new Task({
  description: `
Given the extracted facts and the original content, determine whether this passes banking compliance.
Rules:
- Reject if required disclosures are missing.
- Flag if PII appears without a clear business need.
- Escalate if sanctions-sensitive terms appear.
- Respect jurisdiction-specific restrictions.
Return verdict in JSON matching the required schema.
`,
  expectedOutput: "A JSON compliance verdict with status, riskLevel, findings, rationale.",
  agent: complianceAgent,
});

4) Run the crew and validate output before using it

This is where most teams get sloppy. Always validate the model output before persisting or acting on it.

import { Crew } from "@crewai/crewai";
import { ComplianceVerdictSchema } from "./schema.js";

async function main() {
  const crew = new Crew({
    agents: [complianceAgent],
    tasks: [extractTask as any, reviewTask as any],
    verbose: true,
    process: "sequential",
  });

  const result = await crew.kickoff({
    inputs: {
      content:
        "This loan offer guarantees approval within minutes. Please send your SSN and date of birth to proceed.",
      jurisdiction: "US",
      productType: "consumer-lending",
      policyVersion: "2026.01",
    },
  });

  const parsed = ComplianceVerdictSchema.parse(JSON.parse(String(result)));
  console.log(parsed);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});

If you want a cleaner production pattern, wrap the result in an application service that stores:

  • raw input
  • prompt template version
  • policy version
  • model output
  • parsed verdict
  • human override decision

That gives you an audit trail regulators can actually follow.

Production Considerations

  • Deploy inside your controlled environment

    • Keep execution in-region if your bank has data residency constraints.
    • Do not ship customer data to unmanaged endpoints or default SaaS regions without legal approval.
  • Log everything needed for audit

    • Store prompt version, task version, policy version, model name, timestamps, and final verdict.
    • Make logs immutable or append-only where possible.
  • Add hard guardrails before LLM execution

    • Redact account numbers, SSNs, passport IDs, card PANs before sending text to the agent.
    • Use deterministic rules first for obvious violations like banned phrases or missing disclaimers.
  • Route uncertain cases to humans

    • Anything review or high risk should go to a compliance queue.
    • Never auto-release customer-facing content when sanctions screening or cross-border issues are involved.

Common Pitfalls

  1. Treating the agent as a source of truth

    • The model is a reviewer, not a regulator.
    • Avoid this by pairing it with deterministic policy checks and mandatory human escalation on high-risk cases.
  2. Sending raw sensitive data into prompts

    • Banking data often includes PII, account details, and confidential transaction context.
    • Avoid this by redacting sensitive fields upstream and using minimal context necessary for review.
  3. Skipping schema validation

    • Free-form text responses break downstream automation fast.
    • Avoid this by enforcing Zod validation on every output before storage or actioning.
  4. Ignoring jurisdictional policy drift

    • A rule valid in one market can be illegal in another.
    • Avoid this by versioning policies per region and passing jurisdiction explicitly into every task.

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