<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Milvus on Medium]]></title>
        <description><![CDATA[Stories by Milvus on Medium]]></description>
        <link>https://medium.com/@milvusio?source=rss-a31576809ee1------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*-VEGyAgcIBD62XtZWavy8w.png</url>
            <title>Stories by Milvus on Medium</title>
            <link>https://medium.com/@milvusio?source=rss-a31576809ee1------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 20 Jun 2026 05:58:05 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@milvusio/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Beyond the TurboQuant-RaBitQ Debate: Why Vector Quantization Matters for AI Infrastructure Costs]]></title>
            <link>https://milvusio.medium.com/beyond-the-turboquant-rabitq-debate-why-vector-quantization-matters-for-ai-infrastructure-costs-6334f01b58f4?source=rss-a31576809ee1------2</link>
            <guid isPermaLink="false">https://medium.com/p/6334f01b58f4</guid>
            <dc:creator><![CDATA[Milvus]]></dc:creator>
            <pubDate>Thu, 18 Jun 2026 10:28:38 GMT</pubDate>
            <atom:updated>2026-06-18T10:28:38.425Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F7ARipwk4jD7nOqE_UdehA.png" /></figure><p>Google’s TurboQuant paper (ICLR 2026) reported 6x KV cache compression with near-zero accuracy loss — results striking enough to wipe <a href="https://www.cnbc.com/2026/03/26/google-ai-turboquant-memory-chip-stocks-samsung-micron.html">$90 billion off memory chip stocks</a> in a single day. SK Hynix dropped 12%. Samsung dropped 7%.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*NNcl81gvNVNnuZPJ.png" /></figure><p>The paper quickly drew scrutiny. <a href="https://gaoj0017.github.io/">Jianyang Gao</a>, first author of <a href="https://dl.acm.org/doi/10.1145/3654970">RaBitQ</a> (SIGMOD 2024), <a href="https://medium.com/@gaojianyang0017/turboquant-and-rabitq-what-the-public-story-gets-wrong-23df83209c22">raised questions</a> about the relationship between TurboQuant’s methodology and his prior work on vector quantization. (We’ll be publishing a conversation with Dr. Gao soon — follow us if you’re interested.)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*SqyW7pVudHvxcQBD.png" /></figure><p>This article isn’t about taking sides in that discussion. What struck us is something bigger: the fact that a single <a href="https://milvus.io/docs/index-explained.md">vector quantization</a> paper could move $90 billion in market value tells you how critical this technology has become for AI infrastructure. Whether it’s compressing KV cache in inference engines or compressing indexes in <a href="https://zilliz.com/learn/what-is-vector-database">vector databases</a>, the ability to shrink high-dimensional data while preserving quality has enormous cost implications — and it’s a problem we’ve been working on, integrating RaBitQ into <a href="https://milvus.io/">Milvus</a> vector database and turning it into production infrastructure.</p><p>Here’s what we’ll cover: why vector quantization matters so much right now, how TurboQuant and RaBitQ compare, what RaBitQ is and how it works, the engineering work behind shipping it inside Milvus, and what the broader memory optimization landscape looks like for AI infrastructure.</p><h3>Why Does Vector Quantization Matter for Infrastructure Costs?</h3><p>Vector quantization is not new. What’s new is how urgently the industry needs it. Over the past two years, LLM parameters have ballooned, context windows have stretched from 4K to 128K+ tokens, and unstructured data — text, images, audio, video — has become a first-class input to AI systems. Every one of these trends creates more high-dimensional vectors that need to be stored, indexed, and searched. More vectors, more memory, more cost.</p><p>If you’re running vector search at scale — <a href="https://zilliz.com/learn/Retrieval-Augmented-Generation">RAG pipelines</a>, recommendation engines, multimodal retrieval — memory cost is likely one of your biggest infrastructure headache.</p><p>During model deployment, every major LLM inference stack relies on <a href="https://zilliz.com/glossary/kv-cache">KV cache</a> — storing previously computed key-value pairs so the attention mechanism doesn’t recompute them for every new token. It’s what makes O(n) inference possible instead of O(n²). Every framework from <a href="https://github.com/vllm-project/vllm">vLLM</a> to <a href="https://github.com/NVIDIA/TensorRT-LLM">TensorRT-LLM</a> depends on it. But KV cache can consume more GPU memory than the model weights themselves. Longer contexts, more concurrent users, and it spirals fast.</p><p>The same pressure hits vector databases — billions of high-dimensional vectors sitting in memory, each one a 32-bit float per dimension. Vector quantization compresses these vectors from 32-bit floats down to 4-bit, 2-bit, or even 1-bit representations — shrinking memory by 90% or more. Whether it’s KV cache in your inference engine or indexes in your vector database, the underlying math is the same, and the cost savings are real. That’s why a single paper reporting a breakthrough in this space moved $90 billion in stock market value.</p><h3>TurboQuant vs RaBitQ: What’s the Difference?</h3><p>Both TurboQuant and RaBitQ build on the same foundational technique: applying a random rotation (<a href="https://arxiv.org/abs/2406.03482">Johnson-Lindenstrauss transform</a>) to input vectors before quantization. This rotation transforms irregularly distributed data into a predictable uniform distribution, making it easier to quantize with low error.</p><p>Beyond that shared foundation, the two target different problems and take different approaches:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3urd8alj2-7pwNLS91Lw4A.png" /></figure><p>The key difference for practitioners: TurboQuant optimizes the transient KV cache inside an inference engine, while RaBitQ targets the persistent indexes that a vector database builds, shards, and queries across billions of vectors. For the rest of this article, we’ll focus on RaBitQ — the algorithm we’ve integrated and ship in production inside Milvus.</p><h3>What Is RaBitQ and What Does It Deliver?</h3><p>Here’s the bottom line first: on a 10-million vector dataset at 768 dimensions, RaBitQ compresses each vector to 1/32 of its original size while keeping recall above 94%. In Milvus, that translates to 3.6x higher query throughput than a full-precision index. This isn’t a theoretical projection — it’s a benchmark result from Milvus 2.6.</p><p>Now, how it gets there.</p><p>Traditional binary quantization compresses FP32 vectors to 1 bit per dimension — 32x compression. The tradeoff: recall collapses because you’ve thrown away too much information. <a href="https://arxiv.org/abs/2405.12497">RaBitQ</a> (Gao &amp; Long, SIGMOD 2024) keeps the same 32x compression but preserves the information that actually matters for search. An <a href="https://arxiv.org/abs/2409.09913">extended version</a> (Gao &amp; Long, SIGMOD 2025) proves this is asymptotically optimal, matching the theoretical lower bounds established by Alon &amp; Klartag (FOCS 2017).</p><h3>Why Do Angles Matter More Than Coordinates in High Dimensions?</h3><p>The key insight: in high dimensions, angles between vectors are more stable and informative than individual coordinate values. This is a consequence of measure concentration — the same phenomenon that makes Johnson-Lindenstrauss random projections work.</p><p>What this means in practice: you can discard the exact coordinate values of a high-dimensional vector and keep only its direction relative to the dataset. The angular relationships — which is what <a href="https://zilliz.com/glossary/anns">nearest-neighbor search</a> actually depends on — survive the compression.</p><h3>How Does RaBitQ Work?</h3><p>RaBitQ turns this geometric insight into three steps:</p><p>Step 1: Normalize. Center each vector relative to the dataset centroid and scale to unit length. This converts the problem to inner-product estimation between unit vectors — easier to analyze and bound.</p><p>Step 2: Random rotation + hypercube projection. Apply a random orthogonal matrix (a Johnson-Lindenstrauss-type rotation) to remove bias toward any axis. Project each rotated vector onto the nearest vertex of a {±1/√D}^D hypercube. Each dimension collapses to a single bit. The result: a D-bit binary code per vector.</p><p>Step 3: Unbiased distance estimation. Construct an estimator for the inner product between a query and the original (unquantized) vector. The estimator is provably unbiased with error bounded by O(1/√D). For 768-dimensional vectors, this keeps recall above 94%.</p><p>Distance computation between binary vectors reduces to bitwise AND + popcount — operations modern CPUs execute in a single cycle. This is what makes RaBitQ fast, not just small.</p><h3>Why Is RaBitQ Practical, Not Just Theoretical?</h3><ul><li>No training required. Apply the rotation, check signs. No iterative optimization, no codebook learning. Indexing time is comparable to <a href="https://milvus.io/docs/ivf-pq.md">product quantization</a>.</li><li>Hardware-friendly. Distance computation is bitwise AND + popcount. Modern CPUs (Intel IceLake+, AMD Zen 4+) have dedicated AVX512VPOPCNTDQ instructions. Single-vector estimation runs 3x faster than PQ lookup tables.</li><li>Multi-bit flexibility. The <a href="https://vectordb-ntu.github.io/RaBitQ-Library/">RaBitQ Library</a> supports variants beyond 1-bit: 4-bit achieves ~90% recall, 5-bit ~95%, 7-bit ~99% — all without reranking.</li><li>Composable. Plugs into existing index structures like <a href="https://milvus.io/docs/ivf-flat.md">IVF indexes</a> and <a href="https://milvus.io/docs/hnsw.md">HNSW graphs</a>, and works with FastScan for batch distance computation.</li></ul><h3>From Paper to Production: What We Built to Ship RaBitQ in Milvus</h3><p>The original RaBitQ code is a single-machine research prototype. Making it work across a <a href="https://milvus.io/docs/architecture_overview.md">distributed cluster</a> with sharding, failover, and real-time ingestion required solving four engineering problems. At <a href="https://zilliz.com/">Zilliz</a>, we went beyond simply implementing the algorithm — the work spanned engine integration, hardware acceleration, index optimization, and runtime tuning to turn RaBitQ into an industrial-grade capability inside Milvus. You can find more details in this blog as well: <a href="https://milvus.io/blog/bring-vector-compression-to-the-extreme-how-milvus-serves-3%C3%97-more-queries-with-rabitq.md">Bring Vector Compression to the Extreme: How Milvus Serves 3× More Queries with RaBitQ</a></p><h3>Making RaBitQ Distributed-Ready</h3><p>We integrated RaBitQ directly into <a href="https://github.com/milvus-io/knowhere">Knowhere</a>, Milvus’s core search engine — not as a plugin, but as a native index type with unified interfaces. It works with Milvus’s full distributed architecture: sharding, partitioning, dynamic scaling, and <a href="https://milvus.io/docs/manage-collections.md">collection management</a>.</p><p>The key challenge: making the quantization codebook (rotation matrix, centroid vectors, scaling parameters) segment-aware, so that each shard builds and stores its own quantization state. Index builds, compactions, and load-balancing all understand the new index type natively.</p><h3>Squeezing Every Cycle Out of Popcount</h3><p>RaBitQ’s speed comes from popcount — counting set bits in binary vectors. The algorithm is inherently fast, but how much throughput you get depends on how well you use the hardware. We built dedicated SIMD code paths for both dominant server architectures:</p><ul><li>x86 (Intel IceLake+ / AMD Zen 4+): AVX-512’s VPOPCNTDQ instruction computes popcount across multiple 512-bit registers in parallel. Knowhere’s inner loops are restructured to batch binary distance computations into SIMD-width chunks, maximizing throughput.</li><li>ARM (Graviton, Ampere): SVE (Scalable Vector Extension) instructions for the same parallel popcount pattern — critical since ARM instances are increasingly common in cost-optimized cloud deployments.</li></ul><h3>Eliminating Runtime Overhead</h3><p>RaBitQ needs auxiliary floating-point parameters at query time: the dataset centroid, per-vector norms, and the inner product between each quantized vector and its original (used by the distance estimator). Computing these per query adds latency. Storing the full original vectors defeats the purpose of compression.</p><p>Our solution: pre-compute and persist these parameters during index build, caching them alongside the binary codes. The memory overhead is small (a few floats per vector), but it eliminates per-query computation and keeps latency stable under high concurrency.</p><h3>IVF_RABITQ: The Index You Actually Deploy</h3><p>Starting with <a href="https://milvus.io/blog/introduce-milvus-2-6-built-for-scale-designed-to-reduce-costs.md">Milvus 2.6</a>, we ship <a href="https://milvus.io/docs/ivf-rabitq.md">IVF_RABITQ</a> — <a href="https://milvus.io/docs/ivf-flat.md">Inverted File Index</a> + RaBitQ quantization. The search works in two stages:</p><ol><li>Coarse search (IVF). K-means partitions the vector space into clusters. At query time, only the nprobe closest clusters are scanned.</li><li>Fine scoring (RaBitQ). Within each cluster, distances are estimated using 1-bit codes and the unbiased estimator. Popcount does the heavy lifting.</li></ol><p>The results on a 768-dimensional, 10-million vector dataset:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zqg6zIfQkmRbNEWu2bUQkQ.png" /></figure><p>For workloads that can’t tolerate even a 0.5% recall gap, the refine_type parameter adds a second scoring pass: SQ6, SQ8, FP16, BF16, or FP32. SQ8 is the common choice — it restores recall to IVF_FLAT levels at roughly 1/4 the original memory. You can also apply <a href="https://milvus.io/docs/ivf-sq8.md">scalar quantization</a> to the query side (SQ1–SQ8) independently, giving you two knobs to tune the latency-recall-cost tradeoff per workload.</p><h3>How Milvus Optimizes Memory Beyond Quantization</h3><p>RaBitQ is the most dramatic compression lever, but it’s one layer in a broader <a href="https://milvus.io/blog/milvus-26-preview-72-memory-reduction-without-compromising-recall-and-4x-faster-than-elasticsearch.md">memory optimization</a> stack:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AWawnAgdZX5H3gzSaxhJIw.png" /></figure><h3>Full-Stack Quantization</h3><p>RaBitQ’s 1-bit extreme compression isn’t the right fit for every workload. Milvus offers a complete quantization matrix: <a href="https://milvus.io/docs/ivf-sq8.md">SQ8</a> and <a href="https://milvus.io/docs/ivf-pq.md">product quantization (PQ)</a> for workloads that need a balanced precision-cost tradeoff, RaBitQ for maximum compression on ultra-large datasets, and hybrid configurations that combine multiple methods for fine-grained control.</p><h3>Index Structure Optimization</h3><p>Beyond quantization, Milvus continuously optimizes memory overhead in its core index structures. For <a href="https://milvus.io/docs/hnsw.md">HNSW</a>, we reduced adjacency list redundancy to lower per-graph memory usage. <a href="https://milvus.io/docs/diskann.md">DiskANN</a> pushes both vector data and index structures to SSD, dramatically reducing DRAM dependency for large datasets. We also optimized intermediate memory allocation during index building to prevent OOM failures when building indexes over datasets that approach node memory limits.</p><h3>Smart Memory Loading</h3><p>Milvus’s <a href="https://milvus.io/docs/mmap.md">mmap</a> (memory-mapped I/O) support maps vector data to disk files, relying on the OS page cache for on-demand loading — no need to load all data into memory at startup. Combined with lazy loading and segmented loading strategies that prevent sudden memory spikes, this enables smooth operation with TB-scale vector datasets at a fraction of the memory cost.</p><h3>Tiered Storage</h3><p>Milvus’s <a href="https://milvus.io/docs/tiered-storage-overview.md">three-tier storage architecture</a> spans memory, SSD, and object storage: hot data stays in memory for low latency, warm data is cached on SSD for a balance of performance and cost, and cold data sinks to object storage to minimize overhead. The system handles data scheduling automatically — no application-layer changes required.</p><h3>Cloud-Native Scaling</h3><p>Under Milvus’s <a href="https://milvus.io/docs/architecture_overview.md">distributed architecture</a>, data sharding and load balancing prevent single-node memory overload. Memory pooling reduces fragmentation and improves utilization. <a href="https://zilliz.com/cloud">Zilliz Cloud</a> (fully managed Milvus) takes this further with elastic scheduling for on-demand memory scaling — in Serverless mode, idle resources are automatically released, further reducing total cost of ownership.</p><h3>How These Layers Compound</h3><p>These optimizations aren’t alternatives — they stack. RaBitQ shrinks the vectors. DiskANN keeps the index on SSD. Mmap avoids loading cold data into memory. <a href="https://milvus.io/blog/milvus-tiered-storage-80-less-vector-search-cost-with-on-demand-hot%E2%80%93cold-data-loading.md">Tiered storage</a> pushes archival data to object storage. The result: a deployment serving billions of vectors doesn’t need billions-of-vectors worth of RAM.</p><h3>Get Started</h3><p>As AI data volumes continue to grow, vector database efficiency and cost will directly determine how far AI applications can scale. We’ll continue investing in high-performance, low-cost vector infrastructure — so that more AI applications can move from prototype to production.</p><p><a href="https://github.com/milvus-io/milvus">Milvus</a> is open source. To try IVF_RABITQ:</p><ul><li>Check the <a href="https://milvus.io/docs/ivf-rabitq.md">IVF_RABITQ documentation</a> for configuration and tuning guidance.</li><li>Read the full <a href="https://milvus.io/blog/bring-vector-compression-to-the-extreme-how-milvus-serves-3%C3%97-more-queries-with-rabitq.md">RaBitQ integration blog post</a> for deeper benchmarks and implementation details.</li><li>Join the <a href="https://slack.milvus.io/">Milvus Slack community</a> to ask questions and learn from other developers.</li><li><a href="https://milvus.io/office-hours">Book a free Milvus Office Hours session</a> to walk through your use case.</li></ul><p>If you’d rather skip infrastructure setup, <a href="https://cloud.zilliz.com/signup">Zilliz Cloud</a> (fully managed Milvus) offers a free tier with IVF_RABITQ support.</p><p>We’re running an upcoming interview with Professor <a href="https://personal.ntu.edu.sg/c.long/">Cheng Long</a> (NTU, VectorDB@NTU) and <a href="https://gaoj0017.github.io/">Dr. Jianyang Gao</a> (ETH Zurich), the first author of RaBitQ, where we’ll go deeper into vector quantization theory and what’s next. Drop your questions in the comments.</p><h3>Frequently Asked Questions</h3><h3>What are TurboQuant and RaBitQ?</h3><p>TurboQuant (Google, ICLR 2026) and RaBitQ (Gao &amp; Long, SIGMOD 2024) are both vector quantization methods that use random rotation to compress high-dimensional vectors. TurboQuant targets KV cache compression in LLM inference, while RaBitQ targets persistent vector indexes in databases. Both have contributed to the current wave of interest in vector quantization, though they solve different problems for different systems.</p><h3>How does RaBitQ achieve 1-bit quantization without destroying recall?</h3><p>RaBitQ exploits measure concentration in high-dimensional spaces: the angles between vectors are more stable than individual coordinate values as dimensionality increases. It normalizes vectors relative to the dataset centroid, then projects each one onto the nearest vertex of a hypercube (reducing each dimension to a single bit). An unbiased distance estimator with a provable error bound keeps search accurate despite the compression.</p><h3>What is IVF_RABITQ and when should I use it?</h3><p>IVF_RABITQ is a vector index type in Milvus (available since version 2.6) that combines inverted file clustering with RaBitQ 1-bit quantization. It achieves 94.7% recall at 3.6x the throughput of IVF_FLAT, with memory usage at roughly 1/32 of the original vectors. Use it when you need to serve large-scale vector search (millions to billions of vectors) and memory cost is a primary concern — common in RAG, recommendation, and multimodal search workloads.</p><h3>How does vector quantization relate to KV cache compression in LLMs?</h3><p>Both problems involve compressing high-dimensional floating-point vectors. KV cache stores key-value pairs from the Transformer attention mechanism; at long context lengths, it can exceed the model weights in memory usage. Vector quantization techniques like RaBitQ reduce these vectors to lower-bit representations. The same mathematical principles — measure concentration, random rotation, unbiased distance estimation — apply whether you’re compressing vectors in a database index or in an inference engine’s KV cache.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6334f01b58f4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Is MCP Dead? What We Learned Building with MCP, CLI, and Agent Skills]]></title>
            <link>https://milvusio.medium.com/is-mcp-dead-what-we-learned-building-with-mcp-cli-and-agent-skills-0f7abb305ff3?source=rss-a31576809ee1------2</link>
            <guid isPermaLink="false">https://medium.com/p/0f7abb305ff3</guid>
            <dc:creator><![CDATA[Milvus]]></dc:creator>
            <pubDate>Thu, 18 Jun 2026 10:24:46 GMT</pubDate>
            <atom:updated>2026-06-18T10:24:46.598Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*C2jG1TVTAsc6UGo5r_iEtw.png" /></figure><p>When Perplexity’s CTO Denis Yarats said at ASK 2026 that the company was deprioritizing MCP internally, it set off the usual cycle. YC CEO Garry Tan piled on — MCP eats too much context window, auth is broken, he built a CLI replacement in 30 minutes. Hacker News ran strongly anti-MCP.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/630/0*wHi8bzaPrgeXVqgE.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Oj2a0ISZ3n2SvTz0.png" /></figure><p>A year ago, this level of public skepticism would have been unusual. Model Context Protocol (MCP) was positioned as the definitive standard for <a href="https://zilliz.com/glossary/ai-agents">AI agent</a> tool integration. Server counts were doubling weekly. The pattern since then has followed a familiar arc: rapid hype, broad adoption, then production disillusionment.</p><p>The industry is responding fast. Bytedance’s Lark/Feishu open-sourced their official CLI — 200+ commands across 11 business domains with 19 built-in Agent Skills. Google shipped gws for Google Workspace. The CLI + Skills pattern is quickly becoming the default for enterprise agent tooling, not a niche alternative.</p><p>At Zilliz, we’ve released <a href="https://docs.zilliz.com/reference/cli/overview">Zilliz CLI</a>, which lets you operate and manage <a href="https://milvus.io/intro">Milvus</a> and <a href="https://zilliz.com/cloud">Zilliz Cloud</a> (fully managed Milvus) directly from your terminal without leaving your coding environment. On top of that, we built <a href="https://milvus.io/docs/milvus_for_agents.md">Milvus Skills</a> and <a href="https://docs.zilliz.com/docs/agents/zilliz-skill">Zilliz Skill</a>s so that AI coding agents like Claude Code and Codex can manage your <a href="https://zilliz.com/learn/what-is-vector-database">vector database</a> through natural language.</p><p>We also built an MCP server for Milvus and Zilliz Cloud one year ago. That experience taught us exactly where MCP breaks down — and where it still fits. Three architectural limitations pushed us toward CLI and Skills: context window bloat, passive tool design, and the inability to reuse the agent’s own LLM.</p><p>In this post, we’ll walk through each problem, show what we’re building instead, and lay out a practical framework for choosing between MCP, CLI, and Agent Skills.</p><h3>MCP Eats 72% of Your Context Window at Startup</h3><p>A standard MCP setup can consume around 72% of your available context window before the agent takes a single action. Connect three servers — GitHub, Playwright, and an IDE integration — on a 200K-token model, and tool definitions alone occupy roughly 143K tokens. The agent hasn’t done anything yet. It’s already three-quarters full.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*NG2b-QdKBOLj5yHC.png" /></figure><p>The cost isn’t just tokens. The more unrelated content packed into context, the weaker the model’s focus on what actually matters. A hundred tool schemas sitting in context means the agent wades through all of them on every decision. Researchers have documented what they call <em>context rot</em> — degraded reasoning quality from context overload. In measured tests, tool selection accuracy dropped from 43% to below 14% as tool count increased. More tools, paradoxically, means worse tool use.</p><p>The root cause is architectural. MCP loads all tool descriptions in full at session start, regardless of whether the current conversation will ever use them. That’s a protocol-level design choice, not a bug — but the cost scales with every tool you add.</p><p>Agent skills take a different approach: progressive disclosure. At session start, an agent reads only each Skill’s metadata — name, one-line description, trigger condition. A few dozen tokens total. The full Skill content loads only when the agent determines it’s relevant. Think of it this way: MCP lines up every tool at the door and makes you choose; Skills gives you an index first, full content on demand.</p><p>CLI tools offer a similar advantage. An agent runs git — help or docker — help to discover capabilities on demand, without preloading every parameter definition. Context cost is pay-as-you-go, not upfront.</p><p>At a small scale, the difference is negligible. At production scale, it’s the difference between an agent that works and one that drowns in its own tool definitions.</p><h3>MCP’s Passive Architecture Limits Agent Workflows</h3><p>MCP is a tool-calling protocol: how to discover tools, call them, and receive results. Clean design for simple use cases. But that cleanness is also a constraint.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6sw6bq6QUYvo94cw.png" /></figure><h3>Flat Tool Space with No Hierarchy</h3><p>An MCP tool is a flat function signature. No subcommands, no awareness of session lifecycle, no sense of where the agent is in a multi-step workflow. It waits to be called. That’s all it does.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*zthoKHyJjXXLK-Bq.png" /></figure><p>A CLI works differently. git commit, git push, and git log are completely different execution paths sharing a single interface. An agent runs — help, explores the available surface incrementally, and expands only what it needs — without front-loading all the parameter documentation into context.</p><h3>Skills Encode Workflow Logic — MCP Can’t</h3><p>An Agent Skill is a Markdown file containing a standard operating procedure: what to do first, what to do next, how to handle failures, and when to surface something to the user. The agent receives not just a tool but an entire workflow. Skills actively shape how an agent behaves during a conversation — what triggers them, what they prepare in advance, and how they recover from errors. MCP tools can only wait.</p><h3>MCP Can’t Access the Agent’s LLM</h3><p>This is the limitation that actually stopped us.</p><p>When we built <a href="https://github.com/zilliztech/claude-context">claude-context</a> — an MCP plugin that adds <a href="https://zilliz.com/glossary/semantic-search">semantic search</a> to Claude Code and other AI coding agents, giving them deep context from an entire codebase — we wanted to retrieve relevant historical conversation snippets from Milvus and surface them as context. The <a href="https://zilliz.com/learn/vector-similarity-search">vector search</a> retrieval worked. The problem was what to do with the results.</p><p>Retrieve the top 10 results, and maybe 3 are useful. The other 7 are noise. Hand all 10 to the outer agent, and the noise interferes with the answer. In testing, we saw responses get distracted by irrelevant historical records. We needed to filter before passing results up.</p><p>We tried several approaches. Adding a reranking step inside the MCP server using a small model: not accurate enough, and the relevance threshold needed per-use-case tuning. Using a large model for reranking: technically sound, but an MCP server runs as a separate process with no access to the outer agent’s LLM. We’d have to configure a separate LLM client, manage a separate API key, and handle a separate call path.</p><p>What we wanted was simple: let the outer agent’s LLM participate directly in the filtering decision. Retrieve the top 10, let the agent itself judge what’s worth keeping, and return only the relevant results. No second model. No extra API keys.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*tou8Bt7VhHxj4Jtq.png" /></figure><p>MCP can’t do this. The process boundary between server and agent is also an intelligence boundary. The server can’t use the agent’s LLM; the agent can’t govern what happens inside the server. Fine for simple CRUD tools. The moment a tool needs to make a judgment call, that isolation becomes a real constraint.</p><p>An Agent Skill solves this directly. A retrieval Skill can call vector search for the top 10, have the agent’s own LLM assess relevance, and return only what passes. No additional model. The agent does the filtering itself.</p><h3>What We Built Instead with CLI and Skills</h3><p>We see CLI + Skills as the direction for agent-tool interaction — not just for memory retrieval, but across the stack. This conviction drives everything we’re building.</p><h3>memsearch: A Skills-Based Memory Layer for AI Agents</h3><p>We built <a href="https://github.com/zilliztech/memsearch">memsearch</a>, an open-source memory layer for Claude Code and other AI agents. The Skill runs inside a subagent with three stages: Milvus handles the initial vector search for broad discovery, the agent’s own LLM evaluates relevance and expands context for promising hits, and a final drill-down accesses original conversations only when needed. Noise gets discarded at each stage — intermediate retrieval junk never reaches the primary context window.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*bUo_9WGOZaC-oqq7.png" /></figure><p>The key insight: the agent’s intelligence is part of the tool’s execution. The LLM already in the loop does the filtering — no second model, no extra API key, no brittle threshold tuning. This is a specific use case — conversation-context retrieval for coding agents — but the architecture generalizes to any scenario where a tool needs judgment, not just execution.</p><h3>Zilliz CLI, Skills, and Plugin for Vector Database Operations</h3><p>Milvus is the world’s most widely adopted open-source vector database with <a href="https://github.com/milvus-io/milvus">43K+ stars on GitHub</a>. <a href="https://zilliz.com/cloud">Zilliz Cloud</a> is the fully managed service of Milvus with advanced enterprise features and is much faster than Milvus.</p><p>The same layered architecture mentioned above drives our developer tools:</p><ul><li><a href="https://docs.zilliz.com/reference/cli/overview">Zilliz CLI</a> is the infrastructure layer. Cluster management, <a href="https://milvus.io/docs/manage-collections.md">collection operations</a>, vector search, <a href="https://milvus.io/docs/rbac.md">RBAC</a>, backups, billing — everything you’d do in the Zilliz Cloud console, available from the terminal. Humans and agents use the same commands. Zilliz CLI also serves as the foundation for Milvus Skills and Zilliz Skills.</li><li><a href="https://milvus.io/docs/milvus_for_agents.md">Milvus Skill</a> is the knowledge layer for open-source Milvus. It teaches AI coding agents (Claude Code, Cursor, Codex, GitHub Copilot) to operate any Milvus deployment — <a href="https://milvus.io/docs/milvus_lite.md">Milvus Lite</a>, Standalone, or Distributed — through <a href="https://milvus.io/docs/install-pymilvus.md">pymilvus</a> Python code: connections, <a href="https://milvus.io/docs/schema-hands-on.md">schema design</a>, CRUD, <a href="https://zilliz.com/learn/hybrid-search-with-milvus">hybrid search</a>, <a href="https://milvus.io/docs/full-text-search.md">full-text search</a>, <a href="https://zilliz.com/learn/Retrieval-Augmented-Generation">RAG pipelines</a>.</li><li><a href="https://docs.zilliz.com/docs/agents/zilliz-skill">Zilliz Skill</a> does the same for Zilliz Cloud, teaching agents to manage cloud infrastructure through Zilliz CLI.</li><li><a href="https://github.com/zilliztech/zilliz-plugin">Zilliz Plugin</a> is the developer experience layer for Claude Code — wraps CLI + Skill into a guided experience with slash commands like /zilliz:quickstart and /zilliz:status.</li></ul><p>CLI handles execution, Skills encode knowledge and workflow logic, Plugin delivers the UX. No MCP server in the loop.</p><p>For more details, check out these resources:</p><ul><li><a href="https://zilliz.com/blog/introducing-zilliz-cli-and-agent-skills-for-zilliz-cloud">Introducing Zilliz CLI and Agent Skills for Zilliz Cloud</a></li><li><a href="https://zilliz.com/blog/zilliz-cloud-just-landed-in-claude-code">Zilliz Cloud Just Landed in Claude Code</a></li><li><a href="https://docs.zilliz.com/docs/agents/zilliz-ai-prompts">AI Prompts — Zilliz Cloud Developer Hub</a></li><li><a href="https://docs.zilliz.com/reference/cli/overview">Zilliz CLI Reference — Zilliz Cloud Developer Hub</a></li><li><a href="https://docs.zilliz.com/docs/agents/zilliz-skill">Zilliz Skill — Zilliz Cloud Developer Hub</a></li><li><a href="https://milvus.io/docs/milvus_for_agents.md">Milvus for AI Agents — Milvus Documentation</a></li></ul><h3>Is MCP Actually Dying?</h3><p>A lot of developers and companies including us here at Zilliz are turning to CLI and Skills. But is MCP really dying?</p><p>The short answer: no — but its scope is narrowing to where it actually fits.</p><p>MCP has been donated to the Linux Foundation. Active servers number over 10,000. SDK monthly downloads sit at 97 million. An ecosystem that size doesn’t disappear because of a conference comment.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*t4hmeb4SH9k5h5OU.png" /></figure><p>A Hacker News thread — <em>“When does MCP make sense vs CLI?”</em> — drew responses that mostly favored CLI: “CLI tools are like precision instruments,” “CLIs also feel snappier than MCPs.” Some developers hold a more balanced view: Skills are a detailed recipe that helps you solve a problem better; MCP is the tool that helps you solve the problem. Both have their place.</p><p>That’s fair — but it raises a practical question. If the recipe itself can direct the agent on which tools to use and how, is a separate tool-distribution protocol still necessary?</p><p>It depends on the use case.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*TNQ-fLt8ng3126f7.png" /></figure><p>MCP over stdio — the version most developers run locally — is where the problems accumulate: unstable inter-process communication, messy environment isolation, high token overhead. In that context, better alternatives exist for almost every use case.</p><p>MCP over HTTP is a different story. Enterprise internal tooling platforms need centralized permission management, unified OAuth, standardized telemetry and logging. Fragmented CLI tools genuinely struggle to provide these. MCP’s centralized architecture has real value in that context.</p><p>What Perplexity actually dropped was primarily the stdio use case. Denis Yarats specified “internally” and didn’t call for industry-wide adoption of that choice. That nuance got lost in transmission — “Perplexity abandons MCP” spreads considerably faster than “Perplexity deprioritizes MCP over stdio for internal tool integration.”</p><p>MCP emerged because it solved a real problem: before it, every AI application wrote its own tool-calling logic, with no shared standard. MCP provided a unified interface at the right moment, and the ecosystem built quickly. Production experience then surfaced the limitations. That’s a normal arc for infrastructure tooling — not a death sentence.</p><h3>When to Use MCP, CLI, or Skills</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cjS90V1MELmA48UM3nXYUw.png" /></figure><p>or teams choosing their <a href="https://zilliz.com/glossary/ai-agents">agentic AI</a> tooling stack, here’s how the layers fit:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0_7kRk5cmaTUPf2CX8N81A.png" /></figure><h3>Get Started</h3><p>Everything we’ve discussed in this article is available today:</p><ul><li><a href="https://github.com/zilliztech/memsearch">memsearch</a> — the Skills-based memory layer for AI agents. Drop it into Claude Code or any agent that supports Skills.</li><li><a href="https://docs.zilliz.com/reference/cli/overview">Zilliz CLI</a> — manage Milvus and Zilliz Cloud from your terminal. Install it and explore the subcommands your agents can use.</li><li><a href="https://milvus.io/docs/milvus_for_agents.md">Milvus Skill</a> and <a href="https://docs.zilliz.com/docs/agents/zilliz-skill">Zilliz Skill</a> — give your AI coding agent native Milvus and Zilliz Cloud knowledge.</li></ul><p>Have questions about vector search, agent architecture, or building with CLI and Skills? Join the <a href="https://discord.com/invite/8uyFbECzPX">Milvus Discord community</a> or <a href="https://milvus.io/office-hours">book a free Office Hours session</a> to talk through your use case.</p><p>Ready to build? <a href="https://cloud.zilliz.com/signup">Sign up for Zilliz Cloud</a> — new accounts with a work email get $100 in free credits. Already have an account? <a href="https://cloud.zilliz.com/login">Sign in here</a>.</p><h3>Frequently Asked Questions</h3><h3>What is wrong with MCP for AI agents?</h3><p>MCP has three main architectural limitations in production. First, it loads all tool schemas into the context window at session start — connecting just three MCP servers on a 200K-token model can consume over 70% of available context before the agent does anything. Second, MCP tools are passive: they wait to be called and can’t encode multi-step workflows, error-handling logic, or standard operating procedures. Third, MCP servers run as separate processes with no access to the agent’s LLM, so any tool that needs judgment (like filtering search results for relevance) requires configuring a separate model with its own API key. These problems are most acute with MCP over stdio; MCP over HTTP mitigates some of them.</p><h3>What is the difference between MCP and Agent Skills?</h3><p>MCP is a tool-calling protocol that defines how an agent discovers and invokes external tools. An Agent Skill is a Markdown file containing a full standard operating procedure — triggers, step-by-step instructions, error handling, and escalation rules. The key architectural difference: Skills run inside the agent’s process, so they can leverage the agent’s own LLM for judgment calls like relevance filtering or result reranking. MCP tools run in a separate process and can’t access the agent’s intelligence. Skills also use progressive disclosure — only lightweight metadata loads at startup, with full content loading on demand — keeping context window usage minimal compared to MCP’s upfront schema loading.</p><h3>When should I still use MCP instead of CLI or Skills?</h3><p>MCP over HTTP still makes sense for enterprise tooling platforms where you need centralized OAuth, role-based access control, standardized telemetry, and audit logging across many internal tools. Fragmented CLI tools struggle to provide these enterprise requirements consistently. For local development workflows — where agents interact with tools on your machine — CLI + Skills typically offers better performance, lower context overhead, and more flexible workflow logic than MCP over stdio.</p><h3>How do CLI tools and Agent Skills work together?</h3><p>CLI provides the execution layer (the actual commands), while Skills provide the knowledge layer (when to run which commands, in what order, and how to handle failures). For example, Zilliz CLI handles infrastructure operations like cluster management, collection CRUD, and vector search. Milvus Skill teaches the agent the right pymilvus patterns for schema design, hybrid search, and RAG pipelines. The CLI does the work; the Skill knows the workflow. This layered pattern — CLI for execution, Skills for knowledge, a plugin for UX — is how we’ve structured all of our developer tooling at Zilliz.</p><h3>MCP vs Skills vs CLI: when should I use each?</h3><p>CLI tools like git, docker, or zilliz-cli are best for operational tasks — they expose hierarchical subcommands and load on demand. Skills like milvus-skill are best for agent workflow logic — they carry operating procedures, error recovery, and can access the agent’s LLM. MCP over HTTP still fits enterprise tool platforms needing centralized OAuth, permissions, and audit logging. MCP over stdio — the local version — is being replaced by CLI + Skills in most production setups.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0f7abb305ff3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Harness Engineering: The Execution Layer AI Agents Actually Need]]></title>
            <link>https://milvusio.medium.com/harness-engineering-the-execution-layer-ai-agents-actually-need-c3896359917d?source=rss-a31576809ee1------2</link>
            <guid isPermaLink="false">https://medium.com/p/c3896359917d</guid>
            <dc:creator><![CDATA[Milvus]]></dc:creator>
            <pubDate>Wed, 17 Jun 2026 09:22:05 GMT</pubDate>
            <atom:updated>2026-06-17T09:22:05.835Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FQlPeeCrsOkcFpphr8XWRQ.png" /></figure><p>Mitchell Hashimoto built HashiCorp and co-created Terraform. In February 2026, he published a <a href="https://mitchellh.com/writing/my-ai-adoption-journey">blog post</a> describing a habit he’d developed while working with AI agents: every time an agent made a mistake, he engineered a permanent fix into the agent’s environment. He called it “engineering the harness.” Within weeks, <a href="https://openai.com/index/harness-engineering/">OpenAI</a> and <a href="https://www.anthropic.com/engineering/harness-design-long-running-apps">Anthropic</a> published engineering articles expanding on the idea. The term <em>Harness Engineering</em> had arrived.</p><p>It resonated because it names a problem every engineer building <a href="https://zilliz.com/glossary/ai-agents">AI agents</a> has already hit. <a href="https://zilliz.com/glossary/prompt-as-code-(prompt-engineering)">Prompt engineering</a> gets you better single-turn outputs. Context engineering manages what the model sees. But neither addresses what happens when an agent runs autonomously for hours, making hundreds of decisions without supervision. That’s the gap Harness Engineering fills — and it almost always depends on hybrid search (hybrid full-text and semantic search) to work.</p><h3>What Is Harness Engineering?</h3><p>Harness Engineering is the discipline of designing the execution environment around an autonomous AI agent. It defines which tools the agent can call, where it gets information, how it validates its own decisions, and when it should stop.</p><p>To understand why it matters, consider three layers of AI agent development:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VbifYy1XXzNmK3JBi8WC0Q.png" /></figure><p>Prompt Engineering optimizes the quality of a single exchange — phrasing, structure, examples. One conversation, one output.</p><p>Context Engineering manages how much information the model can see at once — which documents to retrieve, how to compress history, what fits in the context window and what gets dropped.</p><p>Harness Engineering builds the world the agent operates in. Tools, knowledge sources, validation logic, architectural constraints — everything that determines whether an agent can run reliably across hundreds of decisions without human supervision.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ohA-1N54pkjKtF-q.png" /></figure><p>Three layers of AI agent development: Prompt Engineering optimizes what you say, Context Engineering manages what the model sees, and Harness Engineering designs the execution environment</p><p>The first two layers shape the quality of a single turn. The third shapes whether an agent can operate for hours without you watching.</p><p>These aren’t competing approaches. They’re a progression. As agent capability grows, the same team moves through all three — often within a single project.</p><h3>How OpenAI Used Harness Engineering to Build a Million-Line Codebase and Lessons They Learnt</h3><p>OpenAI ran an internal experiment that puts Harness Engineering in concrete terms. They described it in their engineering blog post, <a href="https://openai.com/index/harness-engineering/">“Harness Engineering: Leveraging Codex in an Agent-First World”</a>. A three-person team started with an empty repository in late August 2025. For five months, they wrote no code themselves — every line was generated by Codex, OpenAI’s AI-powered coding agent. The result: one million lines of production code and 1,500 merged pull requests.</p><p>The interesting part isn’t the output. It’s the four problems they hit and the harness-layer solutions they built.</p><h3>Problem 1: No Shared Understanding of the Codebase</h3><p>What abstraction layer should the agent use? What are the naming conventions? Where did last week’s architecture discussion land? Without answers, the agent guessed — and guessed wrong — repeatedly.</p><p>The first instinct was a single AGENTS.md file containing every convention, rule, and historical decision. It failed for four reasons. Context is scarce, and a bloated instruction file crowded out the actual task. When everything is marked important, nothing is. Documentation rots — rules from week two become wrong by week eight. And a flat document can’t be mechanically verified.</p><p>The fix: shrink AGENTS.md to 100 lines. Not rules — a map. It points to a structured docs/ directory containing design decisions, execution plans, product specs, and reference docs. Linters and CI verify that cross-links stay intact. The agent navigates to exactly what it needs.</p><p>The underlying principle: if something isn’t in context at runtime, it doesn’t exist for the agent.</p><h3>Problem 2: Human QA Couldn’t Keep Pace with Agent Output</h3><p>The team plugged Chrome DevTools Protocol into Codex. The agent could screenshot UI paths, observe runtime events, and query logs with LogQL and metrics with PromQL. They set a concrete threshold: a service had to start in under 800 milliseconds before a task was considered complete. Codex tasks ran for over six hours at a stretch — typically while engineers slept.</p><h3>Problem 3: Architectural Drift Without Constraints</h3><p>Without guardrails, the agent reproduced whatever patterns it found in the repo — including bad ones.</p><p>The fix: strict layered architecture with a single enforced dependency direction — Types → Config → Repo → Service → Runtime → UI. Custom linters enforced these rules mechanically, with error messages that included the fix instruction inline.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*0t9c3zfJjqnHA1le.png" /></figure><p>Strict layered architecture with one-way dependency validation: Types at the base, UI at the top, custom linters enforce rules with inline fix suggestions</p><p>In a human team, this constraint usually arrives when a company scales to hundreds of engineers. For a coding agent, it’s a prerequisite from day one. The faster an agent moves without constraints, the worse the architectural drift.</p><h3>Problem 4: Silent Technical Debt</h3><p>The solution: encode the project’s core principles into the repository, then run background Codex tasks on a schedule to scan for deviations and submit refactoring PRs. Most merged automatically within a minute — small continuous payments rather than periodic reckoning.</p><h3>Why AI Agents Can’t Grade Their Own Work</h3><p>OpenAI’s experiment proved Harness Engineering works. But separate research exposed a failure mode inside it: agents are systematically bad at evaluating their own output.</p><p>The problem appears in two forms.</p><p>Context anxiety. As the context window fills, agents begin wrapping up tasks prematurely — not because the work is done, but because they sense the window limit approaching. Cognition, the team behind the AI coding agent Devin, <a href="https://cognition.ai/blog/devin-sonnet-4-5-lessons-and-challenges">documented this behavior</a> while rebuilding Devin for Claude Sonnet 4.5: the model became aware of its own context window and started taking shortcuts well before actually running out of room.</p><p>Their fix was pure harness engineering. They enabled the 1M-token context beta but capped actual usage at 200K tokens — tricking the model into believing it had ample runway. The anxiety vanished. No model change required; just a smarter environment.</p><p>The most common general mitigation is compaction: summarize history and let the same agent continue with compressed context. This preserves continuity but doesn’t eliminate the underlying behavior. An alternative is context reset: clear the window, spin up a fresh instance, and hand off state through a structured artifact. This removes the anxiety trigger entirely but demands a complete handoff document — gaps in the artifact mean gaps in the new agent’s understanding.</p><p>Self-evaluation bias. When agents assess their own output, they score it high. Even on tasks with objective pass/fail criteria, the agent spots a problem, talks itself into believing it’s not serious, and approves work that should fail.</p><p>The fix borrows from GANs (Generative Adversarial Networks): separate the generator from the evaluator completely. In a GAN, two neural networks compete — one generates, one judges — and that adversarial tension forces quality up. The same dynamic applies to <a href="https://milvus.io/blog/openagents-milvus-how-to-build-smarter-multi-agent-systems-that-share-memory.md">multi-agent systems</a>.</p><p>Anthropic tested this with a three-agent harness — Planner, Generator, Evaluator — against a solo agent on the task of building a 2D retro game engine. They describe the full experiment in <a href="https://www.anthropic.com/engineering/harness-design-long-running-apps">“Harness Design for Long-Running Application Development”</a> (Anthropic, 2026). The Planner expands a short prompt into a full product spec, deliberately leaving implementation details unspecified — early over-specification cascades into downstream errors. The Generator implements features in sprints, but before writing code, it signs a sprint contract with the Evaluator: a shared definition of “done.” The Evaluator uses Playwright (Microsoft’s open-source browser automation framework) to click through the application like a real user, testing UI, API, and database behavior. If anything fails, the sprint fails.</p><p>The solo agent produced a game that technically launched, but entity-to-runtime connections were broken at the code level — discoverable only by reading the source. The three-agent harness produced a playable game with AI-assisted level generation, sprite animation, and sound effects.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*bHMF5FsvLubd5mCv.png" /></figure><p>Comparison of solo agent versus three-agent harness: solo agent ran 20 minutes at nine dollars with broken core functionality, while the full harness ran 6 hours at two hundred dollars producing a fully functional game with AI-assisted features</p><p>The three-agent architecture cost roughly 20x more. The output crossed from unusable to usable. That’s the core trade Harness Engineering makes: structural overhead in exchange for reliability.</p><h3>The Retrieval Problem Inside Every Agent Harness</h3><p>Both patterns — the structured docs/ system and the Generator/Evaluator sprint cycle — share a silent dependency: the agent must find the right information from a live, evolving knowledge base when it needs it.</p><p>This is harder than it looks. Take a concrete example: the Generator is executing Sprint 3, implementing user authentication. Before writing code, it needs two kinds of information.</p><p>First, a <a href="https://zilliz.com/glossary/semantic-search">semantic search</a> query: <em>what are this product’s design principles around user sessions?</em> The relevant document might use “session management” or “access control” — not “user authentication.” Without semantic understanding, retrieval misses it.</p><p>Second, an exact-match query: <em>which documents reference the </em><em>validateToken function?</em> A function name is an arbitrary string with no semantic meaning. <a href="https://zilliz.com/glossary/vector-embeddings">Embedding-based retrieval</a> can’t reliably find it. Only keyword matching works.</p><p>These two queries happen simultaneously. They can’t be separated into sequential steps.</p><p>Pure <a href="https://zilliz.com/learn/vector-similarity-search">vector search</a> fails on exact match. Traditional <a href="https://milvus.io/docs/embed-with-bm25.md">BM25</a> fails on semantic queries and can’t predict which vocabulary a document will use. Before Milvus 2.5, the only option was two parallel retrieval systems — a vector index and a <a href="https://milvus.io/docs/full-text-search.md">full-text index</a> — running concurrently at query time with custom result-fusion logic. For a live docs/ repository with continuous updates, both indexes had to stay in sync: every document change triggered reindexing in two places, with the constant risk of inconsistency.</p><h3>How Milvus 2.6 Solves Agent Retrieval with a Single Hybrid Pipeline</h3><p>Milvus is an open-source <a href="https://zilliz.com/learn/what-is-vector-database">vector database</a> designed for AI workloads. Milvus 2.6’s Sparse-BM25 collapses the dual-pipeline retrieval problem into a single system.</p><p>At ingest, Milvus generates two representations simultaneously: a <a href="https://zilliz.com/learn/sparse-and-dense-embeddings">dense embedding</a> for semantic retrieval and a <a href="https://milvus.io/docs/sparse_vector.md">TF-encoded sparse vector</a> for BM25 scoring. Global <a href="https://zilliz.com/learn/tf-idf-understanding-term-frequency-inverse-document-frequency-in-nlp">IDF statistics</a> update automatically as documents are added or removed — no manual reindex triggers. At query time, a natural-language input generates both query vector types internally. <a href="https://milvus.io/docs/rrf-ranker.md">Reciprocal Rank Fusion (RRF)</a> merges the ranked results, and the caller receives a single unified result set.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*hvsZ064HVVjTuSyx.png" /></figure><p>Before and after: two separate systems with manual sync, fragmented results, and custom fusion logic versus Milvus 2.6 single pipeline with dense embedding, Sparse BM25, RRF fusion, and automatic IDF maintenance producing unified results</p><p>One interface. One index to maintain.</p><p>On the <a href="https://zilliz.com/glossary/beir">BEIR benchmark</a> — a standard evaluation suite covering 18 heterogeneous retrieval datasets — Milvus achieves 3–4x higher throughput than Elasticsearch at equivalent recall, with up to 7x QPS improvement on specific workloads. For the sprint scenario, a single query finds both the session design principle (semantic path) and every document mentioning validateToken (exact path). The docs/ repository updates continuously; BM25 IDF maintenance means a newly written document participates in the next query’s scoring without any batch rebuild.</p><p>This is the retrieval layer built for exactly this class of problem. When an agent harness needs to search a living knowledge base — code documentation, design decisions, sprint history — single-pipeline hybrid search isn’t a nice-to-have. It’s what makes the rest of the harness work.</p><h3>The Best Harness Components Are Designed to Be Deleted</h3><p>Every component in a harness encodes an assumption about model limitations. Sprint decomposition was necessary when models lost coherence on long tasks. Context reset was necessary when models experienced anxiety near the window limit. Evaluator agents became necessary when self-evaluation bias was unmanageable.</p><p>These assumptions expire. Cognition’s context-window trick may become unnecessary as models develop genuine long-context stamina. As models continue to improve, other components will become unnecessary overhead that slows agents down without adding reliability.</p><p>Harness Engineering isn’t a fixed architecture. It’s a system recalibrated with every new model release. The first question after any major upgrade isn’t “what can I add?” It’s “what can I remove?”</p><p>The same logic applies to retrieval. As models handle longer contexts more reliably, chunking strategies and retrieval timing will shift. Information that needs careful fragmentation today may be ingestible as full pages tomorrow. The retrieval infrastructure adapts alongside the model.</p><p>Every component in a well-built harness is waiting to be made redundant by a smarter model. That’s not a problem. That’s the goal.</p><h3>Get Started with Milvus</h3><p>If you’re building agent infrastructure that needs hybrid retrieval — semantic and keyword search in one pipeline — here’s where to start:</p><ul><li>Read the <a href="https://milvus.io/blog/introduce-milvus-2-6-built-for-scale-designed-to-reduce-costs.md">Milvus 2.6 release notes</a> for full details on Sparse-BM25, automatic IDF maintenance, and performance benchmarks.</li><li>Join the <a href="https://milvus.io/community">Milvus community</a> to ask questions and share what you’re building.</li><li><a href="https://milvus.io/blog/join-milvus-office-hours-to-get-support-from-vectordb-experts.md">Book a free Milvus Office Hours session</a> to walk through your use case with a vector database expert.</li><li>If you’d rather skip infrastructure setup, <a href="https://cloud.zilliz.com/signup">Zilliz Cloud</a> (fully managed Milvus) offers a free tier to get started with $100 free credits upon registration with work email.</li><li>Star us on GitHub: <a href="https://github.com/milvus-io/milvus">milvus-io/milvus</a> — 43k+ stars and growing.</li></ul><h3>Frequently Asked Questions</h3><h3>What is harness engineering and how is it different from prompt engineering?</h3><p>Prompt engineering optimizes what you say to a model in a single exchange — phrasing, structure, examples. Harness Engineering builds the execution environment around an autonomous AI agent: the tools it can call, the knowledge it can access, the validation logic that checks its work, and the constraints that prevent architectural drift. Prompt engineering shapes one conversation turn. Harness Engineering shapes whether an agent can operate reliably for hours across hundreds of decisions without human supervision.</p><h3>Why do AI agents need both vector search and BM25 at the same time?</h3><p>Agents must answer two fundamentally different retrieval queries simultaneously. Semantic queries — <em>what are our design principles around user sessions?</em> — require dense vector embeddings to match conceptually related content regardless of vocabulary. Exact-match queries — <em>which documents reference the </em><em>validateToken function?</em> — require BM25 keyword scoring, because function names are arbitrary strings with no semantic meaning. A retrieval system that handles only one mode will systematically miss queries of the other type.</p><h3>How does Milvus Sparse-BM25 work for agent knowledge retrieval?</h3><p>At ingest, Milvus generates a dense embedding and a TF-encoded sparse vector for each document simultaneously. Global IDF statistics update in real time as the knowledge base changes — no manual reindexing required. At query time, both vector types are generated internally, Reciprocal Rank Fusion merges the ranked results, and the agent receives a single unified result set. The entire pipeline runs through one interface and one index — critical for continuously updated knowledge bases like a code documentation repository.</p><h3>When should I add an evaluator agent to my agent harness?</h3><p>Add a separate Evaluator when your Generator’s output quality cannot be verified by automated tests alone, or when self-evaluation bias has caused missed defects. The key principle: the Evaluator must be architecturally separate from the Generator — shared context reintroduces the same bias you’re trying to eliminate. The Evaluator should have access to runtime tools (browser automation, API calls, database queries) to test behavior, not just review code. Anthropic’s <a href="https://www.anthropic.com/engineering/harness-design-long-running-apps">research</a> found that this GAN-inspired separation moved output quality from “technically launches but broken” to “fully functional with features the solo agent never attempted.”</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c3896359917d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Interview with RaBitQ Authors: The TurboQuant Dispute and Why the Storage Selloff Was a False Alarm]]></title>
            <link>https://milvusio.medium.com/interview-with-rabitq-authors-the-turboquant-dispute-and-why-the-storage-selloff-was-a-false-alarm-4182dc33bb4b?source=rss-a31576809ee1------2</link>
            <guid isPermaLink="false">https://medium.com/p/4182dc33bb4b</guid>
            <dc:creator><![CDATA[Milvus]]></dc:creator>
            <pubDate>Wed, 17 Jun 2026 09:18:44 GMT</pubDate>
            <atom:updated>2026-06-17T09:18:44.423Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/944/1*_IlfWG8ZHTB2DiqgUeuZvQ.png" /></figure><p>Google’s <a href="https://research.google/blog/turboquant-redefining-ai-efficiency-with-extreme-compression/">TurboQuant</a> paper claimed 6x compression, 8x speedup, and near-zero accuracy loss for vector representations. After it was released, memory and storage stocks fell sharply, and major tech outlets quickly turned it into a headline story.</p><p>The market reaction was only the start. Researchers soon began asking whether the paper’s claims were overstated and whether it treated prior work — especially <a href="https://dl.acm.org/doi/10.1145/3654970">RaBitQ</a> — fairly. The dispute pushed vector quantization back into the spotlight, partly because the same underlying ideas now matter in two critical parts of the AI stack: <a href="https://zilliz.com/learn/vector-similarity-search?__hstc=175614333.01e1d5588e0db010a99d83b2be4ab1d1.1780994632285.1781579330132.1781687753424.10&amp;__hssc=175614333.1.1781687753424&amp;__hsfp=7fe4d262795598604990ec4e169c597d">vector search systems</a> and KV-cache compression for large models.</p><p>To understand both the technical debate and what it means for production systems, we spoke with Cheng Long, Associate Professor at NTU Singapore and head of VectorDB@NTU; Jianyang Gao, first author of RaBitQ; and Li Liu, Director of Engineering at Zilliz. The conversation covered vector quantization itself, the questions raised around TurboQuant, and why this matters for systems like <a href="https://milvus.io/">Milvus</a>, the most popular open-source <a href="https://zilliz.com/learn/what-is-vector-database?__hstc=175614333.01e1d5588e0db010a99d83b2be4ab1d1.1780994632285.1781579330132.1781687753424.10&amp;__hssc=175614333.1.1781687753424&amp;__hsfp=7fe4d262795598604990ec4e169c597d">vector databases</a>, and large-scale vector retrieval.</p><p><em>Related reading:</em> <em>If you want the engineering side rather than the interview, see our companion article on</em> <a href="https://milvus.io/blog/turboquant-rabitq-vector-database-cost.md"><em>how vector quantization affects AI infrastructure costs</em></a><em>.</em></p><h3>Why did vector quantization suddenly become such a big topic?</h3><p>Zilliz: Before we get into the controversy, could you start by explaining what vector quantization is and why it has become so important in AI?</p><p>Cheng Long: Vector quantization is a technique for data compression and approximate representation. It originally came from signal processing, where it was used for image and audio compression. In modern AI systems, its role has changed because vectors have become one of the basic units of computation.</p><p>Today, its importance is clearest in two places.</p><p>One is real-time search over collections with billions or even tens of billions of vectors. In semantic retrieval systems, the core task is similarity search over high-dimensional vectors. But raw vectors are large, and floating-point computation is expensive. At scale, that makes it difficult to deliver millisecond-level latency. Vector quantization helps by compressing vectors into low-bit representations and speeding up distance computation. That is why it matters for practical workloads such as <a href="https://milvus.io/docs/single-vector-search.md">single-vector search</a>, <a href="https://milvus.io/docs/multi-vector-search.md">multi-vector search</a>, and index design in <a href="https://milvus.io/docs/index-explained.md">Milvus search architecture</a>.</p><p>The other is KV cache compression for large models. KV cache reduces redundant computation during generation, but the memory cost grows quickly as context gets longer. So the problem becomes how to compress those vectors without hurting output quality too much. At its core, that is also a vector quantization problem.</p><p>Zilliz: If vector quantization becomes more widely used — and if TurboQuant’s results hold up — does that mean storage demand drops sharply?</p><p>Jianyang Gao: Under the same model and the same workload, compression can reduce storage demand. But that does not justify the broader conclusion people jumped to.</p><p>When TurboQuant talks about 6x compression and 8x speedup, it is comparing against a basic 16-bit/32-bit baseline. That is not the same as comparing against other methods in the same category. So the real effect still needs to be evaluated more carefully.</p><p>Zilliz: Then from that perspective, if the market reaction were really about the technology itself, should it have happened much earlier, when similar ideas had already appeared?</p><p>Cheng Long: From a technical point of view, you could say that similar theoretical territory had already been reached before. But markets do not move in sync with research. There is usually a lag between academic results, engineering adoption, and financial interpretation.</p><p>And over a longer horizon, the effect may not even be linear. Compression can make it possible to run large models on smaller devices, which can create new demand rather than simply reduce it. The relationship between technology and markets is more complicated than a straight-line extrapolation.</p><h3>How did RaBitQ emerge, and what did it contribute?</h3><p>Zilliz: How did you first arrive at the idea for RaBitQ?</p><p>Jianyang Gao: We started from a gap we saw in vector databases. Traditional methods such as <a href="https://milvus.io/docs/ivf-pq.md">Product Quantization</a> worked well empirically, but they offered very little in the way of theoretical guarantees.</p><p>At the time, I was studying high-dimensional probability at NTU Singapore, and that led me to ask whether we could build a method that was not only practical, but also came with a clear theoretical guarantee. That was the starting point for RaBitQ.</p><p>Zilliz: What do you see as RaBitQ’s core originality?</p><p>Jianyang Gao: Its key idea was to use a random rotation, a.k.a., Johnson-Lindenstrauss transformation, to make the distribution of vector coordinates more uniform and more predictable.</p><p>Once you have that, you can derive an optimal quantization estimator on top of it. We then gave a strict proof that it reaches the theoretical lower bound.</p><p>Earlier work had also tried to introduce random rotation. But from our perspective, those methods did not achieve the effect we were looking for because of practical issues in algorithm design.</p><p>Zilliz: From an engineering perspective, what stood out most to you about RaBitQ?</p><p>Li Liu: We had worked with many quantization algorithms, from <a href="https://milvus.io/docs/ivf-sq8.md">scalar quantization methods</a> to PQ and other variants. What stood out about RaBitQ was that it changed how people approached the problem.</p><p>Before that, much of the field was still fairly empirical. You could say a method seemed to work, but it was harder to explain clearly why. RaBitQ approached the problem in a much more mathematical way. The method felt elegant and, in a sense, simple. That way of thinking influenced a lot of later work.</p><p>Zilliz: Put simply, how much can it save in memory and cost?</p><p>Li Liu: At the same recall level, moving from 4-bit compression to 2-bit compression cuts memory use by half.</p><p>And it is not just about compression. Its performance compares favorably with earlier approaches, and that matters in production environments where teams care about both memory efficiency and retrieval quality. That is why it matters for systems that need to balance <a href="https://milvus.io/docs/dense-vector.md">dense vector storage</a>, throughput, and recall.</p><p>Zilliz: Beyond Milvus, where do you see RaBitQ being used today?</p><p>Cheng Long: First, I want to thank the Milvus team, because they were among the earliest to adopt RaBitQ. We also had a lot of discussions and some collaborative research along the way.</p><p>RaBitQ has also been adopted in some other systems including Meta’s FAISS, VSAG, VectorChord, Volcengine OpenSearch, CockroachDB, ElasticSearch, Lucene, and turbopuffer. What stands out on the Milvus side is that the team shipped <a href="https://milvus.io/docs/ivf-rabitq.md">IVF_RABITQ</a> as a real index option in <a href="https://milvus.io/blog/introduce-milvus-2-6-built-for-scale-designed-to-reduce-costs.md">Milvus 2.6</a>, alongside broader work on <a href="https://milvus.io/docs/manage-collections.md">collection management</a>, <a href="https://milvus.io/docs/ivf-flat.md">IVF-based indexing</a>, and <a href="https://milvus.io/docs/hnsw.md">HNSW-based indexing</a>.</p><h3>How should we evaluate TurboQuant?</h3><p>Zilliz: In your public response, you said TurboQuant had some serious issues. What, in your view, were the main ones?</p><p>Jianyang Gao: We see three main problems.</p><p>One is the way the paper describes prior work and discusses overlap. The TurboQuant paper misrepresents the methodology of RaBitQ, ignoring the most similar part, such as Johnson-Lindenstrauss Transformation. Another is the way the paper characterizes the theoretical result. It describes RaBitQ as suboptimal without providing any explanation or evidence, but RaBitQ is optimal in fact. The third is the fairness of the experimental comparison. They use single-core CPU to evaluate RaBitQ while using A100 GPU to evaluate TurboQuant.</p><p>Zilliz: Let’s take the benchmark issue first. Why do you think the comparison was not fair?</p><p>Jianyang Gao: Benchmark claims only mean something if the setup is comparable. If one system is tested under a very different hardware or software environment, then the result may reflect the setup more than the algorithm itself.</p><p>In our view, differences in processor choice, implementation language, and optimization level can make a major difference. That is why benchmark methodology needs to be interpreted very carefully, especially by teams building production retrieval systems.</p><p>Cheng Long: The paper also made some other claims that do not hold.</p><p>For example, the paper says that RaBitQ cannot be vectorized. But RaBitQ had already open-sourced code with SIMD-based vectorized computation when the 2024 paper was published. So from our perspective, that statement was factually incorrect.</p><p>It is also worth mentioning that we began working with NVIDIA last year and completed a GPU implementation of RaBitQ. The related code is under review for inclusion in NVIDIA’s cuVS library.</p><p>Zilliz: Milvus evaluated TurboQuant in the second half of 2025 but did not adopt it. What did your team see in testing?</p><p>Li Liu: It does contain one useful idea. In our view, it makes a small optimization in how the quantization grid is allocated. But the most important step in the method — using random rotation for quantization — was first introduced by RaBitQ.</p><p>And when it comes to unbiased estimation, RaBitQ’s approach is cleaner and its theoretical derivation is stronger.</p><p>That said, because this was a result from Google, we tested it in 2025. In our lab, under a standardized CPU environment, TurboQuant did not outperform our internal RaBitQ version in most of the cases we evaluated. So when the market reacted so strongly, we were genuinely surprised.</p><p>Zilliz: For readers who have not looked closely at either paper, could you walk through where RaBitQ and TurboQuant overlap in plain language?</p><p>Li Liu: At a high level, both methods begin with random rotation. Mathematically, that means multiplying the vector by a random orthogonal matrix. You can think of it as changing your viewing angle in a high-dimensional space. It does not change the relative positions of the data points, but it distributes the information across dimensions more evenly.</p><p>After that comes quantization. You divide the continuous real-valued space into 2^k grid cells, where k is the number of quantization bits, and then map each vector element to a nearby grid point. TurboQuant makes a small adjustment here by allocating the grid according to the data distribution instead of distributing it evenly.</p><p>The last step is error estimation, and this is where RaBitQ’s main contribution lies. Traditional methods calculate directly from the quantized values, which makes the error harder to control. RaBitQ estimates the quantization error more precisely, and that is where its mathematical optimality comes from. TurboQuant’s solution is more complicated, and in our setting the tradeoff did not look as attractive.</p><h3>Why is attribution so hard to resolve in practice?</h3><p>Zilliz: After you published your public statement, how did Google and ICLR respond?</p><p>Cheng Long: ICLR did not take action. We emailed them during the review period in September last year, but did not receive a response. We wrote again in March this year and were told to post comments on OpenReview, but beyond that there was no action.</p><p>As for Google, one of the co-authors replied a few days ago. The reply said they would revise the arXiv version to correct its inaccurate description of RaBitQ’s optimality.</p><p>Zilliz: Earlier the discussion was framed around academic misconduct. Now it also sounds like a question of imbalance and who gets to shape the story. Why is it so hard to defend your work?</p><p>Cheng Long: One problem is scale. AI conferences are now so large that a single cycle can bring in tens of thousands of papers. Organizers simply do not have the capacity to handle every dispute of this kind.</p><p>The other problem is imbalance. Large companies have a much stronger public voice. Independent researchers or smaller teams do not have the same communication power.</p><p>Jianyang Gao: For individuals, the cost is extremely high. Professor Long and I have barely been able to work normally in recent weeks.</p><p>The process itself has also been frustrating. We were firmly rejected when we contacted the authors, and we received no response from the conference organizers. In practice, many researchers look at situations like this and decide to let them go. But that is also how many original contributions disappear from the public narrative.</p><p>Zilliz: It sounds like this is not the first time your team has run into this kind of problem.</p><p>Cheng Long: No, it is not.</p><p>We have seen cases before where companies take RaBitQ, make a few engineering modifications, give it a new name, and then describe it only as something inspired by RaBitQ.</p><p>That is why I appreciate the way some industry teams handle this, including Milvus. When they use RaBitQ, they describe it objectively. And when they add optimizations beyond the original version, they explain those clearly as their own engineering contribution. That gives proper credit to the original work while also showing the company’s technical strength.</p><p>Zilliz: When large companies build on academic work, do they usually provide any financial sharing or benefit allocation?</p><p>Jianyang Gao: In most cases, no.</p><p>That said, large companies still have a strong incentive to present a technical advance as something they created themselves rather than something they adopted from others. Everyone wants customers and investors to see the most advanced work as the result of their own team’s innovation.</p><h3>What comes next for vector quantization?</h3><p>Zilliz: What research directions are you working on now?</p><p>Cheng Long: A large part of our work will remain focused on vector retrieval.</p><p>One direction is to combine RaBitQ with different vector retrieval indexes, such as IVF and HNSW, so the system can support larger-scale data with lower latency, higher concurrency, and lower cost. I am also paying attention to KV cache compression.</p><p>Jianyang Gao: KV cache in large models and vector retrieval share many of the same properties, both mathematically and at the systems level, because both deal with high-dimensional vectors.</p><p>Going forward, I want to think more about how to apply mathematical tools, including ideas from high-dimensional probability, to accelerate inference and training.</p><p>Zilliz: Where is the ceiling for vector quantization as a field? How much room is left for improvement?</p><p>Cheng Long: From a theoretical point of view, the ceiling is largely in sight. RaBitQ is already asymptotically optimal.</p><p>But there is still a great deal of room on the engineering side. You still have to deal with hardware characteristics, data distribution, latency constraints, and many other practical factors. That is exactly why production systems still need careful work in areas such as <a href="https://milvus.io/docs/architecture_overview.md">distributed vector database architecture</a>, <a href="https://milvus.io/docs/sparse_vector.md">sparse vector support</a>, <a href="https://milvus.io/docs/reranking.md">reranking pipelines</a>, and metric selection in <a href="https://milvus.io/docs/metric.md">Milvus distance metrics</a>.</p><h3>Keep Reading</h3><p>If you want to dig deeper into the engineering side of RaBitQ and how it fits into Milvus, these are the most relevant resources:</p><ul><li><a href="https://milvus.io/docs/ivf-rabitq.md">IVF_RABITQ documentation</a> — configuration details and tuning guidance.</li><li><a href="https://milvus.io/blog/bring-vector-compression-to-the-extreme-how-milvus-serves-3%C3%97-more-queries-with-rabitq.md">RaBitQ integration deep dive</a> — how Milvus turned RaBitQ into a production index.</li><li><a href="https://milvus.io/blog/turboquant-rabitq-vector-database-cost.md">How vector quantization affects AI infrastructure costs</a> — our broader analysis of the TurboQuant-RaBitQ discussion.</li><li><a href="https://milvus.io/blog/introduce-milvus-2-6-built-for-scale-designed-to-reduce-costs.md">Milvus 2.6 release post</a> — where IVF_RABITQ shipped as a real Milvus index option.</li><li><a href="https://milvus.io/docs/index-explained.md">Milvus index explained</a> — how IVF_RABITQ fits with other index choices.</li><li><a href="https://milvus.io/docs/ivf-flat.md">IVF_FLAT indexing</a> and <a href="https://milvus.io/docs/hnsw.md">HNSW indexing</a> — useful baselines if you are comparing index tradeoffs.</li><li><a href="https://milvus.io/docs/schema.md">Schema design in Milvus</a> and <a href="https://milvus.io/docs/filtered-search.md">filtered search</a> — useful if you are evaluating RaBitQ in a real application rather than in isolation.</li><li><a href="https://milvus.io/docs/quickstart.md">Milvus quickstart</a> and <a href="https://zilliz.com/learn/Retrieval-Augmented-Generation?__hstc=175614333.01e1d5588e0db010a99d83b2be4ab1d1.1780994632285.1781579330132.1781687753424.10&amp;__hssc=175614333.1.1781687753424&amp;__hsfp=7fe4d262795598604990ec4e169c597d">RAG system design</a> — helpful if you want to try this in a retrieval pipeline.</li></ul><p>Join the <a href="https://slack.milvus.io/">Milvus Slack community</a> or <a href="https://milvus.io/office-hours">book Milvus Office Hours</a> if you want to talk through your workload.</p><p>If you’d rather skip infrastructure setup, you can <a href="https://cloud.zilliz.com/signup?__hstc=175614333.01e1d5588e0db010a99d83b2be4ab1d1.1780994632285.1781579330132.1781687753424.10&amp;__hssc=175614333.1.1781687753424&amp;__hsfp=7fe4d262795598604990ec4e169c597d">sign up for Zilliz Cloud</a> (fully managed Milvus) .</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4182dc33bb4b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[We Built Graph RAG Without the Graph Database]]></title>
            <link>https://milvusio.medium.com/we-built-graph-rag-without-the-graph-database-0ac28ad4a1c7?source=rss-a31576809ee1------2</link>
            <guid isPermaLink="false">https://medium.com/p/0ac28ad4a1c7</guid>
            <dc:creator><![CDATA[Milvus]]></dc:creator>
            <pubDate>Tue, 16 Jun 2026 03:24:26 GMT</pubDate>
            <atom:updated>2026-06-16T03:24:26.103Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GkX9lsmkRaB5yVBA9UWadA.png" /></figure><blockquote>TL;DR:<em> </em>Do you actually need a graph database for Graph RAG? No. Put entities, relations, and passages into Milvus. Use subgraph expansion instead of graph traversal, and one LLM rerank instead of multi-round agent loops. That’s<em> </em><a href="https://github.com/zilliztech/vector-graph-rag">Vector Graph RAG</a>,<em> </em>and it’s what we built. This approach hits 87.8% average Recall@5 on three multi-hop QA benchmarks and beats HippoRAG 2 on a single Milvus instance.</blockquote><p>Multi-hop questions are the wall that most RAG pipelines hit eventually. The answer is in your corpus, but it spans multiple passages connected by entities the question never names. The common fix is to add a graph database, which means running two systems instead of one.</p><p>We kept hitting this wall ourselves and didn’t want to run two databases just to handle it. So we built and open-sourced <a href="https://github.com/zilliztech/vector-graph-rag">Vector Graph RAG</a>, a Python library that brings multi-hop reasoning to <a href="https://zilliz.com/learn/Retrieval-Augmented-Generation">RAG</a> using only <a href="https://milvus.io/docs">Milvus</a>, the most widely adopted open-source vector database. It provides the same multi-hop capability with one database instead of two.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FyCooOl-koxc%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DyCooOl-koxc&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FyCooOl-koxc%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/699ba14e812c259ef2034c4c1373aa06/href">https://medium.com/media/699ba14e812c259ef2034c4c1373aa06/href</a></iframe><h3>Why Multi-Hop Questions Break Standard RAG</h3><p>Multi-hop questions break standard RAG because the answer depends on entity relationships that vector search can’t see. The bridge entity connecting the question to the answer often isn’t in the question itself.</p><p>Simple questions work fine. You chunk documents, embed them, retrieve the closest matches, and feed them to an LLM. “What indexes does Milvus support?” lives in one passage, and vector search finds it.</p><p>Multi-hop questions don’t fit that pattern. Take a question like <em>“What side effects should I watch for with first-line diabetes drugs?”</em> in a medical knowledge base.</p><p>Answering it takes two reasoning steps. First, the system has to know that metformin is the first-line drug for diabetes. Only then can it look up metformin’s side effects: kidney function monitoring, GI discomfort, vitamin B12 deficiency.</p><p>“Metformin” is the bridge entity. It connects the question to the answer, but the question never mentions it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*dWInax7Tjvzso8xA.png" /></figure><p>That’s where <a href="https://zilliz.com/learn/vector-similarity-search">Vector similarity search</a> stops. It retrieves passages that look like the question, diabetes treatment guides and drug side effect lists, but it can’t follow the entity relationships that link those passages together. Facts like “metformin is the first-line drug for diabetes” live in those relationships, not in the text of any single passage.</p><h3>Why Graph Databases and Agentic RAG Aren’t the Answer</h3><p>The standard ways to solve multi-hop RAG are graph databases and iterative agent loops. Both work. Both cost more than most teams want to pay for a single feature.</p><p>Take the graph-database route first. You extract triples from your documents, store them in a graph database, and traverse edges to find multi-hop connections. That means running a second system alongside your <a href="https://zilliz.com/learn/what-is-vector-database">vector database</a>, learning Cypher or Gremlin, and keeping the graph and vector stores in sync.</p><p>Iterative agent loops are the other approach. The LLM retrieves a batch, reasons over it, decides whether it has enough context, and retrieves again if not. <a href="https://arxiv.org/abs/2212.10509">IRCoT</a> (Trivedi et al., 2023) makes 3–5 LLM calls per query. Agentic RAG can exceed 10 because the agent decides when to stop. Cost per query becomes unpredictable, and P99 latency spikes whenever the agent runs extra rounds.</p><p>Neither fits teams that want multi-hop reasoning without rebuilding their stack. So we tried something else.</p><h3>What is Vector Graph RAG, a Graph Structure Inside a Vector Database</h3><p><a href="https://github.com/zilliztech/vector-graph-rag">Vector Graph RAG</a> is an open-source Python library that brings multi-hop reasoning to <a href="https://zilliz.com/learn/Retrieval-Augmented-Generation">RAG</a> using only <a href="https://milvus.io/docs">Milvus</a>. It stores graph structure as ID references across three Milvus collections. Traversal becomes a chain of primary-key lookups in Milvus instead of Cypher queries against a graph database. One Milvus does both jobs.</p><p>It works because relationships in a knowledge graph are just text. The triple <em>(which is metformin, is the first-line drug for type 2 diabetes)</em> is a directed edge in a graph database. It’s also a sentence: “Metformin is the first-line drug for type 2 diabetes.” You can embed that sentence as a vector and store it in <a href="https://milvus.io/docs">Milvus</a>, the same as any other text.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*J_rsnmV7PzKgQQyx.png" /></figure><p>Answering a multi-hop query means following connections from what the query mentions (like “diabetes”) to what it doesn’t (like “metformin”). That only works if the storage preserves those connections: which entity connects to which through which relation. Plain text is searchable, but not followable.</p><p>To keep connections followable in Milvus, we give each entity and each relation a unique ID, then store them in separate collections that reference each other by ID. Three collections in total: entities (the nodes), relations (the edges), and passages (the source text, which the LLM needs for answer generation). Every row has a vector embedding, so we can semantic-search any of the three.</p><p>Entities store deduplicated entities. Each has a unique ID, a <a href="https://zilliz.com/glossary/vector-embeddings">vector embedding</a> for <a href="https://zilliz.com/glossary/semantic-search">semantic search</a>, and a list of relation IDs it participates in.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*W8rGlwZmWZcwKKNcOt27uA.png" /></figure><p>Relations store knowledge triples. Each records its subject and object entity IDs, the passage IDs it came from, and an embedding of the full relationship text.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EqX6J2ulxvK733tH1FSFrA.png" /></figure><p>Passages store original document chunks, with references to the entities and relations extracted from them.</p><p>The three collections point at each other through ID fields: entities carry the IDs of their relations, relations carry the IDs of their subject and object entities and source passages, and passages carry the IDs of everything extracted from them. That network of ID references is the graph.</p><p>Traversal is just a chain of ID lookups. You fetch entity e01 to get its relation_ids, fetch relations r01 and r02 by those IDs, read r01’s object_id to discover entity e02, and keep going. Each hop is a standard Milvus <a href="https://milvus.io/docs/get-and-scalar-query.md">primary-key query</a>. No Cypher required.</p><p>You might wonder whether the extra round trips to Milvus add up. They don’t. Subgraph expansion costs 2–3 ID-based queries totaling 20–30ms. The LLM call takes 1–3 seconds, which makes the ID lookups invisible next to it.</p><h3>How Vector Graph RAG Answers a Multi-Hop Query</h3><p>The retrieval flow takes a multi-hop query to a grounded answer in four steps: seed retrieval → subgraph expansion → LLM rerank → answer generation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gWy7oowcy6P8af9p.png" /></figure><p>We’ll walk through the diabetes question: <em>“What side effects should I watch for with first-line diabetes drugs?”</em></p><h3>Step 1: Seed Retrieval</h3><p>An LLM extracts key entities from the question: “diabetes,” “side effects,” “first-line drug.” Vector search in Milvus finds the most relevant entities and relations directly.</p><p>But metformin isn’t among them. The question doesn’t mention it, so vector search can’t find it.</p><h3>Step 2: Subgraph Expansion</h3><p>This is where Vector Graph RAG diverges from standard RAG.</p><p>The system follows ID references from the seed entities one hop out. It gets the seed entity IDs, finds all relations containing those IDs, and pulls the new entity IDs into the subgraph. Default: one hop.</p><p>Metformin, the bridge entity, enters the subgraph.</p><p>“Diabetes” has a relation: <em>“Metformin is the first-line drug for type 2 diabetes.”</em> Following that edge brings metformin in. Once metformin is in the subgraph, its own relations come with it: <em>“Patients on metformin should have kidney function monitored,” “Metformin may cause gastrointestinal discomfort,” “Long-term metformin use may lead to vitamin B12 deficiency.”</em></p><p>Two facts that lived in separate passages are now connected through one hop of graph expansion. The bridge entity the question never mentioned is now discoverable.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*CWirtCGAIN6MqplW.png" /></figure><h3>Step 3: LLM Rerank</h3><p>Expansion leaves you with dozens of candidate relations. Most are noise.</p><pre>Expanded candidate pool (example):<br>r01: Metformin is the first-line drug for type 2 diabetes          ← Key<br>r02: Patients on metformin should have kidney function monitored   ← Key<br>r03: Metformin may cause gastrointestinal discomfort               ← Key<br>r04: Type 2 diabetes patients should have regular eye exams        ✗ Noise<br>r05: Insulin injection sites should be rotated                     ✗ Noise<br>r06: Diabetes is linked to cardiovascular disease risk             ✗ Noise<br>r07: Metformin is contraindicated in severe liver dysfunction      ✗ Noise (contraindication, not side effect)<br>r08: HbA1c is a monitoring indicator for diabetes                  ✗ Noise<br>r09: Sulfonylureas are second-line treatment for type 2 diabetes   ✗ Noise (second-line, not first-line)<br>r10: Long-term metformin use may lead to vitamin B12 deficiency    ← Key<br>...(more)</pre><p>The system sends these candidates and the original question to an LLM: “Which relate to side effects of first-line diabetes drugs?” It’s one call with no iteration.</p><pre>After LLM filtering:<br>✓ r01: Metformin is the first-line drug for type 2 diabetes          → Establishes the bridge: first-line drug = metformin<br>✓ r02: Patients on metformin should have kidney function monitored   → Side effect: kidney impact<br>✓ r03: Metformin may cause gastrointestinal discomfort               → Side effect: GI issues<br>✓ r10: Long-term metformin use may lead to vitamin B12 deficiency    → Side effect: nutrient deficiency</pre><p>The selected relations cover the full chain: diabetes → metformin → kidney monitoring / GI discomfort / B12 deficiency.</p><h3>Step 4: Answer Generation</h3><p>The system retrieves the original passages for the selected relations and sends them to the LLM.</p><p>The LLM generates from full passage text, not the trimmed triples. Triples are compressed summaries. They lack the context, caveats, and specifics the LLM needs to produce a grounded answer.</p><h3>See Vector Graph RAG in action</h3><p>We also built an interactive frontend that visualizes each step. Click through the steps panel on the left and the graph updates in real time: orange for seed nodes, blue for expanded nodes, green for selected relations. It makes the retrieval flow concrete instead of abstract.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*Unpwv-1O1f_CZEqA.gif" /></figure><h3>Why One Rerank Beats Multiple Iterations</h3><p>Our pipeline makes two LLM calls per query: one for rerank, one for generation. Iterative systems like IRCoT and Agentic RAG run 3 to 10+ calls because they loop: retrieve, reason, retrieve again. We skip the loop because vector search and subgraph expansion cover both semantic similarity and structural connections in one pass, giving the LLM enough candidates to finish in one rerank.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Dla468LF-EimfN3giSCy-g.png" /></figure><p>In production, that’s roughly 60% lower API cost, 2–3x faster responses, and predictable latency. No surprise spikes when an agent decides to run extra rounds.</p><h3>Benchmark Results</h3><p>Vector Graph RAG averages 87.8% Recall@5 across three standard multi-hop QA benchmarks, matching or exceeding every method we tested, including HippoRAG 2, with just Milvus and 2 LLM calls.</p><p>We evaluated on MuSiQue (2–4 hop, the hardest), HotpotQA (2 hop, the most widely used), and 2WikiMultiHopQA (2 hop, cross-document reasoning). The metric is Recall@5: whether the correct supporting passages appear in the top 5 retrieved results.</p><p>We used the exact same pre-extracted triples from the <a href="https://github.com/OSU-NLP-Group/HippoRAG">HippoRAG repository</a> for a fair comparison. No re-extraction, no custom preprocessing. The comparison isolates the retrieval algorithm itself.</p><h3><a href="https://github.com/zilliztech/vector-graph-rag">Vector Graph RAG</a> vs Standard (Naive) RAG</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ndYIySJ9cKCm445a.png" /></figure><p>Vector Graph RAG lifts average Recall@5 from 73.4% to 87.8%, an improvement of 19.6 percentage points.</p><ul><li>MuSiQue: largest gain (+31.4 pp). 3–4 hop benchmark, the hardest multi-hop questions, and exactly where subgraph expansion has the biggest impact.</li><li>2WikiMultiHopQA: sharp improvement (+27.7 pp). Cross-document reasoning, another sweet spot for subgraph expansion.</li><li>HotpotQA: smaller gain (+6.1 pp), but standard RAG already scores 90.8% on this dataset. The ceiling is low.</li></ul><h3><a href="https://github.com/zilliztech/vector-graph-rag">Vector Graph RAG</a> vs State-of-the-Art Methods (SOTA)</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*TL9VGXiGVMddbUMd.png" /></figure><p>Vector Graph RAG takes the highest average score at 87.8% against HippoRAG 2, IRCoT, and NV-Embed-v2.</p><p>Benchmark by benchmark:</p><ul><li>HotpotQA: ties HippoRAG 2 (both 96.3%)</li><li>2WikiMultiHopQA: leads by 3.7 points (94.1% vs 90.4%)</li><li>MuSiQue (the hardest): trails by 1.7 points (73.0% vs 74.7%)</li></ul><p>Vector Graph RAG achieves these numbers with only 2 LLM calls per query, no graph database, and no ColBERTv2. It runs on the simplest infrastructure in the comparison and still takes the highest average.</p><h3>How <a href="https://github.com/zilliztech/vector-graph-rag">Vector Graph RAG</a> Compares to Other Graph RAG Approaches</h3><p>Different Graph RAG approaches optimize for different problems. Vector Graph RAG is built for production multi-hop QA with predictable cost and simple infrastructure.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jeuv9PTO25MtS6dOVOCrKA.png" /></figure><p><a href="https://github.com/microsoft/graphrag">Microsoft GraphRAG</a> uses hierarchical community clustering to answer global summarization questions like ‘what are the main themes across this corpus?’ That’s a different problem than multi-hop QA.”</p><p><a href="https://arxiv.org/abs/2502.14802">HippoRAG 2</a> (Gutierrez et al., 2025) uses cognitive-inspired retrieval with ColBERTv2 token-level matching. Loading the full graph into memory limits scalability.</p><p>Iterative approaches like <a href="https://arxiv.org/abs/2212.10509">IRCoT</a> trade infrastructure simplicity for LLM cost and unpredictable latency.</p><p>Vector Graph RAG targets production multi-hop QA: teams that want predictable cost and latency without adding a graph database.</p><h3>When to Use Vector Graph RAG and Key Use Cases</h3><p>Vector Graph RAG is built for four kinds of workloads:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KlBFzeX8pgTfbaiYFILuZg.png" /></figure><h3>Get Started with Vector Graph RAG</h3><pre>pip install vector-graph-rag<br>from vector_graph_rag import VectorGraphRAG<br>rag = VectorGraphRAG()  # defaults to Milvus Lite, no server needed<br>rag.add_texts([<br>    &quot;Metformin is the first-line drug for type 2 diabetes.&quot;,<br>    &quot;Patients taking metformin should have their kidney function monitored regularly.&quot;,<br>])<br>result = rag.query(&quot;What side effects should I watch for with first-line diabetes drugs?&quot;)<br>print(result.answer)</pre><p>VectorGraphRAG() with no arguments defaults to <a href="https://milvus.io/docs/milvus_lite.md">Milvus Lite</a>. It creates a local .db file, like SQLite. No server to start, nothing to configure.</p><p>add_texts() calls an LLM to extract triples from your text, vectorizes them, and stores everything in Milvus. query() runs the full four-step retrieval flow: seed, expand, rerank, generate.</p><p>For production, swap one URI parameter. The rest of the code stays the same:</p><pre>Local development<br>rag = VectorGraphRAG()<br><br># Self-hosted Milvus<br>rag = VectorGraphRAG(uri=&quot;http://your-milvus-server:19530&quot;)<br><br># Zilliz Cloud (managed Milvus, free tier available)<br>rag = VectorGraphRAG(uri=&quot;your-zilliz-endpoint&quot;, token=&quot;your-api-key&quot;)</pre><p>To import PDFs, web pages, or Word files:</p><pre>from vector_graph_rag.loaders import DocumentImporter<br><br>importer = DocumentImporter(chunk_size=1000, chunk_overlap=200)<br>result = importer.import_sources([<br>    &quot;https://en.wikipedia.org/wiki/Metformin&quot;,<br>    &quot;/path/to/clinical-guidelines.pdf&quot;,<br>])<br>rag.add_documents(result.documents, extract_triplets=True)</pre><h3>Conclusion</h3><p>Graph RAG doesn’t need a graph database. Vector Graph RAG stores graph structure as ID references across three Milvus collections, which turns graph traversal into primary-key lookups and keeps every multi-hop query at a fixed two LLM calls.</p><p>At a glance:</p><ul><li>Open-source Python library. Multi-hop reasoning on Milvus alone.</li><li>Three collections linked by ID. Entities (nodes), relations (edges), passages (source text). Subgraph expansion follows the IDs to discover bridge entities the query doesn’t mention.</li><li>Two LLM calls per query. One rerank, one generation. No iteration.</li><li>87.8% average Recall@5 across MuSiQue, HotpotQA, and 2WikiMultiHopQA, matching or beating HippoRAG 2 on two of three.</li></ul><h3>Try it:</h3><ul><li><a href="https://github.com/zilliztech/vector-graph-rag">GitHub: zilliztech/vector-graph-rag</a> for the code</li><li><a href="https://zilliztech.github.io/vector-graph-rag">Docs</a> for the full API and examples</li><li>Join the <a href="https://slack.milvus.io/">Milvus</a> <a href="https://discord.com/invite/8uyFbECzPX">community</a> <a href="https://slack.milvus.io/">on Discord</a> to ask questions and share feedback</li><li><a href="https://milvus.io/office-hours">Book a Milvus Office Hours session</a> to walk through your use case</li><li><a href="https://cloud.zilliz.com/signup">Zilliz Cloud</a> offers a free tier with managed Milvus if you’d rather skip infrastructure setup</li></ul><h3>FAQ</h3><h3>Can I do Graph RAG with just a vector database?</h3><p>Yes. Vector Graph RAG stores knowledge graph structure (entities, relations, and their connections) inside three Milvus collections linked by ID cross-references. Instead of traversing edges in a graph database, it chains primary-key lookups in Milvus to expand a subgraph around seed entities. This achieves 87.8% average Recall@5 on three standard multi-hop benchmarks without any graph database infrastructure.</p><h3>How does Vector Graph RAG compare to Microsoft GraphRAG?</h3><p>They solve different problems. Microsoft GraphRAG uses hierarchical community clustering for global corpus summarization (“What are the main themes across these documents?”). Vector Graph RAG focuses on multi-hop question answering, where the goal is to chain specific facts across passages. Vector Graph RAG needs only Milvus and two LLM calls per query. Microsoft GraphRAG requires a graph database and carries higher indexing costs.</p><h3>What types of questions benefit from multi-hop RAG?</h3><p>Multi-hop RAG helps with questions where the answer depends on connecting information scattered across multiple passages, especially when a key entity never appears in the question. Examples include “What side effects does the first-line diabetes drug have?” (requires discovering metformin as the bridge), cross-reference lookups in legal or regulatory text, and dependency chain tracing in technical documentation. Standard RAG handles single-fact lookups well. Multi-hop RAG adds value when the reasoning path is two to four steps long.</p><h3>Do I need to extract knowledge graph triples manually?</h3><p>No. add_texts() and add_documents() automatically call an LLM to extract entities and relationships, vectorize them, and store them in Milvus. You can import documents from URLs, PDFs, and DOCX files using the built-in DocumentImporter. For benchmarking or migration, the library supports importing pre-extracted triples from other frameworks like HippoRAG.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0ac28ad4a1c7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Fix Hermes Agent’s Learning Loop with Milvus 2.6 Hybrid Search]]></title>
            <link>https://milvusio.medium.com/how-to-fix-hermes-agents-learning-loop-with-milvus-2-6-hybrid-search-196afb882033?source=rss-a31576809ee1------2</link>
            <guid isPermaLink="false">https://medium.com/p/196afb882033</guid>
            <dc:creator><![CDATA[Milvus]]></dc:creator>
            <pubDate>Tue, 16 Jun 2026 03:13:51 GMT</pubDate>
            <atom:updated>2026-06-16T03:13:51.467Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OXfCGWGCADyNCEJ700w5ww.png" /></figure><p><a href="https://github.com/NousResearch/hermes-agent">Hermes Agent</a> has been everywhere lately. Built by Nous Research, Hermes is a self-hosted personal AI agent that runs on your own hardware (a $5 VPS works) and talks to you through existing chat channels like Telegram.</p><p>Its biggest highlight is a built-in learning loop: the loop creates Skills from experience, improves them during use, and searches past conversations to find reusable patterns. Other agent frameworks hand-code Skills before deployment. Hermes’s Skills grow from use, and repeated workflows become reusable with zero code change.</p><p>The catch is that Hermes’s retrieval is keyword-only. It matches exact words, but not the meaning users are after. When users use different wording across different sessions, the loop can’t connect them, and no new Skill gets written. When there are only a few hundred documents, the gap is tolerable. Past that, the loop stops learning because it can’t find its own history.</p><p>The fix is Milvus 2.6. Its <a href="https://milvus.io/docs/multi-vector-search.md">hybrid search</a> covers both meaning and exact keywords in a single query, so the loop can finally connect rephrased information across sessions. It’s light enough to fit on a small cloud server (a $5/month VPS runs it). Swapping it in doesn’t require changing Hermes — Milvus slots behind the retrieval layer, so the Learning Loop stays intact. Hermes still picks which Skill to run, and Milvus handles what to retrieve.</p><p>But the deeper payoff goes beyond better recall: once retrieval works, the Learning Loop can store the retrieval strategy itself as a Skill — not just the content it retrieves. That’s how the agent’s knowledge work compounds across sessions.</p><h3>Hermes Agent Architecture: How Four-Layer Memory Powers the Skill Learning Loop</h3><p><a href="https://github.com/NousResearch/hermes-agent">Hermes</a> has four memory layers, and L4 Skills is the one that sets it apart.</p><ul><li>L1 — session context, cleared when the session closes</li><li>L2 — persisted facts: project stack, team conventions, resolved decisions</li><li>L3 — SQLite FTS5 keyword search over local files</li><li>L4 — stores workflows as Markdown files. Unlike LangChain tools or AutoGPT plugins, which developers author in code before deployment, L4 Skills are self-written: they grow from what the agent actually runs, with zero developer authoring.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*AvP7Iny3kSGcBnBs.png" /></figure><h3>Why Hermes’s FTS5 Keyword Retrieval Breaks the Learning Loop</h3><p>Hermes needs retrieval to trigger cross-session workflows in the first place. But its built-in L3 layer uses SQLite FTS5, which only matches literal tokens, not meaning.</p><p>When users phrase the same intent differently across sessions, FTS5 misses the match. The Learning Loop doesn’t fire. No new Skill gets written, and next time the intent comes around, the user is back to routing by hand.</p><p>Example: the knowledge base stores “asyncio event loop, async task scheduling, non-blocking I/O.” A user searches “Python concurrency.” FTS5 returns zero hits — no literal word overlap, and FTS5 has no way to see that they’re the same question.</p><p>Under a couple hundred documents, the gap is tolerable. Past that, documentation uses one vocabulary, and users ask in another, and FTS5 has no bridge between them. Unretrievable content might as well not be in the knowledge base, and the Learning Loop has nothing to learn from.</p><h3>How Milvus 2.6 Fixes the Retrieval Gap with Hybrid Search and Tiered Storage</h3><p>Milvus 2.6 brings two upgrades that fit Hermes’s failure points. Hybrid search unblocks the Learning Loop by covering both semantic and keyword retrieval in one call. Tiered storage keeps the whole retrieval backend small enough to run on the same $5/month VPS Hermes was built for.</p><h3>What Hybrid Search Solves: Finding Relevant Information</h3><p>Milvus 2.6 supports running both vector retrieval (semantic) and <a href="https://milvus.io/docs/full-text-search.md">BM25 full-text search</a> (keyword) in a single query, then merging the two ranked lists with <a href="https://milvus.io/docs/multi-vector-search.md">Reciprocal Rank Fusion (RRF)</a>.</p><p>For example: ask “what is the principle of asyncio”, and vector retrieval hits semantically related content. Ask “where is the find_similar_task function defined&quot;, and BM25 precisely matches the function name in code. For questions that involve a function inside a particular type of task, hybrid search returns the right result in one call, with no hand-written routing logic.</p><p>For Hermes, this is what unblocks the Learning Loop. When a second session rephrases the intent, vector retrieval catches the semantic match FTS5 missed. The loop fires, and a new Skill gets written.</p><h3>What Tiered Storage Solves: Cost</h3><p>A naive vector database would want the full embedding index in RAM, which pushes personal deployments toward bigger, more expensive infrastructure. Milvus 2.6 avoids that with three-tier storage, moving entries between tiers based on access frequency:</p><ul><li>Hot — in memory</li><li>Warm — on SSD</li><li>Cold — on object storage</li></ul><p>Only hot data stays resident. A 500-document knowledge base fits under 2 GB of RAM. The whole retrieval stack runs on the same $5/month VPS Hermes targets, with no infrastructure upgrade needed.</p><h3>Hermes + Milvus: System Architecture</h3><p>Hermes picks which Skill to run. Milvus handles what to retrieve. The two systems stay separate, and Hermes’s interface doesn’t change.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kgLE0P3HGf7bFPo7.png" /></figure><p>The flow:</p><ol><li>Hermes identifies the user’s intent and routes to a Skill.</li><li>The Skill calls a retrieval script through the terminal tool.</li><li>The script hits Milvus, runs hybrid search, and returns ranked chunks with source metadata.</li><li>Hermes composes the answer. Memory records the workflow.</li><li>When the same pattern repeats across sessions, the Learning Loop writes a new Skill.</li></ol><h3>How to Install Hermes and Milvus 2.6</h3><p>Install Hermes and <a href="https://milvus.io/docs/install_standalone-docker.md">Milvus 2.6 Standalone</a>, then create a collection with dense and BM25 fields. That’s the full setup before the Learning Loop can fire.</p><h3>Install Hermes</h3><pre>curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash</pre><p>Run hermes to enter the interactive init wizard:</p><ul><li>LLM provider — OpenAI, Anthropic, OpenRouter (OpenRouter has free models)</li><li>Channel — this walkthrough uses a FLark bot</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*j2ZwSxzvSCmZV978.png" /></figure><h3>Run Milvus 2.6 Standalone</h3><p>Single-node standalone is enough for a personal agent:</p><pre>curl -sfL https://raw.githubusercontent.com/milvus-io/milvus/master/scripts/standalone_embed.sh \<br>-o standalone_embed.sh<br>bash standalone_embed.sh start<br># Verify service status<br>docker ps | grep milvus</pre><h3>Create the Collection</h3><p>Schema design caps what retrieval can do. This schema runs dense vectors and BM25 sparse vectors side by side:</p><pre>from pymilvus import MilvusClient, DataType, Function, FunctionType<br>client = MilvusClient(<br>    uri=&quot;http://192.168.x.x:19530&quot;,<br>)<br>schema = client.create_schema(auto_id=True, enable_dynamic_field=True)<br>schema.add_field(&quot;id&quot;, DataType.INT64, is_primary=True)<br># Raw text (for BM25 full-text search)<br>schema.add_field(<br>    &quot;text&quot;,<br>    DataType.VARCHAR,<br>    max_length=8192,<br>    enable_analyzer=True,<br>    enable_match=True<br>)<br># Dense vector (semantic search)<br>schema.add_field(&quot;dense_vector&quot;, DataType.FLOAT_VECTOR, dim=1536)<br># Sparse vector (BM25 auto-generated, Milvus 2.6 feature)<br>schema.add_field(&quot;sparse_vector&quot;, DataType.SPARSE_FLOAT_VECTOR)<br>schema.add_field(&quot;source&quot;, DataType.VARCHAR, max_length=512)<br>schema.add_field(&quot;chunk_index&quot;, DataType.INT32)<br># Tell Milvus to auto-convert text to sparse_vector via BM25<br>bm25_function = Function(<br>    name=&quot;text_bm25&quot;,<br>    function_type=FunctionType.BM25,<br>    input_field_names=[&quot;text&quot;],<br>    output_field_names=[&quot;sparse_vector&quot;],<br>)<br>schema.add_function(bm25_function)<br>index_params = client.prepare_index_params()<br># HNSW graph index (dense vector)<br>index_params.add_index(<br>    field_name=&quot;dense_vector&quot;,<br>    index_type=&quot;HNSW&quot;,<br>    metric_type=&quot;COSINE&quot;,<br>    params={&quot;M&quot;: 16, &quot;efConstruction&quot;: 256}<br>)<br># BM25 inverted index (sparse vector)<br>index_params.add_index(<br>    field_name=&quot;sparse_vector&quot;,<br>    index_type=&quot;SPARSE_INVERTED_INDEX&quot;,<br>    metric_type=&quot;BM25&quot;<br>)<br>client.create_collection(<br>    collection_name=&quot;hermes_milvus&quot;,<br>    schema=schema,<br>    index_params=index_params<br>)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*SJsDi5jX67IJ9vlo.png" /></figure><h3>Hybrid Search Script</h3><pre>import sys, json<br>from openai import OpenAI<br>from pymilvus import MilvusClient, AnnSearchRequest, RRFRanker<br>client = MilvusClient(&quot;http://192.168.x.x:19530&quot;)<br>oai    = OpenAI()<br>COLLECTION = &quot;hermes_milvus&quot;<br>def hybrid_search(query: str, top_k: int = 5) -&gt; list[dict]:<br>    # 1. Vectorize query<br>    dense_vec = oai.embeddings.create(<br>        model=&quot;text-embedding-3-small&quot;,<br>        input=query<br>    ).data[0].embedding<br>    # 2. Dense vector retrieval (semantic relevance)<br>    dense_req = AnnSearchRequest(<br>        data=[dense_vec],<br>        anns_field=&quot;dense_vector&quot;,<br>        param={&quot;metric_type&quot;: &quot;COSINE&quot;, &quot;params&quot;: {&quot;ef&quot;: 128}},<br>        limit=top_k * 2       # Widen candidate set, let RRF do final ranking<br>    )<br>    # 3. BM25 sparse vector retrieval (exact term matching)<br>    bm25_req = AnnSearchRequest(<br>        data=[query],<br>        anns_field=&quot;sparse_vector&quot;,<br>        param={&quot;metric_type&quot;: &quot;BM25&quot;},<br>        limit=top_k * 2<br>    )<br>    # 4. RRF fusion ranking<br>    results = client.hybrid_search(<br>        collection_name=COLLECTION,<br>        reqs=[dense_req, bm25_req],<br>        ranker=RRFRanker(k=60),<br>        limit=top_k,<br>        output_fields=[&quot;text&quot;, &quot;source&quot;, &quot;doc_type&quot;]<br>    )<br>    return [<br>        {<br>            &quot;text&quot;:     r.entity.get(&quot;text&quot;),<br>            &quot;source&quot;:   r.entity.get(&quot;source&quot;),<br>            &quot;doc_type&quot;: r.entity.get(&quot;doc_type&quot;),<br>            &quot;score&quot;:    round(r.distance, 4)<br>        }<br>        for r in results[0]<br>    ]<br>if __name__ == &quot;__main__&quot;:<br>    query= sys.argv[1] if len(sys.argv) &gt; 1 else &quot;&quot;<br>    top_k  = int(sys.argv[2]) if len(sys.argv) &gt; 2 else 5<br>    output = hybrid_search(query, top_k)<br>    print(json.dumps(output, ensure_ascii=False, indent=2))</pre><p>The dense request widens the candidate pool by 2× so RRF has enough to rank from. text-embedding-3-small is the cheapest OpenAI embedding that still holds retrieval quality; swap in text-embedding-3-large if the budget allows.</p><p>With the environment and knowledge base ready, the next section puts the Learning Loop to the test.</p><h3>Hermes Skill Auto-Generation in Practice</h3><p>Two sessions show the Learning Loop in action. In the first, the user names the script by hand. In the second, a new session asks the same question without naming the script. Hermes picks up the pattern and writes three Skills.</p><h3>Session 1: Call the Script by Hand</h3><p>Open Hermes in Lark. Give it the script path and the retrieval target. Hermes invokes the terminal tool, runs the script, and returns the answer with source attribution. No Skill exists yet. This is a plain tool call.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*RN81u_ef7YNjVUfK.png" /></figure><h3>Session 2: Ask Without Naming the Script</h3><p>Clear the conversation. Start fresh. Ask the same category of question without mentioning the script or path.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kxW45jTaQFHb3RQ8.png" /></figure><h3>Memory Writes First, Skill Follows</h3><p>The Learning Loop records the workflow (script, arguments, return shape) and returns the answer. Memory holds the trace; no Skill exists yet.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1LucZX8bOsTLJBzW.png" /></figure><p>The second session’s match tells the loop the pattern is worth keeping. When it fires, three Skills get written:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fuQ5W7C4CQkCOr-YeXhaDA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ZxxDProM2g4Wk2UM.png" /></figure><p>From this point on, users stop naming Skills. Hermes infers intent, routes to the Skill, pulls the relevant chunks from Memory, and writes the answer. There’s no Skill selector in the prompt.</p><p>Most RAG (retrieval-augmented generation) systems solve the storing-and-fetching problem, but the fetch logic itself is hard-coded in application code. Ask in a different way or in a new scenario, and retrieval breaks. Hermes stores the fetch strategy as a Skill, which means the fetch path becomes a document you can read, edit, and version. The line 💾 Memory updated · Skill &#39;hybrid-search-doc-qa&#39; created isn’t a setup-complete marker. It’s the Agent committing a behavior pattern to long-term memory.</p><h3>Hermes vs. OpenClaw: Accumulation vs. Orchestration</h3><p>Hermes and OpenClaw answer different problems. Hermes is built for a single agent that accumulates memory and skills across sessions. OpenClaw is built for breaking a complex task into pieces and handing each piece to a specialized agent.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*QtwifX8bF_7OXe5L.png" /></figure><p>OpenClaw’s strength is orchestration. It optimizes for how much of a task gets done automatically. Hermes’s strength is accumulation: a single agent that remembers across sessions, with skills that grow from use. Hermes optimizes for long-term context and domain experience.</p><p>The two frameworks stack. Hermes ships a one-step migration path that pulls ~/.openclaw memory and skills into Hermes’s memory layers. An orchestration stack can sit on top, with an accumulation agent underneath.</p><p>For the OpenClaw side of the split, see <a href="https://milvus.io/blog/openclaw-formerly-clawdbot-moltbot-explained-a-complete-guide-to-the-autonomous-ai-agent.md">What Is OpenClaw? Complete Guide to the Open-Source AI Agent</a> on the Milvus blog.</p><h3>Conclusion</h3><p>Hermes’s Learning Loop turns repeated workflows into reusable Skills, but only if retrieval can connect them across sessions. FTS5 keyword search can’t. <a href="https://milvus.io/docs/multi-vector-search.md">Milvus 2.6 hybrid search</a> can: dense vectors handle meaning, BM25 handles exact keywords, RRF merges both, and <a href="https://milvus.io/docs/tiered-storage-overview.md">tiered storage</a> keeps the whole stack on a $5/month VPS.</p><p>The bigger point: once retrieval works, the agent doesn’t just store better answers: it stores better retrieval strategies as Skills. The fetch path becomes a versionable document that improves with use. That’s what separates an agent that accumulates domain expertise from one that starts fresh every session. For a comparison of how other agents handle (or fail to handle) this problem, see <a href="https://milvus.io/blog/claude-code-memory-memsearch.md">Claude Code’s Memory System Explained.</a></p><h3>Get Started</h3><p>Try the tools in this article:</p><ul><li><a href="https://github.com/NousResearch/hermes-agent">Hermes Agent on GitHub</a> — install script, provider setup, and channel configuration used above.</li><li><a href="https://milvus.io/docs/install_standalone-docker.md">Milvus 2.6 Standalone Quickstart</a> — single-node Docker deploy for the knowledge-base backend.</li><li><a href="https://milvus.io/docs/multi-vector-search.md">Milvus Hybrid Search Tutorial</a> — full dense + BM25 + RRF example matching the script in this post.</li></ul><p>Got questions about Hermes + Milvus hybrid search?</p><ul><li>Join the <a href="https://discord.gg/milvus">Milvus Discord</a> to ask about hybrid search, tiered storage, or Skill-routing patterns — other developers are building similar stacks.</li><li><a href="https://milvus.io/community#office-hours">Book a Milvus Office Hours session</a> to walk through your own agent + knowledge-base setup with the Milvus team.</li></ul><p>Want to skip the self-host?</p><ul><li><a href="https://cloud.zilliz.com/signup">Sign up</a> or <a href="https://cloud.zilliz.com/login">sign in</a> to Zilliz Cloud — managed Milvus with hybrid search and tiered storage out of the box. New work-email accounts get $100 in free credits.</li></ul><h3>Further Reading</h3><ul><li><a href="https://milvus.io/docs/release_notes.md">Milvus 2.6 release notes</a> — tiered storage, hybrid search, schema changes</li><li><a href="https://zilliz.com/blog">Zilliz Cloud &amp; Milvus CLI + Official Skills</a> — operational tooling for Milvus-native agents</li><li><a href="https://zilliz.com/blog">Why RAG-Style Knowledge Management Breaks for Agents</a> — the case for agent-specific memory design</li><li><a href="https://zilliz.com/blog">Claude Code’s Memory System Is More Primitive Than You’d Expect</a> — comparison piece on another agent’s memory stack</li></ul><h3>Frequently Asked Questions</h3><h3>How does Hermes Agent’s Skill Learning Loop actually work?</h3><p>Hermes records every workflow it runs — the script called, arguments passed, and return shape — as a memory trace. When the same pattern appears across two or more sessions, the Learning Loop fires and writes a reusable Skill: a Markdown file that captures the workflow as a repeatable procedure. From that point on, Hermes routes to the Skill by intent alone, without the user naming it. The critical dependency is retrieval — the loop only fires if it can find the earlier session’s trace, which is why keyword-only search becomes a bottleneck at scale.</p><h3>What’s the difference between hybrid search and vector-only search for agent memory?</h3><p>Vector-only search handles meaning well but misses exact matches. If a developer pastes an error string like ConnectionResetError or a function name like find_similar_task, a pure vector search might return semantically related but wrong results. Hybrid search combines dense vectors (semantic) with BM25 (keyword) and merges the two result sets with Reciprocal Rank Fusion. For agent memory — where queries range from vague intent (“Python concurrency”) to exact symbols — hybrid search covers both ends in a single call without routing logic in your application layer.</p><h3>Can I use Milvus hybrid search with AI agents other than Hermes?</h3><p>Yes. The integration pattern is generic: the agent calls a retrieval script, the script queries Milvus, and results return as ranked chunks with source metadata. Any agent framework that supports tool calls or shell execution can use the same approach. Hermes happens to be a strong fit because its Learning Loop specifically depends on cross-session retrieval to fire, but the Milvus side is agent-agnostic — it doesn’t know or care which agent is calling it.</p><h3>How much does a self-hosted Milvus + Hermes setup cost per month?</h3><p>A single-node Milvus 2.6 Standalone on a 2-core / 4 GB VPS with tiered storage runs about $5/month. OpenAI text-embedding-3-small costs $0.02 per 1M tokens — a few cents per month for a personal knowledge base. LLM inference dominates total cost and scales with usage, not with the retrieval stack.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=196afb882033" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Claude Context: Reduce Claude Code Token Usage with Milvus-Powered Code Retrieval]]></title>
            <link>https://milvusio.medium.com/claude-context-reduce-claude-code-token-usage-with-milvus-powered-code-retrieval-bce6e516aadf?source=rss-a31576809ee1------2</link>
            <guid isPermaLink="false">https://medium.com/p/bce6e516aadf</guid>
            <dc:creator><![CDATA[Milvus]]></dc:creator>
            <pubDate>Mon, 15 Jun 2026 02:43:05 GMT</pubDate>
            <atom:updated>2026-06-15T02:43:05.660Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kcpK-ugRxRp4wzNvOPcAww.png" /></figure><p>Large context windows make AI coding agents feel limitless, right up until they start reading half your repository to answer one question. For many Claude Code users, the expensive part is not just model reasoning. It is the retrieval loop: search a keyword, read a file, search again, read more files, and keep paying for irrelevant context.</p><p>Claude Context is an open-source code retrieval MCP server that gives Claude Code and other AI coding agents a better way to find relevant code. It indexes your repository, stores searchable code chunks in a <a href="https://zilliz.com/learn/what-is-vector-database">vector database</a>, and uses <a href="https://zilliz.com/blog/hybrid-search-with-milvus">hybrid retrieval</a> so the agent can pull in the code it actually needs instead of flooding the prompt with grep results.</p><p>In our benchmarks, Claude Context reduced token consumption by 39.4% on average and cut tool calls by 36.1% while preserving retrieval quality. This post explains why grep-style retrieval wastes context, how Claude Context works under the hood, and how it compares with a baseline workflow on real debugging tasks.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*4MxO_IbNdg_7DbID.png" /></figure><p>Claude Context GitHub repository trending and passing 10,000 stars</p><h3>Why grep-style code retrieval burns tokens in AI coding agents</h3><p>An AI coding agent can only write useful code if it understands the codebase around the task: function call paths, naming conventions, related tests, data models, and historical implementation patterns. A large context window helps, but it does not solve the retrieval problem. If the wrong files enter the context, the model still wastes tokens and may reason from irrelevant code.</p><p>Code retrieval usually falls into two broad patterns:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ARrD8wLolQRemwnMyOVPkQ.png" /></figure><p>This is the same distinction developers see in <a href="https://zilliz.com/blog/metadata-filtering-hybrid-search-or-agent-in-rag-applications">RAG application</a> design: literal matching is useful, but it is rarely enough when meaning matters. A function named compute_final_cost() may be relevant to a query about calculate_total_price() even if the exact words do not match. That is where <a href="https://zilliz.com/blog/semantic-search-vs-lexical-search-vs-full-text-search">semantic search</a> helps.</p><p>In one debugging run, Claude Code repeatedly searched and read files before locating the right area. After several minutes, only a small fraction of the code it had consumed was relevant.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*gud_mg7UmrMtHYYp.png" /></figure><p>Claude Code grep-style search spending time on irrelevant file reads</p><p>That pattern is common enough that developers complain about it publicly: the agent can be smart, but the context retrieval loop still feels expensive and imprecise.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*q-n7lmZwGWo6Mybl.png" /></figure><p>Developer comment about Claude Code context and token usage</p><p>Grep-style retrieval fails in three predictable ways:</p><ul><li>Information overload: large repositories produce many literal matches, and most are not useful for the current task.</li><li>Semantic blindness: grep matches strings, not intent, behavior, or equivalent implementation patterns.</li><li>Context loss: line-level matches do not automatically include the surrounding class, dependencies, tests, or call graph.</li></ul><p>A better code retrieval layer needs to combine keyword precision with semantic understanding, then return complete enough chunks for the model to reason about the code.</p><h3>What is Claude Context?</h3><p>Claude Context is an open-source <a href="https://zilliz.com/glossary/model-context-protocol-(mcp)">Model Context Protocol</a> server for code retrieval. It connects AI coding tools to a Milvus-backed code index, so an agent can search a repository by meaning instead of relying only on literal text search.</p><p>The goal is simple: when the agent asks for context, return the smallest useful set of code chunks. Claude Context does this by parsing the codebase, generating embeddings, storing chunks in the <a href="https://zilliz.com/what-is-milvus">Milvus vector database</a>, and exposing retrieval through MCP-compatible tools.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cbNZAuU-HxZXT5bMKNvCxw.png" /></figure><p>Because Claude Context is exposed through MCP, it can work with Claude Code, Gemini CLI, Cursor-style MCP hosts, and other MCP-compatible environments. The same core retrieval layer can support multiple agent interfaces.</p><h3>How Claude Context works under the hood</h3><p>Claude Context has two main layers: a reusable core module and integration modules. The core handles parsing, chunking, indexing, search, and incremental sync. The upper layer exposes those capabilities through MCP and editor integrations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*g9LsE-oOtiw51DA3.png" /></figure><p>Claude Context architecture showing MCP integrations, core module, embedding provider, and vector database</p><h3>How does MCP connect Claude Context to coding agents?</h3><p>MCP provides the interface between the LLM host and external tools. By exposing Claude Context as an MCP server, the retrieval layer stays independent from any one IDE or coding assistant. The agent calls a search tool; Claude Context handles the code index and returns relevant chunks.</p><p>If you want to understand the broader pattern, the <a href="https://milvus.io/docs/milvus_and_mcp.md">MCP + Milvus guide</a> shows how MCP can connect AI tools to vector database operations.</p><h3>Why use Milvus for code retrieval?</h3><p>Code retrieval needs fast vector search, metadata filtering, and enough scale to handle large repositories. Milvus is designed for high-performance vector search and can support dense vectors, sparse vectors, and reranking workflows. For teams building retrieval-heavy agent systems, the <a href="https://milvus.io/docs/multi-vector-search.md">multi-vector hybrid search</a> docs and <a href="https://milvus.io/api-reference/pymilvus/v2.6.x/MilvusClient/Vector/hybrid_search.md">PyMilvus hybrid_search API</a> show the same underlying retrieval pattern used in production systems.</p><p>Claude Context can use Zilliz Cloud as the managed Milvus backend, which avoids running and scaling the vector database yourself. The same architecture can also be adapted to self-managed Milvus deployments.</p><h3>Which embedding providers does Claude Context support?</h3><p>Claude Context supports multiple embedding options:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*06TERgVH1CAVUXoYCwtC2w.png" /></figure><p>For related Milvus workflows, see the <a href="https://milvus.io/docs/embeddings.md">Milvus embedding overview</a>, <a href="https://milvus.io/docs/embed-with-openai.md">OpenAI embedding integration</a>, <a href="https://milvus.io/docs/embed-with-voyage.md">Voyage embedding integration</a>, and examples of running <a href="https://zilliz.com/blog/simplifying-legal-research-with-rag-milvus-ollama">Ollama with Milvus</a>.</p><h3>Why is the core library written in TypeScript?</h3><p>Claude Context is written in TypeScript because many coding-agent integrations, editor plugins, and MCP hosts are already TypeScript-heavy. Keeping the retrieval core in TypeScript makes it easier to integrate with application-layer tooling while still exposing a clean API.</p><p>The core module abstracts the vector database and embedding provider into a composable Context object:</p><pre>import { Context, MilvusVectorDatabase, OpenAIEmbedding } from &#39;@zilliz/claude-context-core&#39;;<br>// Initialize embedding provider<br>const embedding = new OpenAIEmbedding(...);<br>// Initialize vector database<br>const vectorDatabase = new MilvusVectorDatabase(...);<br>// Create context instance<br>const context = new Context({embedding, vectorDatabase});<br>// Index your codebase with progress tracking<br>const stats = await context.indexCodebase(&#39;./your-project&#39;);<br>// Perform semantic search<br>const results = await context.semanticSearch(&#39;./your-project&#39;, &#39;vector database operations&#39;);</pre><h3>How Claude Context chunks code and keeps indexes fresh</h3><p>Chunking and incremental updates determine whether a code retrieval system is usable in practice. If chunks are too small, the model loses context. If chunks are too large, the retrieval system returns noise. If indexing is too slow, developers stop using it.</p><p>Claude Context handles this with AST-based chunking, a fallback text splitter, and Merkle tree-based change detection.</p><h3>How does AST-based code chunking preserve context?</h3><p>AST chunking is the primary strategy. Instead of splitting files by line count or character count, Claude Context parses code structure and chunks around semantic units such as functions, classes, and methods.</p><p>That gives each chunk three useful properties:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Euy4cBZSlNWA3aRHSIuO9w.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*oS2-d2ifvwflmuhY.png" /></figure><h3>What happens when AST parsing fails?</h3><p>For languages or files that AST parsing cannot handle, Claude Context falls back to LangChain’s RecursiveCharacterTextSplitter. It is less precise than AST chunking, but it prevents indexing from failing on unsupported input.</p><pre>// Use recursive character splitting to preserve code structure<br>const splitter = RecursiveCharacterTextSplitter.fromLanguage(language, {<br>    chunkSize: 1000,<br>    chunkOverlap: 200,<br>});</pre><h3>How does Claude Context avoid re-indexing the whole repository?</h3><p>Re-indexing an entire repository after every change is too expensive. Claude Context uses a Merkle tree to detect exactly what changed.</p><p>A Merkle tree assigns each file a hash, derives each directory hash from its children, and rolls the whole repository into a root hash. If the root hash is unchanged, Claude Context can skip indexing. If the root changes, it walks down the tree to find the changed files and re-embeds only those files.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*IGIVuC6qVFfrtXSw.png" /></figure><p>Merkle tree change detection comparing unchanged and changed file hashes</p><p>Sync runs in three stages:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*w-gZYkH19VcnnRYbW9cr3Q.png" /></figure><p>Local sync state is stored under ~/.context/merkle/, so Claude Context can restore the file hash table and serialized Merkle tree after a restart.</p><h3>What happens when Claude Code uses Claude Context?</h3><p>Setup is a single command before launching Claude Code:</p><pre>claude mcp add claude-context -e OPENAI_API_KEY=your-openai-api-key -e MILVUS_TOKEN=your-zilliz-cloud-api-key -- npx @zilliz/claude-context-mcp@latest</pre><p>After indexing the repository, Claude Code can call Claude Context when it needs codebase context. In the same bug-finding scenario that previously burned time on grep and file reads, Claude Context found the exact file and line number with a full explanation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Q3efjIbx_tdIkYE_.gif" /></figure><p>The tool is not limited to bug hunting. It also helps with refactoring, duplicate code detection, issue resolution, test generation, and any task where the agent needs accurate repository context.</p><p>At equivalent recall, Claude Context reduced token consumption by 39.4% and reduced tool calls by 36.1% in our benchmark. That matters because tool calls and irrelevant file reads often dominate the cost of coding-agent workflows.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*AlXFUM2uUVeWt_id.png" /></figure><p>Benchmark chart showing Claude Context reducing token usage and tool calls versus baseline</p><p>The project now has more than 10,000 GitHub stars, and the repository includes the full benchmark details and package links.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*clD1S4LIKcg6vc4A.png" /></figure><p>Claude Context GitHub star history showing rapid growth</p><h3>How does Claude Context compare with grep on real bugs?</h3><p>The benchmark compares pure text search with Milvus-backed code retrieval on real debugging tasks. The difference is not just fewer tokens. Claude Context changes the agent’s search path: it starts closer to the implementation that needs to change.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nr4bSHh9y3f2_oVY-p-y-Q.png" /></figure><h3>Case 1: Django YearLookup bug</h3><p>Problem description: In the Django framework, the YearLookup query optimization breaks __iso_year filtering. When using the __iso_year filter, the YearLookup class incorrectly applies the standard BETWEEN optimization — valid for calendar years, but not for ISO week-numbering years.</p><pre># This should use EXTRACT(&#39;isoyear&#39; FROM ...) but incorrectly uses BETWEEN<br>DTModel.objects.filter(start_date__iso_year=2020)<br># Generated: WHERE &quot;start_date&quot; BETWEEN 2020-01-01 AND 2020-12-31<br># Should be: WHERE EXTRACT(&#39;isoyear&#39; FROM &quot;start_date&quot;) = 2020</pre><p>Baseline (grep):</p><pre>🔧 directory_tree()<br>⚙️ Result: Retrieved 3000+ lines of directory structure (~50k tokens)<br>   Problem: Massive information overload, no direct relevance<br>🔧 search_text(&#39;ExtractIsoYear&#39;)<br>⚙️ Result: Found 21 matches across multiple files:<br>   - django/db/models/functions/__init__.py:5 (import statement)<br>   - django/db/models/functions/__init__.py:31 (export list)  <br>   - django/db/models/functions/datetime.py:93 (ExtractIsoYear class)<br>   Problem: Most are unrelated imports and registrations<br>🔧 edit_file(&#39;django/db/models/functions/datetime.py&#39;)<br>⚙️ Modified multiple registration statements, but this is the wrong direction for a fix</pre><p>The text search focused on ExtractIsoYear registration instead of the optimization logic in YearLookup.</p><p>Claude Context:</p><pre>🔧 search_code(&#39;YearLookup&#39;)<br>⚙️ Found 10 results for query: &quot;YearLookup&quot; across the codebase<br>   1. Code snippet (python) [repo__django__django]<br>      Location: django/db/models/lookups.py:568-577<br>      Context: YearExact class and get_bound_params method<br>   2. Code snippet (python) [repo__django__django]  <br>      Location: django/db/models/lookups.py:538-569<br>      Context: YearLookup base class and year_lookup_bounds method<br>🔧 edit_file(django/db/models/lookups.py)<br>⚙️ Successfully modified the core optimization logic, adding ISO year handling</pre><p>Semantic search understood YearLookup as the core concept and went straight to the right class.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*qOE9BDpTgbUVQhzr.png" /></figure><p>Django YearLookup benchmark table showing 93 percent fewer tokens with Claude Context</p><p>Result: 93% fewer tokens.</p><h3>Case 2: Xarray swap_dims bug</h3><p>Problem description: The Xarray library’s .swap_dims() method unexpectedly mutates the original object, violating the expectation of immutability.</p><pre>import numpy as np<br>import xarray as xr<br>nz = 11<br>ds = xr.Dataset({<br>    &quot;y&quot;: (&quot;z&quot;, np.random.rand(nz)),<br>    &quot;lev&quot;: (&quot;z&quot;, np.arange(nz) * 10),<br>})<br># This shouldn&#39;t modify ds, but it does<br>ds2 = ds.swap_dims(z=&quot;lev&quot;).rename_dims(lev=&quot;z&quot;).reset_index(&quot;lev&quot;).reset_coords()<br>ds2.swap_dims(z=&#39;lev&#39;)  # this unexpectedly modifies ds2[&#39;lev&#39;]<br># ds2[&#39;lev&#39;] now has dimension &#39;lev&#39; instead of &#39;z&#39;</pre><p>Baseline (grep):</p><pre>🔧 list_directory(&#39;repo__pydata__xarray&#39;)<br>⚙️ Result: Retrieved directory structure across multiple subdirectories<br>   Problem: Basic directory navigation, no targeted search<br>🔧 search_text(&#39;swap_dims&#39;)<br>⚙️ Result: Found 21 matches across core files:<br>   - xarray/core/common.py:600 (Dataset.swap_dims reference)<br>   - xarray/core/dataarray.py:753 (&quot;.rename() or .swap_dims() instead.&quot;)<br>   - xarray/core/dataarray.py:2026 (DataArray.swap_dims reference)<br>   - xarray/core/dataarray.py:2044 (def swap_dims method)<br>   Problem: Many matches scattered across different contexts<br>🔧 read_file(&#39;xarray/core/dataarray.py&#39;, offset=2000, limit=40)<br>⚙️ Result: Read lines 2001-2040 showing rename method documentation<br>🔧 read_file(&#39;xarray/core/dataset.py&#39;, offset=3600, limit=40) <br>⚙️ Result: Read lines 3601-3640 showing rename_dims method</pre><p>The baseline spent time navigating directories and reading nearby code before locating the actual implementation path.</p><p>Claude Context:</p><pre>🔧 search_code(&#39;.swap_dims()&#39;)<br>⚙️ Found 10 results for query: &quot;.swap_dims()&quot; across the codebase<br>   1. Code snippet (python) [repo__pydata__xarray]<br>      Location: xarray/tests/test_formatting_html.py:67-76<br>   2. Code snippet (python) [repo__pydata__xarray]<br>      Location: xarray/tests/test_dataset.py:2926-2979<br>🔧 edit_file(&#39;xarray/core/dataset.py&#39;)<br>⚙️ Successfully modified the file, added dimension handling logic<br>🔧 edit_file(&#39;xarray/core/dataarray.py&#39;)<br>⚙️ Successfully modified the file, ensuring the original DataArray is not mutated</pre><p>Semantic search located the relevant swap_dims() implementation and related context faster.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*DHawV3y6Ppk5yzvr.png" /></figure><p>Xarray swap_dims benchmark table showing 62 percent fewer tokens with Claude Context</p><p>Result: 62% fewer tokens.</p><h3>Get started with Claude Context</h3><p>If you want to try the exact tool from this post, start with the <a href="https://github.com/zilliztech/claude-context">Claude Context GitHub repository</a> and the <a href="https://www.npmjs.com/package/%40zilliz/claude-context-mcp">Claude Context MCP package</a>. The repository includes setup instructions, benchmarks, and the core TypeScript packages.</p><p>If you want to understand or customize the retrieval layer, these resources are useful next steps:</p><ul><li>Learn the vector database basics with the <a href="https://milvus.io/docs/quickstart.md">Milvus Quickstart</a>.</li><li>Explore <a href="https://milvus.io/docs/full-text-search.md">Milvus full text search</a> and the <a href="https://milvus.io/docs/full_text_search_with_milvus.md">LangChain full-text search tutorial</a> if you want to combine BM25-style search with dense vectors.</li><li>Review <a href="https://zilliz.com/blog/top-5-open-source-vector-search-engines">open-source vector search engines</a> if you are comparing infrastructure options.</li><li>Try the <a href="https://zilliz.com/blog/zilliz-cloud-just-landed-in-claude-code">Zilliz Cloud Plugin for Claude Code</a> if you want vector database operations directly inside the Claude Code workflow.</li></ul><p>For help with Milvus or code retrieval architecture, join the <a href="https://milvus.io/community/">Milvus community</a> or book <a href="https://milvus.io/office-hours">Milvus Office Hours</a> for one-on-one guidance. If you would rather skip infrastructure setup, <a href="https://cloud.zilliz.com/signup">sign up for Zilliz Cloud</a> or <a href="https://cloud.zilliz.com/login">sign in to Zilliz Cloud</a> and use managed Milvus as the backend.</p><h3>Frequently Asked Questions</h3><h3>Why does Claude Code use so many tokens on some coding tasks?</h3><p>Claude Code can use many tokens when a task requires repeated search and file-reading loops across a large repository. If the agent searches by keyword, reads irrelevant files, and then searches again, every file read adds tokens even when the code is not useful for the task.</p><h3>How does Claude Context reduce Claude Code token usage?</h3><p>Claude Context reduces token usage by searching a Milvus-backed code index before the agent reads files. It retrieves relevant code chunks with hybrid search, so Claude Code can inspect fewer files and spend more of its context window on code that actually matters.</p><h3>Is Claude Context only for Claude Code?</h3><p>No. Claude Context is exposed as an MCP server, so it can work with any coding tool that supports MCP. Claude Code is the main example in this post, but the same retrieval layer can support other MCP-compatible IDEs and agent workflows.</p><h3>Do I need Zilliz Cloud to use Claude Context?</h3><p>Claude Context can use Zilliz Cloud as a managed Milvus backend, which is the easiest path if you do not want to operate vector database infrastructure. The same retrieval architecture is based on Milvus concepts, so teams can also adapt it to self-managed Milvus deployments.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bce6e516aadf" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Add Long-Term Memory to Anthropic’s Managed Agents with Milvus]]></title>
            <link>https://milvusio.medium.com/how-to-add-long-term-memory-to-anthropics-managed-agents-with-milvus-c88fcf30054e?source=rss-a31576809ee1------2</link>
            <guid isPermaLink="false">https://medium.com/p/c88fcf30054e</guid>
            <dc:creator><![CDATA[Milvus]]></dc:creator>
            <pubDate>Mon, 15 Jun 2026 02:42:41 GMT</pubDate>
            <atom:updated>2026-06-15T02:42:41.411Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MWpzcn5ospXaf11r4KvU-A.png" /></figure><p>Anthropic’s <a href="https://www.anthropic.com/engineering/managed-agents">Managed Agents</a> make agent infrastructure resilient. A 200-step task now survives a harness crash, a sandbox timeout, or a mid-flight infrastructure change without human intervention, and Anthropic reports p50 time-to-first-token dropped roughly 60% and p95 dropped over 90% after the decoupling.</p><p>What reliability doesn’t solve is memory. A 200-step code migration that hits a new dependency conflict on step 201 can’t efficiently look back at how it handled the last one. An agent running vulnerability scans for one customer has no idea that another agent already solved the same case an hour ago. Every session starts on a blank page, and parallel brains have no access to what the others have already worked out.</p><p>The fix is to pair the <a href="https://milvus.io/">Milvus vector database</a> with Anthropic’s Managed Agents: semantic recall within a session, and a shared <a href="https://milvus.io/docs/milvus_for_agents.md">vector memory layer</a> across sessions. The session contract stays untouched, the harness gets one new layer, and long-horizon agent tasks get qualitatively different capabilities.</p><h3>What Managed Agents Solved (and What They Didn’t)</h3><p>Managed Agents solved reliability by decoupling the agent into three independent modules. What it didn’t solve is memory, either as semantic recall inside a single session or as shared experience across parallel sessions. Here’s what got decoupled, and where the memory gap sits inside that decoupled design.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_AY2ajOjah_Xy44H66nDcg.png" /></figure><p>The reframe that makes this design work is stated explicitly in Anthropic’s post:</p><p><em>“The session is not Claude’s context window.”</em></p><p>The context window is ephemeral: bounded in tokens, reconstructed per model call, and discarded when the call returns. The session is durable, stored outside the harness, and represents the system of record for the entire task.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*0sGTCdmcx7elwRbi.png" /></figure><p>When a harness crashes, the platform starts a fresh one with wake(sessionId). The new harness reads the event log via getSession(id), and the task picks up from the last recorded step, with no custom recovery logic to write and no session-level babysitting to operate.</p><p>What the Managed Agents post doesn’t address, and doesn’t claim to, is what the agent does when it needs to remember anything. Two gaps show up the moment you push real workloads through the architecture. One lives inside a single session; the other lives across sessions.</p><h3>Problem 1: Why Linear Session Logs Fail Past a Few Hundred Steps</h3><p>Linear session logs fail past a few hundred steps because sequential reads and semantic search are fundamentally different workloads, and the **getEvents()** API serves only the first one. Slicing by position or seeking to a timestamp is enough to answer “where did this session leave off.” It is not enough to answer the question an agent will predictably need on any long task: have we seen this kind of problem before, and what did we do about it?</p><p>Consider a code migration at step 200 that hits a new dependency conflict. The natural move is to look back. Did the agent run into something similar earlier in this same task? What approach was tried? Did it hold, or did it regress something else downstream?</p><p>With getEvents() there are two ways to answer that, and both are bad:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XZKFFsxsXYs9xzq6vC1_vw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*jhHm8qL_7mhEkE8D.png" /></figure><p>The session is good for recovery and audit, but it was not built with an index that supports “have I seen this before.” Long-horizon tasks are where that question stops being optional.</p><h3>Solution 1: How to Add Semantic Memory to a Managed Agent’s Session</h3><p>Add a Milvus collection alongside the session log and dual-write from **emitEvent**. The session contract stays untouched, and the harness gains semantic query over its own past.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_sj6r72o7uExsDDX.png" /></figure><p>Anthropic’s design leaves headroom for exactly this. Their post states that “any fetched events can also be transformed in the harness before being passed to Claude’s context window. These transformations can be whatever the harness encodes, including context organization… and context engineering.” Context engineering lives in the harness; the session only has to guarantee durability and queryability.</p><p>The pattern: every time emitEvent fires, the harness also computes a <a href="https://zilliz.com/learn/everything-you-need-to-know-about-vector-embeddings">vector embedding</a> for events worth indexing and inserts them into a Milvus collection.</p><pre>rom pymilvus import MilvusClient<br><br>milvus_client = MilvusClient(uri=&quot;http://localhost:19530&quot;)<br><br># Only index high-signal events. Tool retries and intermediate states are noise.<br>INDEXABLE_EVENT_TYPES = {&quot;decision&quot;, &quot;strategy&quot;, &quot;resolution&quot;, &quot;error_handling&quot;}<br><br>async def emit_event(session_id: str, event: dict):<br>    # Original path: append to the session event stream.<br>    await session_store.append(session_id, event)<br><br>    # Extended path: embed the event content and insert into Milvus.<br>    if event[&quot;type&quot;] in INDEXABLE_EVENT_TYPES:<br>        embedding = await embed(event[&quot;content&quot;])<br>        milvus_client.insert(<br>            collection_name=&quot;agent_memory&quot;,<br>            data=[{<br>                &quot;vector&quot;:     embedding,<br>                &quot;session_id&quot;: session_id,<br>                &quot;step&quot;:       event[&quot;step&quot;],<br>                &quot;event_type&quot;: event[&quot;type&quot;],<br>                &quot;content&quot;:    event[&quot;content&quot;],<br>            }]<br>        )</pre><p>When the agent hits step 200 and needs to recall prior decisions, the query is a <a href="https://zilliz.com/glossary/vector-similarity-search">vector search</a> scoped to that session:</p><pre>async def recall_similar(query: str, session_id: str, top_k: int = 5):<br>    query_vector = await embed(query)<br>    results = milvus_client.search(<br>        collection_name=&quot;agent_memory&quot;,<br>        data=[query_vector],<br>        filter=f&#39;session_id == &quot;{session_id}&quot;&#39;,<br>        limit=top_k,<br>        output_fields=[&quot;step&quot;, &quot;event_type&quot;, &quot;content&quot;]<br>    )<br>    return results[0]  # top_k most relevant past events</pre><p>Three production details matter before this ships:</p><ul><li>Pick what to index. Not every event deserves an embedding. Tool-call intermediate states, retry logs, and repetitive status events pollute retrieval quality faster than they improve it. The INDEXABLE_EVENT_TYPES policy is task-dependent, not global.</li><li>Define the consistency boundary. If the harness crashes between the session append and the Milvus insert, one layer is briefly ahead of the other. The window is small but real. Pick a reconciliation path (retry on restart, write-ahead log, or eventual reconciliation) rather than hoping.</li><li>Control embedding spend. A 200-step session that calls an external embedding API synchronously on every step produces an invoice nobody planned for. Queue embeddings and send them asynchronously in batches.</li></ul><p>With those in place, recall takes milliseconds for the vector search plus under 100ms for the embedding call. The top-five most relevant past events land in context before the agent notices friction. The session keeps its original job as the durable log; the harness gains the ability to query its own past semantically rather than sequentially. That’s a modest change at the API surface and a structural change in what the agent can do on long-horizon tasks.</p><h3>Problem 2: Why Parallel Claude Agents Can’t Share Experience</h3><p>Parallel Claude agents can’t share experience because Managed Agents sessions are isolated by design. The same isolation that makes horizontal scaling clean also prevents every brain from learning from every other brain.</p><p>In a decoupled harness, brains are stateless and independent. That isolation unlocks the latency wins Anthropic reports, and it also keeps every session running in the dark about every other session.</p><p>Agent A spends 40 minutes diagnosing a tricky SQL injection vector for one customer. An hour later, Agent B picks up the same case for a different customer and spends its own 40 minutes walking the same dead ends, running the same tool calls, and arriving at the same answer.</p><p>For a single user running the occasional agent, that is wasted compute. For a platform running dozens of concurrent <a href="https://zilliz.com/glossary/ai-agents">AI agents</a> across code review, vulnerability scans, and documentation generation for different customers every day, the cost compounds structurally.</p><p>If the experience every session produces evaporates the moment the session ends, the intelligence is disposable. A platform built this way scales linearly but doesn’t get better at anything over time, the way human engineers do.</p><h3>Solution 2: How to Build a Shared Agent Memory Pool with Milvus</h3><p>Build one vector collection that every harness reads from at startup and writes to at shutdown, partitioned by tenant so experience pools across sessions without leaking across customers.</p><p>When a session ends, the key decisions, problems encountered, and approaches that worked are pushed into the shared Milvus collection. When a new brain initializes, the harness runs a semantic query as part of setup and injects the top-matching past experiences into the context window. Step one of the new agent inherits the lessons of every prior agent.</p><p>Two engineering decisions carry this from prototype to production.</p><h3>Isolating Tenants with the Milvus Partition Key</h3><p>Partition by **tenant_id**, and Customer A’s agent experiences physically don’t live in the same partition as Customer B’s. That’s isolation at the data layer rather than a query convention.</p><p>Brain A’s work on Company A’s codebase should never be retrievable by Company B’s agents. Milvus’s <a href="https://milvus.io/docs/use-partition-key.md">partition key</a> handles this on a single collection, with no second collection per tenant and no sharding logic in application code.</p><pre># Declare partition key at schema creation.<br>schema.add_field(<br>    field_name=&quot;tenant_id&quot;,<br>    datatype=DataType.VARCHAR,<br>    max_length=64,<br>    is_partition_key=True   # Automatic per-tenant partitioning.<br>)<br><br># Every query filters by tenant. Isolation is automatic.<br>results = milvus_client.search(<br>    collection_name=&quot;shared_agent_memory&quot;,<br>    data=[query_vector],<br>    filter=f&#39;tenant_id == &quot;{current_tenant}&quot;&#39;,<br>    limit=5,<br>    output_fields=[&quot;content&quot;, &quot;step&quot;, &quot;session_id&quot;]<br>)</pre><p>Customer A’s agent experiences never surface in Customer B’s queries, not because the query filter is written correctly (though it has to be), but because the data physically does not live in the same partition as Customer B’s. One collection to operate, logical isolation enforced at the query layer, physical isolation enforced at the partition layer.</p><p>See the <a href="https://milvus.io/docs/multi_tenancy.md">multi-tenancy strategies docs</a> for when partition key fits versus when separate collections or databases do, and the <a href="https://milvus.io/blog/build-multi-tenancy-rag-with-milvus-best-practices-part-one.md">multi-tenancy RAG patterns guide</a> for production deployment notes.</p><h3>Why Agent Memory Quality Needs Ongoing Work</h3><p>Memory quality erodes over time: flawed workarounds that happened to succeed once get replayed and reinforced, and stale entries tied to deprecated dependencies keep misleading agents that inherit them. The defenses are operational programs, not database features.</p><p>An agent stumbles on a flawed workaround that happens to succeed once. It gets written to the shared pool. The next agent retrieves it, replays it, and reinforces the bad pattern with a second “successful” usage record.</p><p>Stale entries follow a slower version of the same path. A fix pinned to a dependency version that was deprecated six months ago keeps getting retrieved, and keeps misleading agents that inherit it. The older and more heavily used the pool, the more of this accumulates.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*MvuL0Ol5TdmvQwB2.png" /></figure><p>Three operational programs defend against this:</p><ul><li>Confidence score. Track how often a memory has been successfully applied in downstream sessions. Decay entries that fail in replay. Promote entries that succeed repeatedly.</li><li>Time weighting. Prefer recent experiences. Retire entries past a known staleness threshold, often tied to major dependency version bumps.</li><li>Human spot checks. Entries with high retrieval frequency are high-leverage. When one of them is wrong, it is wrong many times, which is where human review pays back fastest.</li></ul><p>Milvus alone doesn’t solve this, and neither does Mem0, Zep, or any other memory product. Enforcing one pool with many tenants and zero cross-tenant leakage is something you engineer once. Keeping that pool accurate, fresh, and useful is continuous operational work that no database ships pre-configured.</p><h3>Takeaways: What Milvus Adds to Anthropic’s Managed Agents</h3><p>Milvus turns Managed Agents from a reliable-but-forgetful platform into one that compounds experience over time by adding semantic recall inside a session and shared memory across agents.</p><p>Managed Agents answered the reliability question cleanly: both brains and hands are cattle, and any one can die without taking the task with it. That’s the infrastructure problem, and Anthropic solved it well.</p><p>What stayed open was growth. Human engineers compound over time; years of work turn into pattern recognition, and they don’t reason from first principles on every task. Today’s managed agents don’t, because every session starts on a blank page.</p><p>Wiring the session to Milvus for semantic recall inside a task and pooling experience across brains in a shared vector collection is what gives agents a past they can actually use. Plugging in Milvus is the infrastructure piece; pruning wrong memories, retiring stale ones, and enforcing tenant boundaries is the operational piece. Once both are in place, the shape of memory stops being a liability and starts being compounding capital.</p><h3>Get Started</h3><ul><li>Try it locally: spin up an embedded Milvus instance with <a href="https://milvus.io/docs/milvus_lite.md">Milvus Lite</a>. No Docker, no cluster, just pip install pymilvus. Production workloads graduate to <a href="https://milvus.io/docs/install_standalone-docker.md">Milvus Standalone or Distributed</a> when you need them.</li><li>Read the design rationale: Anthropic’s <a href="https://www.anthropic.com/engineering/managed-agents">Managed Agents engineering post</a> walks through the session, harness, and sandbox decoupling in depth.</li><li>Got questions? Join the <a href="https://discord.com/invite/8uyFbECzPX">Milvus Discord</a> community for agent memory design discussions, or book a <a href="https://milvus.io/office-hours">Milvus Office Hours</a> session to walk through your workload.</li><li>Prefer managed? <a href="https://cloud.zilliz.com/signup">Sign up for Zilliz Cloud</a> (or <a href="https://cloud.zilliz.com/login">sign in</a>) for hosted Milvus with partition keys, scaling, and multi-tenancy built in. New accounts get free credits on a work email.</li></ul><h3>Frequently Asked Questions</h3><p>Q: What’s the difference between a session and a context window in Anthropic’s Managed Agents?</p><p>The context window is the ephemeral set of tokens a single Claude call sees. It’s bounded and resets per model invocation. The session is the durable, append-only event log of everything that happened across the whole task, stored outside the harness. When a harness crashes, wake(sessionId) spawns a new harness that reads the session log and resumes. The session is the system of record; the context window is working memory. The session is not the context window.</p><p>Q: How do I persist agent memory across Claude sessions?</p><p>The session itself is already persistent; that’s what getSession(id) retrieves. What’s typically missing is queryable long-term memory. The pattern is to embed high-signal events (decisions, resolutions, strategies) into a vector database like Milvus during emitEvent, then query by semantic similarity at retrieval time. This gives you both the durable session log Anthropic provides and a semantic recall layer for looking back across hundreds of steps.</p><p>Q: Can multiple Claude agents share memory?</p><p>Not out of the box. Each Managed Agents session is isolated by design, which is what lets them scale horizontally. To share memory across agents, add a shared vector collection (for example in Milvus) that each harness reads from at startup and writes to at shutdown. Use Milvus’s partition key feature to isolate tenants so Customer A’s agent memories never leak into Customer B’s sessions.</p><p>Q: What’s the best vector database for AI agent memory?</p><p>The honest answer depends on scale and deployment shape. For prototypes and small workloads, a local embedded option like Milvus Lite runs in-process with no infrastructure. For production agents across many tenants, you want a database with mature multi-tenancy (partition keys, filtered search), hybrid search (vector + scalar + keyword), and millisecond-latency at millions of vectors. Milvus is purpose-built for vector workloads at that scale, which is why it appears in production agent memory systems built on LangChain, Google ADK, Deep Agents, and OpenAgents.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c88fcf30054e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[DeepSeek V4 vs GPT-5.5 vs Qwen3.6: Which Model Should You Use?]]></title>
            <link>https://milvusio.medium.com/deepseek-v4-vs-gpt-5-5-vs-qwen3-6-which-model-should-you-use-fe79d33ad547?source=rss-a31576809ee1------2</link>
            <guid isPermaLink="false">https://medium.com/p/fe79d33ad547</guid>
            <dc:creator><![CDATA[Milvus]]></dc:creator>
            <pubDate>Thu, 11 Jun 2026 10:40:05 GMT</pubDate>
            <atom:updated>2026-06-11T10:40:05.684Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zYHj4R_4zFYBeiJGM3Rcgw.png" /></figure><p>New model releases are moving faster than production teams can evaluate them. DeepSeek V4, GPT-5.5, and Qwen3.6–35B-A3B all look strong on paper, but the harder question for AI application developers is practical: which model should you use for retrieval-heavy systems, coding tasks, long-context analysis, and <a href="https://zilliz.com/learn/Retrieval-Augmented-Generation">RAG pipelines</a>?</p><p>This article compares the three models in practical tests: live information retrieval, concurrency-bug debugging, and long-context marker retrieval. Then it shows how to connect DeepSeek V4 to <a href="https://zilliz.com/learn/what-is-vector-database">Milvus vector database</a>, so retrieved context comes from a searchable knowledge base instead of the model’s parameters alone.</p><h3>What Are DeepSeek V4, GPT-5.5, and Qwen3.6–35B-A3B?</h3><p>DeepSeek V4, GPT-5.5, and Qwen3.6–35B-A3B are different AI models that target different parts of the model stack. DeepSeek V4 focuses on open-weight long-context inference. GPT-5.5 focuses on frontier-hosted performance, coding, online research, and tool-heavy tasks. Qwen3.6–35B-A3B focuses on open-weight multimodal deployment with a much smaller active-parameter footprint.</p><p>The comparison matters because a <a href="https://zilliz.com/learn/comparing-vector-database-vector-search-library-and-vector-search-plugin">production vector search</a> system rarely depends on the model alone. Model capability, context length, deployment control, retrieval quality, and serving cost all affect the final user experience.</p><h3>DeepSeek V4: An Open-Weight MoE Model for Long-Context Cost Control</h3><p><a href="https://api-docs.deepseek.com/news/news260424">DeepSeek V4</a> is an open-weight MoE model family released by DeepSeek on April 24, 2026. The official release lists two variants: DeepSeek V4-Pro and DeepSeek V4-Flash. V4-Pro has 1.6T total parameters with 49B activated per token, while V4-Flash has 284B total parameters with 13B activated per token. Both support a 1M-token context window.</p><p>The <a href="https://huggingface.co/deepseek-ai/DeepSeek-V4-Pro">DeepSeek V4-Pro model card</a> also lists the model as MIT-licensed and available through Hugging Face and ModelScope. For teams building long-context document workflows, the main appeal is cost control and deployment flexibility compared with fully closed frontier APIs.</p><h3>GPT-5.5: A Hosted Frontier Model for Coding, Research, and Tool Use</h3><p><a href="https://openai.com/index/introducing-gpt-5-5/">GPT-5.5</a> is a closed frontier model released by OpenAI on April 23, 2026. OpenAI positions it for coding, online research, data analysis, document work, spreadsheet work, software operation, and tool-based tasks. The official model docs list gpt-5.5 with a 1M-token API context window, while Codex and ChatGPT product limits may differ.</p><p>OpenAI reports strong coding benchmark results: 82.7% on Terminal-Bench 2.0, 73.1% on Expert-SWE, and 58.6% on SWE-Bench Pro. The tradeoff is price: the official API pricing lists GPT-5.5 at $5 per 1M input tokens and $30 per 1M output tokens, before any product-specific or long-context pricing details.</p><h3>Qwen3.6–35B-A3B: A Smaller Active-Parameter Model for Local and Multimodal Workloads</h3><p><a href="https://huggingface.co/Qwen/Qwen3.6-35B-A3B">Qwen3.6–35B-A3B</a> is an open-weight MoE model from Alibaba’s Qwen team. Its model card lists 35B total parameters, 3B activated parameters, a vision encoder, and Apache-2.0 licensing. It supports a native 262,144-token context window and can extend to about 1,010,000 tokens with YaRN scaling.</p><p>That makes Qwen3.6–35B-A3B attractive when local deployment, private serving, image-text input, or Chinese-language workloads matter more than managed frontier-model convenience.</p><h3>DeepSeek V4 vs GPT-5.5 vs Qwen3.6: Model Specs Compared</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fNR3lIvd-VUX6gpVdrRdUQ.png" /></figure><h3>How We Tested DeepSeek V4, GPT-5.5, and Qwen3.6</h3><p>These tests are not a replacement for full benchmark suites. They are practical checks that mirror common developer questions: can the model retrieve current information, reason about subtle code bugs, and locate facts inside a very long document?</p><h3>Which Model Handles Real-Time Information Retrieval Best?</h3><p>We asked each model three time-sensitive questions using web search where available. The instruction was simple: return only the answer and include the source URL.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FJugrMKf0L_KNqZHTYPPUw.png" /></figure><p>OpenAI’s image pricing page uses the label “medium” rather than “standard” for the $0.053 1024×1024 result, so the question is normalized here to match the current API wording.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/922/0*FLTHAk_RQjjPMQ-9.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/896/0*7vQx-Nq9hrlSENXP.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*IR-8CzVHNPxEjHZZ.png" /></figure><h3>Real-Time Retrieval Results: GPT-5.5 Had the Clearest Advantage</h3><h4>DeepSeek V4-Pro</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/847/0*_Ezwmz0Dfyih17jB.png" /></figure><p>DeepSeek V4-Pro answered the first question incorrectly. It could not answer the second and third questions through live web search in this setup.</p><p>The second answer included the correct Billboard URL but did not retrieve the current №1 song. The third answer used the wrong source, so we counted it as incorrect.</p><h4>GPT-5.5</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/728/0*edNBnRxnRtQuEFRk.png" /></figure><p>GPT-5.5 handled this test much better. Its answers were short, accurate, sourced, and fast. When a task depends on current information and the model has live retrieval available, GPT-5.5 had the clear advantage in this setup.</p><h4>Qwen3.6–35B-A3B</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/895/0*SUNUea6NoTp-cjec.png" /></figure><p>Qwen3.6–35B-A3B produced a result similar to DeepSeek V4-Pro. It did not have live web access in this setup, so it could not complete the real-time retrieval task.</p><h3>Which Model Is Better at Debugging Concurrency Bugs?</h3><p>The second test used a Python bank-transfer example with three layers of concurrency problems. The task was not just to find the obvious race condition, but also to explain why the total balance breaks and provide corrected code.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jUUb6ZottThhOOrKXISD7A.png" /></figure><p>The prompt and code are as shown below:</p><pre>The following Python code simulates two bank accounts transferring<br>  money to each other. The total balance should always equal 2000,                                              <br>  but it often doesn&#39;t after running.                                                                           <br>                                                                                                                <br>  Please:                                                                                                       <br>  1. Find ALL concurrency bugs in this code (not just the obvious one)                                          <br>  2. Explain why Total ≠ 2000 with a concrete thread execution example                                          <br>  3. Provide the corrected code                                                                                 <br>                                                                                                                <br>  import threading                                                                                              <br>                                                                  <br>  class BankAccount:<br>      def __init__(self, balance):<br>          self.balance = balance                                                                                <br>   <br>      def transfer(self, target, amount):                                                                       <br>          if self.balance &gt;= amount:                              <br>              self.balance -= amount<br>              target.balance += amount<br>              return True<br>          return False<br>                                                                                                                <br>  def stress_test():<br>      account_a = BankAccount(1000)                                                                             <br>      account_b = BankAccount(1000)                               <br><br>      def transfer_a_to_b():                                                                                    <br>          for _ in range(1000):<br>              account_a.transfer(account_b, 1)                                                                  <br>                                                                  <br>      def transfer_b_to_a():<br>          for _ in range(1000):<br>              account_b.transfer(account_a, 1)                                                                  <br>   <br>      threads = [threading.Thread(target=transfer_a_to_b) for _ in range(10)]                                   <br>      threads += [threading.Thread(target=transfer_b_to_a) for _ in range(10)]<br>                                                                                                                <br>      for t in threads: t.start()<br>      for t in threads: t.join()                                                                                <br>                                                                  <br>      print(f&quot;Total: {account_a.balance + account_b.balance}&quot;)                                                  <br>      print(f&quot;A: {account_a.balance}, B: {account_b.balance}&quot;)<br>                                                                                                                <br>  stress_test()</pre><h3>Code Debugging Results: GPT-5.5 Gave the Most Complete Answer</h3><h4>DeepSeek V4-Pro</h4><p>DeepSeek V4-Pro gave a concise analysis and went straight to the ordered-lock solution, which is the standard way to avoid ABBA deadlock. Its answer demonstrated the right fix, but it did not spend much time explaining why the naive lock-based fix could introduce a new failure mode.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/860/0*UxQkWbwu0FbAD1Pc.png" /></figure><h4>GPT-5.5</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/747/0*GYBLJhTPMrNqlfl1.png" /></figure><p>GPT-5.5 performed best on this test. It found the core issues, anticipated the deadlock risk, explained why the original code could fail, and provided a complete corrected implementation.</p><h4>Qwen3.6–35B-A3B</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/852/0*tME2Rjh-XYESgK1V.png" /></figure><p>Qwen3.6–35B-A3B identified the bugs accurately, and its example execution sequence was clear. The weaker part was the fix: it chose a global class-level lock, which makes every account share the same lock. That works for a small simulation, but it is a poor tradeoff for a real banking system because unrelated account transfers must still wait on the same lock.</p><p>In short: GPT-5.5 not only solved the current bug, but also warned about the next bug a developer might introduce. DeepSeek V4-Pro gave the cleanest non-GPT fix. Qwen3.6 found the issues and produced working code, but did not call out the scalability compromise.</p><h3>Which Model Handles Long-Context Retrieval Best?</h3><p>For the long-context test, we used the full text of <em>Dream of the Red Chamber</em>, roughly 850,000 Chinese characters. We inserted a hidden marker around the 500,000-character position:</p><p>【Milvus test verification code: ZK-7749-ALPHA】</p><p>Then we uploaded the file to each model and asked it to find both the marker content and its position.</p><h3>Long-Context Retrieval Results: GPT-5.5 Found the Marker Most Precisely</h3><h4>DeepSeek V4-Pro</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*rDPLzA0P7R81esuE.png" /></figure><p>DeepSeek V4-Pro found the hidden marker, but it did not find the correct character position. It also gave the wrong surrounding context. In this test, it seemed to locate the marker semantically but lose track of the exact position while reasoning over the document.</p><h4>GPT-5.5</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*QY8kKdJIMnbrUXWl.png" /></figure><p>GPT-5.5 found the marker content, the position, and the surrounding context correctly. It reported the position as 500,002 and even distinguished between zero-indexed and one-indexed counting. The surrounding context also matched the text used when inserting the marker.</p><h4>Qwen3.6–35B-A3B</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*d-EjSPvblz2pQWfL.png" /></figure><p>Qwen3.6–35B-A3B found the marker content and nearby context correctly, but its position estimate was wrong.</p><h3>What Do These Tests Say About Model Selection?</h3><p>The three tests point to a practical selection pattern: GPT-5.5 is the capability pick, DeepSeek V4-Pro is the long-context cost-performance pick, and Qwen3.6–35B-A3B is the local-control pick.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PQ3wj0wXj4xvJ0GgpQVTuA.png" /></figure><p>Use GPT-5.5 when you need the strongest result, and cost is secondary. Use DeepSeek V4-Pro when you need long context, lower serving cost, and API-friendly deployment. Use Qwen3.6–35B-A3B when open weights, private deployment, multimodal support, or serving-stack control matter most.</p><p>For retrieval-heavy applications, though, model choice is only half the story. Even a strong long-context model performs better when the context is retrieved, filtered, and grounded by a dedicated <a href="https://zilliz.com/learn/generative-ai">semantic search system</a>.</p><h3>Why RAG Still Matters for Long-Context Models</h3><p>A long context window does not remove the need for retrieval. It changes the retrieval strategy.</p><p>In a RAG application, the model should not scan every document on every request. A <a href="https://zilliz.com/learn/introduction-to-unstructured-data">vector database architecture</a> stores embeddings, searches for semantically relevant chunks, applies metadata filters, and returns a compact context set to the model. That gives the model better input while reducing cost and latency.</p><p>Milvus fits this role because it handles <a href="https://milvus.io/docs/schema.md">collection schemas</a>, vector indexing, scalar metadata, and retrieval operations in one system. You can start locally with <a href="https://milvus.io/docs/milvus_lite.md">Milvus Lite</a>, move to a standalone <a href="https://milvus.io/docs/quickstart.md">Milvus quickstart</a>, deploy with <a href="https://milvus.io/docs/install_standalone-docker.md">Docker installation</a> or <a href="https://milvus.io/docs/install_standalone-docker-compose.md">Docker Compose deployment</a>, and scale further with <a href="https://milvus.io/docs/install_cluster-milvusoperator.md">Kubernetes deployment</a> when the workload grows.</p><h3>How to Build a RAG Pipeline with Milvus and DeepSeek V4</h3><p>The following walkthrough builds a small RAG pipeline using DeepSeek V4-Pro for generation and Milvus for retrieval. The same structure applies to other LLMs: create embeddings, store them in a collection, search for relevant context, and pass that context into the model.</p><p>For a broader walkthrough, see the official <a href="https://milvus.io/docs/build-rag-with-milvus.md">Milvus RAG tutorial</a>. This example keeps the pipeline small so the retrieval flow is easy to inspect.</p><h3>Prepare the Environment</h3><h3>Install the Dependencies</h3><pre>! pip install --upgrade &quot;pymilvus[model]&quot; openai requests tqdm</pre><p>If you are using Google Colab, you may need to restart the runtime after installing dependencies. Click the Runtime menu, then select Restart session.</p><p>DeepSeek V4-Pro supports an OpenAI-style API. Log in to the official DeepSeek website and set DEEPSEEK_API_KEY as an environment variable.</p><pre>import os<br>os.environ[&quot;DEEPSEEK_API_KEY&quot;] = &quot;sk-*****************&quot;</pre><h3>Prepare the Milvus Documentation Dataset</h3><p>We use the FAQ pages from the <a href="https://github.com/milvus-io/milvus-docs/releases/download/v2.4.6-preview/milvus_docs_2.4.x_en.zip">Milvus 2.4.x documentation archive</a> as the private knowledge source. This is a simple starter dataset for a small RAG demo.</p><p>First, download the ZIP file and extract the documentation into the milvus_docs folder.</p><pre>! wget https://github.com/milvus-io/milvus-docs/releases/download/v2.4.6-preview/milvus_docs_2.4.x_en.zip<br>! unzip -q milvus_docs_2.4.x_en.zip -d milvus_docs</pre><p>We load all Markdown files from the milvus_docs/en/faq folder. For each document, we split the file content by #, which roughly separates major Markdown sections.</p><pre>from glob import glob<br>text_lines = []<br>for file_path in glob(&quot;milvus_docs/en/faq/*.md&quot;, recursive=True):<br>    with open(file_path, &quot;r&quot;) as file:<br>        file_text = file.read()<br>    text_lines += file_text.split(&quot;# &quot;)</pre><h3>Set Up DeepSeek V4 and the Embedding Model</h3><pre>from openai import OpenAI<br>deepseek_client = OpenAI(<br>    api_key=os.environ[&quot;DEEPSEEK_API_KEY&quot;],<br>    base_url=&quot;https://api.deepseek.com&quot;,<br>)</pre><p>Next, choose an embedding model. This example uses DefaultEmbeddingFunction from the PyMilvus model module. See the Milvus docs for more on <a href="https://milvus.io/docs/embeddings.md">embedding functions</a>.</p><pre>from pymilvus import model as milvus_model<br>embedding_model = milvus_model.DefaultEmbeddingFunction()</pre><p>Generate a test vector, then print the vector dimension and the first few elements. The returned dimension is used when creating the Milvus collection.</p><pre>test_embedding = embedding_model.encode_queries([&quot;This is a test&quot;])[0]<br>embedding_dim = len(test_embedding)<br>print(embedding_dim)<br>print(test_embedding[:10])<br>768<br>[-0.04836066  0.07163023 -0.01130064 -0.03789345 -0.03320649 -0.01318448<br> -0.03041712 -0.02269499 -0.02317863 -0.00426028]</pre><h3>Load Data into Milvus</h3><h3>Create a Milvus Collection</h3><p>A Milvus collection stores vector fields, scalar fields, and optional dynamic metadata. The quick setup below uses the high-level MilvusClient API; for production schemas, review the docs on <a href="https://milvus.io/docs/manage-collections.md">collection management</a> and <a href="https://milvus.io/docs/create-collection.md">creating collections</a>.</p><pre>from pymilvus import MilvusClient<br>milvus_client = MilvusClient(uri=&quot;./milvus_demo.db&quot;)<br>collection_name = &quot;my_rag_collection&quot;</pre><p>A few notes about MilvusClient:</p><ul><li>Setting uri to a local file, such as ./milvus.db, is the easiest option because it automatically uses <a href="https://milvus.io/docs/milvus_lite.md">Milvus Lite</a> and stores all data in that file.</li><li>If you have a large dataset, you can set up a higher-performance Milvus server on <a href="https://milvus.io/docs/quickstart.md">Docker or Kubernetes</a>. In that setup, use the server URI, such as http://localhost:19530, as your uri.</li><li>If you want to use <a href="https://docs.zilliz.com/">Zilliz Cloud</a>, the fully managed cloud service for Milvus, set uri and token to the <a href="https://docs.zilliz.com/docs/connect-to-cluster">public endpoint and API key</a> from Zilliz Cloud.</li></ul><p>Check whether the collection already exists. If it does, delete it.</p><pre>if milvus_client.has_collection(collection_name):<br>    milvus_client.drop_collection(collection_name)</pre><p>Create a new collection with the specified parameters. If we do not specify field information, Milvus automatically creates a default id field as the primary key and a vector field to store vector data. A reserved JSON field stores scalar data that is not defined in the schema.</p><pre>milvus_client.create_collection(<br>    collection_name=collection_name,<br>    dimension=embedding_dim,<br>    metric_type=&quot;IP&quot;,  # Inner product distance<br>    consistency_level=&quot;Strong&quot;,  # Strong consistency level<br>)</pre><p>The IP metric means inner product similarity. Milvus also supports other metric types and index choices depending on the vector type and workload; see the guides on <a href="https://milvus.io/docs/id/metric.md">metric types</a> and <a href="https://milvus.io/docs/index_selection.md">index selection</a>. The Strong setting is one of the available <a href="https://milvus.io/docs/consistency.md">consistency levels</a>.</p><h3>Insert the Embedded Documents</h3><p>Iterate through the text data, create embeddings, and insert the data into Milvus. Here, we add a new field named text. Since it is not explicitly defined in the collection schema, it is automatically added to the reserved dynamic JSON field. For production metadata, review <a href="https://milvus.io/docs/enable-dynamic-field.md">dynamic field support</a> and the <a href="https://milvus.io/docs/json-field-overview.md">JSON field overview</a>.</p><pre>from tqdm import tqdm<br>data = []<br>doc_embeddings = embedding_model.encode_documents(text_lines)<br>for i, line in enumerate(tqdm(text_lines, desc=&quot;Creating embeddings&quot;)):<br>    data.append({&quot;id&quot;: i, &quot;vector&quot;: doc_embeddings[i], &quot;text&quot;: line})<br>milvus_client.insert(collection_name=collection_name, data=data)<br>Creating embeddings: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 72/72 [00:00&lt;00:00, 1222631.13it/s]<br>{&#39;insert_count&#39;: 72, &#39;ids&#39;: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71], &#39;cost&#39;: 0}</pre><p>For larger datasets, the same pattern can be extended with explicit schema design, <a href="https://milvus.io/docs/index-vector-fields.md">vector field indexes</a>, scalar indexes, and data lifecycle operations such as <a href="https://milvus.io/docs/insert-update-delete.md">insert, upsert, and delete</a>.</p><h3>Build the RAG Retrieval Flow</h3><h3>Search Milvus for Relevant Context</h3><p>Let’s define a common question about Milvus.</p><pre>question = &quot;How is data stored in milvus?&quot;</pre><p>Search the collection for the question and retrieve the top three semantic matches. This is a basic <a href="https://milvus.io/docs/single-vector-search.md">single-vector search</a>. In production, you can combine it with <a href="https://milvus.io/docs/filtered-search.md">filtered search</a>, <a href="https://milvus.io/docs/full-text-search.md">full-text search</a>, <a href="https://milvus.io/docs/multi-vector-search.md">multi-vector hybrid search</a>, and <a href="https://milvus.io/docs/reranking.md">reranking strategies</a> to improve relevance.</p><pre>search_res = milvus_client.search(<br>    collection_name=collection_name,<br>    data=embedding_model.encode_queries(<br>        [question]<br>    ),  # Convert the question to an embedding vector<br>    limit=3,  # Return top 3 results<br>    search_params={&quot;metric_type&quot;: &quot;IP&quot;, &quot;params&quot;: {}},  # Inner product distance<br>    output_fields=[&quot;text&quot;],  # Return the text field<br>)</pre><p>Now let’s look at the search results for the query.</p><pre>import json<br>retrieved_lines_with_distances = [<br>    (res[&quot;entity&quot;][&quot;text&quot;], res[&quot;distance&quot;]) for res in search_res[0]<br>]<br>print(json.dumps(retrieved_lines_with_distances, indent=4))<br>[<br>    [<br>        &quot; Where does Milvus store data?\n\nMilvus deals with two types of data, inserted data and metadata. \n\nInserted data, including vector data, scalar data, and collection-specific schema, are stored in persistent storage as incremental log. Milvus supports multiple object storage backends, including [MinIO](https://min.io/), [AWS S3](https://aws.amazon.com/s3/?nc1=h_ls), [Google Cloud Storage](https://cloud.google.com/storage?hl=en#object-storage-for-companies-of-all-sizes) (GCS), [Azure Blob Storage](https://azure.microsoft.com/en-us/products/storage/blobs), [Alibaba Cloud OSS](https://www.alibabacloud.com/product/object-storage-service), and [Tencent Cloud Object Storage](https://www.tencentcloud.com/products/cos) (COS).\n\nMetadata are generated within Milvus. Each Milvus module has its own metadata that are stored in etcd.\n\n###&quot;,<br>        0.6572665572166443<br>    ],<br>    [<br>        &quot;How does Milvus flush data?\n\nMilvus returns success when inserted data are loaded to the message queue. However, the data are not yet flushed to the disk. Then Milvus&#39; data node writes the data in the message queue to persistent storage as incremental logs. If `flush()` is called, the data node is forced to write all data in the message queue to persistent storage immediately.\n\n###&quot;,<br>        0.6312146186828613<br>    ],<br>    [<br>        &quot;How does Milvus handle vector data types and precision?\n\nMilvus supports Binary, Float32, Float16, and BFloat16 vector types.\n\n- Binary vectors: Store binary data as sequences of 0s and 1s, used in image processing and information retrieval.\n- Float32 vectors: Default storage with a precision of about 7 decimal digits. Even Float64 values are stored with Float32 precision, leading to potential precision loss upon retrieval.\n- Float16 and BFloat16 vectors: Offer reduced precision and memory usage. Float16 is suitable for applications with limited bandwidth and storage, while BFloat16 balances range and efficiency, commonly used in deep learning to reduce computational requirements without significantly impacting accuracy.\n\n###&quot;,<br>        0.6115777492523193<br>    ]<br>]</pre><h3>Generate a RAG Answer with DeepSeek V4</h3><p>Convert the retrieved documents into string format.</p><pre>context = &quot;\n&quot;.join(<br>    [line_with_distance[0] for line_with_distance in retrieved_lines_with_distances]<br>)</pre><p>Define the system and user prompts for the LLM. This prompt is assembled from the documents retrieved from Milvus.</p><pre>SYSTEM_PROMPT = &quot;&quot;&quot;<br>Human: You are an AI assistant. You are able to find answers to the questions from the contextual passage snippets provided.<br>&quot;&quot;&quot;<br>USER_PROMPT = f&quot;&quot;&quot;<br>Use the following pieces of information enclosed in &lt;context&gt; tags to provide an answer to the question enclosed in &lt;question&gt; tags.<br>&lt;context&gt;<br>{context}<br>&lt;/context&gt;<br>&lt;question&gt;<br>{question}<br>&lt;/question&gt;<br>&quot;&quot;&quot;</pre><p>Use the model provided by DeepSeek V4-Pro to generate a response based on the prompt.</p><pre>response = deepseek_client.chat.completions.create(<br>    model=&quot;deepseek-v4-pro&quot;,<br>    messages=[<br>        {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: SYSTEM_PROMPT},<br>        {&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: USER_PROMPT},<br>    ],<br>)<br>print(response.choices[0].message.content)<br>Milvus stores data in two distinct ways depending on the type:<br>- **Inserted data** (vector data, scalar data, and collection-specific schema) are stored in persistent storage as incremental logs. Milvus supports multiple object storage backends, such as MinIO, AWS S3, Google Cloud Storage, Azure Blob Storage, Alibaba Cloud OSS, and Tencent Cloud Object Storage. Before reaching persistent storage, the data is initially loaded into a message queue; a data node then writes it to disk, and calling `flush()` forces an immediate write.<br>- **Metadata**, generated by each Milvus module, is stored in **etcd**.</pre><p>At this point, the pipeline has completed the core RAG loop: embed documents, store vectors in Milvus, search for relevant context, and generate an answer with DeepSeek V4-Pro.</p><h3>What Should You Improve Before Production?</h3><p>The demo uses simple section splitting and top-k retrieval. That is enough to show the mechanics, but production RAG usually needs more retrieval control.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oE-1n3dy4u9zU79VVrG44A.png" /></figure><p>The most important production habit is to evaluate retrieval separately from generation. If the retrieved context is weak, swapping the LLM often hides the problem instead of solving it.</p><h3>Get Started with Milvus and DeepSeek RAG</h3><p>If you want to reproduce the tutorial, start with the official <a href="https://milvus.io/docs">Milvus documentation</a> and the <a href="https://milvus.io/docs/build-rag-with-milvus.md">Build RAG with Milvus guide</a>. For a managed setup, <a href="https://docs.zilliz.com/docs/connect-to-cluster">connect to Zilliz Cloud</a> with your cluster endpoint and API key instead of running Milvus locally.</p><p>If you want help tuning chunking, indexing, filters, or hybrid retrieval, join the <a href="https://slack.milvus.io/">Milvus Slack community</a> or book a free <a href="https://milvus.io/office-hours">Milvus Office Hours session</a>. If you would rather skip infrastructure setup, use <a href="https://cloud.zilliz.com/login">Zilliz Cloud login</a> or create a <a href="https://cloud.zilliz.com/signup">Zilliz Cloud account</a> to run managed Milvus.</p><h3>Questions Developers Ask About DeepSeek V4, Milvus, and RAG</h3><h3>Is DeepSeek V4 good for RAG?</h3><p>DeepSeek V4-Pro is a strong fit for RAG when you need long-context processing and lower serving cost than premium closed models. You still need a retrieval layer such as Milvus to select relevant chunks, apply metadata filters, and keep the prompt focused.</p><h3>Should I use GPT-5.5 or DeepSeek V4 for a RAG pipeline?</h3><p>Use GPT-5.5 when answer quality, tool use, and live research matter more than cost. Use DeepSeek V4-Pro when long-context processing and cost control matter more, especially if your retrieval layer already supplies high-quality grounded context.</p><h3>Can I run Qwen3.6–35B-A3B locally for private RAG?</h3><p>Yes, Qwen3.6–35B-A3B is open weight and designed for more controllable deployment. It is a good candidate when privacy, local serving, multimodal input, or Chinese-language performance matters, but you still need to validate latency, memory, and retrieval quality for your hardware.</p><h3>Do long-context models make vector databases unnecessary?</h3><p>No. Long-context models can read more text, but they still benefit from retrieval. A vector database narrows the input to relevant chunks, supports metadata filtering, reduces token cost, and makes the application easier to update as documents change.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fe79d33ad547" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[7 Best Open-Source Tools for Claude Code Context Management]]></title>
            <link>https://milvusio.medium.com/7-best-open-source-tools-for-claude-code-context-management-1ea708f64355?source=rss-a31576809ee1------2</link>
            <guid isPermaLink="false">https://medium.com/p/1ea708f64355</guid>
            <dc:creator><![CDATA[Milvus]]></dc:creator>
            <pubDate>Thu, 11 Jun 2026 10:39:24 GMT</pubDate>
            <atom:updated>2026-06-11T10:39:24.300Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I7MwIrF1knS5MbG1L6zHaw.png" /></figure><p>You can give Claude Code a 1M-token context window and still get worse answers over time. The issue is not only context size. It is context quality.</p><p>Claude Code sessions degrade when terminal logs, raw tool output, repeated file reads, verbose responses, and forgotten project history all compete for attention. In long-running agent workflows, that noise turns into a loop: the model loses the thread, you add more turns to fix the answer, and those extra turns add even more noise.</p><p>This is context defocus: the model has enough room to hold information, but the important information is buried under low-signal context. Bigger windows can make this easier to ignore because developers stop thinking carefully about what enters the prompt.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*hghzxCln9r-ZYw-3.png" /></figure><p>Prompt caching diagram showing how reused prefixes can still add billed context across turns</p><p>Prompt caching can reduce repeated-prefix cost, but it does not turn the context window into a junk drawer. You still pay for new tokens, and you still need the model to reason over the right information.</p><p>This article reviews seven open-source tools that attack context defocus from different layers: terminal output, tool output, codebase navigation, file reading, model verbosity, semantic code retrieval, and cross-session memory. It also explains how these ideas map to <a href="https://zilliz.com/learn/what-is-vector-database">vector database</a> design, <a href="https://zilliz.com/learn/vector-similarity-search">vector similarity search</a>, and retrieval systems such as Milvus.</p><h3>What causes Claude Code context defocus?</h3><p>Claude Code context defocus usually comes from five failure modes: too much raw instruction text, noisy tool output, repeated codebase exploration, long model responses, and memory gaps across sessions or agents.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*kZRnzLUfHJMoS0tU.png" /></figure><p>Five causes of Claude Code context loss: redundant instructions, messy tool output, repeated codebase retrieval, long responses, and memory gaps</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ef3lVSYzAlKJIO1JQhFbfQ.png" /></figure><p>A good context-management stack should do three things: keep junk out, retrieve the right project knowledge on demand, and preserve durable decisions across sessions.</p><h3>Which Claude Code context tool should you use first?</h3><p>Start with the layer that creates the most noise in your workflow. If your terminal output is the problem, start with RTK. If Claude keeps wandering through a large repository, start with claude-context or code-review-graph. If your real pain is re-explaining the same decisions every day, start with memsearch.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-R_5h1P2-Ukl5qiueKjCTg.png" /></figure><p>The first five tools reduce what enters or remains in context. The last two make useful context easier to recall.</p><h3>RTK compresses raw command output before Claude sees it</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*2amAk5ARl9kvYpsl.png" /></figure><p>RTK is a CLI proxy for reducing token usage from common developer commands. Its GitHub description says it reduces LLM token consumption by 60–90% on common dev commands, and it ships as a single Rust binary.</p><p>In everyday Claude Code use, commands like git status, pytest, and directory listings often dump full environment info and status descriptions into the context window. The model usually needs only a smaller answer: which files changed, which test failed, where the PR is stuck, or what key files exist in the directory.</p><p>RTK sits between the shell and Claude. It can rewrite commands through Claude Code hooks and pass back compressed output.</p><p>Raw git status output:</p><pre>On branch feat/payment-retry<br>Your branch is up to date with &#39;origin/feat/payment-retry&#39;.<br><br>Changes not staged for commit:<br>  modified:   src/webhook/handler.ts<br>  modified:   src/queue/dlq.ts<br>  modified:   tests/webhook.test.ts<br><br>Untracked files:<br>  docs/notes.md<br><br>no changes added to commit</pre><p>What actually matters:</p><pre>3 modified, 1 untracked<br>- src/webhook/handler.ts<br>- src/queue/dlq.ts<br>- tests/webhook.test.ts</pre><p>Same story with pytest. The raw output is full of passing cases and environment noise:</p><pre>============================= test session starts =============================<br>platform darwin -- Python 3.12.4, pytest-8.4.1<br>collected 128 items<br><br>tests/test_auth.py ....................................<br>tests/test_webhook.py ....F....<br>tests/test_queue.py ...................................<br><br>================================== FAILURES ==================================<br>________________ test_retry_to_dlq __________________<br>E   AssertionError: expected status code 202, got 500</pre><p>Compressed, the signal is immediate:</p><pre>128 tests collected, 1 failed<br>FAIL tests/test_webhook.py::test_retry_to_dlq<br>AssertionError: expected status code 202, got 500</pre><p>RTK is the easiest starting point when your context bloat comes from shell commands rather than code retrieval.</p><h3>Context Mode sandboxes giant tool outputs outside the main chat</h3><p>Context Mode is built for the raw blocks that tools return: test logs, browser DOM snapshots, GitHub payloads, MCP tool output, and scraped pages. Its GitHub description highlights context-window optimization for AI coding agents and reports 98% tool-output reduction.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ZwhooZvlWdYijPMw.png" /></figure><p>Context Mode GitHub repository card showing sandboxed tool output and context optimization positioning</p><p>Its approach is to isolate large tool outputs into a local sandbox and index, then pass only summaries and retrieval handles into the Claude conversation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*aLG1epU_rHzNnrKN.png" /></figure><p>Context Mode flow showing large tool output moving through sandbox execution, SQLite or FTS indexes, summaries, and retrieval results</p><p>The flow is useful because a coding agent often needs the failing node, broken selector, or relevant stack trace, not the entire DOM or every passing test line. Context Mode keeps the full output available locally while preventing it from dominating the main conversation.</p><p>This is similar to how production <a href="https://zilliz.com/blog/hybrid-search-with-milvus">hybrid search</a> systems separate storage from retrieval. You keep the raw data somewhere durable, then retrieve only the slice that matters.</p><h3>code-review-graph maps code structure before Claude navigates it</h3><p>code-review-graph addresses a different problem: Claude does not always need more text; it needs a better map.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*C4ARf1HNxLVezS8a.png" /></figure><p>code-review-graph logo image used in the original article</p><p>In a large repository, a simple question can trigger expensive exploration:</p><blockquote><em>After changing this login logic, which files and tests are affected?</em></blockquote><p>Without a code graph, Claude’s typical move is:</p><pre>read auth.ts<br>grep login<br>read middleware<br>read tests<br>keep guessing</pre><p>code-review-graph pre-builds a structural map of the codebase. It uses Tree-sitter to parse functions, classes, imports, call relationships, inheritance, and test dependencies, then writes the graph into SQLite.</p><p>That makes it useful for code review and blast-radius analysis. Instead of asking Claude to rediscover the dependency graph through repeated reads, you let it query structure first.</p><p>This is adjacent to <a href="https://zilliz.com/blog/semantic-search-vs-lexical-search-vs-full-text-search">semantic search</a>, but not identical. A structural graph answers “what depends on what?” Semantic retrieval answers “what code is conceptually related to this question?” In real code-assistant workflows, you often want both.</p><h3>Token Savior gives Claude symbol summaries before full files</h3><p>Token Savior’s core idea is simple: do not send the full file by default. Send an index or symbol summary first, then expand only when the task needs more detail.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*73AqUkzM057DLeM3.png" /></figure><p>Token Savior GitHub repository card showing its MCP server description and project statistics</p><p>If you ask where a payment webhook is handled, the model often does not need every line of every related file. It first needs to know whether a file or symbol is relevant.</p><p>Token Savior serves code in layers:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ptIcHsug2sXUn6I752H_YA.png" /></figure><p>This mirrors how developers actually read code. You scan, confirm relevance, then open the full file only when necessary. It also resembles the progressive retrieval pattern used in <a href="https://zilliz.com/blog/metadata-filtering-hybrid-search-or-agent-in-rag-applications">RAG applications</a>: retrieve broadly enough to orient, then narrow the context before generation.</p><h3>Caveman reduces Claude’s own response bloat</h3><p>Most context tools focus on what enters the model. Caveman targets what Claude outputs.</p><p>Caveman is a Claude Code skill/plugin that strips filler, pleasantries, wrapper sentences, over-explanation, and repetitive structures. The goal is not to remove knowledge; it is to make the answer denser.</p><p>Without Caveman:</p><blockquote><em>The reason your React component is re-rendering is likely because…</em></blockquote><p>With Caveman:</p><blockquote><em>New object ref each render. Inline object prop = new ref = re-render. Wrap in useMemo.</em></blockquote><p>This matters because Claude’s own answers become future context. If every answer includes a long explanation, the next turn starts with more text than it needs. Shorter answers can improve the next turn as much as they improve the current one.</p><p>For teams thinking about <a href="https://zilliz.com/blog/context-engineering-for-ai-agents">context engineering for AI agents</a>, Caveman is a reminder that output policy is part of context policy.</p><h3>claude-context adds semantic code search through MCP</h3><p>claude-context solves the repeated-codebase-exploration problem with semantic retrieval. It indexes a repository, stores code chunks in a vector database, and exposes search through the <a href="https://zilliz.com/glossary/model-context-protocol-%28mcp%29">Model Context Protocol</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*rTMZecbLjthoj7mQ.png" /></figure><p>Claude Context repository shown on GitHub Trending in the original article</p><p>In a big codebase, you constantly ask Claude questions like:</p><blockquote><em>Help me figure out which parts of the code might be related to this bug.</em></blockquote><p>Without a retrieval layer, Claude’s default approach is often:</p><pre>list the directory<br>grep around<br>read a bunch of files<br>keep guessing</pre><p>claude-context moves that work into a retrieval layer. It chunks the repository, generates embeddings, stores them in a <a href="https://milvus.io/blog/claude-context-reduce-claude-code-token-usage.md">Milvus-backed code index</a>, and retrieves relevant code chunks before the model starts reading files blindly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*FWjBDQ0pQMEewuD1.png" /></figure><p>claude-context flow showing codebase chunking, embeddings, vector database and hybrid search, relevant code retrieval, and Claude context injection</p><p>This is where AI coding tools start to look like search systems. You need chunking, embeddings, metadata, lexical matching, ranking, and freshness. Those are the same building blocks behind <a href="https://zilliz.com/blog/top-10-context-engineering-techniques-you-should-know-for-production-rag">production RAG retrieval</a>, <a href="https://milvus.io/blog/build-smarter-rag-routing-hybrid-retrieval.md">hybrid retrieval routing</a>, and <a href="https://milvus.io/blog/choose-embedding-model-rag-2026.md">embedding model selection</a>.</p><h3>memsearch keeps useful memory across sessions and agents</h3><p>memsearch tackles the opposite side of the problem: not what to forget, but how to recall what matters.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7AzJjko8ZGyP3O_G.png" /></figure><p>memsearch logo image from the original article</p><p>Imagine you tell Claude on Monday:</p><blockquote><em>Our webhook can’t retry on failure — failed events need to go into a dead letter queue.</em></blockquote><p>On Wednesday, you open a new session and ask:</p><blockquote><em>What else can we optimize in the webhook layer?</em></blockquote><p>Without durable memory, Claude treats Monday’s decision as if it never happened. You explain it again.</p><p>memsearch stores memory as local, human-readable Markdown files and uses Milvus as a rebuildable retrieval index. That design keeps memory editable by humans while still making it searchable for agents.</p><p>At retrieval time, memsearch uses progressive recall: search first, expand if needed, then drill down to the original transcript only when necessary.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*spRaNyGtn9iEphKv.png" /></figure><p>memsearch progressive retrieval flow showing search, expand, transcript, and summarized return to the main conversation</p><p>This Markdown-first pattern is useful for teams working across sessions, models, and agents. It also pairs naturally with <a href="https://milvus.io/blog/adding-persistent-memory-to-claude-code-with-the-lightweight-memsearch-plugin.md">long-term AI agent memory</a>, <a href="https://milvus.io/blog/openagents-milvus-how-to-build-smarter-multi-agent-systems-that-share-memory.md">shared multi-agent memory</a>, and the broader problem of preventing <a href="https://zilliz.com/ai-faq/can-context-engineering-help-reduce-context-rot">context rot in agent systems</a>.</p><h3>How do these tools work together?</h3><p>The seven tools are complementary, not interchangeable. Use them as layers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Qb-mQ9NsgLcycSTH6y4Sjg.png" /></figure><p>A practical rollout order is:</p><ol><li>Kill obvious noise first. Add RTK or Context Mode if shell output and tool payloads dominate your context.</li><li>Fix repository navigation. Add code-review-graph for structure or claude-context for semantic code retrieval.</li><li>Control what remains. Use Token Savior and Caveman to keep file reads and model responses compact.</li><li>Preserve durable knowledge. Use memsearch when repeated explanations become the bottleneck.</li></ol><h3>Keep in touch</h3><ul><li>Join the <a href="https://discord.com/invite/8uyFbECzPX">Milvus Discord community</a> to ask questions and compare context-management patterns with other developers.</li><li><a href="https://milvus.io/office-hours">Book a free Milvus Office Hours session</a> if you want help designing a retrieval layer for code, memory, or RAG workloads.</li><li>If you’d rather skip the infrastructure setup, <a href="https://cloud.zilliz.com/signup">Zilliz Cloud</a> (managed Milvus) offers a free tier to get started.</li></ul><h3>Frequently Asked Questions</h3><p>How do I reduce Claude Code token usage without losing useful context?</p><p>Start by compressing the noisiest inputs: terminal output, raw tool payloads, and repeated code reads. Then add retrieval tools such as claude-context or code-review-graph so Claude can pull relevant code instead of exploring the repository from scratch.</p><p>Should I use claude-context or code-review-graph for a large repo?</p><p>Use claude-context when you need semantic code search, especially when you do not know the exact file or symbol name. Use code-review-graph when you need structural answers such as call relationships, imports, test dependencies, and review blast radius.</p><p>Is memory different from code retrieval in Claude Code?</p><p>Yes. Code retrieval finds relevant project files or symbols. Memory retrieval recalls durable decisions, user preferences, debugging history, and cross-session lessons. memsearch focuses on memory; claude-context focuses on code retrieval.</p><p>Do these tools replace prompt caching or a larger context window?</p><p>No. Prompt caching and large context windows help with capacity and cost, but they do not decide what information deserves attention. Context-management tools improve the quality and density of what enters the model in the first place.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*maLBQEj-XTnF9UbT.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1ea708f64355" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>