How to Build a loan approval Agent Using LlamaIndex in Python for pension funds
A loan approval agent for pension funds takes a member or sponsor loan request, pulls the relevant policy and portfolio context, checks eligibility against fund rules, scores risk, and produces a decision package with an audit trail. It matters because pension funds operate under tighter governance than retail lenders: every decision needs to be explainable, policy-aligned, and traceable for compliance, trustees, and regulators.
Architecture
- •
Policy retrieval layer
- •Stores lending policy docs, trustee resolutions, credit committee notes, and jurisdiction-specific rules.
- •Uses
VectorStoreIndex+RetrieverQueryEngineto fetch only the relevant clauses for a request.
- •
Loan intake schema
- •Normalizes applicant data: member status, contribution history, requested amount, tenor, collateral, employer details.
- •Keeps the agent from reasoning over messy free text.
- •
Decision engine
- •Combines retrieved policy context with structured inputs.
- •Uses an LLM through LlamaIndex to produce a recommendation: approve, reject, or escalate.
- •
Risk and compliance checks
- •Applies deterministic rules before the model can recommend approval.
- •Enforces pension-fund-specific constraints like maximum exposure, eligibility windows, and prohibited use cases.
- •
Audit log
- •Persists retrieved evidence, model output, timestamps, and final decision.
- •This is non-negotiable when trustees or regulators ask why a loan was approved.
- •
Human review queue
- •Routes borderline cases to a compliance officer or credit committee.
- •Prevents the agent from making unilateral decisions outside policy bounds.
Implementation
1) Install dependencies and load policy documents
Use LlamaIndex to index your lending policy documents. In practice these are PDFs, DOCX files, or exported trustee resolutions stored in a controlled repository.
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.core.settings import Settings
from llama_index.llms.openai import OpenAI
# Configure your LLM
Settings.llm = OpenAI(model="gpt-4o-mini", temperature=0)
# Load policy docs from a controlled directory
documents = SimpleDirectoryReader("./policy_docs").load_data()
# Build an index over the policy corpus
index = VectorStoreIndex.from_documents(documents)
# Create a query engine for retrieval + synthesis
query_engine = index.as_query_engine(similarity_top_k=3)
This gives you a retrieval layer that can answer questions like: “What is the maximum loan-to-benefit ratio for active members?” or “Which cases require trustee approval?”
2) Define structured loan input and pre-checks
Do not let the model infer critical facts from prose if you already have them as fields. Pension fund lending should start with deterministic validation before any LLM call.
from dataclasses import dataclass
@dataclass
class LoanRequest:
member_id: str
employment_status: str
requested_amount: float
monthly_contribution: float
years_to_retirement: int
collateral_value: float
country: str
def precheck(request: LoanRequest) -> list[str]:
reasons = []
if request.employment_status.lower() != "active":
reasons.append("Applicant is not an active member.")
if request.years_to_retirement < 2:
reasons.append("Less than 2 years to retirement.")
if request.requested_amount > request.collateral_value * 0.5:
reasons.append("Requested amount exceeds collateral limit.")
return reasons
These checks are where pension-fund-specific controls live. If your fund cannot lend to deferred members or cannot exceed a fixed percentage of accrued benefits, enforce that here.
3) Ask the agent for a recommendation with evidence
Now combine structured input with retrieved policy text. The output should be short and operational: decision plus reason plus cited evidence.
def evaluate_loan(request: LoanRequest):
rule_text = query_engine.query(
f"""
Summarize the lending rules relevant to this request:
member status={request.employment_status},
amount={request.requested_amount},
years_to_retirement={request.years_to_retirement},
country={request.country}.
"""
)
prompt = f"""
You are evaluating a pension fund loan application.
Applicant:
- Member ID: {request.member_id}
- Employment status: {request.employment_status}
- Requested amount: {request.requested_amount}
- Monthly contribution: {request.monthly_contribution}
- Years to retirement: {request.years_to_retirement}
- Collateral value: {request.collateral_value}
- Country: {request.country}
Policy context:
{rule_text}
Return JSON with keys:
decision (approve|reject|escalate),
reason,
evidence,
risk_flags.
"""
response = Settings.llm.complete(prompt)
return response.text
request = LoanRequest(
member_id="M12345",
employment_status="active",
requested_amount=5000,
monthly_contribution=300,
years_to_retirement=8,
collateral_value=15000,
country="ZA",
)
precheck_reasons = precheck(request)
if precheck_reasons:
print({"decision": "reject", "reason": precheck_reasons})
else:
print(evaluate_loan(request))
The important pattern here is that the model does not decide in isolation. It receives only the retrieved policy context plus normalized fields, then emits a structured result that downstream systems can parse.
4) Add an audit trail for trustees and compliance
Every decision needs reproducibility. Store the input payload, pre-check results, retrieved policy snippets, and final response in your audit store.
import json
from datetime import datetime
def audit_record(request: LoanRequest, prechecks: list[str], result_text: str):
record = {
"timestamp": datetime.utcnow().isoformat(),
"member_id": request.member_id,
"input": request.__dict__,
"prechecks": prechecks,
"model_result": result_text,
}
with open("loan_audit_log.jsonl", "a", encoding="utf-8") as f:
f.write(json.dumps(record) + "\n")
if precheck_reasons:
audit_record(request, precheck_reasons, json.dumps({"decision": "reject"}))
else:
result = evaluate_loan(request)
audit_record(request, [], result)
In production this should go to immutable storage with retention policies aligned to your regulator’s requirements.
Production Considerations
- •
Data residency
- •Keep member data and policy documents in-region if your pension fund operates under local residency laws.
- •If you use hosted LLMs, confirm where prompts and embeddings are processed and stored.
- •
Monitoring
- •Track approval rates by branch, employer group, geography, and membership category.
- •Watch for drift in recommendation patterns after policy updates or market shocks.
- •
Guardrails
- •Hard-block any case that violates mandatory fund rules before it reaches the model.
- •Use human approval for exceptions such as large exposures or politically sensitive sponsors.
- •
Auditability
- •Persist retrieved evidence alongside each decision.
- •Make sure trustees can reconstruct why the agent approved or rejected a loan months later.
Common Pitfalls
- •
Letting the LLM replace hard policy rules
- •Mistake: asking the model to “decide based on policy” without deterministic checks.
- •Fix: enforce eligibility and exposure limits in code first; use the model only for synthesis and explanation.
- •
Using unstructured prompts instead of structured inputs
- •Mistake: dumping raw application text into one giant prompt.
- •Fix: normalize fields into a
LoanRequestobject and pass only what matters.
- •
Ignoring compliance evidence
- •Mistake: returning “approve” without citations or traceability.
- •Fix: always store retrieved clauses from
VectorStoreIndexqueries plus the final output in an audit log.
If you build it this way, you get an agent that is useful to operations teams without crossing the line into uncontrolled automation. For pension funds that line matters more than fancy model output.
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