How to Integrate LlamaIndex for banking with Supabase for multi-agent systems
Why this integration matters
If you’re building banking agents, you need two things: a reliable retrieval layer and a shared state layer. LlamaIndex for banking handles document ingestion, indexing, and grounded answers over policy docs, KYC records, loan files, and internal runbooks; Supabase gives your multi-agent system Postgres-backed persistence, auth, and event-friendly state.
Together, they let multiple agents coordinate on the same customer case without stepping on each other. One agent can retrieve bank policy context, another can write structured decisions to Supabase, and a supervisor agent can track the full workflow.
Prerequisites
- •Python 3.10+
- •A Supabase project with:
- •
SUPABASE_URL - •
SUPABASE_SERVICE_ROLE_KEYor anon key for limited access
- •
- •A Postgres database in Supabase with tables for:
- •agent state
- •conversation logs
- •task queue or case status
- •LlamaIndex installed with the banking-oriented connectors you use for your data sources
- •
llama-indexcore packages installed - •
supabase-pyinstalled - •Access to your banking documents:
- •PDFs
- •CSV exports
- •internal knowledge base pages
- •An embedding model and LLM configured in your LlamaIndex stack
Install the Python dependencies:
pip install llama-index supabase python-dotenv
Integration Steps
1) Configure credentials and clients
Start by loading environment variables and creating both clients. Keep Supabase credentials server-side; do not ship service keys to the browser.
import os
from dotenv import load_dotenv
from supabase import create_client, Client
load_dotenv()
SUPABASE_URL = os.environ["SUPABASE_URL"]
SUPABASE_KEY = os.environ["SUPABASE_SERVICE_ROLE_KEY"]
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
For LlamaIndex, set up your LLM and embedding model as you normally would in your banking stack.
from llama_index.core import Settings
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI
Settings.llm = OpenAI(model="gpt-4o-mini")
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
2) Load banking documents into LlamaIndex
Use LlamaIndex readers to pull in policy files or customer-support runbooks. In a real banking setup, this is where you ingest compliance docs, lending policies, or fraud escalation playbooks.
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
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 suspected account takeover?")
print(response)
If you already have structured sources like SharePoint exports or internal PDFs, swap in the appropriate reader. The important part is that LlamaIndex becomes the retrieval layer for agent reasoning.
3) Create a Supabase table for agent state
You need shared memory across agents. Store case status, retrieved evidence, and next actions in Supabase so every agent sees the same source of truth.
Example SQL:
create table if not exists agent_cases (
id uuid primary key default gen_random_uuid(),
customer_id text not null,
case_type text not null,
status text not null default 'open',
evidence jsonb not null default '{}'::jsonb,
updated_at timestamptz not null default now()
);
Then write from Python after an agent makes a decision.
case_payload = {
"customer_id": "CUST-10021",
"case_type": "fraud_review",
"status": "needs_human_review",
"evidence": {
"retrieved_policy": str(response),
"agent": "fraud-triage-agent"
}
}
result = supabase.table("agent_cases").insert(case_payload).execute()
print(result.data)
4) Read shared state before each agent action
Multi-agent systems break when agents operate on stale context. Before an agent acts, pull the latest case row from Supabase and feed it back into the prompt or task planner.
case_id = "your-case-id-here"
existing_case = (
supabase.table("agent_cases")
.select("*")
.eq("id", case_id)
.single()
.execute()
)
case_data = existing_case.data
print(case_data)
Now combine that with retrieval from LlamaIndex so the agent has both operational state and policy context.
policy_answer = query_engine.query(
f"Given this case status: {case_data['status']}, what should the next step be?"
)
update_payload = {
"status": "awaiting_compliance_review",
"evidence": {
**case_data["evidence"],
"next_step": str(policy_answer)
}
}
supabase.table("agent_cases").update(update_payload).eq("id", case_id).execute()
5) Wire an orchestrator pattern around both systems
The clean pattern here is: retrieve from LlamaIndex, persist decisions in Supabase, then let another agent continue from that persisted state. This keeps each agent stateless except for its reads/writes to Postgres.
def triage_case(case_id: str):
case_row = (
supabase.table("agent_cases")
.select("*")
.eq("id", case_id)
.single()
.execute()
).data
prompt = f"""
Case type: {case_row['case_type']}
Current status: {case_row['status']}
Evidence: {case_row['evidence']}
What is the next best action according to bank policy?
"""
decision = query_engine.query(prompt)
supabase.table("agent_cases").update({
"status": "triaged",
"evidence": {
**case_row["evidence"],
"triage_decision": str(decision)
}
}).eq("id", case_id).execute()
return decision
That pattern scales well when you add more agents:
- •intake agent creates the case
- •policy agent retrieves grounded guidance from LlamaIndex
- •compliance agent reviews sensitive steps
- •supervisor agent updates final status in Supabase
Testing the Integration
Run a simple end-to-end check: query policy content through LlamaIndex, write a record to Supabase, then read it back.
test_doc_query = query_engine.query("What documents are required for enhanced due diligence?")
insert_result = supabase.table("agent_cases").insert({
"customer_id": "TEST-001",
"case_type": "kYC_review",
"status": "open",
"evidence": {"policy_answer": str(test_doc_query)}
}).execute()
row_id = insert_result.data[0]["id"]
fetched = (
supabase.table("agent_cases")
.select("*")
.eq("id", row_id)
.single()
.execute()
)
print(fetched.data["status"])
print(fetched.data["evidence"]["policy_answer"])
Expected output:
open
Enhanced due diligence typically requires source of funds documentation...
If that round-trip works, your retrieval layer and shared-state layer are connected correctly.
Real-World Use Cases
- •
Fraud investigation workflow
- •One agent retrieves fraud playbooks from LlamaIndex.
- •Another stores investigator notes and evidence in Supabase.
- •A supervisor agent assigns next actions based on current case status.
- •
Loan underwriting assistant
- •The underwriting agent queries lending policies and exception rules.
- •Supabase stores applicant progress, missing documents, and approval flags.
- •Multiple agents can handle income verification, risk checks, and compliance review independently.
- •
Customer service escalation system
- •The support agent grounds responses in bank policy docs.
- •Supabase tracks ticket ownership across agents.
- •A resolution agent closes cases only after all required checks are complete.
This combo gives you grounded reasoning plus durable coordination. That’s the baseline architecture I’d use before adding queues, event streams, or human-in-the-loop approvals.
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