How to Build a underwriting Agent Using AutoGen in Python for investment banking
A underwriting agent in investment banking takes a deal package, extracts the key facts, checks them against internal policy and market assumptions, and produces a draft credit or underwriting recommendation with evidence attached. It matters because bankers spend too much time on repetitive document review, and the real risk is not speed — it is inconsistent judgment, missing controls, and weak auditability.
Architecture
- •User proxy layer:
autogen.UserProxyAgentto receive banker input, trigger execution, and enforce human approval before any external action. - •Document analyst agent:
autogen.AssistantAgentthat reads term sheets, CIMs, issuer financials, and extracts structured deal facts. - •Policy/compliance agent: another
AssistantAgentthat checks the extracted facts against underwriting policy, KYC/AML flags, concentration limits, and jurisdiction rules. - •Risk synthesis agent: an
AssistantAgentthat scores the deal, highlights red flags, and drafts the underwriting memo. - •Tooling layer: Python functions exposed through AutoGen for fetching approved internal data, calculating ratios, and logging decisions.
- •Audit store: immutable logging of prompts, tool calls, outputs, and human approvals for model risk management and regulatory review.
Implementation
1) Install AutoGen and define your tools
Use the current AutoGen package that exposes AssistantAgent and UserProxyAgent. Keep tools deterministic; underwriting is not the place for free-form “smart” calculations.
pip install pyautogen
from autogen import AssistantAgent, UserProxyAgent
from typing import Dict
def calc_interest_coverage(ebitda: float, interest_expense: float) -> float:
if interest_expense == 0:
raise ValueError("interest_expense cannot be zero")
return round(ebitda / interest_expense, 2)
def check_concentration_limit(exposure: float, limit: float = 50_000_000) -> bool:
return exposure <= limit
def get_policy_summary() -> str:
return (
"Underwriting policy: require minimum interest coverage of 3.0x, "
"flag leverage above 5.0x EBITDA, require KYC complete, "
"and escalate any cross-border data transfer."
)
2) Create agents with clear responsibilities
The key pattern is separation of duties. The analyst extracts facts; the compliance agent evaluates them; the user proxy controls execution and approval.
llm_config = {
"config_list": [
{
"model": "gpt-4o-mini",
"api_key": "YOUR_OPENAI_API_KEY",
}
],
"temperature": 0,
}
analyst = AssistantAgent(
name="deal_analyst",
llm_config=llm_config,
system_message=(
"You extract underwriting facts from deal materials. "
"Return concise JSON-like fields with revenue, EBITDA, debt, leverage, "
"interest expense, sector, jurisdiction, and any missing items."
),
)
compliance = AssistantAgent(
name="policy_checker",
llm_config=llm_config,
system_message=(
"You evaluate underwriting facts against policy. "
"Call out KYC/AML issues, concentration risk, residency concerns, "
"and any breaches of underwriting thresholds."
),
)
user_proxy = UserProxyAgent(
name="banker",
human_input_mode="ALWAYS",
code_execution_config=False,
)
3) Register tools and run a controlled multi-agent flow
This is where AutoGen becomes useful. Let the agents reason over the facts while your Python functions handle calculations and policy lookups.
analyst.register_for_llm(name="calc_interest_coverage", description="Calculate interest coverage ratio")(calc_interest_coverage)
analyst.register_for_llm(name="check_concentration_limit", description="Check exposure against limit")(check_concentration_limit)
compliance.register_for_llm(name="get_policy_summary", description="Return underwriting policy summary")(get_policy_summary)
user_proxy.register_for_execution(name="calc_interest_coverage")(calc_interest_coverage)
user_proxy.register_for_execution(name="check_concentration_limit")(check_concentration_limit)
user_proxy.register_for_execution(name="get_policy_summary")(get_policy_summary)
deal_materials = """
Issuer: Northwind Industrial Holdings
Jurisdiction: UK
Revenue: 420000000
EBITDA: 78000000
Debt: 260000000
Interest Expense: 24000000
Requested Exposure: 60000000
KYC Status: complete
"""
chat_result = user_proxy.initiate_chat(
analyst,
message=(
f"Extract underwriting facts from this deal package:\n{deal_materials}\n"
f"Then calculate interest coverage using calc_interest_coverage."
),
)
print(chat_result.summary)
For production use in banking workflows, you usually chain the output into a second review step:
facts = """
Revenue=420000000; EBITDA=78000000; Debt=260000000;
InterestExpense=24000000; Exposure=60000000; KYC=complete; Jurisdiction=UK
"""
review = user_proxy.initiate_chat(
compliance,
message=(
f"Review these underwriting facts:\n{facts}\n"
f"Use this policy:\n{get_policy_summary()}\n"
f"Return only risks, breaches, and approval recommendation."
),
)
print(review.summary)
4) Add an approval gate before anything leaves the desk
Underwriting recommendations should never auto-send to clients or committees without banker sign-off. Use UserProxyAgent as the final control point.
- •Banker reviews extracted facts.
- •Banker approves or edits the memo.
- •System writes prompt/output/tool logs to immutable storage.
- •Only then does the agent generate a committee-ready draft.
Production Considerations
- •
Auditability
- •Log every prompt, tool call, model output, and human override with timestamps and case IDs.
- •Store immutable records for model risk review and regulatory exams.
- •
Data residency
- •Keep issuer documents and extracted features in-region if you are handling EU/UK or other restricted datasets.
- •Do not send raw confidential materials to endpoints outside approved jurisdictions.
- •
Guardrails
- •Force deterministic tools for ratios and thresholds.
- •Block unsupported actions like client-facing commitments or legal conclusions.
- •Require explicit human approval for any recommendation above materiality thresholds.
- •
Monitoring
- •Track extraction accuracy on sampled deals.
- •Monitor false positives on compliance flags and drift in model outputs by sector.
- •Alert when an agent produces missing citations or inconsistent leverage math.
Common Pitfalls
- •
Letting the LLM do arithmetic
- •Don’t ask the model to compute leverage or coverage ratios from scratch in prose.
- •Put those calculations in Python tools so results are stable and auditable.
- •
Mixing analysis with approval
- •Don’t let one agent both assess risk and approve the deal.
- •Separate analyst logic from compliance review and keep a human approval step at the end.
- •
Ignoring document provenance
- •Don’t accept extracted numbers without source traceability.
- •Attach page references or section references from term sheets and financial statements so reviewers can verify every material field.
If you build it this way, AutoGen gives you orchestration without giving up control. That is the right tradeoff for investment banking: structured automation on top of hard compliance boundaries.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
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