<?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[The Knowledge Layer]]></title><description><![CDATA[How AI agents store, update, retrieve, and compose knowledge in production: for the engineers building agent systems and the people who pay them to ship.
]]></description><link>https://www.ratkonikolic.com</link><image><url>https://substackcdn.com/image/fetch/$s_!sw8y!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0a97ded-37ff-4273-bc45-6ae54689e069_512x512.png</url><title>The Knowledge Layer</title><link>https://www.ratkonikolic.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 26 Aug 2026 00:35:23 GMT</lastBuildDate><atom:link href="https://www.ratkonikolic.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Ratko Nikolić]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[ratkonikolic@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[ratkonikolic@substack.com]]></itunes:email><itunes:name><![CDATA[Ratko Nikolić]]></itunes:name></itunes:owner><itunes:author><![CDATA[Ratko Nikolić]]></itunes:author><googleplay:owner><![CDATA[ratkonikolic@substack.com]]></googleplay:owner><googleplay:email><![CDATA[ratkonikolic@substack.com]]></googleplay:email><googleplay:author><![CDATA[Ratko Nikolić]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Vector vs graph vs episodic: a tour of agent memory systems]]></title><description><![CDATA[RAG retrieves from a fixed corpus. Memory is the part that remembers what happened, and the vendors building it have each bet on a different abstraction. Picking the wrong one is expensive.]]></description><link>https://www.ratkonikolic.com/p/vector-vs-graph-vs-episodic-a-tour</link><guid isPermaLink="false">https://www.ratkonikolic.com/p/vector-vs-graph-vs-episodic-a-tour</guid><dc:creator><![CDATA[Ratko Nikolić]]></dc:creator><pubDate>Tue, 25 Aug 2026 08:00:49 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b29d52c4-baff-4aa7-98c8-77175c90646c_1424x752.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3><strong>The problem</strong></h3><p>An agent handles a customer over three sessions across two weeks. Session one, the customer explains they&#8217;re on the enterprise plan and their main pain is API rate limits. Session two, a different day, they ask a follow-up, and the agent greets them like a stranger, re-asks which plan they&#8217;re on, and re-explains the rate-limit basics it already walked through. Session three, the customer mentions they <em>downgraded</em> last week, and the agent cheerfully keeps citing enterprise-tier limits, because nothing told it the earlier fact had expired.</p><p>Everything in this series so far retrieves from a corpus that sits still. Memory is the part of the knowledge layer that has to remember things that <em>happened</em>: facts that accrue from the interaction itself, change over time, and contradict what was true last week. That&#8217;s a different write path, and the knowledge layer (the part of an agent system that decides reliability in production, and an engineering discipline in its own right) gets a lot harder once it has to update, not just retrieve. The vendors building agent memory have each bet on a different abstraction for that write path, and the bet they made determines what your agent is good and bad at remembering.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.ratkonikolic.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 The Knowledge Layer! 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><h3><strong>How agent memory works</strong></h3><p>Strip away the branding and there are three abstractions underneath every memory product. Most real systems combine two of them, and in my view every product I&#8217;ve looked at is a bet on which of the three to lead with, not a fourth kind. (The cognitive-science taxonomies add procedural memory, the learned skills and routines. It&#8217;s real, and it&#8217;s starting to show up as a feature, LangMem&#8217;s prompt-updating memory and Mem0&#8217;s procedural memory type among them, but no product leads with it yet, so it stays out of this tour.)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qPAe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F831c060c-2ede-4850-b473-028a39308b8e_5149x2025.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qPAe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F831c060c-2ede-4850-b473-028a39308b8e_5149x2025.png 424w, https://substackcdn.com/image/fetch/$s_!qPAe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F831c060c-2ede-4850-b473-028a39308b8e_5149x2025.png 848w, https://substackcdn.com/image/fetch/$s_!qPAe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F831c060c-2ede-4850-b473-028a39308b8e_5149x2025.png 1272w, https://substackcdn.com/image/fetch/$s_!qPAe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F831c060c-2ede-4850-b473-028a39308b8e_5149x2025.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qPAe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F831c060c-2ede-4850-b473-028a39308b8e_5149x2025.png" width="1456" height="573" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/831c060c-2ede-4850-b473-028a39308b8e_5149x2025.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:573,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!qPAe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F831c060c-2ede-4850-b473-028a39308b8e_5149x2025.png 424w, https://substackcdn.com/image/fetch/$s_!qPAe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F831c060c-2ede-4850-b473-028a39308b8e_5149x2025.png 848w, https://substackcdn.com/image/fetch/$s_!qPAe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F831c060c-2ede-4850-b473-028a39308b8e_5149x2025.png 1272w, https://substackcdn.com/image/fetch/$s_!qPAe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F831c060c-2ede-4850-b473-028a39308b8e_5149x2025.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><p></p><p><strong>Semantic memory</strong> is the vector approach: extract the durable facts from a conversation, embed them, and retrieve the relevant ones later by similarity. It&#8217;s RAG pointed at the interaction history instead of a document corpus. <strong>Episodic / working memory</strong> keeps a running, self-editing representation of what happened (a summarized history, a persona block, a scratchpad) that the agent rewrites as the conversation grows, so the context window holds the <em>gist</em> rather than the raw transcript. <strong>Temporal knowledge graph</strong> memory stores facts as typed nodes and edges, each stamped with when it became true and when it stopped. Of the three, it&#8217;s the one that handles the downgrade in the opening story by construction: superseding a fact is a first-class, dated operation that keeps the old value in the timeline, rather than an update pass that has to notice the collision and get it right.</p><h3><strong>In practice: the vendor tour</strong></h3><p>This is the most vendor-heavy article in the series, because the memory space is where the abstraction choice is most visible in the product. Four worth knowing, each leading with a different bet.</p><p><strong>Mem0</strong> leads with <strong>semantic memory plus lightweight extraction</strong>. It sits next to your agent&#8217;s model calls: after each exchange it pulls the salient facts out and stores them as embeddings, and before each answer it recalls the relevant ones by similarity. It&#8217;s the vector bet, productised, with a focus on keeping the recalled context small. Mem0&#8217;s own paper (Prateek Chhikara and co-authors, <em>Mem0: Building Production-Ready AI Agents with Scalable Long-Term Memory</em>, [arXiv 2504.19413](<strong><a href="https://arxiv.org/abs/2504.19413">https://arxiv.org/abs/2504.19413</a></strong>), April 2025, later published at ECAI 2025) frames the win as token efficiency: store a compact set of extracted facts rather than stuffing whole histories into context, and it reports a 91% lower p95 latency and over 90% lower token cost than a full-context baseline on the LoCoMo benchmark. Even the vector bet is being pulled toward time: Mem0 rewrote its extraction and retrieval algorithm in April 2026 (single-pass extraction, multi-signal retrieval), then in May 2026 added temporal reasoning and memory decay on top of it, which tells you where the pressure in this space is. It&#8217;s the easiest of the four to drop in, and the right default when &#8220;remember what this user told me&#8221; is most of what you need.</p><p><strong>Letta</strong> leads with <strong>episodic / self-editing memory</strong>, and it&#8217;s the direct descendant of the <strong>MemGPT</strong> paper (Charles Packer and co-authors, <em>MemGPT: Towards LLMs as Operating Systems</em>, [arXiv 2310.08560](<strong><a href="https://arxiv.org/abs/2310.08560">https://arxiv.org/abs/2310.08560</a></strong>), October 2023). The core idea is borrowed from operating systems: treat the context window like RAM and an external store like disk, and let the agent itself decide what to page in and out, editing its own memory blocks (a persona, a running summary, key facts) as the conversation evolves. The bet is that an agent which <em>manages</em> its own context beats one handed a fixed retrieval, and it&#8217;s the strongest fit for long-running conversational agents that need a coherent sense of the whole relationship, not just a bag of recalled facts.</p><p><strong>Zep</strong> leads with the <strong>temporal knowledge graph</strong>, built on its open-source engine <strong>Graphiti</strong>. Every fact extracted from the conversation becomes a typed edge in a graph with validity timestamps, so the system knows not just <em>what</em> is true but <em>when</em> it was true and what superseded it (Preston Rasmussen and co-authors, <em>Zep: A Temporal Knowledge Graph Architecture for Agent Memory</em>, [arXiv 2501.13956](<strong><a href="https://arxiv.org/abs/2501.13956">https://arxiv.org/abs/2501.13956</a></strong>), January 2025). This is the abstraction that handles change correctly (the downgraded customer, the moved deadline, the role that changed), and it&#8217;s where the memory question and the GraphRAG question from Article 4 turn out to be the same question asked of a different corpus.</p><p><strong>A-MEM</strong> is the research frontier rather than a product, and it&#8217;s the one I find most interesting. Wujiang Xu and co-authors (<em>A-MEM: Agentic Memory for LLM Agents</em>, [arXiv 2502.12110](<strong><a href="https://arxiv.org/abs/2502.12110">https://arxiv.org/abs/2502.12110</a></strong>), February 2025, published at NeurIPS 2025) borrow the Zettelkasten note-taking method: each memory is an atomic note that the system <em>links</em> to related notes and re-indexes as new memories arrive, so the memory structure evolves instead of sitting in a flat store. It&#8217;s a bet that the organisation of memory should be dynamic: the same instinct behind the schema-evolution problem, which is one of the genuinely unsolved problems in the area, and what draws me to it.</p><p>The temporal-graph case is the easiest to motivate. Take a media-analytics agent tracking a developing story: the signature question is <em>&#8220;how did this narrative evolve over six weeks, and who introduced each turn?&#8221;</em> That&#8217;s hard to answer with semantic memory alone, because the answer isn&#8217;t a set of recalled facts, it&#8217;s a <em>timeline</em> of who-said-what-when with each claim stamped and linked. A temporal graph stores exactly that; a vector store flattens it into a pile of similar-looking sentences with no order. The abstraction you pick is the set of questions you can answer.</p><h3><strong>Where it shines</strong></h3><p>Two situations where memory earns a dedicated system rather than a longer prompt.</p><p>The first is <strong>long-running relationships</strong>: an assistant a user returns to across days or weeks, a sales agent tracking a deal, a support bot that should know the customer&#8217;s history. Here the value is continuity: not re-asking, not contradicting, building on what came before. The opening story is this case failing, and it&#8217;s the one buyers feel most directly because it reads as the agent being <em>dumb</em> even when the underlying model is excellent.</p><p>The second is <strong>questions about change over time</strong>: anything where <em>when</em> a fact was true matters as much as the fact. Compliance histories, evolving narratives, account states that supersede each other, &#8220;what did we know and when.&#8221; This is the temporal-graph sweet spot, and it&#8217;s common in finance, journalism, and any regulated domain where an out-of-date fact stated confidently is a real liability, not a cosmetic miss.</p><h3><strong>Where it breaks</strong></h3><p>Memory is harder than retrieval, and the failure modes are quieter.</p><p><strong>Stale and contradictory memory.</strong> The single worst failure: the agent confidently recalls a fact that was superseded, like the enterprise-tier limits after a downgrade. Semantic memory is especially prone to this, because two contradictory facts (&#8221;on the enterprise plan&#8221;, &#8220;on the pro plan&#8221;) embed to nearly the same vector, and a plain vector store has no native notion of one replacing the other. The vendors know it: Mem0&#8217;s paper describes an LLM pass that decides whether each new fact adds, updates, or deletes an existing memory, but that pass is another extraction call that can get the call wrong. If your domain has facts that expire, an abstraction without a time dimension will quietly serve the dead one.</p><p><strong>Extraction errors compound.</strong> Every memory system that extracts facts from conversation can extract the wrong fact (mis-attribute a preference, capture a hypothetical as a commitment), and once a wrong memory is written, it gets recalled and reinforced. Unlike a bad retrieval, which is transient, a bad memory persists and poisons future answers until something deletes it.</p><p><strong>Unbounded growth and recall noise.</strong> Memory accumulates, and a store that never forgets eventually recalls ten marginally-relevant facts for every useful one, drowning the signal and inflating the context bill. Deciding what <em>not</em> to remember (and what to forget) is an unsolved design problem that most teams discover only after the store is already bloated.</p><p><strong>No standard for evaluation.</strong> Until 2024 there wasn&#8217;t a widely shared yardstick for any of this. <strong>LoCoMo</strong> (Adyasha Maharana and co-authors, [arXiv 2402.17753](<strong><a href="https://arxiv.org/abs/2402.17753">https://arxiv.org/abs/2402.17753</a></strong>), ACL 2024) was the first purpose-built one to get wide pickup, and <strong>LongMemEval</strong> (Di Wu and co-authors, [arXiv 2410.10813](<strong><a href="https://arxiv.org/abs/2410.10813">https://arxiv.org/abs/2410.10813</a></strong>), October 2024, ICLR 2025) put the harder numbers on it: 500 questions testing information extraction, multi-session reasoning, temporal reasoning, knowledge updates, and abstention across long histories, on which commercial chat assistants and long-context models showed a 30% accuracy drop.</p><p>The measurement problem has since moved rather than gone away. <strong>MemDelta</strong> (Kuan Wang, [arXiv 2606.29914](<strong><a href="https://arxiv.org/abs/2606.29914">https://arxiv.org/abs/2606.29914</a></strong>), June 2026, preprint) re-ran memory systems against RAG and full-context baselines on LongMemEval, changing one component at a time. Swapping only the embedding model shifted accuracy by about 6 points, enough to flip the winner, and on some question types a managed memory layer matched plain retrieval at roughly fifty times the cost. The recommendation that follows, fix the embedding model across comparisons and report write-path cost before crediting the architecture, is the right one. If you&#8217;re not measuring memory against something like these, you&#8217;re shipping on vibes.</p><h3><strong>When not to use it</strong></h3><p>If your agent is stateless by nature (every query is self-contained, no continuity across turns matters, the corpus answers everything), then a memory system is complexity you don&#8217;t need, and you should stay with the retrieval stack from the earlier articles. A single-shot Q&amp;A bot over a documentation set has no use for episodic memory; bolting one on just adds a write path to maintain and a new way to be wrong. Memory earns its keep when the <em>interaction</em> carries information the corpus doesn&#8217;t: when &#8220;what did this user tell me last Tuesday&#8221; is a question your agent actually needs to answer.</p><p><strong>Cost / latency / setup effort:</strong></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XZaB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc895f64e-4d4c-409b-9a1a-86b77e22a5ea_801x135.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XZaB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc895f64e-4d4c-409b-9a1a-86b77e22a5ea_801x135.png 424w, https://substackcdn.com/image/fetch/$s_!XZaB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc895f64e-4d4c-409b-9a1a-86b77e22a5ea_801x135.png 848w, https://substackcdn.com/image/fetch/$s_!XZaB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc895f64e-4d4c-409b-9a1a-86b77e22a5ea_801x135.png 1272w, https://substackcdn.com/image/fetch/$s_!XZaB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc895f64e-4d4c-409b-9a1a-86b77e22a5ea_801x135.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XZaB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc895f64e-4d4c-409b-9a1a-86b77e22a5ea_801x135.png" width="801" height="135" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c895f64e-4d4c-409b-9a1a-86b77e22a5ea_801x135.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:135,&quot;width&quot;:801,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!XZaB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc895f64e-4d4c-409b-9a1a-86b77e22a5ea_801x135.png 424w, https://substackcdn.com/image/fetch/$s_!XZaB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc895f64e-4d4c-409b-9a1a-86b77e22a5ea_801x135.png 848w, https://substackcdn.com/image/fetch/$s_!XZaB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc895f64e-4d4c-409b-9a1a-86b77e22a5ea_801x135.png 1272w, https://substackcdn.com/image/fetch/$s_!XZaB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc895f64e-4d4c-409b-9a1a-86b77e22a5ea_801x135.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p><h3><strong>Combinations and hybrids</strong></h3><p>The clean split in practice: use a vector store for &#8220;what does the corpus say&#8221; (RAG, Articles 2&#8211;3), and a memory system for &#8220;what do I know about this user / this session / this developing situation.&#8221; Most production agents need both, and the good ones keep them separate: corpus knowledge and interaction memory have different lifecycles, different freshness needs, and different failure modes, and fusing them into one store muddies all three. Inside memory, the strong hybrids pair episodic working memory (for the coherent gist of the conversation) with a temporal graph (for the facts that must stay correct as they change). That is, not coincidentally, the same vector-plus-graph pattern Article 4 landed on for retrieval. And the agent deciding <em>what</em> to commit to memory is itself a retrieval-as-decision problem, straight out of the agentic-RAG article. The techniques in this series are less a menu of alternatives than a set of parts that keep recombining.</p><h3><strong>Production checklist</strong></h3><ul><li><p><strong>Give facts a time dimension</strong> if anything in your domain expires: valid-from / valid-to, or you will serve superseded facts with confidence.</p></li><li><p><strong>Log every memory write</strong> with its source turn, so a wrong memory can be traced to the exchange that created it and deleted.</p></li><li><p><strong>Set an eviction / forgetting policy</strong> up front (decide what ages out and how) rather than discovering the bloat after the store is huge and the recall is noisy.</p></li><li><p><strong>Separate corpus retrieval from interaction memory</strong>; don&#8217;t let one store do both jobs.</p></li><li><p><strong>Measure recall quality against a memory benchmark</strong> (LongMemEval- or LoCoMo-style), not just anecdotes: track multi-session and temporal questions specifically, and hold the embedding model fixed when you compare systems.</p></li><li><p><strong>Alert on contradiction</strong>: when a new memory conflicts with a stored one, surface it rather than silently keeping both.</p></li><li><p><strong>Cap and monitor memory-write cost</strong>; every extraction is a model call, and at scale the write path can cost more than the reads.</p></li></ul><h3><strong>The take</strong></h3><p>Agent memory isn&#8217;t one technique: it&#8217;s three abstractions wearing vendor logos, and the one you pick decides which questions your agent can answer. Vector memory for &#8220;remember what they told me,&#8221; episodic memory for &#8220;keep a coherent sense of the whole relationship,&#8221; temporal graphs for &#8220;track what&#8217;s true and when it changed.&#8221; Most real agents need a blend, all of them need a forgetting policy and a time dimension, and none of them should be shipped without measuring recall against something harder than your own optimism. Pick the abstraction that matches the questions you actually get asked, and budget for the write path, because remembering is more expensive than retrieving.</p><p><em><strong>I take on a small number of advisory engagements each year for teams hitting exactly these problems. Reach out if that&#8217;s you.</strong></em></p><p><strong>What to read next</strong></p><p><strong>This series</strong>:</p><ul><li><p><strong><a href="https://ratkonikolic.substack.com/p/your-agents-problem-isnt-the-model">Article 1 &#8212; Your agent&#8217;s problem isn&#8217;t the model, it&#8217;s the knowledge layer</a></strong></p></li><li><p><strong><a href="https://www.linkedin.com/pulse/naive-rag-baseline-youll-always-benchmark-against-ratko-nikoli%C4%87-i7h0e/">Article 2</a> <a href="https://ratkonikolic.substack.com/p/naive-rag-the-baseline-youll-always">&#8212; Naive RAG: the baseline you&#8217;ll always benchmark against</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/advanced-rag-what-you-actually-run">Article 3 &#8212; Advanced RAG: what you actually run in production</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/graphrag-and-friends-when-entities">Article 4 &#8212; GraphRAG and friends: when entities and relationships beat similarity</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/agentic-rag-when-retrieval-becomes">Article 5 &#8212; Agentic RAG: when retrieval becomes a decision, not a pipeline</a></strong></p></li><li><p><a href="https://ratkonikolic.substack.com/p/vector-vs-graph-vs-episodic-a-tour">Article 6 &#8212; Vector vs graph vs episodic: a tour of agent memory systems</a> </p></li><li><p>Article 7 &#8212; Context engineering: the discipline that replaces prompt engineering (<em>coming soon</em>)</p></li></ul><p><strong>External:</strong></p><ul><li><p>Packer et al. (October 2023), <em>MemGPT: Towards LLMs as Operating Systems</em>. <strong><a href="https://arxiv.org/abs/2310.08560">https://arxiv.org/abs/2310.08560</a></strong>. The OS-for-context idea behind Letta and self-editing memory.</p></li><li><p>Rasmussen et al. (January 2025), <em>Zep: A Temporal Knowledge Graph Architecture for Agent Memory</em>. <strong><a href="https://arxiv.org/abs/2501.13956">https://arxiv.org/abs/2501.13956</a></strong>. Memory as a temporal graph; the open-source engine is Graphiti.</p></li><li><p>Xu et al. (February 2025), <em>A-MEM: Agentic Memory for LLM Agents</em>. <strong><a href="https://arxiv.org/abs/2502.12110">https://arxiv.org/abs/2502.12110</a></strong>. Zettelkasten-style atomic memory that re-links as it grows.</p></li><li><p>Wu et al. (October 2024, ICLR 2025), <em>LongMemEval: Benchmarking Chat Assistants on Long-Term Interactive Memory</em>. <strong><a href="https://arxiv.org/abs/2410.10813">https://arxiv.org/abs/2410.10813</a></strong>. The benchmark to measure any of this against.</p></li><li><p>Wang (June 2026, preprint), <em>MemDelta: Controlled Baselines and Hidden Confounds in Agent Memory Evaluation</em>. <strong><a href="https://arxiv.org/abs/2606.29914">https://arxiv.org/abs/2606.29914</a></strong>. Why memory-vs-RAG comparisons flip when you change one component, and why write-path cost belongs in the report.</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.ratkonikolic.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 The Knowledge Layer! 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[Serbian Legal AI: a RAG architecture comparison]]></title><description><![CDATA[Five knowledge-layer architectures, one Serbian-law corpus, 300 graded answers.]]></description><link>https://www.ratkonikolic.com/p/serbian-legal-ai-a-rag-architecture</link><guid isPermaLink="false">https://www.ratkonikolic.com/p/serbian-legal-ai-a-rag-architecture</guid><dc:creator><![CDATA[Ratko Nikolić]]></dc:creator><pubDate>Tue, 11 Aug 2026 08:03:03 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f04b9587-48a0-4beb-9e3b-ecfbc04da16f_2560x1440.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Five knowledge-layer architectures, one Serbian-law corpus, 300 graded answers. The agent led every quality axis among the arms you could ship, the typed knowledge graph didn&#8217;t earn its rung, and the caveats are printed next to the numbers they belong to.</p><h3><strong>The question nobody benchmarks honestly</strong></h3><p>Every team building a retrieval system hits the same fork, and almost nobody has numbers to settle it. Do you run plain vector search? Add reranking and hybrid search? Build a knowledge graph? Wrap the whole thing in an agent that decides what to fetch? Or skip retrieval and stuff the documents into a long-context window, now that the windows are big enough to hold them?</p><p>The honest answer is &#8220;it depends,&#8221; and the thing it depends on is almost never the cleverness of the technique. It is the shape of your corpus and the shape of the questions your users actually ask. I wanted that answer with numbers attached, so, together with <strong><a href="https://www.linkedin.com/preload/?_bprMode=vanilla#">Sasa Mirkovic</a></strong>, I built a system where the <em>same</em> question is answered five different ways over <em>one</em> real corpus, and we measured what each approach buys and what it costs: accuracy, citation quality, hallucination rate, temporal correctness, latency, and dollars per query, side by side.</p><p>If you have been following this series, you have met these architectures one at a time: <strong><a href="https://www.ratkonikolic.com/p/naive-rag-the-baseline-youll-always">naive RAG in article 2</a></strong>, <strong><a href="https://www.ratkonikolic.com/p/advanced-rag-what-you-actually-run">the production-grade flat stack in article 3</a></strong>, <strong><a href="https://www.ratkonikolic.com/p/graphrag-and-friends-when-entities">GraphRAG in article 4</a></strong>, and <strong><a href="https://www.ratkonikolic.com/p/agentic-rag-when-retrieval-becomes">agentic retrieval in article 5</a></strong> (the fifth arm, long-context stuffing, is the one everyone argues about without needing an article). This is the post they were building toward, where the arguments stop and the measurement starts. The project is open source, linked at the bottom, and there is a screen-capture walkthrough of the running system further down.</p><p>The frame the whole thing rests on, and the through-line of everything I write: the knowledge layer, how an agent stores, updates, retrieves, and assembles what it knows, is the part that decides whether it is reliable in production. This is five architectures for that layer, measured on which parts actually pay.</p><h3><strong>One corpus, built deep</strong></h3><p>&#8220;One real corpus&#8221; should mean something, so here are the actual numbers. The corpus is Serbian statutory law from the official state legal-information system (PIS); the texts are public and excluded from copyright by statute, so there is no employer or client data anywhere near this. It holds <strong>33 seed statutes plus a six-act shared backbone</strong> (the Constitution and the codes everything else leans on), spanning <strong>ten everyday-law clusters</strong>: employment and contributions, family and inheritance, real estate and construction, consumer law, traffic, personal tax and freelancing, data and digital, company life, civil disputes and enforcement, and health and welfare. From those laws the pipeline then walks the delegation graph and fetches <strong>every reachable implementing bylaw</strong> (about 475 materialize with article structure; roughly 550 more fetch as HTML but carry no article structure and stay graph-only stubs) plus <strong>21 Constitutional-Court decisions</strong>. That is <strong>536 acts with full text</strong> and <strong>25,675 retrievable units</strong>: one chunk per article per version slice, including 3,257 dated version slices, around 910 extracted HTML-table annexes, and around 167 vision-OCR&#8217;d image annexes.</p><p>Every arm queries the same two stores:</p><ul><li><p>A <strong>vector plus full-text index</strong> (LanceDB, gemini-embedding-2 embeddings, BM25 for the lexical leg), so a query can land on the exact text in force on a given date.</p></li><li><p>A <strong>typed temporal knowledge graph</strong> in plain SQLite: eleven edge types, including article-to-article cross-references, term-aware definition links, the law-to-bylaw delegation edge, and a constitutional-validity edge that models a court strike as a first-class temporal death.</p></li></ul><p>Two invariants run through everything. First, no claim without provenance: every retrievable unit carries its law, article, version, and an ELI URL, and an answer with no citations is only legal when it abstains. Second, correctness is time-indexed: statutes amend, and a confidently cited repealed article is worse than no answer, so every unit carries validity dates.</p><p>Hold onto one set of numbers from that graph: the article-to-article cross-reference web has a <strong>mean out-degree of 0.57</strong>, <strong>81% of article nodes have no outgoing reference at all</strong>, and only <strong>264 of its edges (2.2%) cross from one law to another</strong>. That is most of the story of Finding 2.</p><h3><strong>The setup: a ladder, not a demo</strong></h3><p>The five arms are not five random systems. They are a ladder, where each rung adds exactly one class of capability over the one below it:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1uuQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63ff8eff-22b6-4d4f-827a-49d3cc1f79b1_721x400.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1uuQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63ff8eff-22b6-4d4f-827a-49d3cc1f79b1_721x400.png 424w, https://substackcdn.com/image/fetch/$s_!1uuQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63ff8eff-22b6-4d4f-827a-49d3cc1f79b1_721x400.png 848w, https://substackcdn.com/image/fetch/$s_!1uuQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63ff8eff-22b6-4d4f-827a-49d3cc1f79b1_721x400.png 1272w, https://substackcdn.com/image/fetch/$s_!1uuQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63ff8eff-22b6-4d4f-827a-49d3cc1f79b1_721x400.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1uuQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63ff8eff-22b6-4d4f-827a-49d3cc1f79b1_721x400.png" width="721" height="400" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/63ff8eff-22b6-4d4f-827a-49d3cc1f79b1_721x400.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:400,&quot;width&quot;:721,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!1uuQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63ff8eff-22b6-4d4f-827a-49d3cc1f79b1_721x400.png 424w, https://substackcdn.com/image/fetch/$s_!1uuQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63ff8eff-22b6-4d4f-827a-49d3cc1f79b1_721x400.png 848w, https://substackcdn.com/image/fetch/$s_!1uuQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63ff8eff-22b6-4d4f-827a-49d3cc1f79b1_721x400.png 1272w, https://substackcdn.com/image/fetch/$s_!1uuQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63ff8eff-22b6-4d4f-827a-49d3cc1f79b1_721x400.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></p><ul><li><p><strong>Context-Stuffing</strong> is the &#8220;why retrieve at all&#8221; arm, run as an <em>oracle</em>: it is handed every act the gold answer cites, a priori, and stuffs them whole into the window. That makes it a ceiling, not a deployable system (knowing which acts to read is precisely the problem retrieval exists to solve), so it is reported but kept out of the ranking. Think of it as an open-book exam where someone else has already found the right pages.</p></li><li><p><strong>Naive RAG</strong> is the floor: embed the query, take the top-8 vector hits, generate. Deliberately dumb.</p></li><li><p><strong>Advanced RAG</strong> is the production flat stack: hybrid search (dense vectors plus BM25, fused with Reciprocal Rank Fusion), a temporal filter that drops articles not in force on the asked-about date, a listwise LLM reranker, and a diversity cap so one chatty bylaw cannot crowd out the governing article.</p></li><li><p><strong>Advanced + Graph</strong> takes advanced&#8217;s exact output as its seeds, then adds typed-graph traversal on top: cross-reference and definition hops, a delegation-gated law-to-bylaw hop, and the constitutional-validity path. It is a strict superset of advanced, pinned by a unit test: turn the structure off and it reproduces advanced exactly, so any difference between the two is attributable to structure and nothing else.</p></li><li><p><strong>Agentic</strong> is a bounded ReAct loop (at most 10 steps) over seven typed tools that cover everything the other arms can reach: search, fetch an article, expand references, pull delegated bylaws, check constitutionality, read a law&#8217;s validity timeline.</p></li></ul><p>Everything else is held constant: same corpus, same chunking, same generator (Gemini 3.6 Flash), same prompts, temperature zero. Retrieval strategy is the only treatment. Grading is a cross-family judge, Claude Opus 5 grading Gemini&#8217;s answers against gold, precisely because the first objection to any LLM-graded benchmark is &#8220;the model graded itself.&#8221; A second-family juror grades nearly every item too (293 of the 295 gradable pairs), and the agreement between them is reported.</p><p>Three honesty notes before the table, because they bound everything in it. This is a <strong>single-seed</strong> run, so every number is a point estimate on 60 items. The judge-juror agreement came out at <strong>&#945; = 0.764, below the 0.80 bar</strong> I would want; a second juror pass made the disagreement diagnosable (81% of it sits on the correct-versus-partial boundary, so ordinal &#945; reads 0.842, and the ranking with every engineered-versus-naive p-value survives re-derivation from the second judge&#8217;s labels), which bounds the caveat without dissolving it: margins of two or three items are still not safe to read; margins of sixteen-plus are. And the generator is a floating model alias with a run-to-run flip rate of about 6% of items (quantified on its predecessor alias), so any difference of four items or fewer sits inside the drift envelope. I will point at these caveats exactly where they bite.</p><h3><strong>The scoreboard</strong></h3><p>Sixty situational, first-person client questions (&#8221;I&#8217;m buying a flat and the contract goes to the notary...&#8221;), three difficulty tiers, five arms, 300 graded answers:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RJ00!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bd6ed81-008e-4c92-b460-6795906ee930_744x190.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RJ00!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bd6ed81-008e-4c92-b460-6795906ee930_744x190.png 424w, https://substackcdn.com/image/fetch/$s_!RJ00!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bd6ed81-008e-4c92-b460-6795906ee930_744x190.png 848w, https://substackcdn.com/image/fetch/$s_!RJ00!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bd6ed81-008e-4c92-b460-6795906ee930_744x190.png 1272w, https://substackcdn.com/image/fetch/$s_!RJ00!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bd6ed81-008e-4c92-b460-6795906ee930_744x190.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RJ00!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bd6ed81-008e-4c92-b460-6795906ee930_744x190.png" width="744" height="190" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8bd6ed81-008e-4c92-b460-6795906ee930_744x190.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:190,&quot;width&quot;:744,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!RJ00!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bd6ed81-008e-4c92-b460-6795906ee930_744x190.png 424w, https://substackcdn.com/image/fetch/$s_!RJ00!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bd6ed81-008e-4c92-b460-6795906ee930_744x190.png 848w, https://substackcdn.com/image/fetch/$s_!RJ00!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bd6ed81-008e-4c92-b460-6795906ee930_744x190.png 1272w, https://substackcdn.com/image/fetch/$s_!RJ00!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bd6ed81-008e-4c92-b460-6795906ee930_744x190.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p><p>Accuracy counts only answers the judge marked fully correct; correctness gives half credit for partially correct ones. Provenance F1 is deterministic citation precision and recall against the gold articles, no judge involved. The intervals are Wilson 95% on the accuracy proportion, item-sampling only. Every engineered arm&#8217;s interval overlaps every other&#8217;s; only naive separates cleanly.</p><p>Deployable ranking: <strong>Agentic 0.87 &gt; Advanced + Graph 0.77 &#8776; Advanced 0.73 &gt; Naive 0.48.</strong> Five things in that table are worth stopping on.</p><h3><strong>Finding 1: the retrieval ladder pays, and this one has receipts</strong></h3><p>Every engineered arm beats the naive floor decisively: paired exact McNemar p = 0.0003 or better on all three comparisons, with naive losing 16, 18, and 24 of the discordant items respectively. Naive&#8217;s confidence interval is the only one that does not overlap the rest of the board.</p><p>The cheapest step is still the biggest bargain: naive to advanced is +0.25 accuracy for about a cent and a half more per query. Hybrid search, a reranker, a temporal filter, and a diversity cap. No new model, no graph, no agent. If your RAG system is underperforming and you have not done these four things, that is almost certainly your problem, not the model. This is the least glamorous finding, and given the caveats above it is also the only one with margins wide enough that no plausible amount of judge disagreement or generator drift can touch it.</p><h3><strong>Finding 2: the typed graph added nothing, and the scope of that sentence is the finding</strong></h3><p>In the GraphRAG article I said a graph earns its keep when relationships are first-class in the questions your users ask. The corollary under test here is whether the corpus has the connection density to traverse. Here is what happened when I measured mine: Advanced + Graph came out at 0.77 against advanced&#8217;s 0.73, which sounds like a win until you run the paired test. Two items in one direction, four in the other, p = 0.69. In the previous campaign the graph arm sat nominally <em>below</em> advanced; scoring corrections landed in between, so the two campaigns are not strict replicates, but an ordering that will not stay put is exactly what a null effect looks like. <strong>This graph layer, on this corpus, neither beats nor loses to strong flat retrieval.</strong></p><p>The instrumentation is what makes that sentence worth publishing. The superset design rules out &#8220;you built the graph arm wrong&#8221;: structure-off provably reproduces advanced, so the null delta is attributable to the structure itself. And the decomposition locates <em>why</em> it is null, stage by stage:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-Vs7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbb5f63f-9f59-4169-bb37-31221e78b682_744x113.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-Vs7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbb5f63f-9f59-4169-bb37-31221e78b682_744x113.png 424w, https://substackcdn.com/image/fetch/$s_!-Vs7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbb5f63f-9f59-4169-bb37-31221e78b682_744x113.png 848w, https://substackcdn.com/image/fetch/$s_!-Vs7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbb5f63f-9f59-4169-bb37-31221e78b682_744x113.png 1272w, https://substackcdn.com/image/fetch/$s_!-Vs7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbb5f63f-9f59-4169-bb37-31221e78b682_744x113.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-Vs7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbb5f63f-9f59-4169-bb37-31221e78b682_744x113.png" width="744" height="113" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cbb5f63f-9f59-4169-bb37-31221e78b682_744x113.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:113,&quot;width&quot;:744,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!-Vs7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbb5f63f-9f59-4169-bb37-31221e78b682_744x113.png 424w, https://substackcdn.com/image/fetch/$s_!-Vs7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbb5f63f-9f59-4169-bb37-31221e78b682_744x113.png 848w, https://substackcdn.com/image/fetch/$s_!-Vs7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbb5f63f-9f59-4169-bb37-31221e78b682_744x113.png 1272w, https://substackcdn.com/image/fetch/$s_!-Vs7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbb5f63f-9f59-4169-bb37-31221e78b682_744x113.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p><p>At the construction stage, the cross-reference web barely exists. Serbian statutes rarely cite each other by article number: the code of obligations has roughly 1,100 articles and only 12 of them carry a numbered cross-reference at all, none pointing outside the code. Corpus-wide, 81% of article nodes are isolated and 2.2% of reference edges cross laws. You cannot manufacture those edges without fabricating law. At the retrieval stage, the one dense structure the corpus <em>does</em> have, the law-to-bylaw delegation spine, hits a different wall: a single law can delegate to as many as 79 materialized bylaws, and the graph hop picks which ones to search in arbitrary stored order rather than by relevance. Ranking that fan-out by the query would fix it, but ranking by the query <em>is retrieval</em>, the thing the flat backbone already does over the whole corpus. That is the sharpest form of the result: on this corpus, the typed edges add no retrieval power that good flat retrieval doesn&#8217;t already have.</p><p>Two scope notes, both load-bearing. This is a claim about <em>this</em> graph implementation on <em>this</em> corpus, not about graph structure in general; the fan-out problem is a fixable engineering property, and fixing it is deliberately left to a held-out test so the negative result stays clean. And on the three constitutional-validity questions, where the validity edges genuinely exist, the graph arm was the only fixed-pipeline arm to go 3 for 3 (the agentic loop managed it too). Three questions proves nothing, but it points where structure&#8217;s remaining home turf is: validity- and definition-aware traversal, not cross-reference multi-hop.</p><p>The durable lesson survives all the caveats: <strong>whether a graph helps is a property of your corpus topology, not of the technique.</strong> Count your cross-references before you build one.</p><h3><strong>Finding 3: the agent is the headline, for the quality profile rather than the accuracy lead</strong></h3><p>Agentic tops the accuracy column at 0.87, a 13-point lead over advanced. I am deliberately not headlining that number, because it does not survive multiple-comparison correction: p = 0.0386 uncorrected, against a Bonferroni threshold of 0.0083 across the six pairwise tests, and against the graph arm it is nowhere near significance. On accuracy, the honest verdict is &#8220;promising, unproven at this sample size.&#8221;</p><p>What the data does support is the quality profile, and it is consistent across every axis I measured. Best deployable correctness (0.93). Best deployable provenance F1 (0.61). Misgrounding and hallucination rates as low as any arm&#8217;s on the board, the oracle included (0.07 and 0.07, versus naive&#8217;s 0.22 and 0.20). Zero over-abstentions: it never refused an answerable question, while naive refused seven. It is the only deployable arm that holds up on the hard tier (16 of 20, level with the oracle, though the oracle&#8217;s sixteenth hard item rests on a re-run cell the report discloses). And the price of all that is about 2.3&#215; advanced&#8217;s cost ($0.068 vs $0.030 per query) and under twice the median latency, 26 seconds against 15.</p><p>That is a much better trade than the agentic folklore suggests. Retrieval-as-a-decision is a trustworthiness purchase: for a legal, medical, or financial assistant where the expensive failure is a confident wrong answer with a plausible citation, the safety delta is worth double the spend. For an internal FAQ bot it is not. That is the actual decision, and now it has a price tag.</p><h3><strong>Finding 4: the ceiling closed, and what that actually means</strong></h3><p>The oracle, handed every act the gold answer cites, scores 0.92. Two readings of that number are wrong and one is useful.</p><p>Wrong reading one: &#8220;long context killed RAG.&#8221; The oracle&#8217;s input assumption <em>is</em> the problem statement: someone has to know which acts the answer rests on, and that act selection is what retrieval does. The previous campaign measured its worth directly, as a disclosed same-day correction: an oracle stuffing only the single primary act scored 0.42, and handing over the full gold act set moved it to 0.93. Knowing <em>which documents to read</em> was worth more than any retrieval-stage refinement measured in this project. Wrong reading two: &#8220;so use the oracle&#8217;s setup anyway.&#8221; It costs $0.197 per query, 12.8&#215; naive and 2.9&#215; agentic, and it is temporally blind by construction: it stuffs current consolidated text, so on questions where the in-force answer is a superseded version it structurally cannot cite the right law.</p><p>The useful reading is narrower. The gap between the best deployable arm and the ceiling has closed to within what this benchmark can measure: agentic versus oracle is three items against six, p = 0.51, and that is a statement about statistical power, not proof of parity. Still, a bounded agent over typed tools, paying a third of the oracle&#8217;s price and keeping temporal awareness, is at least keeping pace with perfect act selection at this sample size. If that holds up at more seeds, it is the best argument I know for spending your budget on the knowledge layer rather than on a bigger window.</p><h3><strong>Finding 5: temporal correctness turned out to be a property of the knowledge base, not the model</strong></h3><p>The most transferable result is also the one I have to report most carefully. On questions dated into the past, where the correct answer is a superseded version of an article, what decides the outcome is whether the arm&#8217;s <em>retrieval layer</em> can reach and prefer the right version slice. Naive and the oracle index only current text, so where the in-force text at the asked date is a superseded slice, they cannot cite it, structurally. The three arms with a validity filter cannot cite an out-of-force one. Neither outcome could have come out otherwise, which is why I am calling this a <strong>mechanism demonstration, not a measurement</strong>: my dated tier held three items, and after two of them were passed by all five arms, exactly one item did the discriminating.</p><p>Full disclosure, because it belongs next to this number: that one discriminating item was itself corrected after arm behaviour had been analysed, an exception to the benchmark&#8217;s blind-authoring rule that the report states rather than hides, and it is a second reason no temporal effect is claimed here. There is also a methodological trap inside this that anyone building a temporal benchmark will hit: a per-citation validity metric ends up measuring the arm&#8217;s retrieval configuration, not its temporal reasoning, and an arm can pass it by citing the wrong law entirely. In my view this methodological finding will outlive the scoreboard. If your corpus has versions, effective dates, or amendment history, temporal correctness has to be built into storage and retrieval as validity intervals and an as-of filter. No prompt and no bigger model fixes it downstream, and measuring it takes a tier of materially amended articles I have not built yet.</p><h3><strong>Watch it work</strong></h3><p>Numbers are one kind of evidence; the system showing its work is another. I recorded a short screen-capture walkthrough of the running app, and it is embedded here on the canonical version of this post:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;6ad742f6-c431-4987-b505-103977fdf670&quot;,&quot;duration&quot;:null}"></div><p>What it walks through, in order: a real question asked with an as-of date and the arm selector; the answer with citation chips and validity badges (green &#8220;in force since&#8221;, red &#8220;ceased to be valid&#8221;); the Runs drill-down for that exact answer, with per-stage latency, cost, and, for the agentic arm, the full tool trace of what the agent searched, fetched, and expanded before answering; the Benchmark tab, where the whole five-arm matrix in this post can be re-run with any capability toggled off; and the Corpus topology panel, the sparsity numbers behind Finding 2. Every number on those screens comes from the same telemetry rows the published report is computed from. There is no demo mode.</p><h3><strong>What this actually costs to run</strong></h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hRrM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7147e3b-1d98-4eaf-8e83-06c74bc18555_744x244.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hRrM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7147e3b-1d98-4eaf-8e83-06c74bc18555_744x244.png 424w, https://substackcdn.com/image/fetch/$s_!hRrM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7147e3b-1d98-4eaf-8e83-06c74bc18555_744x244.png 848w, https://substackcdn.com/image/fetch/$s_!hRrM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7147e3b-1d98-4eaf-8e83-06c74bc18555_744x244.png 1272w, https://substackcdn.com/image/fetch/$s_!hRrM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7147e3b-1d98-4eaf-8e83-06c74bc18555_744x244.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hRrM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7147e3b-1d98-4eaf-8e83-06c74bc18555_744x244.png" width="744" height="244" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b7147e3b-1d98-4eaf-8e83-06c74bc18555_744x244.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:244,&quot;width&quot;:744,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!hRrM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7147e3b-1d98-4eaf-8e83-06c74bc18555_744x244.png 424w, https://substackcdn.com/image/fetch/$s_!hRrM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7147e3b-1d98-4eaf-8e83-06c74bc18555_744x244.png 848w, https://substackcdn.com/image/fetch/$s_!hRrM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7147e3b-1d98-4eaf-8e83-06c74bc18555_744x244.png 1272w, https://substackcdn.com/image/fetch/$s_!hRrM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7147e3b-1d98-4eaf-8e83-06c74bc18555_744x244.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></p><p>Generating the full 300-answer campaign cost $20.91 in API calls across the five arms; the cross-family grading runs on top of that.</p><h3><strong>What this is, and what it isn&#8217;t</strong></h3><p>This is a build-in-public launch of a real open-source project, built in cooperation with <strong><a href="https://www.linkedin.com/preload/?_bprMode=vanilla#">Sasa Mirkovic</a></strong> (<strong><a href="https://github.com/SasaMirkovic">https://github.com/SasaMirkovic</a></strong>), who co-designed the ingestion pipeline and the knowledge base every arm retrieves over and advised on the retrieval architecture and the evaluation design. The evidential position is stated rather than implied. The three caveats from the top (single seed, below-threshold judge agreement, generator drift) ride every number above; the 16-to-24-item margins behind Finding 1 survive them, the small margins do not. The gold answers are source-authored and mechanically checked for grounding in the statute text they cite, but not yet reviewed by practising lawyers. No external system (LightRAG, Microsoft GraphRAG) has been run on this corpus yet, so the results say what each architecture buys relative to the others here, not how any of them compares to a published system. The hardened tier, with three-plus seeds, expert-validated gold, and external baselines, is the next phase, and it feeds the benchmark paper this project exists to support. The full report, including the sections titled &#8220;what to distrust&#8221; and &#8220;what this evaluation does not establish,&#8221; ships in the repo.</p><p>For an enterprise the translation is direct. Swap Serbian statutes for your regulated, amendment-heavy corpus (policies, contracts, compliance manuals, anything with versions and effective dates) and the decision rules transfer as-is: do the boring retrieval engineering first, count your cross-references before you build a graph, budget the agentic loop for the queries where being confidently wrong actually costs you, and put temporal validity in the knowledge base, because nothing downstream can recover it.</p><h3><strong>Run it yourself</strong></h3><p>The repo is public at <strong><a href="https://github.com/RatkoNikolic/srb-legal-rag">https://github.com/RatkoNikolic/srb-legal-rag</a></strong> and small (~6 MB): the five instrumented arms, the eval harness, the 60-question golden set (CC BY 4.0, reusable in published work with attribution), 224 tests, the web UI, and six design docs that explain every decision with the literature behind it. The code is Apache-2.0. Setup instructions are in the README, and building your own knowledge base is three commands: a rate-limited crawl of the official source (about 7 minutes), a local graph build (seconds), and embedding (about $1.50 of API calls). Re-running the full benchmark needs a Gemini key plus an Anthropic key for the cross-family judge; generation alone ran me about $21, with grading on top.</p><p>One thing to know before you build, because it is unusual and deliberate: <strong>the repository ships the machinery, not the corpus.</strong> No statute text is distributed, and your rebuilt knowledge base will not byte-match the one these numbers were measured on. That is a measured fact, not a guess: a fresh rebuild produced 24,652 units against the published 25,675, with hundreds of article chunks existing only on one side. Serbian law amends continuously (the source moves under you), the annex layer needs its own paid extraction step whose vision-OCR portion is model output that varies even on identical inputs, and borderline documents flip between parseable and not. Comparing arms <em>within</em> your own build stays valid; comparing your numbers to mine does not. <strong>The exact knowledge base behind the published campaign, the full chunk set, the typed graph, and the vector index, is available on request</strong> (email in the repo README): it is too large to ship in the repo, and given the probabilistic construction and the drift in the source materials, handing over the measured artifact is the only honest way to let someone run the same comparison these numbers came from.</p><p><em><strong>I take on a small number of advisory engagements each year for teams building retrieval systems that have to hold up in production. Reach out if that&#8217;s you.</strong></em></p><h3><strong>What to read next</strong></h3><p><strong>This series:</strong></p><ul><li><p><strong><a href="https://ratkonikolic.substack.com/p/your-agents-problem-isnt-the-model">Article 1 &#8212; Your agent&#8217;s problem isn&#8217;t the model, it&#8217;s the knowledge layer</a></strong></p></li><li><p><strong><a href="https://www.linkedin.com/pulse/naive-rag-baseline-youll-always-benchmark-against-ratko-nikoli%C4%87-i7h0e/">Article 2</a> <a href="https://ratkonikolic.substack.com/p/naive-rag-the-baseline-youll-always">&#8212; Naive RAG: the baseline you&#8217;ll always benchmark against</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/advanced-rag-what-you-actually-run">Article 3 &#8212; Advanced RAG: what you actually run in production</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/graphrag-and-friends-when-entities">Article 4 &#8212; GraphRAG and friends: when entities and relationships beat similarity</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/agentic-rag-when-retrieval-becomes">Article 5 &#8212; Agentic RAG: when retrieval becomes a decision, not a pipeline</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/vector-vs-graph-vs-episodic-a-tour">Article 6 &#8212; Vector vs graph vs episodic: a tour of agent memory systems</a> </strong></p></li><li><p>Article 7 &#8212; Context engineering: the discipline that replaces prompt engineering (<em>coming soon</em>)</p></li></ul><p><strong>External:</strong></p><ul><li><p><em>Xiang et al. (2025), When to use Graphs in RAG: A Comprehensive Analysis for Graph Retrieval-Augmented Generation. [<strong><a href="https://arxiv.org/abs/2506.05690](https://arxiv.org/abs/2506.05690)">https://arxiv.org/abs/2506.05690](https://arxiv.org/abs/2506.05690)</a></strong>. Root-causes graph underperformance at the construction stage, the same decomposition Finding 2 runs.</em></p></li><li><p><em>Xiao et al. (2025), GraphRAG-Bench: Challenging Domain-Specific Reasoning for Evaluating Graph Retrieval-Augmented Generation. [<strong><a href="https://arxiv.org/abs/2506.02404](https://arxiv.org/abs/2506.02404)">https://arxiv.org/abs/2506.02404](https://arxiv.org/abs/2506.02404)</a></strong>. The construction, retrieval, generation stage split and the structural stats (degree, isolated share) this benchmark reports.</em></p></li><li><p><em>Han et al. (2025), RAG vs. GraphRAG: A Systematic Evaluation and Key Insights. [<strong><a href="https://arxiv.org/abs/2502.11371](https://arxiv.org/abs/2502.11371)">https://arxiv.org/abs/2502.11371](https://arxiv.org/abs/2502.11371)</a></strong>. The flat-versus-graph comparison precedent: measured evidence that graph RAG does not dominate flat RAG.</em></p></li><li><p><em>Fan et al. (2026), Can LLMs Time Travel? Enhancing Temporal Consistency in Legal Agentic Search through Reinforcement Learning. [<strong><a href="https://arxiv.org/abs/2605.25920](https://arxiv.org/abs/2605.25920)">https://arxiv.org/abs/2605.25920](https://arxiv.org/abs/2605.25920)</a></strong>. Point-in-time legal retrieval as a first-class problem, the axis this benchmark could only demonstrate, not measure.</em></p></li><li><p><em>Yang et al. (EMNLP 2018), HotpotQA: A Dataset for Diverse, Explainable Multi-hop Question Answering. [<strong><a href="https://arxiv.org/abs/1809.09600](https://arxiv.org/abs/1809.09600)">https://arxiv.org/abs/1809.09600](https://arxiv.org/abs/1809.09600)</a></strong>. The origin of gold-context-as-ceiling: its gold-supporting-fact setting is &#8220;an upper bound on performance&#8221;, which is exactly how the oracle arm is used here.</em></p></li><li><p><em>srb-legal-rag: [<strong><a href="https://github.com/RatkoNikolic/srb-legal-rag](https://github.com/RatkoNikolic/srb-legal-rag)">https://github.com/RatkoNikolic/srb-legal-rag](https://github.com/RatkoNikolic/srb-legal-rag)</a></strong>. The code, the question sets, and the full campaign report behind every number in this post.</em></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Agentic RAG: when retrieval becomes a decision, not a pipeline]]></title><description><![CDATA[Naive and advanced RAG retrieve the same way every time. Agentic RAG lets the model decide what to look up, whether the results are good enough, and when to stop. You pay for that judgement in latency]]></description><link>https://www.ratkonikolic.com/p/agentic-rag-when-retrieval-becomes</link><guid isPermaLink="false">https://www.ratkonikolic.com/p/agentic-rag-when-retrieval-becomes</guid><dc:creator><![CDATA[Ratko Nikolić]]></dc:creator><pubDate>Tue, 28 Jul 2026 08:01:59 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/123c1f87-98b2-4824-9eb9-615243c86fb4_1424x752.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3><strong>The problem</strong></h3><p>A team ships a support assistant over a good advanced-RAG stack: hybrid search, a reranker, metadata filters, the works. It answers single-fact questions well. Then a user asks: <em>&#8220;I&#8217;m moving from the Berlin office to the Madrid one mid-contract: what changes for my health cover, my notice period, and my equity vesting?&#8221;</em> The pipeline does what it always does: embeds the question, pulls the top chunks, stuffs them in. It comes back with a confident paragraph about health cover and silently drops the other two. Three questions went in; one came out, and nobody flagged the gap.</p><p>The pipeline isn&#8217;t broken. It did exactly what a pipeline does: one retrieval, one shot, no second look. The failure is that nothing in the system ever <em>decided</em> this question needed three separate lookups, or noticed that the retrieved context only covered one of them. That deciding is the thing agentic RAG adds. The knowledge layer (the part of an agent system that decides reliability in production, and an engineering discipline in its own right) stops being a fixed conveyor belt and becomes a loop the model drives: retrieve, look at what came back, decide whether it&#8217;s enough, and go again if it isn&#8217;t.</p><h3><strong>How agentic RAG works</strong></h3><p>The spine is one idea: make retrieval a tool the model calls inside a reasoning loop, instead of a step that always runs once before the model sees anything.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gjx8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3e9dfaf-567a-4e9a-9008-b6bc8cdcde0a_744x371.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gjx8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3e9dfaf-567a-4e9a-9008-b6bc8cdcde0a_744x371.png 424w, https://substackcdn.com/image/fetch/$s_!gjx8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3e9dfaf-567a-4e9a-9008-b6bc8cdcde0a_744x371.png 848w, https://substackcdn.com/image/fetch/$s_!gjx8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3e9dfaf-567a-4e9a-9008-b6bc8cdcde0a_744x371.png 1272w, https://substackcdn.com/image/fetch/$s_!gjx8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3e9dfaf-567a-4e9a-9008-b6bc8cdcde0a_744x371.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gjx8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3e9dfaf-567a-4e9a-9008-b6bc8cdcde0a_744x371.png" width="744" height="371" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c3e9dfaf-567a-4e9a-9008-b6bc8cdcde0a_744x371.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:371,&quot;width&quot;:744,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!gjx8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3e9dfaf-567a-4e9a-9008-b6bc8cdcde0a_744x371.png 424w, https://substackcdn.com/image/fetch/$s_!gjx8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3e9dfaf-567a-4e9a-9008-b6bc8cdcde0a_744x371.png 848w, https://substackcdn.com/image/fetch/$s_!gjx8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3e9dfaf-567a-4e9a-9008-b6bc8cdcde0a_744x371.png 1272w, https://substackcdn.com/image/fetch/$s_!gjx8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3e9dfaf-567a-4e9a-9008-b6bc8cdcde0a_744x371.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><p></p><p>The pattern traces back to <strong>ReAct</strong> (Shunyu Yao and co-authors, <em>ReAct: Synergizing Reasoning and Acting in Language Models</em>, [arXiv 2210.03629](<strong><a href="https://arxiv.org/abs/2210.03629">https://arxiv.org/abs/2210.03629</a></strong>), ICLR 2023), which interleaved reasoning steps with tool actions so a model could think, act, observe the result, and think again. Retrieval is just one of those actions. Two later papers sharpen it for RAG specifically. <strong>Self-RAG</strong> (Akari Asai and co-authors, [arXiv 2310.11511](<strong><a href="https://arxiv.org/abs/2310.11511">https://arxiv.org/abs/2310.11511</a></strong>), ICLR 2024) trains the model to emit &#8220;reflection tokens&#8221; that decide <em>whether</em> to retrieve at all and then critique whether the retrieved passage actually supports the answer: retrieval on demand, with a built-in quality check. <strong>Adaptive-RAG</strong> (Soyeong Jeong and co-authors, [arXiv 2403.14403](<strong><a href="https://arxiv.org/abs/2403.14403">https://arxiv.org/abs/2403.14403</a></strong>), NAACL 2024) adds a complexity classifier up front: trivial questions get answered with no retrieval, single-hop questions get one pass, and only genuinely multi-hop questions pay for the full iterative loop. The recurring move in all three is the same: spend retrieval effort in proportion to how hard the question actually is.</p><p>In production, this is usually built as a small state machine rather than a free-for-all. <strong>LangGraph</strong>, the graph-based agent framework from the LangChain team (1.0 in October 2025, now well into its 1.x line), is the de-facto way teams wire these loops as explicit nodes and edges with a retry budget, precisely so the &#8220;loop until satisfied&#8221; can&#8217;t run away. The broader industry has been moving the same direction: the <strong>Model Context Protocol</strong> (open-sourced by Anthropic in November 2024, adopted by OpenAI and Google through 2025, and donated to the Linux Foundation&#8217;s Agentic AI Foundation in December 2025) standardised how an agent reaches tools and data sources, which is exactly the plumbing an agentic retriever needs to query a vector store, a graph, a SQL database, and a third-party API through one interface.</p><h3><strong>In practice</strong></h3><p>Take the relocation question from the top. A static pipeline runs one retrieval. An agentic one does something closer to this:</p><pre><code><code>User: moving Berlin &#8594; Madrid mid-contract. Health cover, notice period, equity vesting?

