<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mithilesh Kumar</title>
    <description>The latest articles on DEV Community by Mithilesh Kumar (@mithxcode).</description>
    <link>https://dev.to/mithxcode</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4066830%2Fb9998848-6ae0-4829-8a40-d780510d7725.jpg</url>
      <title>DEV Community: Mithilesh Kumar</title>
      <link>https://dev.to/mithxcode</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mithxcode"/>
    <language>en</language>
    <item>
      <title>Beyond Basic RAG: Building Production-Grade Agentic Workflows with Hybrid Search and Custom Re-Ranking</title>
      <dc:creator>Mithilesh Kumar</dc:creator>
      <pubDate>Tue, 11 Aug 2026 14:30:22 +0000</pubDate>
      <link>https://dev.to/mithxcode/beyond-basic-rag-building-production-grade-agentic-workflows-with-hybrid-search-and-custom-5c5e</link>
      <guid>https://dev.to/mithxcode/beyond-basic-rag-building-production-grade-agentic-workflows-with-hybrid-search-and-custom-5c5e</guid>
      <description>&lt;p&gt;By &lt;strong&gt;Mithilesh Kumar&lt;/strong&gt; | AI Engineer &amp;amp; Systems Architect&lt;/p&gt;

&lt;p&gt;Standard Retrieval-Augmented Generation (RAG) pipelines often hit a wall in production environments. While simple vector similarity search works well for basic Q&amp;amp;A demos, real-world enterprise applications demand multi-step reasoning, precise contextual retrieval, and dynamic decision-making.&lt;/p&gt;

&lt;p&gt;When building scalable AI systems, relying solely on dense vector embeddings leads to missing exact-keyword matches, failing on complex multi-part queries, and introducing unnecessary LLM hallucinations.&lt;/p&gt;

&lt;p&gt;In this guide, I will walk you through building a &lt;strong&gt;Production-Grade Agentic RAG Architecture&lt;/strong&gt; using &lt;strong&gt;Hybrid Search (Dense + Sparse)&lt;/strong&gt;, &lt;strong&gt;Cross-Encoder Re-Ranking&lt;/strong&gt;, and &lt;strong&gt;Stateful Agent Workflows&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Bottlenecks of Naive RAG in Production
&lt;/h2&gt;

&lt;p&gt;In a standard Naive RAG setup, the pipeline follows a rigid pattern: &lt;code&gt;User Query -&amp;gt; Embedding -&amp;gt; Vector DB Lookup -&amp;gt; LLM Context Window&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This approach fails in production due to three critical bottlenecks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Semantic Shift &amp;amp; Loss of Keywords:&lt;/strong&gt; Vector embeddings capture semantic meaning but struggle with specific product IDs, technical code snippets, or proper nouns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top-K Irrelevance:&lt;/strong&gt; Retrieving top-k documents purely based on cosine similarity often pulls in contextually adjacent but factually useless chunks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single-Shot Failure:&lt;/strong&gt; Real-world queries require multi-step decomposition. A single retrieval step cannot handle queries that require comparing two distinct documents or routing to different data sources.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  2. The Architectural Blueprint
&lt;/h2&gt;

&lt;p&gt;To solve these challenges, we replace the linear pipeline with an &lt;strong&gt;Agentic Workflow&lt;/strong&gt; supported by a dual-retrieval and re-ranking engine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frsj2ci8pv9d82zdvegpd.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frsj2ci8pv9d82zdvegpd.jpeg" alt="Mithilesh Kumar designing agentic workflows on a glass whiteboard" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Architectural Components:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Query Router (Agentic Layer):&lt;/strong&gt; Dynamically analyzes incoming intent and decides whether to route the request to a vector store, a relational database, or a web search API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid Search Engine:&lt;/strong&gt; Combines &lt;strong&gt;BM25 (Sparse Keyword Search)&lt;/strong&gt; and &lt;strong&gt;Dense Vector Search (e.g., OpenAI / BGE Embeddings)&lt;/strong&gt; using Reciprocal Rank Fusion (RRF).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Encoder Re-Ranker:&lt;/strong&gt; A specialized model (like &lt;code&gt;bge-reranker-large&lt;/code&gt;) that evaluates the exact query-document pairs to assign a true relevance score before sending context to the LLM.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Implementation: Hybrid Search &amp;amp; Re-Ranking Code
&lt;/h2&gt;

