How to Build a loan approval Agent Using CrewAI in TypeScript for wealth management

By Cyprian AaronsUpdated 2026-04-21
loan-approvalcrewaitypescriptwealth-management

A loan approval agent in wealth management is not a chatbot that says “approved” or “denied.” It is a controlled workflow agent that gathers client data, checks policy constraints, evaluates affordability and risk, and produces an auditable recommendation for a human credit officer. That matters because wealth clients expect speed, but the firm still needs compliance, explainability, and traceability on every decision.

Architecture

  • Client intake layer

    • Collects KYC/AML status, income, assets under management, liabilities, requested amount, tenor, and purpose.
    • Normalizes data into a structured payload before any agent call.
  • Policy retrieval layer

    • Pulls lending policy rules from approved internal sources.
    • Enforces product limits, jurisdiction constraints, concentration limits, and exception thresholds.
  • Risk analysis agent

    • Evaluates debt-to-income ratio, liquidity coverage, collateral quality, and portfolio concentration.
    • Produces a structured recommendation with reasons.
  • Compliance review agent

    • Checks suitability rules, KYC completeness, sanctions flags, adverse media triggers, and required disclosures.
    • Stops the workflow when mandatory fields are missing.
  • Decision orchestrator

    • Coordinates the agents in sequence.
    • Returns an approval recommendation plus an audit trail for the credit committee or RM.
  • Audit and persistence layer

    • Stores prompts, outputs, policy versions, model version, timestamps, and reviewer overrides.
    • Keeps records in the correct region for data residency requirements.

Implementation

1) Install CrewAI for TypeScript and define your domain model

Use the TypeScript SDK and keep your inputs typed. In wealth management workflows, you want compile-time checks on every field that can affect eligibility or compliance.

// package.json dependencies should include the CrewAI TS SDK
// npm install @crewaiinc/crewai zod

import { z } from "zod";

export const LoanApplicationSchema = z.object({
  clientId: z.string(),
  jurisdiction: z.string(),
  requestedAmount: z.number().positive(),
  annualIncome: z.number().nonnegative(),
  liquidAssets: z.number().nonnegative(),
  existingDebt: z.number().nonnegative(),
  creditScore: z.number().int().min(300).max(850),
  kycComplete: z.boolean(),
  amlClear: z.boolean(),
  purpose: z.string(),
});

export type LoanApplication = z.infer<typeof LoanApplicationSchema>;

2) Create specialized agents with explicit responsibilities

CrewAI works best when each agent has one job. For loan approvals, do not let one general-purpose agent make both compliance and risk calls without separation.

import { Agent } from "@crewaiinc/crewai";

export const riskAgent = new Agent({
  role: "Loan Risk Analyst",
  goal: "Assess affordability and repayment risk for wealth management lending",
  backstory:
    "You analyze income stability, debt burden, liquidity coverage, and collateral context.",
});

export const complianceAgent = new Agent({
  role: "Wealth Compliance Reviewer",
  goal: "Verify KYC/AML status and lending policy constraints before recommendation",
  backstory:
    "You enforce suitability rules, regulatory checks, and internal policy requirements.",
});

3) Build tasks with structured outputs

The key pattern is to force structured output so your downstream system can persist decisions cleanly. Use Task with explicit descriptions and expected outputs.

import { Task } from "@crewaiinc/crewai";
import { LoanApplication } from "./schema";

export function buildTasks(app: LoanApplication) {
  const complianceTask = new Task({
    description: `
Review this loan application for compliance.
Application:
${JSON.stringify(app)}
Check KYC completeness, AML clearance, jurisdiction restrictions,
and whether any mandatory information is missing.
Return JSON with fields:
status (pass|fail), reasons (string[]), blockers (string[])
`,
    agent: complianceAgent,
    expectedOutput:
      "A JSON object describing compliance status with reasons and blockers.",
  });

  const riskTask = new Task({
    description: `
Assess loan risk for this application.
Application:
${JSON.stringify(app)}
Evaluate debt-to-income pressure using annualIncome vs existingDebt,
liquidity support using liquidAssets vs requestedAmount,
and give a recommendation.
Return JSON with fields:
status (approve|review|decline), reasons (string[]), score (0-100)
`,
    agent: riskAgent,
    expectedOutput:
      "A JSON object describing risk score and recommendation.",
    context: [complianceTask],
  });

  return { complianceTask, riskTask };
}

4) Orchestrate the crew and produce an auditable result

The orchestration step should be deterministic around policy gates. If compliance fails, do not even ask the risk model to “talk it out.”

import { Crew } from "@crewaiinc/crewai";
import { LoanApplicationSchema } from "./schema";
import { buildTasks } from "./tasks";

export async function evaluateLoan(input: unknown) {
  const app = LoanApplicationSchema.parse(input);
  const { complianceTask, riskTask } = buildTasks(app);

  const crew = new Crew({
    agents: [complianceAgent, riskAgent],
    tasks: [complianceTask, riskTask],
    verbose: true,
    process: "sequential",
  });

  
   const result = await crew.kickoff();

   return {
     clientId: app.clientId,
     jurisdiction: app.jurisdiction,
     decisionArtifact: result,
     auditMeta: {
       modelProvider: "CrewAI",
       workflowVersion: "loan-approval-v1",
       kycComplete: app.kycComplete,
       amlClear: app.amlClear,
     },
   };
}

In production you would persist result alongside policy versioning and reviewer overrides. That gives you a complete audit trail when a client disputes why a facility was declined or escalated.

Production Considerations

  • Deployment

    • Run the agent behind an internal API gateway with mTLS and per-request auth.
    • Keep inference endpoints in-region to satisfy data residency requirements for client financial data.
  • Monitoring

    • Log task-level outputs separately for compliance review and model drift analysis.
    • Track decline rates by jurisdiction, RM team, product type, and exception path.
  • Guardrails

    • Block approvals when kycComplete or amlClear is false.
    • Require human review above configurable exposure thresholds or when asset concentration exceeds policy limits.
  • Auditability

    • Store prompt text, task output JSON, policy snapshot ID, timestamp, operator ID, and final human override.
    • Never overwrite prior decision artifacts; append revisions only.

Common Pitfalls

  • Using one agent for everything

    This turns your workflow into an untestable blob. Split compliance from risk so each control can be validated independently.

  • Letting free-form text drive decisions

    If the output is prose instead of structured JSON, you will end up parsing opinions in production. Force schema-shaped outputs at every task boundary.

  • Ignoring residency and retention rules

    Wealth management data often falls under stricter storage rules than standard retail lending data. Keep records in approved regions and align retention with legal/compliance policy.


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