How to Build a policy Q&A Agent Using LlamaIndex in TypeScript for wealth management

By Cyprian AaronsUpdated 2026-04-21
policy-q-allamaindextypescriptwealth-managementpolicy-qanda

A policy Q&A agent for wealth management answers client and advisor questions from approved internal documents: suitability rules, fee policies, KYC/AML procedures, product constraints, and escalation playbooks. It matters because the difference between a correct answer and a sloppy one is compliance risk, client trust, and auditability.

Architecture

  • Document ingestion layer

    • Pull policy PDFs, Word docs, and internal wiki pages from approved sources.
    • Normalize them into text chunks with metadata like policyType, jurisdiction, effectiveDate, and owner.
  • Embedding and index layer

    • Use LlamaIndex to turn policy chunks into vectors.
    • Store them in a vector index for semantic retrieval across long policy libraries.
  • Retriever

    • Fetch only the most relevant policy sections for a user question.
    • Add metadata filters for jurisdiction, product line, or advisor channel when needed.
  • Response synthesizer

    • Generate answers grounded in retrieved policy text.
    • Force citations so the agent can show where each answer came from.
  • Guardrail layer

    • Block unsupported advice, portfolio recommendations, or anything outside policy scope.
    • Route sensitive questions to human compliance review.
  • Audit logging

    • Persist the user question, retrieved chunks, answer text, and document IDs.
    • Keep this for supervision, incident review, and regulator requests.

Implementation

1. Install the TypeScript packages

You need the core LlamaIndex package plus an embedding model. For production wealth workflows, keep your model choice explicit so compliance can review it.

npm install llamaindex dotenv

Set your OpenAI key in .env:

OPENAI_API_KEY=your_key_here

2. Load policy documents and build the index

This example uses SimpleDirectoryReader, VectorStoreIndex, and Settings. The pattern is simple: load approved files, chunk them, embed them, then query against that index.

import "dotenv/config";
import {
  Settings,
  SimpleDirectoryReader,
  VectorStoreIndex,
} from "llamaindex";

async function main() {
  const documents = await new SimpleDirectoryReader().loadData({
    directoryPath: "./policy-docs",
  });

  Settings.chunkSize = 1024;
  Settings.chunkOverlap = 150;

  const index = await VectorStoreIndex.fromDocuments(documents);

  const queryEngine = index.asQueryEngine({
    similarityTopK: 3,
  });

  const response = await queryEngine.query({
    query: "What is the approval process for discretionary portfolio changes?",
  });

  console.log(response.toString());
}

main().catch(console.error);

That gets you a working baseline. In wealth management, I would not stop here; you still need metadata control and audit logging.

3. Add metadata-aware retrieval for jurisdiction and policy type

Wealth firms rarely have one global policy set. You usually need to filter by region, business line, or client segment before answering.

import "dotenv/config";
import {
  MetadataFilter,
  MetadataFilters,
  SimpleDirectoryReader,
  VectorStoreIndex,
} from "llamaindex";

async function buildAgent() {
  const documents = await new SimpleDirectoryReader().loadData({
    directoryPath: "./policy-docs",
    fileExts: [".pdf", ".docx", ".txt"],
    metadata: (file) => ({
      sourceFile: file.name,
      jurisdiction: file.name.includes("UK") ? "UK" : "US",
      policyType: file.name.includes("KYC") ? "KYC" : "General",
    }),
  });

  const index = await VectorStoreIndex.fromDocuments(documents);

  const retriever = index.asRetriever({
    similarityTopK: 5,
    filters: new MetadataFilters({
      filters: [
        new MetadataFilter({
          key: "jurisdiction",
          value: "US",
        }),
      ],
    }),
  });

  return retriever;
}

This matters when the same question has different answers depending on domicile or regulator. A UK adviser policy is not interchangeable with a US retail suitability rule.

4. Wrap retrieval with a compliance-safe answer flow

For wealth management, you want a controlled answer format: answer only from sources, cite them, and refuse unsupported requests. Use the retriever output as the only context passed into synthesis.

import { OpenAI } from "llamaindex";

async function answerQuestion(question: string) {
  const retriever = await buildAgent();
  const nodes = await retriever.retrieve(question);

  if (nodes.length === null || nodes.length === undefined || nodes.length === no) {
    throw new Error("No relevant policy found; escalate to compliance.");
}

The above snippet shows the shape of the flow; in practice you should complete it with response synthesis using queryEngine.query() or a custom prompt that requires citations. The important part is that your application never lets the model freewheel outside retrieved policy text.

Production Considerations

  • Deployment

    • Keep ingestion offline from runtime answering.
    • Rebuild indexes on a schedule or on document change events so advisors always see current policies.
    • Pin model versions and embeddings so responses remain stable for audit review.
  • Monitoring

    • Log question text, retrieved node IDs, source files, and final response.
    • Track “no answer found” rates because they often reveal missing policies or bad chunking.
    • Sample responses for compliance QA weekly.
  • Guardrails


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