<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Experiments with AI]]></title><description><![CDATA[Curious learner about this ever changing space, I like to document and publish my learnings.]]></description><link>https://utkarshumang.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!XwxE!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18591df1-c1b9-4d7a-8bd5-d22215b9e062_780x780.png</url><title>Experiments with AI</title><link>https://utkarshumang.substack.com</link></image><generator>Substack</generator><lastBuildDate>Sun, 09 Aug 2026 22:06:55 GMT</lastBuildDate><atom:link href="https://utkarshumang.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Utkarsh Umang]]></copyright><language><![CDATA[en-gb]]></language><webMaster><![CDATA[utkarshumang@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[utkarshumang@substack.com]]></itunes:email><itunes:name><![CDATA[Utkarsh Umang]]></itunes:name></itunes:owner><itunes:author><![CDATA[Utkarsh Umang]]></itunes:author><googleplay:owner><![CDATA[utkarshumang@substack.com]]></googleplay:owner><googleplay:email><![CDATA[utkarshumang@substack.com]]></googleplay:email><googleplay:author><![CDATA[Utkarsh Umang]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Your Dictionary to Everything AI Agents]]></title><description><![CDATA[For anyone who&#8217;s used ChatGPT or Claude casually and wants to understand how production AI systems are actually built.]]></description><link>https://utkarshumang.substack.com/p/your-dictionary-to-everything-ai</link><guid isPermaLink="false">https://utkarshumang.substack.com/p/your-dictionary-to-everything-ai</guid><dc:creator><![CDATA[Utkarsh Umang]]></dc:creator><pubDate>Sat, 06 Jun 2026 06:14:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!AgA1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You don&#8217;t need a technical background to read this. Every section is self-contained, so skim freely and go deep only where it interests you. A new AI tool or framework launches every other day, but most of the fundamentals boil down to the concepts covered here. This is the reference I wish existed when I started building agentic systems.</p><h3>1. Prompting: The Foundation</h3><p>Every production AI system starts with one thing: a well-written prompt. If you&#8217;ve used ChatGPT or Claude, you already know what a prompt is. You type something, the model responds. Simple enough.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://utkarshumang.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en-gb&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Experiments with AI! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>But there&#8217;s a massive gap between &#8220;hey, summarise this for me&#8221; and a prompt that works reliably thousands of times without a human babysitting it. Production prompts are engineered, not typed.</p><h4>The Prompt Structure Framework</h4><p>A well-structured prompt has five components, and the more precisely you define each one, the more predictable your output becomes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AgA1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AgA1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png 424w, https://substackcdn.com/image/fetch/$s_!AgA1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png 848w, https://substackcdn.com/image/fetch/$s_!AgA1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png 1272w, https://substackcdn.com/image/fetch/$s_!AgA1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AgA1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png" width="604" height="386" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:386,&quot;width&quot;:604,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AgA1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png 424w, https://substackcdn.com/image/fetch/$s_!AgA1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png 848w, https://substackcdn.com/image/fetch/$s_!AgA1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png 1272w, https://substackcdn.com/image/fetch/$s_!AgA1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3044b447-781d-4f22-b0a9-18cb4adb56a7_604x386.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Types of Prompting</h4><p>Now, even with a perfectly structured prompt, <em>how</em> you use it matters. There are three main prompting strategies, and each trades off between simplicity and accuracy.</p><p><strong>Zero-shot</strong> is the simplest. You give the AI a task with no examples and expect it to figure it out. &#8220;Translate this sentence to French: The meeting is at 3pm.&#8221; Works well when the task is well-defined and the model already knows the pattern.</p><p><strong>Few-shot</strong> is the next step up. You provide a few examples of input-output pairs so the model understands the exact pattern or format you want. Instead of describing your requirements in words, you show it: &#8220;Here are three examples of how I want emails summarised. Now summarise this one.&#8221; This is surprisingly effective for getting consistent formatting and tone.</p><p><strong>Chain-of-thought</strong> is the heavy hitter. Instead of asking for a direct answer, you ask the AI to reason through the problem step by step before concluding. This is what powers &#8220;reasoning models&#8221; like OpenAI&#8217;s o1 or Claude&#8217;s extended thinking mode. It trades speed for accuracy, and it&#8217;s the go-to for complex analytical tasks where a snap answer would miss nuance.</p><div><hr></div><h3>2. From Casual Use to Production Systems</h3><p>If you&#8217;ve spent any time with ChatGPT or Claude, you&#8217;ve probably developed a rhythm: send a message, get an answer you don&#8217;t love, tweak your ask, try again, repeat three or four times until the output clicks. That works when you&#8217;re the human in the loop, manually steering the conversation.</p><p>But in a production system, software needs to do this reliably, automatically, thousands of times a day. There&#8217;s no human sitting there hitting &#8220;regenerate&#8221; or &#8220;sending new instructions in a new message&#8221;. You can&#8217;t afford retries.</p><p>The solution is deceptively simple: stop asking one model to do everything in one shot. Instead, figure out the manual workflow first , what steps would a human take to solve this task? Then break those steps into smaller, discrete pieces, and assign each piece to a focused AI agent.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7u4Z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fa52c-4984-42a5-bea3-1f9022143bb0_714x372.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7u4Z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fa52c-4984-42a5-bea3-1f9022143bb0_714x372.png 424w, https://substackcdn.com/image/fetch/$s_!7u4Z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fa52c-4984-42a5-bea3-1f9022143bb0_714x372.png 848w, https://substackcdn.com/image/fetch/$s_!7u4Z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fa52c-4984-42a5-bea3-1f9022143bb0_714x372.png 1272w, https://substackcdn.com/image/fetch/$s_!7u4Z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fa52c-4984-42a5-bea3-1f9022143bb0_714x372.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7u4Z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fa52c-4984-42a5-bea3-1f9022143bb0_714x372.png" width="714" height="372" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/306fa52c-4984-42a5-bea3-1f9022143bb0_714x372.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:372,&quot;width&quot;:714,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7u4Z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fa52c-4984-42a5-bea3-1f9022143bb0_714x372.png 424w, https://substackcdn.com/image/fetch/$s_!7u4Z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fa52c-4984-42a5-bea3-1f9022143bb0_714x372.png 848w, https://substackcdn.com/image/fetch/$s_!7u4Z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fa52c-4984-42a5-bea3-1f9022143bb0_714x372.png 1272w, https://substackcdn.com/image/fetch/$s_!7u4Z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306fa52c-4984-42a5-bea3-1f9022143bb0_714x372.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This is the core idea behind agentic AI systems. Instead of one model doing everything and hoping for the best, you decompose the problem into focused steps, each handled by a smaller, cheaper, more reliable agent. The compound effect is a system that&#8217;s faster, more predictable, and significantly easier to debug when something goes wrong.</p><div><hr></div><h3><strong>3. Sub-Agents and Model Parameters</strong></h3><p>Now that you know the &#8220;why&#8221; behind breaking things down, let&#8217;s look at the building blocks.</p><p>A sub-agent is an AI model assigned to one specific, narrow task within a larger workflow. One agent extracts data from a PDF invoice. Another validates that data against a database. A third formats and sends a confirmation email. Because each sub-agent does a focused job, you can use smaller, faster, and cheaper models instead of one heavy model doing everything.</p><p>But assigning the right model isn&#8217;t enough. You also need to tune <em>how</em> the model behaves. The most important dial here is <strong>temperature</strong>.</p><p>Temperature controls how &#8220;creative&#8221; or &#8220;random&#8221; a model&#8217;s output is. Think of it as a spectrum. At the low end (close to 0), the model plays it safe, it picks the most predictable response every time. Ask the same question twice and you get the same answer. This is what you want for deterministic tasks like extracting data from a document or classifying a support ticket.</p><p>At the high end (close to 1), the model takes more risks and explores a wider range of possibilities. The output will vary each time you run it. This is useful for creative tasks like brainstorming, writing, or generating ideas.</p><p><strong>The rule of thumb is simple</strong>: if the task needs consistency, go low. If the task needs creativity, go higher.</p><div><hr></div><h3>4. Agentic Workflow Paradigms</h3><p>You have sub-agents. Now you need a way to connect them. There are two main paradigms, and understanding the difference between them is one of the most important architectural decisions you&#8217;ll make.</p><p>The first is <strong>chain-based workflows</strong>. This is the simplest pattern: the output of Agent 1 feeds into Agent 2, which feeds into Agent 3, and so on. Linear, predictable, easy to debug. <strong>LangChain</strong> is the most popular framework for building these. Its key benefit is abstraction &#8594; it doesn&#8217;t care whether you&#8217;re using Claude, GPT-4, or any other model under the hood. Switching providers requires minimal code changes. It also ships with ready-made components for common tasks like connecting to databases, handling memory, and formatting outputs, so you write far less boilerplate.</p><p>The second is <strong>orchestration-based workflows</strong>. This is where things get powerful. Instead of a fixed linear chain, a single Orchestrator Agent sits at the top of the system. You tell it what sub-agents are available and what each one does. When a task comes in, the orchestrator reads it, figures out a plan, and decides which sub-agents to call, in what order, and what to do with their outputs.</p><p>The critical difference: orchestration can be <strong>cyclic</strong>. The orchestrator can call Agent A, send its output to Agent B, get a result back, decide it needs to call Agent A again with new information, and loop until a condition is met. <strong>LangGraph</strong> is the framework for this. It extends LangChain, and the distinction is exactly this: LangChain is for linear chains, LangGraph is for graph-based workflows that can branch, loop, and route dynamically.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dthQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd927f641-d4ed-4609-9306-b7c471c61eb0_709x428.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dthQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd927f641-d4ed-4609-9306-b7c471c61eb0_709x428.png 424w, https://substackcdn.com/image/fetch/$s_!dthQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd927f641-d4ed-4609-9306-b7c471c61eb0_709x428.png 848w, https://substackcdn.com/image/fetch/$s_!dthQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd927f641-d4ed-4609-9306-b7c471c61eb0_709x428.png 1272w, https://substackcdn.com/image/fetch/$s_!dthQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd927f641-d4ed-4609-9306-b7c471c61eb0_709x428.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dthQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd927f641-d4ed-4609-9306-b7c471c61eb0_709x428.png" width="709" height="428" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d927f641-d4ed-4609-9306-b7c471c61eb0_709x428.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:428,&quot;width&quot;:709,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dthQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd927f641-d4ed-4609-9306-b7c471c61eb0_709x428.png 424w, https://substackcdn.com/image/fetch/$s_!dthQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd927f641-d4ed-4609-9306-b7c471c61eb0_709x428.png 848w, https://substackcdn.com/image/fetch/$s_!dthQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd927f641-d4ed-4609-9306-b7c471c61eb0_709x428.png 1272w, https://substackcdn.com/image/fetch/$s_!dthQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd927f641-d4ed-4609-9306-b7c471c61eb0_709x428.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The way to think about it: if your task is &#8220;do A, then B, then C, done&#8221; &#8594; use a chain. If your task is &#8220;figure out what needs to happen and adapt as you go&#8221; &#8594; use an orchestrator.</figcaption></figure></div><div><hr></div><h3>5. Agentic Patterns</h3><p>Beyond how agents are wired together, there are established patterns for how an individual agent <em>reasons and acts</em> when given a task. Two of the most important ones are ReAct and Plan and Execute.</p><p><strong>ReAct (Reasoning and Acting)</strong> is a loop. When given a task, the agent doesn&#8217;t immediately produce an answer. Instead, it cycles through three steps: Reason (what do I know, what do I still need?), Act (call a tool, fetch data), and Observe (is this enough to answer?). If the answer is no, it loops back to Reason and tries again.</p><p>This pattern is powerful because the agent is adaptive. It doesn&#8217;t commit to a fixed plan upfront. It responds to what it actually finds at each step, which makes it well suited for tasks where the path to the answer isn&#8217;t known in advance.</p><p><strong>Plan and Execute</strong> takes the opposite approach. Instead of reasoning one step at a time, the agent first builds a complete plan before doing anything. A Planner Agent generates the full step-by-step breakdown, and then an Executor works through that plan sequentially. The advantage is predictability and efficiency, you know the full plan upfront, which makes it easier to parallelise steps, estimate cost, and debug failures. The trade-off is rigidity: if something unexpected comes up mid-execution, the plan may need to be revised.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RT5g!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f98e270-db39-48be-9152-1bb3de27a7cf_700x461.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RT5g!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f98e270-db39-48be-9152-1bb3de27a7cf_700x461.png 424w, https://substackcdn.com/image/fetch/$s_!RT5g!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f98e270-db39-48be-9152-1bb3de27a7cf_700x461.png 848w, https://substackcdn.com/image/fetch/$s_!RT5g!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f98e270-db39-48be-9152-1bb3de27a7cf_700x461.png 1272w, https://substackcdn.com/image/fetch/$s_!RT5g!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f98e270-db39-48be-9152-1bb3de27a7cf_700x461.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RT5g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f98e270-db39-48be-9152-1bb3de27a7cf_700x461.png" width="700" height="461" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3f98e270-db39-48be-9152-1bb3de27a7cf_700x461.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:461,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RT5g!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f98e270-db39-48be-9152-1bb3de27a7cf_700x461.png 424w, https://substackcdn.com/image/fetch/$s_!RT5g!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f98e270-db39-48be-9152-1bb3de27a7cf_700x461.png 848w, https://substackcdn.com/image/fetch/$s_!RT5g!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f98e270-db39-48be-9152-1bb3de27a7cf_700x461.png 1272w, https://substackcdn.com/image/fetch/$s_!RT5g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3f98e270-db39-48be-9152-1bb3de27a7cf_700x461.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The decision between the two comes down to the nature of the task. Use ReAct when the task is exploratory or unpredictable and the agent needs to adapt based on what it finds. Use Plan and Execute when the task is well-defined and you want efficiency, parallelism, and a clear audit trail of what was supposed to happen.</p><div><hr></div><h3>6. Context Engineering</h3><p>Your AI agent can only make good decisions if it has the right information. Context engineering is the discipline of figuring out what information to inject into each prompt, and doing it efficiently.</p><p>The naive approach is to dump all user data into every prompt. The problem: prompts get huge, slow, and expensive. AI models charge by the token (roughly by word count), so sending a 50-page document when you only need two paragraphs from it is burning money for no reason.</p><p>The smart approach is to dynamically fetch only what&#8217;s relevant, right before sending the prompt. There are two main techniques depending on where your data lives.</p><p>If the relevant data lives in a <strong>structured database</strong> (rows and columns), you use tool calling to run a SQL query and pull only the relevant rows. A user asks &#8220;what&#8217;s my order status?&#8221; &#8594; the system queries the orders database for that specific user&#8217;s recent orders, injects just those rows into the prompt, and the agent answers accurately.</p><p>If the relevant data lives in <strong>unstructured form</strong> (documents, PDFs, notes, emails), you can&#8217;t just run a SQL query. This is where <strong>RAG</strong> (Retrieval-Augmented Generation) comes in. You build a pipeline that breaks all your documents into small chunks, converts those chunks into numerical vectors (a way of representing meaning mathematically), and when a query comes in, finds the chunks that are closest in meaning to the query. The AI sees only the most relevant pieces of your knowledge base, not everything. Check my others <a href="https://medium.com/towards-artificial-intelligence/building-rag-systems-a-complete-guide-a1b94c997000">post</a> for a detailed guide into RAG.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sh5Z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67bce5c2-5bc6-4b5d-bd02-414b1cb02eb6_724x392.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sh5Z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67bce5c2-5bc6-4b5d-bd02-414b1cb02eb6_724x392.png 424w, https://substackcdn.com/image/fetch/$s_!sh5Z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67bce5c2-5bc6-4b5d-bd02-414b1cb02eb6_724x392.png 848w, https://substackcdn.com/image/fetch/$s_!sh5Z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67bce5c2-5bc6-4b5d-bd02-414b1cb02eb6_724x392.png 1272w, https://substackcdn.com/image/fetch/$s_!sh5Z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67bce5c2-5bc6-4b5d-bd02-414b1cb02eb6_724x392.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sh5Z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67bce5c2-5bc6-4b5d-bd02-414b1cb02eb6_724x392.png" width="724" height="392" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67bce5c2-5bc6-4b5d-bd02-414b1cb02eb6_724x392.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:392,&quot;width&quot;:724,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sh5Z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67bce5c2-5bc6-4b5d-bd02-414b1cb02eb6_724x392.png 424w, https://substackcdn.com/image/fetch/$s_!sh5Z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67bce5c2-5bc6-4b5d-bd02-414b1cb02eb6_724x392.png 848w, https://substackcdn.com/image/fetch/$s_!sh5Z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67bce5c2-5bc6-4b5d-bd02-414b1cb02eb6_724x392.png 1272w, https://substackcdn.com/image/fetch/$s_!sh5Z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67bce5c2-5bc6-4b5d-bd02-414b1cb02eb6_724x392.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The key insight here is that context engineering is about precision, not volume. The less irrelevant noise you put in the prompt, the better the agent performs.</p><div><hr></div><h3>7. Harness Engineering</h3><p>If context engineering is about <em>what information</em> the agent receives, harness engineering is about <em>what capabilities and behaviours</em> the agent is equipped with. Think of it like fishing, the right bait gets you the right output.</p><p>The most common tool in harness engineering is <strong>Skills</strong>. A skill is a markdown file (a simple text file) that describes how the agent should behave in a specific situation. It&#8217;s not a prompt for a user task, it&#8217;s a behaviour guide embedded in the agent&#8217;s system.</p><p>For example, an email reply agent might have a file called <code>email-reply-skill.md</code> that specifies: always start with the customer&#8217;s name, never promise refunds without checking the policy tool, keep replies under 150 words, and match the tone of the incoming email.</p><p>The agent reads this skill file as part of its setup and follows these rules every time it writes an email. Skills make agents more predictable and significantly easier to update &#8594; you change a behavior by editing a markdown file, not by rewriting the entire prompt.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F7lz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26fd3561-ad1f-4d7b-ab99-bdebd41ad3c0_714x291.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F7lz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26fd3561-ad1f-4d7b-ab99-bdebd41ad3c0_714x291.png 424w, https://substackcdn.com/image/fetch/$s_!F7lz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26fd3561-ad1f-4d7b-ab99-bdebd41ad3c0_714x291.png 848w, https://substackcdn.com/image/fetch/$s_!F7lz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26fd3561-ad1f-4d7b-ab99-bdebd41ad3c0_714x291.png 1272w, https://substackcdn.com/image/fetch/$s_!F7lz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26fd3561-ad1f-4d7b-ab99-bdebd41ad3c0_714x291.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F7lz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26fd3561-ad1f-4d7b-ab99-bdebd41ad3c0_714x291.png" width="714" height="291" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/26fd3561-ad1f-4d7b-ab99-bdebd41ad3c0_714x291.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:291,&quot;width&quot;:714,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!F7lz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26fd3561-ad1f-4d7b-ab99-bdebd41ad3c0_714x291.png 424w, https://substackcdn.com/image/fetch/$s_!F7lz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26fd3561-ad1f-4d7b-ab99-bdebd41ad3c0_714x291.png 848w, https://substackcdn.com/image/fetch/$s_!F7lz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26fd3561-ad1f-4d7b-ab99-bdebd41ad3c0_714x291.png 1272w, https://substackcdn.com/image/fetch/$s_!F7lz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26fd3561-ad1f-4d7b-ab99-bdebd41ad3c0_714x291.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Together, these two layers cover the full picture. Context engineering ensures your agent has the right information. Harness engineering ensures it does the right thing with that information.</p><div><hr></div><h3>8. RAG vs Fine-Tuning</h3><p>These two come up in almost every conversation about making an AI model better at a specific use case, and they&#8217;re often confused. They solve fundamentally different problems.</p><p><strong>RAG</strong> changes the information the model sees. You&#8217;re giving a smart person the right reference book before an exam. The model itself doesn&#8217;t change, you&#8217;re just making sure it has access to the right data at the right time. It&#8217;s relatively cheap, you can update the data anytime, and it&#8217;s the first thing you should try.</p><p><strong>Fine-tuning</strong> changes the model&#8217;s internal weights, how it <em>thinks</em>. You&#8217;re sending that person to school for a year. The model learns to behave differently: a specific tone, a specific format, a specific reasoning style. It&#8217;s expensive, requires training compute and labeled data, and the changes are baked into the model.</p><p>The rule of thumb: try RAG first. It&#8217;s faster, cheaper, and easier to update. Only fine-tune when you&#8217;ve confirmed that the model&#8217;s behavior or thinking pattern is the bottleneck, not the information it has. If your agent keeps getting the facts wrong, that&#8217;s a context problem &#8594; use RAG. If your agent gets the facts right but writes in the wrong tone or follows the wrong reasoning pattern, that&#8217;s a behavior problem &#8594; consider fine-tuning.</p><div><hr></div><h3>9. Tool Calling and MCP</h3><p>Your AI agent knows a lot from its training data, and you can give it relevant context via the techniques we just covered. But sometimes it needs real-time, external data that neither its training nor your database has.</p><p>Say you want an agent to check a creator&#8217;s Instagram follower count before making a recommendation. That number changes daily and lives outside your system. This is where tools come in.</p><p>You define a tool by giving the agent a simple spec: a name, a description of what it does, what inputs it expects, and what it returns. The agent doesn&#8217;t need to know the implementation details, it just needs to know the tool exists and what it&#8217;s for. When the agent decides it needs follower data mid-task, it generates the right API call, gets the data back, and uses it in its reasoning.</p><p>Tools are essentially a catalog of external capabilities you hand to the agent. The agent decides when and which ones to use.</p><p>Now, defining tools manually for every external service gets tedious fast. MCP (Model Context Protocol) is the solution. MCP is an open standard that lets external services publish their tools in a standardised format. Instead of you writing every tool definition, the service hosts an MCP server that your agent connects to. Once connected, the agent automatically discovers all available tools from that server and knows how to use them.</p><p>Think of it as a plugin store for AI agents. Companies like Apify, Slack, and Google have published MCP servers. Your agent connects to one endpoint and instantly gains access to dozens of tools without manual integration work.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hk4I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8b930d-7928-4df6-a515-8afd0eb0501f_715x402.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hk4I!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8b930d-7928-4df6-a515-8afd0eb0501f_715x402.png 424w, https://substackcdn.com/image/fetch/$s_!hk4I!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8b930d-7928-4df6-a515-8afd0eb0501f_715x402.png 848w, https://substackcdn.com/image/fetch/$s_!hk4I!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8b930d-7928-4df6-a515-8afd0eb0501f_715x402.png 1272w, https://substackcdn.com/image/fetch/$s_!hk4I!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8b930d-7928-4df6-a515-8afd0eb0501f_715x402.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hk4I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8b930d-7928-4df6-a515-8afd0eb0501f_715x402.png" width="715" height="402" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d8b930d-7928-4df6-a515-8afd0eb0501f_715x402.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:402,&quot;width&quot;:715,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hk4I!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8b930d-7928-4df6-a515-8afd0eb0501f_715x402.png 424w, https://substackcdn.com/image/fetch/$s_!hk4I!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8b930d-7928-4df6-a515-8afd0eb0501f_715x402.png 848w, https://substackcdn.com/image/fetch/$s_!hk4I!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8b930d-7928-4df6-a515-8afd0eb0501f_715x402.png 1272w, https://substackcdn.com/image/fetch/$s_!hk4I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d8b930d-7928-4df6-a515-8afd0eb0501f_715x402.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3>10. Reliability in Production: The Judge Agent</h3><p>Getting an agentic system to work once in a demo is easy. Getting it to work correctly thousands of times in production is the hard part. There are two sides to reliability: making sure the output is good, and making sure the system stays up.</p><p><strong>The Judge Agent</strong></p><p>A judge agent is a separate AI model whose only job is to review the output of your system and decide: does this actually answer the user&#8217;s question correctly? It reads both the original input and the final output, then produces a verdict.</p><p>There are two ways to deploy a judge. In a <strong>sequential</strong> setup, every output goes through the judge before reaching the user. If the judge rejects it, a Refiner Agent tries to correct the output, and the loop repeats until it passes. This adds latency but guarantees quality, use it when accuracy is critical.</p><p>In a <strong>parallel</strong> setup, the user gets their answer immediately. The judge reviews it in the background, and if something looks wrong, it fires an alert (typically a Slack message or a review queue entry). Zero added latency for users, while still catching errors for the team. This is the more common production pattern.</p><p>Two critical details: first, use a different model for your judge than the one powering your system. A model tends to rate its own outputs favourably. If your system runs on GPT-4, use Claude as the judge, and vice versa. Second, enable extended thinking mode on your judge, instead of a simple pass/fail, the judge reasons through <em>why</em> the output is good or bad, which makes verdicts more accurate and gives your team much more useful debugging information.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AzS-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa340680d-2860-4399-adea-a882d440990e_716x554.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AzS-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa340680d-2860-4399-adea-a882d440990e_716x554.png 424w, https://substackcdn.com/image/fetch/$s_!AzS-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa340680d-2860-4399-adea-a882d440990e_716x554.png 848w, https://substackcdn.com/image/fetch/$s_!AzS-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa340680d-2860-4399-adea-a882d440990e_716x554.png 1272w, https://substackcdn.com/image/fetch/$s_!AzS-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa340680d-2860-4399-adea-a882d440990e_716x554.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AzS-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa340680d-2860-4399-adea-a882d440990e_716x554.png" width="716" height="554" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a340680d-2860-4399-adea-a882d440990e_716x554.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:554,&quot;width&quot;:716,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AzS-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa340680d-2860-4399-adea-a882d440990e_716x554.png 424w, https://substackcdn.com/image/fetch/$s_!AzS-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa340680d-2860-4399-adea-a882d440990e_716x554.png 848w, https://substackcdn.com/image/fetch/$s_!AzS-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa340680d-2860-4399-adea-a882d440990e_716x554.png 1272w, https://substackcdn.com/image/fetch/$s_!AzS-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa340680d-2860-4399-adea-a882d440990e_716x554.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong>The LLM Gateway</strong></p><p>Evaluating output quality is one side of reliability. The other side is simpler: is the system even running?</p><p>Every AI provider has rate limits. Hit the ceiling and your requests start failing. Providers also go down sometimes. If your entire system is hardwired to one model from one provider, their bad day becomes your bad day.</p><p>An LLM Gateway sits in front of all your model calls and acts as a traffic controller. It handles two things: rate limit management (if you&#8217;re hitting OpenAI&#8217;s limit, it routes overflow to a second API key or a different provider entirely) and failover (if one provider starts failing consistently, it reroutes to another). Your system keeps running. Your users see nothing.</p><p>Think of it as a load balancer, but specifically for AI model APIs. Popular open-source options like <strong>LiteLLM</strong> also give you a unified API, so your code doesn&#8217;t need to know which model it&#8217;s talking to at any given moment.</p><div><hr></div><h3>11. Memory in Agentic Systems</h3><p>When a conversation is short and simple, memory isn&#8217;t a problem. But what happens when a conversation runs fifty messages deep? Or when an agentic workflow crashes halfway through and needs to resume? Memory management becomes a critical layer in production systems.</p><p>The brute force approach is what you&#8217;ve already seen in ChatGPT. Every time you send message five, the system quietly packages up your previous four messages and four AI responses and sends all of it to the model again. That&#8217;s how the AI &#8220;remembers&#8221; what was said earlier. It works, but it doesn&#8217;t scale. As conversations get longer, you&#8217;re sending more tokens on every request. Costs go up, speed goes down, and eventually you hit the model&#8217;s context limit.</p><p>The smarter approach is to add a <strong>Summariser Agent</strong> to the system. After every batch of messages (say every ten), the summariser reads the conversation so far and produces a compact memory object: the key facts, decisions, and context, stored as a structured summary. Going forward, instead of sending all fifty past messages, you send the compact summary plus the last few messages in full. The prompt stays lean while preserving the important context.</p><p>But memory isn&#8217;t just for conversations. In a multi-step agentic workflow, if your system has five sub-agents and crashes at step three, you don&#8217;t want to start over from step one. <strong>Checkpointing</strong> solves this. After each sub-agent completes its task, its output is saved to a persistent store. If the workflow fails mid-run, the retry picks up from the last successful checkpoint. This is both a reliability pattern and a cost-saving one, you don&#8217;t waste compute redoing work that already succeeded.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p60e!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bab63e3-6777-4d51-a494-55274b0b3628_719x482.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p60e!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bab63e3-6777-4d51-a494-55274b0b3628_719x482.png 424w, https://substackcdn.com/image/fetch/$s_!p60e!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bab63e3-6777-4d51-a494-55274b0b3628_719x482.png 848w, https://substackcdn.com/image/fetch/$s_!p60e!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bab63e3-6777-4d51-a494-55274b0b3628_719x482.png 1272w, https://substackcdn.com/image/fetch/$s_!p60e!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bab63e3-6777-4d51-a494-55274b0b3628_719x482.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p60e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bab63e3-6777-4d51-a494-55274b0b3628_719x482.png" width="719" height="482" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9bab63e3-6777-4d51-a494-55274b0b3628_719x482.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:482,&quot;width&quot;:719,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!p60e!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bab63e3-6777-4d51-a494-55274b0b3628_719x482.png 424w, https://substackcdn.com/image/fetch/$s_!p60e!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bab63e3-6777-4d51-a494-55274b0b3628_719x482.png 848w, https://substackcdn.com/image/fetch/$s_!p60e!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bab63e3-6777-4d51-a494-55274b0b3628_719x482.png 1272w, https://substackcdn.com/image/fetch/$s_!p60e!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9bab63e3-6777-4d51-a494-55274b0b3628_719x482.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3>12. Observability: Knowing What Actually Happened</h3><p>Building an agentic system is one thing. Understanding what it did on any given run is another. Observability is the practice of logging and inspecting every step of an agentic execution, and it&#8217;s the difference between &#8220;something went wrong&#8221; and &#8220;I know exactly what went wrong and why.&#8221;</p><p>The tool most commonly used for this is <strong>Langfuse</strong>. Every time your agentic system runs, Langfuse records a <strong>trace</strong>: a detailed log of every step, showing which agent was called, what prompt it received, what the model returned, how long each step took, and how many tokens were used.</p><p>This matters for two reasons. First, <strong>debugging</strong>. When your system produces a wrong output, you don&#8217;t have to guess. You open the trace for that run and walk through it step by step. Was the wrong context injected? Did a sub-agent get malformed input? Did the judge agent fire correctly? The trace tells you.</p><p>Second, <strong>evaluation</strong>. When you&#8217;re trying to understand whether your system is improving or regressing over time, traces give you the raw evidence. You can compare runs, measure latency across sub-agents, and identify which step is the bottleneck.</p><p>Think of observability as your system&#8217;s black box recorder. You hope you don&#8217;t need it, but when something goes wrong, it&#8217;s the first place you look.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!d6jr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffddcaf1c-9dfa-4987-9f43-e0bb7f5d8c8b_709x308.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!d6jr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffddcaf1c-9dfa-4987-9f43-e0bb7f5d8c8b_709x308.png 424w, https://substackcdn.com/image/fetch/$s_!d6jr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffddcaf1c-9dfa-4987-9f43-e0bb7f5d8c8b_709x308.png 848w, https://substackcdn.com/image/fetch/$s_!d6jr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffddcaf1c-9dfa-4987-9f43-e0bb7f5d8c8b_709x308.png 1272w, https://substackcdn.com/image/fetch/$s_!d6jr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffddcaf1c-9dfa-4987-9f43-e0bb7f5d8c8b_709x308.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!d6jr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffddcaf1c-9dfa-4987-9f43-e0bb7f5d8c8b_709x308.png" width="709" height="308" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fddcaf1c-9dfa-4987-9f43-e0bb7f5d8c8b_709x308.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:308,&quot;width&quot;:709,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!d6jr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffddcaf1c-9dfa-4987-9f43-e0bb7f5d8c8b_709x308.png 424w, https://substackcdn.com/image/fetch/$s_!d6jr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffddcaf1c-9dfa-4987-9f43-e0bb7f5d8c8b_709x308.png 848w, https://substackcdn.com/image/fetch/$s_!d6jr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffddcaf1c-9dfa-4987-9f43-e0bb7f5d8c8b_709x308.png 1272w, https://substackcdn.com/image/fetch/$s_!d6jr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffddcaf1c-9dfa-4987-9f43-e0bb7f5d8c8b_709x308.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3>13. Human in the Loop (HITL)</h3><p>Not every decision should be made entirely by an AI agent. HITL is the design pattern of intentionally building moments into your workflow where a human reviews, approves, or redirects before the system proceeds.</p><p>The simplest form is a chat interface. After every AI response, the human can react: ask for a revision, correct something, or confirm before the next step begins. Simple, effective, but not always the best UX.</p><p>The smarter approach is <strong>purpose-built interfaces</strong>. Consider an AI system that generates a webpage. A naive HITL design would be: show the page, let the user describe what they don&#8217;t like in a chat box, regenerate the whole thing. That&#8217;s slow and frustrating. A better approach is a direct editing interface where the user can click on any element, change an image, tweak the copy, adjust the layout &#8594; without going back to the AI for minor fixes. The AI handles the heavy lifting, the human handles the fine-tuning through purpose-built controls.</p><p>HITL also serves as a safety valve. Remember the judge agent from earlier? If the judge is uncertain about an output, rather than sending it to the user or retrying automatically, it can route the output to a human reviewer with a note: &#8220;I&#8217;m not confident this email should be sent. Can you review before it goes out?&#8221; This is especially important for irreversible actions, sending emails, making payments, deleting records, posting publicly. Any action you can&#8217;t undo is a good candidate for a human checkpoint.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G8OO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a543d0-6c86-47e7-8ddb-d1af994f25d5_700x297.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G8OO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a543d0-6c86-47e7-8ddb-d1af994f25d5_700x297.png 424w, https://substackcdn.com/image/fetch/$s_!G8OO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a543d0-6c86-47e7-8ddb-d1af994f25d5_700x297.png 848w, https://substackcdn.com/image/fetch/$s_!G8OO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a543d0-6c86-47e7-8ddb-d1af994f25d5_700x297.png 1272w, https://substackcdn.com/image/fetch/$s_!G8OO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a543d0-6c86-47e7-8ddb-d1af994f25d5_700x297.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G8OO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a543d0-6c86-47e7-8ddb-d1af994f25d5_700x297.png" width="700" height="297" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/09a543d0-6c86-47e7-8ddb-d1af994f25d5_700x297.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:297,&quot;width&quot;:700,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!G8OO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a543d0-6c86-47e7-8ddb-d1af994f25d5_700x297.png 424w, https://substackcdn.com/image/fetch/$s_!G8OO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a543d0-6c86-47e7-8ddb-d1af994f25d5_700x297.png 848w, https://substackcdn.com/image/fetch/$s_!G8OO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a543d0-6c86-47e7-8ddb-d1af994f25d5_700x297.png 1272w, https://substackcdn.com/image/fetch/$s_!G8OO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a543d0-6c86-47e7-8ddb-d1af994f25d5_700x297.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Good HITL design is really a UX problem: what&#8217;s the minimum friction way to let a human correct or guide the system at the right moments?</p><div><hr></div><h3><strong>14. Structured Outputs</strong></h3><p>LLMs produce free-form text by default. That&#8217;s fine when the output is meant for a human to read. But in a production agentic system, the output of one agent is usually the input of the next. If Agent 2 expects a specific JSON format and Agent 1 returns something slightly different, the whole pipeline breaks.</p><p>Structured outputs solve this. Instead of letting the agent return whatever text it wants, you define an exact schema: a data structure that specifies which fields must be present and what type each field should be. For example, an invoice extraction agent might be required to return a JSON object with <code>vendor_name</code> (string), <code>invoice_date</code> (date), <code>total_amount</code> (number), and <code>line_items</code> (array). Every time the agent runs, its output is validated against this schema the moment it arrives, before it touches anything downstream.</p><p>This matters because without schema validation, a missing field might not cause an error until three steps later in the pipeline, at which point tracing it back to the original agent is painful. Catching it early makes errors obvious, fast to fix, and easy to log. Most LLM providers now support structured output or JSON mode natively, and frameworks like LangChain have built-in support for defining and enforcing output schemas.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wmoa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be6c779-8ee6-4e00-9ee5-4465c51afe9e_714x330.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wmoa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be6c779-8ee6-4e00-9ee5-4465c51afe9e_714x330.png 424w, https://substackcdn.com/image/fetch/$s_!wmoa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be6c779-8ee6-4e00-9ee5-4465c51afe9e_714x330.png 848w, https://substackcdn.com/image/fetch/$s_!wmoa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be6c779-8ee6-4e00-9ee5-4465c51afe9e_714x330.png 1272w, https://substackcdn.com/image/fetch/$s_!wmoa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be6c779-8ee6-4e00-9ee5-4465c51afe9e_714x330.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wmoa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be6c779-8ee6-4e00-9ee5-4465c51afe9e_714x330.png" width="714" height="330" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9be6c779-8ee6-4e00-9ee5-4465c51afe9e_714x330.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:330,&quot;width&quot;:714,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wmoa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be6c779-8ee6-4e00-9ee5-4465c51afe9e_714x330.png 424w, https://substackcdn.com/image/fetch/$s_!wmoa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be6c779-8ee6-4e00-9ee5-4465c51afe9e_714x330.png 848w, https://substackcdn.com/image/fetch/$s_!wmoa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be6c779-8ee6-4e00-9ee5-4465c51afe9e_714x330.png 1272w, https://substackcdn.com/image/fetch/$s_!wmoa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9be6c779-8ee6-4e00-9ee5-4465c51afe9e_714x330.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3>15. Putting It All Together</h3><p>Here&#8217;s how a production agentic system actually looks when all of these pieces combine. Every layer solves a specific problem: prompting ensures each agent gets clear instructions, sub-agents break the work into focused pieces, context engineering ensures agents have the right information, harness engineering ensures they behave consistently, tool calling and MCP connect them to the outside world, structured outputs keep the pipeline stable, judge agents guard quality, memory keeps context alive, observability lets you debug, and HITL keeps humans in control where it matters.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9KwE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b0c2446-8788-44c5-aebd-4935111b8af2_681x670.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9KwE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b0c2446-8788-44c5-aebd-4935111b8af2_681x670.png 424w, https://substackcdn.com/image/fetch/$s_!9KwE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b0c2446-8788-44c5-aebd-4935111b8af2_681x670.png 848w, https://substackcdn.com/image/fetch/$s_!9KwE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b0c2446-8788-44c5-aebd-4935111b8af2_681x670.png 1272w, https://substackcdn.com/image/fetch/$s_!9KwE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b0c2446-8788-44c5-aebd-4935111b8af2_681x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9KwE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b0c2446-8788-44c5-aebd-4935111b8af2_681x670.png" width="681" height="670" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5b0c2446-8788-44c5-aebd-4935111b8af2_681x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:681,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9KwE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b0c2446-8788-44c5-aebd-4935111b8af2_681x670.png 424w, https://substackcdn.com/image/fetch/$s_!9KwE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b0c2446-8788-44c5-aebd-4935111b8af2_681x670.png 848w, https://substackcdn.com/image/fetch/$s_!9KwE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b0c2446-8788-44c5-aebd-4935111b8af2_681x670.png 1272w, https://substackcdn.com/image/fetch/$s_!9KwE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b0c2446-8788-44c5-aebd-4935111b8af2_681x670.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>That&#8217;s the full picture. None of these layers exist in isolation, they&#8217;re designed to work together. Context engineering feeds the orchestrator the right information. The orchestrator, equipped with skills, routes work to focused sub-agents. Those agents use tools and MCP to reach the outside world. Structured outputs keep the data flowing cleanly between them. Judge agents catch errors before they reach the user. Memory keeps context alive across long conversations and multi-step workflows. Observability logs everything so you can debug and improve. And HITL keeps humans in the loop where the stakes are highest.</p><p>A new AI tool or framework launches every other day, but the fundamentals don&#8217;t change that fast. If you understand these concepts, you have the mental model to evaluate anything new that comes along.</p><p>If you found this useful, I write about AI engineering and system design on Substack. Subscribe!</p><div class="embedded-publication-wrap" data-attrs="{&quot;id&quot;:9174741,&quot;embedding_publication_id&quot;:null,&quot;name&quot;:&quot;Experiments with AI&quot;,&quot;logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!XwxE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18591df1-c1b9-4d7a-8bd5-d22215b9e062_780x780.png&quot;,&quot;base_url&quot;:&quot;https://utkarshumang.substack.com&quot;,&quot;hero_text&quot;:&quot;Curious learner about this ever changing space, I like to document and publish my learnings.&quot;,&quot;author_name&quot;:&quot;Utkarsh Umang&quot;,&quot;show_subscribe&quot;:true,&quot;logo_bg_color&quot;:&quot;#ffffff&quot;,&quot;language&quot;:&quot;en-gb&quot;}" data-component-name="EmbeddedPublicationToDOMWithSubscribe"><div class="embedded-publication show-subscribe"><a class="embedded-publication-link-part" native="true" href="https://utkarshumang.substack.com?utm_source=substack&amp;utm_campaign=publication_embed&amp;utm_medium=web"><img class="embedded-publication-logo" src="https://substackcdn.com/image/fetch/$s_!XwxE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18591df1-c1b9-4d7a-8bd5-d22215b9e062_780x780.png" width="56" height="56" style="background-color: rgb(255, 255, 255);"><span class="embedded-publication-name">Experiments with AI</span><div class="embedded-publication-hero-text">Curious learner about this ever changing space, I like to document and publish my learnings.</div><div class="embedded-publication-author-name">By Utkarsh Umang</div></a><form class="embedded-publication-subscribe" method="GET" action="https://utkarshumang.substack.com/subscribe?"><input type="hidden" name="source" value="publication-embed"><input type="hidden" name="autoSubmit" value="true"><input type="email" class="email-input" name="email" placeholder="Type your email..."><input type="submit" class="button primary" value="Subscribe"></form></div></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://utkarshumang.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en-gb&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Experiments with AI! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Building RAG Systems: A Complete Guide]]></title><description><![CDATA[Imagine asking ChatGPT about your company's refund policy. It either makes something up or tells you it doesn't know. That's not a model problem, that's a data problem. RAG is how you fix that.]]></description><link>https://utkarshumang.substack.com/p/building-rag-systems-a-complete-guide</link><guid isPermaLink="false">https://utkarshumang.substack.com/p/building-rag-systems-a-complete-guide</guid><dc:creator><![CDATA[Utkarsh Umang]]></dc:creator><pubDate>Fri, 22 May 2026 09:56:57 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!p1jJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6cbd89-2844-4497-a697-10973056194f_800x311.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div><hr></div><h3>1. What is RAG?</h3><p>RAG stands for Retrieval Augmented Generation. Let&#8217;s unpack what that actually means in plain terms.</p><p>Think of a regular LLM as a very well-read person who studied everything on the internet up until a certain date, then went into a room with no phone, no books, and no internet. Smart, but limited to what they already know.<br>RAG gives that person a library they can look things up in before answering. Here&#8217;s how the three parts map to that:</p><p><strong>Retrieval</strong> is the act of going to the library and fetching the relevant pages. Technically, this means querying a knowledge base, which is where your documents live.</p><p><strong>Augmented</strong> means the user&#8217;s question doesn&#8217;t go to the LLM alone. It goes with the retrieved pages attached. The LLM now sees: <em>&#8220;Here&#8217;s what the user asked, and here&#8217;s the relevant context from the knowledge base. Now answer.&#8221;</em></p><p><strong>Generation</strong> is the final step: the LLM reads everything and produces an answer grounded in your actual data.</p><h3>Why do we need RAG?</h3><p>LLMs have two core limitations when it comes to working with your data:</p><p>First, they have a knowledge cutoff. Anything that happened after they were trained, they simply don&#8217;t know about.<br>Second, they have a context window limit. You can&#8217;t just paste your entire company wiki into a prompt and expect it to work. Even models with large context windows get slower, more expensive, and less accurate as the context grows.</p><p>RAG solves both. Instead of stuffing everything into the prompt, you only retrieve what&#8217;s relevant to the current question and pass that in. It&#8217;s precise, it&#8217;s efficient, and it works with documents the model has never seen, your internal policies, product docs, support tickets, anything.</p><h3>RAG vs fine-tuning</h3><p>This is the most common question when people first encounter RAG: <em>&#8220;Why not just fine-tune the model on my data?&#8221;</em></p><p>The distinction comes down to what you&#8217;re actually trying to change.</p><p>Fine-tuning changes how the model behaves. It&#8217;s the right tool when you want the model to adopt a specific tone, follow a certain format, or develop a skill it didn&#8217;t have before. For example, training a model to always respond like a customer support agent for your brand.</p><p>RAG changes what the model knows. It&#8217;s the right tool when the model&#8217;s behavior is fine, but it needs access to data it wasn&#8217;t trained on. For example, answering questions about a document uploaded by a user five minutes ago.</p><p>A useful mental model: fine-tuning is retraining the chef, RAG is handing them a recipe card before they cook.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p1jJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6cbd89-2844-4497-a697-10973056194f_800x311.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p1jJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6cbd89-2844-4497-a697-10973056194f_800x311.png 424w, https://substackcdn.com/image/fetch/$s_!p1jJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6cbd89-2844-4497-a697-10973056194f_800x311.png 848w, https://substackcdn.com/image/fetch/$s_!p1jJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6cbd89-2844-4497-a697-10973056194f_800x311.png 1272w, https://substackcdn.com/image/fetch/$s_!p1jJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6cbd89-2844-4497-a697-10973056194f_800x311.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p1jJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6cbd89-2844-4497-a697-10973056194f_800x311.png" width="800" height="311" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4e6cbd89-2844-4497-a697-10973056194f_800x311.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:311,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!p1jJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6cbd89-2844-4497-a697-10973056194f_800x311.png 424w, https://substackcdn.com/image/fetch/$s_!p1jJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6cbd89-2844-4497-a697-10973056194f_800x311.png 848w, https://substackcdn.com/image/fetch/$s_!p1jJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6cbd89-2844-4497-a697-10973056194f_800x311.png 1272w, https://substackcdn.com/image/fetch/$s_!p1jJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e6cbd89-2844-4497-a697-10973056194f_800x311.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3>2. The two pipelines of a RAG system</h3><p>Every RAG system, no matter how simple or complex, is built on two pipelines. Understanding this split is the key to understanding how the whole thing works.</p><p>The first is the <strong>ingestion pipeline</strong>: this is where you prepare your knowledge base and store it in a way that can be searched efficiently. You run this once upfront, and again whenever your data changes.</p><p>The second is the <strong>retrieval pipeline</strong>: this runs every single time a user asks a question. It fetches the relevant context and hands it to the LLM to generate an answer.</p><p>A good analogy is a library. Ingestion is the process of acquiring books, cataloguing them, and putting them on shelves in an organized way. Retrieval is what happens when someone walks in and asks a librarian a question. The librarian goes to the right shelf, pulls the relevant pages, and uses them to answer.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!edYc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F643cf55d-80e2-4294-9dfa-42bee8010118_800x289.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!edYc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F643cf55d-80e2-4294-9dfa-42bee8010118_800x289.png 424w, https://substackcdn.com/image/fetch/$s_!edYc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F643cf55d-80e2-4294-9dfa-42bee8010118_800x289.png 848w, https://substackcdn.com/image/fetch/$s_!edYc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F643cf55d-80e2-4294-9dfa-42bee8010118_800x289.png 1272w, https://substackcdn.com/image/fetch/$s_!edYc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F643cf55d-80e2-4294-9dfa-42bee8010118_800x289.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!edYc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F643cf55d-80e2-4294-9dfa-42bee8010118_800x289.png" width="800" height="289" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/643cf55d-80e2-4294-9dfa-42bee8010118_800x289.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:289,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!edYc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F643cf55d-80e2-4294-9dfa-42bee8010118_800x289.png 424w, https://substackcdn.com/image/fetch/$s_!edYc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F643cf55d-80e2-4294-9dfa-42bee8010118_800x289.png 848w, https://substackcdn.com/image/fetch/$s_!edYc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F643cf55d-80e2-4294-9dfa-42bee8010118_800x289.png 1272w, https://substackcdn.com/image/fetch/$s_!edYc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F643cf55d-80e2-4294-9dfa-42bee8010118_800x289.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h3>3. The ingestion pipeline</h3><p>The ingestion pipeline is where your raw data gets transformed into something a RAG system can actually search. If this step is done poorly, no amount of clever retrieval logic will save you. Garbage in, garbage out.</p><p>It has four steps: source, chunking, embedding, and storing. Let&#8217;s go through each.</p><h4>Step 1: Source (knowledge base)</h4><p>This is your raw data. It could be a folder of PDFs, a Notion workspace, a database, customer support tickets, product documentation, anything. The knowledge base is everything you want your RAG system to be able to answer questions about.</p><p>The important thing to recognize here is that this data hasn&#8217;t been processed yet. It&#8217;s just raw text in various formats, potentially hundreds of thousands of tokens worth of it. You can&#8217;t pass it to an LLM as-is, which is why the next step exists.</p><h4>Step 2: Chunking</h4><p>Chunking is the process of splitting your raw text into smaller, manageable pieces. You&#8217;re essentially deciding: &#8220;How big should each unit of searchable information be?&#8221;</p><p>A common default is 1,000 tokens per chunk, but you can tune this up or down depending on your use case.</p><p>There&#8217;s also a concept called <strong>chunk overlap</strong>: the last N characters of one chunk are repeated at the start of the next. This exists to prevent a sentence from being cut mid-thought at a chunk boundary, losing its meaning in the process. Think of it like a sliding window moving across your document.</p><p>Chunking sounds simple but it&#8217;s one of the most consequential decisions in your entire pipeline. Here&#8217;s why it can go wrong:</p><ul><li><p><strong>Chunks too small:</strong> You preserve precision but lose context. A chunk that says &#8220;it increased by 23%&#8221; is meaningless without knowing what &#8220;it&#8221; refers to.</p></li><li><p><strong>Chunks too large:</strong> You retrieve too much noise along with the relevant information, which dilutes the LLM&#8217;s answer.</p></li><li><p><strong>Poor boundaries:</strong> Splitting mid-paragraph or mid-table breaks the logical flow of information.</p></li><li><p><strong>No structural awareness:</strong> A naive splitter doesn&#8217;t know the difference between a heading, a code block, and body text. It just cuts at character counts, which often produces nonsensical chunks.</p></li></ul><p>This is why there are multiple chunking strategies, and choosing the right one for your document type matters more than most people initially realise.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lI1s!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1d4c552-5ed5-47c4-bacc-0eb7bdd33177_800x222.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lI1s!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1d4c552-5ed5-47c4-bacc-0eb7bdd33177_800x222.png 424w, https://substackcdn.com/image/fetch/$s_!lI1s!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1d4c552-5ed5-47c4-bacc-0eb7bdd33177_800x222.png 848w, https://substackcdn.com/image/fetch/$s_!lI1s!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1d4c552-5ed5-47c4-bacc-0eb7bdd33177_800x222.png 1272w, https://substackcdn.com/image/fetch/$s_!lI1s!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1d4c552-5ed5-47c4-bacc-0eb7bdd33177_800x222.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lI1s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1d4c552-5ed5-47c4-bacc-0eb7bdd33177_800x222.png" width="800" height="222" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d1d4c552-5ed5-47c4-bacc-0eb7bdd33177_800x222.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:222,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lI1s!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1d4c552-5ed5-47c4-bacc-0eb7bdd33177_800x222.png 424w, https://substackcdn.com/image/fetch/$s_!lI1s!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1d4c552-5ed5-47c4-bacc-0eb7bdd33177_800x222.png 848w, https://substackcdn.com/image/fetch/$s_!lI1s!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1d4c552-5ed5-47c4-bacc-0eb7bdd33177_800x222.png 1272w, https://substackcdn.com/image/fetch/$s_!lI1s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd1d4c552-5ed5-47c4-bacc-0eb7bdd33177_800x222.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Chunk size and overlap visualised as a sliding window over text</figcaption></figure></div><p>Now let&#8217;s look at the different chunking strategies available and when to use each.</p><h4>Chunking strategies:</h4><p>Not all text is structured the same way, so there&#8217;s no single chunking strategy that works everywhere. Here are the five main approaches, roughly ordered from simplest to most sophisticated:</p><p><strong>Character text splitter</strong> is the most basic approach. It splits text at a separator character (a double newline by default), then combines the resulting pieces until they fill up the chunk size limit. If a single piece is already larger than the chunk size, it&#8217;s kept as-is. It&#8217;s fast and cheap, but completely ignores the meaning of what it&#8217;s splitting.</p><p><strong>Recursive text splitter</strong> is an upgrade on the above. Instead of one separator, you give it a priority list: try splitting by paragraph first, then by sentence, then by word if needed. If a chunk is still too large after the first split, it recursively applies the next separator. This is the default in most RAG frameworks like LangChain for a reason: it respects document structure without being expensive.</p><p><strong>Document-specific splitting</strong> goes one step further by understanding the file format itself. A PDF splitter knows about pages and columns. A Markdown splitter knows about headers and code blocks. An Excel splitter knows about rows and sheets. Use this when your source documents have rich structure that a generic splitter would destroy.</p><p><strong>Semantic chunking</strong> is where it gets interesting. Instead of splitting by characters or structure, it splits by meaning. Here&#8217;s how it works: every sentence gets encoded into a vector, then sentences are compared against each other using cosine similarity. Sentences above a similarity threshold (commonly the 70th percentile) get grouped into the same chunk. Sentences that diverge in meaning start a new chunk. The result is chunks that are semantically coherent rather than just the right size. The tradeoff is cost: you&#8217;re running an embedding model during ingestion, not just doing string operations.</p><p><strong>Agentic chunking</strong> is the most accurate and the most expensive. You pass the raw text to an LLM with a prompt that says &#8220;divide this into logical chunks.&#8221; The LLM reads the content with full comprehension and makes chunking decisions the way a human editor would. Reserved for high-stakes use cases where quality matters more than cost.</p><p>In practice, production pipelines rarely use any of these in isolation. Libraries like <code>unstructured.io</code> combine multiple strategies under the hood depending on what type of content they&#8217;re processing.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QC7d!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cdb44a0-ff4f-45af-a4e9-0e8438f74a28_800x353.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QC7d!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cdb44a0-ff4f-45af-a4e9-0e8438f74a28_800x353.png 424w, https://substackcdn.com/image/fetch/$s_!QC7d!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cdb44a0-ff4f-45af-a4e9-0e8438f74a28_800x353.png 848w, https://substackcdn.com/image/fetch/$s_!QC7d!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cdb44a0-ff4f-45af-a4e9-0e8438f74a28_800x353.png 1272w, https://substackcdn.com/image/fetch/$s_!QC7d!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cdb44a0-ff4f-45af-a4e9-0e8438f74a28_800x353.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QC7d!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cdb44a0-ff4f-45af-a4e9-0e8438f74a28_800x353.png" width="800" height="353" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0cdb44a0-ff4f-45af-a4e9-0e8438f74a28_800x353.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:353,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QC7d!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cdb44a0-ff4f-45af-a4e9-0e8438f74a28_800x353.png 424w, https://substackcdn.com/image/fetch/$s_!QC7d!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cdb44a0-ff4f-45af-a4e9-0e8438f74a28_800x353.png 848w, https://substackcdn.com/image/fetch/$s_!QC7d!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cdb44a0-ff4f-45af-a4e9-0e8438f74a28_800x353.png 1272w, https://substackcdn.com/image/fetch/$s_!QC7d!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0cdb44a0-ff4f-45af-a4e9-0e8438f74a28_800x353.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The Five strategies and how they differ in terms of accuracy and cost</figcaption></figure></div><h4>Step 3: Embedder</h4><p>Once your chunks are ready, the next step is to convert each one into a vector, a list of numbers that captures the semantic meaning of that text.</p><p>Here&#8217;s the intuition: words and phrases that mean similar things end up close to each other in vector space. &#8220;Dog&#8221; and &#8220;puppy&#8221; will have vectors that point in nearly the same direction. &#8220;Dog&#8221; and &#8220;quarterly earnings&#8221; will not. This is how the retrieval step finds relevant chunks later: it converts the user&#8217;s query into a vector and looks for chunks whose vectors are nearby.</p><p>The quality of your embedder directly affects the quality of your retrieval. The MTEB leaderboard is the standard benchmark for comparing embedding models. As a reference, OpenAI&#8217;s two main options are:</p><ul><li><p><strong>text-embedding-3-small:</strong> 1,536 dimensions by default, configurable to 512 or 1,024. Good balance of quality and cost.</p></li><li><p><strong>text-embedding-3-large:</strong> 3,072 dimensions by default. More expressive, captures finer semantic nuance, but more expensive.</p></li></ul><p>More dimensions generally means richer representation, but it also means more storage and slower search. For most applications, <code>text-embedding-3-small</code> is sufficient to start.</p><h4>Step 4: Vector DB</h4><p>The final step of ingestion is storing your vectors somewhere they can be searched at query time. This is the vector database.</p><p>Choosing the right one mostly comes down to your infrastructure preferences and how far along you are in building:</p><ul><li><p><strong>Pinecone:</strong> Fully managed, API-based. Zero infrastructure to maintain. Good choice if you want to move fast and don&#8217;t want to think about ops.</p></li><li><p><strong>Qdrant:</strong> Open source and self-hostable. Good if you want control over your data and are comfortable running your own infrastructure.</p></li><li><p><strong>pgvector:</strong> A Postgres extension that adds vector search to your existing database. The best choice if you&#8217;re already on Postgres and want to keep your stack simple.</p></li><li><p><strong>ChromaDB:</strong> Extremely easy to set up, runs locally. The go-to for prototyping and experimentation.</p></li><li><p><strong>FAISS:</strong> A Meta library for efficient similarity search. Lightweight, runs in-memory, great for local development or when you need raw speed without a database server.</p></li></ul><p>With step 4 complete, ingestion is done. Your knowledge base is now chunked, embedded, and stored, ready to be searched.</p><div><hr></div><h3>4. The retrieval pipeline</h3><p>Ingestion was the one-time setup. The retrieval pipeline is what runs live, every single time a user asks a question. It has three steps.</p><h4>Step 1: Query</h4><p>The user types a question in natural language. The very first thing the system does is convert that question into a vector, using the exact same embedding model that was used during ingestion.</p><p>This point is easy to miss but critical: it has to be the same model. Your chunks were embedded into a specific vector space. Your query needs to land in that same space for similarity search to make sense. Using a different model is like translating a sentence into French to compare it with text in German and expecting the words to align.</p><h4>Step 2: Retriever</h4><p>Now that the query is a vector, the retriever takes it and searches the vector DB for the chunks whose vectors are closest to it. The closeness is measured using cosine similarity, which looks at the angle between two vectors:</p><p><code>cosine similarity = (A &#183; B) / (|A| &#215; |B|)</code></p><p>The smaller the angle between two vectors, the more semantically similar the underlying text is. With modern normalized embedding models, the denominator is always 1, so similarity essentially reduces to a dot product between the two vectors.</p><p>The retriever returns the top-k most similar chunks. These are the pieces of your knowledge base most likely to contain the answer to the user&#8217;s question.</p><h4>Step 3: LLM generation</h4><p>The retrieved chunks are combined with the original user query and passed to the LLM as a single prompt. The structure looks something like:</p><p><em>&#8220;Here is some context: [chunk 1] [chunk 2] [chunk 3]. Using this context, answer the following question: [user query].&#8221;</em></p><p>The LLM now has everything it needs: the question and the relevant information to answer it. This is the augmentation step from our earlier definition, now made concrete. The model generates a response grounded in your actual data rather than just its training weights.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OO2i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed95e68-1248-4de9-b857-618052c9a490_800x244.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OO2i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed95e68-1248-4de9-b857-618052c9a490_800x244.png 424w, https://substackcdn.com/image/fetch/$s_!OO2i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed95e68-1248-4de9-b857-618052c9a490_800x244.png 848w, https://substackcdn.com/image/fetch/$s_!OO2i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed95e68-1248-4de9-b857-618052c9a490_800x244.png 1272w, https://substackcdn.com/image/fetch/$s_!OO2i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed95e68-1248-4de9-b857-618052c9a490_800x244.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OO2i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed95e68-1248-4de9-b857-618052c9a490_800x244.png" width="800" height="244" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ed95e68-1248-4de9-b857-618052c9a490_800x244.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:244,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!OO2i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed95e68-1248-4de9-b857-618052c9a490_800x244.png 424w, https://substackcdn.com/image/fetch/$s_!OO2i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed95e68-1248-4de9-b857-618052c9a490_800x244.png 848w, https://substackcdn.com/image/fetch/$s_!OO2i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed95e68-1248-4de9-b857-618052c9a490_800x244.png 1272w, https://substackcdn.com/image/fetch/$s_!OO2i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ed95e68-1248-4de9-b857-618052c9a490_800x244.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The full retrieval flow</figcaption></figure></div><div><hr></div><h3>5. History aware retrieval</h3><p>The three-step retrieval pipeline works well for a single question. But real users don&#8217;t ask one question and stop. They have conversations.</p><p>Consider this exchange:</p><blockquote><p><em>User: &#8220;What is RAG?&#8221; <br>System: </em>explains RAG<em> <br>User: &#8220;How is it different from fine-tuning?&#8221;</em></p></blockquote><p>That second question, sent to a basic RAG system, is ambiguous. &#8220;It&#8221; refers to RAG, but the retriever has no idea. It sees the words &#8220;different from fine-tuning&#8221; and may retrieve completely irrelevant chunks. The conversation history exists in the UI, but the retrieval system is stateless.</p><p>History-aware retrieval solves this by adding a query rewriting step before retrieval. Here&#8217;s how it works:</p><p>The system stores the full conversation, every question and every answer. When a new question comes in, it doesn&#8217;t go straight to the retriever. Instead, the system passes the chat history along with the new question to the LLM and asks it to rewrite the query into a fully self-contained standalone question.</p><p>So &#8220;How is it different from fine-tuning?&#8221; becomes &#8220;How is RAG different from fine-tuning?&#8221; before it ever reaches the retriever. Now the retrieval is accurate regardless of how many turns deep the conversation is.</p><p>Once the answer comes back, the new question and answer are appended to the chat history, and the loop continues.</p><p>It adds one LLM call per query, but it&#8217;s a small cost for a significant improvement in multi-turn accuracy.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D9Ak!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46519cd6-5158-4f28-b31f-04f66dff7467_800x333.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D9Ak!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46519cd6-5158-4f28-b31f-04f66dff7467_800x333.png 424w, https://substackcdn.com/image/fetch/$s_!D9Ak!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46519cd6-5158-4f28-b31f-04f66dff7467_800x333.png 848w, https://substackcdn.com/image/fetch/$s_!D9Ak!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46519cd6-5158-4f28-b31f-04f66dff7467_800x333.png 1272w, https://substackcdn.com/image/fetch/$s_!D9Ak!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46519cd6-5158-4f28-b31f-04f66dff7467_800x333.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D9Ak!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46519cd6-5158-4f28-b31f-04f66dff7467_800x333.png" width="800" height="333" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/46519cd6-5158-4f28-b31f-04f66dff7467_800x333.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:333,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D9Ak!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46519cd6-5158-4f28-b31f-04f66dff7467_800x333.png 424w, https://substackcdn.com/image/fetch/$s_!D9Ak!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46519cd6-5158-4f28-b31f-04f66dff7467_800x333.png 848w, https://substackcdn.com/image/fetch/$s_!D9Ak!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46519cd6-5158-4f28-b31f-04f66dff7467_800x333.png 1272w, https://substackcdn.com/image/fetch/$s_!D9Ak!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F46519cd6-5158-4f28-b31f-04f66dff7467_800x333.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The flow with history aware retrieval added</figcaption></figure></div><div><hr></div><h3>6. Production ingestion pipeline using unstructured.io</h3><p>Everything we covered in the ingestion pipeline so far was conceptually clean: take your documents, chunk them, embed them, store them. In practice, it&#8217;s messier.</p><p>Real-world documents are not plain text files. A company&#8217;s knowledge base might include PDFs with embedded tables, Word docs with inconsistent formatting, slide decks, spreadsheets, and scanned images. A plain text splitter handed a PDF with a financial table will produce garbage chunks that destroy the meaning of that table entirely.</p><p>This is the problem <code>unstructured.io</code> solves. It&#8217;s an ETL (extract, transform, load) library built specifically for the chaos of real-world documents. It handles the complexity of mixed content types so your chunking and embedding steps receive clean, structured input. Here&#8217;s what a production ingestion pipeline looks like when built with it.</p><h4>Step 1: File service</h4><p>Raw documents are uploaded to a file service before any processing begins. S3 is the standard choice here. This gives you a durable, scalable store for source files that&#8217;s decoupled from your processing infrastructure, so you can reprocess documents at any time without needing to re-upload them.</p><h4>Step 2: Queue</h4><p>Document processing is slow. A large PDF can take several seconds to partition, chunk, and embed. In a production system you never want that blocking a request thread.</p><p>Instead, each uploaded file drops a message into a queue. Workers pick up jobs from the queue and process them asynchronously. This keeps ingestion non-blocking and makes the system resilient: if a worker crashes mid-job, the message stays in the queue and gets retried.</p><h4>Step 3: Partitioning</h4><p>This is where unstructured.io earns its place. Partitioning is the step that breaks a complex document into its atomic elements: paragraphs of text, tables, images, headers, captions, footers.</p><p>This is fundamentally different from chunking. Chunking is about size. Partitioning is about structure. Unstructured reads the document layout first, identifies what type of content each section is, and classifies it before any splitting happens. A table is recognised as a table, not just &#8220;some text with a lot of whitespace.&#8221; An image is extracted as an image, not skipped.</p><h4>Step 4: Chunking</h4><p>Once the document is partitioned into atomic elements, unstructured applies a chunking strategy called &#8220;chunk by title.&#8221; It keeps all content under the same heading together as a unit, which preserves the semantic relationship between a heading and the paragraphs that follow it.</p><p>Images and tables get special treatment here because they can&#8217;t just be chunked as text:</p><ul><li><p><strong>Images</strong> are stored as base64 encoded data, but the original image file is also retained.</p></li><li><p><strong>Tables</strong> are stored as text chunks, but the original table structure is also retained.</p></li></ul><p>This distinction matters for the next step.</p><h4>Step 5: Agentic chunking for multimodal chunks</h4><p>For chunks that contain multimodal content like tables or images, unstructured uses agentic chunking. An LLM is asked to generate a natural language summary of what the chunk contains.</p><p>The reason for this split is that retrieval and generation have different requirements. Retrieval needs something compact and semantic, a dense summary that embeds well and surfaces reliably when a user asks a related question. Generation needs the full original content, the actual table with all its rows and values, or the image with all its detail.</p><p>So the pipeline stores both, and in LangChain&#8217;s document model this maps cleanly to two fields:</p><ul><li><p><code>page_content</code> stores the LLM-generated summary, used for embedding and retrieval</p></li><li><p><code>metadata</code> stores the original content, passed to the LLM at generation time</p></li></ul><p>The result is a pipeline that retrieves accurately and generates completely, even when your knowledge base is full of charts, tables, and images.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EjZ-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52cb6e49-5062-4de4-9508-aaede8b9a892_800x378.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EjZ-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52cb6e49-5062-4de4-9508-aaede8b9a892_800x378.png 424w, https://substackcdn.com/image/fetch/$s_!EjZ-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52cb6e49-5062-4de4-9508-aaede8b9a892_800x378.png 848w, https://substackcdn.com/image/fetch/$s_!EjZ-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52cb6e49-5062-4de4-9508-aaede8b9a892_800x378.png 1272w, https://substackcdn.com/image/fetch/$s_!EjZ-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52cb6e49-5062-4de4-9508-aaede8b9a892_800x378.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EjZ-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52cb6e49-5062-4de4-9508-aaede8b9a892_800x378.png" width="800" height="378" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/52cb6e49-5062-4de4-9508-aaede8b9a892_800x378.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:378,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EjZ-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52cb6e49-5062-4de4-9508-aaede8b9a892_800x378.png 424w, https://substackcdn.com/image/fetch/$s_!EjZ-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52cb6e49-5062-4de4-9508-aaede8b9a892_800x378.png 848w, https://substackcdn.com/image/fetch/$s_!EjZ-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52cb6e49-5062-4de4-9508-aaede8b9a892_800x378.png 1272w, https://substackcdn.com/image/fetch/$s_!EjZ-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52cb6e49-5062-4de4-9508-aaede8b9a892_800x378.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Full production ingestion pipeline</figcaption></figure></div><div><hr></div><h3>7. Advanced retrieval techniques</h3><p>Basic retrieval gets you surprisingly far: embed the query, find the most similar chunks, pass them to the LLM. For simple use cases it works fine. But as your knowledge base grows and your users ask more complex questions, the cracks start to show. You get irrelevant chunks, redundant context, and queries that miss relevant information simply because of how they were phrased.</p><p>Here are four techniques that meaningfully improve retrieval accuracy in production.</p><h4>Scored retrieval</h4><p>The simplest upgrade and the one you should add first.</p><p>By default, a retriever returns the top-k chunks regardless of how similar they actually are. If a user asks about your refund policy and your knowledge base doesn&#8217;t contain anything about it, basic retrieval will still return the top-k chunks, they&#8217;ll just be loosely related noise. The LLM then tries to answer using that noise and either hallucinates or produces a vague, hedged response.</p><p>Scored retrieval adds a minimum similarity threshold. Any chunk that scores below it gets dropped, even if it was technically in the top-k. The most common threshold is 0.3. It&#8217;s a small change that prevents low-quality context from polluting the prompt and nudging the LLM toward bad answers.</p><h4>MMR : Max Marginal Relevance</h4><p>Scored retrieval filters out irrelevant chunks. MMR solves a different problem: redundancy.</p><p>Imagine asking &#8220;What are the benefits of RAG?&#8221; and your top-5 retrieved chunks are all slight variations of the same paragraph from five different pages of the same document. They&#8217;re all relevant, but they&#8217;re all saying the same thing. You&#8217;ve wasted most of your context window passing duplicate information to the LLM.</p><p>MMR balances relevance with diversity. It retrieves a larger candidate set first, then selects the final chunks by iteratively picking the one that is both relevant to the query and maximally different from what&#8217;s already been selected. Three parameters control this:</p><ul><li><p><code>top_k</code>: how many chunks to ultimately send to the LLM</p></li><li><p><code>fetch_k</code>: how many chunks to retrieve as the initial candidate pool before filtering</p></li><li><p><code>lambda_mult</code>: the diversity dial. 0 means maximum diversity, 1 means maximum relevance (equivalent to standard retrieval)</p></li></ul><p>One caveat: MMR is not the right choice when you need precise, factual answers where every piece of context must be directly on-point. Introducing diversity can occasionally pull in chunks that are semantically interesting but not strictly relevant to the question.</p><p>For factual Q&amp;A, stick with scored retrieval. <br>For broader research-style queries, MMR shines.</p><h4>Multi-query retrieval</h4><p>Vector search is sensitive to phrasing. A user asking &#8220;How do I reduce LLM hallucinations?&#8221; might miss chunks that were written around &#8220;improving factual accuracy&#8221; or &#8220;grounding model outputs,&#8221; even though they cover the exact same concept.</p><p>Multi-query retrieval addresses this by using the LLM to generate several different phrasings of the original question before running retrieval. Each variation gets its own retrieval pass, and the results are merged into a single deduplicated set of chunks. The LLM then generates an answer from this richer, more comprehensive context.</p><p>It costs more, one extra LLM call upfront plus multiple retrieval passes, but for complex or ambiguous queries it can significantly improve recall.</p><h4>Reciprocal Rank Fusion (RRF)</h4><p>Multi-query retrieval creates a new problem: you now have multiple ranked lists of chunks coming back from different query variations, and you need a principled way to combine them into one final ranking.</p><p>For example if you generated 5 queries from 1 user query and fetched 5 chunks with each generated query, you now have 25 chunks, these 25 chunks need not be unique and you can only pass top 5 chunks to the LLM for generation. A reranker helps here by identifying the top 5 relevant chunks from this set of 25 chunks.</p><p>RRF is the standard solution. For each chunk, it looks at its rank position across all the retrieval results it appeared in and computes a combined score:</p><p><code>RRF score = &#931; 1 / (k + rank)</code></p><p>A chunk that ranked highly across multiple query variations ends up with a high RRF score. A chunk that only appeared in one result list, or ranked low, gets a lower score. The constant k is typically set to 60, which softens the penalty for lower-ranked chunks so that a chunk ranked 10th doesn&#8217;t get completely written off just because another chunk ranked 1st.</p><p>RRF is retrieval-method agnostic, which makes it especially useful in hybrid search setups where you&#8217;re combining results from both vector search and keyword search, which we&#8217;ll cover next.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fGqb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdba5acca-1852-4d5a-8a9c-01bc07122523_800x378.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fGqb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdba5acca-1852-4d5a-8a9c-01bc07122523_800x378.png 424w, https://substackcdn.com/image/fetch/$s_!fGqb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdba5acca-1852-4d5a-8a9c-01bc07122523_800x378.png 848w, https://substackcdn.com/image/fetch/$s_!fGqb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdba5acca-1852-4d5a-8a9c-01bc07122523_800x378.png 1272w, https://substackcdn.com/image/fetch/$s_!fGqb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdba5acca-1852-4d5a-8a9c-01bc07122523_800x378.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fGqb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdba5acca-1852-4d5a-8a9c-01bc07122523_800x378.png" width="800" height="378" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dba5acca-1852-4d5a-8a9c-01bc07122523_800x378.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:378,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fGqb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdba5acca-1852-4d5a-8a9c-01bc07122523_800x378.png 424w, https://substackcdn.com/image/fetch/$s_!fGqb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdba5acca-1852-4d5a-8a9c-01bc07122523_800x378.png 848w, https://substackcdn.com/image/fetch/$s_!fGqb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdba5acca-1852-4d5a-8a9c-01bc07122523_800x378.png 1272w, https://substackcdn.com/image/fetch/$s_!fGqb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdba5acca-1852-4d5a-8a9c-01bc07122523_800x378.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">These four techniques layer on top of each other in a retrieval pipeline</figcaption></figure></div><div><hr></div><h3>8. Hybrid search</h3><p>Semantic search is powerful, but it has a blind spot: precision.</p><p>Ask a semantic search system for &#8220;invoice INV-2024&#8211;00892&#8221; and it might return chunks about invoicing processes, billing cycles, or payment terms. Conceptually related, but completely wrong. Semantic search looks for meaning, and meaning doesn&#8217;t help you when the user is looking for an exact string.</p><p>This is where keyword search fills the gap. And hybrid search is the approach that combines both, using each where it&#8217;s strongest.</p><p>The tradeoff looks like this: semantic search understands intent and handles paraphrasing well, but struggles with exact matches. Keyword search is precise and reliable for specific terms, but falls apart when a user phrases their query differently from how the document was written. Hybrid search gets you both.</p><h4>BM25 : Best Matching 25</h4><p>The most widely used keyword search algorithm in RAG systems is BM25. It scores chunks based on two complementary signals:</p><p><strong>TF (Term Frequency)</strong> measures how often the searched term appears in a given chunk. A chunk that mentions &#8220;pgvector&#8221; five times is likely more about pgvector than one that mentions it once in passing.</p><p><strong>IDF (Inverse Document Frequency)</strong> corrects for common words. If a term appears in almost every chunk in your knowledge base, finding it doesn&#8217;t tell you much. IDF down-weights frequent terms and up-weights rare ones, so a search for a specific product code or a niche technical term gets ranked above chunks that just happen to contain common words like &#8220;the&#8221; or &#8220;data.&#8221;</p><p>Together, TF and IDF give BM25 its precision: it finds chunks where the exact term appears and ranks them higher when that term is meaningfully rare across the knowledge base.</p><h4>Ensemble retriever</h4><p>To combine semantic and keyword search, you use an ensemble retriever. It runs both retrievers in parallel and merges their results using RRF, which we covered in the previous section.</p><p>What makes the ensemble retriever flexible is weighting. You can control how much you want to lean toward semantic results versus keyword results. A knowledge base full of technical documentation with specific product codes might warrant a higher keyword weight. A conversational FAQ might lean more semantic. The weights feed directly into the RRF scoring as numerators, so tuning them shifts which retriever has more influence over the final ranking.</p><h4>In production</h4><p>A production-grade retrieval setup combines everything from the last two sections: multiple query variants, run across both semantic and keyword retrievers, with RRF merging the results.</p><p>Even then, you&#8217;re often left with more chunks than you want to pass to the LLM. Running multi-query hybrid search can surface 20 to 30 candidate chunks. Passing all of them increases cost, latency, and the risk of noisy context degrading the answer quality.</p><p>This is where reranking comes in: a final filtering step that scores the merged candidates more carefully and cuts the list down to the top 5 or top 10 before anything reaches the LLM. We&#8217;ll cover that in the next section.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!C_vm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F174f1e6e-14b2-40fe-9b50-78395f97795e_800x338.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!C_vm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F174f1e6e-14b2-40fe-9b50-78395f97795e_800x338.png 424w, https://substackcdn.com/image/fetch/$s_!C_vm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F174f1e6e-14b2-40fe-9b50-78395f97795e_800x338.png 848w, https://substackcdn.com/image/fetch/$s_!C_vm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F174f1e6e-14b2-40fe-9b50-78395f97795e_800x338.png 1272w, https://substackcdn.com/image/fetch/$s_!C_vm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F174f1e6e-14b2-40fe-9b50-78395f97795e_800x338.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!C_vm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F174f1e6e-14b2-40fe-9b50-78395f97795e_800x338.png" width="800" height="338" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/174f1e6e-14b2-40fe-9b50-78395f97795e_800x338.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:338,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!C_vm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F174f1e6e-14b2-40fe-9b50-78395f97795e_800x338.png 424w, https://substackcdn.com/image/fetch/$s_!C_vm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F174f1e6e-14b2-40fe-9b50-78395f97795e_800x338.png 848w, https://substackcdn.com/image/fetch/$s_!C_vm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F174f1e6e-14b2-40fe-9b50-78395f97795e_800x338.png 1272w, https://substackcdn.com/image/fetch/$s_!C_vm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F174f1e6e-14b2-40fe-9b50-78395f97795e_800x338.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Semantic and Keyword search combine in Hybrid search</figcaption></figure></div><div><hr></div><h3>9. Reranking</h3><p>After hybrid search and RRF, you might still have 20 to 30 candidate chunks. Passing all of them to the LLM would bloat the context window, increase cost and latency, and reintroduce the exact noise problem RAG was designed to solve. In production you want to pass the top 5 to 10 chunks, no more.</p><p>But how do you decide which 5 to 10 are the best ones? The similarity scores from vector search are good approximations, not precise relevance scores. This is where a reranker comes in.</p><p>A reranker is a model that sits between the retriever and the LLM. It takes every candidate chunk, scores it carefully against the query, and reorders the list so you can confidently cut it at the top.</p><h4>The two stage process</h4><p>It helps to think of the full retrieval pipeline as two distinct stages with different jobs:</p><p><strong>Stage 1, embeddings:</strong> fast and broad. You cast a wide net using vector similarity. This is intentionally an approximation: you&#8217;re finding chunks that are roughly in the right direction, not necessarily the most relevant ones. Speed is the priority here.</p><p><strong>Stage 2, reranker:</strong> slow and precise. For each chunk returned in stage 1, the reranker takes the query and the chunk together, encodes them jointly, and produces a precise relevance score. This is repeated for every candidate, then the list is reordered by these scores and trimmed.</p><p>The two-stage design is deliberate. Running a precise reranker over your entire vector DB on every query would be too slow. Running only fast vector search gives you speed but imprecision. Together, you get the best of both.</p><h4>Bi-encoder vs cross-encoder</h4><p>Understanding this distinction explains why reranking is more accurate than embedding alone.</p><p>An embedding model is a bi-encoder. It encodes the query into a vector and each chunk into a vector separately, then compares them after the fact. It&#8217;s fast because the chunk vectors can be precomputed and stored. But encoding them separately means the model never gets to see how the query and chunk interact with each other. It&#8217;s comparing two things in isolation.</p><p>A reranker is a cross-encoder. It takes the query and the chunk concatenated together as a single input and encodes them jointly. Because the model sees both at the same time, it can capture much richer signals: does the chunk directly answer the question, or just share some keywords? Is the relevance explicit or just implied? This joint encoding produces a relevance score that&#8217;s meaningfully more accurate than cosine similarity.</p><p>The tradeoff is that cross-encoders can&#8217;t precompute anything. Every query requires a fresh pass over every candidate chunk, which is why you use the bi-encoder to filter down to a manageable set first. Cohere&#8217;s reranker is one of the most widely used options in production.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FbYX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa1dafc-7045-4d95-bf4c-788323238ed2_800x422.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FbYX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa1dafc-7045-4d95-bf4c-788323238ed2_800x422.png 424w, https://substackcdn.com/image/fetch/$s_!FbYX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa1dafc-7045-4d95-bf4c-788323238ed2_800x422.png 848w, https://substackcdn.com/image/fetch/$s_!FbYX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa1dafc-7045-4d95-bf4c-788323238ed2_800x422.png 1272w, https://substackcdn.com/image/fetch/$s_!FbYX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa1dafc-7045-4d95-bf4c-788323238ed2_800x422.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FbYX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa1dafc-7045-4d95-bf4c-788323238ed2_800x422.png" width="800" height="422" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cfa1dafc-7045-4d95-bf4c-788323238ed2_800x422.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:422,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FbYX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa1dafc-7045-4d95-bf4c-788323238ed2_800x422.png 424w, https://substackcdn.com/image/fetch/$s_!FbYX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa1dafc-7045-4d95-bf4c-788323238ed2_800x422.png 848w, https://substackcdn.com/image/fetch/$s_!FbYX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa1dafc-7045-4d95-bf4c-788323238ed2_800x422.png 1272w, https://substackcdn.com/image/fetch/$s_!FbYX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcfa1dafc-7045-4d95-bf4c-788323238ed2_800x422.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">From hybrid search all the way through to the final answer, with reranking as the last filter before the LLM</figcaption></figure></div><div><hr></div><h3>Where to go from here?</h3><p>This post covered the full architecture of a RAG system, from the ingestion pipeline and chunking strategies to hybrid search, RRF, and reranking. By now you should have a solid mental model of how a production RAG system is actually built.</p><p>But building the pipeline is only half the story. Once it&#8217;s running, a new set of questions takes over:</p><p>What actually breaks in production, and how do you diagnose it? How do you ensure reliability when your knowledge base changes? What does hallucination look like in a RAG system specifically, and how do you reduce it? How do you evaluate whether your RAG system is good, not just working?</p><p>These are the questions that separate a RAG proof-of-concept from a production system you can trust.</p><p>I&#8217;ll be covering each of them in the next part of this series.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://utkarshumang.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://utkarshumang.substack.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://utkarshumang.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Experiments with AI! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item></channel></rss>