How to Build a policy Q&A Agent Using CrewAI in Python for lending

By Cyprian AaronsUpdated 2026-04-21
policy-q-acrewaipythonlendingpolicy-qanda

A policy Q&A agent for lending answers questions like “Can this borrower qualify under our current DTI policy?” or “What exceptions are allowed for self-employed applicants?” It matters because loan officers, ops teams, and support staff need fast, consistent answers grounded in approved policy, not memory or guesswork. If you build it right, you reduce turnaround time without creating compliance drift.

Architecture

  • Policy source layer

    • Pulls from approved lending policy PDFs, internal SOPs, and product matrices.
    • Only indexed content should be available to the agent.
  • Retrieval layer

    • Uses a vector store or search index to fetch relevant policy passages.
    • Must return citations so every answer is auditable.
  • CrewAI agent layer

    • A single policy specialist agent is usually enough for Q&A.
    • Add a second reviewer agent if you want stricter compliance checks.
  • Guardrail layer

    • Blocks unsupported advice, missing citations, and out-of-scope questions.
    • Forces the model to answer “I don’t know” when policy evidence is weak.
  • Audit and logging layer

    • Stores question, retrieved passages, final answer, timestamps, and user identity.
    • Required for lending audit trails and dispute handling.

Implementation

  1. Install CrewAI and define the policy tools

Use CrewAI’s Agent, Task, Crew, and Tool primitives. For lending, the retrieval tool should only search approved documents stored in your controlled repository.

from crewai import Agent, Task, Crew
from crewai.tools import BaseTool
from pydantic import BaseModel, Field

class PolicyLookupInput(BaseModel):
    query: str = Field(..., description="Lending policy question")

class LendingPolicyLookupTool(BaseTool):
    name: str = "lending_policy_lookup"
    description: str = "Search approved lending policy documents and return relevant excerpts."
    args_schema = PolicyLookupInput

    def _run(self, query: str) -> str:
        # Replace with your real retrieval backend:
        # Elasticsearch / pgvector / Pinecone / OpenSearch
        if "DTI" in query.upper():
            return (
                "DTI Policy v3.2: Maximum front-end DTI is 28% for standard conforming loans. "
                "Exceptions up to 31% require compensating factors and manager approval. "
                "Source: Lending Policy Manual §4.1."
            )
        return "No matching policy excerpt found."

policy_agent = Agent(
    role="Lending Policy Analyst",
    goal="Answer lending policy questions using only approved policy excerpts.",
    backstory=(
        "You work in credit operations and must never invent policy. "
        "Always cite the source excerpt used to answer."
    ),
    tools=[LendingPolicyLookupTool()],
    verbose=True,
)
  1. Create a task that forces grounded answers

The task should instruct the agent to use retrieved excerpts only. In lending, that means no freeform advice unless it is traceable to a policy document.

policy_task = Task(
    description=(
        "Answer the user's lending policy question using only the provided policy excerpt. "
        "If the excerpt does not contain enough information, say you cannot confirm it from policy."
    ),
    expected_output=(
        "A concise answer with a quoted policy reference and a clear yes/no/conditional response."
    ),
    agent=policy_agent,
)
  1. Run the crew with a strict execution pattern

This is the basic production pattern: one agent, one retrieval tool, one task. Keep it simple until you have evidence you need multi-agent review.

crew = Crew(
    agents=[policy_agent],
    tasks=[policy_task],
    verbose=True,
)

result = crew.kickoff(inputs={
    "question": "What is the maximum DTI allowed for a standard conforming loan?"
})

print(result)
  1. Add a compliance review step before returning answers

For lending workflows, I recommend a second task that checks whether the answer is supported by cited text. That gives you an internal control before anything reaches a loan officer or customer-facing channel.

compliance_agent = Agent(
    role="Compliance Reviewer",
    goal="Verify that every answer is supported by cited lending policy text.",
    backstory="You reject unsupported claims and enforce audit-ready responses.",
)

compliance_task = Task(
    description=(
        "Review the draft answer for unsupported statements, missing citations, "
        "or language that could be interpreted as underwriting advice."
    ),
    expected_output="Approved or rejected with reasons.",
    agent=compliance_agent,
)

review_crew = Crew(
    agents=[policy_agent, compliance_agent],
    tasks=[policy_task, compliance_task],
)

Production Considerations

  • Auditability

    • Persist user question, retrieved excerpts, final response, model version, and timestamp.
    • In lending disputes, you need to show exactly which policy text informed the response.
  • Data residency

    • Keep document storage and vector indexes in-region if your lending policies or customer data are subject to jurisdictional controls.
    • Don’t send borrower PII into external tools unless your legal and security teams have signed off.
  • Guardrails

    • Reject questions that ask for underwriting decisions on live applications unless the agent is explicitly authorized.
    • Force citations from approved sources only; no citations means no answer.
  • Monitoring

    • Track hallucination rate, unanswered rate, citation coverage, and escalation frequency.
    • Alert when answers drift toward exception language or when retrieval starts returning stale policies.

Common Pitfalls

  • Using general-purpose web search

    • This breaks control over source of truth.
    • Fix it by restricting retrieval to your approved lending document corpus.
  • Letting the model answer without evidence

    • The biggest failure mode is confident but uncited guidance.
    • Fix it by requiring retrieved excerpts in every response and rejecting empty retrieval results.
  • Mixing customer data with policy lookup

    • A policy Q&A agent should usually not need SSNs, account numbers, or full application files.
    • Fix it by separating policy knowledge from borrower records and redacting inputs before they hit tools.

If you want this to hold up in production lending workflows, treat it like a controlled decision-support system, not a chatbot. The difference is simple: one can be trusted in an audit; the other cannot unless you build all the controls around it.


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