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

By Cyprian AaronsUpdated 2026-04-21
loan-approvalcrewaipythonbanking

A loan approval agent automates the first pass of lending decisions: it collects applicant data, checks policy rules, assesses risk signals, and produces a recommendation with an audit trail. In banking, this matters because it reduces manual review time without removing control, and it gives compliance teams a traceable decision path instead of a black box.

Architecture

  • Application intake tool

    • Pulls structured borrower data from CRM, LOS, PDFs, or internal APIs.
    • Normalizes fields like income, DTI, employment status, and requested amount.
  • Policy evaluation agent

    • Checks hard rules: minimum credit score, max debt-to-income ratio, residency constraints, product eligibility.
    • Flags cases that must be rejected or escalated.
  • Risk analysis agent

    • Summarizes credit history, affordability, exposure concentration, and fraud indicators.
    • Produces a risk note for the final decision maker.
  • Compliance reviewer agent

    • Verifies required disclosures, adverse action triggers, KYC/AML checks, and fair lending constraints.
    • Ensures the output is explainable and auditable.
  • Decision orchestrator

    • Combines outputs from the specialist agents.
    • Produces one of three outcomes: approve, reject, or manual review.
  • Audit logger

    • Stores inputs, intermediate reasoning summaries, tool outputs, and final recommendation.
    • Supports model governance and regulatory review.

Implementation

1) Define the agents with narrow responsibilities

Use separate agents for policy checks, risk analysis, and compliance review. In banking systems, narrow scope is safer than one general-purpose agent making all decisions.

from crewai import Agent

policy_agent = Agent(
    role="Loan Policy Analyst",
    goal="Evaluate loan applications against bank lending policy and return a clear eligibility result.",
    backstory=(
        "You are a strict lending policy analyst for a regulated bank. "
        "You only approve applications that satisfy documented policy rules."
    ),
    verbose=True,
    allow_delegation=False,
)

risk_agent = Agent(
    role="Credit Risk Analyst",
    goal="Assess borrower risk using provided application data and summarize key risk factors.",
    backstory=(
        "You analyze affordability, repayment capacity, and credit risk for consumer loans."
    ),
    verbose=True,
    allow_delegation=False,
)

compliance_agent = Agent(
    role="Compliance Reviewer",
    goal="Check the application output for regulatory issues and explainability requirements.",
    backstory=(
        "You review lending decisions for fairness, auditability, and policy adherence."
    ),
    verbose=True,
    allow_delegation=False,
)

2) Create tasks with explicit banking instructions

Each task should return structured text that downstream systems can parse. Avoid free-form prose only; your operations team will need consistent outputs for logging and human review.

from crewai import Task

policy_task = Task(
    description=(
        "Review this loan application against bank policy.\n"
        "Applicant: {applicant_json}\n\n"
        "Return:\n"
        "- eligibility: approved/rejected/manual_review\n"
        "- reason_codes: list of short codes\n"
        "- summary: one paragraph\n"
        "Do not invent missing data."
    ),
    expected_output="A structured eligibility assessment with reason codes.",
    agent=policy_agent,
)

risk_task = Task(
    description=(
        "Assess credit risk using the same application data.\n"
        "Focus on income stability, debt-to-income ratio, existing obligations,\n"
        "and any obvious repayment concerns.\n"
        "Return a concise risk summary and key drivers."
    ),
    expected_output="A concise credit risk assessment with key drivers.",
    agent=risk_agent,
)

compliance_task = Task(
    description=(
        "Review the proposed decision for compliance concerns.\n"
        "Check for missing disclosures, explainability gaps,\n"
        "fair lending concerns, and any need for manual review.\n"
        "Return compliance_status and notes."
    ),
    expected_output="A compliance review with status and notes.",
    agent=compliance_agent,
)

3) Orchestrate the crew and run the workflow

CrewAI’s Crew class coordinates execution. For loan approval workflows, start with sequential execution so each step is deterministic and auditable.

from crewai import Crew, Process

loan_crew = Crew(
    agents=[policy_agent, risk_agent, compliance_agent],
    tasks=[policy_task, risk_task, compliance_task],
    process=Process.sequential,
    verbose=True,
)

application = {
    "applicant_json": """
{
  "applicant_id": "A-10482",
  "loan_amount": 25000,
  "annual_income": 92000,
  "monthly_debt": 1100,
  "credit_score": 721,
  "employment_years": 4,
  "residency_country": "US",
  "product": "personal_loan"
}
"""
}

result = loan_crew.kickoff(inputs=application)
print(result)

That pattern gives you one execution path per application. In production you would wrap kickoff() in your service layer and persist the output to an audit store before returning a recommendation to the LOS.

4) Add a deterministic decision layer outside the LLM

Do not let the model make the final binding decision alone. Use the crew output as input to a rule engine or human review queue so policy remains under bank control.

def finalize_decision(policy_output: str, compliance_output: str) -> str:
    combined = f"{policy_output}\n{compliance_output}".lower()

    if "rejected" in combined:
        return "reject"
    if "manual_review" in combined or "manual review" in combined:
        return "manual_review"
    if "non-compliant" in combined or "fair lending concern" in combined:
        return "manual_review"

    return "approve"

decision = finalize_decision(str(result), str(result))
print({"final_decision": decision})

Production Considerations

  • Keep sensitive data inside your residency boundary

    • If your bank requires regional processing, run CrewAI workers in-region and avoid sending PII to external endpoints.
    • Mask account numbers, SSNs/NINs, salary slips, and addresses before passing context to agents.
  • Persist every step for audit

    • Store input payloads, task outputs, timestamps, model version IDs, prompt versions, and final decision.
    • Regulators care about why a loan was approved or denied months later.
  • Add guardrails before production traffic

    • Enforce schema validation on inputs.
    • Block unsupported products or jurisdictions before calling kickoff().
    • Require human approval for borderline cases like thin-file borrowers or high-risk segments.
  • Monitor drift and failure modes

    • Track approval rates by segment.
    • Watch for spikes in manual review or rejection rates after prompt changes.
    • Compare agent recommendations against historical underwriter decisions.

Common Pitfalls

  • Using one agent to do everything

    • This creates weak controls and messy reasoning.
    • Split policy, risk, and compliance into separate agents with no delegation.
  • Letting free-form output drive automation

    • Natural language alone is hard to validate.
    • Require structured fields like eligibility, reason_codes, and compliance_status.
  • Skipping human-in-the-loop escalation

    • Edge cases will happen: incomplete documents, conflicting bureau data, fraud signals.
    • Route those cases to manual review instead of forcing an automated answer.
  • Ignoring explainability requirements

    • “The model said no” is not acceptable in banking.
    • Keep reason codes tied to explicit policy thresholds so adverse action notices can be generated cleanly.

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