&lt;p&gt;Here is a modular Python implementation demonstrating how to combine hybrid retrieval with a re-ranking step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sentence_transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CrossEncoder&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductionRAGPipeline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reranker_model_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;BAAI/bge-reranker-large&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Initialize Cross-Encoder for precision scoring
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reranker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CrossEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reranker_model_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reciprocal_rank_fusion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dense_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;sparse_results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Combines Dense and Sparse search results using Reciprocal Rank Fusion (RRF).&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;rrf_scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dense_results&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;doc_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;doc_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rrf_scores&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;rrf_scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;doc&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;rrf_scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sparse_results&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;doc_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;doc_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rrf_scores&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;rrf_scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;doc&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;rrf_scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;reranked_docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rrf_scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;doc&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;reranked_docs&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rerank_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retrieved_docs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;top_n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Applies Cross-Encoder re-ranking on fused retrieval results.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;retrieved_docs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="n"&gt;pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;retrieved_docs&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reranker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pairs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;retrieved_docs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rerank_score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;final_sorted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retrieved_docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rerank_score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;final_sorted&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;top_n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;









&lt;h2&gt;
  
  
  4. Benchmarks &amp;amp; Production Lessons Learned
&lt;/h2&gt;

&lt;p&gt;When deploying this agentic RAG system in production, several key trade-offs emerged:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Latency vs. Precision:&lt;/strong&gt; Cross-encoders add approximately 50-150ms of latency per request. Mitigate this by passing only the top 15-20 RRF-fused documents to the re-ranker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Compression:&lt;/strong&gt; Stripping out useless metadata before feeding documents into the final prompt reduced token costs by nearly &lt;strong&gt;38%&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent Loops:&lt;/strong&gt; Always enforce a hard ceiling (e.g., maximum 3 reflection iterations) on agent decision loops to prevent infinite fallback execution.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Transitioning from Naive RAG to an &lt;strong&gt;Agentic Hybrid Pipeline&lt;/strong&gt; is necessary for building reliable, production-ready AI applications. By combining sparse keyword matching, dense semantic search, cross-encoder re-ranking, and dynamic query routing, you create a system that is robust, accurate, and cost-effective.&lt;/p&gt;




&lt;h3&gt;
  
  
  About the Author
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Mithilesh Kumar&lt;/strong&gt; is an AI Engineer and Systems Architect specializing in Large Language Models (LLMs), Multi-Agent Workflows, and Production-Grade RAG Systems. He focuses on building deterministic, low-latency AI software and enterprise systems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio:&lt;/strong&gt; &lt;a href="https://mithilesh-kumar-ai-engineer.netlify.app" rel="noopener noreferrer"&gt;mithilesh-kumar-ai-engineer.netlify.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://linkedin.com/in/mithileshkumar001" rel="noopener noreferrer"&gt;linkedin.com/in/mithileshkumar001&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/mithxcode" rel="noopener noreferrer"&gt;github.com/mithxcode&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;X (Twitter):&lt;/strong&gt; &lt;a href="https://x.com/MITHILESH_7781" rel="noopener noreferrer"&gt;x.com/MITHILESH_7781&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>rag</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Why Basic RAG Fails in Production and How Adaptive Query Routing Fixes It</title>
      <dc:creator>Mithilesh Kumar</dc:creator>
      <pubDate>Sat, 08 Aug 2026 20:01:15 +0000</pubDate>
      <link>https://dev.to/mithxcode/why-basic-rag-fails-in-production-and-how-adaptive-query-routing-fixes-it-5c1n</link>
      <guid>https://dev.to/mithxcode/why-basic-rag-fails-in-production-and-how-adaptive-query-routing-fixes-it-5c1n</guid>
      <description>&lt;p&gt;Most developers build Retrieval-Augmented Generation (RAG) pipelines assuming every user query needs a vector search. In production, this naive approach fails in three distinct scenarios:&lt;/p&gt;

&lt;p&gt;Simple Queries: "Hi", "Who created this bot?", or general knowledge queries don't need expensive vector database lookups.&lt;/p&gt;

&lt;p&gt;Ambiguous Queries: Vague user questions lead to noisy retrieval, diluting the LLM's context window with irrelevant chunks.&lt;/p&gt;

&lt;p&gt;Out-of-Domain Queries: When the vector DB contains no relevant documents, naive RAG forces the LLM to hallucinate an answer based on poor context.&lt;/p&gt;

&lt;p&gt;In this guide, I’ll break down how to implement Adaptive RAG with Dynamic Query Routing using LangChain, Vector Stores (Pinecone/Chroma), and FastAPI.&lt;/p&gt;

&lt;p&gt;What is Adaptive RAG?&lt;br&gt;
Instead of routing every request directly to vector retrieval, Adaptive RAG acts as an intent-aware orchestrator:&lt;/p&gt;

