How to Build a policy Q&A Agent Using AutoGen in TypeScript for retail banking
A policy Q&A agent answers staff or customer questions about bank policies, product rules, and operational procedures using approved source material. In retail banking, that matters because the wrong answer can create compliance issues, inconsistent treatment of customers, and avoidable escalations to operations or legal.
Architecture
- •
User interface layer
- •Chat UI for branch staff, contact center agents, or internal ops teams.
- •Sends the user question plus session metadata like region, product line, and channel.
- •
Policy retrieval layer
- •Pulls from approved policy documents, procedure manuals, FAQ articles, and product disclosures.
- •Uses vector search or keyword retrieval to return only current, versioned sources.
- •
AutoGen orchestration layer
- •Coordinates the conversation between a policy assistant agent and a retrieval/tooling agent.
- •Keeps the assistant grounded in retrieved policy excerpts instead of free-form generation.
- •
Guardrail layer
- •Blocks unsupported advice, regulated content leakage, and requests outside policy scope.
- •Enforces “answer only from sources” behavior and escalation when confidence is low.
- •
Audit and logging layer
- •Stores question, retrieved passages, model output, citations, and final action taken.
- •Required for compliance review, incident analysis, and model risk management.
- •
Deployment controls
- •Region-specific hosting for data residency.
- •Secrets management, PII redaction, rate limiting, and tenant isolation.
Implementation
1) Install AutoGen for TypeScript and define your policy context
Use the TypeScript AutoGen package and keep your policy corpus outside the model prompt. The agent should receive only the minimum context needed to answer.
npm install @autogenai/autogen openai
import { AssistantAgent } from "@autogenai/autogen";
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY!,
});
const policyAssistant = new AssistantAgent({
name: "policy_assistant",
modelClient: client,
systemMessage: `
You are a retail banking policy Q&A assistant.
Answer only using provided policy excerpts.
If the answer is not in the excerpts, say you cannot confirm it from current policy.
Do not provide legal advice. Do not speculate.
Always cite the excerpt IDs used in the answer.
`,
});
2) Build a retrieval function that returns approved excerpts
In production, this comes from your document store or vector database. The key pattern is to return short excerpts with IDs and metadata so the model can cite them.
type PolicyExcerpt = {
id: string;
title: string;
version: string;
region: string;
text: string;
};
async function retrievePolicyExcerpts(query: string): Promise<PolicyExcerpt[]> {
// Replace with vector search + metadata filters:
// region = user's jurisdiction
// product = relevant retail banking product
// status = approved/current only
return [
{
id: "KYC-001",
title: "Customer Identification Requirements",
version: "2025.01",
region: "US",
text: "For new deposit accounts, two forms of identification are required unless an exception is approved by Compliance.",
},
{
id: "FEE-014",
title: "Overdraft Fee Disclosure",
version: "2025.02",
region: "US",
text: "Overdraft fees must be disclosed before account opening and in periodic statements as required by applicable regulation.",
},
];
}
3) Ask AutoGen to answer with citations and an escalation rule
The actual pattern is to inject retrieved excerpts into the assistant call as structured context. Keep the response constrained so you can audit it later.
async function answerPolicyQuestion(question: string) {
const excerpts = await retrievePolicyExcerpts(question);
const contextBlock = excerpts
.map(
(e) =>
`[${e.id}] ${e.title} v${e.version} (${e.region}): ${e.text}`
)
.join("\n");
const result = await policyAssistant.run([
{
role: "user",
content: `
Question:
${question}
Approved policy excerpts:
${contextBlock}
Instructions:
- Answer using only these excerpts.
- If multiple excerpts apply, reconcile them explicitly.
- If no excerpt answers the question, say "I can't confirm this from current policy."
- Include excerpt IDs at the end of each key claim.
`,
},
]);
return result.messages.at(-1)?.content ?? "";
}
answerPolicyQuestion("Can we open a checking account with one ID if the customer is already known?")
.then(console.log)
.catch(console.error);
4) Add a second pass for compliance review on risky queries
For retail banking, some questions need escalation instead of direct answers. Use a lightweight classifier step before responding.
function requiresEscalation(question: string): boolean {
const riskyTerms = [
"fair lending",
"regulatory exception",
"sanctions",
"SAR",
"legal hold",
"identity verification bypass",
"complaint escalation",
];
return riskyTerms.some((term) => question.toLowerCase().includes(term));
}
async function safeAnswer(question: string) {
if (requiresEscalation(question)) {
return "This request requires review by Compliance or Operations. I can't provide a policy answer here.";
}
return await answerPolicyQuestion(question);
}
Production Considerations
- •
Enforce data residency by region
- •Keep EU customer data and EU policy corpora in-region.
- •Do not send customer PII to a model endpoint outside approved jurisdictions.
- •
Log every decision path
- •Store question text, retrieved excerpt IDs, model response, timestamp, user role, and region.
- •This gives you an audit trail for complaints and internal reviews.
- •
Add hard guardrails before generation
- •Block requests involving sanctions screening bypasses, KYC exceptions without approval paths, or legal interpretation.
- •Route those to human review instead of letting the model improvise.
- •
Monitor drift against source-of-truth policies
- •Version your documents and expire old ones automatically.
Common Pitfalls
- •
Letting the model answer without retrieval
If you skip retrieval grounding, the assistant will fill gaps with plausible but wrong banking language. Always pass approved excerpts into each turn.
- •
Using stale policy versions
Retail banking policies change often due to regulatory updates. Filter retrieval by
status=currentandeffectiveDate, then log which version was used in every response. - •
Ignoring jurisdiction
A deposit account rule in one country may be invalid in another. Filter by region before prompting the model so US policies do not leak into UK or EU workflows.
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