How to Build a loan approval Agent Using CrewAI in TypeScript for investment banking

By Cyprian AaronsUpdated 2026-04-21
loan-approvalcrewaitypescriptinvestment-banking

A loan approval agent in investment banking takes a deal package, extracts the borrower’s financials, checks policy and compliance constraints, scores risk, and produces a decision memo with an audit trail. It matters because bankers need faster credit turnaround without losing control over KYC, AML, policy exceptions, and model governance.

Architecture

  • Input ingestion layer

    • Pulls borrower documents from internal systems: PDFs, financial statements, credit memos, KYC files.
    • Normalizes text into structured fields the agents can reason over.
  • Policy and compliance agent

    • Checks mandatory conditions: KYC status, sanctions screening, beneficial ownership completeness, jurisdiction restrictions.
    • Flags exceptions that require human approval.
  • Credit analysis agent

    • Reviews leverage, debt service coverage ratio, liquidity, covenant headroom, and historical performance.
    • Produces a structured risk summary instead of free-form commentary.
  • Decision orchestration layer

    • Uses CrewAI to coordinate tasks across analysts and produce a final recommendation.
    • Keeps each step isolated for auditability.
  • Audit and evidence store

    • Persists inputs, intermediate outputs, model versions, timestamps, and final recommendation.
    • Required for internal model risk management and regulator review.
  • Human approval checkpoint

    • Routes borderline cases to a banker or credit officer.
    • Prevents the agent from making binding decisions on its own.

Implementation

1) Set up the CrewAI project in TypeScript

Use the TypeScript package and configure your LLM provider through environment variables. For investment banking workloads, keep credentials out of code and route all logs to your controlled environment.

npm init -y
npm install @crewai/crewai zod dotenv

Create a minimal entry point:

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

const analyst = new Agent({
  role: "Credit Analyst",
  goal: "Assess loan applications against bank policy and risk criteria",
  backstory:
    "You are a senior credit analyst at an investment bank. You evaluate leverage, liquidity, covenants, KYC status, and repayment capacity.",
});

const compliance = new Agent({
  role: "Compliance Officer",
  goal: "Validate the application against AML/KYC and lending policy",
  backstory:
    "You enforce sanctions checks, jurisdiction rules, beneficial ownership completeness, and escalation thresholds.",
});

const decisionTask = new Task({
  description:
    "Review the borrower package and produce a structured loan approval recommendation with reasons and exceptions.",
  expectedOutput:
    "A JSON-like recommendation containing approve/reject/refer_to_human plus rationale.",
  agent: analyst,
});

const crew = new Crew({
  agents: [analyst, compliance],
  tasks: [decisionTask],
});

async function main() {
  const result = await crew.kickoff();
  console.log(result);
}

main().catch(console.error);

This is the core pattern: define narrow roles, assign explicit tasks, then run the crew with kickoff(). In practice you will wire this to your document pipeline and persist every task output.

2) Add structured inputs and hard validation

Do not feed raw PDFs directly into the decision task. Convert them into a normalized application object first so the agent sees stable fields like revenue, EBITDA, requested amount, entity type, country of incorporation, and KYC status.

import { z } from "zod";

const LoanApplicationSchema = z.object({
  borrowerName: z.string(),
  countryOfIncorporation: z.string(),
  requestedAmountUSD: z.number().positive(),
  annualRevenueUSD: z.number().nonnegative(),
  ebitdaUSD: z.number(),
  totalDebtUSD: z.number().nonnegative(),
  kycComplete: z.boolean(),
});

type LoanApplication = z.infer<typeof LoanApplicationSchema>;

const application: LoanApplication = LoanApplicationSchema.parse({
  borrowerName: "Northstar Capital Ltd",
  countryOfIncorporation: "UK",
  requestedAmountUSD: 25000000,
  annualRevenueUSD: 180000000,
  ebitdaUSD: 42000000,
  totalDebtUSD: 98000000,
  kycComplete: true,
});

This gives you deterministic validation before any model call. If the data is incomplete or malformed, fail early instead of letting the agent infer missing facts.

3) Orchestrate separate analysis tasks for compliance and credit

Split compliance from credit. That separation matters because investment banking teams need to show that policy checks were performed independently from commercial judgment.

import { Agent, Task, Crew } from "@crewai/crewai";

const creditAgent = new Agent({
  role: "Credit Analyst",
  goal: "Assess repayment capacity and risk metrics",
});

const complianceAgent = new Agent({
  role: "Compliance Officer",
  goal: "Check AML/KYC and lending policy constraints",
});

const creditTask = new Task({
  description:
    `Evaluate this application for credit quality:
     Borrower: ${application.borrowerName}
     Revenue USD: ${application.annualRevenueUSD}
     EBITDA USD: ${application.ebitdaUSD}
     Debt USD: ${application.totalDebtUSD}
     Requested USD: ${application.requestedAmountUSD}`,
  expectedOutput:
    "Return leverage assessment, DSCR commentary if possible from provided data, key risks, and whether it should be approved or escalated.",
});

const complianceTask = new Task({
    description:
      `Validate compliance readiness for:
       Borrower country: ${application.countryOfIncorporation}
       KYC complete: ${application.kycComplete}`,
    expectedOutput:
      "Return pass/fail on KYC readiness plus any policy or residency concerns.",
});

creditTask.agent = creditAgent;
complianceTask.agent = complianceAgent;

const crew = new Crew({
    agents: [creditAgent, complianceAgent],
    tasks: [creditTask, complianceTask],
});

const output = await crew.kickoff();
console.log(output);

The pattern here is simple but effective:

  • Compliance task runs with narrow scope.
  • Credit task focuses on economics.
  • Final human review combines both outputs before any binding action.

###4) Add a final decision gate

For production use in banking you want “recommendation only,” not autonomous execution. The final step should synthesize results into one of three states:

  • approve
  • reject
  • refer_to_human

That gate should be rule-based around thresholds such as missing KYC, restricted jurisdictions, high leverage multiples, or policy exceptions. Keep it outside the model so it stays deterministic under audit.

Production Considerations

  • Data residency

Use region-bound infrastructure for document storage and model calls. If borrower data cannot leave a specific jurisdiction or cloud region, enforce that at the network boundary before it reaches CrewAI.

  • Auditability

Persist every prompt input, task output, tool call result, model version, timestamped decision path. Internal audit will ask who saw what data and why the recommendation was made.

  • Guardrails

Block decisions when mandatory fields are missing or when sanctions/KYC checks are inconclusive. The agent should escalate uncertainty instead of guessing.

  • Monitoring

Track approval rates by segment, exception rates by banker desk, latency per task, and drift in recommendation patterns. In investment banking you also want alerts when outputs change after prompt or model updates.

Common Pitfalls

  1. Letting one agent do everything

    • This turns your workflow into an opaque chat session.
    • Fix it by splitting compliance、credit analysis、and final decisioning into separate tasks with clear outputs.
  2. Skipping structured validation

    • If you pass messy source documents straight to the model,you will get inconsistent decisions.
    • Fix it with schema validation using Zod before calling Crew or Task.
  3. Treating recommendations as approvals

    • A loan approval agent should not bypass human credit authority in investment banking.
    • Fix it by enforcing a mandatory reviewer step for exceptions,large exposures,and any case with incomplete KYC or policy ambiguity。

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