How to Build a customer support Agent Using AutoGen in Python for banking

By Cyprian AaronsUpdated 2026-04-21
customer-supportautogenpythonbanking

A banking customer support agent built with AutoGen handles routine customer queries, triages issues, pulls policy-safe answers from approved sources, and escalates anything sensitive to a human. It matters because banking support is high-volume, regulated, and unforgiving: one wrong answer about fees, card blocks, chargebacks, or account access can create compliance risk and customer harm.

Architecture

  • User-facing assistant agent

    • Handles the first response.
    • Keeps the conversation structured and concise.
    • Never directly invents policy or account details.
  • Policy retrieval layer

    • Pulls from approved banking knowledge: FAQs, fee schedules, dispute policies, KYC rules.
    • Keeps responses grounded in bank-approved content.
  • Compliance guardrail layer

    • Detects requests involving PII, account numbers, authentication, disputes, fraud claims, and complaints.
    • Forces escalation when the request crosses policy boundaries.
  • Human escalation agent

    • Receives cases the model cannot safely answer.
    • Produces a summary for a support analyst or contact center queue.
  • Audit logging

    • Stores prompts, tool calls, model outputs, and escalation reasons.
    • Supports traceability for internal audit and regulator review.
  • Secure deployment boundary

    • Enforces data residency, encryption, secrets management, and network controls.
    • Prevents customer data from leaving approved regions or systems.

Implementation

1) Install AutoGen and define your agents

For this pattern I use autogen-agentchat with the AssistantAgent and UserProxyAgent classes. The assistant answers only from policy context; the user proxy simulates a support channel or can be wired to your web backend.

pip install autogen-agentchat autogen-ext[openai]
import os
import asyncio
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.messages import TextMessage
from autogen_ext.models.openai import OpenAIChatCompletionClient

MODEL = OpenAIChatCompletionClient(
    model="gpt-4o-mini",
    api_key=os.environ["OPENAI_API_KEY"],
)

SYSTEM_PROMPT = """
You are a banking customer support agent.
Rules:
- Answer only using the provided policy context.
- Never ask for full card numbers, passwords, PINs, OTPs, or online banking credentials.
- If the user asks about disputes, fraud claims, account access problems, AML/KYC issues,
  or anything requiring identity verification, escalate to a human.
- Keep answers short and professional.
- If policy context does not contain the answer, say you need to escalate.
"""

support_agent = AssistantAgent(
    name="bank_support_agent",
    model_client=MODEL,
    system_message=SYSTEM_PROMPT,
)

2) Add a simple policy retrieval function

In production this would call your vector store or document service. The key pattern is to inject only approved content into the model context. Do not pass raw CRM records unless they are redacted and authorized.

POLICY_KB = {
    "card_replacement": "Debit card replacement takes 3-5 business days. Expedited delivery may be available for eligible accounts.",
    "wire_transfer": "Domestic wire transfers submitted before cutoff time are processed same business day.",
    "fees": "Monthly maintenance fee waivers apply to qualifying accounts with direct deposit or minimum balance.",
}

def retrieve_policy(query: str) -> str:
    q = query.lower()
    if "card" in q:
        return POLICY_KB["card_replacement"]
    if "wire" in q or "transfer" in q:
        return POLICY_KB["wire_transfer"]
    if "fee" in q or "maintenance" in q:
        return POLICY_KB["fees"]
    return "No matching policy found."

3) Run the agent with an escalation rule

This example uses AssistantAgent.run() directly. Before answering, we check for banking-sensitive topics and force escalation if needed. That keeps the LLM out of areas where it should not improvise.

SENSITIVE_PATTERNS = [
    "password", "pin", "otp", "one-time code", "full card number",
    "fraud", "chargeback", "dispute", "kyc", "aml", "account locked"
]

def needs_escalation(user_text: str) -> bool:
    text = user_text.lower()
    return any(pattern in text for pattern in SENSITIVE_PATTERNS)

async def handle_support_request(user_text: str):
    if needs_escalation(user_text):
        return {
            "route": "human_escalation",
            "message": (
                "I can help route this to a specialist. "
                "Please provide a short summary without sensitive credentials."
            ),
        }

    policy_context = retrieve_policy(user_text)
    prompt = f"""
Customer message: {user_text}

Approved policy context:
{policy_context}
"""
    result = await support_agent.run(task=prompt)
    return {
        "route": "auto_resolved",
        "message": result.messages[-1].content,
    }

if __name__ == "__main__":
    response = asyncio.run(handle_support_request("What is your fee waiver policy?"))
    print(response)

4) Add audit logging around every interaction

For banking you need an immutable trail: input classification, retrieved policy source, model output, and whether escalation happened. Keep logs separate from application logs so access can be tightly controlled.

import json
from datetime import datetime

def audit_event(event_type: str, payload: dict):
    record = {
        "timestamp": datetime.utcnow().isoformat(),
        "event_type": event_type,
        **payload,
    }
    with open("audit_log.jsonl", "a", encoding="utf-8") as f:
        f.write(json.dumps(record) + "\n")

async def audited_handle_support_request(user_text: str):
    audit_event("incoming_message", {"text": user_text})

    if needs_escalation(user_text):
        audit_event("escalation_triggered", {"reason": "sensitive_topic"})
        return {"route": "human_escalation"}

    policy_context = retrieve_policy(user_text)
    audit_event("policy_retrieved", {"context": policy_context})

    result = await support_agent.run(task=f"{user_text}\n\nPolicy:\n{policy_context}")
    final_message = result.messages[-1].content

    audit_event("agent_response", {"response": final_message})
    return {"route": "auto_resolved", "message": final_message}

Production Considerations

  • Deployment boundary

    • Run the agent inside your bank’s approved cloud region or private network.
    • Keep secrets in a managed vault and never hardcode API keys.
    • If your bank has residency constraints, pin both model endpoint and logs to that region.
  • Monitoring

    • Track escalation rate, hallucination rate, response latency, and unresolved intents.
    • Sample transcripts for compliance review with PII redaction before storage.
    • Alert on repeated requests involving authentication or fraud because those often indicate abuse.
  • Guardrails

    • Redact account numbers, SSNs/national IDs, card PANs, OTPs before they reach the model.
    • Use allowlisted knowledge sources only; do not let the agent browse arbitrary URLs.
    • Force human review for complaints involving regulatory rights: disputes, chargebacks, lending decisions.
  • Auditability

    • Store prompt versions alongside outputs so you can reproduce behavior later.
    • Log which policy document answered the question.
    • Keep retention aligned with legal hold and records management rules.

Common Pitfalls

  1. Letting the model answer from memory

    • This is how you get incorrect fee explanations or bad dispute guidance.
    • Fix it by grounding every response in retrieved bank-approved policy text.
  2. Passing raw customer data into prompts

    • Full account details and authentication data should never be exposed to the LLM.
    • Fix it with redaction middleware and strict field-level filtering before any agent call.
  3. Skipping escalation paths

    • Banking support is not fully automatable.
    • Fix it by defining hard triggers for fraud claims, identity verification issues, complaints, and regulatory topics.
  4. Treating logs as harmless debug output

    • Support transcripts often contain regulated personal data.
    • Fix it by encrypting logs at rest, restricting access by role, and separating audit logs from app logs.

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