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

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

A loan approval agent in investment banking is not a chatbot that says “approved” or “rejected.” It is a controlled workflow agent that gathers borrower data, checks policy, scores risk, flags compliance issues, and packages a decision for human review or downstream systems. That matters because loan origination in banking is constrained by auditability, model governance, and regulatory controls, not just accuracy.

Architecture

  • Ingress layer

    • Accepts borrower application data from CRM, LOS, or internal APIs.
    • Normalizes fields like income, leverage ratio, collateral value, and jurisdiction.
  • Policy retrieval layer

    • Pulls underwriting rules, credit policy, and product constraints from approved internal sources.
    • Keeps the agent grounded in bank-specific policy instead of free-form reasoning.
  • Agent team

    • A planner/manager coordinates the workflow.
    • A risk analyst agent evaluates financial ratios and covenant breaches.
    • A compliance agent checks KYC/AML, sanctions, suitability, and jurisdictional restrictions.
    • A credit memo agent drafts a decision summary for human underwriters.
  • Tooling layer

    • Functions for credit scoring, document lookup, and policy search.
    • Deterministic tools are better than letting the model infer numbers.
  • Audit and observability

    • Stores prompts, tool calls, intermediate outputs, final recommendation, and approver identity.
    • Required for model risk management and post-trade / post-credit review.
  • Human approval gate

    • Routes borderline or high-risk cases to an underwriter.
    • Prevents autonomous approvals where policy requires maker-checker controls.

Implementation

1) Install AutoGen and define your bank-safe configuration

Use AutoGen’s agent classes directly. For most production setups, AssistantAgent handles specialized roles and UserProxyAgent acts as the orchestrator or human-in-the-loop boundary.

pip install pyautogen
import os
from autogen import AssistantAgent, UserProxyAgent

llm_config = {
    "config_list": [
        {
            "model": "gpt-4o-mini",
            "api_key": os.environ["OPENAI_API_KEY"],
        }
    ],
    "temperature": 0,
}

def no_code_execution(*args, **kwargs):
    return False

manager = UserProxyAgent(
    name="manager",
    human_input_mode="NEVER",
    code_execution_config=False,
)

risk_agent = AssistantAgent(
    name="risk_analyst",
    llm_config=llm_config,
)

compliance_agent = AssistantAgent(
    name="compliance_officer",
    llm_config=llm_config,
)

memo_agent = AssistantAgent(
    name="credit_memo_writer",
    llm_config=llm_config,
)

Keep temperature=0 for underwriting workflows. You want stable outputs for the same input set because reproducibility matters in audit reviews.

2) Add deterministic tools for policy checks

Do not ask the model to calculate debt service coverage ratio from scratch if you can compute it in Python. Use tools for hard checks and let the agents interpret results.

def calculate_dscr(net_operating_income: float, annual_debt_service: float) -> float:
    if annual_debt_service == 0:
        return float("inf")
    return round(net_operating_income / annual_debt_service, 2)

def check_ltv(loan_amount: float, collateral_value: float) -> float:
    if collateral_value == 0:
        return float("inf")
    return round(loan_amount / collateral_value, 2)

def underwriting_rules(application: dict) -> dict:
    dscr = calculate_dscr(
        application["net_operating_income"],
        application["annual_debt_service"],
    )
    ltv = check_ltv(application["loan_amount"], application["collateral_value"])

    return {
        "dscr": dscr,
        "ltv": ltv,
        "min_dscr_pass": dscr >= 1.25,
        "max_ltv_pass": ltv <= 0.75,
        "kyc_pass": application["kyc_status"] == "verified",
        "sanctions_pass": application["sanctions_hit"] is False,
        "jurisdiction_ok": application["country"] in {"US", "UK", "SG"},
    }

This gives you deterministic underwriting evidence. The LLM should explain the result and spot contradictions, not invent ratios.

3) Orchestrate the multi-agent review

A simple pattern is: manager sends the case to risk and compliance agents first; then a memo writer summarizes the outcome. In AutoGen terms, initiate_chat() starts the interaction.

application = {
    "borrower_name": "Acme Holdings Ltd",
    "loan_amount": 5000000,
    "collateral_value": 8000000,
    "net_operating_income": 1200000,
    "annual_debt_service": 850000,
    "kyc_status": "verified",
    "sanctions_hit": False,
    "country": "US",
}

rules = underwriting_rules(application)

risk_prompt = f"""
Review this loan application from a credit risk perspective.
Application: {application}
Policy results: {rules}
Return only your risk assessment with key concerns.
"""

compliance_prompt = f"""
Review this loan application for compliance issues.
Application: {application}
Policy results: {rules}
Focus on KYC/AML/sanctions/jurisdiction concerns.
Return only your compliance assessment.
"""

risk_result = manager.initiate_chat(risk_agent, message=risk_prompt)
compliance_result = manager.initiate_chat(compliance_agent, message=compliance_prompt)

memo_prompt = f"""
Draft a concise credit memo using these assessments:

Risk assessment:
{risk_result.summary}

Compliance assessment:
{compliance_result.summary}

Policy results:
{rules}

State one of: APPROVE_FOR_REVIEW, DECLINE, ESCALATE.
"""
memo_result = manager.initiate_chat(memo_agent, message=memo_prompt)

print(memo_result.summary)

This pattern works because each agent has one job. Risk does not decide sanctions exposure; compliance does not re-score leverage. That separation maps cleanly to banking controls.

4) Add a decision gate before any downstream action

Never let an LLM directly trigger booking or disbursement. Convert its output into a controlled decision object and require explicit approval thresholds.

def final_decision(rules: dict, memo_text: str) -> str:
    if not rules["kyc_pass"] or not rules["sanctions_pass"] or not rules["jurisdiction_ok"]:
        return "DECLINE"
    if rules["min_dscr_pass"] and rules["max_ltv_pass"]:
        return "APPROVE_FOR_HUMAN_REVIEW"
    return "ESCALATE"

decision = final_decision(rules, memo_result.summary)
print({"decision": decision})

In investment banking workflows, “approve” usually means “approve for committee or underwriter,” not automatic booking. Keep that distinction explicit in code and logs.

Production Considerations

  • Audit logging

    • Persist raw inputs, normalized inputs, tool outputs, prompt versions, model version, timestamps, and final disposition.
    • Store immutable records in an audit store that meets retention requirements.
  • Data residency

    • Keep borrower PII and financial statements inside approved regions.
    • If your bank has regional processing rules, route requests to region-specific model endpoints or self-hosted inference.
  • Guardrails

    • Block autonomous approval on high-value loans above threshold limits.
    • Hard-fail on sanctions hits, missing KYC status, expired documents, or unsupported jurisdictions.
  • Monitoring

    • Track false approvals/declines by segment: geography, industry sector, deal size.
    • Watch for prompt drift when policy text changes or new products are introduced.

Common Pitfalls

  • Letting the model do arithmetic

    • Mistake: asking the LLM to calculate DSCR or LTV from raw numbers.
    • Fix: compute ratios in Python tools and pass results back to agents.
  • No separation between compliance and risk

    • Mistake: one agent decides everything.
    • Fix: split responsibilities so each agent has one control domain.
  • Using free-form outputs in production

    • Mistake: parsing natural language directly into booking actions.
    • Fix: force structured decisions like DECLINE, ESCALATE, or APPROVE_FOR_HUMAN_REVIEW.
  • Ignoring governance requirements

    • Mistake: deploying without audit trails or data residency controls.
    • Fix: treat every run as a regulated event with traceable inputs and outputs.

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