How to Integrate LlamaIndex for banking with Supabase for AI agents

By Cyprian AaronsUpdated 2026-04-22
llamaindex-for-bankingsupabaseai-agents

Combining LlamaIndex for banking with Supabase gives you a clean pattern for building AI agents that can retrieve regulated banking knowledge, store conversation state, and persist audit-friendly metadata in one stack. LlamaIndex handles retrieval and tool orchestration; Supabase gives you Postgres, auth, and a simple API for persistence.

Prerequisites

  • Python 3.10+
  • A Supabase project with:
    • SUPABASE_URL
    • SUPABASE_SERVICE_ROLE_KEY or anon key for read-only access
  • A vector-enabled Postgres setup in Supabase
  • LlamaIndex installed with the banking-specific package or your internal banking index wrapper
  • An embeddings provider configured, such as OpenAI or Azure OpenAI
  • Access to the documents you want to index:
    • policy docs
    • product terms
    • KYC/AML procedures
    • support playbooks

Install the core packages:

pip install llama-index supabase python-dotenv sqlalchemy psycopg2-binary

Integration Steps

  1. Set up environment variables and connect to Supabase.

Use .env so your agent runtime stays clean.

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)
print("Supabase connected")

At this point you should be able to read and write rows through the Supabase client. In production, use the service role key only from backend services.

  1. Create a table for agent memory and retrieval metadata.

For banking agents, keep message history separate from indexed knowledge. That makes auditing easier and avoids mixing user chat with source documents.

from supabase import create_client

schema_sql = """
create table if not exists agent_messages (
    id bigserial primary key,
    session_id text not null,
    role text not null,
    content text not null,
    created_at timestamptz default now()
);
"""

# Run this once via SQL editor or your migration tool.
print(schema_sql)

If you want vector search in Supabase, add a documents table with an embedding column:

create table if not exists bank_documents (
    id bigserial primary key,
    title text not null,
    content text not null,
    metadata jsonb default '{}'::jsonb,
    embedding vector(1536)
);
  1. Build a LlamaIndex index from banking documents.

This example uses VectorStoreIndex and a simple directory reader. Swap in your own loaders for PDFs, SharePoint exports, or internal policy stores.

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.embeddings.openai import OpenAIEmbedding

Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")

documents = SimpleDirectoryReader("./banking_docs").load_data()
index = VectorStoreIndex.from_documents(documents)

query_engine = index.as_query_engine(similarity_top_k=3)
response = query_engine.query("What is the escalation path for suspicious transaction alerts?")
print(response)

For banking use cases, chunking matters. Keep sections small enough to preserve context like thresholds, exceptions, and approval chains.

  1. Persist agent state in Supabase after each interaction.

Your agent should write both user input and model output to Supabase. That gives you traceability when compliance asks who asked what and what the assistant answered.

def save_message(session_id: str, role: str, content: str):
    supabase.table("agent_messages").insert({
        "session_id": session_id,
        "role": role,
        "content": content,
    }).execute()

session_id = "sess_001"
user_question = "Can I waive the monthly fee for a premium customer?"

save_message(session_id, "user", user_question)

answer = query_engine.query(user_question)
save_message(session_id, "assistant", str(answer))

If you need structured metadata, store it alongside the message:

supabase.table("agent_messages").insert({
    "session_id": session_id,
    "role": "assistant",
    "content": str(answer),
}).execute()
  1. Query Supabase from LlamaIndex for retrieval-augmented responses.

If your source of truth lives in Postgres tables rather than flat files, use a SQL-aware retriever. This is useful for balances, product catalogs, or policy lookup tables.

from llama_index.core.indices.struct_store import SQLTableRetrieverQueryEngine
from llama_index.core.objects import ObjectIndex
from llama_index.core.indices.struct_store.sql_retriever import NLSQLRetriever

# Example assumes you've already connected SQLAlchemy engine to Supabase Postgres.
# Use your postgres connection string here.
postgres_url = os.getenv("SUPABASE_POSTGRES_URL")

from sqlalchemy import create_engine
engine = create_engine(postgres_url)

sql_retriever = NLSQLRetriever(
    sql_database=None,
    tables=["bank_documents"],
)

# In practice wire this to a proper SQLDatabase object.
print("SQL retriever ready")

For many teams, the cleaner pattern is:

  • LlamaIndex handles document retrieval over indexed policy docs
  • Supabase stores sessions, feedback, approvals, and operational data

That separation keeps the system maintainable.

Testing the Integration

Run one end-to-end check: ask a question, generate an answer from LlamaIndex, then persist it in Supabase.

test_session_id = "test_sess_123"
question = "What documents are required for corporate account onboarding?"

save_message(test_session_id, "user", question)
result = query_engine.query(question)
save_message(test_session_id, "assistant", str(result))

rows = supabase.table("agent_messages").select("*").eq("session_id", test_session_id).execute()
print(rows.data)

Expected output:

[
  {"session_id": "test_sess_123", "role": "user", "content": "What documents are required...", ...},
  {"session_id": "test_sess_123", "role": "assistant", "content": "...answer grounded in banking docs...", ...}
]

If that returns two rows and the answer references your indexed policy content, the integration is working.

Real-World Use Cases

  • Compliance assistant

    • Retrieve KYC/AML procedures from LlamaIndex.
    • Store every user prompt and answer in Supabase for audit review.
  • Banking support copilot

    • Answer questions about fees, limits, card replacement flows, and escalation rules.
    • Keep conversation state in Supabase so agents can resume context across sessions.
  • Internal policy bot

    • Index HR or operations manuals with LlamaIndex.
    • Use Supabase to track feedback on bad answers and route them back into document updates.

The practical win here is simple: LlamaIndex gives your agent grounded answers from controlled banking content; Supabase gives you durable state and operational control. That combination is strong enough for real systems where auditability matters more than demo polish.


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