Agent (plan):    three sub-questions, different policy areas. Decompose.
  &#8594; retrieve("health insurance transfer between EU offices")     &#10003; found
  &#8594; retrieve("notice period change on internal relocation")      &#10003; found
  &#8594; retrieve("equity vesting on country transfer")               &#10007; weak match
Agent (judge):   vesting result is thin. Re-query with a narrower term.
  &#8594; retrieve("RSU vesting schedule employee relocation")         &#10003; found
Agent (judge):   three areas covered. Compose.</code></code></pre><p>Four retrievals, two planning steps, one re-query when a result came back weak, versus the single shot a pipeline would have taken. That&#8217;s the whole trade in one trace. The agent caught the thin vesting result and went back for it, which is the failure the static pipeline shipped silently. It also cost roughly three-to-five times the model calls of a one-shot answer, because every plan, judge, and re-query is another round-trip to the model. Agentic RAG buys reliability on hard questions and pays for it in latency and tokens. That sentence is the whole article, and the discipline is knowing when the trade is worth it.</p><h3><strong>Where it shines</strong></h3><p>Two situations make the extra cost pay for itself.</p><p>The first is <strong>multi-hop and multi-part questions</strong>: anything that needs more than one fact, retrieved separately and combined. The relocation question is one; <em>&#8220;which of our vendors fail the new compliance rule, and what&#8217;s the remediation for each&#8221;</em> is another. A single retrieval can&#8217;t serve these because the sub-answers live in different documents and a one-shot top-*k* will over-weight whichever sub-question embeds strongest. The agent&#8217;s ability to decompose, retrieve per part, and notice a gap is the entire value.</p><p>The second is <strong>mixed-source corpora where the right source depends on the question</strong>. When some answers live in unstructured docs, some in a SQL table, some behind an API, and some in a knowledge graph, a static pipeline that always hits the vector store is wrong most of the time. An agent can route: read the question, pick the tool, and fall back to another source when the first comes up empty. This is common in enterprise settings where &#8220;the knowledge&#8221; is genuinely spread across systems, and it&#8217;s where retrieval-as-a-decision earns its keep over retrieval-as-a-step. The pattern has gone product-shaped, too: Microsoft&#8217;s <strong>Azure AI Search agentic retrieval</strong> (public preview in 2025; the core moved to GA in the April 2026 API, with the LLM query-planning step itself still in preview) ships exactly this loop as a managed service, with an LLM planning subqueries, running them in parallel, and merging the results. Microsoft has since wrapped the same engine into <strong>Foundry IQ</strong> (announced November 2025, in preview), pitched, in Microsoft&#8217;s own words, as a managed &#8220;knowledge layer&#8221; for agents.</p><h3><strong>Where it breaks</strong></h3><p>Be honest about the failure modes, because they&#8217;re nastier than a pipeline&#8217;s.</p><ul><li><p><strong>The cost and latency multiply.</strong> Three-to-five times the model calls is the rough rule, and it lands on every hard question, not just occasionally. A question that took 2 seconds and one model call now takes 6&#8211;10 seconds and five, and the bill scales with it. On a high-traffic assistant that delta is not a rounding error: it&#8217;s the difference between a viable unit economic and an unviable one.</p></li><li><p><strong>Loops that don&#8217;t terminate.</strong> The signature agentic failure: the agent judges the results insufficient, re-queries, judges again, and never converges, burning budget and latency on a question it&#8217;s never going to answer. Every production loop needs a hard iteration cap and a &#8220;give up gracefully&#8221; branch, or it will eventually find the input that spins forever.</p></li><li><p><strong>Confident wrong routing.</strong> When the agent decides <em>not</em> to retrieve (Self-RAG&#8217;s whole premise is that sometimes it shouldn&#8217;t), it can decide wrong and answer a factual question from parametric memory, hallucinating where a retrieval would have saved it. The decision to skip retrieval is itself a new failure surface that a static pipeline simply doesn&#8217;t have.</p></li><li><p><strong>Harder to debug.</strong> A pipeline has one retrieval trace. An agent has a branching tree of plans, tool calls, and judgements, and when the answer is wrong you have to reconstruct <em>which decision</em> went wrong. The observability burden is real, and teams underestimate it.</p></li></ul><h3><strong>When not to use it</strong></h3><p>If your questions are overwhelmingly single-fact lookups over one corpus (the FAQ-shaped workload from the naive-RAG article), agentic RAG is pure overhead. You pay 3&#8211;5&#215; the cost and the added latency to wrap a decision around a question that only ever needed one retrieval, and a good advanced-RAG stack will beat it on both cost and speed. The loop earns its place only when a meaningful share of real questions are multi-hop, ambiguous, or span sources. Reach for it when you can point to the specific questions a pipeline keeps getting wrong; don&#8217;t reach for it because &#8220;agentic&#8221; is the word of the season.</p><p><strong>Cost / latency / setup effort:</strong></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VM5G!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5453b9f2-08c1-4191-a10d-f702b5c98632_744x98.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VM5G!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5453b9f2-08c1-4191-a10d-f702b5c98632_744x98.png 424w, https://substackcdn.com/image/fetch/$s_!VM5G!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5453b9f2-08c1-4191-a10d-f702b5c98632_744x98.png 848w, https://substackcdn.com/image/fetch/$s_!VM5G!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5453b9f2-08c1-4191-a10d-f702b5c98632_744x98.png 1272w, https://substackcdn.com/image/fetch/$s_!VM5G!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5453b9f2-08c1-4191-a10d-f702b5c98632_744x98.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VM5G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5453b9f2-08c1-4191-a10d-f702b5c98632_744x98.png" width="744" height="98" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5453b9f2-08c1-4191-a10d-f702b5c98632_744x98.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:98,&quot;width&quot;:744,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!VM5G!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5453b9f2-08c1-4191-a10d-f702b5c98632_744x98.png 424w, https://substackcdn.com/image/fetch/$s_!VM5G!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5453b9f2-08c1-4191-a10d-f702b5c98632_744x98.png 848w, https://substackcdn.com/image/fetch/$s_!VM5G!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5453b9f2-08c1-4191-a10d-f702b5c98632_744x98.png 1272w, https://substackcdn.com/image/fetch/$s_!VM5G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5453b9f2-08c1-4191-a10d-f702b5c98632_744x98.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p><h3><strong>Combinations and hybrids</strong></h3><p>Agentic RAG isn&#8217;t a replacement for the earlier techniques: it&#8217;s a controller that sits on top of them. The tools the agent calls <em>are</em> naive RAG, advanced RAG, and GraphRAG; the agent just decides which one to use and whether to go again. The most effective real systems pair an agentic loop with a complexity gate in the Adaptive-RAG spirit: cheap questions bypass the loop entirely and get a one-shot answer, and only the hard ones pay for the full plan-retrieve-judge cycle. That gate is what keeps the cost honest: without it, you pay the 3&#8211;5&#215; tax on every trivial lookup. Pair it the other way and agentic RAG also feeds the next article: an agent that decides <em>what</em> to remember across turns is the bridge from retrieval into memory.</p><h3><strong>Production checklist</strong></h3><ul><li><p><strong>Cap the loop.</strong> A hard maximum on retrieval iterations plus a graceful &#8220;I couldn&#8217;t find enough&#8221; branch. Non-negotiable, or you will ship the infinite loop.</p></li><li><p><strong>Budget per query.</strong> Track and cap model calls and tokens per answer; alert when a single question blows past the expected envelope.</p></li><li><p><strong>Log the full decision tree</strong> (every plan, tool call, observation, and judgement), not just the final retrieval. This is the only way to debug a wrong answer in a branching system.</p></li><li><p><strong>Instrument the retrieve/skip decision</strong> separately; measure how often the agent chooses not to retrieve and how often that choice was wrong.</p></li><li><p><strong>Gate by complexity</strong> so trivial questions never enter the loop. Measure what fraction of traffic actually needs it.</p></li><li><p><strong>Watch p99 latency and tail cost</strong>, not the averages; the agentic tail is where both the budget and the user patience go.</p></li><li><p><strong>Evaluate end-to-end, not per-retrieval</strong>: a loop can make three good retrievals and still compose a bad answer, so score the final result against a golden set.</p></li></ul><h3><strong>The take</strong></h3><p>Agentic RAG turns retrieval from a fixed step into a decision the model makes, and that&#8217;s genuinely more powerful on the questions that need it: multi-hop, ambiguous, multi-source. But power you pay for on every query is a liability, not a feature. Wrap the loop in a complexity gate, cap it hard, instrument every decision, and spend the 3&#8211;5&#215; only where the reliability gain is real. The teams that win with agentic RAG are the ones who know exactly which questions justify the loop, and route everything else around it.</p><p><em><strong>I take on a small number of advisory engagements each year for teams hitting exactly these problems. Reach out if that&#8217;s you.</strong></em></p><h3><strong>What to read next</strong></h3><p><strong>This series</strong>:</p><ul><li><p><strong><a href="https://ratkonikolic.substack.com/p/your-agents-problem-isnt-the-model">Article 1 &#8212; Your agent&#8217;s problem isn&#8217;t the model, it&#8217;s the knowledge layer</a></strong></p></li><li><p><strong><a href="https://www.linkedin.com/pulse/naive-rag-baseline-youll-always-benchmark-against-ratko-nikoli%C4%87-i7h0e/">Article 2</a> <a href="https://ratkonikolic.substack.com/p/naive-rag-the-baseline-youll-always">&#8212; Naive RAG: the baseline you&#8217;ll always benchmark against</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/advanced-rag-what-you-actually-run">Article 3 &#8212; Advanced RAG: what you actually run in production</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/graphrag-and-friends-when-entities">Article 4 &#8212; GraphRAG and friends: when entities and relationships beat similarity</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/agentic-rag-when-retrieval-becomes">Article 5 &#8212; Agentic RAG: when retrieval becomes a decision, not a pipeline</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/vector-vs-graph-vs-episodic-a-tour">Article 6 &#8212; Vector vs graph vs episodic: a tour of agent memory systems</a> </strong></p></li><li><p>Article 7 &#8212; Context engineering: the discipline that replaces prompt engineering (<em>coming soon</em>)</p></li></ul><p><strong>External:</strong></p><ul><li><p>Yao et al. (ICLR 2023), <em>ReAct: Synergizing Reasoning and Acting in Language Models</em>. <strong><a href="https://arxiv.org/abs/2210.03629">https://arxiv.org/abs/2210.03629</a></strong>. The reasoning-plus-acting loop everything here is built on.</p></li><li><p>Asai et al. (ICLR 2024), <em>Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection</em>. <strong><a href="https://arxiv.org/abs/2310.11511">https://arxiv.org/abs/2310.11511</a></strong>. Retrieve-on-demand with a built-in quality check.</p></li><li><p>Jeong et al. (NAACL 2024), <em>Adaptive-RAG: Learning to Adapt Retrieval-Augmented Large Language Models through Question Complexity</em>. <strong><a href="https://arxiv.org/abs/2403.14403">https://arxiv.org/abs/2403.14403</a></strong>. Spend retrieval effort in proportion to question difficulty.</p></li><li><p>Singh et al. (2025), <em>Agentic Retrieval-Augmented Generation: A Survey on Agentic RAG</em>. <strong><a href="https://arxiv.org/abs/2501.09136">https://arxiv.org/abs/2501.09136</a></strong>. The field map: where the ReAct-descended patterns sit in the broader agentic-RAG taxonomy.</p></li><li><p>LangGraph (LangChain): <strong><a href="https://github.com/langchain-ai/langgraph">https://github.com/langchain-ai/langgraph</a></strong>. The production-standard way to wire these loops as explicit, bounded state machines (docs now at <strong><a href="http://docs.langchain.com/">docs.langchain.com</a></strong>).</p></li></ul>]]></content:encoded></item><item><title><![CDATA[GraphRAG and friends: when entities and relationships beat similarity]]></title><description><![CDATA[Some questions aren't about what a document says &#8212; they're about how things are connected. Vector search can't answer those. A typed knowledge graph can, and the cost is the hard part.]]></description><link>https://www.ratkonikolic.com/p/graphrag-and-friends-when-entities</link><guid isPermaLink="false">https://www.ratkonikolic.com/p/graphrag-and-friends-when-entities</guid><dc:creator><![CDATA[Ratko Nikolić]]></dc:creator><pubDate>Tue, 14 Jul 2026 08:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/baf09650-70f9-4825-83dd-82cd0b6db8b8_1424x752.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3><strong>The problem</strong></h3><p>Here is a question that breaks every RAG pipeline in this series so far: <em>&#8220;which of our suppliers are connected to the legal entities named in this dispute?&#8221;</em> The answer isn&#8217;t sitting in a chunk anywhere. It&#8217;s a path &#8212; supplier to parent company to subsidiary to the named party &#8212; assembled from facts that live in four different documents. Naive RAG retrieves the four documents independently and has nothing to join them. Advanced RAG reranks those four documents more precisely and still has nothing to join them. The retrieval got better; the question stayed unanswerable, because similarity search returns <em>passages</em>, and the answer is a <em>traversal</em>.</p><p>That&#8217;s the line that divides this article from the previous two. Vector search hands you the ten business cards that look most like your query. A graph hands you the org chart. When the question is &#8220;what does this document say,&#8221; the business cards are what you want. When the question is &#8220;how are these things connected,&#8221; you need the org chart &#8212; and building, storing, and querying that org chart is a different region of the knowledge layer, the part of an agent system that decides reliability in production and is an engineering discipline in its own right. This is where structure stops being optional.</p><h3><strong>How GraphRAG works</strong></h3><p>The spine: extract entities and relationships from the corpus into a graph, optionally summarize clusters of that graph ahead of time, and at query time either traverse the graph directly or retrieve over those summaries.</p><p>Microsoft&#8217;s GraphRAG &#8212; the paper that named the pattern, Edge and co-authors&#8217; <em>From Local to Global: A Graph RAG Approach to Query-Focused Summarization</em> ([arXiv 2404.16130](<strong><a href="https://arxiv.org/abs/2404.16130">https://arxiv.org/abs/2404.16130</a></strong>), April 2024) &#8212; does it in two passes. First, an LLM reads the corpus and extracts an entity-and-relationship graph. Then it partitions that graph into communities of closely-related entities using the Leiden algorithm, and pre-writes a summary of each community. A &#8220;global&#8221; question &#8212; <em>&#8220;what are the recurring themes across all these incident reports?&#8221;</em> &#8212; gets answered by map-reducing over the community summaries rather than over raw chunks, which is something flat RAG simply cannot do, because no single chunk contains the global answer.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5tf2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2b3570-2ab8-4bd5-bb3a-3e869ecbbcde_744x214.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5tf2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2b3570-2ab8-4bd5-bb3a-3e869ecbbcde_744x214.png 424w, https://substackcdn.com/image/fetch/$s_!5tf2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2b3570-2ab8-4bd5-bb3a-3e869ecbbcde_744x214.png 848w, https://substackcdn.com/image/fetch/$s_!5tf2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2b3570-2ab8-4bd5-bb3a-3e869ecbbcde_744x214.png 1272w, https://substackcdn.com/image/fetch/$s_!5tf2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2b3570-2ab8-4bd5-bb3a-3e869ecbbcde_744x214.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5tf2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2b3570-2ab8-4bd5-bb3a-3e869ecbbcde_744x214.png" width="744" height="214" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7a2b3570-2ab8-4bd5-bb3a-3e869ecbbcde_744x214.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:214,&quot;width&quot;:744,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!5tf2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2b3570-2ab8-4bd5-bb3a-3e869ecbbcde_744x214.png 424w, https://substackcdn.com/image/fetch/$s_!5tf2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2b3570-2ab8-4bd5-bb3a-3e869ecbbcde_744x214.png 848w, https://substackcdn.com/image/fetch/$s_!5tf2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2b3570-2ab8-4bd5-bb3a-3e869ecbbcde_744x214.png 1272w, https://substackcdn.com/image/fetch/$s_!5tf2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a2b3570-2ab8-4bd5-bb3a-3e869ecbbcde_744x214.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p></p><p>The dominant production pattern looks slightly different from the research paper. Most teams store a property graph in Neo4j, Memgraph, or an embeddable store like K&#249;zu; chunks become document nodes linked to the entities they mention; and retrieval combines an LLM writing a Cypher query against the graph with ordinary vector search over the chunk embeddings. Neo4j&#8217;s neo4j-graphrag-python SDK and its Knowledge Graph Builder are the de-facto reference here, and LlamaIndex&#8217;s PropertyGraphIndex exposes the same idea framework-agnostically.</p><h3><strong>In practice</strong></h3><p>The example I&#8217;ll use is corporate ownership and supply relationships &#8212; the kind of corpus where the relationships <em>are</em> the point, not the prose.</p><p>Companies own stakes in other companies, supply each other, and share directors &#8212; and those links change as deals close. So the schema is genuinely typed: Company and Person nodes, OWNS edges carrying a stake percentage, SUPPLIES edges, DIRECTOR_OF edges, and a validity stamp on every edge so the graph knows which relationships held on a given date. The base vocabulary isn&#8217;t invented &#8212; it maps onto established models like the Financial Industry Business Ontology (FIBO) and legal-entity identifiers (LEI), which keeps the schema defensible rather than ad hoc.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wPCm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b2ab93c-1da3-499f-9f1b-692b0aed14a7_859x1000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wPCm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b2ab93c-1da3-499f-9f1b-692b0aed14a7_859x1000.png 424w, https://substackcdn.com/image/fetch/$s_!wPCm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b2ab93c-1da3-499f-9f1b-692b0aed14a7_859x1000.png 848w, https://substackcdn.com/image/fetch/$s_!wPCm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b2ab93c-1da3-499f-9f1b-692b0aed14a7_859x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!wPCm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b2ab93c-1da3-499f-9f1b-692b0aed14a7_859x1000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wPCm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b2ab93c-1da3-499f-9f1b-692b0aed14a7_859x1000.png" width="859" height="1000" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1b2ab93c-1da3-499f-9f1b-692b0aed14a7_859x1000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1000,&quot;width&quot;:859,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!wPCm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b2ab93c-1da3-499f-9f1b-692b0aed14a7_859x1000.png 424w, https://substackcdn.com/image/fetch/$s_!wPCm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b2ab93c-1da3-499f-9f1b-692b0aed14a7_859x1000.png 848w, https://substackcdn.com/image/fetch/$s_!wPCm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b2ab93c-1da3-499f-9f1b-692b0aed14a7_859x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!wPCm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1b2ab93c-1da3-499f-9f1b-692b0aed14a7_859x1000.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></p><p>Now the question <em>&#8220;which suppliers does Beta Retail depend on, and which of those came under new ownership after 2024-01-01?&#8221;</em> becomes a short traversal instead of an impossibility:</p><pre><code><code>```cypher
MATCH (b:Company {name: 'Beta Retail'})-[:SUPPLIES*1..3]-&gt;(dep:Company)
MATCH (parent:Company)-[o:OWNS]-&gt;(dep)
WHERE o.since &gt; date('2024-01-01')
RETURN dep.name, parent.name, o.since ORDER BY o.since
```</code></code></pre><p>Flat RAG can&#8217;t express &#8220;depend on through the supply chain&#8221; &#8212; there&#8217;s no similarity score for a dependency path. The graph makes it a path query, and crucially it returns <em>provenance</em>: which company, which relationship, valid on which date. For a due-diligence or compliance answer, an uncited or out-of-date link is worse than no answer, and that&#8217;s exactly the failure a typed temporal graph is built to prevent.</p><h3><strong>Where it shines</strong></h3><p>Two situations make the cost worth it.</p><p>The first is <strong>relationship and multi-hop questions</strong> &#8212; anything of the form &#8220;how is X connected to Y,&#8221; &#8220;what depends on Z,&#8221; &#8220;trace the chain from A to B.&#8221; Supply-chain and ownership graphs, compliance and KYC (&#8221;is this counterparty linked to a sanctioned entity through any chain of ownership?&#8221;), the supplier-dependency case above. These questions are common in finance, law, and regulated industries, and they&#8217;re precisely the ones similarity search can&#8217;t touch. KAG, Lei Liang and co-authors&#8217; framework from Ant Group ([arXiv 2409.13731](<strong><a href="https://arxiv.org/abs/2409.13731">https://arxiv.org/abs/2409.13731</a></strong>), September 2024), leans hard into this &#8212; it adds logical-form reasoning over the graph and reported a 19.6% relative F1 gain on the multi-hop benchmark HotpotQA over a strong graph-RAG baseline (HippoRAG), which is the kind of lift you only get when the structure is doing real work.</p><p>The second is <strong>global sensemaking over a whole corpus</strong> &#8212; &#8220;what are the main themes,&#8221; &#8220;summarize the recurring risks across a thousand reports.&#8221; This is what GraphRAG&#8217;s community summaries were built for: the answer isn&#8217;t in any one document, it&#8217;s a property of the whole set, and the pre-computed summaries are how you reach it without stuffing the entire corpus into a context window.</p><h3><strong>Where it breaks</strong></h3><p>Be honest about this, because the hype skips it. A knowledge graph is expensive and brittle in three specific ways.</p><p><strong>It&#8217;s expensive to build.</strong> Entity-and-relation extraction means an LLM call over every chunk of the corpus, and on a large corpus that indexing bill is real &#8212; easily orders of magnitude more than the few cents naive RAG cost in Article 2. Microsoft&#8217;s own answer to this is LazyGraphRAG (November 2024), which defers the community summarization until query time and cuts indexing cost down to roughly vector-RAG levels while keeping most of the global-query quality &#8212; Microsoft reports more than 700&#215; lower cost on global queries than full GraphRAG. LightRAG (Guo and co-authors, EMNLP 2025 Findings, [arXiv 2410.05779](<strong><a href="https://arxiv.org/abs/2410.05779">https://arxiv.org/abs/2410.05779</a></strong>)) attacks the same problem from the freshness side, with dual-level retrieval and <em>incremental</em> graph updates so you don&#8217;t re-extract the world every time a document changes.</p><p><strong>It&#8217;s hard to keep fresh.</strong> A flat vector store updates by embedding the new document; a graph updates by re-extracting entities, reconciling them against what&#8217;s already there, and fixing up edges &#8212; which is a much heavier operation, and the one teams underestimate most.</p><p><strong>The schema is the hard part, and it can&#8217;t be frozen.</strong> This is where I spend my research time, so I&#8217;ll be opinionated: the genuinely unsolved problem in enterprise knowledge graphs isn&#8217;t extraction, it&#8217;s <em>schema evolution</em>. You design a typed schema, and then the world hands you an entity type you didn&#8217;t anticipate &#8212; a new regulatory instrument, a new category of counterparty, a relationship that doesn&#8217;t fit your existing edge types. The agent ingesting that new document has to decide, under cost, whether to coerce the new thing into an existing type or propose extending the schema. Get that decision wrong in one direction and the graph rots into a mess of mis-typed nodes; wrong in the other and it fragments into a thousand one-off types nobody can query. Almost nobody has a principled control policy for that decision yet &#8212; it&#8217;s one of the genuinely unsolved problems in the area.</p><h3><strong>When not to use it</strong></h3><p>Most enterprises don&#8217;t need a knowledge graph &#8212; and that&#8217;s worth saying out loud before anyone spends a quarter building one. If your questions are overwhelmingly &#8220;what does this document say about X&#8221; rather than &#8220;how is X connected to Y,&#8221; a graph is expensive overkill, and a good advanced-RAG stack will beat a half-maintained graph every time. The graph earns its keep only when relationships are first-class in the questions your users actually ask, <em>and</em> you have the engineering capacity to keep it fresh. A stale graph is worse than no graph, because it answers a connection query with false confidence.</p><p><strong>Cost / latency / setup effort:</strong></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7R5I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec1dde13-482c-458b-8314-77cf3a99ea3a_744x66.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7R5I!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec1dde13-482c-458b-8314-77cf3a99ea3a_744x66.png 424w, https://substackcdn.com/image/fetch/$s_!7R5I!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec1dde13-482c-458b-8314-77cf3a99ea3a_744x66.png 848w, https://substackcdn.com/image/fetch/$s_!7R5I!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec1dde13-482c-458b-8314-77cf3a99ea3a_744x66.png 1272w, https://substackcdn.com/image/fetch/$s_!7R5I!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec1dde13-482c-458b-8314-77cf3a99ea3a_744x66.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7R5I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec1dde13-482c-458b-8314-77cf3a99ea3a_744x66.png" width="744" height="66" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ec1dde13-482c-458b-8314-77cf3a99ea3a_744x66.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:66,&quot;width&quot;:744,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!7R5I!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec1dde13-482c-458b-8314-77cf3a99ea3a_744x66.png 424w, https://substackcdn.com/image/fetch/$s_!7R5I!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec1dde13-482c-458b-8314-77cf3a99ea3a_744x66.png 848w, https://substackcdn.com/image/fetch/$s_!7R5I!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec1dde13-482c-458b-8314-77cf3a99ea3a_744x66.png 1272w, https://substackcdn.com/image/fetch/$s_!7R5I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec1dde13-482c-458b-8314-77cf3a99ea3a_744x66.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p><h3><strong>Combinations and hybrids</strong></h3><p>In production, GraphRAG is almost never the <em>whole</em> answer &#8212; it&#8217;s the half that handles relationships, sitting next to a vector store that handles &#8220;what does this say.&#8221; The standard hybrid lets an agent route: similarity search for descriptive questions, graph traversal for relational ones, often both fused for questions that have a descriptive and a relational part. That routing decision &#8212; does this question need the graph at all &#8212; is itself a retrieval-as-decision problem, which is the subject of the next article on agentic RAG. The heuristic to remember: <strong>vectors for &#8220;what does this say&#8221;; graphs for &#8220;how are these connected.&#8221;</strong> Most real systems need a little of both, and the engineering is in knowing which question is in front of you.</p><h3><strong>Production checklist</strong></h3><ul><li><p><strong>Version the schema explicitly</strong> and treat a schema change as a migration, not a config tweak &#8212; log when types are added and why.</p></li><li><p><strong>Track extraction precision/recall</strong> on a labelled sample; a graph built from sloppy extraction is confidently wrong, which is the worst failure mode.</p></li><li><p><strong>Stamp every node and edge with provenance and validity dates</strong> &#8212; which document, which version, in force when &#8212; so a traversal can return a citation, not just an answer.</p></li><li><p><strong>Instrument graph freshness</strong>: how stale is the graph relative to the corpus, and alert when re-extraction falls behind ingestion.</p></li><li><p><strong>Reconcile entities deliberately</strong> &#8212; decide your dedup/merge policy for &#8220;is this the same entity&#8221; up front; entity resolution drift is silent and corrosive.</p></li><li><p><strong>Measure how often the graph is actually needed</strong> &#8212; if most queries route to the vector side, that&#8217;s a signal you may not have needed the graph.</p></li><li><p><strong>Keep a coerce-vs-extend policy</strong> for new types, even a crude one, so schema growth is a decision and not an accident.</p></li></ul><h3><strong>The take</strong></h3><p>GraphRAG isn&#8217;t a better RAG &#8212; it&#8217;s a different tool for a different question. When the answer is a passage, use vectors; when the answer is a path, you need a graph, and you should go in clear-eyed about the build cost, the freshness burden, and the fact that the schema is the part nobody has fully solved. Most teams don&#8217;t need one. The ones that do &#8212; law, finance, compliance, anywhere relationships are the product &#8212; get answers from it that no amount of reranking would ever surface.</p><p><em><strong><span>New articles land here first. Subscribe for the full series. I take on a small number of advisory engagements each year for teams hitting exactly these problems. The fastest way to reach me is on</span><span data-color="#2adccb" style="color: rgb(42, 220, 203);"> </span><a href="https://www.linkedin.com/in/ratko-nikolic/"><span data-color="#2adccb" style="color: rgb(42, 220, 203);">LinkedIn</span></a><span>; reach out if that&#8217;s you.</span></strong></em></p><h3><strong>What to read next</strong></h3><p><strong>This series</strong>:</p><ul><li><p><strong><a href="https://ratkonikolic.substack.com/p/your-agents-problem-isnt-the-model">Article 1 &#8212; Your agent&#8217;s problem isn&#8217;t the model, it&#8217;s the knowledge layer</a></strong></p></li><li><p><strong><a href="https://www.linkedin.com/pulse/naive-rag-baseline-youll-always-benchmark-against-ratko-nikoli%C4%87-i7h0e/">Article 2</a> <a href="https://ratkonikolic.substack.com/p/naive-rag-the-baseline-youll-always">&#8212; Naive RAG: the baseline you&#8217;ll always benchmark against</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/advanced-rag-what-you-actually-run">Article 3 &#8212; Advanced RAG: what you actually run in production</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/graphrag-and-friends-when-entities">Article 4 &#8212; GraphRAG and friends: when entities and relationships beat similarity</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/agentic-rag-when-retrieval-becomes">Article 5 &#8212; Agentic RAG: when retrieval becomes a decision, not a pipeline</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/vector-vs-graph-vs-episodic-a-tour">Article 6 &#8212; Vector vs graph vs episodic: a tour of agent memory systems</a> </strong></p></li><li><p>Article 7 &#8212; Context engineering: the discipline that replaces prompt engineering (<em>coming soon</em>)</p></li></ul><p><strong>External:</strong></p><ul><li><p>Edge et al. (April 2024), <em>From Local to Global: A Graph RAG Approach to Query-Focused Summarization</em>. <strong><a href="https://arxiv.org/abs/2404.16130">https://arxiv.org/abs/2404.16130</a></strong> &#8212; the paper that named GraphRAG.</p></li><li><p>Guo et al. (EMNLP 2025 Findings), <em>LightRAG: Simple and Fast Retrieval-Augmented Generation</em>. <strong><a href="https://arxiv.org/abs/2410.05779">https://arxiv.org/abs/2410.05779</a></strong> &#8212; graph RAG with incremental updates; the freshness answer.</p></li><li><p>Liang et al. (September 2024), <em>KAG: Boosting LLMs in Professional Domains via Knowledge Augmented Generation</em>. <strong><a href="https://arxiv.org/abs/2409.13731">https://arxiv.org/abs/2409.13731</a></strong> &#8212; logical-form reasoning over the graph for professional domains.</p></li><li><p>Microsoft Research (November 2024), <em>LazyGraphRAG: setting a new standard for quality and cost</em>. <strong><a href="https://www.microsoft.com/en-us/research/blog/lazygraphrag-setting-a-new-standard-for-quality-and-cost/">https://www.microsoft.com/en-us/research/blog/lazygraphrag-setting-a-new-standard-for-quality-and-cost/</a></strong> &#8212; the cost answer, and the most-cited recent move in this space.</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Advanced RAG: what you actually run in production]]></title><description><![CDATA[Four moves turn the naive baseline into something that survives real traffic &#8212; hybrid search, reranking, query rewriting, and metadata filtering. Each fixes a specific failure and each costs you.]]></description><link>https://www.ratkonikolic.com/p/advanced-rag-what-you-actually-run</link><guid isPermaLink="false">https://www.ratkonikolic.com/p/advanced-rag-what-you-actually-run</guid><dc:creator><![CDATA[Ratko Nikolić]]></dc:creator><pubDate>Tue, 30 Jun 2026 08:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ee048e0b-1ee7-4974-809e-6ded26799912_1424x752.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3><strong>The problem</strong></h3><p>The naive pipeline from the last article gets a team about 70% of the way there, and then it stalls. The pattern is always the same: the demo answers were good, the corpus grew, the questions got more varied, and recall quietly fell off a cliff. A query that names an exact product code returns ten semantically-fuzzy chunks and misses the one document that actually mentions the code. A user phrases a question nothing like how the document was written, and the right chunk never clears the similarity threshold. The team adds more documents hoping to help, and makes it worse &#8212; more haystack, same needle.</p><p>None of this is a model problem, and a bigger embedding model won&#8217;t fix it. It&#8217;s the knowledge layer &#8212; the part of an agent system that decides reliability in production and is an engineering discipline in its own right &#8212; hitting the limits of pure top-*k* vector search. Advanced RAG is the set of moves that push past those limits. There are four worth knowing, and the discipline is in knowing which failure each one fixes and what it costs you, because none of them is free.</p><h3><strong>The four moves</strong></h3><p>Here&#8217;s the naive pipeline with the four upgrades dropped into place &#8212; the Article 2 baseline with four new boxes wired in.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!a3nF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81261feb-ad42-49d5-8b79-8e7e0105a85b_2232x1038.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!a3nF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81261feb-ad42-49d5-8b79-8e7e0105a85b_2232x1038.png 424w, https://substackcdn.com/image/fetch/$s_!a3nF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81261feb-ad42-49d5-8b79-8e7e0105a85b_2232x1038.png 848w, https://substackcdn.com/image/fetch/$s_!a3nF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81261feb-ad42-49d5-8b79-8e7e0105a85b_2232x1038.png 1272w, https://substackcdn.com/image/fetch/$s_!a3nF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81261feb-ad42-49d5-8b79-8e7e0105a85b_2232x1038.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!a3nF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81261feb-ad42-49d5-8b79-8e7e0105a85b_2232x1038.png" width="1456" height="677" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/81261feb-ad42-49d5-8b79-8e7e0105a85b_2232x1038.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:677,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Article content&quot;,&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="Article content" title="Article content" srcset="https://substackcdn.com/image/fetch/$s_!a3nF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81261feb-ad42-49d5-8b79-8e7e0105a85b_2232x1038.png 424w, https://substackcdn.com/image/fetch/$s_!a3nF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81261feb-ad42-49d5-8b79-8e7e0105a85b_2232x1038.png 848w, https://substackcdn.com/image/fetch/$s_!a3nF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81261feb-ad42-49d5-8b79-8e7e0105a85b_2232x1038.png 1272w, https://substackcdn.com/image/fetch/$s_!a3nF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81261feb-ad42-49d5-8b79-8e7e0105a85b_2232x1038.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><figcaption class="image-caption">Figure 1 &#8212; Advanced RAG. Query rewriting at the front, hybrid retrieval feeding a fusion step, metadata filtering, and a reranker before the context is assembled. Each box is an independent decision with its own cost.</figcaption></figure></div><h3><strong>Move 1 &#8212; Hybrid search (BM25 + vectors)</strong></h3><p><strong>The failure it fixes:</strong><span> </span>pure vector search is blind to exact tokens. Embeddings encode meaning, so a part number like SKU-44918, a statute reference, or a rare acronym embeds into roughly the same region as its neighbours and gets lost. Keyword search &#8212; BM25, the decades-old probabilistic ranking function that still backs Elasticsearch and OpenSearch &#8212; is exact where vectors are fuzzy. Hybrid search runs both and combines the result lists, usually with Reciprocal Rank Fusion, which scores a document by the reciprocal of its rank in each list and needs no tuning to merge them.</p><p><strong>What it costs:</strong><span> </span>a second index to build and keep in sync, and a fusion step. Operationally modest &#8212; pgvector plus a Postgres full-text index, or a single store that does both, keeps it to one system. Anthropic&#8217;s<span> </span><em>Contextual Retrieval</em><span> </span>write-up (September 2024) put a number on the payoff: contextual embeddings alone cut their top-20 retrieval failure rate by 35%, and adding contextual BM25 took the cut to 49%.<span> </span><strong>Skip it</strong><span> </span>when your corpus has no exact-match vocabulary &#8212; pure prose with no codes, IDs, or names &#8212; where keyword matching adds noise instead of signal.</p><h3><strong>Move 2 &#8212; Reranking</strong></h3><p>This is the highest-leverage single move, and the first one to reach for when retrieval is &#8220;almost there.&#8221;</p><p><strong>The failure it fixes:</strong><span> </span>the top-*k* chunks from a similarity search are ranked by a cheap approximation &#8212; cosine distance between independently-computed embeddings, which never actually compared the query and the chunk against each other. A reranker is a cross-encoder: it reads the query and each candidate chunk<span> </span><em>together</em><span> </span>and scores genuine relevance. You retrieve a generous longlist (say top-50 cheaply), then rerank to a precise shortlist (top-5). It&#8217;s a recruiting funnel &#8212; a cheap CV screen gets you fifty plausible candidates, and the expensive interview reads each one carefully before you pick five.</p><p><strong>In practice:</strong><span> </span>Cohere&#8217;s Rerank 4 (*Introducing Rerank 4*, December 2025 &#8212; Fast and Pro variants, a 32k context window, 100+ languages) and Voyage&#8217;s rerank-2.5 are the two production defaults. A realistic before/after on a mid-sized corpus: retrieve-then-rerank takes recall@5 from around 0.6 to 0.85, and p99 latency from roughly 200 ms to 600 ms. In the Anthropic numbers above, adding reranking on top of contextual hybrid search took the failure-rate cut from 49% all the way to 67%.</p><p><strong>What it costs:</strong><span> </span>an extra network call per query and that latency bump &#8212; the reranker has to score every candidate, so 80&#8211;150 ms is typical on top of retrieval, more if your longlist is large.<span> </span><strong>Skip it</strong><span> </span>when your corpus is so small that the top-*k* is already the whole relevant set, or when sub-200 ms latency is a hard product requirement you can&#8217;t spend.</p><h3><strong>Move 3 &#8212; Query rewriting</strong></h3><p><strong>The failure it fixes:</strong><span> </span>the user&#8217;s phrasing and the document&#8217;s phrasing don&#8217;t match, and one short query can&#8217;t express a multi-part question. Three sub-moves handle this.<span> </span><em>Expansion</em><span> </span>rewrites a terse query into a fuller one before embedding.<span> </span><em>Decomposition</em><span> </span>splits a compound question &#8212;<span> </span><em>&#8220;compare our refund policy for EU and US customers&#8221;</em><span> </span>&#8212; into separate retrievals that get merged. And<span> </span><em>HyDE</em><span> </span>(Hypothetical Document Embeddings, from Gao and co-authors&#8217;<span> </span><em>Precise Zero-Shot Dense Retrieval without Relevance Labels</em>, [arXiv 2212.10496](<strong><a href="https://arxiv.org/abs/2212.10496">https://arxiv.org/abs/2212.10496</a></strong>), December 2022) has the model write a fake ideal answer first and embeds<span> </span><em>that</em><span> </span>instead of the question &#8212; on the theory that an answer looks more like the target document than the question does.</p><p><strong>What it costs:</strong><span> </span>an extra LLM call before retrieval even starts, which adds latency and a little money to every query, and introduces a new failure surface &#8212; a bad rewrite retrieves confidently for the wrong question. In practice this is the move to add last, after hybrid search and reranking, because its wins are real but smaller and its cost lands on every single query.<span> </span><strong>Skip it</strong><span> </span>for short, well-formed queries over a corpus written in the user&#8217;s own vocabulary &#8212; an internal tool where people already ask in the documents&#8217; language gains little.</p><h3><strong>Move 4 &#8212; Metadata filtering</strong></h3><p><strong>The failure it fixes:</strong><span> </span>the naive pipeline ranks on similarity alone and has no notion that last year&#8217;s fee schedule is superseded by this year&#8217;s, or that a document belongs to a tenant the user can&#8217;t see. Metadata filtering attaches structured fields &#8212; valid_from, tenant_id, document_type, access tags &#8212; to each chunk and filters on them before or during retrieval. This is also the cheapest, most boring, and most-skipped reliability win in the whole pipeline.</p><p><strong>What it costs:</strong><span> </span>almost nothing at query time, and real discipline at index time &#8212; someone has to populate the metadata correctly and keep it correct, which is process work rather than ML work.<span> </span><strong>Skip it</strong><span> </span>essentially never. Even a single valid_from date filter pays for itself the first time it stops the agent from quoting a retired policy, and access-control filtering isn&#8217;t optional the moment your corpus spans more than one permission boundary.</p><h3><strong>Where the four leave you</strong></h3><p><strong>Cost / latency / setup effort (deltas over naive RAG):</strong></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SJv0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89517-c19f-4f93-85ef-0a12e092fa6d_1004x208.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SJv0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89517-c19f-4f93-85ef-0a12e092fa6d_1004x208.png 424w, https://substackcdn.com/image/fetch/$s_!SJv0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89517-c19f-4f93-85ef-0a12e092fa6d_1004x208.png 848w, https://substackcdn.com/image/fetch/$s_!SJv0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89517-c19f-4f93-85ef-0a12e092fa6d_1004x208.png 1272w, https://substackcdn.com/image/fetch/$s_!SJv0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89517-c19f-4f93-85ef-0a12e092fa6d_1004x208.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SJv0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89517-c19f-4f93-85ef-0a12e092fa6d_1004x208.png" width="1004" height="208" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/05f89517-c19f-4f93-85ef-0a12e092fa6d_1004x208.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:208,&quot;width&quot;:1004,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Article content&quot;,&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="Article content" title="Article content" srcset="https://substackcdn.com/image/fetch/$s_!SJv0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89517-c19f-4f93-85ef-0a12e092fa6d_1004x208.png 424w, https://substackcdn.com/image/fetch/$s_!SJv0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89517-c19f-4f93-85ef-0a12e092fa6d_1004x208.png 848w, https://substackcdn.com/image/fetch/$s_!SJv0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89517-c19f-4f93-85ef-0a12e092fa6d_1004x208.png 1272w, https://substackcdn.com/image/fetch/$s_!SJv0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F05f89517-c19f-4f93-85ef-0a12e092fa6d_1004x208.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><p>Read the table as a menu, not a recipe. The order of adoption that holds up in production, and that the costs above argue for &#8212; call it the cost-order rule: metadata filtering first (cheap, always worth it), then reranking (highest leverage), then hybrid search (cheap insurance against exact-match misses), then query rewriting last (real but smaller wins, paid on every query). And to put a boundary on the whole menu: all four together are typically a two-to-three-week retrofit on an existing pipeline, not a rebuild.</p><h3><strong>The stack a competent team converges on</strong></h3><p>Not as a prescription &#8212; as a checkpoint to measure your own choices against. After the dust settles, most teams running serious RAG land in the same place: a single store doing both vector and keyword search, Reciprocal Rank Fusion to merge them, a cross-encoder reranker (Cohere Rerank 4 or Voyage rerank-2.5) trimming the longlist to a tight shortlist, metadata filters enforcing recency and access control, and query rewriting added only where the query/document vocabulary genuinely diverges. The embedding and reranker models underneath keep moving &#8212; Voyage shipped its mixture-of-experts voyage-4-large in January 2026, the rerankers turn over every few months &#8212; but the<span> </span><em>shape</em><span> </span>of the stack has been stable for a while now, and that stability is the signal that this is the production answer, not a fashion.</p><p>If your stack looks materially different from that and you can say<span> </span><em>why</em><span> </span>&#8212; a latency budget that rules out reranking, a corpus with no exact-match vocabulary that rules out BM25 &#8212; you&#8217;re fine. If it looks different and you<span> </span><em>can&#8217;t</em><span> </span>say why, that&#8217;s worth a look.</p><h3><strong>Combinations and what&#8217;s next</strong></h3><p>Advanced RAG is still retrieval over a flat corpus &#8212; it makes the retrieval sharper, but it can&#8217;t answer a question whose answer isn&#8217;t sitting in some chunk. When the question is about<span> </span><em>relationships</em><span> </span>between entities &#8212;<span> </span><em>&#8220;which suppliers connect to the parties in this dispute?&#8221;</em><span> </span>&#8212; no amount of reranking helps, because the answer is a path through a graph, not a passage in a document. That&#8217;s where GraphRAG comes in, and it&#8217;s the next article. And when retrieval needs to become a decision the agent makes &#8212; query, judge the results, refine, query again &#8212; you&#8217;ve crossed into agentic RAG, two articles out. Advanced RAG is the substrate both of those assume you&#8217;ve already got right.</p><h3><strong>Production checklist</strong></h3><ul><li><p><strong>Measure recall@k before and after every move</strong><span> </span>on a held-out golden set &#8212; never add a reranker or a rewriter on faith; prove the delta.</p></li><li><p><strong>Log the full retrieval trace</strong>: rewritten query, both retrieval lists, fused order, reranker scores, final shortlist. When an answer is wrong, this is where you see which move failed.</p></li><li><p><strong>Watch the latency budget per stage</strong><span> </span>&#8212; query rewriting and reranking each add a measurable slice; track p99, not just the average, because the tail is what users complain about.</p></li><li><p><strong>Keep the longlist size honest</strong><span> </span>&#8212; reranking a 200-candidate list is slow and rarely beats reranking 50; tune it.</p></li><li><p><strong>Treat metadata as a first-class schema</strong>, version it, and validate it at index time; silent metadata rot defeats the filter quietly.</p></li><li><p><strong>Alert when the reranker&#8217;s top score is low</strong><span> </span>&#8212; same principle as naive RAG, but now you have a more trustworthy signal to threshold on.</p></li><li><p><strong>Re-evaluate the embedding and reranker models quarterly</strong><span> </span>&#8212; they turn over fast, and a model swap is often a bigger win than another pipeline tweak.</p></li></ul><h3><strong>The take</strong></h3><p>Advanced RAG isn&#8217;t a different technique from naive RAG &#8212; it&#8217;s the same pipeline with four targeted repairs, each aimed at a failure you can name. Add them in cost order, measure every one against your baseline, and stop when the numbers stop moving. The team that does this beats the team chasing a bigger model almost every time, because they&#8217;re fixing the layer where the failures actually live.</p><p><em><strong><span>New articles land here first. Subscribe for the full series. I take on a small number of advisory engagements each year for teams hitting exactly these problems. The fastest way to reach me is on </span><a href="https://www.linkedin.com/in/ratko-nikolic/"><span data-color="#2adccb" style="color: rgb(42, 220, 203);">LinkedIn</span></a><span>; reach out if that&#8217;s you.</span></strong></em></p><h3><strong>What to read next</strong></h3><p><strong>This series</strong>:</p><ul><li><p><strong><a href="https://ratkonikolic.substack.com/p/your-agents-problem-isnt-the-model">Article 1 &#8212; Your agent&#8217;s problem isn&#8217;t the model, it&#8217;s the knowledge layer</a></strong></p></li><li><p><strong><a href="https://www.linkedin.com/pulse/naive-rag-baseline-youll-always-benchmark-against-ratko-nikoli%C4%87-i7h0e/">Article 2</a> <a href="https://ratkonikolic.substack.com/p/naive-rag-the-baseline-youll-always">&#8212; Naive RAG: the baseline you&#8217;ll always benchmark against</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/advanced-rag-what-you-actually-run">Article 3 &#8212; Advanced RAG: what you actually run in production</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/graphrag-and-friends-when-entities">Article 4 &#8212; GraphRAG and friends: when entities and relationships beat similarity</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/agentic-rag-when-retrieval-becomes">Article 5 &#8212; Agentic RAG: when retrieval becomes a decision, not a pipeline</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/vector-vs-graph-vs-episodic-a-tour">Article 6 &#8212; Vector vs graph vs episodic: a tour of agent memory systems</a> </strong></p></li><li><p>Article 7 &#8212; Context engineering: the discipline that replaces prompt engineering (<em>coming soon</em>)</p></li></ul><p><strong>External:</strong></p><ul><li><p>Anthropic (September 2024),<span> </span><em>Introducing Contextual Retrieval</em>.<span> </span><strong><a href="https://www.anthropic.com/news/contextual-retrieval">https://www.anthropic.com/news/contextual-retrieval</a></strong><span> </span>&#8212; the clearest published numbers on what hybrid search + reranking buys you.</p></li><li><p>Gao et al. (December 2022),<span> </span><em>Precise Zero-Shot Dense Retrieval without Relevance Labels</em><span> </span>(HyDE).<span> </span><strong><a href="https://arxiv.org/abs/2212.10496">https://arxiv.org/abs/2212.10496</a></strong><span> </span>&#8212; the query-rewriting idea most worth understanding.</p></li><li><p>Cohere (December 2025),<span> </span><em>Introducing Rerank 4: Cohere&#8217;s most powerful reranker yet</em>.<span> </span><strong><a href="https://cohere.com/blog/rerank-4">https://cohere.com/blog/rerank-4</a></strong><span> </span>&#8212; the current production-default reranker and what a cross-encoder adds.</p></li><li><p>Voyage AI (January 2026),<span> </span><em>The Voyage 4 model family</em>.<span> </span><strong><a href="https://blog.voyageai.com/2026/01/15/voyage-4/">https://blog.voyageai.com/2026/01/15/voyage-4/</a></strong><span> </span>&#8212; where the embedding frontier underneath all of this currently sits.</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Naive RAG: the baseline you'll always benchmark against]]></title><description><![CDATA[The simplest retrieval pipeline there is &#8212; chunk, embed, match, stuff into the prompt. It's also the thing every fancier technique has to prove it beats.]]></description><link>https://www.ratkonikolic.com/p/naive-rag-the-baseline-youll-always</link><guid isPermaLink="false">https://www.ratkonikolic.com/p/naive-rag-the-baseline-youll-always</guid><dc:creator><![CDATA[Ratko Nikolić]]></dc:creator><pubDate>Tue, 16 Jun 2026 08:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ce4c6f6e-4760-4384-b363-93f98c1463d3_1424x752.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3><strong>The problem</strong></h3><p>A team builds a support assistant that answers questions over about three hundred internal policy pages. It works for weeks. Then someone asks whether the company covers relocation costs for a transfer between two offices, and the assistant confidently quotes the<span> </span><em>parental</em><span> </span>relocation benefit &#8212; wrong policy, right neighborhood. The page with the correct answer exists. It just never makes it into the model&#8217;s context.</p><p>That is the naive-RAG failure in one sentence: the answer is in the corpus, the model is fine, and the retrieval step quietly hands over the wrong paragraph. Before you can fix that &#8212; with reranking, hybrid search, graphs, any of the machinery the rest of this series covers &#8212; you have to understand the pipeline that produced it. Naive RAG is the first and simplest thing you build in the knowledge layer, the part of an agent system that decides reliability in production and is an engineering discipline in its own right. Everything else in this series is a response to where naive RAG breaks.</p><h3><strong>How naive RAG works</strong></h3><p>The spine is four steps: split the documents into chunks, turn each chunk into a vector, store the vectors, and at query time pull the few chunks closest to the question and paste them into the 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_!saGT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd4e1c6a-2ad9-464c-a705-0411fc25e391_2232x1041.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!saGT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd4e1c6a-2ad9-464c-a705-0411fc25e391_2232x1041.png 424w, https://substackcdn.com/image/fetch/$s_!saGT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd4e1c6a-2ad9-464c-a705-0411fc25e391_2232x1041.png 848w, https://substackcdn.com/image/fetch/$s_!saGT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd4e1c6a-2ad9-464c-a705-0411fc25e391_2232x1041.png 1272w, https://substackcdn.com/image/fetch/$s_!saGT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd4e1c6a-2ad9-464c-a705-0411fc25e391_2232x1041.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!saGT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd4e1c6a-2ad9-464c-a705-0411fc25e391_2232x1041.png" width="1456" height="679" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fd4e1c6a-2ad9-464c-a705-0411fc25e391_2232x1041.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:679,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Article content&quot;,&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="Article content" title="Article content" srcset="https://substackcdn.com/image/fetch/$s_!saGT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd4e1c6a-2ad9-464c-a705-0411fc25e391_2232x1041.png 424w, https://substackcdn.com/image/fetch/$s_!saGT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd4e1c6a-2ad9-464c-a705-0411fc25e391_2232x1041.png 848w, https://substackcdn.com/image/fetch/$s_!saGT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd4e1c6a-2ad9-464c-a705-0411fc25e391_2232x1041.png 1272w, https://substackcdn.com/image/fetch/$s_!saGT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffd4e1c6a-2ad9-464c-a705-0411fc25e391_2232x1041.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><figcaption class="image-caption">Figure 1 &#8212; Naive RAG end to end. No reranking, no query rewriting, no filtering &#8212; every later technique article adds a box to this diagram.</figcaption></figure></div><p>Each step is a single choice. Chunking is usually fixed-size &#8212; say 500 tokens with a 50-token overlap so a sentence straddling a boundary survives in at least one piece. Embedding is one model call per chunk; the common picks are OpenAI&#8217;s text-embedding-3-large, Cohere&#8217;s Embed 4 (shipped April 2025, with a 128k-token context window that lets you embed a 200-page document in one pass), or Voyage&#8217;s voyage-4-large (January 2026, which Voyage bills as the first production embedding model built on a mixture-of-experts architecture). Storage, for most teams starting out, is pgvector on the Postgres they already run &#8212; no new system to operate &#8212; or Chroma if they want something embedding-native and local. Retrieval is a cosine-similarity search for the top<span> </span><em>k</em><span> </span>chunks,<span> </span><em>k</em><span> </span>usually between 3 and 8. That&#8217;s the whole thing. You can stand it up in an afternoon.</p><h3><strong>In practice</strong></h3><p>Here&#8217;s the shape of it, stripped to pseudo-code:</p><pre><code><code># index time &#8212; runs once, then on updates
for doc in corpus:
    for chunk in split(doc, size=500, overlap=50):
        vec = embed(chunk, model="text-embedding-3-large")
        db.insert(text=chunk, vector=vec, source=doc.id)

# query time &#8212; runs per question
q_vec   = embed(user_question, model="text-embedding-3-large")
hits    = db.search(q_vec, top_k=5)            # cosine similarity
context = "\n\n".join(h.text for h in hits)
answer  = llm(f"Answer using only this context:\n{context}\n\nQ: {user_question}") </code></code></pre><p>The economics are why this is everyone&#8217;s starting point. Embedding a 300-page handbook is roughly 200k tokens; at text-embedding-3-large prices &#8212; about $0.13 per million tokens &#8212; indexing the whole corpus costs you a few cents, once. Per query you pay one tiny embedding call plus one model call, and a cosine search over a few thousand chunks on pgvector returns in well under 50 ms. The latency a user feels is almost entirely the model generating the answer, not the retrieval. For a corpus this size, naive RAG is close to free and close to instant.</p><h3><strong>Where it shines</strong></h3><p>Two situations where I&#8217;d push back on anyone who wants something fancier.</p><p>The first is<span> </span><strong>FAQ-shaped corpora</strong><span> </span>&#8212; a body of mostly self-contained question-and-answer pairs or short policy statements, where the answer to any given question lives in one place. An internal IT helpdesk over a couple of hundred wiki pages, a product-support bot over a structured knowledge base: the unit of retrieval and the unit of answer line up, so pulling the single closest chunk usually pulls the right one. Adding a graph or an agentic loop here buys you latency and nothing else.</p><p>The second is<span> </span><strong>low-volume, low-stakes internal tooling</strong><span> </span>&#8212; the onboarding assistant, the &#8220;where&#8217;s the form for X&#8221; bot, the thing fifty employees hit a few times a week. The corpus is small, the cost of an occasional wrong answer is a follow-up Slack message rather than a compliance incident, and the engineering budget is better spent elsewhere. Naive RAG is the bicycle here: unglamorous, occasionally exactly enough, and the thing you measure every proposed upgrade against before you pay for the upgrade.</p><h3><strong>Where it breaks</strong></h3><p>The failure modes are specific, and they&#8217;re worth naming because every later technique exists to fix one of them.</p><p><strong>Chunk-boundary loss.</strong><span> </span>A fixed-size splitter has no idea what a sentence or a clause means; it cuts at a token count. If the answer to a question spans the seam between chunk 7 and chunk 8, similarity search may surface only one half. Counterintuitively, fancier chunking doesn&#8217;t reliably fix this &#8212; Renyi Qu and co-authors, in<span> </span><em>Is Semantic Chunking Worth the Computational Cost?</em><span> </span>(NAACL 2025 Findings, [arXiv 2410.13070](<strong><a href="https://arxiv.org/abs/2410.13070">https://arxiv.org/abs/2410.13070</a></strong>)), found that semantic chunking&#8217;s extra compute often<span> </span><em>didn&#8217;t</em><span> </span>beat plain fixed-size chunks on real documents. The baseline is stubborn, which is exactly why it&#8217;s the baseline.</p><p><strong>Semantically-close-but-wrong matches.</strong><span> </span>Embeddings encode topical similarity, not factual identity. Ask about paternity leave and the closest vectors may be the maternity-leave chunks, because the model considers them near-synonymous &#8212; which is how the support assistant in the opening example quotes the wrong relocation policy. The retrieved chunk<span> </span><em>looks</em><span> </span>relevant, scores well, and is wrong, and the model has no way to know.</p><p><strong>No sense of recency or version.</strong><span> </span>Naive RAG ranks on similarity alone. If your corpus contains last year&#8217;s fee schedule and this year&#8217;s, both embed to nearly the same vector, and the pipeline has no notion that one supersedes the other &#8212; so it may hand the model the stale one, or both at once with no signal about which to trust.</p><p><strong>No multi-hop, no relationships.</strong><span> </span>Any question that requires joining two facts &#8212;<span> </span><em>&#8220;which of our vendors are subsidiaries of companies we&#8217;ve flagged?&#8221;</em><span> </span>&#8212; is dead on arrival, because each fact lives in a different chunk and similarity search retrieves them independently, with nothing to connect them.</p><h3><strong>When not to use it</strong></h3><p>The moment any of these is true, naive RAG stops being the right baseline and becomes a liability: the corpus updates frequently with facts that supersede each other, the questions require synthesis across multiple documents or reasoning over relationships, or a wrong answer is expensive &#8212; legal, medical, financial. If a confident wrong answer costs you a customer or a compliance finding, the few cents you saved on the retrieval pipeline is the wrong place to economize.</p><p><strong>Cost / latency / setup effort:</strong></p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9s6M!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38076fe-e3e2-4bf1-b839-8279ba829002_718x88.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9s6M!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38076fe-e3e2-4bf1-b839-8279ba829002_718x88.png 424w, https://substackcdn.com/image/fetch/$s_!9s6M!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38076fe-e3e2-4bf1-b839-8279ba829002_718x88.png 848w, https://substackcdn.com/image/fetch/$s_!9s6M!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38076fe-e3e2-4bf1-b839-8279ba829002_718x88.png 1272w, https://substackcdn.com/image/fetch/$s_!9s6M!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38076fe-e3e2-4bf1-b839-8279ba829002_718x88.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9s6M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38076fe-e3e2-4bf1-b839-8279ba829002_718x88.png" width="718" height="88" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b38076fe-e3e2-4bf1-b839-8279ba829002_718x88.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:88,&quot;width&quot;:718,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Article content&quot;,&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="Article content" title="Article content" srcset="https://substackcdn.com/image/fetch/$s_!9s6M!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38076fe-e3e2-4bf1-b839-8279ba829002_718x88.png 424w, https://substackcdn.com/image/fetch/$s_!9s6M!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38076fe-e3e2-4bf1-b839-8279ba829002_718x88.png 848w, https://substackcdn.com/image/fetch/$s_!9s6M!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38076fe-e3e2-4bf1-b839-8279ba829002_718x88.png 1272w, https://substackcdn.com/image/fetch/$s_!9s6M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb38076fe-e3e2-4bf1-b839-8279ba829002_718x88.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption"></figcaption></figure></div><h3><strong>Combinations and hybrids</strong></h3><p>Nobody runs naive RAG in production for long, but almost everyone runs<span> </span><em>something built on top of it</em>. The upgrades are additive, and each targets one failure mode above. A reranker &#8212; Cohere Rerank, Voyage rerank &#8212; re-scores the top<span> </span><em>k</em><span> </span>so the genuinely-relevant chunk beats the merely-similar one; that&#8217;s the cheapest single fix and it&#8217;s the subject of the next article. Hybrid search bolts a keyword index (BM25) onto the vector search so exact terms like a product code or a statute number stop getting lost in semantic fog. Metadata filtering on a valid_from date is how you teach the pipeline about recency. And Anthropic&#8217;s<span> </span><em>Contextual Retrieval</em><span> </span>(September 2024) attacks chunk-boundary loss directly, by prepending a short LLM-generated description of each chunk&#8217;s context before embedding it. The point is that naive RAG isn&#8217;t a competitor to any of these &#8212; it&#8217;s the substrate they all assume.</p><h3><strong>Production checklist</strong></h3><ul><li><p><strong>Log every retrieval</strong>: the question, the<span> </span><em>k</em><span> </span>chunks returned, their similarity scores, and which document each came from. Without this you cannot debug a single wrong answer.</p></li><li><p><strong>Hold out a golden set</strong><span> </span>of 50&#8211;100 real questions with known-correct source chunks, and measure recall@k on it before and after any change.</p></li><li><p><strong>Alert on low top-score queries</strong><span> </span>&#8212; when the best chunk&#8217;s similarity is below a threshold, the model is probably about to improvise. Flag it rather than answer it.</p></li><li><p><strong>Instrument the &#8220;no good chunk&#8221; path</strong><span> </span>explicitly; decide whether the agent says &#8220;I don&#8217;t know&#8221; or falls back to the model&#8217;s parametric knowledge, and make that a deliberate choice, not an accident.</p></li><li><p><strong>Track chunk size and overlap as config</strong>, not as buried constants &#8212; they are the parameters you&#8217;ll tune most.</p></li><li><p><strong>Re-index on a schedule</strong><span> </span>and log when each chunk was last refreshed, so a stale corpus is visible rather than silent.</p></li><li><p><strong>Watch p99 latency</strong><span> </span>as the corpus grows; the cliff comes later than you&#8217;d think on pgvector, but it comes.</p></li></ul><h3><strong>The take</strong></h3><p>Naive RAG is not a strawman and it&#8217;s not a beginner&#8217;s mistake &#8212; it&#8217;s the control group. Build it first, measure it honestly, and make every fancier technique earn its place against those numbers. Most of the time the upgrade is worth it; some of the time the bicycle was already enough, and the only way to know is to have ridden it first.</p><p></p><p><em><strong>New articles land here first. Subscribe for the full series. I take on a small number of advisory engagements each year for teams hitting exactly these problems. The fastest way to reach me is on <a href="https://www.linkedin.com/in/ratko-nikolic/"><span data-color="#2adccb" style="color: rgb(42, 220, 203);">LinkedIn</span></a>; reach out if that&#8217;s you.</strong></em></p><p></p><h3><strong>What to read next</strong></h3><p><strong>This series</strong>:</p><ul><li><p><strong><a href="https://ratkonikolic.substack.com/p/your-agents-problem-isnt-the-model">Article 1 &#8212; Your agent&#8217;s problem isn&#8217;t the model, it&#8217;s the knowledge layer</a></strong></p></li><li><p><strong><a href="https://www.linkedin.com/pulse/naive-rag-baseline-youll-always-benchmark-against-ratko-nikoli%C4%87-i7h0e/">Article 2</a> <a href="https://ratkonikolic.substack.com/p/naive-rag-the-baseline-youll-always">&#8212; Naive RAG: the baseline you&#8217;ll always benchmark against</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/advanced-rag-what-you-actually-run">Article 3 &#8212; Advanced RAG: what you actually run in production</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/graphrag-and-friends-when-entities">Article 4 &#8212; GraphRAG and friends: when entities and relationships beat similarity</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/agentic-rag-when-retrieval-becomes">Article 5 &#8212; Agentic RAG: when retrieval becomes a decision, not a pipeline</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/vector-vs-graph-vs-episodic-a-tour">Article 6 &#8212; Vector vs graph vs episodic: a tour of agent memory systems</a> </strong></p></li><li><p>Article 7 &#8212; Context engineering: the discipline that replaces prompt engineering (<em>coming soon</em>)</p></li></ul><p><strong>External:</strong></p><ul><li><p>Lewis et al. (2020),<span> </span><em>Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks</em><span> </span>(NeurIPS 2020).<span> </span><strong><a href="https://arxiv.org/abs/2005.11401">https://arxiv.org/abs/2005.11401</a></strong><span> </span>&#8212; the paper that named the pattern.</p></li><li><p>Qu, Tu &amp; Bao (NAACL 2025 Findings),<span> </span><em>Is Semantic Chunking Worth the Computational Cost?</em><span> </span><strong><a href="https://arxiv.org/abs/2410.13070">https://arxiv.org/abs/2410.13070</a></strong><span> </span>&#8212; the evidence that fixed-size chunking is a hard baseline to beat.</p></li><li><p>Merola &amp; Singh (April 2025),<span> </span><em>Reconstructing Context: Evaluating Advanced Chunking Strategies for Retrieval-Augmented Generation</em>.<span> </span><strong><a href="https://arxiv.org/abs/2504.19754">https://arxiv.org/abs/2504.19754</a></strong><span> </span>&#8212; a careful look at where smarter chunking (late chunking, contextual retrieval) does and doesn&#8217;t pay off.</p></li><li><p>Voyage AI (January 2026),<span> </span><em>The Voyage 4 model family: shared embedding space with MoE architecture</em>.<span> </span><strong><a href="https://blog.voyageai.com/2026/01/15/voyage-4/">https://blog.voyageai.com/2026/01/15/voyage-4/</a></strong><span> </span>&#8212; where the embedding-model frontier sits right now.</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Your agent's problem isn't the model. It's the knowledge layer.]]></title><description><![CDATA[Most agent failures aren't model failures or prompt failures &#8212; they're failures in the layer underneath. This series is about that layer.]]></description><link>https://www.ratkonikolic.com/p/your-agents-problem-isnt-the-model</link><guid isPermaLink="false">https://www.ratkonikolic.com/p/your-agents-problem-isnt-the-model</guid><dc:creator><![CDATA[Ratko Nikolić]]></dc:creator><pubDate>Tue, 02 Jun 2026 08:00:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/cb957152-3bae-4936-aedb-e993d747a2bd_1424x752.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3><strong>The pattern</strong></h3><p>I&#8217;ll start with a pattern. You&#8217;ve probably seen it.</p><p>An LLM agent demos well. The team builds it against a few hand-picked examples, ships it to a stakeholder meeting, the stakeholder is impressed, and the project gets the green light for production. Three months in, the agent is quietly turned off and replaced with a form. Nobody calls it a failure; they call it a<span> </span><em>V1</em>.</p><p>When you dig into why, the failure is almost never the model. The team didn&#8217;t pick the wrong LLM &#8212; they were probably on<span> </span><strong><a href="https://www.anthropic.com/news/claude-opus-4-7">Claude Opus 4.7</a></strong>,<span> </span><strong><a href="https://openai.com/index/introducing-gpt-5-5/">GPT-5.5</a></strong>, or<span> </span><strong><a href="https://blog.google/innovation-and-ai/models-and-research/gemini-models/gemini-3-5/">Gemini 3.5 Flash</a></strong>, and any of those would have been fine (even an overkill in most cases). The failure is almost never the prompt either; modern models tolerate prompt sloppiness in a way they didn&#8217;t two years ago. The failure is, almost every time, in the layer between the corpus of company knowledge and the model: which documents got retrieved, what the memory remembered (or forgot), how the context was packed, what got cached, what was stale, what was missing.</p><p>Most people now call it the<span> </span><strong>knowledge layer</strong>.<span> </span><strong><a href="https://www.pinecone.io/">Pinecone</a></strong><span> </span>calls its<span> </span><strong><a href="https://www.pinecone.io/product/nexus/">Nexus</a></strong><span> </span>a<span> </span><em>&#8220;knowledge engine&#8221;</em>. Microsoft markets<span> </span><strong><a href="https://learn.microsoft.com/en-us/fabric/iq/overview">Fabric IQ</a></strong><span> </span>as a<span> </span><em>&#8220;unified intelligence platform&#8221;</em>. Google&#8217;s April 2026 rebrand from Dataplex Universal Catalog to<span> </span><em><strong><a href="https://cloud.google.com/products/knowledge-catalog">Knowledge Catalog</a></strong></em><span> </span>put the word in the product name. What&#8217;s lagged is the engineering discipline around it &#8212; most teams still treat it as three separate plug-ins (RAG, memory, context engineering) bolted onto a model rather than one coherent job. This series makes the case that this &#8212; treated as one job, not three &#8212; is what decides whether your agent survives production.</p><p>This first piece is the map: what the knowledge layer is, why it deserves to be treated as its own engineering discipline, and the three places I keep seeing teams break in production. This article series will go deep on the techniques &#8212; what they do, where they shine, where they break, and how to choose between them.</p><h3><strong>What the knowledge layer actually is</strong></h3><p>Strip an agent system down and you find three things stacked on top of each other.</p><p>There&#8217;s the<span> </span><strong>model</strong><span> </span>&#8212; the LLM you&#8217;re renting from OpenAI, Anthropic, Google, or whichever provider you prefer. There&#8217;s the<span> </span><strong>prompt</strong><span> </span>&#8212; the instructions you give it, the role you put it in, the format you ask the output in. And underneath those, doing the work that&#8217;s much less visible, there&#8217;s the<span> </span><strong>knowledge layer</strong><span> </span>&#8212; everything that has to happen for the model to know what&#8217;s actually in your company, your conversation history, your last invoice, your evolving SOPs.</p><p>In practice the knowledge layer is four sub-problems that compose into one:</p><ul><li><p><strong>Storage.</strong><span> </span>Where the corpus lives. The vector-database era is the canonical answer &#8212;<span> </span><strong><a href="https://www.pinecone.io/">Pinecone</a></strong>,<span> </span><strong><a href="https://weaviate.io/">Weaviate</a></strong>,<span> </span><strong><a href="https://qdrant.tech/">Qdrant</a></strong>, or<span> </span><strong><a href="https://www.trychroma.com/">Chroma</a></strong><span> </span>if you&#8217;re starting small;<span> </span><strong><a href="https://milvus.io/">Milvus</a></strong><span> </span>or<span> </span><strong><a href="https://vespa.ai/">Vespa</a></strong><span> </span>at scale. But the most common starting point in real enterprises isn&#8217;t a dedicated vector database at all &#8212; it&#8217;s<span> </span><strong><a href="https://github.com/pgvector/pgvector">pgvector</a></strong><span> </span>on the Postgres they already run, which means no new system to operate, transactional consistency with the rest of the data, and a migration path to a purpose-built store only if and when scale forces it. &#8220;Just use pgvector&#8221; is the right first answer more often than any vendor will tell you. The graph side has its own canon:<span> </span><strong><a href="https://neo4j.com/">Neo4j</a></strong>,<span> </span><strong><a href="https://memgraph.com/">Memgraph</a></strong>,<span> </span><strong><a href="https://www.tigergraph.com/">TigerGraph</a></strong><span> </span>for typed-relation corpora. And in 2026 a new tier appeared &#8212; dedicated<span> </span><em>knowledge engines</em><span> </span>explicitly built for agents:<span> </span><strong>Pinecone Nexus</strong><span> </span>(May 2026, ships with a query language called KnowQL and compile-time artifacts),<span> </span><strong>Microsoft Fabric IQ</strong><span> </span>(announced at Ignite 2025, semantic layer over OneLake with ontology + graph + agents),<span> </span><strong>Google Knowledge Catalog</strong><span> </span>(the April 2026 rebrand of Dataplex Universal Catalog, building dynamic context graphs for Gemini agents). The schema and abstractions you commit to here are very hard to change later.</p></li><li><p><strong>Updating.</strong><span> </span>How the storage stays fresh when the world moves on &#8212; when a policy is rewritten, when a product is discontinued, when a customer changes their preferences. Historically this was a custom ETL pipeline somebody on the team owned. In 2025&#8211;2026 it&#8217;s slowly becoming a vendor concern &#8212; Pinecone Nexus&#8217;s Context Compiler,<span> </span><strong><a href="https://mem0.ai/">Mem0</a></strong>&#8216;s dynamic memory extraction,<span> </span><strong><a href="https://www.letta.com/">Letta</a></strong>&#8216;s streaming-update primitives &#8212; but most enterprises still hand-roll it. This is the sub-problem most teams discover six months in.</p></li><li><p><strong>Retrieval.</strong><span> </span>How the right slice of the corpus shows up at the right moment &#8212; what gets pulled when the user asks<span> </span><em>&#8220;is acupuncture covered by my health plan?&#8221;</em>, and what gets ignored. Embedding-model choice (<strong><a href="https://platform.openai.com/docs/guides/embeddings">text-embedding-3-large</a></strong><span> </span>from OpenAI,<span> </span><strong><a href="https://cohere.com/blog/embed-4">Cohere Embed 4</a></strong>,<span> </span><strong><a href="https://www.voyageai.com/">Voyage 3</a></strong>) and reranker choice (<strong><a href="https://cohere.com/rerank">Cohere Rerank 3.5</a></strong>, Voyage Rerank) make most of the difference, with hybrid sparse-dense techniques (BM25 + vectors) and graph-augmented retrievers (<strong><a href="https://arxiv.org/abs/2410.05779">LightRAG</a></strong>,<span> </span><strong><a href="https://arxiv.org/abs/2409.13731">KAG</a></strong>) cleaning up the rest. Most &#8220;RAG isn&#8217;t working&#8221; conversations turn out to be retrieval conversations.</p></li><li><p><strong>Context construction.</strong><span> </span>How the retrieved material gets ordered, weighted, and packed into the model&#8217;s context window. The state of the art shifted twice in 2024&#8211;2025 &#8212; first with Anthropic&#8217;s<span> </span><em><strong><a href="https://www.anthropic.com/news/contextual-retrieval">Contextual Retrieval</a></strong></em><span> </span>(September 2024), which argued context construction is its own engineering discipline, then with Anthropic&#8217;s<span> </span><em><strong><a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents">Effective context engineering for AI agents</a></strong></em><span> </span>essay and the broader industry adoption of<span> </span><strong><a href="https://www.anthropic.com/news/prompt-caching">prompt caching</a></strong>, structured outputs, and (with Claude Managed Agents in April 2026) cross-session memory primitives. The model only sees what context construction decides to show it, so this step quietly governs the quality of every answer.</p></li></ul><p>The four are tightly coupled. A change in storage forces a change in retrieval. A change in retrieval breaks context construction. A change in update policy can quietly poison both. Teams that treat them as four separate engineering problems eat the cost of integrating them by accident.</p><h3><strong>Why it&#8217;s one discipline, not three</strong></h3><p>I want to argue that the knowledge layer is worth treating as<span> </span><strong>one engineering job</strong><span> </span>rather than three separate ones (RAG, memory, context engineering). Three reasons.</p><p>The first is that the failures cluster here. When agents fail in production, they fail because retrieval pulled the wrong document, because the corpus was stale, because the conversation history attributed a fact to the wrong session, or because the relevant chunk got drowned out by ten less-relevant chunks in a stuffed context window. These are different surface symptoms of the same underlying engineering problem: getting the right information in front of the model at the right moment.</p><p>The second is that the techniques compose. GraphRAG and a typed memory system aren&#8217;t alternatives; they&#8217;re tools you reach for at different points in the same pipeline. Treating each technique as a separate engineering investment is what produces the demo-to-production gap &#8212; the team ships RAG, finds it isn&#8217;t enough, layers on memory, finds that doesn&#8217;t fit either, plugs in a reranker, plugs in a graph, and the architecture quietly becomes a graveyard of half-finished plug-ins.</p><p>The third is that the discipline is recognizably different from prompting and from model choice. Prompting is<span> </span><em>how to talk to the model</em>. Model choice is<span> </span><em>which model to rent</em>. The knowledge layer is<span> </span><em>what does this model know about your business and how does it stay current</em>. Those are different jobs, and putting them in the same bucket &#8212; the way &#8220;let&#8217;s add RAG&#8221; used to be a complete project plan &#8212; is part of why so many enterprise agent projects stall a year in.</p><p>The industry has been converging on this view in public. Anthropic published<span> </span><em>Contextual Retrieval</em><span> </span>in September 2024, essentially an argument that context construction is its own engineering problem, not a free side-effect of dropping a vector store next to your prompt. Microsoft&#8217;s<span> </span><em><strong><a href="https://arxiv.org/abs/2404.16130">GraphRAG</a></strong></em><span> </span>paper, five months earlier, made the same case for structured knowledge. By the time Anthropic shipped<span> </span><strong>Claude Managed Agents</strong><span> </span>in April 2026 &#8212; multiagent orchestration, persistent state &#8212; and demoed cross-session &#8220;dreaming&#8221; at Code with Claude the following month, the knowledge layer wasn&#8217;t a side project anymore; it was the developer surface. The terminology and the products are converging fast. What&#8217;s still missing in most enterprise teams is the engineering culture around treating this as one coherent job rather than three plug-ins.</p><p>The model is the chef. The prompt is the recipe. The knowledge layer is the pantry &#8212; and the pantry is where most kitchens go wrong.</p><h3><strong>The three places it breaks</strong></h3><p>Three failure modes account for most of what kills enterprise agents in production. They show up across verticals, model choices, and frameworks.</p><p><strong>Stale corpus.</strong><span> </span>The data was right when it was loaded. Then a policy changed, a product was rebranded, a fee schedule was updated &#8212; and nobody told the retrieval system. The agent keeps citing the old version with full confidence because, from its perspective, the old version is the source of truth. The cost of this failure isn&#8217;t only the wrong answer; it&#8217;s that the user now has to fact-check the agent every time, which destroys the time-saving the agent was supposed to deliver in the first place.</p><p><strong>Wrong retrieval.</strong><span> </span>The right document exists in the corpus, but it didn&#8217;t surface for the user&#8217;s question. Maybe the question was phrased differently from how the document was written; maybe the embedding model &#8212; text-embedding-3-large, Cohere Embed 4, Voyage 3, take your pick &#8212; treats two semantically-related phrases as unrelated; maybe the chunking sliced the relevant passage in half. The agent then either falls back on the model&#8217;s pre-trained knowledge &#8212; which is generic and often wrong for your domain &#8212; or fabricates an answer from the closest-but-incorrect chunks it did manage to retrieve.</p><p><strong>Wrong context construction.</strong><span> </span>Retrieval surfaced the right chunk, but it was packed in among ten less-relevant chunks, or it was at the bottom of a long context window where models attend less, or the system prompt was so long that the retrieved content was effectively buried. The model had the right information in front of it and still gave the wrong answer because the context wasn&#8217;t constructed to let it see clearly.</p><p>The pattern across all three is that the model and the prompt were fine, and a smarter model or a cleaner prompt wouldn&#8217;t have helped. The fix is at the knowledge-layer level.</p><h3><strong>The map</strong></h3><p>Here&#8217;s how the four sub-problems compose into a pipeline.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1l8G!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52624a8e-23a1-4389-a014-7e373021d573_1488x851.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1l8G!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52624a8e-23a1-4389-a014-7e373021d573_1488x851.png 424w, https://substackcdn.com/image/fetch/$s_!1l8G!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52624a8e-23a1-4389-a014-7e373021d573_1488x851.png 848w, https://substackcdn.com/image/fetch/$s_!1l8G!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52624a8e-23a1-4389-a014-7e373021d573_1488x851.png 1272w, https://substackcdn.com/image/fetch/$s_!1l8G!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52624a8e-23a1-4389-a014-7e373021d573_1488x851.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1l8G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52624a8e-23a1-4389-a014-7e373021d573_1488x851.png" width="1456" height="833" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/52624a8e-23a1-4389-a014-7e373021d573_1488x851.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:833,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Article content&quot;,&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="Article content" title="Article content" srcset="https://substackcdn.com/image/fetch/$s_!1l8G!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52624a8e-23a1-4389-a014-7e373021d573_1488x851.png 424w, https://substackcdn.com/image/fetch/$s_!1l8G!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52624a8e-23a1-4389-a014-7e373021d573_1488x851.png 848w, https://substackcdn.com/image/fetch/$s_!1l8G!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52624a8e-23a1-4389-a014-7e373021d573_1488x851.png 1272w, https://substackcdn.com/image/fetch/$s_!1l8G!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52624a8e-23a1-4389-a014-7e373021d573_1488x851.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"></figcaption></figure></div><p>The interesting moves all happen along that horizontal axis: choosing a storage abstraction (vector store, typed graph, hybrid), choosing an update strategy (re-index, delta, event-driven), choosing a retrieval method (dense, sparse, hybrid, agentic), choosing a context construction policy (reranking, compression, structured assembly). The next nine articles in this series each go deep on one of those decision points.</p><h3><strong>The landscape</strong></h3><p>Before the techniques, here&#8217;s how to approximately position them mentally. Two axes do most of the work:</p><ul><li><p><strong>Horizontal &#8212; how structured the underlying knowledge is.</strong><span> </span>Raw vectors on the left (the semantic-similarity world), typed graphs and ontologies on the right (the relational world).</p></li><li><p><strong>Vertical &#8212; how much agency the system has at retrieval time.</strong><span> </span>A fixed pipeline at the bottom (the agent doesn&#8217;t decide what to fetch), an agentic loop at the top (the agent plans and refines retrieval as part of its reasoning).</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0lBD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0a153e-f77c-40e3-af66-241462c34d8f_1000x1000.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0lBD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0a153e-f77c-40e3-af66-241462c34d8f_1000x1000.png 424w, https://substackcdn.com/image/fetch/$s_!0lBD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0a153e-f77c-40e3-af66-241462c34d8f_1000x1000.png 848w, https://substackcdn.com/image/fetch/$s_!0lBD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0a153e-f77c-40e3-af66-241462c34d8f_1000x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!0lBD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0a153e-f77c-40e3-af66-241462c34d8f_1000x1000.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0lBD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0a153e-f77c-40e3-af66-241462c34d8f_1000x1000.png" width="1000" height="1000" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fe0a153e-f77c-40e3-af66-241462c34d8f_1000x1000.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1000,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Article content&quot;,&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="Article content" title="Article content" srcset="https://substackcdn.com/image/fetch/$s_!0lBD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0a153e-f77c-40e3-af66-241462c34d8f_1000x1000.png 424w, https://substackcdn.com/image/fetch/$s_!0lBD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0a153e-f77c-40e3-af66-241462c34d8f_1000x1000.png 848w, https://substackcdn.com/image/fetch/$s_!0lBD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0a153e-f77c-40e3-af66-241462c34d8f_1000x1000.png 1272w, https://substackcdn.com/image/fetch/$s_!0lBD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe0a153e-f77c-40e3-af66-241462c34d8f_1000x1000.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"></figcaption></figure></div><p>The axes are a loose synthesis of the architectural breakdown in the<span> </span><em>SoK: Agentic RAG</em><span> </span>paper (Mishra et al.,<span> </span><strong><a href="https://arxiv.org/abs/2603.07379">arxiv 2603.07379</a></strong>, March 2026) and the<span> </span><em>Agentic RAG Survey</em><span> </span>(Singh et al.,<span> </span><strong><a href="https://arxiv.org/abs/2501.09136">arxiv 2501.09136</a></strong>, revised April 2026), both of which organize current paradigms along similar structure-and-agency dimensions. The placements on the map aren&#8217;t precise &#8212; vendors move on it as they ship &#8212; but it&#8217;s the first thing I sketch when a team asks<span> </span><em>&#8220;where does our stack sit?&#8221;</em><span> </span>The most interesting movement in 2025&#8211;2026 has been<span> </span><strong>up and to the right</strong>: from naive RAG in the bottom-left to compiled knowledge engines and ontology-backed agent platforms in the top-right.</p><h3><strong>What this series will cover</strong></h3><p>Briefly, and not as a table of contents.</p><p>Articles 2&#8211;5 walk through the retrieval surface &#8212; naive RAG, advanced RAG (the production version with reranking, hybrid search, query rewriting), GraphRAG for when relationships matter more than similarity, and agentic RAG for when retrieval becomes a decision the agent makes rather than a pipeline it runs. Article 6 covers agent memory systems &#8212; Mem0, Letta,<span> </span><strong><a href="https://www.getzep.com/">Zep</a></strong>,<span> </span><strong><a href="https://langchain-ai.github.io/langmem/">LangMem</a></strong><span> </span>(the four-vendor landscape that consolidated through 2025&#8211;2026), plus research-side proposals like A-MEM and MemPalace &#8212; and the question of what kind of memory your agent actually needs. Article 7 is on context engineering, which I think is the discipline that quietly replaces prompt engineering for serious teams. Article 8 critiques knowledge editing &#8212; the model-weight-surgery techniques the academic world is excited about, and why they&#8217;re wrong for almost every enterprise update problem. Article 9 is on evaluation, the part most teams skip and most regret skipping. Article 10 is the practical selection guide: given your corpus, your update frequency, your latency budget, and your team&#8217;s depth, here&#8217;s what to actually build.</p><p>On the community and open-source side, the conversation has been just as alive &#8212; and worth keeping an eye on even if you don&#8217;t deploy any of these. Andrej Karpathy&#8217;s<span> </span><em><strong><a href="https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f">LLM Wiki</a></strong></em><strong><a href="https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f"><span> </span>gist</a></strong><span> </span>(April 2026) sketched a pattern for compounding personal knowledge that pre-compiles a maintained wiki of interlinked entity pages instead of re-retrieving raw chunks at query time.<span> </span><strong><a href="https://github.com/mempalace/mempalace">MemPalace</a></strong><span> </span>(April 2026) applied the ancient method-of-loci spatial metaphor to long-term memory and pulled 47k GitHub stars in two weeks, prompting a<span> </span><strong><a href="https://arxiv.org/abs/2604.21284">critical-analysis paper from Dey and Viradecha</a></strong><span> </span>that, fairly, attributed most of the retrieval performance to the underlying embeddings rather than the spatial metaphor.<span> </span><strong><a href="https://github.com/agiresearch/a-mem">A-MEM</a></strong><span> </span>(February 2025, AGI Research) extended the Zettelkasten idea into agentic memory with dynamic indexing. MAGMA (January 2026) experimented with multi-graph agentic memory. None of these are production stacks yet, but they&#8217;re where the next set of ideas tends to come from.</p><p>The articles can be read in isolation, but they reward being read in sequence.</p><h3><strong>What it costs you when you get this wrong</strong></h3><p>Rough numbers, because the buyer reading this needs them.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kRfr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78135306-5566-42a1-8225-eaa5a4be6c94_611x261.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kRfr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78135306-5566-42a1-8225-eaa5a4be6c94_611x261.png 424w, https://substackcdn.com/image/fetch/$s_!kRfr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78135306-5566-42a1-8225-eaa5a4be6c94_611x261.png 848w, https://substackcdn.com/image/fetch/$s_!kRfr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78135306-5566-42a1-8225-eaa5a4be6c94_611x261.png 1272w, https://substackcdn.com/image/fetch/$s_!kRfr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78135306-5566-42a1-8225-eaa5a4be6c94_611x261.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kRfr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78135306-5566-42a1-8225-eaa5a4be6c94_611x261.png" width="611" height="261" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/78135306-5566-42a1-8225-eaa5a4be6c94_611x261.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:261,&quot;width&quot;:611,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Article content&quot;,&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="Article content" title="Article content" srcset="https://substackcdn.com/image/fetch/$s_!kRfr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78135306-5566-42a1-8225-eaa5a4be6c94_611x261.png 424w, https://substackcdn.com/image/fetch/$s_!kRfr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78135306-5566-42a1-8225-eaa5a4be6c94_611x261.png 848w, https://substackcdn.com/image/fetch/$s_!kRfr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78135306-5566-42a1-8225-eaa5a4be6c94_611x261.png 1272w, https://substackcdn.com/image/fetch/$s_!kRfr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78135306-5566-42a1-8225-eaa5a4be6c94_611x261.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"></figcaption></figure></div><p>These are rough. I haven&#8217;t seen a team that escaped them by working harder on prompts.</p><h3><strong>The take</strong></h3><p>If you&#8217;re building agents and you&#8217;re spending most of your engineering effort on prompts and model selection, you&#8217;re working on roughly twenty percent of the problem. The other eighty percent &#8212; the part that decides whether your agent survives contact with real users and real data &#8212; lives in the knowledge layer. Get it right and the model and prompt choices become easy. Get it wrong and no amount of model upgrading or prompt tuning will save you.</p><p>The knowledge layer is the part of an agent system that decides reliability in production, and it&#8217;s an engineering discipline in its own right. That&#8217;s the claim the rest of this series defends.</p><p><em><strong><span>New articles land here first. Subscribe for the full series. I take on a small number of advisory engagements each year for teams hitting exactly these problems. The fastest way to reach me is on </span><a href="https://www.linkedin.com/in/ratko-nikolic/"><span data-color="#2adccb" style="color: rgb(42, 220, 203);">LinkedIn</span></a><span>; reach out if that&#8217;s you.</span></strong></em></p><h3><strong>What to read next</strong></h3><p><strong>This series:</strong></p><ul><li><p><strong><a href="https://ratkonikolic.substack.com/p/your-agents-problem-isnt-the-model">Article 1 &#8212; Your agent&#8217;s problem isn&#8217;t the model, it&#8217;s the knowledge layer</a></strong></p></li><li><p><strong><a href="https://www.linkedin.com/pulse/naive-rag-baseline-youll-always-benchmark-against-ratko-nikoli%C4%87-i7h0e/">Article 2</a> <a href="https://ratkonikolic.substack.com/p/naive-rag-the-baseline-youll-always">&#8212; Naive RAG: the baseline you&#8217;ll always benchmark against</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/advanced-rag-what-you-actually-run">Article 3 &#8212; Advanced RAG: what you actually run in production</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/graphrag-and-friends-when-entities">Article 4 &#8212; GraphRAG and friends: when entities and relationships beat similarity</a></strong></p></li><li><p><strong><a href="https://www.ratkonikolic.com/p/agentic-rag-when-retrieval-becomes">Article 5 &#8212; Agentic RAG: when retrieval becomes a decision, not a pipeline</a></strong></p></li><li><p><strong><a href="https://ratkonikolic.substack.com/p/vector-vs-graph-vs-episodic-a-tour">Article 6 &#8212; Vector vs graph vs episodic: a tour of agent memory systems</a></strong> </p></li><li><p>Article 7 &#8212; Context engineering: the discipline that replaces prompt engineering (<em>coming soon</em>)</p></li></ul><p><strong>External:</strong></p><ul><li><p>Lewis et al. (2020),<span> </span><em>Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks</em>.<span> </span><strong><a href="https://arxiv.org/abs/2005.11401">https://arxiv.org/abs/2005.11401</a></strong><span> </span>&#8212; the original RAG paper; useful background.</p></li><li><p>Edge et al. (April 2024),<span> </span><em>GraphRAG: A Graph-Based Approach to Retrieval-Augmented Generation</em>.<span> </span><strong><a href="https://arxiv.org/abs/2404.16130">https://arxiv.org/abs/2404.16130</a></strong><span> </span>&#8212; pioneer of &#8220;the knowledge layer needs structure&#8221; framing.</p></li><li><p>Anthropic (September 2024),<span> </span><em>Introducing Contextual Retrieval</em>.<span> </span><strong><a href="https://www.anthropic.com/news/contextual-retrieval">https://www.anthropic.com/news/contextual-retrieval</a></strong><span> </span>&#8212; the most cited industry write-up making the context-engineering case.</p></li><li><p>Anthropic Engineering (September 2025),<span> </span><em>Effective context engineering for AI agents</em>.<span> </span><strong><a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents">https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents</a></strong><span> </span>&#8212; the vendor-side &#8220;this is the discipline&#8221; essay, more practical than the 2024 piece.</p></li><li><p>Singh et al. (revised April 2026),<span> </span><em>Agentic Retrieval-Augmented Generation: A Survey on Agentic RAG</em>.<span> </span><strong><a href="https://arxiv.org/abs/2501.09136">https://arxiv.org/abs/2501.09136</a></strong><span> </span>&#8212; the canonical survey of where the retrieval-as-decision wave landed.</p></li><li><p>Du (March 2026),<span> </span><em>Memory for Autonomous LLM Agents: Mechanisms, Evaluation, and Emerging Frontiers</em>.<span> </span><strong><a href="https://arxiv.org/abs/2603.07670">https://arxiv.org/abs/2603.07670</a></strong><span> </span>&#8212; the current state-of-the-field write-up for the memory side.</p></li></ul>]]></content:encoded></item></channel></rss>