How to Integrate LlamaIndex for investment banking with Supabase for production AI

By Cyprian AaronsUpdated 2026-04-21
llamaindex-for-investment-bankingsupabaseproduction-ai

Why this integration matters

If you’re building AI for investment banking, you need two things working together: retrieval over sensitive deal content and a durable system of record for prompts, outputs, feedback, and audit trails. LlamaIndex gives you the retrieval layer over filings, CIMs, earnings decks, and internal research; Supabase gives you Postgres-backed storage, auth, and row-level security for production workflows.

The result is a practical agent stack: ingest bank documents into LlamaIndex, persist metadata and conversation state in Supabase, then serve answers with traceability. That’s the difference between a demo and something a banking team can actually run.

Prerequisites

  • Python 3.10+
  • A Supabase project with:
    • Project URL
    • An API key
    • A Postgres database enabled
  • Access to your investment banking document corpus:
    • PDFs, DOCX, text files, or extracted deal notes
  • LlamaIndex installed with the connectors you need
  • supabase-py installed
  • Environment variables set:
    • SUPABASE_URL
    • SUPABASE_SERVICE_ROLE_KEY or anon key for limited access
    • OPENAI_API_KEY or another embedding/LLM provider key
  • A local .env file or secret manager in place

Install the packages:

pip install llama-index supabase python-dotenv pypdf

Integration Steps

1) Connect to Supabase and load configuration

Start by wiring Supabase into your app. In production, use the service role key only on the backend.

import os
from dotenv import load_dotenv
from supabase import create_client, Client

load_dotenv()

SUPABASE_URL = os.getenv("SUPABASE_URL")
SUPABASE_KEY = os.getenv("SUPABASE_SERVICE_ROLE_KEY")

supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)

# quick health check: read from a table you created for agent logs
response = supabase.table("agent_runs").select("*").limit(1).execute()
print(response.data)

Create a simple table for audit logs if you don’t have one yet:

create table if not exists agent_runs (
  id bigserial primary key,
  user_id text,
  query text not null,
  answer text not null,
  source_count int default 0,
  created_at timestamptz default now()
);

2) Build a LlamaIndex document index for banking content

Use LlamaIndex to ingest deal docs or research notes. For investment banking use cases, keep documents split by source so citations stay clean.

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader

docs = SimpleDirectoryReader("./banking_docs").load_data()

index = VectorStoreIndex.from_documents(docs)
query_engine = index.as_query_engine(similarity_top_k=5)

response = query_engine.query("Summarize revenue drivers and key risks in this company.")
print(response)

If your corpus is large, swap in persistent storage and a proper vector backend. The pattern stays the same: LlamaIndex handles retrieval orchestration; your storage layer handles persistence.

3) Persist agent requests and responses in Supabase

Every production banking workflow needs traceability. Store the user question, model answer, and retrieval metadata in Supabase after each run.

query_text = "What are the main valuation concerns in this target?"
result = query_engine.query(query_text)

supabase.table("agent_runs").insert({
    "user_id": "banking_analyst_001",
    "query": query_text,
    "answer": str(result),
    "source_count": len(getattr(result, "source_nodes", []))
}).execute()

print("Saved run to Supabase")

This gives you an audit trail for compliance reviews and internal QA. It also makes it easy to inspect failure cases later.

4) Store retrieved chunks or citations in Supabase for reuse

For repeated analyst workflows, cache retrieved chunks in Postgres so agents can reuse context without re-querying every time. This is useful for deal teams that ask similar questions across multiple sessions.

retrieved_nodes = result.source_nodes[:3]

for node in retrieved_nodes:
    supabase.table("retrieval_cache").insert({
        "doc_id": node.node.metadata.get("file_name", "unknown"),
        "chunk_text": node.node.text[:2000],
        "score": float(node.score) if node.score is not None else None,
        "query": query_text
    }).execute()

Suggested table:

create table if not exists retrieval_cache (
  id bigserial primary key,
  doc_id text,
  chunk_text text not null,
  score numeric,
  query text,
  created_at timestamptz default now()
);

5) Query Supabase to power an agent memory layer

Use Supabase as lightweight memory for follow-up questions. This works well when bankers ask iterative questions like “show me the last answer” or “what docs did we use?”

history = supabase.table("agent_runs") \
    .select("query, answer, created_at") \
    .eq("user_id", "banking_analyst_001") \
    .order("created_at", desc=True) \
    .limit(5) \
    .execute()

for row in history.data:
    print(row["created_at"], row["query"])

That pattern lets you build a session-aware assistant without stuffing everything into the prompt. Keep state in Postgres; keep reasoning in the model layer.

Testing the Integration

Run one end-to-end test: retrieve from LlamaIndex, write to Supabase, then read it back.

test_query = "What are the biggest risks mentioned in this filing?"
test_result = query_engine.query(test_query)

inserted = supabase.table("agent_runs").insert({
    "user_id": "test_user",
    "query": test_query,
    "answer": str(test_result),
    "source_count": len(getattr(test_result, "source_nodes", []))
}).execute()

fetched = supabase.table("agent_runs") \
    .select("*") \
    .eq("user_id", "test_user") \
    .order("created_at", desc=True) \
    .limit(1) \
    .execute()

print(fetched.data[0]["query"])
print(fetched.data[0]["source_count"])

Expected output:

What are the biggest risks mentioned in this filing?
3

If source_count is zero, your index is probably empty or your documents aren’t being parsed correctly.

Real-World Use Cases

  • Deal diligence assistant

    • Search CIMs, earnings transcripts, and internal notes with LlamaIndex.
    • Store answers and citations in Supabase for compliance review.
  • Analyst copilot with memory

    • Persist user sessions, prior questions, and preferred templates in Supabase.
    • Use LlamaIndex to answer follow-up questions from deal documents.
  • Research QA pipeline

    • Run automated checks on generated summaries.
    • Save outputs and reviewer feedback in Supabase for human-in-the-loop approval.

If you want this to survive production traffic in banking, keep the responsibilities clean: LlamaIndex handles retrieval and synthesis; Supabase handles persistence, access control, and auditability. That separation is what keeps the system maintainable when the first pilot turns into a real desk workflow.


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