&lt;p&gt;graph TD&lt;br&gt;
    A[User Query Received] --&amp;gt; B[Intent Classifier Node]&lt;br&gt;
    B --&amp;gt;|General Query| C[Direct LLM Response]&lt;br&gt;
    B --&amp;gt;|Internal Docs| D[Vector DB Retrieval]&lt;br&gt;
    B --&amp;gt;|External/News| E[Web Search Fallback]&lt;br&gt;
    D --&amp;gt; F[Hallucination Grader Node]&lt;/p&gt;

&lt;p&gt;Classify Intent: Determine whether the query needs internal vector docs, web search, or a direct response.&lt;/p&gt;

&lt;p&gt;Retrieve &amp;amp; Grade: Fetch documents, then evaluate their relevance score before generating the answer.&lt;/p&gt;

&lt;p&gt;Fallback Circuit: If document relevance is low, trigger fallback web search (e.g., Tavily API) or ask the user for clarification.&lt;/p&gt;

&lt;p&gt;Step 1: Building a Structured Router with Pydantic&lt;br&gt;
We enforce a strict JSON output schema using Pydantic to ensure our routing decision is 100% deterministic.&lt;/p&gt;

&lt;p&gt;from pydantic import BaseModel, Field&lt;br&gt;
from typing import Literal&lt;/p&gt;

