Agentic RAG
Combining Retrieval-Augmented Generation with Agents β self-search, self-evaluate, self-correct
Traditional RAG vs Agentic RAG
Traditional RAG
User query β Embed β Search vector DB β Return top-K β Generate answer
A fixed pipeline with no ability to self-evaluate results.
Agentic RAG
User query β Agent analyzes β Choose search strategy
β Search β Evaluate results
β Not enough? β Modify query β Search again
β Good enough? β Generate answer
The agent autonomously decides the approach, evaluates results, and self-corrects when needed.
Key Differences
| Aspect | Traditional RAG | Agentic RAG |
|---|---|---|
| Flow | Fixed pipeline | Agent decides |
| Evaluation | None | Self-evaluates results |
| Self-correction | None | Yes, auto-retry |
| Multi-source | Single vector DB | Multiple sources, tools |
| Complexity | Low | High |
Building Agentic RAG With Supabase pgvector
Step 1: Setup Vector Store
-- In Supabase SQL Editor
create extension if not exists vector;
create table documents (
id bigserial primary key,
content text,
metadata jsonb,
embedding vector(1536) -- OpenAI text-embedding-3-small
);
create index on documents
using ivfflat (embedding vector_cosine_ops)
with (lists = 100);
-- Semantic search function
create or replace function match_documents(
query_embedding vector(1536),
match_threshold float default 0.7,
match_count int default 5
) returns table (
id bigint,
content text,
metadata jsonb,
similarity float
) language plpgsql as $$
begin
return query
select
d.id, d.content, d.metadata,
1 - (d.embedding <=> query_embedding) as similarity
from documents d
where 1 - (d.embedding <=> query_embedding) > match_threshold
order by d.embedding <=> query_embedding
limit match_count;
end;
$$;
Step 2: Embedding & Retrieval Agent
import { generateText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { createClient } from "@supabase/supabase-js";
import { z } from "zod";
const supabase = createClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_KEY!
);
const searchDocuments = tool({
description: "Search for relevant documents in the knowledge base",
parameters: z.object({
query: z.string().describe("Question or topic to search for"),
threshold: z.number().default(0.7).describe("Similarity threshold (0-1)")
}),
execute: async ({ query, threshold }) => {
const embeddingResponse = await openai.embeddings.create({
model: "text-embedding-3-small",
input: query
});
const queryEmbedding = embeddingResponse.data[0].embedding;
const { data, error } = await supabase.rpc("match_documents", {
query_embedding: queryEmbedding,
match_threshold: threshold,
match_count: 5
});
if (error) return { success: false, error: error.message };
return { success: true, documents: data };
}
});
const refineSearch = tool({
description: "Search again with an adjusted query when initial results are insufficient",
parameters: z.object({
originalQuery: z.string(),
refinedQuery: z.string(),
reason: z.string().describe("Reason for refining")
}),
execute: async ({ refinedQuery }) => {
return { success: true, documents: [] };
}
});
Step 3: Self-Evaluating Agent Loop
const result = await generateText({
model: openai("gpt-4o"),
system: `You are an intelligent search assistant. Process:
1. Search for relevant documents
2. Evaluate result quality (relevance, completeness)
3. If results aren't good enough, refine query and search again
4. Only answer when you have reliable information
5. If you can't find anything, say so honestly`,
tools: { searchDocuments, refineSearch },
maxSteps: 8,
prompt: userQuestion
});
Corrective RAG
A critical pattern: the agent self-corrects when it detects issues.
const evaluateAndCorrect = tool({
description: "Evaluate retrieval results and decide next step",
parameters: z.object({
retrievedDocs: z.array(z.string()),
queryIntent: z.string(),
assessment: z.enum(["sufficient", "partial", "insufficient"]),
nextAction: z.enum(["answer", "refine_query", "try_different_source", "admit_unknown"])
}),
execute: async ({ assessment, nextAction }) => {
return { assessment, nextAction, message: `Assessment: ${assessment}. Action: ${nextAction}` };
}
});
Self-Correction Flow
Query β Search β Evaluate results
βββ Sufficient β Generate answer
βββ Partial β Refine query β Search again
βββ Insufficient β Try different source
βββ Repeatedly failing β Admit unknown
Best Practices
- Set appropriate similarity thresholds β too high (>0.9) misses results, too low (<0.5) returns noise
- Limit loop iterations β maxSteps 5-8 is reasonable, avoid infinite loops
- Log every step β observability is key to debugging Agentic RAG
- Fallback to human β when the agent is uncertain, ask the user
Summary
- Agentic RAG = RAG + Agent that decides, evaluates, and self-corrects
- Use Supabase pgvector for the vector store
- Corrective RAG pattern: evaluate β refine β retry
- Agent knows when to stop and admit it doesnβt know