How to Build a policy Q&A Agent Using AutoGen in TypeScript for investment banking

By Cyprian AaronsUpdated 2026-04-21
policy-q-aautogentypescriptinvestment-bankingpolicy-qanda

A policy Q&A agent for investment banking answers internal questions about trading policies, compliance rules, client communication standards, and operational procedures. It matters because bankers need fast, consistent answers without exposing sensitive policy text to the wrong people or letting a model invent guidance that could trigger compliance issues.

Architecture

  • User interface

    • A chat surface in Slack, Teams, or an internal web app.
    • Keep it thin. The real control belongs in the backend.
  • Policy retrieval layer

    • Pulls from approved sources: policy PDFs, wiki pages, control manuals, SOPs.
    • Uses document chunking plus embeddings or keyword retrieval before the LLM sees anything.
  • AutoGen agent runtime

    • AssistantAgent handles the Q&A behavior.
    • UserProxyAgent orchestrates execution and can enforce tool calls or human review.
  • Compliance guardrail layer

    • Blocks prohibited topics, redacts PII, and enforces jurisdiction-specific rules.
    • Logs every answer with source references for audit.
  • Audit and observability

    • Stores prompt, retrieved passages, final answer, user identity, timestamp, and policy version.
    • Required for model risk management and post-trade review workflows.
  • Data residency boundary

    • Keeps documents and logs in approved regions.
    • Matters if your bank has strict EU/UK/US separation requirements.

Implementation

1) Install AutoGen and define your runtime config

Use the TypeScript package for AutoGen and keep model settings explicit. In investment banking, do not rely on defaults you cannot explain to compliance or risk teams.

npm install @autogenai/autogen
import { AssistantAgent, UserProxyAgent } from "@autogenai/autogen";

const llmConfig = {
  model: "gpt-4o-mini",
  apiKey: process.env.OPENAI_API_KEY!,
};

const assistant = new AssistantAgent({
  name: "policy_qa_assistant",
  systemMessage: `
You answer only from provided policy context.
If the context is insufficient, say you cannot confirm the policy.
Always cite the source snippets used.
Do not provide legal advice.
`,
  llmConfig,
});

const userProxy = new UserProxyAgent({
  name: "policy_qa_user",
});

2) Build a retrieval function over approved policy content

For a real bank, this should query your document store or vector index. The important part is that the assistant only sees approved snippets plus metadata like document name and version.

type PolicyChunk = {
  source: string;
  section: string;
  text: string;
};

const policyIndex: PolicyChunk[] = [
  {
    source: "IB-Compliance-Handbook-v7.3",
    section: "Client Communications / Email Approval",
    text: "All external client-facing communications must be reviewed by an approved supervisor when discussing live deals or pricing.",
  },
  {
    source: "IB-Market-Abuse-Policy-v4.1",
    section: "Restricted Lists",
    text: "Employees must not disclose restricted list information to unauthorized persons under any circumstance.",
  },
];

function retrievePolicyContext(query: string): string {
  const hits = policyIndex.filter((chunk) =>
    query.toLowerCase().includes("email") || query.toLowerCase().includes("client")
      ? chunk.section.includes("Client Communications")
      : query.toLowerCase().includes("restricted")
        ? chunk.section.includes("Restricted Lists")
        : true
  );

  return hits
    .map(
      (chunk) =>
        `[Source: ${chunk.source} | Section: ${chunk.section}]\n${chunk.text}`
    )
    .join("\n\n");
}

3) Run the agent with a strict prompt pattern

The pattern here is simple: retrieve context first, then ask the assistant to answer only from that context. For investment banking policies, this is better than free-form chat because it creates an auditable chain from question to source text.

async function answerPolicyQuestion(question: string) {
  const context = retrievePolicyContext(question);

  const prompt = `
Question:
${question}

Approved policy context:
${context}

Instructions:
- Answer strictly from the approved context.
- If the answer is not fully supported, say so.
- Include bullet-point citations using the source names above.
`;

  const result = await assistant.generateReply([{ role: "user", content: prompt }]);

  return result.content;
}

async function main() {
  const question = "Can I email a client about a live deal without supervisor approval?";
  const answer = await answerPolicyQuestion(question);
  console.log(answer);
}

main().catch(console.error);

4) Add human-in-the-loop escalation for ambiguous questions

In banking, ambiguity should route to compliance rather than producing a confident guess. AutoGen gives you a clean place to insert approval gates before returning an answer to users.

async function safeAnswer(question: string) {
  const answer = await answerPolicyQuestion(question);

  if (
    answer.toLowerCase().includes("cannot confirm") ||
    answer.toLowerCase().includes("insufficient")
  ) {
    return {
      status: "needs_review",
      message: "This question requires compliance review.",
      draftAnswer: answer,
    };
  }

  return {
    status: "approved",
    message: answer,
  };
}

Production Considerations

  • Audit every interaction

    • Store question text, retrieved sources, model response, user ID, and policy version.
    • This is mandatory when internal audit asks why a banker received a specific instruction.
  • Enforce data residency

    • Keep embeddings, logs, and raw documents inside approved regions.
    • Do not send restricted content across borders just because your LLM endpoint is elsewhere.
  • Add deterministic guardrails

    • Block prompts containing requests for insider information, trade recommendations based on MNPI, or bypassing supervision controls.
    • Use rule-based filters before the LLM call and after generation.
  • Monitor hallucination rate by topic

    • Track unanswered questions by policy domain.
    • If “restricted list,” “client communications,” or “Chinese wall” queries spike in escalations, your retrieval coverage is weak.

Common Pitfalls

  • Letting the model answer without retrieved context

    This turns your agent into a generic chatbot with compliance risk. Always pass approved snippets into the prompt and force abstention when evidence is missing.

  • Skipping source versioning

    A policy Q&A agent that does not record document version numbers will fail audit. Store exact versions so you can prove what was in force at response time.

  • Using one global prompt for all jurisdictions

    Banking policies differ across regions. A UK desk may have different disclosure rules than a US desk, so route by entity, desk location, and user entitlements before retrieving context.


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