How to Build a loan approval Agent Using AutoGen in TypeScript for retail banking

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

A loan approval agent in retail banking automates the first pass of a credit application: it collects applicant details, checks policy rules, summarizes risk, and prepares a recommendation for a human underwriter. It matters because retail banks need faster turnaround without losing control over compliance, auditability, and consistent decisioning.

Architecture

  • Applicant intake service

    • Receives application data from the web app or branch system.
    • Normalizes fields like income, employment status, existing obligations, and requested amount.
  • Policy and eligibility engine

    • Applies deterministic rules before any LLM call.
    • Handles hard rejects such as age limits, debt-to-income thresholds, missing documents, and product-specific constraints.
  • AutoGen agent team

    • Uses AssistantAgent instances to reason over the application.
    • One agent can summarize the case, another can critique the recommendation, and a final agent can produce an underwriting memo.
  • Tool layer

    • Exposes bank-approved functions for credit bureau lookup, affordability calculation, document verification, and sanctions/AML screening.
    • Keeps sensitive operations outside free-form model output.
  • Audit and case management store

    • Persists every input, tool call, intermediate response, and final recommendation.
    • Required for model governance, explainability, and regulator review.

Implementation

1) Install AutoGen and define your case model

Use the TypeScript AutoGen package that exposes AssistantAgent, UserProxyAgent, and GroupChatManager. Keep your domain model strict so you can validate inputs before they reach the agents.

npm install @autogenai/autogen zod
import { z } from "zod";

export const LoanApplicationSchema = z.object({
  applicantId: z.string(),
  fullName: z.string(),
  annualIncome: z.number().nonnegative(),
  monthlyDebt: z.number().nonnegative(),
  requestedAmount: z.number().positive(),
  termMonths: z.number().int().positive(),
  employmentStatus: z.enum(["employed", "self_employed", "contract", "unemployed"]),
  residencyCountry: z.string(),
  consentToCreditCheck: z.boolean(),
});

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

This is not optional. In retail banking, bad input is not just a bug; it becomes an audit issue when a decision trace cannot explain why a field was accepted.

2) Add deterministic pre-checks before the LLM

Do not ask an agent to discover basic eligibility rules from scratch. Hard rules should run first so the model only handles judgment calls and narrative generation.

import { LoanApplication } from "./schema";

export function precheck(app: LoanApplication) {
  if (!app.consentToCreditCheck) {
    return { eligible: false, reason: "Missing consent for credit bureau check" };
  }

  const dti = app.monthlyDebt / (app.annualIncome / 12);
  if (dti > 0.45) {
    return { eligible: false, reason: `DTI too high: ${dti.toFixed(2)}` };
  }

  if (app.residencyCountry !== "ZA") {
    return { eligible: false, reason: "Out of jurisdiction for this product" };
  }

  return { eligible: true as const, dti };
}

This pattern reduces hallucination risk and gives compliance teams a clear separation between policy logic and AI reasoning.

3) Build the AutoGen agents and wire in tools

Here is the core pattern. The AssistantAgent produces a recommendation; the UserProxyAgent represents your system or analyst; and tools are exposed through function calls you control.

import { AssistantAgent, UserProxyAgent } from "@autogenai/autogen";

const underwritingAgent = new AssistantAgent({
  name: "underwriting_agent",
  systemMessage: [
    "You are a retail banking loan underwriting assistant.",
    "Use only provided application data and tool outputs.",
    "Never approve loans that violate policy constraints.",
    "Return a concise recommendation with reasons and risks."
  ].join(" "),
});

const reviewerAgent = new AssistantAgent({
  name: "reviewer_agent",
  systemMessage:
    "You critique underwriting recommendations for policy gaps, missing evidence, or weak reasoning.",
});

const analyst = new UserProxyAgent({
  name: "bank_system",
});

async function getCreditSummary(applicantId: string) {
  // Replace with internal service call
  return {
    bureauScore: 712,
    delinquenciesLast24M: 0,
    utilizationPct: 34,
    adverseFlags: [],
    applicantId,
  };
}

async function runUnderwritingCase(applicationText: string) {
  const result = await underwritingAgent.initiateChat(
    analyst,
    applicationText
      ? `Assess this loan application:\n${applicationText}`
      : "No application provided."
      ,
    {
      maxRound: 3,
      tools: [
        {
          name: "getCreditSummary",
          description: "Fetch bureau summary for an applicant",
          parameters: {
            type: "object",
            properties: { applicantId: { type: "string" } },
            required: ["applicantId"],
          },
          execute: async ({ applicantId }: { applicantId: string }) =>
            JSON.stringify(await getCreditSummary(applicantId)),
        },
      ],
    }
  );

  return result;
}

The exact method names may vary by package version, but the working pattern is stable across AutoGen TypeScript builds:

  • create agents with new AssistantAgent(...)
  • drive the interaction with initiateChat(...)
  • keep external banking systems behind explicit tool boundaries

4) Orchestrate human review on borderline cases

Retail banking should not fully automate every approval. Use a second agent or an analyst workflow when policy is ambiguous or confidence is low.

async function routeCase(appraisalScore?: number) {
	if ((appraisalScore ?? 0) < threshold) {
		return {
			nextStep:
				"HUMAN_REVIEW",
			reason:
				"Borderline case requires underwriter approval"
		};
	}

	return {
		nextStep:
			"AUTO_RECOMMENDATION"
	};
}

In practice, send only non-sensitive summaries to the reviewer unless your jurisdiction and data residency controls explicitly allow more. For cross-border deployments, keep PII in-region and pass tokenized references into the agent layer.

Production Considerations

  • Data residency

Keep applicant PII inside the region where it was collected. If your bank operates across multiple jurisdictions, deploy separate inference endpoints per region and never route raw loan data through an out-of-region model endpoint.

  • Audit logging

Log every prompt, tool call, tool response, final recommendation, timestamp, model version, and policy version. Regulators will ask how a decision was made months later; if you cannot reconstruct it exactly, you do not have a production system.

  • Guardrails

Use hard validation before any agent call:

  • income ranges
  • DTI thresholds
  • consent checks
  • sanctions/AML screening status
  • document completeness

If any of these fail, short-circuit to rejection or manual review without asking the model to “reason it out.”

  • Monitoring

Track approval rate drift, manual override rate, false positives on fraud flags, latency per case, and tool failure rate. A sudden shift in approvals by branch region or channel is usually an upstream data issue or policy regression.

Common Pitfalls

  1. Letting the model make policy decisions

    • Mistake: asking the agent to decide whether a borrower meets minimum criteria.
    • Fix: encode eligibility rules in deterministic code first; use AutoGen for narrative assessment and exception handling.
  2. Passing raw PII into every agent turn

    • Mistake: dumping full identity records into prompts.
    • Fix: tokenize sensitive fields early and only resolve them inside approved tools when absolutely necessary.
  3. Skipping versioned policies

    • Mistake: changing underwriting thresholds without tracking which applications used which rules.
    • Fix: version your policy engine separately from your prompt templates and persist both in the case record.

A loan approval agent only works in retail banking when it behaves like part of a controlled decisioning pipeline. AutoGen gives you multi-agent orchestration; your job is to wrap it in strict validation, auditable tools, jurisdiction-aware deployment boundaries, and human override paths where risk demands it.


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