How to Build a policy Q&A Agent Using AutoGen in TypeScript for fintech
A policy Q&A agent answers internal questions like “Can I reimburse this expense?” or “Does this vendor contract need legal review?” by retrieving the right policy, reasoning over it, and returning a grounded answer with citations. For fintech, that matters because policy drift, compliance mistakes, and inconsistent guidance turn into audit findings, customer risk, and expensive manual review.
Architecture
Build this agent with a small set of components that are easy to audit and hard to misuse:
- •
Policy corpus
- •HR, expense, vendor risk, AML/KYC, data retention, and security policies stored as versioned documents.
- •Keep document metadata:
policyId,version,jurisdiction,effectiveDate,owner.
- •
Retriever
- •A search layer that returns the top policy chunks for a question.
- •In production, use vector search plus keyword filters for jurisdiction and document type.
- •
Assistant agent
- •An
AssistantAgentthat drafts the answer from retrieved context only. - •Configure it to cite sources and refuse unsupported claims.
- •An
- •
User proxy / orchestrator
- •A
UserProxyAgentthat receives the user question and triggers the assistant. - •This is where you enforce approval flows if the answer is high-risk.
- •A
- •
Audit logger
- •Store the question, retrieved chunks, final answer, model version, and timestamps.
- •Fintech teams need this for compliance reviews and incident investigations.
- •
Guardrail layer
- •Block sensitive requests outside scope: fraud advice, regulated legal interpretation, or PII leakage.
- •Route those to human review instead of letting the model improvise.
Implementation
1) Install AutoGen for TypeScript and define your policy context
Use the AutoGen TypeScript package and keep your policy snippets small enough to fit in context. The important part is not “more tokens”; it’s deterministic retrieval and traceability.
npm install @autogen-ai/autogen
Create a typed policy record so every retrieved chunk carries metadata you can audit later.
type PolicyChunk = {
policyId: string;
version: string;
title: string;
jurisdiction: "US" | "UK" | "EU";
content: string;
};
const policyChunks: PolicyChunk[] = [
{
policyId: "EXP-001",
version: "3.2",
title: "Expense Policy",
jurisdiction: "US",
content:
"Meals over $75 require manager approval. Alcohol is not reimbursable unless pre-approved for client events.",
},
{
policyId: "VND-014",
version: "1.8",
title: "Third-Party Risk Policy",
jurisdiction: "EU",
content:
"Any vendor accessing customer data requires security review, DPA execution, and data residency assessment.",
},
];
2) Build a retrieval function with strict filtering
For fintech, retrieval should be narrow. If the user asks about UK travel expenses, don’t feed US vendor-risk text into the prompt.
function retrievePolicyContext(question: string): PolicyChunk[] {
const q = question.toLowerCase();
return policyChunks.filter((chunk) => {
const matchesExpense =
q.includes("expense") || q.includes("meal") || q.includes("travel");
const matchesVendor =
q.includes("vendor") || q.includes("third-party") || q.includes("dpa");
const matchesJurisdiction =
(q.includes("uk") && chunk.jurisdiction === "UK") ||
(q.includes("eu") && chunk.jurisdiction === "EU") ||
(!q.includes("uk") && !q.includes("eu"));
return (
matchesJurisdiction &&
((matchesExpense && chunk.policyId.startsWith("EXP")) ||
(matchesVendor && chunk.policyId.startsWith("VND")))
);
});
}
3) Create an AutoGen assistant that answers only from provided context
The actual pattern in AutoGen TS is an AssistantAgent plus a UserProxyAgent. The assistant gets a system message that forces grounded answers and citations.
import { AssistantAgent, UserProxyAgent } from "@autogen-ai/autogen";
const assistant = new AssistantAgent({
name: "policy_assistant",
systemMessage: [
"You are a fintech policy Q&A agent.",
"Answer only using the provided policy context.",
"If the context does not contain enough information, say 'I need a human review'.",
"Always cite policyId and version for each rule you use.",
"Do not provide legal advice or interpret regulations beyond internal policy text.",
].join(" "),
});
const userProxy = new UserProxyAgent({
name: "employee_user",
});
Now wire retrieval into the prompt you send to the assistant.
async function answerPolicyQuestion(question: string) {
const context = retrievePolicyContext(question);
const contextText = context
.map(
(c) =>
`[${c.policyId} v${c.version} | ${c.jurisdiction}] ${c.title}: ${c.content}`
)
.join("\n");
const prompt = `
Question: ${question}
Policy context:
${contextText}
Instructions:
- Answer in plain English.
- Include bullet points if there are conditions or exceptions.
- Cite every rule with [policyId vversion].
- If no relevant rule exists in context, say you need human review.
`;
const result = await userProxy.initiateChat(assistant, prompt);
return result;
}
4) Add an approval path for risky answers
In fintech you do not want an LLM making final calls on ambiguous cases like sanctions screening exceptions or cross-border data transfers. Route those cases to humans based on keywords or confidence thresholds from your own logic.
function requiresHumanReview(question: string): boolean {
const riskyTerms = ["sanctions", "aml", "kyc", "legal advice", "data residency"];
return riskyTerms.some((term) => question.toLowerCase().includes(term));
}
async function handleQuestion(question: string) {
if (requiresHumanReview(question)) {
return {
status: "review_required",
message:
"This question touches regulated topics. Route it to compliance or legal review.",
};
}
return await answerPolicyQuestion(question);
}
That pattern keeps the model inside its lane. The assistant drafts answers; your application decides whether the answer can be shown directly.
Production Considerations
- •
Deployment
- •Keep retrieval services in-region if policies contain employee or customer data subject to residency constraints.
- •Separate public cloud inference from sensitive document storage when your control framework requires it.
- •
Monitoring
- •Log every question, retrieved chunks, model response, latency, and reviewer override.
- •Track “human review required” rate; spikes usually mean bad retrieval or missing policies.
- •
Guardrails
- •Redact PII before sending prompts to the model.
- •Block questions about sanctions evasion, fraud bypassing, or regulatory interpretation beyond internal text.
- •
Auditability
- •Persist
policyId,version, timestamp, and answer hash. - •When policies change, answers should be reproducible against the exact version used at runtime.
- •Persist
Common Pitfalls
- •
Stuffing too much policy text into one prompt
- •This causes vague answers and weak citations.
- •Fix it by retrieving only relevant chunks plus metadata for traceability.
- •
Letting the model answer outside policy scope
- •If you ask “Is this compliant?” without grounding it in internal rules, the model will guess.
- •Force a fallback like “I need a human review” when evidence is missing.
- •
Ignoring jurisdiction and versioning
- •A US expense rule can be wrong for EU employees even if the wording looks similar.
- •Always filter by jurisdiction and include effective dates/version numbers in every response path.
- •
Skipping audit logs because “it’s just Q&A”
- •In fintech, Q&A becomes evidence during audits and disputes.
- •Store inputs, outputs, source docs, and reviewer actions from day one.
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