How to Build a underwriting Agent Using CrewAI in Python for insurance
An underwriting agent takes a submission, extracts the relevant risk factors, checks them against underwriting guidelines, and returns a recommendation with evidence. In insurance, that matters because underwriters spend too much time on repetitive triage work, and every automated decision needs to be explainable, auditable, and compliant.
Architecture
A production underwriting agent in CrewAI needs these components:
- •
Submission intake
- •Pull structured data from ACORD forms, PDFs, emails, or API payloads.
- •Normalize fields like applicant name, line of business, limits, prior losses, and location.
- •
Risk extraction agent
- •Read the submission and extract underwriting signals.
- •Identify missing fields, red flags, and inconsistencies.
- •
Guideline checker tool
- •Compare extracted facts against underwriting rules.
- •Enforce appetite rules, referral thresholds, and mandatory declines.
- •
Decision synthesizer
- •Produce a recommendation: accept, refer, decline, or request more info.
- •Attach rationale and supporting evidence for audit.
- •
Audit logger
- •Persist inputs, outputs, model version, timestamps, and rule hits.
- •Support later review by compliance and underwriting leadership.
- •
Human review handoff
- •Escalate borderline cases to an underwriter.
- •Keep the agent advisory-only unless your regulatory framework explicitly allows automation.
Implementation
1) Define tools for guideline checks and audit logging
CrewAI works best when the LLM is constrained by tools instead of being asked to “know” underwriting policy. For insurance work, put your actual rules in code so they are versioned and testable.
from crewai.tools import BaseTool
from pydantic import BaseModel, Field
from typing import Dict, Any
import json
from datetime import datetime
class GuidelineInput(BaseModel):
submission: Dict[str, Any] = Field(...)
class UnderwritingGuidelineTool(BaseTool):
name: str = "underwriting_guideline_check"
description: str = "Checks a submission against underwriting appetite rules."
def _run(self, submission: Dict[str, Any]) -> str:
reasons = []
decision = "accept"
premium = submission.get("annual_premium", 0)
state = submission.get("state", "")
prior_losses = submission.get("prior_losses", 0)
if state in ["AK", "LA"]:
decision = "refer"
reasons.append("State requires manual review due to catastrophe exposure.")
if prior_losses >= 3:
decision = "decline"
reasons.append("Three or more prior losses exceed appetite.")
if premium > 250000:
decision = "refer"
reasons.append("Premium exceeds automatic authority threshold.")
return json.dumps({"decision": decision, "reasons": reasons})
class AuditTool(BaseTool):
name: str = "audit_logger"
description: str = "Writes underwriting decisions to an audit record."
def _run(self, record: Dict[str, Any]) -> str:
record["timestamp"] = datetime.utcnow().isoformat()
with open("underwriting_audit.jsonl", "a") as f:
f.write(json.dumps(record) + "\n")
return "logged"
2) Create the CrewAI agents
Use one agent for extraction and one for recommendation. Keep the roles narrow so you can inspect failures and tune prompts without turning the system into a blob of generic reasoning.
from crewai import Agent
risk_extractor = Agent(
role="Insurance Risk Extractor",
goal="Extract underwriting-relevant facts from submissions accurately.",
backstory=(
"You are an insurance operations analyst who extracts only factual "
"submission details and flags missing or inconsistent data."
),
tools=[UnderwritingGuidelineTool()],
verbose=True,
)
underwriting_decider = Agent(
role="Underwriting Decision Maker",
goal="Produce a defensible underwriting recommendation with evidence.",
backstory=(
"You are a senior commercial lines underwriter. You must cite rule-based "
"findings and never invent facts not present in the submission."
),
tools=[AuditTool()],
verbose=True,
)
3) Define tasks with explicit outputs
Make each task produce a bounded artifact. That gives you better control over downstream processing and makes it easier to store evidence for compliance reviews.
from crewai import Task
extract_task = Task(
description=(
"Review the insurance submission below and extract key risk facts: "
"insured name, state, line of business, annual premium, prior losses, "
"limits requested, missing fields, and any red flags.\n\n"
"{submission}"
),
expected_output="A structured summary of underwriting facts in JSON-like format.",
agent=risk_extractor,
)
decide_task = Task(
description=(
"Using the extracted facts from the previous task and the guideline tool "
"output if needed, produce one recommendation: accept, refer, or decline. "
"Include reason codes suitable for audit."
),
expected_output="A final underwriting recommendation with rationale.",
agent=underwriting_decider,
)
4) Run the crew and persist the result
This is the actual orchestration pattern you want in production: extract first, then decide. If you need stronger determinism later on, wrap this behind an API service and add schema validation before writing decisions into your policy admin system.
from crewai import Crew
import os
submission_text = """
Applicant: North Ridge Manufacturing
State: TX
Line of Business: General Liability
Annual Premium: 180000
Prior Losses: 1
Limits Requested: 1M/2M
"""
crew = Crew(
agents=[risk_extractor, underwriting_decider],
tasks=[extract_task, decide_task],
verbose=True,
)
result = crew.kickoff(inputs={"submission": submission_text})
print(result)
Production Considerations
- •
Compliance controls
- •Keep human approval in the loop for declines and referrals unless your governance team has signed off on automation.
- •Store reason codes tied to filed guidelines so decisions can be explained during audits.
- •
Data residency
- •Do not send regulated customer data to models or endpoints outside approved regions.
- •If you operate across jurisdictions like EU or Canada, isolate workloads by region and keep logs local.
- •
Monitoring
- •Track referral rate, decline rate, missing-field rate, hallucination rate, and underwriter override rate.
- •Alert when the agent starts recommending outcomes outside historical norms.
- •
Guardrails
- •Validate every output against a strict schema before it reaches downstream systems.
- •Block free-form recommendations that do not include evidence from either the submission or guideline tool.
Common Pitfalls
- •
Letting the model invent risk facts
- •Avoid this by forcing extraction into structured fields first.
- •Never let the decision step infer values that were not present in source documents.
- •
Encoding underwriting rules only in prompts
- •Prompts drift. Put appetite rules in code or a policy service.
- •Version those rules alongside your model prompt so audits can reproduce decisions.
- •
Skipping audit trails
- •If you cannot reconstruct why a case was accepted or declined six months later, you do not have a production system.
- •Log inputs، outputs، timestamps، model version، prompt version، and rule hits.
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