{"slug": "how-to-build-a-production-grade-rag-agent-with-hybrid-search-in-30-minutes", "title": "How to Build a Production-Grade RAG Agent with Hybrid Search in 30 Minutes", "summary": "A developer detailed a production-grade RAG agent architecture that combines hybrid search with Reciprocal Rank Fusion (RRF) and a LangGraph supervisor agent. The approach uses PostgreSQL's pgvector for dense embeddings and full-text search for sparse retrieval, executed in a single SQL query. The developer emphasized that naive vector-only retrieval fails on exact keywords, acronyms, and error codes, and the hybrid method improves accuracy for enterprise knowledge bases.", "body_md": "Most Retrieval-Augmented Generation (RAG) tutorials stop at a naive vector lookup: embed text with OpenAI, store it in Pinecone or Chroma, and perform cosine similarity search.\n\nIn production environments, this naive approach quickly fails. Vector embeddings excel at semantic similarity, but they consistently stumble on exact keywords, acronyms, product SKUs, UUIDs, and domain-specific error codes.\n\nTo build an enterprise-grade RAG agent, you need **Hybrid Search with Reciprocal Rank Fusion (RRF)** combined with a deterministic multi-agent harness.\n\n`pgvector`\n\n)Consider a developer searching an enterprise knowledge base for:\n\n`\"Fix CVE-2024-38077 Windows Netlogon RPC buffer overflow\"`\n\n`\"CVE-2024-38077\"`\n\n, but misses related contextual documentation that uses synonyms like `\"Netlogon remote elevation vulnerability\"`\n\n.\n### The Solution: Hybrid Search + Reciprocal Rank Fusion (RRF)\nHybrid search executes both retrieval pipelines concurrently and merges the candidate rankings using the mathematical RRF formula:\n$$\\text{RRF Score}(d) = \\sum_{m \\in M} \\frac{1}{60 + r_m(d)}$$\nWhere:`pgvector`\n\n+ `tsvector`\n\n)\nYou don't need a separate vector database. PostgreSQL handles dense vector embeddings and sparse full-text search within a single atomic ACID transaction.\n\n```\nsql\n-- Enable vector extension\nCREATE EXTENSION IF NOT EXISTS vector;\n-- Create enterprise knowledge documents table\nCREATE TABLE enterprise_documents (\n    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n    tenant_id VARCHAR(64) NOT NULL,\n    title TEXT NOT NULL,\n    content TEXT NOT NULL,\n    search_vector TSVECTOR GENERATED ALWAYS AS (to_tsvector('english', title || ' ' || content)) STORED,\n    embedding VECTOR(1536), -- Compatible with text-embedding-3-small\n    metadata JSONB DEFAULT '{}'::jsonb,\n    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n);\n-- Fast approximate nearest neighbor index (HNSW)\nCREATE INDEX ON enterprise_documents USING hnsw (embedding vector_cosine_ops)\nWITH (m = 16, ef_construction = 64);\n-- High-performance GIN index for sparse full-text search\nCREATE INDEX ON enterprise_documents USING gin(search_vector);\n3. The SQL Reciprocal Rank Fusion (RRF) Query\nHere is the single SQL query that executes both dense and sparse retrieval in parallel and merges them via RRF:\n\nsql\nWITH dense_candidates AS (\n    SELECT id, content, metadata,\n           rank() OVER (ORDER BY embedding <=> $1) as d_rank\n    FROM enterprise_documents\n    WHERE tenant_id = $3\n    LIMIT 50\n),\nsparse_candidates AS (\n    SELECT id, content, metadata,\n           rank() OVER (ORDER BY ts_rank_cd(search_vector, plainto_tsquery($2)) DESC) as s_rank\n    FROM enterprise_documents\n    WHERE tenant_id = $3 AND search_vector @@ plainto_tsquery($2)\n    LIMIT 50\n)\nSELECT \n    COALESCE(d.id, s.id) as id,\n    COALESCE(d.content, s.content) as content,\n    COALESCE(d.metadata, s.metadata) as metadata,\n    (COALESCE(1.0 / (60 + d.d_rank), 0.0) + COALESCE(1.0 / (60 + s.s_rank), 0.0)) as fusion_score\nFROM dense_candidates d\nFULL OUTER JOIN sparse_candidates s ON d.id = s.id\nORDER BY fusion_score DESC\nLIMIT 10;\n4. Connecting the Retrieval Engine to LangGraph\nNow we wrap the hybrid search function inside an autonomous LangGraph Supervisor Agent that can analyze the retrieved context and verify facts before generating an answer.\n\ntypescript\nimport { StateGraph, END, START } from '@langchain/langgraph';\nimport { HybridSearchEngine } from './tools/hybridSearch';\nexport async function createRAGAgent() {\n  const searchEngine = new HybridSearchEngine(process.env.DATABASE_URL!);\n  const workflow = new StateGraph({\n    // Define state channels\n    channels: {\n      query: { value: (x, y) => y ?? x, default: () => '' },\n      retrievedContext: { value: (x, y) => y ?? x, default: () => [] },\n      finalAnswer: { value: (x, y) => y ?? x, default: () => '' },\n    }\n  });\n  // Step 1: Hybrid Retrieval Node\n  workflow.addNode('retrieve', async (state) => {\n    const embedding = await generateEmbedding(state.query);\n    const results = await searchEngine.search(state.query, embedding, 5);\n    return { retrievedContext: results };\n  });\n  // Step 2: Answer Generation Node (Claude 3.5 Sonnet)\n  workflow.addNode('synthesize', async (state) => {\n    const answer = await generateGroundedAnswer(state.query, state.retrievedContext);\n    return { finalAnswer: answer };\n  });\n  workflow.addEdge(START, 'retrieve');\n  workflow.addEdge('retrieve', 'synthesize');\n  workflow.addEdge('synthesize', END);\n  return workflow.compile();\n}\n5. Architectural Checklist for Production RAG\nBefore rolling this out to production users, enforce these 4 guardrails:\n\nStrict Multi-Tenant Row-Level Security (RLS): Ensure tenant IDs are parameterized at the DB connection level.\nContext Window Truncation: Dynamically budget token usage with tiktoken to prevent context overflow.\nCross-Encoder Re-ranking: For legal/medical data, add a secondary cross-encoder re-ranking pass (cohere.rerank or bge-reranker-large).\nHallucination Tripwires: Measure output faithfulness against retrieved <context> chunks using an automated LLM-as-a-Judge pass.\n🚀 Complete Production Starter Kits & Resources\nIf you are building autonomous AI agents or production RAG systems, explore our battle-tested templates:\n\n⭐️ Open-Source Claude Skills Starter Kit — Free on GitHub\n📦 LangGraph Multi-Agent Production Starter Kit ($29) — Full TypeScript + Python code with Redis & pgvector memory\n📋 Claude Code & Agent Prompt Templates Pack ($19) — 50 battle-tested production prompts\n🛠️ Claude AI Engineering Skills Pack — 84 Skills ($49) — (Use coupon LAUNCH20 for 20% off)\nHow are you currently handling hybrid search and agent orchestration in your stack? Let's discuss in the comments!\n```\n\n", "url": "https://wpnews.pro/news/how-to-build-a-production-grade-rag-agent-with-hybrid-search-in-30-minutes", "canonical_source": "https://dev.to/yevhen_shaforostov_5a73a4/how-to-build-a-production-grade-rag-agent-with-hybrid-search-in-30-minutes-31of", "published_at": "2026-08-29 16:46:20+00:00", "updated_at": "2026-08-29 17:19:01.191611+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-agents", "developer-tools"], "entities": ["OpenAI", "Pinecone", "Chroma", "PostgreSQL", "pgvector", "LangGraph", "CVE-2024-38077"], "alternates": {"html": "https://wpnews.pro/news/how-to-build-a-production-grade-rag-agent-with-hybrid-search-in-30-minutes", "markdown": "https://wpnews.pro/news/how-to-build-a-production-grade-rag-agent-with-hybrid-search-in-30-minutes.md", "text": "https://wpnews.pro/news/how-to-build-a-production-grade-rag-agent-with-hybrid-search-in-30-minutes.txt", "jsonld": "https://wpnews.pro/news/how-to-build-a-production-grade-rag-agent-with-hybrid-search-in-30-minutes.jsonld"}}