&lt;p&gt;class RouteQuery(BaseModel):&lt;br&gt;
    """Route a user query to the most appropriate data source."""&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;datasource: Literal["vectorstore", "web_search", "direct_llm"] = Field(
    ...,
    description="Given a user question, choose whether to route it to vectorstore, web search, or direct LLM."
)
reasoning: str = Field(
    ..., description="Brief explanation for the routing decision."
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Step 2: Query Classification Node&lt;br&gt;
Using function calling / structured output capabilities of LLMs (like Google Gemini or OpenAI):&lt;/p&gt;

&lt;p&gt;from langchain_core.prompts import ChatPromptTemplate&lt;br&gt;
from langchain_google_genai import ChatGoogleGenerativeAI&lt;/p&gt;

&lt;p&gt;llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash", temperature=0)&lt;br&gt;
structured_router = llm.with_structured_output(RouteQuery)&lt;/p&gt;

&lt;p&gt;system_prompt = """You are an expert at routing user queries.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use 'vectorstore' for questions related to internal technical documents, architecture, or codebase.&lt;/li&gt;
&lt;li&gt;Use 'web_search' for recent events, live news, or external context.&lt;/li&gt;
&lt;li&gt;Use 'direct_llm' for greetings, general conversational queries, or basic coding syntax.
"""&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;route_prompt = ChatPromptTemplate.from_messages([&lt;br&gt;
    ("system", system_prompt),&lt;br&gt;
    ("human", "{question}")&lt;br&gt;
])&lt;/p&gt;

&lt;p&gt;question_router = route_prompt | structured_router&lt;/p&gt;

&lt;h1&gt;
  
  
  Test the router
&lt;/h1&gt;

&lt;p&gt;result = question_router.invoke({"question": "What is the API endpoint for CGC-NEXUS event registration?"})&lt;br&gt;
print(f"Destination: {result.datasource} | Reason: {result.reasoning}")&lt;/p&gt;

&lt;h1&gt;
  
  
  Output: Destination: vectorstore | Reason: Query asks about specific internal project endpoints.
&lt;/h1&gt;

&lt;p&gt;Step 3: Integrating into Async FastAPI Endpoint&lt;br&gt;
Here is how to expose the adaptive pipeline via a FastAPI service:&lt;/p&gt;

&lt;p&gt;from fastapi import FastAPI, HTTPException&lt;br&gt;
from pydantic import BaseModel&lt;/p&gt;

&lt;p&gt;app = FastAPI(title="Adaptive RAG Engine")&lt;/p&gt;

&lt;p&gt;class QueryRequest(BaseModel):&lt;br&gt;
    question: str&lt;/p&gt;

&lt;p&gt;@app.post("/api/v1/query")&lt;br&gt;
async def process_query(request: QueryRequest):&lt;br&gt;
    try:&lt;br&gt;
        # Step 1: Route Query&lt;br&gt;
        decision = await question_router.ainvoke({"question": request.question})&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # Step 2: Execute based on intent
    if decision.datasource == "direct_llm":
        response = await llm.ainvoke(request.question)
        return {"source": "direct_llm", "answer": response.content}

    elif decision.datasource == "vectorstore":
        # Perform vector store search &amp;amp; hallucination check
        return {"source": "vectorstore", "answer": "Retrieved from vector database."}

    else:
        # Fallback to Web Search
        return {"source": "web_search", "answer": "Retrieved from web search fallback."}

except Exception as e:
    raise HTTPException(status_code=500, detail=str(e))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Key Production Insights&lt;br&gt;
Cost Optimization: Filtering out trivial questions before vector search reduces API calls and vector database read costs by up to 40%.&lt;/p&gt;

&lt;p&gt;Zero Hallucination Loop: By running a fast grader node on retrieved chunks, you ensure irrelevant text never enters the final LLM prompt context.&lt;/p&gt;

&lt;p&gt;Latency Reduction: Direct LLM calls bypass embedding generation and vector lookup entirely, responding in under 300ms.&lt;/p&gt;

&lt;p&gt;Connect &amp;amp; Explore Code&lt;br&gt;
Live Portfolio: &lt;a href="https://mithilesh-kumar-ai-engineer.netlify.app/" rel="noopener noreferrer"&gt;https://mithilesh-kumar-ai-engineer.netlify.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub Repository: &lt;a href="https://github.com/mithxcode" rel="noopener noreferrer"&gt;https://github.com/mithxcode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/mithileshkumar001" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/mithileshkumar001&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;X (Twitter): &lt;a href="https://x.com/MITHILESH_7781" rel="noopener noreferrer"&gt;https://x.com/MITHILESH_7781&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How are you handling ambiguous queries in your RAG pipelines? Drop a comment below!&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>langchain</category>
      <category>fastapi</category>
    </item>
    <item>
      <title>Building Scalable Multi-Agent Workflows &amp; RAG Pipelines with LangGraph and FastAPI</title>
      <dc:creator>Mithilesh Kumar</dc:creator>
      <pubDate>Fri, 07 Aug 2026 05:14:38 +0000</pubDate>
      <link>https://dev.to/mithxcode/building-scalable-multi-agent-workflows-rag-pipelines-with-langgraph-and-fastapi-2lm0</link>
      <guid>https://dev.to/mithxcode/building-scalable-multi-agent-workflows-rag-pipelines-with-langgraph-and-fastapi-2lm0</guid>
      <description>&lt;p&gt;Building fully autonomous AI systems requires moving beyond simple linear prompts to robust, stateful agentic workflows. In this article, I share my core architecture for engineering Multi-Agent Systems and Retrieval-Augmented Generation (RAG) pipelines using &lt;strong&gt;LangGraph&lt;/strong&gt;, &lt;strong&gt;FastAPI&lt;/strong&gt;, and &lt;strong&gt;Python&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Agentic Workflows and LangGraph?
&lt;/h2&gt;

&lt;p&gt;Traditional LLM applications often struggle with complex, multi-step execution paths. By leveraging &lt;strong&gt;LangGraph&lt;/strong&gt;, we can model agent interactions as state machines (graphs), allowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cyclic execution loops&lt;/strong&gt; for iterative refinement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State management&lt;/strong&gt; across multiple tool calls and reasoning steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human-in-the-loop&lt;/strong&gt; integration for safety and oversight.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Core Architecture Stack
&lt;/h2&gt;

&lt;p&gt;A modern agentic AI pipeline relies on a clean, scalable setup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration Layer:&lt;/strong&gt; LangGraph / LangChain for handling agent routines and condition-based routing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend API Service:&lt;/strong&gt; FastAPI for ultra-fast async request handling and stream processing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieval Layer (RAG):&lt;/strong&gt; Vector databases paired with hybrid search algorithms for low-latency context retrieval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Foundation Models:&lt;/strong&gt; OpenAI &amp;amp; Google Gemini APIs.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Key Takeaways for AI Engineers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic Routing:&lt;/strong&gt; Always keep edge transitions explicit to prevent agent loops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured Outputs:&lt;/strong&gt; Enforce Pydantic schemas on LLM outputs for reliable API responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability:&lt;/strong&gt; Track token usage and execution steps using tools like LangSmith.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  About the Author
&lt;/h3&gt;

&lt;p&gt;Hi! I am &lt;strong&gt;Mithilesh Kumar&lt;/strong&gt;, an AI Engineer specializing in Multi-Agent Systems, Agentic Workflows, and Modern Web Technologies. &lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Explore my portfolio and live projects:&lt;/strong&gt; &lt;a href="https://mithilesh-kumar-ai-engineer.netlify.app/" rel="noopener noreferrer"&gt;https://mithilesh-kumar-ai-engineer.netlify.app/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>python</category>
      <category>langchain</category>
    </item>
  </channel>
</rss>
