bhattyuvraj22/loan-underwriting-env
π€ Live on Hugging Face: https://huggingface.co/spaces/bhattyuvraj22/loan-underwriting-env
π Overview
Mortgage underwriting is a high-stakes, rule-governed decision process performed daily by human officers at banks and lenders. This environment simulates that exact workflow, giving AI agents the same data a real underwriter sees and scoring them on the same criteria a real lender would use.
An agent must:
- Compute DTI (Debt-to-Income) and LTV (Loan-to-Value) ratios
- Apply policy rules to approve, reject, or escalate each applicant
- Assign accurate interest rates for approved applicants
- Identify all applicable risk flags
- Manage portfolio constraints (capital budgets, risk concentration caps)
This makes it an ideal benchmark for structured financial reasoning β rules are explicit and deterministic, but edge cases (borderline DTI, fraud detection, thin files) challenge even frontier models.
π― Tasks
Scoring Breakdown
<details> <summary><b>Task 1 β Easy (click to expand)</b></summary>
</details>
<details> <summary><b>Task 2 β Medium (click to expand)</b></summary>
</details>
<details> <summary><b>Task 3 β Hard (click to expand)</b></summary>
</details>
π Baseline Scores
Measured withgpt-4o,seed=42,temperature=0
π² Random agent:~0.10β0.30 | π All-escalate agent:~0.45β0.65
π Observation Space
Returned by POST /reset and GET /state:
{
"task_id": "task_1_easy",
"step": 0,
"max_steps": 1,
"done": false,
"message": "Episode started. Submit decisions for all applicants in context.applicants.",
"context": {
"applicants": [
{
"applicant_id": "APP-4821-00",
"annual_income": 95000,
"monthly_debt": 1200,
"credit_score": 710,
"loan_amount": 320000,
"property_value": 400000,
"employment_years": 4.5,
"employment_type": "salaried",
"prior_default": false,
"fraud_flag": false,
"income_verified": true
}
],
"policy": "ESCALATE if fraud_flag OR income_verified=false OR prior_default OR 0.40<=DTI<=0.45..."
}
}β‘ Action Space
Submitted to POST /step:
{
"task_id": "task_1_easy",
"decisions": [
{
"applicant_id": "APP-4821-00",
"decision": "approve",
"interest_rate": 7.18,
"risk_flags": ["high_ltv"],
"reasoning": "DTI=0.1516 LTV=0.8000 => approve. Rate=6.60."
}
]
}Risk Flags
π Underwriting Rules
DTI = (monthly_debt Γ 12) / annual_income
LTV = loan_amount / property_value
βββ Priority 1 β ESCALATE (human review required) βββ
β’ fraud_flag = true
β’ income_verified = false
β’ prior_default = true
β’ 0.40 β€ DTI β€ 0.45 (borderline zone)
βββ Priority 2 β REJECT (if not escalating) βββ
β’ DTI > 0.45
β’ credit_score < 620
β’ LTV > 0.97
βββ Priority 3 β APPROVE (all other cases) βββ
interest_rate = round(6.5 + max(0, (DTIβ0.28)Γ4) + max(0, (720βcredit_score)Γ0.01), 2)π Quick Start
Prerequisites
- Python 3.11+
- Docker
- API key for any OpenAI-compatible provider (OpenAI, Groq, Together AI, etc.)
1. Clone & Install
git clone https://huggingface.co/spaces/bhattyuvraj22/loan-underwriting-env
cd loan-underwriting-env
pip install -r requirements.txt2. Start the Server
uvicorn main:app --host 0.0.0.0 --port 7860 --reload3. Verify It's Running
curl http://localhost:7860/health
# {"status":"ok","env":"loan-underwriting-env","version":"1.0.0"}
curl http://localhost:7860/tasks
# Lists all 3 tasks4. Run Baseline Inference
With Groq (free tier available):
export HF_TOKEN=gsk_your_groq_key
export API_BASE_URL=https://api.groq.com/openai/v1
export MODEL_NAME=llama-3.3-70b-versatile
export ENV_URL=http://localhost:7860
python inference.pyWith OpenAI:
export HF_TOKEN=sk-your_openai_key
export API_BASE_URL=https://api.openai.com/v1
export MODEL_NAME=gpt-4o
export ENV_URL=http://localhost:7860
python inference.pyFor reproducibility:
python inference.py --seed 123π³ Docker
# Build
docker build -t loan-underwriting-env .
# Run
docker run -p 7860:7860 loan-underwriting-env
# Verify
curl http://localhost:7860/health
# Run inference against the container
HF_TOKEN=your_key \
API_BASE_URL=https://api.groq.com/openai/v1 \
MODEL_NAME=llama-3.3-70b-versatile \
ENV_URL=http://localhost:7860 \
python inference.pyπ API Reference
π Interactive docs available at http://localhost:7860/docsFull Episode β curl Example
# Step 1: Reset
curl -s -X POST http://localhost:7860/reset \
-H "Content-Type: application/json" \
-d '{"task_id": "task_1_easy", "seed": 42}' | python -m json.tool
# Step 2: Submit decisions (copy applicant_id from reset response)
curl -s -X POST http://localhost:7860/step \
-H "Content-Type: application/json" \
-d '{
"task_id": "task_1_easy",
"decisions": [{
"applicant_id": "APP-XXXX-00",
"decision": "approve",
"interest_rate": 7.18,
"risk_flags": ["high_ltv"],
"reasoning": "DTI=0.15 LTV=0.80 => approve"
}]
}' | python -m json.toolποΈ Project Structure
loan-underwriting-env/
β
βββ π main.py # FastAPI app β all HTTP endpoints
βββ π inference.py # Baseline inference script (OpenAI-compatible)
βββ π openenv.yaml # OpenEnv spec β observation/action space definitions
βββ π requirements.txt # Python dependencies
βββ π pyproject.toml # Project metadata + entry points
βββ π Dockerfile # Container definition
βββ π uv.lock # Locked dependency tree
β
βββ π env/
β βββ models.py # Typed Pydantic models (Observation, AgentAction, Reward)
β βββ state.py # Session manager (reset / step / state logic)
β βββ underwriting.py # Applicant generator + ground truth computation
β βββ graders/
β βββ grader1.py # Easy β decision + rate + flags
β βββ grader2.py # Medium β batch + constraints + safety
β βββ grader3.py # Hard β escalation F1 + fraud detection
β
βββ π server/
βββ app.py # Entry point for multi-mode deploymentπ§ Reward Design
Partial progress signal β Every scoring component is independent. An agent that gets decisions right but misses risk flags still earns 0.50β0.75, not zero. This gives a meaningful learning signal at every skill level.
Anti-trivial-strategy design β A lazy "escalate everything" strategy scores only ~0.45β0.65 because decision accuracy penalises incorrect escalations of should-approve applicants. A correct agent scores 0.90+.
Safety penalties β False approvals of hard-reject and fraud applicants incur explicit deductions on top of the decision accuracy loss, strongly incentivising conservative handling of risky cases.
π Environment Checklist
<div align="center">
Built for the OpenEnv Challenge Β· Powered by FastAPI Β· Hosted on Hugging Face Spaces
</div>
