<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://weaviate.io/blog</id>
    <title>Weaviate Blog</title>
    <updated>2026-09-09T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://weaviate.io/blog"/>
    <subtitle>Weaviate Blog</subtitle>
    <icon>https://weaviate.io/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[HFresh: Memory-Efficient Vector Search]]></title>
        <id>https://weaviate.io/blog/hfresh</id>
        <link href="https://weaviate.io/blog/hfresh"/>
        <updated>2026-09-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[HFresh is Weaviate's disk-based vector index for memory-efficient vector search, combining low heap usage with incremental background maintenance.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Scaling a vector database across multiple nodes." src="https://weaviate.io/assets/images/hero-0d5232f85002506f88763522238ef8ea.jpg" width="1730" height="909" class="img_ev3q"></p>
<br>
<p>HFresh is Weaviate's disk-based vector index for applications that prioritize lower memory use over peak query throughput. That tradeoff is useful for small applications with limited resources as well as large datasets. Weaviate Cloud's <a href="https://docs.weaviate.io/cloud/manage-clusters/create#optimization-profile" target="_blank" rel="noopener noreferrer" class="">Free Tier</a>, for example, uses HFresh by default through its Cost Optimized profile.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="understanding-hnsws-memory-bottleneck-in-similarity-search">Understanding HNSW's memory bottleneck in similarity search<a href="https://weaviate.io/blog/hfresh#understanding-hnsws-memory-bottleneck-in-similarity-search" class="hash-link" aria-label="Direct link to Understanding HNSW's memory bottleneck in similarity search" title="Direct link to Understanding HNSW's memory bottleneck in similarity search" translate="no">​</a></h2>
<p>When it comes to finding similar vectors quickly, HNSW (Hierarchical Navigable Small World) has become the gold standard. It's fast and accurate, but as datasets grow from millions to billions of vectors, HNSW reveals a fundamental constraint: its graph and vector cache are kept in memory.</p>
<p>HNSW is a graph-based index that organizes vectors into a hierarchical structure. At the top layer, you have a sparse graph with long-distance connections that help you quickly navigate to the right neighborhood. As you descend through the layers, the graphs become denser with more local connections, eventually guiding you to the most similar vectors at the bottom layer.</p>
<p><img decoding="async" loading="lazy" alt="HNSW organizes vectors into progressively denser graph layers that guide a query toward nearby vectors." src="https://weaviate.io/assets/images/hnsw-explained-09135d3f50d1e3724786918b5a29b8c0.png" width="1200" height="870" class="img_ev3q"></p>
<p>The question isn't whether HNSW is good. It absolutely is. If you need the lowest possible latency and highest throughput, HNSW is hard to beat. But many applications prioritize lower memory use and larger scale over peak query performance.</p>
<p>This is where disk-based indexes become interesting. What if you could trade some latency for much lower memory use and the ability to scale to larger datasets?</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="introducing-hfresh">Introducing HFresh<a href="https://weaviate.io/blog/hfresh#introducing-hfresh" class="hash-link" aria-label="Direct link to Introducing HFresh" title="Direct link to Introducing HFresh" translate="no">​</a></h2>
<p>HFresh is a modern disk-based vector index designed for high recall, strong update performance, and controlled query I/O at large scale. It builds on ideas introduced by the <a href="https://arxiv.org/pdf/2410.14452" target="_blank" rel="noopener noreferrer" class="">SPFresh</a> research paper, adapting the design to use battle-tested components already present in Weaviate.</p>
<p>At a high level, HFresh belongs to the family of partition-based vector indices. Instead of connecting every vector to neighbors in a global graph like HNSW, HFresh divides vectors into many small regions called postings. Each posting contains vectors that are close to each other in vector space and is stored on disk in an LSM store.</p>
<p><img decoding="async" loading="lazy" alt="HFresh architecture with an RQ8 centroid HNSW in memory pointing to RQ1 postings on disk." src="https://weaviate.io/assets/images/hfresh-structure-820476e5da431e832aae43961003be67.png" width="1200" height="976" class="img_ev3q"></p>
<p>To make this layout efficient, HFresh uses a two-stage search strategy.</p>
<p>First, a compact in-memory centroid index identifies which regions of the vector space are relevant to a query. Then, only corresponding postings are fetched from disk and searched in detail. By limiting disk reads to a small subset of the dataset, HFresh is designed to keep I/O bounded and latency predictable, even as the dataset grows into billions.</p>
<p>This structure is designed to support very large datasets while keeping performance predictable.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="freshness-without-rebuilds">Freshness without rebuilds<a href="https://weaviate.io/blog/hfresh#freshness-without-rebuilds" class="hash-link" aria-label="Direct link to Freshness without rebuilds" title="Direct link to Freshness without rebuilds" translate="no">​</a></h3>
<p>The key idea behind SPFresh, and inherited by HFresh, is that most updates only affect a small region of the vector space.</p>
<p>In traditional partition-based indexes, updates can accumulate and partitions can drift, eventually requiring a full rebuild to restore recall and latency, a process that can take hours or days at scale.</p>
<p>SPFresh shows that this is often unnecessary. In a well-structured partitioned index, inserting or deleting a vector typically only affects a small neighborhood of the vector space. Instead of rebuilding everything, you can maintain index quality through incremental rebalancing, using a small set of local operations.</p>
<ul>
<li class=""><strong>Splitting</strong> oversized postings</li>
<li class=""><strong>Merging</strong> undersized ones</li>
<li class=""><strong>Reassigning</strong> vectors when boundaries shift</li>
</ul>
<p>These operations run mostly asynchronously in the background, continuously repairing small local imbalances before they accumulate into global problems. The result is an index that stays fresh and well-balanced over time, without disruptive rebuild cycles.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-hfresh-builds-on-spfresh">How HFresh builds on SPFresh<a href="https://weaviate.io/blog/hfresh#how-hfresh-builds-on-spfresh" class="hash-link" aria-label="Direct link to How HFresh builds on SPFresh" title="Direct link to How HFresh builds on SPFresh" translate="no">​</a></h3>
<p>HFresh takes the core idea behind SPFresh and adapts it to fit Weaviate's architecture. The goal was not to reproduce the paper component by component, but to keep what makes the design so interesting:</p>
<ul>
<li class="">local maintenance instead of rebuilds</li>
<li class="">controlled query I/O</li>
<li class="">a clear separation between the in-memory routing layer and disk-based postings</li>
</ul>
<p>From there, we made a series of pragmatic choices. Instead of introducing entirely new ANN machinery, we reused battle-tested pieces already present in Weaviate and shaped them to serve this new layout. This means keeping the overall SPFresh philosophy, while rethinking some of its components to better match Weaviate's strengths around indexing, filtering, compression, and updates.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="hnsw-as-the-centroid-index">HNSW as the centroid index<a href="https://weaviate.io/blog/hfresh#hnsw-as-the-centroid-index" class="hash-link" aria-label="Direct link to HNSW as the centroid index" title="Direct link to HNSW as the centroid index" translate="no">​</a></h2>
<p>A key design choice in HFresh is the use of HNSW as the centroid index, rather than SPTAG.</p>
<p>SPTAG is the ANN index used in Microsoft's original SPANN design and carried over into SPFresh. It combines a partitioning tree with a graph, allowing queries to quickly navigate toward the closest centroids and, from there, the right posting lists. For Weaviate, however, HNSW was the more natural fit: it already plays that role very well.</p>
<p>HNSW is the most widely used vector index in Weaviate and one of the most battle-tested parts of the system. We understand its behavior well in production, across a wide range of workloads and dataset sizes. Reusing it for centroid search lets HFresh build on infrastructure that is already proven, rather than introducing a brand-new mechanism.</p>
<p>HNSW is also a strong fit for what the centroid index actually needs to do. In HFresh, the centroid layer is responsible for routing queries to the right postings quickly and accurately. That means it must remain compact, have low latency, and support frequent updates as postings evolve over time.</p>
<p>Centroids are not static: splits, merges, and reassignments continuously reshape the partitioning of the vector space, so the centroid index must be able to absorb many insertions and deletions without requiring expensive rebuilds.</p>
<p>Another advantage is that the centroid index can itself be quantized. Because the centroid layer is only used to identify promising regions of the vector space, HFresh can compress those vectors aggressively enough to reduce memory usage while maintaining the accuracy needed for strong recall. In fact, HFresh uses HNSW with RQ8, reducing memory usage of centroids by 4x.</p>
<p>Using HNSW here also means that improvements to HNSW automatically benefit HFresh. A good example is <a class="" href="https://weaviate.io/blog/speed-up-filtered-vector-search">ACORN</a>, which improves filtered search by making graph traversal more efficient when only part of the dataset matches a filter. Since HFresh relies on HNSW as the centroid layer, those improvements are not isolated: they strengthen HFresh's query path.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="quantization">Quantization<a href="https://weaviate.io/blog/hfresh#quantization" class="hash-link" aria-label="Direct link to Quantization" title="Direct link to Quantization" translate="no">​</a></h2>
<p>HFresh uses Rotational Quantization in two places, with two different compression levels.</p>
<p>The reason is that the two stages of search have different jobs. The centroid index routes the query to the right postings, so it needs enough precision to avoid sending the query to the wrong part of the vector space. The postings, on the other hand, are used to generate candidates. Their approximate scores are not the final ranking, because HFresh later rescores the best candidates using the original uncompressed vectors.</p>
<p>Rotational Quantization works by rotating vectors into a representation that is easier to compress, then reducing the precision of each dimension. HFresh uses:</p>
<ul>
<li class=""><strong>RQ8 for centroids</strong>, reducing centroid vector memory by <strong>4x</strong></li>
<li class=""><strong>RQ1 for postings</strong>, reducing stored vector data by up to <strong>32x</strong> compared to 32-bit floats</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="rq8-for-the-centroid-index">RQ8 for the centroid index<a href="https://weaviate.io/blog/hfresh#rq8-for-the-centroid-index" class="hash-link" aria-label="Direct link to RQ8 for the centroid index" title="Direct link to RQ8 for the centroid index" translate="no">​</a></h3>
<p>The first stage of HFresh search uses an HNSW index over centroids. This in-memory index identifies which postings are likely to contain the nearest neighbors for a query.</p>
<p>HFresh uses RQ8 here because routing mistakes are expensive. If the centroid search misses the right region, the later posting scan may never see the true nearest neighbors. RQ8 gives a strong compromise: it makes centroid-vector payloads approximately <strong>4x smaller</strong> before overhead while keeping enough precision for accurate routing.</p>
<p>This works especially well because the centroid index is much smaller than the full vector dataset. HFresh can afford a higher-precision compression format for centroids, while still keeping the in-memory layer compact.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="rq1-for-postings">RQ1 for postings<a href="https://weaviate.io/blog/hfresh#rq1-for-postings" class="hash-link" aria-label="Direct link to RQ1 for postings" title="Direct link to RQ1 for postings" translate="no">​</a></h3>
<p>After HFresh has selected the most promising postings, it scans the vectors stored inside them. This stage has a different tradeoff.</p>
<p>Postings live on disk, so their size directly affects storage cost and query I/O. HFresh stores posting vectors with RQ1, where each dimension is represented with a single bit. Compared to 32-bit float vectors, that is up to a <strong>32x reduction</strong> in vector storage.</p>
<p>That aggressive compression makes each posting smaller and cheaper to read. It also makes the first-pass distance computation fast enough to scan many candidates.</p>
<p>HFresh does not rely on RQ1 scores for the final ranking. Instead, RQ1 is used to build a candidate set. HFresh then fetches the original uncompressed vectors for the top candidates and recomputes exact distances during rescoring. This keeps disk reads small without giving up final ranking quality.</p>
<p><img decoding="async" loading="lazy" alt="HFresh query path from the in-memory centroid HNSW through selected RQ1 postings and full-precision rescoring." src="https://weaviate.io/assets/images/hfresh-query-path-3bac75e7e11cb92ac3ea8cb7de1a67cb.png" width="1200" height="1185" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="background-operations">Background operations<a href="https://weaviate.io/blog/hfresh#background-operations" class="hash-link" aria-label="Direct link to Background operations" title="Direct link to Background operations" translate="no">​</a></h2>
<p>The reason HFresh can stay balanced over time without rebuilds is that maintenance is built directly into the index. Instead of letting imbalances accumulate and then fixing everything in one large offline job, HFresh breaks down maintenance into small background tasks that can be processed continuously.</p>
<p>In practice, most foreground writes stay simple: vectors are appended quickly, and follow-up work is pushed to background queues. Those tasks are persisted in dedicated on-disk queues, so they survive restarts and can be drained incrementally by the scheduler.</p>
<p>HFresh organizes this work into three main background task types: split, merge, and reassign.</p>
<p><img decoding="async" loading="lazy" alt="An oversized posting split into two balanced postings with new centroids." src="https://weaviate.io/assets/images/hfresh-split-0212479c5b6ff6fbb1d637aa3eb8c079.png" width="1200" height="520" class="img_ev3q"></p>
<p><strong>Split:</strong> When a posting grows too large, HFresh splits it. The posting is loaded, stale entries are garbage-collected, its vectors are divided into two balanced groups using the Balanced K-Means algorithm, and two new centroids are created to replace the old one. This keeps postings from growing too much, which would make disk reads heavier and routing less precise.</p>
<p><img decoding="async" loading="lazy" alt="An undersized posting merged into a nearby posting under one centroid." src="https://weaviate.io/assets/images/hfresh-merge-5ab946dabe55fd855f23513a8fa235fd.png" width="1200" height="520" class="img_ev3q"></p>
<p><strong>Merge:</strong> The opposite problem is postings that become too small. That can happen after deletes or simply as the data distribution evolves. In those cases, HFresh looks for a nearby posting that can absorb the smaller one without becoming too large itself. If it finds a good candidate, it merges the two and removes the extra centroid. This prevents the index from fragmenting into too many tiny postings.</p>
<p><img decoding="async" loading="lazy" alt="A vector reassigned from one posting to a better neighboring posting." src="https://weaviate.io/assets/images/hfresh-reassign-a4be01751bb29f958fbb1d5e2b0f8311.png" width="1200" height="520" class="img_ev3q"></p>
<p><strong>Reassign:</strong> After a split or a merge, some vectors may no longer belong in the posting where they are currently stored. That's where reassignment comes in. The SPFresh paper describes a protocol called LIRE (<strong>L</strong>ightweight <strong>I</strong>ncremental <strong>Re</strong>balancing) which, after a split, checks whether some vectors would now fit better under one of the new centroids, or even under a neighboring posting. After a merge, it checks whether some vectors that were absorbed should really be moved elsewhere instead. These reassignments let HFresh progressively correct mistakes instead of trying to get everything perfect in one step.</p>
<p>Together, these background operations form a continuous balancing loop. Inserts make local changes, and the index quietly tidies itself up afterward. The result is an index that stays fresh over time without disruptive rebuild cycles.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="filtered-search">Filtered search<a href="https://weaviate.io/blog/hfresh#filtered-search" class="hash-link" aria-label="Direct link to Filtered search" title="Direct link to Filtered search" translate="no">​</a></h2>
<p>Filtered vector search adds another constraint: results must be similar to the query vector while also satisfying the filter. In an e-commerce search, for example, that might mean finding similar products from specific brands, within a price range, and currently in stock.</p>
<p>HFresh uses an allow list, represented as a bitmap, to track the document IDs that satisfy the filter. It then chooses between two search strategies based on the number of matching vectors.</p>
<p>For highly selective filters, running the full HFresh pipeline can cost more than searching the matching subset directly. When the allow list contains fewer than 5,000 IDs, HFresh bypasses centroid routing and posting scans, fetches the original vectors for those IDs, and computes exact distances over them. The current 5,000-ID cutoff is a fixed internal heuristic, not a configurable threshold or a general tuning recommendation.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="posting-aware-filtering">Posting-aware filtering<a href="https://weaviate.io/blog/hfresh#posting-aware-filtering" class="hash-link" aria-label="Direct link to Posting-aware filtering" title="Direct link to Posting-aware filtering" translate="no">​</a></h3>
<p>For broader filters, HFresh uses its regular two-stage search with a posting-aware form of prefiltering. The filter identifies matching objects, but the centroid HNSW routes queries to postings rather than individual objects. HFresh bridges those two levels using metadata that records which vector IDs belong to each posting.</p>
<p>The process is:</p>
<ol>
<li class="">Translate the object-level allow list into posting eligibility using the posting metadata.</li>
<li class="">Navigate the centroid HNSW with <a class="" href="https://weaviate.io/blog/speed-up-filtered-vector-search">ACORN</a>, selecting postings that can contribute at least one matching vector.</li>
<li class="">Read the selected postings and reapply the original allow list while scanning their compressed vectors.</li>
<li class="">Rescore the top candidates using their original uncompressed vectors.</li>
</ol>
<p>Because HFresh can replicate a vector across multiple postings, it also tracks which matching vectors have already contributed to posting selection. This avoids reading multiple postings solely because they contain replicas of the same match. Together, posting-level selection and vector-level checks reduce unnecessary disk reads while ensuring that the final results satisfy the filter.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-use-hfresh">How to use HFresh<a href="https://weaviate.io/blog/hfresh#how-to-use-hfresh" class="hash-link" aria-label="Direct link to How to use HFresh" title="Direct link to How to use HFresh" translate="no">​</a></h2>
<p>To use HFresh, configure it as the vector index when creating a collection.</p>
<p>Here is an example using the Python client:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">config </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> VectorDistances</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">collection </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"Article"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    vector_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Vectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">self_provided</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"Title"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        vector_index_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">VectorIndex</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">hfresh</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            distance_metric</span><span class="token operator">=</span><span class="token plain">VectorDistances</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">COSINE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Tuning HFresh</div><div class="admonitionContent_BuS1"><p>Start with the defaults. If recall is too low, increase:</p><ul>
<li class=""><code>search_probe</code> to search more postings per query.</li>
<li class=""><code>quantizer.rescore_limit</code> to rescore more candidates using full-precision vectors.</li>
</ul><p>Both settings can be changed without rebuilding the index.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="experiments">Experiments<a href="https://weaviate.io/blog/hfresh#experiments" class="hash-link" aria-label="Direct link to Experiments" title="Direct link to Experiments" translate="no">​</a></h2>
<p>We benchmarked uncompressed HNSW, HNSW with RQ1, HNSW with RQ8, and HFresh on the DBpedia OpenAI 1M dataset. HNSW indexes were built with <code>efConstruction=256</code> and <code>maxConnections=16</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="heap-usage">Heap usage<a href="https://weaviate.io/blog/hfresh#heap-usage" class="hash-link" aria-label="Direct link to Heap usage" title="Direct link to Heap usage" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="Heap memory usage at rest for HFresh, uncompressed HNSW, HNSW with RQ1, and HNSW with RQ8." src="https://weaviate.io/assets/images/vector-memory-chart-841fc0db359c706ae89f458429ec915b.png" width="2400" height="1600" class="img_ev3q"></p>
<p>These measurements report Go heap usage, not total process or system memory. HFresh also relies on OS-managed caching for its on-disk data, which is not captured by the heap figures.</p>
<p>The clearest difference is heap usage at rest. HFresh uses 239 MB of heap, compared with 6.67 GB for uncompressed HNSW.</p>
<p>HFresh also uses less heap than quantized HNSW. HNSW with RQ1 uses 715 MB, approximately 3x as much as HFresh, while HNSW with RQ8 uses 2.38 GB, approximately 10x as much.</p>
<p>This difference follows directly from HFresh's architecture. HFresh keeps the RQ8-compressed centroid index and supporting metadata in memory while storing compressed postings on disk. Posting membership, vector versions and deletion state, and posting sizes also consume heap and grow with the dataset, but this layout reduces the heap required for index data.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="query-throughput">Query throughput<a href="https://weaviate.io/blog/hfresh#query-throughput" class="hash-link" aria-label="Direct link to Query throughput" title="Direct link to Query throughput" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="Query throughput versus recall for HFresh, uncompressed HNSW, HNSW with RQ1, and HNSW with RQ8." src="https://weaviate.io/assets/images/qps-recall-4316f2c564751c8920e03bb6481f225a.png" width="2400" height="1600" class="img_ev3q"></p>
<p>The QPS-recall curve shows the query-performance side of HFresh's heap advantage.</p>
<p>At comparable recall, HNSW and its quantized variants deliver substantially higher throughput than HFresh. This is expected: HNSW searches an in-memory graph, while HFresh reads selected postings from disk and fetches original vectors for rescoring.</p>
<p>These results clarify when to choose each index. HNSW remains the better option when the lowest latency and highest throughput matter most. HFresh is designed for workloads where keeping the full index in memory is too expensive and lower throughput is an acceptable tradeoff for a much smaller heap footprint.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="scaling-to-one-billion-vectors">Scaling to one billion vectors<a href="https://weaviate.io/blog/hfresh#scaling-to-one-billion-vectors" class="hash-link" aria-label="Direct link to Scaling to one billion vectors" title="Direct link to Scaling to one billion vectors" translate="no">​</a></h3>
<p>Separately from the DBpedia benchmarks, we tested HFresh index construction with one billion randomly generated 256-dimensional vectors. We used default index-construction settings and imported batches of 1,000 with 12 workers.</p>
<table><thead><tr><th>Metric</th><th>Result</th></tr></thead><tbody><tr><td>Dataset</td><td><strong>1 billion 256-dimensional vectors</strong></td></tr><tr><td>Compute</td><td><strong>32 vCPUs, 256 GB RAM</strong> (<code>n2-highmem-32</code>)</td></tr><tr><td>Storage</td><td><strong>4 TB SSD Persistent Disk</strong> (<code>pd-ssd</code>)</td></tr><tr><td>Peak VM memory usage</td><td><strong>204 GB</strong></td></tr><tr><td>VM memory usage after restart</td><td><strong>54 GB</strong></td></tr><tr><td>Go heap after restart</td><td><strong>47 GB</strong></td></tr><tr><td>Peak disk usage</td><td><strong>3.09 TB</strong></td></tr><tr><td>Disk usage after import</td><td><strong>2.28 TB</strong></td></tr></tbody></table>
<p>The run successfully constructed the billion-vector HFresh index. No recall or QPS measurements were collected for this scale test.</p>
<p>The VM memory measurements come from GCP system metrics, while the heap measurement comes from a Go heap profile.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://weaviate.io/blog/hfresh#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>HFresh gives Weaviate a disk-based index for memory-efficient vector search, from small applications to large, mutable datasets. By keeping a compact centroid index and supporting metadata in memory and maintaining disk-resident postings incrementally, it reduces the heap required for index data without relying on full index rebuilds. HNSW remains the better choice when the lowest latency and highest throughput matter most; HFresh is designed for workloads where a smaller heap footprint justifies lower query throughput.</p>
<p>HFresh was introduced as a technical preview in Weaviate 1.36 and became generally available in Weaviate 1.38. See the <a href="https://docs.weaviate.io/weaviate/concepts/vector-index#hfresh-index" target="_blank" rel="noopener noreferrer" class="">documentation</a> to get started.</p>
<p>If you are evaluating HFresh for a large-scale workload, we would like to hear about your dataset, performance requirements, and results.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/hfresh#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=hfresh&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Asdine El Hrychy</name>
            <uri>https://github.com/asdine</uri>
        </author>
        <author>
            <name>Roberto Esposito</name>
            <uri>https://www.linkedin.com/in/robbespo00</uri>
        </author>
        <category label="engineering" term="engineering"/>
        <category label="concepts" term="concepts"/>
        <category label="search" term="search"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building Foundry Part 3: From archive to creative search]]></title>
        <id>https://weaviate.io/blog/building-foundry-creative-search</id>
        <link href="https://weaviate.io/blog/building-foundry-creative-search"/>
        <updated>2026-09-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Part 3: We turn a messy creative archive into a searchable library using a manifest, Weaviate, and hybrid search.]]></summary>
        <content type="html"><![CDATA[<figure><video width="100%" autoplay="" loop="" muted="" controls=""><source src="/assets/medias/Foundry_test-938bdd9863b5e9d757de0d7c1e5ca277.mp4" type="video/mp4"><p>Your browser does not support the video tag.</p></video><figcaption>Foundry searching the creative archive</figcaption></figure>
<blockquote>
<p><strong>Building Foundry</strong><br>
<!-- -->A practical series on creative workflows, semantic search, and Weaviate.</p>
</blockquote>
<p>Read the previous post in the series: <a class="" href="https://weaviate.io/blog/building-foundry-where-workflows-break">Part 2: Where creative workflows break</a>.</p>
<p>Part 1 introduced the problem. Part 2 showed why familiar ways of organising work become less reliable as an archive grows. Now we are going to build the solution.</p>
<p>Foundry turns an existing archive into a searchable creative library. It scans the files, records what it finds, prepares each asset for retrieval, and synchronises the result with Weaviate. Nothing is moved or renamed. Every result still leads back to its original source.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">creative archive</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      ↓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">read-only scanner</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      ↓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">manifest and descriptions</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      ↓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">Weaviate collection</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      ↓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">keyword, semantic, or hybrid search</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      ↓</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">source asset</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="starting-with-the-archive-we-already-have">Starting with the archive we already have<a href="https://weaviate.io/blog/building-foundry-creative-search#starting-with-the-archive-we-already-have" class="hash-link" aria-label="Direct link to Starting with the archive we already have" title="Direct link to Starting with the archive we already have" translate="no">​</a></h2>
<p>Our test archive contains 23 assets from five fictional projects. Inside are concept art, design exports, production notes, audio, video, and reference images.</p>
<p>The names are deliberately inconsistent:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">final_FINAL_v7.svg</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">BROLL_NEW2.svg</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">scene_14_USE_THIS.svg</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">logo_options_FINAL3.svg</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">bridge_texture.svg</span><br></span></code></pre></div></div>
<p>That mess is intentional. Foundry should be useful with the archive a team has today, not the perfectly organised archive it may never have time to create.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-scan-without-changing-the-source">Step 1: scan without changing the source<a href="https://weaviate.io/blog/building-foundry-creative-search#step-1-scan-without-changing-the-source" class="hash-link" aria-label="Direct link to Step 1: scan without changing the source" title="Direct link to Step 1: scan without changing the source" translate="no">​</a></h2>
<p>Foundry begins with a read-only scan. It walks the selected folder and records facts about every supported file.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npm install</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">npm run demo</span><br></span></code></pre></div></div>
<p>The scanner captures the source path, project, file type, size, modified date, and a content hash. It writes the result to <code>output/manifest.json</code>.</p>
<p><img decoding="async" loading="lazy" alt="Foundry archive inventory showing references, concepts, and video assets" src="https://weaviate.io/assets/images/image-02-c7d2dcfecdf8336846378b8b672a5654.jpg" width="950" height="506" class="img_ev3q"></p>
<p>The content hash gives each asset a stable identity. It lets Foundry detect changes even when a filename stays the same and skip work when nothing has changed.</p>
<p>The browser turns that inventory into something visual. Images have previews, videos can be played, and documents remain visible without thumbnails.</p>
<p>This first checkpoint matters because search cannot find what the scanner missed.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-prepare-records-for-retrieval">Step 2: prepare records for retrieval<a href="https://weaviate.io/blog/building-foundry-creative-search#step-2-prepare-records-for-retrieval" class="hash-link" aria-label="Direct link to Step 2: prepare records for retrieval" title="Direct link to Step 2: prepare records for retrieval" translate="no">​</a></h2>
<p>The manifest tells us what exists. The next step is to describe what those files contain.</p>
<p>The preparation stage adds descriptions, tags, extracted text, relationship roles, and a source URI. A prepared image record looks like this:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"fileName"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"rain-floor.jpg"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"relativePath"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"RAIN TRAILER/References/rain-floor.jpg"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"project"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"RAIN TRAILER"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"assetType"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"image"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"relationshipRole"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"reference"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"description"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Heavy rain striking a reflective floor with bright droplets and bokeh."</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"tags"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"rain"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"wet floor"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"reflection"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"atmosphere"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"sourceUri"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"foundry://RAIN TRAILER/References/rain-floor.jpg"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>The <code>foundry://</code> URI points back to the asset without treating Weaviate as file storage. A production version could use a DAM link, mounted path, S3 URL, or application route.</p>
<p>For now, the demo uses a small enrichment manifest so every run produces the same result. Later versions can generate this context from image captions, OCR, transcripts, and video keyframes.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-synchronise-with-weaviate">Step 3: synchronise with Weaviate<a href="https://weaviate.io/blog/building-foundry-creative-search#step-3-synchronise-with-weaviate" class="hash-link" aria-label="Direct link to Step 3: synchronise with Weaviate" title="Direct link to Step 3: synchronise with Weaviate" translate="no">​</a></h2>
<p>Before synchronisation, Foundry shows exactly what will be indexed. The user can review descriptions, metadata, and source paths before anything reaches Weaviate.</p>
<p><img decoding="async" loading="lazy" alt="Foundry ingestion review showing objects and vectorised fields" src="https://weaviate.io/assets/images/image-03-4980e2194f317e4e2605a05af706aa52.jpg" width="1000" height="300" class="img_ev3q"></p>
<p>The application then creates or updates the <code>Foundry</code> collection. Weaviate generates embeddings and stores them beside the metadata. Each object keeps its source path and rights status.</p>
<p><img decoding="async" loading="lazy" alt="Foundry showing a completed Weaviate synchronisation" src="https://weaviate.io/assets/images/image-04-ed437f01a06cbbfc6eafe4dfda59efb3.jpg" width="1100" height="300" class="img_ev3q"></p>
<p>Running the process again does not create duplicates. Deterministic identifiers ensure that each asset updates the same object.</p>
<p>The same workflow is available from the command line:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">npm run scan</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">npm run ingest:prepare</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">npm run ingest:cloud</span><br></span></code></pre></div></div>
<p>Cloud credentials stay in a local <code>.env</code> file:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">WEAVIATE_URL=https://your-cluster.weaviate.network</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">WEAVIATE_API_KEY=replace-with-a-read-write-api-key</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">WEAVIATE_COLLECTION=Foundry</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-search-the-archive">Step 4: search the archive<a href="https://weaviate.io/blog/building-foundry-creative-search#step-4-search-the-archive" class="hash-link" aria-label="Direct link to Step 4: search the archive" title="Direct link to Step 4: search the archive" translate="no">​</a></h2>
<p>Once synchronisation finishes, the archive becomes a live search workspace.</p>
<p>The first test query is easy to describe but hard to map to a filename:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">white rabbit in a grassy landscape</span><br></span></code></pre></div></div>
<p><img decoding="async" loading="lazy" alt="Foundry hybrid retrieval returning rabbit and landscape assets" src="https://weaviate.io/assets/images/image-05-8c9d8538cc7bd224658de53871d02fd9.jpg" width="950" height="506" class="img_ev3q"></p>
<p>The results include a rabbit reference, the Big Buck Bunny trailer, and related landscape imagery. There is no need to remember a filename or folder. The user describes what they remember and Foundry brings the relevant work back into view.</p>
<p>Foundry exposes three retrieval modes:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">keyword  → exact words and names</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">semantic → meaning represented by embeddings</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">hybrid   → keyword and semantic signals combined</span><br></span></code></pre></div></div>
<p>Keyword search works when someone remembers a filename or production term. Semantic search works when they remember the content. Hybrid search brings both kinds of memory into one result set.</p>
<p>Filters make those results practical. Users can narrow the archive by project, file type, or relationship role. The same pattern can support approval status, rights, expiry dates, and delivery formats.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-the-build-proves">What the build proves<a href="https://weaviate.io/blog/building-foundry-creative-search#what-the-build-proves" class="hash-link" aria-label="Direct link to What the build proves" title="Direct link to What the build proves" translate="no">​</a></h2>
<p>The prototype now completes the journey from source folder to useful result:</p>
<ul>
<li class="">It scans a nested archive without changing the source files.</li>
<li class="">It creates stable records and detects changes with content hashes.</li>
<li class="">It enriches records before ingestion instead of relying on filenames alone.</li>
<li class="">It stores searchable records and managed embeddings in Weaviate.</li>
<li class="">It compares keyword, semantic, and hybrid retrieval on the same archive.</li>
<li class="">It returns images and video with links back to their source.</li>
</ul>
<p>Foundry is still a prototype. Automatic enrichment, incremental rescans, rights-aware filtering, and relevance feedback would be the next update to the project.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="run-foundry">Run Foundry<a href="https://weaviate.io/blog/building-foundry-creative-search#run-foundry" class="hash-link" aria-label="Direct link to Run Foundry" title="Direct link to Run Foundry" translate="no">​</a></h2>
<p>The project is available on <a href="https://github.com/Shan-Weaviate/foundry" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">cp .env.example .env</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Add your Weaviate Cloud URL and API key</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">npm install</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">npm run demo</span><br></span></code></pre></div></div>
<p>Use Node.js 22 or newer for cloud synchronisation and live search. The local inventory can run without cloud credentials.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>Explore the <a href="https://github.com/Shan-Weaviate/foundry" target="_blank" rel="noopener noreferrer" class="">Foundry repository</a> and follow the README to scan the sample archive or connect your own Weaviate Cloud collection.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="from-hidden-files-to-useful-history">From hidden files to useful history<a href="https://weaviate.io/blog/building-foundry-creative-search#from-hidden-files-to-useful-history" class="hash-link" aria-label="Direct link to From hidden files to useful history" title="Direct link to From hidden files to useful history" translate="no">​</a></h2>
<p>Foundry began with a familiar creative frustration: remembering the work but not where it lives.</p>
<p>It does not replace the folders, tools, or habits behind that work. It gives the archive a new way to reveal itself. An asset that once depended on the right filename, folder, or colleague can now be found through the idea behind it.</p>
<p>The archive stops being a place where finished work disappears. It becomes creative material again.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/building-foundry-creative-search#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=building-foundry-creative-search&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Shan Blackwood</name>
            <uri>https://www.linkedin.com/in/shan-blackwood/</uri>
        </author>
        <author>
            <name>Svitlana Smolianova</name>
            <uri>https://linkedin.com/in/svitlana-sm</uri>
        </author>
        <author>
            <name>Victoria Slocum</name>
            <uri>https://www.linkedin.com/in/victorialslocum/</uri>
        </author>
        <category label="creative-ai" term="creative-ai"/>
        <category label="workflows" term="workflows"/>
        <category label="search" term="search"/>
        <category label="weaviate" term="weaviate"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[How to extract meaning from charts and tables in PDFs]]></title>
        <id>https://weaviate.io/blog/charts-tables-pdfs</id>
        <link href="https://weaviate.io/blog/charts-tables-pdfs"/>
        <updated>2026-09-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[PDFs full of charts and tables are notoriously hard to put through a traditional RAG pipeline. In this post, we show how late-interaction multi-vector retrieval lets you search PDFs by what the page looks like: no OCR, no chunking, no text extraction.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Gross margin trend chart from NVIDIA&amp;#39;s Q2 FY26 deck, retrieved by a single text query without any OCR." src="https://weaviate.io/assets/images/nvidia-gross-margin-trend-e0d7228ff81c186427895df91b474186.png" width="2000" height="1125" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="intro">Intro<a href="https://weaviate.io/blog/charts-tables-pdfs#intro" class="hash-link" aria-label="Direct link to Intro" title="Direct link to Intro" translate="no">​</a></h2>
<p>If you have ever tried to put a stack of investor decks, scientific papers, or annual reports through a RAG pipeline, then you know the drill: set up an Optical Character Recognition (OCR) or text-extraction step, pick a chunking strategy, embed text, and finally retrieve information. After going through all this, someone may ask a question about revenue in <code>Q2 FY25</code>, and your retrieval would return three pages of unrelated bullet points because the actual answer is in a bar chart that was invisible to your index.</p>
<p>This used to be what people had to do — just leave out the interesting parts of a PDF from RAG such as bar charts with trends, comparison tables, architectural diagrams, and things in general that make PDFs so much more valuable than mere text.</p>
<p>In this article, we'll show you a better way that not only retrieves the rich information embedded in charts, but also eliminates complex processing steps. We'll cover:</p>
<ul>
<li class=""><strong>Classic RAG</strong>: Why OCR and text embedding works great for some (structured and unstructured) data, but not for rich PDFs.</li>
<li class=""><strong>Late Interaction RAG</strong>: What late-interaction multi-vector models are, and why they let you skip text extraction entirely.</li>
<li class=""><strong>Drag-N-Drop and Done</strong>: How to ingest multiple PDFs in Weaviate Cloud with just a few clicks.</li>
<li class=""><strong>Real Examples</strong>: Example queries against NVIDIA's FY2026 quarterly earnings, where each top result is the <em>exact chart</em> that answers a question.</li>
<li class=""><strong>Complex Agentic Reasoning</strong>: How to wrap the same data with the Weaviate Query Agent for synthesised answers with page-image citations.</li>
<li class=""><strong>Codified and Deployment-Ready</strong>: The same ingestion pipeline in roughly 50 lines of Python for when you need to deploy this in production.</li>
</ul>
<p>If you'd rather just see the demo first and read the explanations later, skip to the queries section below.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-traditional-rag-falls-short">How traditional RAG falls short<a href="https://weaviate.io/blog/charts-tables-pdfs#how-traditional-rag-falls-short" class="hash-link" aria-label="Direct link to How traditional RAG falls short" title="Direct link to How traditional RAG falls short" translate="no">​</a></h2>
<p>Let's first look at what most people do today when it comes to building a RAG pipeline for PDFs:</p>
<ol>
<li class="">OCR (or text-extract) the file (using either a python library or third-party tooling).</li>
<li class="">Chunk the text.</li>
<li class="">Embed the chunks with a text embedding model.</li>
<li class="">Retrieve, (maybe) rerank, generate.</li>
</ol>
<p>There's nothing inherently bad about this workflow, but there's a naive underlying assumption that <em>the page can be reduced to a sequence of text tokens without losing the richness of the content</em>. For a press release or a Wikipedia article, this is mostly fine, but for a slide deck full of charts, a 10-K with comparison tables, or an academic paper with illustrative figures, it's simply not enough.</p>
<p>You could build a complex ETL pipeline to extract charts and vectorize them separately, but that means another model in the pipeline and introduces more complexity into the stack as well as merging problems at query time.</p>
<p>With a late-interaction multi-vector model, you don't need any of those: You embed the <em>page</em>, and not the text within it. The model sees the chart the way you do. Yes, you heard that right, there is not even a chunking step — the page <em>is</em> the chunk.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="late-interaction-multi-vector-retrieval-in-two-paragraphs">Late-interaction multi-vector retrieval, in two paragraphs<a href="https://weaviate.io/blog/charts-tables-pdfs#late-interaction-multi-vector-retrieval-in-two-paragraphs" class="hash-link" aria-label="Direct link to Late-interaction multi-vector retrieval, in two paragraphs" title="Direct link to Late-interaction multi-vector retrieval, in two paragraphs" translate="no">​</a></h2>
<p>Before we get to the demo, let's take a quick detour on what makes this work. If you already know your way around ColPali / ColBERT, feel free to skip or skim.</p>
<p>Traditional dense embedding models compress an entire document (or chunk) into a single vector. Late-interaction multi-vector models do something different: they encode the document as a <em>set</em> of vectors, typically one per token (or for a vision model like the one we're about to use, one per image patch). At query time, your query is also encoded as a set, and the relevance score is the sum of best matches between query tokens and document tokens (a quantity called MaxSim).</p>
<p>Instead of asking <em>"is this whole page about my whole question?"</em>, the model can ask <em>"is the part of this page that talks about Q4 FY26 a good match for the part of my question about 'change over time'?"</em>. For a chart-heavy page, this is exactly the granularity that's needed. The model doesn't have to summarise an entire slide into a single vector, but can keep one vector per region of the page, and the query can pick out the regions that matter.</p>
<p>So really, there are two distinct advantages here:</p>
<ol>
<li class="">Because it's a <strong>visual model</strong> you keep the layout, the charts, the tables, etc. <em>and</em></li>
<li class="">By using MaxSim over a set of vectors, you <strong>eliminate the need for chunking</strong>.</li>
</ol>
<p>Weaviate offers <code>multi2multivec-weaviate</code>, a vectorizer module that runs a hosted late-interaction multi-vector model on Weaviate Cloud, so you don't have to host or manage a model in order to generate multi-vectors from your PDFs.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ingesting-pdfs-by-drag-and-drop">Ingesting PDFs by Drag-and-Drop<a href="https://weaviate.io/blog/charts-tables-pdfs#ingesting-pdfs-by-drag-and-drop" class="hash-link" aria-label="Direct link to Ingesting PDFs by Drag-and-Drop" title="Direct link to Ingesting PDFs by Drag-and-Drop" translate="no">​</a></h2>
<p>The fastest way to try this is the drag-and-drop importer in <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a>.</p>
<ol>
<li class="">Open your cluster in the Console.</li>
<li class="">Go to <em>Collections</em> and create a new collection.</li>
<li class="">Select the upload from file option and drop in your PDFs.</li>
</ol>
<div style="display:flex;gap:1rem;align-items:flex-start;margin:1.5rem 0"><div style="flex:1.5606 1 0"><a href="https://weaviate.io/assets/images/console-create-collection-90227cca6ba85195d4aa8c781acac4d5.png" target="_blank" rel="noopener noreferrer"><img src="https://weaviate.io/assets/images/console-create-collection-90227cca6ba85195d4aa8c781acac4d5.png" alt="Create new collection page in the Weaviate Console, with the Upload CSV, Excel or PDF option highlighted" style="width:100%;height:auto;display:block"></a></div><div style="flex:1.7175 1 0"><a href="https://weaviate.io/assets/images/console-upload-completed-4ff5dab338fa25e52498b3028da13c41.png" target="_blank" rel="noopener noreferrer"><img src="https://weaviate.io/assets/images/console-upload-completed-4ff5dab338fa25e52498b3028da13c41.png" alt="Weaviate Console after upload: a single NVIDIA Q4 FY26 PDF marked complete with a Next button" style="width:100%;height:auto;display:block"></a></div></div>
<p>And that's the entire ingestion process. Behind the scenes, Weaviate is doing three things:</p>
<ol>
<li class="">Rendering each PDF page to a high-resolution image.</li>
<li class="">Storing that image as a <code>BLOB</code> property on a new collection.</li>
<li class="">Vectorizing it with the <code>multi2multivec-weaviate</code> module, producing many vectors per page.</li>
</ol>
<p>A few things are worth noting:</p>
<ul>
<li class=""><strong>One object equals one page.</strong> The unit of retrieval is the page, which is also the unit a human navigates a document by.</li>
<li class=""><strong>No OCR.</strong> The model never sees the text as text. It sees the page as an image. That's why a chart with no caption is just as searchable as a paragraph.</li>
<li class=""><strong>The vectors are compressed.</strong> Late-interaction models can produce hundreds of vectors per page, which would be expensive to store naively. Weaviate uses a <a href="https://docs.weaviate.io/weaviate/configuration/compression/multi-vectors" target="_blank" rel="noopener noreferrer" class="">multi-vector encoding</a> scheme that keeps the index compact. (More on that also in the trade-offs section below.)</li>
</ul>
<p>For this demo, we've imported NVIDIA's four FY2026 quarterly investor presentations (Q1 through Q4). They cover the financial year ending in January 2026, contain wall-to-wall charts and tables, and total 92 pages. The whole import took about a minute and a half.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="interrogating-nvidias-quarterly-earnings">Interrogating NVIDIA's Quarterly Earnings<a href="https://weaviate.io/blog/charts-tables-pdfs#interrogating-nvidias-quarterly-earnings" class="hash-link" aria-label="Direct link to Interrogating NVIDIA's Quarterly Earnings" title="Direct link to Interrogating NVIDIA's Quarterly Earnings" translate="no">​</a></h2>
<p>Before we do anything fancy such as agentic reasoning on the data, we want to show you the raw retrieval results, as they are already impressive on their own.</p>
<p>With ingestion complete, you can query the data directly in the Console (or with any Weaviate client). The query is in plain English, and the result is a ranked list of pages with page images inline.</p>
<p>Let's walk through three queries and show you what results are returned.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="query-1-how-did-automotive-revenue-change-over-time">Query 1: <em>"how did automotive revenue change over time?"</em><a href="https://weaviate.io/blog/charts-tables-pdfs#query-1-how-did-automotive-revenue-change-over-time" class="hash-link" aria-label="Direct link to query-1-how-did-automotive-revenue-change-over-time" title="Direct link to query-1-how-did-automotive-revenue-change-over-time" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="Top result for the automotive revenue query — a five-quarter bar chart from NVIDIA&amp;#39;s Q2 FY26 deck" src="https://weaviate.io/assets/images/nvidia-automotive-revenue-85faef4afeec10a9bf00e73a989fa32d.png" width="2000" height="1125" class="img_ev3q"></p>
<p>The top result is a single page from the Q2 FY26 deck, titled <em>Automotive</em>. The left half is a bar chart showing five quarters of revenue (<code>$346M → $449M → $570M → $567M → $586M</code>, +69% Y/Y). The right half contains three bullet points about <code>Thor SoC</code> and <code>DRIVE AV</code>.</p>
<p>The phrase <em>"over time"</em> doesn't appear anywhere on this page. Neither does the word <em>"change"</em>. The model didn't match against text semantically, but rather the image of the page. What it saw was five bars of increasing height with quarterly labels, and that was enough to identify the page as a match for a question about a temporal trend.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="query-2-gross-margin-trend">Query 2: <em>"gross margin trend"</em><a href="https://weaviate.io/blog/charts-tables-pdfs#query-2-gross-margin-trend" class="hash-link" aria-label="Direct link to query-2-gross-margin-trend" title="Direct link to query-2-gross-margin-trend" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="Top result for the gross margin trend query — a combination chart with revenue bars and a gross margin line over five quarters, plus a financial KPI table" src="https://weaviate.io/assets/images/nvidia-gross-margin-trend-e0d7228ff81c186427895df91b474186.png" width="2000" height="1125" class="img_ev3q"></p>
<p>The top result here is the <em>Q2 FY26 Financial Summary</em> page. On the left is a combination chart: revenue bars and a non-GAAP gross margin line over five quarters. On the right is a GAAP/non-GAAP KPI table with Y/Y and Q/Q deltas.</p>
<p>Again, nothing on this page literally says "gross margin trend", but there <em>is</em> a line chart that visualises the gross margin dipping from 75.7% to 61.0% in Q1 FY26 and recovering to 72.7% in Q2 FY26. That's what a <em>trend</em> looks like, and it's what the model retrieved.</p>
<p>A side note: the same page also contains a detailed financial table. That makes it a particularly useful retrieval target if you're then going to ask follow-up questions like <em>"by how many basis points did gross margin recover Q/Q?"</em> The answer is sitting on the page the model already returned. More on that below when we introduce the Query Agent.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="query-3-how-did-data-center-revenue-change-over-time">Query 3: <em>"how did data center revenue change over time?"</em><a href="https://weaviate.io/blog/charts-tables-pdfs#query-3-how-did-data-center-revenue-change-over-time" class="hash-link" aria-label="Direct link to query-3-how-did-data-center-revenue-change-over-time" title="Direct link to query-3-how-did-data-center-revenue-change-over-time" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="Top result for the data center revenue query — Q4 FY26 revenue page with a Y/Y bar chart and bullet points" src="https://weaviate.io/assets/images/nvidia-data-center-revenue-cba7e28113971072f98de56a2abcd759.png" width="2000" height="1125" class="img_ev3q"></p>
<p>The top result is the Q4 FY26 <em>Revenue</em> page — a Y/Y bar chart (<code>$39.3B → $68.1B</code>) with a callout that data center revenue is up 13x since the emergence of ChatGPT. This is a great example that the model still respects text when it's the better match. In this case the chart is less relevant, but the box stating the exact answer is what returned the highest similarity (MaxSim) on this page. So you get the best of both modalities.</p>
<p>The runner-up is the dedicated <em>Data Center</em> page from a different quarter, which splits the segment into Compute and Networking:</p>
<p><img decoding="async" loading="lazy" alt="Runner-up: Q3 FY26 Data Center page splitting the segment into Compute and Networking bar charts" src="https://weaviate.io/assets/images/nvidia-data-center-split-9df02586dbcfe9cd614253b520897560.png" width="2000" height="1125" class="img_ev3q"></p>
<p>Notice how the second-best match isn't simply <em>"another page about data center"</em>, but a different <em>kind</em> of answer — the same revenue, broken down differently. That's a useful property for an agent that wants to triangulate across multiple views of the same underlying number. Speaking of which...</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="from-search-to-answers-the-weaviate-query-agent">From search to answers: the Weaviate Query Agent<a href="https://weaviate.io/blog/charts-tables-pdfs#from-search-to-answers-the-weaviate-query-agent" class="hash-link" aria-label="Direct link to From search to answers: the Weaviate Query Agent" title="Direct link to From search to answers: the Weaviate Query Agent" translate="no">​</a></h2>
<p>Vector search returns results, but sometimes you want an answer.</p>
<p>The <a href="https://docs.weaviate.io/agents/query" target="_blank" rel="noopener noreferrer" class="">Weaviate Query Agent</a> is a managed agent that wraps vector retrieval with multi-step reasoning, source citations, and inline page images. It is available out of the box for any Weaviate Cloud cluster. Simply point it to a collection and ask a question.</p>
<p><img decoding="async" loading="lazy" alt="Weaviate Query Agent answering an automotive revenue question with a synthesised, multi-quarter response" src="https://weaviate.io/assets/images/query-agent-response-dba61844921e16001352d72e099f1cb2.png" width="3680" height="2382" class="img_ev3q"></p>
<p>If we ask <em>"How did automotive revenue change across FY26 quarters? What's driving it?"</em> about the same collection, the agent comes back with a synthesised answer (the numbers from the bar chart, plus the bullet points about <code>Thor SoC</code> and <code>DRIVE AV</code> adoption) and the underlying page images as citations. The agent decided which pages to retrieve, <em>looked</em> at them visually, and quoted directly from the slide.</p>
<div style="display:flex;gap:1.5rem;align-items:flex-start;margin:1.5rem 0"><div style="flex:1"><p>Open the <em>Sources</em> panel and you'll see exactly which pages backed the answer. Among the citations is the <em>Automotive</em> page from the Q1 FY26 deck — the same kind of bar chart we surfaced in the raw vector search earlier, just for a different quarter.</p><p>Every numerical claim in the response is anchored to a specific page in a specific PDF, with the page image right there for verification. You don't have to blindly trust the agent, but can read the contents of the slide for yourself.</p></div><img src="https://weaviate.io/assets/images/query-agent-sources-49cc33b2f9338242e692bbc5017195e3.png" alt="Sources panel from the Query Agent — the cited pages include the actual Automotive bar chart from the Q1 FY26 deck" style="width:40%;flex:0 0 40%;max-width:360px"></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="building-a-deployable-pipeline-with-python">Building a deployable pipeline with Python<a href="https://weaviate.io/blog/charts-tables-pdfs#building-a-deployable-pipeline-with-python" class="hash-link" aria-label="Direct link to Building a deployable pipeline with Python" title="Direct link to Building a deployable pipeline with Python" translate="no">​</a></h2>
<p>The drag-and-drop UI is the fastest path to creating a POC, but most production pipelines need code, and here is the equivalent in roughly 50 lines.</p>
<p>First, install the dependencies:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">pip install "weaviate-client&gt;=4.21" PyMuPDF</span><br></span></code></pre></div></div>
<p>Then, render each PDF page to a 2000-pixel PNG and store it as a BLOB in a collection vectorized with <code>multi2multivec-weaviate</code>:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> os</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> base64 </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> b64encode</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> pathlib </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Path</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> fitz  </span><span class="token comment" style="color:rgb(98, 114, 164)"># PyMuPDF</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> connect_to_weaviate_cloud</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">config </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Property</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">page_to_b64</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> long_edge</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">int</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">2000</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">-</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">str</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    scale </span><span class="token operator">=</span><span class="token plain"> long_edge </span><span class="token operator">/</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">max</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">width</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rect</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">height</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    pix </span><span class="token operator">=</span><span class="token plain"> page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">get_pixmap</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">matrix</span><span class="token operator">=</span><span class="token plain">fitz</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Matrix</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">scale</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> scale</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> b64encode</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">pix</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">tobytes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">output</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"png"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">decode</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client </span><span class="token operator">=</span><span class="token plain"> connect_to_weaviate_cloud</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    os</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">environ</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"WEAVIATE_URL"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    auth_credentials</span><span class="token operator">=</span><span class="token plain">os</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">environ</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"WEAVIATE_API_KEY"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">not</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">exists</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"PDF"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"PDF"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"pdf_name"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"page_number"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">INT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"page_image"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">BLOB</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        vector_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">MultiVectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">multi2vec_weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            image_field</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"page_image"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">col </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"PDF"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> pdf_path </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> Path</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"pdfs"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">glob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"*.pdf"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">with</span><span class="token plain"> col</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">fixed_size</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">batch_size</span><span class="token operator">=</span><span class="token number">2</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> fitz</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">open</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">pdf_path</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> doc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> i</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> page </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">enumerate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">doc</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> start</span><span class="token operator">=</span><span class="token number">1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">add_object</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token string" style="color:rgb(255, 121, 198)">"pdf_name"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> pdf_path</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">name</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token string" style="color:rgb(255, 121, 198)">"page_number"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> i</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token string" style="color:rgb(255, 121, 198)">"page_image"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> page_to_b64</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">page</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>A few notes on the above:</p>
<ul>
<li class=""><strong>The Python call <code>MultiVectors.multi2vec_weaviate(image_field="page_image")</code> configures the <code>multi2multivec-weaviate</code> module.</strong> This is the same vectorizer used by the Console import UI.</li>
<li class=""><strong><code>PyMuPDF</code> does the rasterization.</strong> The <code>2000</code> pixel long-edge target is a sensible default; smaller targets saves time while larger gives the model more detail. We haven't found a strong case for going below 1500 or above 2500.</li>
<li class=""><strong><code>batch_size=2</code> is intentional.</strong> Each object carries a multi-megabyte image, so small batches keep the gRPC payload sane.</li>
</ul>
<p>Query the created collection to return ranked pages:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> MetadataQuery</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">res </span><span class="token operator">=</span><span class="token plain"> col</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">near_text</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    query</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"how did automotive revenue change over time"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    limit</span><span class="token operator">=</span><span class="token number">5</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return_properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"pdf_name"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"page_number"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return_metadata</span><span class="token operator">=</span><span class="token plain">MetadataQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">distance</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> o </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> res</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">objects</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">o</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">metadata</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">distance</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> o</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">properties</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>On the NVIDIA corpus, this returns the Q2 FY26 <em>Automotive</em> page as result #1: the same five-quarter bar chart you saw above, retrieved by an end-to-end pipeline that contains zero OCR.</p>
<p>The same Query Agent you saw in the Console is also available from Python. Pass it the collections to reason over, then <code>ask()</code>:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">agents</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> QueryAgent</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate_agents</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> QueryAgentCollectionConfig</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">agent </span><span class="token operator">=</span><span class="token plain"> QueryAgent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    client</span><span class="token operator">=</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    collections</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        QueryAgentCollectionConfig</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"PDF"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">response </span><span class="token operator">=</span><span class="token plain"> agent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ask</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"How did automotive revenue change across FY26 quarters? What's driving it?"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">response</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">display</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p><code>response.display()</code> renders the same synthesised answer plus page-image citations you saw in the Console.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="so-is-this-the-silver-bullet-for-pdfs">So is this the silver bullet for PDFs?<a href="https://weaviate.io/blog/charts-tables-pdfs#so-is-this-the-silver-bullet-for-pdfs" class="hash-link" aria-label="Direct link to So is this the silver bullet for PDFs?" title="Direct link to So is this the silver bullet for PDFs?" translate="no">​</a></h2>
<p>Of course not. As always in Engineering, there are trade-offs:</p>
<ul>
<li class=""><strong>Many vectors per object/page.</strong> Late-interaction multi-vector models produce many vectors per page. You can partially offset this with compression techniques, such as <a class="" href="https://weaviate.io/blog/muvera">Muvera</a>, which are natively supported in Weaviate. This helps, but also introduces a compression/accuracy trade-off. For a corpus that is dominated by large amounts of plain text (think legal contracts, transcripts, or log files), a text embedding model will still be cheaper and just as accurate.</li>
<li class=""><strong>Page-level retrieval is coarse.</strong> If your answer lives in one paragraph buried in a dense contract, returning a whole page may be more context than you want. In practice, we see this typically mitigated in the agent layer (e.g. Weaviate's Query agent), where the relevant paragraph can be identified without requiring a significant number of tokens.</li>
<li class=""><strong>The model has to understand your charts.</strong> It generalises well from the public corpora it was trained on, but if you have very domain-specific visual conventions (think highly stylised internal templates), you should validate retrieval quality on it first.</li>
</ul>
<p>So when does this approach with late-interaction multi-vector models win? Mostly in PDF-heavy domains that contain assets such as quarterly slide decks, due-diligence packets, scientific figures, and technical drawings, etc. For text-dominated corpora, a text pipeline is most likely cheaper and sufficiently performant.</p>
<p>For further optimization, you might consider using a hybrid approach, where you identify pages with charts to implement as multi-vectors and the remaining corpus as text, and then use an RRF-style approach to merge results at query time.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://weaviate.io/blog/charts-tables-pdfs#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Let's wrap up with the key takeaways:</p>
<ul>
<li class=""><strong>Charts and tables are not problems to be solved by better OCR.</strong> They are <em>primary information</em> that gets destroyed in extraction. If your pipeline only indexes text, valuable information from charts is already lost before you started embedding.</li>
<li class=""><strong>Late-interaction multi-vector models let you skip extraction entirely.</strong> Render the page, embed the image, and ask questions about what the image means. The model retrieves pages by what they look like --- charts, tables, layout, and all.</li>
<li class=""><strong>On Weaviate Cloud, ingestion is drag-and-drop.</strong> Point the Query Agent at the resulting collection, ask a question, and get an answer with proper images as citation.</li>
<li class=""><strong>Turn the same primitive into deployable code.</strong> <code>MultiVectors.multi2vec_weaviate(image_field="page_image")</code> is the entire vectorizer config. The rest is rasterising pages with PyMuPDF and a small <code>batch.add_object</code> loop.</li>
</ul>
<p>If you have been working around chart-heavy PDFs because the indexing pipeline made them too painful to deal with, this is worth a try. The kind of files you used to skip, because they were <em>"mostly charts"</em>, are exactly what this approach is built for.</p>
<p>Spin up a <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a> cluster, upload your PDFs, and start asking questions today.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/charts-tables-pdfs#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=charts-tables-pdfs&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Etienne Dilocker</name>
            <uri>https://github.com/etiennedi</uri>
        </author>
        <author>
            <name>Augustas Skaburskas</name>
            <uri>https://www.linkedin.com/in/augustas-skaburskas/</uri>
        </author>
        <category label="how-to" term="how-to"/>
        <category label="search" term="search"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Weaviate 1.39 Release]]></title>
        <id>https://weaviate.io/blog/weaviate-1-39-release</id>
        <link href="https://weaviate.io/blog/weaviate-1-39-release"/>
        <updated>2026-08-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Weaviate 1.39 promotes the Boost API and MMR diversity selection to GA, previews 4-bit Rotational Quantization, and ships an experimental Search REST API.]]></summary>
        <content type="html"><![CDATA[<p>Weaviate <code>v1.39</code> is now available open-source and on <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a>.</p>
<p>Two search features reach <strong>general availability</strong> in this release: the <strong>Boost API</strong> for query-time rescoring, and <strong>Maximal Marginal Relevance (MMR) diversity selection</strong>, which works on hybrid search as well as vector search. Two more are new: <strong>4-bit Rotational Quantization</strong> as a preview, and an experimental <strong>Search REST API</strong>. This post also covers <strong>gRPC-Web</strong>, which shipped quietly in the 1.38 line, and the <strong>HNSW snapshot</strong> rework, which cuts commit-log disk usage and speeds up startup.</p>
<p>Here are the release highlights!</p>
<p><img decoding="async" loading="lazy" alt="Weaviate 1.39 is released" src="https://weaviate.io/assets/images/hero-a412819ae697ef06bc71aff11e9f7f87.png" width="1200" height="630" class="img_ev3q"></p>
<ul>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-39-release#boost-api---general-availability" class="">Boost API - General Availability</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-39-release#mmr-diversity-selection---general-availability" class="">MMR Diversity Selection - General Availability</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-39-release#4-bit-rotational-quantization-preview" class="">4-bit Rotational Quantization (Preview)</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-39-release#search-rest-api-experimental" class="">Search REST API (Experimental)</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-39-release#grpc-web" class="">gRPC-Web</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-39-release#hnsw-snapshots-automatic---general-availability" class="">HNSW Snapshots, Automatic - General Availability</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-39-release#performance-improvements-and-fixes" class="">Performance Improvements and Fixes</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-39-release#community-contributions" class="">Community Contributions</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-39-release#summary" class="">Summary</a></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="boost-api---general-availability">Boost API - General Availability<a href="https://weaviate.io/blog/weaviate-1-39-release#boost-api---general-availability" class="hash-link" aria-label="Direct link to Boost API - General Availability" title="Direct link to Boost API - General Availability" translate="no">​</a></h2>
<p>The <a class="" href="https://weaviate.io/blog/weaviate-1-38-release#boost-api-preview">Boost API</a>, introduced as a preview in <code>v1.38</code>, is now <strong>generally available</strong>.</p>
<p>Boost is a query-time rescorer. After the primary search fetches its candidates, Weaviate scores each one against your boost conditions and re-sorts the list. Unlike a filter, it never removes anything: an object that matches nothing is demoted, not dropped. That is the difference between "only show me in-stock products" and "prefer in-stock products, but still show me the perfect match that is out of stock".</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works">How it works<a href="https://weaviate.io/blog/weaviate-1-39-release#how-it-works" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h3>
<p>A boost holds between one and twenty conditions, and there are four kinds:</p>
<ul>
<li class=""><strong><code>filter</code></strong> promotes results that satisfy a filter</li>
<li class=""><strong><code>property_value</code></strong> ranks by a numeric property's value</li>
<li class=""><strong><code>time_decay</code></strong> favors objects near a point in time</li>
<li class=""><strong><code>numeric_decay</code></strong> favors objects near a target number</li>
</ul>
<p>Two weights control the result. The outer <code>weight</code> (default <code>0.5</code>) mixes the boost score into the original relevance score: <code>(1 - weight) * primary + weight * boost</code>. Each condition then carries its own <code>weight</code> (default <code>1.0</code>). Make that one <strong>negative</strong> if you want the condition to demote instead of promote.</p>
<p>A third setting, <code>depth</code> (default <code>100</code>, capped by <code>QUERY_MAXIMUM_RESULTS</code>), is how many candidates the primary search fetches before the re-sort. An operator can move that default for the whole cluster with <code>QUERY_BOOST_DEFAULT_DEPTH</code>.</p>
<p>Here is what that does to a real result page. The same query runs twice over a small product catalog: once plain, once with a boost that prefers products that are in stock and recently released:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> datetime </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> timedelta</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Boost</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Filter</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">prefer_in_stock_and_recent </span><span class="token operator">=</span><span class="token plain"> Boost</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">blend</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Boost</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">Filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">by_property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"in_stock"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">equal</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> weight</span><span class="token operator">=</span><span class="token number">2.0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Boost</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">time_decay</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"released"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> scale</span><span class="token operator">=</span><span class="token plain">timedelta</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">days</span><span class="token operator">=</span><span class="token number">30</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    weight</span><span class="token operator">=</span><span class="token number">0.3</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain">   </span><span class="token comment" style="color:rgb(98, 114, 164)"># 30% boost, 70% original relevance</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    depth</span><span class="token operator">=</span><span class="token number">200</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)"># re-score the top 200 candidates</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> label</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> boost </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"plain hybrid"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token boolean">None</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"with boost"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> prefer_in_stock_and_recent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    response </span><span class="token operator">=</span><span class="token plain"> collection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">hybrid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">query</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"wireless headphones"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> limit</span><span class="token operator">=</span><span class="token number">4</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> boost</span><span class="token operator">=</span><span class="token plain">boost</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">label</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> obj </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">objects</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"  "</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> obj</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">properties</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"title"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"| in stock:"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> obj</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">properties</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"in_stock"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">plain hybrid</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Kestrel Wireless Headphones | in stock: True</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Meridian Wireless Headphones | in stock: False</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Aurora Wireless Headphones | in stock: False</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Nimbus Wireless Headphones | in stock: True</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">with boost</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Kestrel Wireless Headphones | in stock: True</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Nimbus Wireless Headphones | in stock: True</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Wireless Earbuds Pro | in stock: True</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Meridian Wireless Headphones | in stock: False</span><br></span></code></pre></div></div>
<p>Nimbus is in stock and twelve days old, so it climbs from fourth to second. The earbuds take third for the same reason, even though the text match is weaker. The two out-of-stock listings lose ground: Meridian slides to fourth, and Aurora drops off the page. Neither one was removed from the result set. Kestrel, the best keyword and vector match, still holds first place. A <code>weight</code> of <code>0.3</code> leaves 70% of the score with the search itself. Raise it toward <code>1.0</code> and stock and freshness take over the ordering. Lower it toward <code>0.0</code> and you get the plain result back.</p>
<p>Boost is available on <code>hybrid</code>, <code>bm25</code>, <code>near_text</code>, <code>near_vector</code>, <code>near_object</code>, <code>near_media</code>, and <code>near_image</code>, in both the <code>.query.*</code> and <code>.generate.*</code> namespaces. It is not available on <code>fetch_objects</code>, which has no relevance score to blend with.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Boost runs before a reranker</div><div class="admonitionContent_BuS1"><p>If you combine <code>boost=</code> with <code>rerank=</code>, the <a href="https://docs.weaviate.io/weaviate/search/rerank" target="_blank" rel="noopener noreferrer" class="">reranker</a> runs afterwards and re-sorts the boosted page, so it has the last word. Use one or the other unless you want that layering.</p></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/search/boost" target="_blank" rel="noopener noreferrer" class="">How-to: Search - Boost results</a></li>
<li class=""><a href="https://docs.weaviate.io/weaviate/search/boost#blending-and-weights" target="_blank" rel="noopener noreferrer" class="">How-to: Search - Blending and weights</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mmr-diversity-selection---general-availability">MMR Diversity Selection - General Availability<a href="https://weaviate.io/blog/weaviate-1-39-release#mmr-diversity-selection---general-availability" class="hash-link" aria-label="Direct link to MMR Diversity Selection - General Availability" title="Direct link to MMR Diversity Selection - General Availability" translate="no">​</a></h2>
<p><a class="" href="https://weaviate.io/blog/weaviate-1-37-release#diversity-search-with-mmr-preview">MMR diversity selection</a>, a preview since <code>v1.37</code>, is now <strong>generally available</strong>. It works on hybrid search alongside every <code>near_*</code> search. Hybrid support is not new in <code>v1.39</code>: it landed in <code>v1.38.6</code>, so if you are on a recent 1.38 patch you already have it. What <code>v1.39</code> changes is the maturity label.</p>
<p>MMR picks results one at a time. At each step it weighs two things: how well a candidate matches the query, and how different it is from the results already picked. You end up with a first page that covers the topic instead of showing the same passage nine times. That helps most in <a class="" href="https://weaviate.io/blog/hybrid-search-explained">hybrid search</a>. The keyword half and the vector half of a hybrid query tend to agree on the same cluster of near-identical chunks, so their merged top 10 is often the most repetitive list in your system.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works-1">How it works<a href="https://weaviate.io/blog/weaviate-1-39-release#how-it-works-1" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h3>
<p>MMR runs near the end of the query pipeline, after the two halves are merged and before the page is cut. A reranker, if you use one, runs after MMR:</p>
<!-- -->
<p>Two values configure it, and both are easy to get backwards.</p>
<p><strong><code>balance</code></strong> trades relevance against diversity. It takes a value from <code>0.0</code> to <code>1.0</code>, and anything outside that range is rejected with <code>MMR balance must be between 0 and 1</code>. At <code>1.0</code> you get <strong>pure relevance</strong>, which is the same order you would get without MMR. At <code>0.0</code> you get <strong>pure diversity</strong>. So <strong>lower means more diverse</strong>. The default is <code>0.0</code>, not <code>0.5</code>. Leave <code>balance</code> out and you get the most aggressive setting there is, so always pass it explicitly.</p>
<p><strong><code>limit</code></strong> on the MMR selection is your <strong>page size</strong>, the number of results you get back. MMR picks those results out of a candidate pool, and the pool is the query's own <code>limit</code>. The MMR limit must be at least 1 and no larger than the query limit.</p>
<p>Here is the same query at three settings. The collection holds documentation chunks, and four of them say roughly the same thing about carbon pricing:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Diversity</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> balance </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">1.0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">0.3</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">0.0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    response </span><span class="token operator">=</span><span class="token plain"> collection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">hybrid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        query</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"carbon pricing"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        limit</span><span class="token operator">=</span><span class="token number">8</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain">                                                      </span><span class="token comment" style="color:rgb(98, 114, 164)"># candidate pool</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        diversity_selection</span><span class="token operator">=</span><span class="token plain">Diversity</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">mmr</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">limit</span><span class="token operator">=</span><span class="token number">4</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> balance</span><span class="token operator">=</span><span class="token plain">balance</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain">  </span><span class="token comment" style="color:rgb(98, 114, 164)"># 4 returned</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"balance=</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">balance</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> obj </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">objects</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"  "</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> obj</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">properties</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"title"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">balance=1.0</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Carbon tax versus cap and trade</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Carbon pricing basics</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Carbon pricing FAQ</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   What is a carbon price?</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">balance=0.3</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Carbon tax versus cap and trade</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Carbon pricing FAQ</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Carbon pricing basics</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Adaptation funding for coastal cities</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">balance=0.0</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Carbon tax versus cap and trade</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Methane rules for oil and gas</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Adaptation funding for coastal cities</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">   Renewable subsidies and grid buildout</span><br></span></code></pre></div></div>
<p>At <code>1.0</code> the page is four ways of saying the same thing, which is the page you get without MMR. At <code>0.3</code> one of the duplicates gives up its slot to a chunk on adaptation funding. At <code>0.0</code> relevance stops counting after the first pick, and a carbon-pricing query comes back with methane rules and grid buildout. That last one is what you get if you leave <code>balance</code> out.</p>
<p>You need Python client <strong>4.23.0</strong> or newer. That is the release where <code>diversity_selection</code> arrives on <code>collection.query.hybrid</code> and <code>collection.generate.hybrid</code>. MMR is not available on <code>bm25</code>, which has no vectors to measure distance between, and it does not work on multi-vector collections.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/search/similarity#diversity-selection-mmr" target="_blank" rel="noopener noreferrer" class="">How-to: Search - Diversity selection (MMR)</a></li>
<li class=""><a href="https://docs.weaviate.io/weaviate/search/hybrid#diversity-selection-mmr" target="_blank" rel="noopener noreferrer" class="">How-to: Hybrid search - Diversity selection (MMR)</a></li>
<li class=""><a class="" href="https://weaviate.io/blog/hybrid-search-explained">Blog: Hybrid search explained</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-bit-rotational-quantization-preview">4-bit Rotational Quantization (Preview)<a href="https://weaviate.io/blog/weaviate-1-39-release#4-bit-rotational-quantization-preview" class="hash-link" aria-label="Direct link to 4-bit Rotational Quantization (Preview)" title="Direct link to 4-bit Rotational Quantization (Preview)" translate="no">​</a></h2>
<p><a href="https://docs.weaviate.io/weaviate/concepts/vector-quantization#rotational-quantization" target="_blank" rel="noopener noreferrer" class="">Rotational quantization (RQ)</a> shrinks vectors in two steps. First it rotates the vector so the values spread evenly across the dimensions. Then it stores each dimension as a small integer code instead of a 32-bit float. Weaviate already ships 8-bit and 1-bit RQ. <code>v1.39</code> adds a <strong>4-bit</strong> width as a preview.</p>
<p>Four bits is half a byte, so two dimensions pack into one byte. At 1536 dimensions that is a 16-byte header plus 768 bytes of codes: <strong>784 bytes per vector</strong>, against 6144 bytes for raw <code>float32</code>. That is <strong>7.84x</strong> smaller, not a round "8x", because the header stays.</p>
<p>The general form is <code>16 + ceil(outputDim / 2)</code> bytes, where <code>outputDim = 64 * ceil(inputDim / 64)</code>. The rotation rounds your dimension count up to the next multiple of 64. At 1536 that round-up is free, because 1536 is 24 x 64. At 1000 dimensions it is not: you pay for 1024.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works-2">How it works<a href="https://weaviate.io/blog/weaviate-1-39-release#how-it-works-2" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h3>
<p>There is no preview flag to unlock. It is a plain schema value, <code>rq.bits = 4</code>, on a vector index:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">config </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Configure</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string" style="color:rgb(255, 121, 198)">"Doc"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    vector_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Vectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text2vec_weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"default"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        source_properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"title"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"body"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        vector_index_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">VectorIndex</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">hnsw</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            quantizer</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">VectorIndex</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Quantizer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rq</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                bits</span><span class="token operator">=</span><span class="token number">4</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                rescore_limit</span><span class="token operator">=</span><span class="token number">20</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p><code>bits</code> is fixed the moment RQ is first enabled on a vector, and you cannot change it later. There is no migration from 8-bit codes to 4-bit codes, so pick the width when you create the collection.</p>
<p>If you would rather not set it per collection, an operator can make it the cluster-wide default for new vector indexes with <code>DEFAULT_QUANTIZATION=rq-4</code>. A new HNSW index then comes up with <code>bits: 4</code> and a <code>rescoreLimit</code> of <code>20</code>. Flat indexes are left alone.</p>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>4-bit is HNSW-only</div><div class="admonitionContent_BuS1"><p>The flat index still rejects it with <code>RQ bits must be either 1 or 8</code>, and that applies to the flat side of a dynamic index too. Use <code>bits: 4</code> on an HNSW index.</p></div></div>
<p>Like the other RQ widths, 4-bit works with the <code>cosine</code>, <code>dot</code>, and <code>l2-squared</code> distance metrics.</p>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Preview</div><div class="admonitionContent_BuS1"><p>The 4-bit width is a <strong>preview</strong> feature. Its behavior and defaults may change in future releases.</p></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/concepts/vector-quantization#rotational-quantization" target="_blank" rel="noopener noreferrer" class="">Concepts: Vector quantization - Rotational quantization</a></li>
<li class=""><a href="https://docs.weaviate.io/weaviate/concepts/vector-quantization#rescoring" target="_blank" rel="noopener noreferrer" class="">Concepts: Vector quantization - Rescoring</a></li>
<li class=""><a href="https://docs.weaviate.io/weaviate/config-refs/indexing/vector-index" target="_blank" rel="noopener noreferrer" class="">Config references: Vector index parameters</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="search-rest-api-experimental">Search REST API (Experimental)<a href="https://weaviate.io/blog/weaviate-1-39-release#search-rest-api-experimental" class="hash-link" aria-label="Direct link to Search REST API (Experimental)" title="Direct link to Search REST API (Experimental)" translate="no">​</a></h2>
<p>Weaviate has two search APIs today. gRPC is fast, but it wants a generated client and HTTP/2. GraphQL means building a query string by hand and digging metadata out of <code>_additional</code>. Neither is pleasant from a shell script, a Lambda, an edge worker, an API gateway, or a language with no Weaviate client.</p>
<p><code>v1.39</code> adds an <strong>experimental Search REST API</strong>. You post JSON over plain HTTP/1.1 and get JSON back, and the endpoints are described by the OpenAPI spec like the rest of the REST API. That also suits LLM tool calling, where a model needs a documented HTTP endpoint rather than a client library.</p>
<p><code>v1.39.0</code> shipped one endpoint, <code>POST /v1/search/{collection}/near-text</code>. The <code>v1.39.1</code> patch added three more search endpoints and a matching aggregate endpoint, so on <code>1.39.1</code> or newer you get <a href="https://docs.weaviate.io/weaviate/api/rest#tag/search" target="_blank" rel="noopener noreferrer" class="">all five</a>:</p>
<ul>
<li class=""><code>POST /v1/search/{collection}/near-text</code></li>
<li class=""><code>POST /v1/search/{collection}/bm25</code></li>
<li class=""><code>POST /v1/search/{collection}/hybrid</code></li>
<li class=""><code>POST /v1/search/{collection}/near-object</code></li>
<li class=""><code>POST /v1/aggregate/{collection}</code></li>
</ul>
<p>The examples below use <code>near-text</code>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works-3">How it works<a href="https://weaviate.io/blog/weaviate-1-39-release#how-it-works-3" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h3>
<p>The endpoints are <strong>off by default</strong>. Turn them on per node with <a href="https://docs.weaviate.io/deploy/configuration/env-vars#EXPERIMENTAL_REST_SEARCH_ENABLED" target="_blank" rel="noopener noreferrer" class=""><code>EXPERIMENTAL_REST_SEARCH_ENABLED</code></a>:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token key atrule">services</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> cr.weaviate.io/semitechnologies/weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">1.39.1</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">environment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token key atrule">EXPERIMENTAL_REST_SEARCH_ENABLED</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'true'</span><br></span></code></pre></div></div>
<p>Accepted truthy values are <code>on</code>, <code>enabled</code>, <code>1</code>, and <code>true</code>. One switch covers every endpoint in the set. When the feature is off, the routes are still there. They answer <code>422</code> with a message naming the variable to set, instead of a confusing <code>404</code>.</p>
<p>The request body is all camelCase. For <code>near-text</code>, <code>query</code> is a <strong>required array of strings</strong>, and each string is a piece of text to search for. Send one string for an ordinary search. Send several and Weaviate averages them into a single search vector. You can also send <code>certainty</code> or <code>distance</code> (not both), <code>targetVector</code>, <code>where</code>, <code>limit</code>, <code>offset</code>, <code>autoLimit</code>, <code>returnProperties</code>, <code>returnMetadata</code>, <code>tenant</code>, and <code>consistencyLevel</code>.</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">curl -s -X POST http://localhost:8080/v1/search/Movie/near-text \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H 'Content-Type: application/json' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -d '{"query":["spaceship galaxy"],"limit":3,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">       "returnProperties":["title","hasAuthor.name"],</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">       "returnMetadata":["distance"]}'</span><br></span></code></pre></div></div>
<p>The response is <code>{results, tookMs}</code>. Every hit comes back in the same flat shape, <code>{id, properties, references, metadata}</code>:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"results"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"id"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"2aeb3309-33e7-4a8d-a8e2-6413b53890d8"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"properties"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token property">"title"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"spaceship galaxy adventure"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"references"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token property">"hasAuthor"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token property">"name"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"famous writer"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"metadata"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token property">"distance"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">0.07182336</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"tookMs"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token number">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p><code>references</code> is left out when your query does not read across a reference, and <code>metadata</code> is left out when you asked for nothing beyond the id. Vectors are never returned.</p>
<p>On errors you get the standard <code>{"error": [{"message": "..."}]}</code> body.</p>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Experimental means the shape can still change</div><div class="admonitionContent_BuS1"><p>This API is off by default, and its request and response shape is not frozen. Reference selection is the most likely part to change. In <code>v1.39</code> you ask for a referenced property by writing it with a dot inside <code>returnProperties</code>, one level deep, such as <code>"hasAuthor.name"</code>. That form is being replaced, so expect to update anything you build on it today.</p></div></div>
<p>No official client wraps this endpoint yet. Every Weaviate client speaks gRPC for search, so <code>curl</code> or raw HTTP is how you reach it for now. Boost, MMR, reranking, generative search, and group-by are not available over REST.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/api/rest#tag/search" target="_blank" rel="noopener noreferrer" class="">References: RESTful API - Search endpoints</a></li>
<li class=""><a href="https://docs.weaviate.io/deploy/configuration/env-vars#EXPERIMENTAL_REST_SEARCH_ENABLED" target="_blank" rel="noopener noreferrer" class="">Environment variables: <code>EXPERIMENTAL_REST_SEARCH_ENABLED</code></a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="grpc-web">gRPC-Web<a href="https://weaviate.io/blog/weaviate-1-39-release#grpc-web" class="hash-link" aria-label="Direct link to gRPC-Web" title="Direct link to gRPC-Web" translate="no">​</a></h2>
<p>Browsers cannot speak plain gRPC, so front-end code has never been able to call Weaviate's gRPC API directly. <strong>gRPC-Web</strong> closes that gap by serving the same API over ordinary HTTP. It arrived in <code>v1.38.3</code> and has not been covered in a release post until now.</p>
<p>The interface lives under the <code>/v1/grpc-web/</code> path prefix on the <strong>same port as the REST API</strong> (default <code>8080</code>). It is not on the gRPC port and not on a port of its own, so there is no second port to open in a firewall or an ingress rule.</p>
<p>It is <strong>enabled by default</strong>. To turn it off, set the <a href="https://docs.weaviate.io/deploy/configuration/env-vars/runtime-config" target="_blank" rel="noopener noreferrer" class="">runtime-configuration</a> key <code>grpc_web_enabled</code> to <code>false</code>. The key is snake_case, and it has no environment-variable equivalent. The change takes effect without a restart. While the interface is off, a request to a <code>/v1/grpc-web/</code> path comes back as a plain <code>404</code>, the same as any other path Weaviate does not serve. The rest of the REST API is unaffected.</p>
<p>One caveat: the Weaviate client libraries all connect over plain gRPC today, so none of them uses this interface yet.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/api/grpc#grpc-web" target="_blank" rel="noopener noreferrer" class="">References: gRPC API - gRPC-Web</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="hnsw-snapshots-automatic---general-availability">HNSW Snapshots, Automatic - General Availability<a href="https://weaviate.io/blog/weaviate-1-39-release#hnsw-snapshots-automatic---general-availability" class="hash-link" aria-label="Direct link to HNSW Snapshots, Automatic - General Availability" title="Direct link to HNSW Snapshots, Automatic - General Availability" translate="no">​</a></h2>
<p>An HNSW index is rebuilt on startup by replaying its commit log, the append-only write-ahead log that records every change to the graph. A <em>snapshot</em> is a compacted image of that graph, so startup can load one file instead of replaying millions of records. Until now the snapshot was an optional cache: you scheduled it with a handful of environment variables, and the log it summarized stayed on disk forever. You paid for the same graph twice.</p>
<p>In <code>v1.39</code> snapshots are automatic and <strong>generally available</strong>. Weaviate writes and refreshes them in the background, and once a new snapshot is safely on disk it <strong>deletes every commit log that snapshot covers</strong>. What you get:</p>
<ul>
<li class=""><strong>Less disk.</strong> You keep the snapshot plus the writes made since it, instead of the snapshot plus the full history. On vector-heavy clusters that is most of the win.</li>
<li class=""><strong>Faster, steadier startup.</strong> Loading a snapshot takes about the same time on every restart. Replaying a log that only ever grows does not.</li>
<li class=""><strong>Nothing to tune.</strong> There are no snapshot environment variables and no schedule to set. Weaviate decides when to write the next one.</li>
</ul>
<p>Two things to know about the disk savings. The cleanup only runs on shards that are <strong>loaded</strong>, so an inactive tenant keeps its old files until the next time you use it. And disk usage goes <strong>up</strong> for a while during a snapshot, because Weaviate writes the new file before it deletes the old ones. Keep the headroom you have today.</p>
<p>Five settings that used to control snapshotting are now <strong>ignored</strong>. Weaviate still accepts them, and they will be removed in a future version:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">PERSISTENCE_HNSW_DISABLE_SNAPSHOTS</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">PERSISTENCE_HNSW_SNAPSHOT_INTERVAL_SECONDS</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">PERSISTENCE_HNSW_SNAPSHOT_ON_STARTUP</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">PERSISTENCE_HNSW_SNAPSHOT_MIN_DELTA_COMMITLOGS_NUMBER</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">PERSISTENCE_HNSW_SNAPSHOT_MIN_DELTA_COMMITLOGS_SIZE_PERCENTAGE</span><br></span></code></pre></div></div>
<p>Setting any of them logs a one-line warning at startup instead of failing, so an upgrade will not break on a stale config file. Delete them when it suits you. One HNSW persistence setting survives: <a href="https://docs.weaviate.io/deploy/configuration/env-vars#PERSISTENCE_HNSW_MAX_LOG_SIZE" target="_blank" rel="noopener noreferrer" class=""><code>PERSISTENCE_HNSW_MAX_LOG_SIZE</code></a> (default <code>500MiB</code>). It sets the write-ahead-log rotation size, not anything about snapshots, and it still applies.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/concepts/storage#hnsw-snapshots" target="_blank" rel="noopener noreferrer" class="">Concepts: Storage - HNSW snapshots</a></li>
<li class=""><a href="https://docs.weaviate.io/deploy/configuration/env-vars#PERSISTENCE_HNSW_MAX_LOG_SIZE" target="_blank" rel="noopener noreferrer" class="">Environment variables: <code>PERSISTENCE_HNSW_MAX_LOG_SIZE</code></a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="performance-improvements-and-fixes">Performance Improvements and Fixes<a href="https://weaviate.io/blog/weaviate-1-39-release#performance-improvements-and-fixes" class="hash-link" aria-label="Direct link to Performance Improvements and Fixes" title="Direct link to Performance Improvements and Fixes" translate="no">​</a></h2>
<p>Beyond the headline features, <code>v1.39</code> ships a long list of improvements. A few worth calling out:</p>
<ul>
<li class=""><strong>Faster keyword search:</strong> <code>bm25</code> queries, and the keyword half of <code>hybrid</code>, come back sooner after a round of work on the scoring path.</li>
<li class=""><strong>Cross-property keyword <code>AND</code>:</strong> a new <code>AndCross</code> search operator asks for every query term to appear somewhere on the object, rather than all of them inside one property. It shipped in the 1.38 line, and it is opt-in, so plain <code>And</code> keeps the behavior you have today.</li>
<li class=""><strong>Cheaper async replication:</strong> background repair does less redundant work on clusters with many tenants. Fixes stop deleted objects from coming back during a first scan, stop a repair from overwriting a newer local write, and stop a tenant shutdown from leaking memory.</li>
<li class=""><strong>Leaner HFresh:</strong> the HFresh vector index uses less memory and writes to disk less often.</li>
<li class=""><strong>More reliable backups:</strong> listing a backup on Azure no longer scans every object, a restore no longer forces lazy-loaded shards to load, and you can now set how many files an incremental backup deduplicates.</li>
<li class=""><strong>Safer replica movement:</strong> moving a replica between nodes now uses hard links, so it no longer pauses compaction. Schema changes that would clash with a move in flight are rejected, and two copy operations on the same shard no longer trip over each other.</li>
<li class=""><strong>Latency metrics below a millisecond:</strong> the HTTP and gRPC request-duration histograms now have buckets down to 100µs, so fast queries no longer all land in one bucket.</li>
<li class=""><strong>Batch delete returns 422:</strong> a batch delete with missing match fields now answers <code>422 Unprocessable Entity</code> instead of <code>500</code>.</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://github.com/weaviate/weaviate/releases/tag/v1.39.0" target="_blank" rel="noopener noreferrer" class="">Weaviate 1.39: GitHub Release Notes</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="community-contributions">Community Contributions<a href="https://weaviate.io/blog/weaviate-1-39-release#community-contributions" class="hash-link" aria-label="Direct link to Community Contributions" title="Direct link to Community Contributions" translate="no">​</a></h2>
<p>Weaviate is open source, and this release includes work from five first-time contributors. Thank you to:</p>
<ul>
<li class=""><a href="https://github.com/hashkanna" target="_blank" rel="noopener noreferrer" class="">@hashkanna</a>: location configuration for the <code>text2vec-google</code> module (<a href="https://github.com/weaviate/weaviate/pull/8418" target="_blank" rel="noopener noreferrer" class="">#8418</a>)</li>
<li class=""><a href="https://github.com/vjsai" target="_blank" rel="noopener noreferrer" class="">@vjsai</a>: rejecting a negative <code>desiredCount</code> in sharding configuration (<a href="https://github.com/weaviate/weaviate/pull/11824" target="_blank" rel="noopener noreferrer" class="">#11824</a>)</li>
<li class=""><a href="https://github.com/Joe-Weaviate" target="_blank" rel="noopener noreferrer" class="">@Joe-Weaviate</a>: using <code>automaxprocs</code> to set <code>GOMAXPROCS</code>, adding cgroup v2 support (<a href="https://github.com/weaviate/weaviate/pull/11918" target="_blank" rel="noopener noreferrer" class="">#11918</a>)</li>
<li class=""><a href="https://github.com/VihaanAgarwal" target="_blank" rel="noopener noreferrer" class="">@VihaanAgarwal</a>: a fix to the object write path on collections with named vectors (<a href="https://github.com/weaviate/weaviate/pull/11919" target="_blank" rel="noopener noreferrer" class="">#11919</a>)</li>
<li class=""><a href="https://github.com/apoorva-01" target="_blank" rel="noopener noreferrer" class="">@apoorva-01</a>: returning <code>422</code> for a batch delete with missing match fields (<a href="https://github.com/weaviate/weaviate/pull/12049" target="_blank" rel="noopener noreferrer" class="">#12049</a>)</li>
</ul>
<p>If you'd like to contribute, check out the <a href="https://docs.weaviate.io/contributor-guide/" target="_blank" rel="noopener noreferrer" class="">contributor guide</a> and the <a href="https://github.com/weaviate/weaviate/issues" target="_blank" rel="noopener noreferrer" class=""><code>good-first-issue</code></a> label on GitHub.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://weaviate.io/blog/weaviate-1-39-release#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<p>Weaviate <code>v1.39</code> promotes two search features to general availability, previews a third, and makes HNSW snapshots automatic.</p>
<p><strong>Key highlights:</strong></p>
<ul>
<li class=""><strong>Boost API (GA)</strong>: query-time rescoring that promotes or demotes results without dropping any, across hybrid, keyword, and vector searches</li>
<li class=""><strong>MMR Diversity Selection (GA)</strong>: diversity selection on hybrid and <code>near_*</code> searches, so page one covers the topic instead of repeating it</li>
<li class=""><strong>4-bit Rotational Quantization (Preview)</strong>: a third RQ width at 784 bytes per 1536-dimension vector, 7.84x smaller than raw <code>float32</code>, on HNSW indexes</li>
<li class=""><strong>Search REST API (Experimental)</strong>: JSON over plain HTTP/1.1, off by default. <code>near-text</code> in <code>v1.39.0</code>, plus <code>bm25</code>, <code>hybrid</code>, <code>near-object</code>, and an aggregate endpoint in <code>v1.39.1</code></li>
<li class=""><strong>gRPC-Web</strong>: the gRPC API reachable from a browser over ordinary HTTP, on the REST port, enabled by default since <code>v1.38.3</code></li>
<li class=""><strong>HNSW Snapshots, Automatic (GA)</strong>: less disk spent on commit logs, faster and steadier startup, five tuning knobs retired, and nothing left to schedule</li>
</ul>
<p><strong>Ready to get started?</strong></p>
<p>The release is available open-source on <a href="https://github.com/weaviate/weaviate/releases/tag/v1.39.0" target="_blank" rel="noopener noreferrer" class="">GitHub</a> and on <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a>, where you can spin up a cluster on the free tier.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>Not all features may be available on Weaviate Cloud. Preview and experimental features, and anything that needs specific environment configuration, may not be enabled on managed clusters, or may arrive there on a different schedule.</p></div></div>
<p>If you are upgrading a self-hosted cluster, check the <a href="https://docs.weaviate.io/deploy/migration#general-upgrade-instructions" target="_blank" rel="noopener noreferrer" class="">migration guide</a> for version-specific notes.</p>
<p>Thanks for reading, and happy vector searching!</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/weaviate-1-39-release#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=weaviate-1-39-release&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Ivan Despot</name>
            <uri>https://www.linkedin.com/in/ivan-g-despot/</uri>
        </author>
        <category label="release" term="release"/>
        <category label="engineering" term="engineering"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building Foundry Part 2: Where creative workflows break]]></title>
        <id>https://weaviate.io/blog/building-foundry-where-workflows-break</id>
        <link href="https://weaviate.io/blog/building-foundry-where-workflows-break"/>
        <updated>2026-08-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Part 2: Why folders, tags, and keyword search break down in real creative workflows and what retrieval needs to do instead.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="hero" src="https://weaviate.io/assets/images/hero-b49ceec72fc24ffc33651dad0b9254ab.jpg" width="1200" height="630" class="img_ev3q"></p>
<blockquote>
<p><strong>Building Foundry</strong><br>
<!-- -->A practical series on creative workflows, semantic search, and Weaviate.</p>
</blockquote>
<p>Read the previous post in the series: <a class="" href="https://weaviate.io/blog/building-foundry-ai-creative-workflows">Part 1: AI isn't replacing creativity, it's removing friction</a>.</p>
<p>Most creative teams already know they are losing time to search. What is less obvious is where the breakdown actually happens. It usually doesn’t begin with bad tools or careless teams. Instead, as projects scale, naming conventions drift, metadata quality drops, and the cost of keeping everything perfectly organized becomes higher than the cost of living with a little chaos. For a while, that tradeoff feels reasonable. Then retrieval starts to fail, and no one can find anything anymore.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-first-failure-folders">The first failure: folders<a href="https://weaviate.io/blog/building-foundry-where-workflows-break#the-first-failure-folders" class="hash-link" aria-label="Direct link to The first failure: folders" title="Direct link to The first failure: folders" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Creative workflows fail at retrieval" src="https://weaviate.io/assets/images/image-1-632a861d68500666556ee0ba3eca3fbf.jpg" width="1448" height="1086" class="img_ev3q"></p>
<p>Folder trees work best when projects are small, ownership is stable, and everyone agrees on the same mental model. Creative production rarely stays in that state for long.</p>
<p>In game development, one environment team might organize assets by biome, another by sprint, and another by engine-ready status. All three structures make sense locally. Across a two-year production, they become incompatible maps of the same work. In film production, footage often starts organized by shoot day, then gets reorganized by sequence in editorial, while VFX and color keep their own derivative structures. In design teams, client work, exploration files, and final exports often live in separate systems with weak links between them.</p>
<p>Folders still matter, but over time they describe where a file landed, not what that file is useful for.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-second-failure-tags">The second failure: tags<a href="https://weaviate.io/blog/building-foundry-where-workflows-break#the-second-failure-tags" class="hash-link" aria-label="Direct link to The second failure: tags" title="Direct link to The second failure: tags" translate="no">​</a></h2>
<p>Tagging is usually proposed as the cure for messy folders, and in controlled environments it can work well. The challenge is that consistent tagging is a process discipline, and process discipline is fragile under deadline pressure.</p>
<p>Animation teams shipping sequences on tight schedules do not stop to apply perfect descriptive tags to every versioned scene file. Music producers bouncing between sessions do not pause to classify each stem with reusable semantic labels. Designers preparing campaign variants for multiple channels rarely annotate every intermediate exploration with future retrieval in mind.</p>
<p>None of this reflects poor craft. It reflects incentives. Teams optimize for shipping what is needed now, not for a hypothetical retrieval request six months later. As a result, tag quality tends to be uneven: high for formal deliverables, sparse for working files, and inconsistent across individuals.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-third-failure-keyword-search">The third failure: keyword search<a href="https://weaviate.io/blog/building-foundry-where-workflows-break#the-third-failure-keyword-search" class="hash-link" aria-label="Direct link to The third failure: keyword search" title="Direct link to The third failure: keyword search" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Keyword vs Semantic" src="https://weaviate.io/assets/images/image-2-59e506ebefc4430cd43ddf9ee3ab186b.jpg" width="1448" height="1086" class="img_ev3q"></p>
<p>Keyword search is excellent when the query and the stored text use the same words. But creative work is full of vocabulary mismatch. A film editor might search for "quiet emotional close-up" while a clip is described internally as "CU actor B reaction alt take." A game artist may search "wet brutalist corridor" while files are named around level IDs and sprint numbers. A graphic designer searching for "playful geometric logo options" may be looking for a file titled <code>final_FINAL_logo_v7</code>, because the client came back half a dozen times with edits.</p>
<p>Creative work is messy, and file names rarely contain the descriptions we need to find them again.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="these-failures-compound-over-time">These failures compound over time<a href="https://weaviate.io/blog/building-foundry-where-workflows-break#these-failures-compound-over-time" class="hash-link" aria-label="Direct link to These failures compound over time" title="Direct link to These failures compound over time" translate="no">​</a></h2>
<p>Any one of these issues is manageable. Together, they create a compounding effect.</p>
<p>A project starts with a clean structure. Team members rotate. Vendors contribute assets using different conventions. Naming drift increases. Tagging discipline varies by deadline and role. Archive volume grows. Eventually the team has not one system but several partially overlapping systems. At that point, finding material becomes less about search and more about social memory: asking the person who might remember.</p>
<p>That approach does not scale. It also creates uneven access to institutional knowledge. Senior contributors become implicit search engines, and new team members spend longer rebuilding context that already exists in files they cannot easily discover.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-retrieval-needs-to-do-differently">What retrieval needs to do differently<a href="https://weaviate.io/blog/building-foundry-where-workflows-break#what-retrieval-needs-to-do-differently" class="hash-link" aria-label="Direct link to What retrieval needs to do differently" title="Direct link to What retrieval needs to do differently" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Workflow Diagram" src="https://weaviate.io/assets/images/image-3-16b4c12f8f28599732e09ea7c73d0c89.jpg" width="1448" height="1086" class="img_ev3q"></p>
<p>If we treat this as a retrieval problem rather than an organization problem, requirements change.</p>
<p>Retrieval has to work when naming is imperfect. It has to work when tags are incomplete. It has to work when the user can describe intent clearly but cannot reproduce the original wording used at creation time. It also has to preserve precision when exact constraints matter, such as project, date range, rights status, delivery format, or asset type.</p>
<p>That is why modern systems combine multiple signals:</p>
<ul>
<li class="">semantic similarity for meaning</li>
<li class="">keyword matching for exact terms</li>
<li class="">metadata filters for hard constraints</li>
</ul>
<p>This can be built using a two-phase path: ingestion first, retrieval second.</p>
<p>Ingestion is where assets are prepared for future search. Files are processed, embeddings are generated, and available metadata is attached. In creative pipelines, this can include project identifiers, file types, timestamps, contributor roles, rights or licensing fields, and any production-specific attributes you already track. The goal is to capture enough structure and enough semantic representation that future queries have multiple routes to the right result.</p>
<p>Retrieval is where those routes are combined. A user might search in natural language, then refine with metadata filters, then rely on hybrid ranking that blends semantic and keyword scores. Vector databases can store embeddings with metadata at scale, which means semantic and filtered search can run in one coherent flow.</p>
<p>Using Weaviate as an implementation example, we can ingest assets with embeddings and metadata, query with vector and keyword signals, then apply metadata constraints for production-safe results.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What’s next<a href="https://weaviate.io/blog/building-foundry-where-workflows-break#whats-next" class="hash-link" aria-label="Direct link to What’s next" title="Direct link to What’s next" translate="no">​</a></h2>
<p>Creative workflows do not break because teams are disorganized. They break because production systems are optimized for shipping, while media retrieval systems are often optimized for ideal data hygiene that real projects cannot maintain.</p>
<p>Building a vector-based retrieval system is the practical direction for teams that want less time lost to searching and less creative work stranded in archives.</p>
<p>In the next post, we’ll begin that implementation with the foundation: data ingestion. A read-only discovery pass will scan a messy creative archive and turn it into a structured manifest ready for metadata enrichment and vector embeddings. From there, we can ingest those records into Weaviate and add hybrid queries and metadata filtering.</p>
<hr>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/building-foundry-where-workflows-break#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=building-foundry-where-workflows-break&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Shan Blackwood</name>
            <uri>https://www.linkedin.com/in/shan-blackwood/</uri>
        </author>
        <author>
            <name>Svitlana Smolianova</name>
            <uri>https://linkedin.com/in/svitlana-sm</uri>
        </author>
        <author>
            <name>Victoria Slocum</name>
            <uri>https://www.linkedin.com/in/victorialslocum/</uri>
        </author>
        <category label="creative-ai" term="creative-ai"/>
        <category label="workflows" term="workflows"/>
        <category label="search" term="search"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Scaling Test-Time Compute in Search Mode]]></title>
        <id>https://weaviate.io/blog/search-mode-effort</id>
        <link href="https://weaviate.io/blog/search-mode-effort"/>
        <updated>2026-08-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Introducing medium, high, and ultrahigh effort tiers to the Query Agent's Search Mode.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="hero" src="https://weaviate.io/assets/images/hero-8237f87f091069c1c1123d1ef022c83a.png" width="1200" height="630" class="img_ev3q"></p>
<p>Scaling test-time compute has become one of the clearest successes of the foundation model era. Spend more compute on a problem at inference, get a better result. Retrieval is no exception. The new <code>effort</code> parameter in the Query Agent’s <a href="https://docs.weaviate.io/query-agent/guides/search_mode" target="_blank" rel="noopener noreferrer" class="">Search Mode</a> now lets you control this. On BRIGHT Biology, one of the hardest reasoning-intensive retrieval benchmarks, ultrahigh effort Search Mode lifts nDCG@10 to 57.5 compared to 13.0 with Hybrid Search alone.</p>
<p>Different applications sit at different points on the accuracy / latency tradeoff curve. Available in <code>weaviate-agents 1.8.0</code> and <code>agents-typescript-client 1.7.0</code>, <code>effort</code> lets you choose per request how much work the Query Agent invests in each search.</p>
<!-- -->
<div class="theme-tabs-container tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">Python</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">JS/TS</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">agents</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> QueryAgent</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">qa </span><span class="token operator">=</span><span class="token plain"> QueryAgent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  client</span><span class="token operator">=</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  collections</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"IRPAPERS"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">response </span><span class="token operator">=</span><span class="token plain"> qa</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">search</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token string" style="color:rgb(255, 121, 198)">"What are Listwise Rerankers?"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  effort</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"ultrahigh"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><div class="language-typescript codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-typescript codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> QueryAgent </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"weaviate-agents"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> qa </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">new</span><span class="token plain"> </span><span class="token class-name">QueryAgent</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  collections</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"IRPAPERS"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">const</span><span class="token plain"> response </span><span class="token operator">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">await</span><span class="token plain"> qa</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token function" style="color:rgb(80, 250, 123)">search</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"What are Setwise Rerankers?"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  effort</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"ultrahigh"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">;</span><br></span></code></pre></div></div></div></div></div>
<p>Search Mode’s three <code>effort</code> tiers: <code>medium</code>, <code>high</code>, and <code>ultrahigh</code> scale computation at the two stages where Search Mode does its work: query writing and reranking. At higher effort, the agent thinks longer about how to decompose queries and reranks results more thoroughly. At lower effort, it trades some of that depth for speed and cost. Turn it up when the answer matters, and turn it down when latency does!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="benchmarks">Benchmarks<a href="https://weaviate.io/blog/search-mode-effort#benchmarks" class="hash-link" aria-label="Direct link to Benchmarks" title="Direct link to Benchmarks" translate="no">​</a></h2>
<p>The following table compares our <code>medium</code>, <code>high</code>, and <code>ultrahigh</code> effort tiers in Search Mode against Weaviate’s Hybrid Search across 8 benchmarks: 5 subsets from <a href="https://arxiv.org/abs/2407.12883" target="_blank" rel="noopener noreferrer" class="">BRIGHT</a>, <a href="https://arxiv.org/abs/2602.17687" target="_blank" rel="noopener noreferrer" class="">IRPAPERS</a>, <a href="https://arxiv.org/abs/2505.08643" target="_blank" rel="noopener noreferrer" class="">WixQA</a>, and a subset from <a href="https://arxiv.org/pdf/2605.06235" target="_blank" rel="noopener noreferrer" class="">OBLIQ-Bench</a>. We chose these benchmarks because they illustrate reasoning-intensive and domain-specific retrieval problems.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="methodology">Methodology<a href="https://weaviate.io/blog/search-mode-effort#methodology" class="hash-link" aria-label="Direct link to Methodology" title="Direct link to Methodology" translate="no">​</a></h3>
<p>As in our first Search Mode Benchmarking blog, we compare against Weaviate's Hybrid Search, combining BM25 with vector search over Snowflake Arctic 2.0 embeddings, fused with Reciprocal Rank Fusion (RRF). We then run Search Mode at each of the three effort tiers on the same collections. To account for the stochasticity of the models used in Search Mode, every Search Mode configuration is run for 3 trials, and we report the mean and standard deviation across trials. Hybrid Search is nearly deterministic given a fixed collection, so we report a single run.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="metrics-glossary">Metrics Glossary<a href="https://weaviate.io/blog/search-mode-effort#metrics-glossary" class="hash-link" aria-label="Direct link to Metrics Glossary" title="Direct link to Metrics Glossary" translate="no">​</a></h4>
<ul>
<li class=""><strong>Gold Document</strong>: In IR benchmarks, the "gold document" is the labeled relevant document, or documents, for a given query.</li>
<li class=""><strong>Success@K</strong>: Measures whether or not the K retrieved documents are gold documents. We typically report Success when setting K = 1 to account for multiple gold documents per query.</li>
<li class=""><strong>Recall@K</strong>: Measures how many of the gold documents are in the top K results.</li>
<li class=""><strong>nDCG@K</strong>: Short for normalized Discounted Cumulative Gain, nDCG considers not only whether relevant documents are retrieved, but also how they are ordered. Its strength lies in capturing graded relevance rather than binary relevance, and rewarding systems that place the best results higher in the list.</li>
</ul>
<hr>
<p>For all metrics, higher values indicate better performance. Each metric emphasizes a different aspect of information retrieval, and together they provide a fuller picture.</p>
<hr>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="benchmarks-glossary">Benchmarks Glossary<a href="https://weaviate.io/blog/search-mode-effort#benchmarks-glossary" class="hash-link" aria-label="Direct link to Benchmarks Glossary" title="Direct link to Benchmarks Glossary" translate="no">​</a></h4>
<ul>
<li class=""><strong>BRIGHT</strong>: Featured in ICLR 2025, BRIGHT tests reasoning-intensive retrieval with long, descriptive queries sampled from StackExchange posts. The gold documents are web pages cited in accepted or highly upvoted answers. We use 5 subsets: Biology, Earth Science, Economics, Psychology, and Robotics.</li>
<li class=""><strong>IRPAPERS</strong>: Our benchmark of Information Retrieval papers, published at the start of 2026 to study domain-specific retrieval and compare text- and image-based systems. We report results on the text transcriptions.</li>
<li class=""><strong>WixQA</strong>: Released by the <a href="https://www.wix.com/" target="_blank" rel="noopener noreferrer" class="">Wix.com</a> AI Research team in May 2025, WixQA tests domain-specific technical support retrieval with 200 expert-written customer queries, each paired with gold documents authored by Wix support specialists.</li>
<li class=""><strong>OBLIQ-Bench</strong>: Introduced by MIT researchers in May 2026, OBLIQ-Bench targets queries where relevance is latent, or oblique, rather than stated in the document's surface text. We use the Congress Hearings subset with 254 tip-of-the-tongue queries over 213,650 congressional hearing passages.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="Search Mode Effort Benchmarks" src="https://weaviate.io/assets/images/metric-viewer-b427e4b333181a2554e0bfcb5ce5a7b8.png" width="2194" height="2060" class="img_ev3q"></p>
<p>Across all eight benchmarks, the pattern is consistent: every <code>effort</code> tier of Search Mode outperforms Hybrid Search, and higher effort delivers higher accuracy on average. The size of the gap between tiers depends on the problem. On BRIGHT, where queries demand multi-step reasoning, the tiers separate sharply. Ultrahigh effort lifts nDCG@10 from 13.0 to 57.5 on Biology and from 22.2 to 54.4 on Psychology, with each step up in effort buying meaningful additional accuracy. On domain-specific, but less reasoning-intensive benchmarks like IRPAPERS and WixQA, the gap shrinks. Here medium effort already captures most of the gain over Hybrid Search, and higher tiers add smaller increments on top.</p>
<p>Because Search Mode’s inference pipeline is stochastic, adjacent tiers can overlap on individual datasets. For example, on BRIGHT Economics, medium effort edges out high. Averaged across benchmarks and trials, the ordering holds and higher effort consistently delivers higher accuracy. Standard deviations are computed across three trials per system, and the consistency across runs gives us confidence these gains are robust rather than artifacts of a single sample.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="bright">BRIGHT<a href="https://weaviate.io/blog/search-mode-effort#bright" class="hash-link" aria-label="Direct link to BRIGHT" title="Direct link to BRIGHT" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="BRIGHT results" src="https://weaviate.io/assets/images/bright-average-of-5-subsets-ee93494c520639431983a3a201f82a54.png" width="2328" height="1192" class="img_ev3q"></p>
<p>The BRIGHT subsets reward effort differently. On Biology and Psychology, each step up in effort buys a meaningful gain, with ultrahigh effort roughly quadrupling Hybrid Search's nDCG@10 on Biology. Earth Science tells a different story, where medium effort already triples the Hybrid Search baseline and the higher tiers add smaller refinements on top. Robotics is the most striking case where medium and high effort improve on Hybrid Search only modestly, but ultrahigh effort jumps well past both, lifting Success@1 from 25.7 at medium to 45.9 at high. Robotics also has by far the longest queries of the five subsets, averaging 819 tokens, which suggests the hardest queries are exactly where the extra computation pays off most.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="irpapers">IRPAPERS<a href="https://weaviate.io/blog/search-mode-effort#irpapers" class="hash-link" aria-label="Direct link to IRPAPERS" title="Direct link to IRPAPERS" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="IRPAPERS results" src="https://weaviate.io/assets/images/irpapers-text-only-ddcb2e87c955f55c6faddbd971df89cb.png" width="1828" height="1192" class="img_ev3q"></p>
<p>Compared to BRIGHT, the effort tiers sit much closer together on IRPAPERS. Medium effort already captures most of the gain over Hybrid Search, with high and ultrahigh adding only a couple of points on top.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="wixqa">WixQA<a href="https://weaviate.io/blog/search-mode-effort#wixqa" class="hash-link" aria-label="Direct link to WixQA" title="Direct link to WixQA" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="WixQA results" src="https://weaviate.io/assets/images/wixqa-ec441205525a6e8528c111d9948be0d9.png" width="1828" height="1192" class="img_ev3q"></p>
<p>The pattern from IRPAPERS repeats here. Every Search Mode effort tier clears Hybrid Search by a wide margin, while the gaps between effort tiers stay small. In practical terms, even at medium effort, Search Mode returns the document a Wix support specialist would hand you at rank 1 for about two out of three customer questions, compared to two out of five with Hybrid Search. On benchmarks like these, where queries are shorter and demand less multi-step reasoning than BRIGHT, medium effort seems to capture most of the available gain. For latency-sensitive applications or to save cost, it may be worth testing whether the cheapest tier is already enough.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="obliq-bench">OBLIQ-Bench<a href="https://weaviate.io/blog/search-mode-effort#obliq-bench" class="hash-link" aria-label="Direct link to OBLIQ-Bench" title="Direct link to OBLIQ-Bench" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="OBLIQ-Bench results" src="https://weaviate.io/assets/images/obliq-bench-congress-ce7268482a696b5f8965952a50a00fa0.png" width="2328" height="1192" class="img_ev3q"></p>
<p>These are the lowest absolute scores in this analysis. Hybrid Search essentially hits the floor, surfacing the gold passage in its top 20 results for fewer than 1 in 12 queries. Search Mode changes the picture substantially. Ultrahigh effort reaches 24.4 Success@1, roughly a 7x improvement over Hybrid Search, and this is the one benchmark where the tiers stay cleanly separated on every metric. Each step up in effort buys a real gain, reinforcing the pattern from BRIGHT that the hardest problems reward the most computation.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-search-mode">What is Search Mode?<a href="https://weaviate.io/blog/search-mode-effort#what-is-search-mode" class="hash-link" aria-label="Direct link to What is Search Mode?" title="Direct link to What is Search Mode?" translate="no">​</a></h2>
<p>The Query Agent is Weaviate’s agentic interface to your data. Instead of writing search queries, filters, and aggregations by hand, you describe what you want in natural language and the Query Agent figures out how to get it from your Weaviate collections. It comes in three modes: <strong>Ask Mode</strong>, which answers questions with generated responses grounded in your data, <strong>Search Mode</strong>, which returns the documents themselves, and <strong>Suggest Queries Mode</strong>, which proposes queries to help users explore what their collections can answer.</p>
<p>Search Mode is a drop-in upgrade for any pipeline that expects ranked search results and can tolerate additional latency, whether that’s a RAG system, an agentic workflow, or even a search bar.</p>
<p>The benchmarks so far have tested how well Search Mode finds relevant documents, but it can do more. Because the Query Agent understands your collection schemas, it can translate natural language into structured queries. For example, given a query such as, <em>"Find me some vintage shoes under $70"</em>, Search Mode recognizes "under $70" as a structured filter. It applies a hard constraint on the price property, and searches for vintage shoes among the results that qualify. This lets you combine semantic meaning and structured constraints with one system.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="conclusion">Conclusion<a href="https://weaviate.io/blog/search-mode-effort#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion" translate="no">​</a></h2>
<p>Our benchmarks show what higher effort in Search Mode buys: consistent accuracy gains that grow with the difficulty of the retrieval problem. Additional effort trades latency and cost for that quality. If your application depends on surfacing the right result, such as agentic workflows, deep research, or high-stakes question answering, we recommend experimenting with the new effort tiers. If you are latency-sensitive, medium effort Search Mode or Weaviate's Hybrid Search remains a great fit.</p>
<p>All results can be found or reproduced with our open-source <a href="https://github.com/weaviate/query-agent-benchmarking" target="_blank" rel="noopener noreferrer" class="">query-agent-benchmarking</a> tool. This tool supports 22 benchmarks in total, further including benchmarks such as BEIR, LoTTe, EnronQA, and FreshStack if you would like to extend these comparisons. The tool further supports running the effort sweep comparison on your own search evals stored in Weaviate.</p>
<p>Thank you for reading!</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/search-mode-effort#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=search-mode-effort&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Connor Shorten</name>
            <uri>https://github.com/CShorten</uri>
        </author>
        <category label="agents" term="agents"/>
        <category label="search" term="search"/>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Building Foundry: AI isn’t replacing creativity, it’s removing friction]]></title>
        <id>https://weaviate.io/blog/building-foundry-ai-creative-workflows</id>
        <link href="https://weaviate.io/blog/building-foundry-ai-creative-workflows"/>
        <updated>2026-07-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Why AI won’t replace creatives, and how it can remove friction from messy workflows, lost files, and creative processes.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="hero" src="https://weaviate.io/assets/images/hero-48d592d241a916c77429c6699c2c6ec3.jpg" width="1200" height="630" class="img_ev3q"></p>
<p>File names like <em>final_final_v7.png</em>, <em>USE_THIS_ONE.mov</em> or <em>new_character_export.psd</em> are oddly universal. They appear in game studios, post-production houses, animation pipelines, and design agencies working across every kind of project. The specific conventions vary, but the underlying situation does not: creative work accumulates faster than anyone can organise it, and finding something you made six months ago is often harder than making it again from scratch.</p>
<p>You don’t need better naming conventions or a different design tool to solve this. It’s a retrieval problem, and it’s one that most creative tools have never been designed to solve.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-problem-isnt-creativity">The problem isn’t creativity<a href="https://weaviate.io/blog/building-foundry-ai-creative-workflows#the-problem-isnt-creativity" class="hash-link" aria-label="Direct link to The problem isn’t creativity" title="Direct link to The problem isn’t creativity" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Creative workflows often break when trying to find and reuse work." src="https://weaviate.io/assets/images/messy-files-2c6ad19fe94bf807efe82d38b16989f6.jpg" width="1024" height="768" class="img_ev3q"></p>
<p>The persistent question in conversations about AI and creative work is whether AI can generate something: a painting, a screenplay, or a piece of music. But the more immediate and practical story is far less dramatic.</p>
<p>Consider how a game production pipeline actually works. A concept artist produces dozens of character sketches before one direction gets approved. The rejected explorations go into a folder named something like “alt_directions_v2”, and within three months nobody can reliably locate the version that sparked the final design. Then, on a sequel or expansion, someone needs that exact colour palette and aesthetic direction. Because searching for “dark armour character concepts 2023” turns up nothing useful, they start from scratch rather than building on what already exists.</p>
<p>The same problem looks different depending on the discipline. A film editor searching for specific B-roll scrolls through bins labelled by card number and shoot date, because nobody had time to write shot descriptions during production. An animator looking for a reference of a particular run cycle digs through folders three levels deep before giving up. A graphic designer trying to find an earlier logo exploration for a returning client reconstructs it from memory. A music producer hunting for a drum texture they used two years ago opens session after session, listening through stems, until they find it or settle for something new.</p>
<p>Searching for previous work, redesigning things that have already been done, and trying to stay organized in a sea of ever-growing media all take away from the creative work that actually matters.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-time-actually-goes">Where time actually goes<a href="https://weaviate.io/blog/building-foundry-ai-creative-workflows#where-time-actually-goes" class="hash-link" aria-label="Direct link to Where time actually goes" title="Direct link to Where time actually goes" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="A surprising amount of creative time is spent searching." src="https://weaviate.io/assets/images/cake-58ca7e3da01a6b1ab803b81a5a4dae3b.jpg" width="1024" height="768" class="img_ev3q"></p>
<p>In most creative workflows, the actual moment of making something occupies a surprisingly small fraction of total project time. Pre-production and post-production dwarf the production itself. Research, reference gathering, asset organisation, version tracking, and the constant process of locating what already exists all compete for hours that would otherwise go toward the work.</p>
<p>Consider a scenario common in animation production: a rigging team needs to check how a particular character’s shoulder topology was handled in a previous project. There is no organised asset library, just a shared drive arranged by project name and date. The rig file is in there somewhere, but finding it requires either knowing exactly where to look or asking someone who does. If the person who built the original rig has since moved to a different studio, that knowledge leaves with them.</p>
<p>This is partly a documentation problem, but the right naming and organization only gets a team so far. The work exists. The information exists. But the inability to retrieve it efficiently is costing the team time, consistency, and sometimes money when they unknowingly reproduce work that already exists.</p>
<p>Traditional search compounds the problem rather than solving it. Keyword search requires you to guess which words were used when something was named or described, often by someone else, often months or years earlier. Searching for “blue environmental concept” returns nothing if the file is called <code>ENV_ALTSTYLING_DARK_V4</code>.</p>
<p>Weaviate is designed to handle this type of retrieval, storing semantic representations alongside traditional metadata so creative assets can be searched by both meaning and structured filters.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ai-as-a-workflow-layer">AI as a workflow layer<a href="https://weaviate.io/blog/building-foundry-ai-creative-workflows#ai-as-a-workflow-layer" class="hash-link" aria-label="Direct link to AI as a workflow layer" title="Direct link to AI as a workflow layer" translate="no">​</a></h2>
<p>The most useful aspect of AI for creative fields isn’t as a generator of new work, but as the infrastructure layer that makes existing work more accessible.</p>
<p>This is where a class of technology called <a class="" href="https://weaviate.io/blog/vector-search-explained">semantic search</a> becomes genuinely relevant to creative workflows. To build this infrastructure layer, we can use semantic search to organize and retrieve documents based on meaning, not just by matching exact terms or phrases.</p>
<p>This works by using machine learning to change the original media into vector embeddings. A machine learning model processes a piece of content, whether that content is text, an image, or an audio file, and converts it into a long list of numbers that represents what the content means or depicts. Two things that mean a similar thing, even if described very differently, produce number sequences that sit close together in the resulting high-dimensional vector space. For example, a query for “dark forest with blue atmospheric haze” and an image of a misty pine forest at dusk will produce embeddings that cluster near each other in this space, even though neither the query nor the image share any matching text.</p>
<p>Vector search is the process of finding items whose embeddings are closest to a given query. That proximity is what enables retrieval by meaning rather than by keyword.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-simple-example">A simple example<a href="https://weaviate.io/blog/building-foundry-ai-creative-workflows#a-simple-example" class="hash-link" aria-label="Direct link to A simple example" title="Direct link to A simple example" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Weaviate Playground: comparing keyword, vector, and hybrid search. Showing how semantic search retrieves results based on meaning rather than exact words." src="https://weaviate.io/assets/images/search-0f0f08e6a27e2eb23984029c65dad3b3.jpg" width="1510" height="672" class="img_ev3q"></p>
<p>A game studio building an open-world RPG might accumulate tens of thousands of concept images over a multi-year production. Team composition changes, folder structures evolve, and naming conventions that were carefully maintained in year one have become considerably more creative by year three.</p>
<p>A designer joining the team near launch needs reference for a cold, forested biome that should feel visually distinct from the game’s existing environments. Searching for “cold forest biome” returns nothing useful from a keyword search because those files were named when nobody anticipated that particular query. A semantic search system, given the same natural-language description, can match against visual embeddings of the images themselves, automatically generated descriptions created during indexing, or a combination of both.</p>
<p>Before search becomes possible, content needs to be processed and stored in a way that supports semantic retrieval. This is the ingestion step: running files through a pipeline that generates an embedding for each item and stores that embedding alongside the original content and its metadata.</p>
<p>Metadata remains important even in a semantic search system. We still need to keep that information to know that our result belongs to the correct project, was created within the past two years, and is the right file type. So, in addition to our original media and our generated vector embeddings, it’s important that we store the file’s metadata as well.</p>
<p>A vector database holds all of this together. Unlike a traditional relational database designed for exact lookups, a vector database stores embeddings alongside the original data and metadata, with its internal architecture optimised for fast semantic retrieval. When you run a query, the database converts it into an embedding and returns the items whose embeddings are most similar. The result is search that appears to understand what you are actually looking for, not just what you typed. You can try the <a href="https://playground.weaviate.io/" target="_blank" rel="noopener noreferrer" class="">semantic search playground</a> to see the difference between keyword, vector, and hybrid results on the same query.</p>
<br>
<!-- -->
<br>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="this-is-just-the-start">This is just the start<a href="https://weaviate.io/blog/building-foundry-ai-creative-workflows#this-is-just-the-start" class="hash-link" aria-label="Direct link to This is just the start" title="Direct link to This is just the start" translate="no">​</a></h2>
<p>None of what has been described here is beyond current technology. Semantic search and vector databases are already used in enterprise knowledge management, legal document retrieval, and e-commerce product search for exactly these reasons. We can apply those same principles to creative asset management.</p>
<p>The challenge lies in the ingestion layer: deciding what gets indexed, how descriptions and embeddings are generated for different content types, and how the search interface fits into existing tools and workflows.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What’s next<a href="https://weaviate.io/blog/building-foundry-ai-creative-workflows#whats-next" class="hash-link" aria-label="Direct link to What’s next" title="Direct link to What’s next" translate="no">​</a></h2>
<p>In the next post, we’ll look closely at where creative workflows actually break down, and why conventional folder structures, tagging systems, and keyword search consistently fail to keep pace with how creative teams produce work. After that, we’ll walk through a concrete implementation: a working semantic search system for creative assets built with Weaviate, step by step.</p>
<hr>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/building-foundry-ai-creative-workflows#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=building-foundry-ai-creative-workflows&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Shan Blackwood</name>
            <uri>https://www.linkedin.com/in/shan-blackwood/</uri>
        </author>
        <author>
            <name>Svitlana Smolianova</name>
            <uri>https://linkedin.com/in/svitlana-sm</uri>
        </author>
        <author>
            <name>Victoria Slocum</name>
            <uri>https://www.linkedin.com/in/victorialslocum/</uri>
        </author>
        <category label="creative-ai" term="creative-ai"/>
        <category label="workflows" term="workflows"/>
        <category label="search" term="search"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Query Profiling: See Where a Slow Query Spends Its Time]]></title>
        <id>https://weaviate.io/blog/query-profiling</id>
        <link href="https://weaviate.io/blog/query-profiling"/>
        <updated>2026-07-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[When a Weaviate query is slow, the first question is where the time went. Query profiling returns a per-stage, per-shard timing breakdown, making query performance issues visible.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Where did the time go? Query profiling breaks a slow search into its stages." src="https://weaviate.io/assets/images/hero-d6ff5108f8f80410c4281a8d2c334533.png" width="1200" height="630" class="img_ev3q"></p>
<br>
<p>A query in production is slow. Maybe it was always a little slow and it finally crossed the line where someone noticed, or maybe it regressed after a data load. Either way you now have a single question, and it is the same question every time: where did the time go? Was it the filter, the vector search, the object read from disk, or the keyword scoring? Until you can split that number into its parts, every fix is a guess.</p>
<p>Weaviate has always been able to answer this. The trouble was getting the answer out.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-we-used-to-find-slow-queries">How we used to find slow queries<a href="https://weaviate.io/blog/query-profiling#how-we-used-to-find-slow-queries" class="hash-link" aria-label="Direct link to How we used to find slow queries" title="Direct link to How we used to find slow queries" translate="no">​</a></h2>
<p>The existing tool is the <a href="https://docs.weaviate.io/deploy/configuration/logging#slow-query-logging" target="_blank" rel="noopener noreferrer" class="">slow query log</a>. You turn it on with two environment variables and restart the node:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">QUERY_SLOW_LOG_ENABLED=true</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">QUERY_SLOW_LOG_THRESHOLD=2s</span><br></span></code></pre></div></div>
<p>Any query that runs longer than the threshold is logged at WARN with its full timing breakdown attached: the class and shard, the filters, the limit, and every internal timer the engine recorded on the way through. If you have <a href="https://docs.weaviate.io/deploy/configuration/env-vars" target="_blank" rel="noopener noreferrer" class="">runtime overrides</a> already wired up, you can flip both settings live from the overrides file and skip the restart, because the server rereads them on its load interval.</p>
<p>For catching regressions across a whole fleet over time, this works well. It is a passive net that stays out of the way until something trips it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-the-old-approach-falls-short">Where the old approach falls short<a href="https://weaviate.io/blog/query-profiling#where-the-old-approach-falls-short" class="hash-link" aria-label="Direct link to Where the old approach falls short" title="Direct link to Where the old approach falls short" translate="no">​</a></h2>
<p>The slow query log is built for a different job than the one you have when a specific query is slow right now, and four things get in the way.</p>
<p>First, the plain enablement path needs a restart. Restarting a node to debug a latency problem changes the thing you are measuring. A fresh process starts with cold OS page caches, so the first queries after a restart read from disk where a warm node would have hit memory. You end up profiling the restart as much as the query.</p>
<p>Second, the settings you tune live are temporary knobs. If you raised the threshold or toggled the log through runtime overrides to catch a specific query, that change lives in the overrides file, not in the deployment manifests your cluster is actually built from. It is a state you have to remember to undo, and it drifts out of sync with how the deployment is defined.</p>
<p>Third, it is always after the fact. The log only reacts once a query has already crossed the threshold. You cannot point it at the query in front of you and ask for its numbers; you wait for that query, or one like it, to be slow again. On top of that the log samples about one percent of all queries at INFO regardless of speed, so a fast query can show up in the output next to the genuinely slow ones and you have to filter the noise out.</p>
<p>Fourth, it is per node. Each node logs the shard searches that ran on it, and nothing stitches those lines together. On a single query that fans out across a cluster, the timings you want are spread across several nodes' logs, and reassembling one query's picture is manual work.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-query-profiling">What is query profiling?<a href="https://weaviate.io/blog/query-profiling#what-is-query-profiling" class="hash-link" aria-label="Direct link to What is query profiling?" title="Direct link to What is query profiling?" translate="no">​</a></h2>
<p>Query profiling is the direct answer to all four. It is a per-query, opt-in flag. You set it on one search, the server collects the timing breakdown for that search, and it returns the numbers inline on the response. There is no env var, no threshold, no restart, and nothing to reset afterward.</p>
<p>Under the hood it uses the same instrumentation as the slow query log, so the numbers are the same numbers, delivered differently. And it closes the per-node gap directly: the coordinating node gathers the profiles from every shard on every node that took part in the query and returns them together. One request gives you the whole cluster's view of that one query.</p>
<p>You enable it per query. In Python, add it to the return metadata:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> MetadataQuery</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">response </span><span class="token operator">=</span><span class="token plain"> collection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">near_vector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    near_vector</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token number">0.1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">0.2</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">0.3</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    limit</span><span class="token operator">=</span><span class="token number">10</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return_metadata</span><span class="token operator">=</span><span class="token plain">MetadataQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">query_profile</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> shard </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query_profile</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">shards</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">shard</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">name</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> shard</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> shard</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">searches</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Query profiling is available in the official Python, JavaScript/TypeScript, Java (v6), and C# clients, and over gRPC directly by setting <code>QueryProfile</code> in the request metadata. The profile rides on the response object at <code>response.query_profile</code>, not on any individual result. Profiling covers vector search, keyword scoring, and filter evaluation. It does not measure generative modules, rerankers, or other post-processing.</p>
<p>Query profiling was <a href="https://docs.weaviate.io/weaviate/search/query-profile" target="_blank" rel="noopener noreferrer" class="">introduced in v1.36.9</a>, announced as a preview with the <a href="https://weaviate.io/blog/weaviate-1-37-release" target="_blank" rel="noopener noreferrer" class="">v1.37 release</a>, and is generally available as of v1.38. When the flag is off, the cost is a single boolean check. When it is on, the added cost is microsecond-level timer reads. It is meant for debugging and optimization, not for your production hot paths.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="reading-the-numbers">Reading the numbers<a href="https://weaviate.io/blog/query-profiling#reading-the-numbers" class="hash-link" aria-label="Direct link to Reading the numbers" title="Direct link to Reading the numbers" translate="no">​</a></h2>
<p>The profile is organized by shard. Each shard entry names the shard and the node that ran it, and holds a <code>details</code> map of metric name to value for each search type it performed. A pure vector query shows the vector timers, a <a href="https://docs.weaviate.io/weaviate/search/bm25" target="_blank" rel="noopener noreferrer" class="">BM25</a> query shows the keyword timers, a <a href="https://docs.weaviate.io/weaviate/search/filters" target="_blank" rel="noopener noreferrer" class="">filtered</a> query adds the filter timers, and a hybrid query carries both a vector and a keyword section. Only the stages that actually ran show up, so the exact set of fields depends on the query.</p>
<p><img decoding="async" loading="lazy" alt="Search Metrics Diagram" src="https://weaviate.io/assets/images/search_metrics-81e866aca0bdfb9ae5ad303962df6607.png" width="2082" height="1515" class="img_ev3q"></p>
<p><code>total_took</code> is the wall time of the whole shard search. Everything else explains where that time went.</p>
<p>On the vector path, <code>objects_took</code> is object hydration: reading the final objects out of the on-disk objects store. A high value here means disk-bound hydration, and it usually points at page-cache misses, a large <code>limit</code>, or large objects. This is the clearest disk signal in the profile.</p>
<p><code>filters_build_allow_list_took</code> is filter resolution: turning your <code>where</code> clause into a set of matching document IDs through the <a href="https://docs.weaviate.io/weaviate/concepts/indexing" target="_blank" rel="noopener noreferrer" class="">inverted index</a>. It is driven by filter cardinality and by whether those index segments are in memory or on disk. The <code>filters_ids_matched</code> count sits right next to it and tells you which regime you are in. A large count means a broad filter matching many documents; a small count with a high time points more at disk reads.</p>
<p><code>vector_search_took</code> is the <a href="https://docs.weaviate.io/weaviate/concepts/vector-index" target="_blank" rel="noopener noreferrer" class="">vector index</a> doing its search, and its main sub-timer is <code>knn_search_layer_N_took</code>, one entry per HNSW layer, with layer 0 normally dominating. This is graph traversal: exploring candidates and computing distances. It is worth being precise here, because it is easy to read a high vector time as the node running out of resources. It usually is not. The HNSW graph lives in RAM, so this timer measures compute, not a wait on disk. A high value means the traversal itself is expensive, and the levers are the ones that control traversal cost: <code>ef</code>, vector dimensionality, and the filter strategy on filtered searches. Tune those before you reach for more hardware.</p>
<p>The one vector stage that can genuinely touch disk is <code>knn_search_rescore_took</code>. It only appears when compression is enabled, and it reads full-precision vectors back to rescore the compressed candidates. A high value there can mean disk latency during rescore, which is a different problem from a slow traversal.</p>
<p><code>hnsw_flat_search</code> is a boolean, not a timer. When it is <code>true</code> under a filter, the filter was selective enough that a brute-force scan of the matches was cheaper than walking the graph, and the engine took that path on purpose.</p>
<p>On the keyword path, the <code>kwd_*</code> family breaks BM25 down the same way. Two are worth knowing by name. <code>kwd_3_term_time</code> is the cost of reading the per-term posting lists out of the inverted segments, so it is sensitive to the number of query terms and to disk reads. <code>kwd_4_bmw_time</code> is the BlockMax WAND traversal that scores the posting blocks, so it grows with low query selectivity and long posting lists. A slow keyword query is usually one or the other, and the split tells you which.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="worked-examples">Worked examples<a href="https://weaviate.io/blog/query-profiling#worked-examples" class="hash-link" aria-label="Direct link to Worked examples" title="Direct link to Worked examples" translate="no">​</a></h2>
<p>The numbers below are illustrative, but they show the shape of the output and how to read it.</p>
<p>A vector search where hydration dominates:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"shards"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"name"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"1a2b3c4dshard"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"node"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"weaviate-0"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"searches"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token property">"vector"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token property">"details"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"total_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"48.2ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"filters_build_allow_list_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"2.1ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"filters_ids_matched"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"512"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"vector_search_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"8.4ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"knn_search_layer_0_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"7.9ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"knn_search_rescore_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"0.3ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"hnsw_flat_search"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"false"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"objects_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"36.8ms"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>The filter and the vector search are cheap. <code>objects_took</code> is most of <code>total_took</code>, so the time is going into reading objects off disk. Check the page cache and storage on that node, and consider a smaller <code>limit</code> or a lighter payload.</p>
<p>A filter that matches too much:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"shards"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"name"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"9f8e7d6cshard"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"node"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"weaviate-1"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"searches"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token property">"vector"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token property">"details"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"total_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"61.5ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"filters_build_allow_list_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"41.2ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"filters_ids_matched"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"12840000"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"vector_search_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"15.6ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"knn_search_layer_0_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"14.8ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"hnsw_flat_search"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"false"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"objects_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"3.9ms"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>Here <code>filters_build_allow_list_took</code> is the largest slice, and <code>filters_ids_matched</code> is over ten million. The filter is broad, so building the allow-list is the cost. This is a cardinality problem, not a disk one: rethink the filter so it selects less, or apply the wide condition differently rather than as a pre-filter over the whole set.</p>
<p>A compressed index where rescore hits disk:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"shards"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"name"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"5c4b3a2fshard"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"node"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"weaviate-0"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"searches"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token property">"vector"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token property">"details"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"total_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"39.7ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"vector_search_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"35.1ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"knn_search_layer_0_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"9.2ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"knn_search_rescore_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"25.4ms"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"hnsw_flat_search"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"false"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token property">"objects_took"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"3.8ms"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>The graph traversal at layer 0 is fine. Almost all of <code>vector_search_took</code> is <code>knn_search_rescore_took</code>, the stage that reads full-precision vectors back for the compressed candidates. That points at disk latency during rescore rather than at the graph, so the investigation moves to storage and to the compression configuration.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://weaviate.io/blog/query-profiling#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<p>Query profiling has become one of the first things our solution engineering team reaches for when a customer reports a slow query. Instead of enabling a log, waiting for the query to be slow again, and stitching node logs together, you set one flag, run the query once, and read the breakdown across the whole cluster. The guesswork about where the time went is gone, and what is left is a specific stage to fix.</p>
<p>If you want help reading a profile or working out what to change based on one, reach out. Our solution engineering team looks at these breakdowns with customers on a regular basis, so if you are a customer, your usual Weaviate contact or support channel is the fastest way to get us the details. If you are running the open-source project, ask in the <a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="">community forum</a> and we will help you work through it there.</p>
<p>To go deeper:</p>
<ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/search/query-profile" target="_blank" rel="noopener noreferrer" class="">Query profiling</a> in the docs</li>
<li class=""><a href="https://docs.weaviate.io/deploy/configuration/logging#slow-query-logging" target="_blank" rel="noopener noreferrer" class="">Slow query logging</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-37-release" target="_blank" rel="noopener noreferrer" class="">The Weaviate 1.37 release post</a></li>
</ul>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/query-profiling#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=query-profiling&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Byron Voorbach</name>
            <uri>https://github.com/byronvoorbach</uri>
        </author>
        <category label="concepts" term="concepts"/>
        <category label="engineering" term="engineering"/>
        <category label="search" term="search"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Weaviate 1.38 Release]]></title>
        <id>https://weaviate.io/blog/weaviate-1-38-release</id>
        <link href="https://weaviate.io/blog/weaviate-1-38-release"/>
        <updated>2026-06-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[This release brings the HFresh disk-based vector index and the built-in MCP Server to general availability, rebuilds cluster-wide async replication to run from a single scheduler (on by default), and adds two previews: the Boost API and Nested Object Filtering.]]></summary>
        <content type="html"><![CDATA[<p>Weaviate <code>v1.38</code> is now available open-source and on <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a>.</p>
<p>Two capabilities reach general availability in this release: the <strong>HFresh</strong> disk-based vector index and the built-in <strong>MCP Server</strong>. <strong>Async replication</strong> has been rebuilt to run cluster-wide from a single scheduler, and it now runs by default on every replicated collection. Two new previews join them: the <strong>Boost API</strong> for query-time rescoring and <strong>Nested Object Filtering</strong>.</p>
<p>Here are the release highlights!</p>
<p><img decoding="async" loading="lazy" alt="Weaviate 1.38 is released" src="https://weaviate.io/assets/images/hero-4a89efeaabb0804a755c5d50b90bcc88.png" width="1200" height="630" class="img_ev3q"></p>
<ul>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-38-release#hfresh-vector-index---general-availability" class="">HFresh Vector Index - General Availability</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-38-release#mcp-server---general-availability" class="">MCP Server - General Availability</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-38-release#async-replication-everywhere" class="">Async Replication, Everywhere</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-38-release#boost-api-preview" class="">Boost API (Preview)</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-38-release#nested-object-filtering-preview" class="">Nested Object Filtering (Preview)</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-38-release#performance-improvements-and-fixes" class="">Performance Improvements and Fixes</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-38-release#community-contributions" class="">Community Contributions</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-38-release#summary" class="">Summary</a></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="hfresh-vector-index---general-availability">HFresh Vector Index - General Availability<a href="https://weaviate.io/blog/weaviate-1-38-release#hfresh-vector-index---general-availability" class="hash-link" aria-label="Direct link to HFresh Vector Index - General Availability" title="Direct link to HFresh Vector Index - General Availability" translate="no">​</a></h2>
<p><a class="" href="https://weaviate.io/blog/weaviate-1-36-release#hfresh-preview">HFresh</a>, the disk-based vector index we introduced as a technical preview in <code>v1.36</code>, is now <strong>generally available</strong>. It's inspired by the <a href="https://arxiv.org/abs/2410.14452" target="_blank" rel="noopener noreferrer" class="">SPFresh algorithm</a>: instead of keeping every vector in memory like HNSW, HFresh groups vectors into on-disk regions called <em>postings</em> and keeps a small in-memory HNSW index over their centroids to decide which regions to read. Memory stays low and latency stays predictable as a collection grows into the billions, which makes it a good fit for <strong>streaming workloads</strong> where data changes continuously rather than being loaded once.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works">How it works<a href="https://weaviate.io/blog/weaviate-1-38-release#how-it-works" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h3>
<p>HFresh is selected per (named) vector, the same way as any other index. In <code>v1.38</code> it's no longer behind a preview flag — you enable it by configuring a vector to use it:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">config </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> VectorDistances</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string" style="color:rgb(255, 121, 198)">"Article"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    vector_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Vectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text2vec_weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"default"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        source_properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"title"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"body"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        vector_index_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">VectorIndex</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">hfresh</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            distance_metric</span><span class="token operator">=</span><span class="token plain">VectorDistances</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">COSINE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>HFresh has <strong>RQ-1</strong> <a href="https://docs.weaviate.io/weaviate/concepts/vector-quantization" target="_blank" rel="noopener noreferrer" class="">quantization</a> built in: postings are stored compressed on disk, and final ranking rescores against the uncompressed vectors for accuracy. It supports the <code>cosine</code> and <code>l2-squared</code> distance metrics.</p>
<p>Because the index rebalances incrementally — splitting oversized postings, merging undersized ones, and reassigning vectors as the boundaries shift — it keeps up with continuous updates without the periodic full rebuilds that other on-disk indexes depend on.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/concepts/vector-index#hfresh-index" target="_blank" rel="noopener noreferrer" class="">Concepts: Vector Index - HFresh</a></li>
<li class=""><a href="https://arxiv.org/abs/2410.14452" target="_blank" rel="noopener noreferrer" class="">SPFresh: Incremental In-Place Update for Billion-Scale Vector Search</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mcp-server---general-availability">MCP Server - General Availability<a href="https://weaviate.io/blog/weaviate-1-38-release#mcp-server---general-availability" class="hash-link" aria-label="Direct link to MCP Server - General Availability" title="Direct link to MCP Server - General Availability" translate="no">​</a></h2>
<p>The built-in <a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer" class="">Model Context Protocol (MCP)</a> server, introduced as a preview in <a class="" href="https://weaviate.io/blog/weaviate-1-37-release#mcp-server-preview"><code>v1.37</code></a>, is now <strong>generally available</strong>. It lets LLMs, IDEs, and AI agents work with Weaviate directly — inspecting schemas, running hybrid searches, and writing objects back — with no glue code. The server is a Streamable HTTP endpoint at <code>/v1/mcp</code> on the same port as the REST API, authenticates with a Bearer / API-key token, and respects Weaviate's standard <a href="https://docs.weaviate.io/deploy/configuration/authorization" target="_blank" rel="noopener noreferrer" class="">RBAC</a> permissions.</p>
<p>The server exposes four tools:</p>
<ul>
<li class=""><strong><code>weaviate-collections-get-config</code></strong> — inspect a collection's schema and configuration</li>
<li class=""><strong><code>weaviate-tenants-list</code></strong> — list the tenants of a multi-tenant collection</li>
<li class=""><strong><code>weaviate-query-hybrid</code></strong> — run a hybrid (vector + keyword) search</li>
<li class=""><strong><code>weaviate-objects-upsert</code></strong> — insert or update objects (only when write access is enabled)</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works-1">How it works<a href="https://weaviate.io/blog/weaviate-1-38-release#how-it-works-1" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h3>
<p>You enable the server with <code>MCP_SERVER_ENABLED</code>, and optionally expose its write tools with <code>MCP_SERVER_WRITE_ACCESS_ENABLED</code>. What's new in <code>v1.38</code> is that both flags are <strong>runtime-configurable</strong>: rather than only being read at startup, Weaviate now picks up changes to them from its runtime-overrides file while the cluster is running.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># Runtime-overrides file — applied without a restart</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">mcp_server_enabled</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token boolean important">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">mcp_server_write_access_enabled</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token boolean important">true</span><br></span></code></pre></div></div>
<p>So you can grant or revoke an agent's write access on a live cluster, with no rolling restart.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/configuration/mcp-server" target="_blank" rel="noopener noreferrer" class="">Docs: Weaviate MCP server</a></li>
<li class=""><a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer" class="">Model Context Protocol</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="async-replication-everywhere">Async Replication, Everywhere<a href="https://weaviate.io/blog/weaviate-1-38-release#async-replication-everywhere" class="hash-link" aria-label="Direct link to Async Replication, Everywhere" title="Direct link to Async Replication, Everywhere" translate="no">​</a></h2>
<p>Async replication is the background repair process that keeps replicas in sync on collections with a replication factor greater than 1. In <code>v1.38</code> it has been re-architected to run <strong>cluster-wide from a single scheduler</strong>, rather than being configured and run separately per collection. It also now runs <strong>by default</strong> on every RF &gt; 1 collection, where previously it was opt-in per collection.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works-2">How it works<a href="https://weaviate.io/blog/weaviate-1-38-release#how-it-works-2" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h3>
<p>One scheduler coordinates async repair across all replicated collections, drawing from a single shared worker pool instead of a separate pool per collection. That makes repair behavior consistent across the cluster and simpler to operate at scale.</p>
<p>With the move to a central scheduler, the per-collection <code>maxWorkers</code> and <code>enabled</code> settings are gone. Two cluster-level controls replace them:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># Size of the shared async-replication worker pool</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">ASYNC_REPLICATION_SCHEDULER_WORKERS</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'&lt;n&gt;'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Kill-switch — pause all async replication, no restart needed</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">ASYNC_REPLICATION_DISABLED</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'false'</span><br></span></code></pre></div></div>
<p><code>ASYNC_REPLICATION_SCHEDULER_WORKERS</code> sizes the shared pool, and <code>ASYNC_REPLICATION_DISABLED</code> is a cluster-wide kill-switch you can flip at runtime.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/concepts/replication-architecture" target="_blank" rel="noopener noreferrer" class="">Concepts: Replication architecture - Async replication</a></li>
<li class=""><a href="https://docs.weaviate.io/deploy/configuration/replication" target="_blank" rel="noopener noreferrer" class="">Configuration: Replication</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="boost-api-preview">Boost API (Preview)<a href="https://weaviate.io/blog/weaviate-1-38-release#boost-api-preview" class="hash-link" aria-label="Direct link to Boost API (Preview)" title="Direct link to Boost API (Preview)" translate="no">​</a></h2>
<p>Sometimes you want to nudge results without removing any. A filter is too blunt for that — it drops everything that doesn't match — when what you really want is to rank fresh articles a little higher, or favor in-stock products, while keeping the full result set. The new <strong>Boost API</strong> does exactly that.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works-3">How it works<a href="https://weaviate.io/blog/weaviate-1-38-release#how-it-works-3" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h3>
<p>Boost runs <em>after</em> the primary search. It re-scores the candidates by blending their original score with one or more boost conditions, then re-sorts them — promoting or demoting results without dropping any. Conditions can be based on:</p>
<ul>
<li class=""><strong>Filter matches</strong> — promote results that satisfy a filter</li>
<li class=""><strong>Property values</strong> — rank by a numeric property's value</li>
<li class=""><strong>Time decay</strong> — favor more recent (or near-a-date) objects</li>
<li class=""><strong>Numeric decay</strong> — favor objects closer to a target number</li>
</ul>
<p>In the Python client (<code>v4.22.0</code>+), you build a boost and pass it to any query via <code>boost=</code>:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Boost</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Filter</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Softly promote in-stock products without dropping the rest</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">response </span><span class="token operator">=</span><span class="token plain"> collection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">hybrid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    query</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"wireless headphones"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    limit</span><span class="token operator">=</span><span class="token number">10</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    boost</span><span class="token operator">=</span><span class="token plain">Boost</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token builtin" style="color:rgb(189, 147, 249)">filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">by_property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"in_stock"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">equal</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        weight</span><span class="token operator">=</span><span class="token number">0.3</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>The <code>weight</code> (0–1) sets how much the boost shifts the final score: the result is <code>(1 - weight)</code> of the original score plus <code>weight</code> of the boost score. Boost is <strong>gRPC-only</strong> — there's no REST or GraphQL equivalent — and a single query can apply at most <strong>20 conditions</strong>.</p>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Preview</div><div class="admonitionContent_BuS1"><p>The Boost API is a <strong>preview</strong> feature, available over gRPC. The API and behavior may change in future releases.</p></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/search/boost" target="_blank" rel="noopener noreferrer" class="">How-to: Search - Boost results</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="nested-object-filtering-preview">Nested Object Filtering (Preview)<a href="https://weaviate.io/blog/weaviate-1-38-release#nested-object-filtering-preview" class="hash-link" aria-label="Direct link to Nested Object Filtering (Preview)" title="Direct link to Nested Object Filtering (Preview)" translate="no">​</a></h2>
<p>Weaviate <code>v1.38</code> adds a preview for <strong>filtering on nested object properties</strong>. Until now, <code>object</code> and <code>object[]</code> properties were stored but couldn't be filtered on directly.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works-4">How it works<a href="https://weaviate.io/blog/weaviate-1-38-release#how-it-works-4" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h3>
<p>You filter on a nested field by referencing it with a <strong>dotted path</strong> — for example, <code>cars.make</code> to filter on the <code>make</code> field inside a <code>cars</code> object property. The feature is <strong>off by default</strong> and gated behind a preview environment variable:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token key atrule">WEAVIATE_PREVIEW_NESTED_FILTERING</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'true'</span><br></span></code></pre></div></div>
<p>Once enabled, the dotted path goes wherever you'd normally supply a property name, including from the clients:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Filter</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">response </span><span class="token operator">=</span><span class="token plain"> collection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">fetch_objects</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    filters</span><span class="token operator">=</span><span class="token plain">Filter</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">by_property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"cars.make"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">equal</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"Toyota"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>This works for data nested inside both <code>object</code> and <code>object[]</code> properties.</p>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Preview</div><div class="admonitionContent_BuS1"><p>Nested Object Filtering is a <strong>preview</strong> feature, off by default behind <code>WEAVIATE_PREVIEW_NESTED_FILTERING</code>. The API and behavior may change in future releases.</p></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/search/filters" target="_blank" rel="noopener noreferrer" class="">How-to: Filters</a></li>
<li class=""><a href="https://docs.weaviate.io/weaviate/config-refs/datatypes" target="_blank" rel="noopener noreferrer" class="">Config references: Data types - object</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="performance-improvements-and-fixes">Performance Improvements and Fixes<a href="https://weaviate.io/blog/weaviate-1-38-release#performance-improvements-and-fixes" class="hash-link" aria-label="Direct link to Performance Improvements and Fixes" title="Direct link to Performance Improvements and Fixes" translate="no">​</a></h2>
<p>Beyond the headline features, <code>v1.38</code> ships a long list of improvements. A few worth calling out:</p>
<ul>
<li class=""><strong>Production-ready replica movement:</strong> Moving a shard's replicas between nodes — for rebalancing and scaling — graduates to production-ready, backed by a change-capture log that keeps writes flowing during the move.</li>
<li class=""><strong>Default vector index type:</strong> A new cluster-level setting picks the default vector index for new collections (including named vectors), instead of always defaulting to HNSW.</li>
<li class=""><strong>Usage guardrails:</strong> Operators can set server-side limits on the number of objects, collections, tenants, and shards, plus allow-lists for vector-index and compression types.</li>
<li class=""><strong>New module — <code>text2vec-digitalocean</code>:</strong> Generate embeddings through DigitalOcean's inference platform.</li>
<li class=""><strong>Backup reliability:</strong> Backups no longer pause compactions, and object-storage listing is faster — both help large collections back up more reliably.</li>
<li class=""><strong>Fractional BM25 property boosts:</strong> Keyword-search property boosts now accept fractional values (e.g. <code>title^2.5</code>), not just integers.</li>
<li class=""><strong>Deterministic tie-breaking:</strong> Vector searches break ties between equal-distance results deterministically, for stable, repeatable ordering.</li>
<li class=""><strong>Faster startup</strong> and an improved cache for compressed vector indexes.</li>
</ul>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://github.com/weaviate/weaviate/releases/tag/v1.38.0" target="_blank" rel="noopener noreferrer" class="">Weaviate 1.38: GitHub Release Notes</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="community-contributions">Community Contributions<a href="https://weaviate.io/blog/weaviate-1-38-release#community-contributions" class="hash-link" aria-label="Direct link to Community Contributions" title="Direct link to Community Contributions" translate="no">​</a></h2>
<p>Weaviate is open source, and this release includes work from several first-time contributors. Thank you to:</p>
<ul>
<li class=""><a href="https://github.com/dillonledoux" target="_blank" rel="noopener noreferrer" class="">@dillonledoux</a> — the new <code>text2vec-digitalocean</code> module (<a href="https://github.com/weaviate/weaviate/pull/11298" target="_blank" rel="noopener noreferrer" class="">#11298</a>)</li>
<li class=""><a href="https://github.com/anishesg" target="_blank" rel="noopener noreferrer" class="">@anishesg</a> — inverted-index and HFresh fixes, including correct handling of negative zero and pre-1970 dates (<a href="https://github.com/weaviate/weaviate/pull/11120" target="_blank" rel="noopener noreferrer" class="">#11120</a>)</li>
<li class=""><a href="https://github.com/msnandhis" target="_blank" rel="noopener noreferrer" class="">@msnandhis</a> — fractional BM25 property boosts (<a href="https://github.com/weaviate/weaviate/pull/11471" target="_blank" rel="noopener noreferrer" class="">#11471</a>)</li>
<li class=""><a href="https://github.com/3em0" target="_blank" rel="noopener noreferrer" class="">@3em0</a> — reject duplicate static API keys (<a href="https://github.com/weaviate/weaviate/pull/11393" target="_blank" rel="noopener noreferrer" class="">#11393</a>)</li>
<li class=""><a href="https://github.com/kedar49" target="_blank" rel="noopener noreferrer" class="">@kedar49</a> — collision check for DB user identifiers (<a href="https://github.com/weaviate/weaviate/pull/11381" target="_blank" rel="noopener noreferrer" class="">#11381</a>)</li>
<li class=""><a href="https://github.com/SAY-5" target="_blank" rel="noopener noreferrer" class="">@SAY-5</a> — HFresh stability fix during async init (<a href="https://github.com/weaviate/weaviate/pull/11087" target="_blank" rel="noopener noreferrer" class="">#11087</a>)</li>
</ul>
<p>If you'd like to contribute, check out the <a href="https://docs.weaviate.io/contributor-guide/" target="_blank" rel="noopener noreferrer" class="">contributor guide</a> and the <a href="https://github.com/weaviate/weaviate/issues" target="_blank" rel="noopener noreferrer" class=""><code>good-first-issue</code></a> label on GitHub.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://weaviate.io/blog/weaviate-1-38-release#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<p>Weaviate <code>v1.38</code> brings two capabilities to general availability — HFresh and the MCP Server — alongside a rebuilt async replication path and two new previews.</p>
<p><strong>Key highlights:</strong></p>
<ul>
<li class=""><strong>HFresh (GA)</strong> — The disk-based, SPFresh-inspired vector index for streaming workloads, selected per named vector with <code>vectorIndexType: "hfresh"</code> and built-in RQ-1 quantization</li>
<li class=""><strong>MCP Server (GA)</strong> — The built-in Model Context Protocol server at <code>/v1/mcp</code>, with its enable flags now runtime-configurable</li>
<li class=""><strong>Async Replication, Everywhere</strong> — Cluster-wide async repair from one scheduler and a shared worker pool, on by default for replicated collections, with a runtime kill-switch</li>
<li class=""><strong>Boost API (Preview)</strong> — Query-time rescoring that promotes or demotes results without dropping any</li>
<li class=""><strong>Nested Object Filtering (Preview)</strong> — Filter on <code>object</code> / <code>object[]</code> properties using a dotted path</li>
</ul>
<p><strong>Ready to get started?</strong></p>
<p>The release is available open-source on <a href="https://github.com/weaviate/weaviate/releases/tag/v1.38.0" target="_blank" rel="noopener noreferrer" class="">GitHub</a> and on <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a>, where you can spin up a cluster on the free tier.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>Not all features may be available on Weaviate Cloud. Some capabilities — preview features in particular, and those that require specific environment configuration — may not be enabled on managed clusters, or may become available on a different schedule.</p></div></div>
<p>For those upgrading a self-hosted version, please check the <a href="https://docs.weaviate.io/deploy/migration#general-upgrade-instructions" target="_blank" rel="noopener noreferrer" class="">migration guide</a> for version-specific notes.</p>
<p>Thanks for reading, and happy vector searching!</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/weaviate-1-38-release#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=weaviate-1-38-release&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Ivan Despot</name>
            <uri>https://www.linkedin.com/in/ivan-g-despot/</uri>
        </author>
        <category label="release" term="release"/>
        <category label="engineering" term="engineering"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Import & Vectorize Data with Weaviate at Scale]]></title>
        <id>https://weaviate.io/blog/data-import-best-practices</id>
        <link href="https://weaviate.io/blog/data-import-best-practices"/>
        <updated>2026-06-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Server-side batching, retries, the blobHash data type, and multimodal ingestion — what to use when, with code.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Import and vectorize data with Weaviate at scale: server-side batching, retries, the blobHash data type, and multimodal ingestion" src="https://weaviate.io/assets/images/hero-3d3404ba029aa5e8104892b0590e738c.png" width="1200" height="630" class="img_ev3q"></p>
<p>Most vector database pilots fail at ingest, not at search. You build a clever retrieval pipeline, you watch it work on a thousand documents, and then someone hands you fifty million rows. The next two weeks disappear into rate limits, partial failures, and three rewrites of your batch logic.</p>
<p>This post is the guide I wish I had the first time I imported a real dataset into Weaviate. It covers server-side batching, error handling, the data type decisions that cost you the most if you get them wrong, and how to ingest media and PDFs without standing up an OCR pipeline.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Try this as you read</div><div class="admonitionContent_BuS1"><p>The fastest way to follow along is a <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">free Weaviate Cloud trial</a> paired with <a href="https://docs.weaviate.io/weaviate/model-providers" target="_blank" rel="noopener noreferrer" class="">Weaviate Embeddings</a>. No infrastructure to manage, no embedding API keys, free vectorization on the trial. Every code snippet below runs against that setup without modification.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-ingest-problem-nobody-warns-you-about">The ingest problem nobody warns you about<a href="https://weaviate.io/blog/data-import-best-practices#the-ingest-problem-nobody-warns-you-about" class="hash-link" aria-label="Direct link to The ingest problem nobody warns you about" title="Direct link to The ingest problem nobody warns you about" translate="no">​</a></h2>
<p>A working prototype tells you nothing about what happens at scale. The problems that bite production teams almost never show up in tutorials.</p>
<p>Four bite hardest:</p>
<ul>
<li class=""><strong>Rate limits from your embedding provider:</strong> Most teams hit them within an hour of a real import, then write retry code, then write retry code for the retry code.</li>
<li class=""><strong>HTTP 200 lying to you:</strong> A successful batch response does not mean every object made it in. Individual objects can fail silently behind a green status code.</li>
<li class=""><strong>Duplicate work on retry:</strong> If you generate fresh IDs each time you re-run, you re-vectorize the same documents and pay for it twice.</li>
<li class=""><strong>Memory blowups on media:</strong> Loading a million product photos into a Python list ends your script before your batch logic ever runs.</li>
</ul>
<p>The rest of this post is what to do about each of them.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="server-side-batching">Server-side batching<a href="https://weaviate.io/blog/data-import-best-practices#server-side-batching" class="hash-link" aria-label="Direct link to Server-side batching" title="Direct link to Server-side batching" translate="no">​</a></h2>
<p>Server-side batching is a streaming import mode where the Weaviate server tells the client how much data to send next based on its own current workload. Instead of you guessing a batch size and a concurrency level, the server measures its queue depth and applies backpressure across a persistent connection.</p>
<p>This matters because the right batch size is not a constant. It depends on how many properties you have, the size of your text fields, whether you are vectorizing on the fly, what the vectorizer is doing under the hood, and what else the cluster is busy with. Hand-tuning it is brittle. The server has all of that information already.</p>
<p>Here is the pattern in the Python client:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> weaviate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">init </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Auth</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client </span><span class="token operator">=</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">connect_to_weaviate_cloud</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    cluster_url</span><span class="token operator">=</span><span class="token plain">WCD_URL</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    auth_credentials</span><span class="token operator">=</span><span class="token plain">Auth</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">api_key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">WCD_API_KEY</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">collection </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"Products"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">with</span><span class="token plain"> collection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">stream</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> row </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> iter_rows</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">add_object</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">properties</span><span class="token operator">=</span><span class="token plain">row</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">number_errors </span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token number">10</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"Too many errors, stopping."</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">break</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> collection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">failed_objects</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation builtin" style="color:rgb(189, 147, 249)">len</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation interpolation">collection</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token string-interpolation interpolation">batch</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token string-interpolation interpolation">failed_objects</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)"> objects failed."</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>That is the whole pattern. No <code>batch_size</code>, no <code>concurrent_requests</code>, no tuning. The <code>stream()</code> context manager opens the persistent connection, the server sets the rate, errors stream back asynchronously without interrupting the flow.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="error-handling-and-retries">Error handling and retries<a href="https://weaviate.io/blog/data-import-best-practices#error-handling-and-retries" class="hash-link" aria-label="Direct link to Error handling and retries" title="Direct link to Error handling and retries" translate="no">​</a></h2>
<p>The most common bug in production import scripts is treating a 200 response as proof of success. It is not. A 200 means your request reached the server and was accepted. It does not mean every object was written. Vectorizer errors, schema mismatches, and rate-limit responses from upstream embedding APIs all show up as per-object failures inside an otherwise-happy batch response.</p>
<p>The Python client surfaces three things on every batch:</p>
<ul>
<li class=""><code>batch.failed_objects</code> — every object that failed, with the error attached</li>
<li class=""><code>batch.failed_references</code> — every cross-reference that failed</li>
<li class=""><code>batch.number_errors</code> — running count inside the context manager</li>
</ul>
<p>Treat <code>failed_objects</code> as a queue. Write it to a file, retry it, and if it fails again on the same error, move it to a dead-letter location so the rest of your import does not stall behind one broken row.</p>
<p>Here is a retry-with-checkpoint pattern that holds up in production:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> json</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">util </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> generate_uuid5</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">with</span><span class="token plain"> collection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">stream</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> row </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> iter_rows</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">add_object</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            properties</span><span class="token operator">=</span><span class="token plain">row</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            uuid</span><span class="token operator">=</span><span class="token plain">generate_uuid5</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">row</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"source_id"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">with</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">open</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"failed.jsonl"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"a"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> f</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> obj </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> collection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">failed_objects</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        f</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">write</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">json</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">dumps</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token string" style="color:rgb(255, 121, 198)">"properties"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> obj</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">object_</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">properties</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token string" style="color:rgb(255, 121, 198)">"error"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> obj</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">message</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">+</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"\n"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Two things make this safe to re-run. First, <code>generate_uuid5</code> produces the same UUID for the same <code>source_id</code> every time, so a retry overwrites instead of duplicating. Second, errors land in a file you can re-import after fixing the underlying issue. No silent loss, no double-billing on embeddings.</p>
<p><img decoding="async" loading="lazy" alt="Retry-with-checkpoint flow showing successful writes to Weaviate alongside a failure branch that captures failed_objects to a JSONL file, retries with deterministic UUIDs, and dead-letters repeat failures." src="https://weaviate.io/assets/images/retry-checkpoint-flow-72dec1000e327ed02ae6119f33354733.png" width="2400" height="1064" class="img_ev3q"></p>
<p>Common failure modes and what to do about them:</p>
<table><thead><tr><th>Symptom</th><th>Likely cause</th><th>Fix</th></tr></thead><tbody><tr><td>HTTP 200, objects missing</td><td>Vectorizer rate-limited the request</td><td>Inspect <code>failed_objects</code>, retry the failed subset</td></tr><tr><td>Memory blow-up on the client</td><td>Loading the entire dataset before streaming</td><td>Stream from disk or a DB cursor, do not pre-load</td></tr><tr><td>Duplicate objects after a retry</td><td>Fresh random UUIDs on each run</td><td>Use <code>generate_uuid5</code> from a stable source key</td></tr><tr><td>Empty vectors after import</td><td>Vectorizer module not configured on the collection</td><td>Check the collection config before re-running</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ingesting-through-the-mcp-server">Ingesting through the MCP server<a href="https://weaviate.io/blog/data-import-best-practices#ingesting-through-the-mcp-server" class="hash-link" aria-label="Direct link to Ingesting through the MCP server" title="Direct link to Ingesting through the MCP server" translate="no">​</a></h2>
<p>Weaviate ships a built-in <a href="https://docs.weaviate.io/weaviate/configuration/mcp-server" target="_blank" rel="noopener noreferrer" class="">MCP server</a> (preview, added in v1.37.1) that lets an LLM or IDE assistant — Claude Code, Cursor, VS Code — read and write your instance over the <a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer" class="">Model Context Protocol</a>. Enable it with <code>MCP_SERVER_ENABLED=true</code>, opt into writes with <code>MCP_SERVER_WRITE_ACCESS_ENABLED=true</code>, and the server exposes a <code>weaviate-objects-upsert</code> tool that creates or updates objects from inside a conversation. It runs on the same port as the REST API and respects RBAC, so there is nothing extra to deploy.</p>
<p>This is the right tool when an agent needs to write a few records as it works — persisting agent memory, syncing a small collection, or fixing up a handful of objects without leaving your editor.</p>
<p>It is not an ingestion pipeline. Every object is assembled by the model and handed over as a tool call, so you are bound by the context window and per-call latency, with none of the backpressure, streaming, or retry-checkpoint machinery from the sections above. Past a few dozen objects, reach for <code>collection.batch.stream()</code> (or your client's batch API) and leave the MCP server for the conversational, small-batch writes it is built for.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="choosing-data-types-before-you-import">Choosing data types before you import<a href="https://weaviate.io/blog/data-import-best-practices#choosing-data-types-before-you-import" class="hash-link" aria-label="Direct link to Choosing data types before you import" title="Direct link to Choosing data types before you import" translate="no">​</a></h2>
<p>Schema decisions cost ten times more to fix after the import has run. Get them right the first time.</p>
<p>The ones that matter most at import time:</p>
<ul>
<li class=""><strong><code>text</code> with the right tokenization.</strong> Tokenization decides which BM25 queries match which records. The default is fine for English prose. For product codes, URLs, or anything where the literal string matters, switch to <code>field</code> tokenization. The <a href="https://docs.weaviate.io/weaviate/tutorials/tokenization" target="_blank" rel="noopener noreferrer" class="">tokenization tutorial</a> walks through the trade-offs.</li>
<li class=""><strong><code>uuid</code> for foreign keys.</strong> Indexed for fast filtering, validated at insert time, and rendered as a real UUID in your client rather than a string.</li>
<li class=""><strong><code>int</code> vs <code>number</code>.</strong> Use <code>int</code> for counts and IDs. Use <code>number</code> for prices and ratios. Mixing them up forces casts in every query.</li>
<li class=""><strong>Reference types</strong> for relationships you actually filter on. Do not flatten everything into one big nested object if you query the related fields independently.</li>
</ul>
<p>The full list is in the <a href="https://docs.weaviate.io/weaviate/config-refs/datatypes" target="_blank" rel="noopener noreferrer" class="">data types reference</a>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="blobhash-store-the-embedding-skip-the-bytes"><code>blobHash</code>: store the embedding, skip the bytes<a href="https://weaviate.io/blog/data-import-best-practices#blobhash-store-the-embedding-skip-the-bytes" class="hash-link" aria-label="Direct link to blobhash-store-the-embedding-skip-the-bytes" title="Direct link to blobhash-store-the-embedding-skip-the-bytes" translate="no">​</a></h3>
<p>If you are importing media — images, audio, video, PDFs — this is the data type to know.</p>
<p>A regular <code>blob</code> stores the full base64 payload on disk. A <code>blobHash</code> does not. It sends the raw bytes through the vectorizer at import time so the model sees the actual media, then drops everything but a SHA-256 hash. The vector index keeps the embedding. The blob storage keeps a 32-byte fingerprint.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"properties"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"name"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"product_image"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"dataType"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"blobHash"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>The practical impact: a 10 TB image corpus shrinks to a few gigabytes of hashes plus the vector index. Similarity search behaves exactly the same way it would with a <code>blob</code>. You just do not pay to store the original bytes inside Weaviate. Keep those in object storage where they belong.</p>
<p><img decoding="async" loading="lazy" alt="Side-by-side diagram comparing blob and blobHash. Both data types send raw bytes through the same vectorizer, but blob persists the full base64 payload while blobHash retains only a 32-byte SHA-256 hash — shrinking a 10 TB image corpus to a few gigabytes stored inside Weaviate." src="https://weaviate.io/assets/images/blobhash-vs-blob-1e8b10aada0f234bc156ac74b623e2fc.png" width="1800" height="1967" class="img_ev3q"></p>
<p>There is one more nice property. When you update an object, the new base64 is hashed and compared to the stored hash before anything else happens. If the hash matches, Weaviate skips re-vectorization entirely. That alone pays for itself the first time someone re-runs an import pipeline by mistake.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pdf-vectorization-without-the-ocr-pipeline">PDF vectorization without the OCR pipeline<a href="https://weaviate.io/blog/data-import-best-practices#pdf-vectorization-without-the-ocr-pipeline" class="hash-link" aria-label="Direct link to PDF vectorization without the OCR pipeline" title="Direct link to PDF vectorization without the OCR pipeline" translate="no">​</a></h2>
<p>For most readers, the practical question is "how do I ingest a folder of PDFs without writing an OCR pipeline." The shortest answer is to spin up a Weaviate Cloud trial and use Weaviate Embeddings.</p>
<p>Weaviate Embeddings has a multimodal model designed for image-based document retrieval. You hand it a page image, it produces a vector. No OCR step. No layout detection. No text extraction. Tables, charts, scanned forms, mixed-language documents all go in the same way. This is cloud-only, but it is the lowest-friction path for trying PDF retrieval on a real dataset and works well for collections up to a few hundred thousand pages without any architectural decisions on your part.</p>
<p>Another ready-made option is Google's <code>multi2vec-google</code> (with <code>gemini-embedding-2</code> at 3072 dimensions), enabled by default on Weaviate Cloud. It follows the same workflow: you render pages to images and embed those. The module takes image input, not raw PDF files, so the rasterization step is the same as with Weaviate Embeddings.</p>
<p>If you are self-hosting at scale and document layout matters, look at the <a href="https://docs.weaviate.io/weaviate/recipes/multi-vector-colipali-rag" target="_blank" rel="noopener noreferrer" class="">multi-vector ColPali recipe</a>. It uses a vision-language model to produce multiple vectors per page and skips chunking entirely. More moving parts, but it is the state of the art for retrieval over visually rich documents.</p>
<p>All three paths live in the same place — the <a href="https://docs.weaviate.io/weaviate/model-providers" target="_blank" rel="noopener noreferrer" class="">model providers reference</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="multimodal-ingestion-text-image-audio-video">Multimodal ingestion: text, image, audio, video<a href="https://weaviate.io/blog/data-import-best-practices#multimodal-ingestion-text-image-audio-video" class="hash-link" aria-label="Direct link to Multimodal ingestion: text, image, audio, video" title="Direct link to Multimodal ingestion: text, image, audio, video" translate="no">​</a></h2>
<p>Multimodal in Weaviate is not a separate product. It is a vectorizer module on the collection. You declare which model the collection uses, you import objects with media properties (ideally as <code>blobHash</code>), and you query across modalities with the same client you already have.</p>
<p>Coverage by provider:</p>
<table><thead><tr><th>Provider</th><th>Module</th><th>Text</th><th>Image</th><th>Audio</th><th>Video</th></tr></thead><tbody><tr><td>Weaviate Embeddings</td><td>native (WCD)</td><td>✓</td><td>✓</td><td></td><td></td></tr><tr><td>Google</td><td><code>multi2vec-google</code></td><td>✓</td><td>✓</td><td>✓</td><td>✓</td></tr><tr><td>Voyage AI</td><td><code>multi2vec-voyageai</code></td><td>✓</td><td>✓</td><td></td><td>✓</td></tr><tr><td>Jina AI</td><td><code>multi2vec-jinaai</code></td><td>✓</td><td>✓</td><td></td><td></td></tr><tr><td>Cohere</td><td><code>multi2vec-cohere</code></td><td>✓</td><td>✓</td><td></td><td></td></tr><tr><td>NVIDIA</td><td><code>multi2vec-nvidia</code></td><td>✓</td><td>✓</td><td></td><td></td></tr><tr><td>CLIP (self-hosted)</td><td><code>multi2vec-clip</code></td><td>✓</td><td>✓</td><td></td><td></td></tr><tr><td>ImageBind (self-hosted)</td><td><code>multi2vec-bind</code></td><td>✓</td><td>✓</td><td></td><td></td></tr></tbody></table>
<p>A concrete scenario. You are building search for an e-commerce catalog. Every product has a name, a description, three photos, and a fifteen-second demo video. You want one query — "compact wireless earbuds with active noise cancellation" — to find the right product whether the relevant signal is in the text, the photo, or the video.</p>
<p>You declare one collection that uses <code>multi2vec-google</code> across named vectors: a text vector over the name and description, plus a separate <code>blobHash</code> vector for the product image and another for the demo video. Each <code>blobHash</code> property needs its own named vector — once Weaviate replaces the raw bytes with a hash, they can no longer be re-vectorized alongside other fields, so the schema keeps them apart. A single multi-target query then ranks across all three vectors at once: one collection, one query, three modalities — and the media bytes are never stored twice inside Weaviate.</p>
<p>Full setup details for every provider are in the <a href="https://docs.weaviate.io/weaviate/model-providers" target="_blank" rel="noopener noreferrer" class="">model providers reference</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-checklist-before-you-press-go">A checklist before you press go<a href="https://weaviate.io/blog/data-import-best-practices#a-checklist-before-you-press-go" class="hash-link" aria-label="Direct link to A checklist before you press go" title="Direct link to A checklist before you press go" translate="no">​</a></h2>
<ol>
<li class="">Pick data types deliberately. <code>blobHash</code> for any media you do not need to retrieve raw. <code>field</code> tokenization for any text where the literal string matters.</li>
<li class="">Pick the vectorizer at the collection level, not in your import script. Weaviate Embeddings is the easiest default on Weaviate Cloud.</li>
<li class="">Use deterministic UUIDs (<code>generate_uuid5</code> from a stable source key) so retries are idempotent.</li>
<li class="">Use server-side batching via <code>collection.batch.stream()</code> if you are on the Python client.</li>
<li class="">Log <code>failed_objects</code> to a dead-letter file. Do not just print them.</li>
<li class="">Checkpoint progress for large jobs so a crash does not cost you the whole run.</li>
<li class="">If you are importing media at scale, keep the source bytes in object storage and let Weaviate keep the hash, not the file.</li>
</ol>
<p>Do these seven things and you will not be the team rewriting their import script for the third time next quarter.</p>
<p>The fastest way to try any of this is a <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">free Weaviate Cloud trial</a> paired with Weaviate Embeddings. No infrastructure to manage, no embedding API keys, and every snippet in this post runs against it without modification. The <a href="https://docs.weaviate.io/weaviate/tutorials/import" target="_blank" rel="noopener noreferrer" class="">import tutorial</a> is a good next stop once you have a cluster up.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/data-import-best-practices#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=data-import-best-practices&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Ivan Despot</name>
            <uri>https://www.linkedin.com/in/ivan-g-despot/</uri>
        </author>
        <author>
            <name>Tommy Smith</name>
            <uri>https://github.com/tsmith023</uri>
        </author>
        <category label="how-to" term="how-to"/>
        <category label="engineering" term="engineering"/>
        <category label="concepts" term="concepts"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Weaviate Cloud is now free to start]]></title>
        <id>https://weaviate.io/blog/weaviate-free-tier</id>
        <link href="https://weaviate.io/blog/weaviate-free-tier"/>
        <updated>2026-06-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Weaviate Cloud is now free to start across the entire product suite.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Hero image" src="https://weaviate.io/assets/images/hero-7e23f1bcec767c4354a06f1686768a05.png" width="1200" height="630" class="img_ev3q"></p>
<p>For years, the most common question we got was some version of "Does Weaviate have a free tier?" And for years, my sincere answer was a little awkward: Weaviate has always been free. It's open source, and anyone can run Weaviate on their local machines or own clouds without paying us a cent.</p>
<p>And people do, at an incredible scale. Today, we see many millions of active Weaviate databases running every single month, and our client downloads are rapidly approaching double-digit millions.</p>
<p>So whenever someone asked for a free tier on Weaviate Cloud, part of me wanted to say: “You already have one, go run it yourself.” For a long time, this felt like a complete and principled answer. We didn't want to build a watered-down hosted version just to have a "Free" button on the pricing page when the most powerful free option, the actual open-source database, was already sitting right there.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-changed">What changed<a href="https://weaviate.io/blog/weaviate-free-tier#what-changed" class="hash-link" aria-label="Direct link to What changed" title="Direct link to What changed" translate="no">​</a></h2>
<p>Then we stopped being only a database.</p>
<p>Over the past two years, Weaviate grew into a platform. We built the <a href="https://weaviate.io/product/query-agent" target="_blank" rel="noopener noreferrer" class="">Query Agent</a> so you can ask questions of your data in natural language without orchestrating retrieval yourself. We built <a href="https://weaviate.io/product/engram" target="_blank" rel="noopener noreferrer" class="">Engram</a>, a managed memory layer so your agents can actually remember and improve over time. These aren't things you spin up from a docker run, but cloud-native services that we operate, scale and maintain.</p>
<p>So while "Just run the open source version" is sound advice for the database, it doesn't work for Query Agent or Engram because they are cloud services. And we introduced free tiers for these products so that all of our products are free to try. Despite this, the managed Weaviate database on Cloud remained without complete parity in this respect and offered a time-limited sandbox.</p>
<p>This didn’t quite sit right, because if we are going to build and scale a platform, the way in should be free across its entirety.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="free-tiers-across-the-whole-platform">Free tiers across the whole platform<a href="https://weaviate.io/blog/weaviate-free-tier#free-tiers-across-the-whole-platform" class="hash-link" aria-label="Direct link to Free tiers across the whole platform" title="Direct link to Free tiers across the whole platform" translate="no">​</a></h2>
<p>So that's what we're announcing today. Weaviate Cloud is now free to start across the entire product suite. The Database, Query Agent, and Engram are all available as free tiers.</p>
<p>The Weaviate Cloud managed database is now genuinely free, without a credit card or time expiration. It’s the same Weaviate you know and love, with enough room to build a serious prototype, and stays on as long as you’re using it.</p>
<p>(If you're curious about the exact allowances, they're all on the <a href="https://weaviate.io/pricing" target="_blank" rel="noopener noreferrer" class="">pricing page</a>.)</p>
<p>This is the parity we've wanted for a while across all of our products and we are ecstatic to share the change with you.</p>
<p>That shift from "free until the clock runs out" to "free as long as it's useful to you" is the right direction. A free tier should be a place you can actually settle into and build and not a sprint against an expiry date.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="when-youre-ready-for-more">When you're ready for more<a href="https://weaviate.io/blog/weaviate-free-tier#when-youre-ready-for-more" class="hash-link" aria-label="Direct link to When you're ready for more" title="Direct link to When you're ready for more" translate="no">​</a></h2>
<p>At some point your project outgrows the free tier, with more data, traffic, and real users. When that happens, you can easily upgrade your free cluster to a pay-as-you-go cluster that can scale up. No migration or re-architecting is required, and you can ship what you’ve prototyped.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="start-building">Start building<a href="https://weaviate.io/blog/weaviate-free-tier#start-building" class="hash-link" aria-label="Direct link to Start building" title="Direct link to Start building" translate="no">​</a></h2>
<p>If you've been waiting for a reason to try Weaviate Cloud in any of our products, this is the moment: Go build something. We can't wait to see what you make.</p>
<p>- <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Sign up for free</a><br>
<!-- -->- <a href="https://docs.weaviate.io/cloud/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart guide</a><br>
<!-- -->- <a href="https://weaviate.io/pricing" target="_blank" rel="noopener noreferrer" class="">See what's included</a></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/weaviate-free-tier#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=weaviate-free-tier&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Bob van Luijt</name>
            <uri>https://github.com/bobvanluijt</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Engram is now Generally Available]]></title>
        <id>https://weaviate.io/blog/engram-generally-available</id>
        <link href="https://weaviate.io/blog/engram-generally-available"/>
        <updated>2026-06-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Engram, Weaviate's managed memory and context service for agentic applications, is now generally available.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Hero image announcing Engram is now generally available" src="https://weaviate.io/assets/images/hero-7f1bf81fca9bd1c6c21775fbaa3be943.png" width="1200" height="630" class="img_ev3q"></p>
<p>We're thrilled to announce that Engram is now generally available. Engram is our managed memory and context service, purpose-built to help agents orchestrate workflows, learn from experience, and anchor decisions to trusted knowledge. If you've been following our work on memory for agents — from the conceptual framing in <a href="https://weaviate.io/blog/limit-in-the-loop" target="_blank" rel="noopener noreferrer" class="">The Limit in the Loop</a> to the <a href="https://weaviate.io/blog/engram-deep-dive" target="_blank" rel="noopener noreferrer" class="">architectural deep dive</a> — today is the day that we open our doors for you to start building with Engram.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="memory-is-infrastructure">Memory is infrastructure<a href="https://weaviate.io/blog/engram-generally-available#memory-is-infrastructure" class="hash-link" aria-label="Direct link to Memory is infrastructure" title="Direct link to Memory is infrastructure" translate="no">​</a></h2>
<p>Agents we build are supposed to compound in value over time. They should build up interactions, accumulate context, and get more useful the longer they run. In practice, however, this value compounding does not happen, and agent usage may even backfire, due to three failure modes:</p>
<ul>
<li class=""><strong>Long-context degradation.</strong> Sending whole conversations back to models on every turn drives up latency and cost. More importantly, this can cause answer quality to drop in the middle of long inputs even with state-of-the-art context windows.</li>
<li class=""><strong>Messy raw data.</strong> User interactions are noisy and facts evolve over time. Piling raw events into a data store and asking an LLM to reconcile them at query time pushes the hardest part of the problem to the worst place for solving it.</li>
<li class=""><strong>Multi-agent context fragmentation.</strong> The moment a single request crosses agents, built-in memory patterns collapse. Instead shared memory that's persistent and scoped is required to orchestrate workflows beyond single-agent loops.</li>
</ul>
<p>These problems sit on the critical path to success for any production-grade agent and are deeply structural. The solution is not a patch at the prompt layer, but rather systematic memory and context management. Memory mustn't be a superficial bolt-on but should be treated as a deliberate infrastructure component in the same way that storage, retrieval, and observability are.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-engram-is">What Engram is<a href="https://weaviate.io/blog/engram-generally-available#what-engram-is" class="hash-link" aria-label="Direct link to What Engram is" title="Direct link to What Engram is" translate="no">​</a></h2>
<p>Engram is a managed service that turns raw, noisy agent events into structured, durable, scoped memories, and serves them back through Weaviate's hybrid semantic and keyword retrieval. It is a memory layer you can trust that inherits the maturity of the Weaviate database.</p>
<p>Asynchronous pipelines run in the background to extract relevant information, reconcile it against what's already known while handling deduplication, preference changes, and time-evolving facts, and persist a clean memory state. Use-case templates for personalization are available day one with templates for continual learning, and multi-agent state available in the following weeks. Teams that outgrow them can drop down to direct pipeline control without leaving the platform. For the architecture in detail — pipelines, topics, scopes, and buffers — see the <a href="https://weaviate.io/blog/engram-deep-dive" target="_blank" rel="noopener noreferrer" class="">Engram deep dive</a>.</p>
<p>The road from preview to GA was shaped by real-world use cases; putting Engram into different situations surfaced the changes that define production-ready: more durable pipelines, more efficient extractions and transforms, and deterministic reconciliation that avoids memory drift. This hardening lies beneath everything you get with Engram:</p>
<ul>
<li class=""><strong>Actively maintained memory instead of an ever-growing context blob.</strong> Pipelines extract, deduplicate, and reconcile against what's already known, so the memory state stays clean as interactions accumulate.</li>
<li class=""><strong>Fire-and-forget at the application layer.</strong> Memory pipelines run asynchronously and durably in the background; the hot path is never blocked on memory I/O. Backed by Temporal-grade durability so partial failures recover cleanly and commits stay atomic.</li>
<li class=""><strong>Templates for the common case, primitives for everything else.</strong> Personalization, continual learning, and multi-agent state ship as ready-to-deploy templates. Teams that need more control drop into the underlying pipeline primitives without changing platforms.</li>
<li class=""><strong>Built-in scopes from day one.</strong> Per-project, per-user, and per-property isolation is part of the primitive (not a feature flag bolted on later), so the right memories are visible to the right caller by construction.</li>
<li class=""><strong>Unified retrieval on Weaviate.</strong> Memory inherits Weaviate's hybrid search, scaling characteristics, and operational track record. There's no parallel system to deploy, secure, or operate.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="who-should-use-engram">Who should use Engram<a href="https://weaviate.io/blog/engram-generally-available#who-should-use-engram" class="hash-link" aria-label="Direct link to Who should use Engram" title="Direct link to Who should use Engram" translate="no">​</a></h2>
<p>Engram is for teams whose agents have outgrown a single turn: assistants that should remember a user across sessions, agents that should get better from feedback instead of repeating mistakes, and multi-agent systems that need to share scoped state. If you're building one of these, you've almost certainly built some version of memory yourself.</p>
<p>It usually starts as one of a few things: sending whole conversations back to the model on every turn, hand-pruning a <code>MEMORY.md</code>, storing raw events as memory directly inside a data store, or running a standalone memory provider alongside your retrieval stack. Each works for a window of complexity before breaking due to the reasons above: degrading context with growth, unreconciled raw data, and fragmenting memory across multiple agents.</p>
<p>Engram is what's on the other side of that break: active reconciliation instead of accumulation, durable pipelines instead of synchronous side effects, and one platform for memory and retrieval instead of two.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="get-started-with-engram">Get started with Engram<a href="https://weaviate.io/blog/engram-generally-available#get-started-with-engram" class="hash-link" aria-label="Direct link to Get started with Engram" title="Direct link to Get started with Engram" translate="no">​</a></h2>
<p>Engram is now generally available in <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a>. Start compounding your agents' value today with our free tier.</p>
<p>Spin up your first project in a few clicks:</p>
<figure style="margin:2rem auto"><img src="https://weaviate.io/assets/images/engram-create-48f43417fccbac08b8efaa1377dbb90b.png" alt="Creating a new Engram project in the Weaviate Cloud console" style="max-width:100%;display:block;margin:0 auto;border:1px solid var(--ifm-color-emphasis-200);border-radius:8px"><figcaption style="text-align:center;font-size:0.9rem;color:var(--ifm-color-emphasis-600);margin-top:0.5rem">Create a new Engram project.</figcaption></figure>
<figure style="margin:2rem auto"><img src="https://weaviate.io/assets/images/engram-overview-ce818eb9b29d30ccd9dd2f6778ff9198.png" alt="The Engram project dashboard, showing the default group with its topics and the extract-transform-commit pipeline" style="max-width:100%;display:block;margin:0 auto;border:1px solid var(--ifm-color-emphasis-200);border-radius:8px"><figcaption style="text-align:center;font-size:0.9rem;color:var(--ifm-color-emphasis-600);margin-top:0.5rem">The project dashboard.</figcaption></figure>
<ul>
<li class="">Read the <a href="https://docs.weaviate.io/engram" target="_blank" rel="noopener noreferrer" class="">Engram documentation</a></li>
<li class="">For the full architecture story, see the <a href="https://weaviate.io/blog/engram-deep-dive" target="_blank" rel="noopener noreferrer" class="">Engram deep dive</a></li>
<li class="">Subscribe to the <a href="https://events.weaviate.io/weaviate-agents-newsletter" target="_blank" rel="noopener noreferrer" class="">Weaviate Agents newsletter</a> for product updates and best practices</li>
</ul>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/engram-generally-available#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=engram-generally-available&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Charles Pierse</name>
            <uri>https://github.com/cdpierse</uri>
        </author>
        <author>
            <name>Yaru Lin</name>
            <uri>mailto:yaru@weaviate.io</uri>
        </author>
        <category label="release" term="release"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Leveling up Weaviate Cloud security: Expanding role-based access control for Cloud console]]></title>
        <id>https://weaviate.io/blog/rbac-overview</id>
        <link href="https://weaviate.io/blog/rbac-overview"/>
        <updated>2026-05-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Weaviate Cloud now supports more granular role-based access control with new Editor and Viewer roles for improved security and organizational management.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Leveling up Weaviate Cloud security" src="https://weaviate.io/assets/images/hero-229c3b8452ed90541cf952c6692901f7.png" width="1200" height="630" class="img_ev3q"></p>
<p>You can now assign more granular roles to users in your Weaviate Cloud organization. We are expanding role-based access control (RBAC) for the Cloud console with two new roles — <strong>Editor</strong> and <strong>Viewer</strong> — that add to the existing <strong>Owner</strong> and <strong>Admin</strong> roles, giving organizations more control over resource access.</p>
<p>Role-based access control is a security best practice and a standard feature in modern cloud platforms. It provides a structured way to grant, organize, and delegate permissions across the people and applications working with your cloud resources. RBAC reduces the risk of accidental changes, limits the blast radius of mistakes, and gives security and platform teams the clarity they need to scale Weaviate Cloud usage across an organization.</p>
<p>By assigning Editor or Viewer roles instead of sharing full access, organizations can apply the principle of least privilege, ensuring team members have only the access they need to do their jobs. This applies whether you're a small team of developers or an enterprise rolling out Weaviate across multiple business units.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="weaviate-cloud-roles-and-use-cases">Weaviate Cloud roles and use cases<a href="https://weaviate.io/blog/rbac-overview#weaviate-cloud-roles-and-use-cases" class="hash-link" aria-label="Direct link to Weaviate Cloud roles and use cases" title="Direct link to Weaviate Cloud roles and use cases" translate="no">​</a></h2>
<p>Within a Weaviate Cloud organization, every user can be assigned one of four roles. Each role grants a specific set of permissions across organization settings, billing, cluster management, and access to cluster data.</p>
<table><thead><tr><th style="text-align:left">Owner</th><th style="text-align:left">Admin</th></tr></thead><tbody><tr><td style="text-align:left">Full access to everything in the organization, including billing, user management, and the ability to invite other users as Owners. The person who creates the organization is automatically assigned this role. <br><br> Owners are the only role that can promote other users to Owner. Typically reserved for the small group of people responsible for the organization end-to-end.</td><td style="text-align:left">Manages clusters, billing, and day-to-day organization activity. Admins can invite new users to the organization (but not as Owners) and have full control over cluster creation, configuration, and deletion. <br><br> This is the right role for senior engineers, platform leads, or anyone who needs to operate Weaviate Cloud without the ability to reshape ownership.</td></tr><tr><td style="text-align:left"><strong>Editor</strong> <em>(New)</em></td><td style="text-align:left"><strong>Viewer</strong> <em>(New)</em></td></tr><tr><td style="text-align:left">Manages clusters without touching billing or user invitations. Editors can create, configure, modify, and delete clusters but cannot change billing information or invite new users to the organization. <br><br> This role fits engineers building on Weaviate day-to-day who don't need to manage the organization itself.</td><td style="text-align:left">Read-only access. Viewers can see clusters, configurations, and organization details, but cannot make any changes. <br><br> This is the right role for stakeholders who need visibility — security reviewers, finance partners, or observers from other teams — without the ability to alter anything.</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-manage-roles-in-weaviate-cloud">How to manage roles in Weaviate Cloud<a href="https://weaviate.io/blog/rbac-overview#how-to-manage-roles-in-weaviate-cloud" class="hash-link" aria-label="Direct link to How to manage roles in Weaviate Cloud" title="Direct link to How to manage roles in Weaviate Cloud" translate="no">​</a></h2>
<p>Managing roles in Weaviate Cloud takes just a few clicks.</p>
<ol>
<li class=""><strong>Open your organization menu.</strong> At the top of the Weaviate Cloud console, click the <em>Organization</em> dropdown.</li>
<li class=""><strong>Select Organization settings.</strong> From the dropdown, choose <em>Organization settings</em> to open your organization's management page.</li>
<li class=""><strong>Manage users and roles.</strong> Under the <em>Users and Access</em> section, you'll see every member of your organization, their assigned role, and a description of what each role can do. From here you can:<!-- -->
<ul>
<li class="">Click <em>+ Add User</em> to invite a new member and assign their role during invitation</li>
<li class="">Change an existing user's role using the role selector</li>
<li class="">Remove a user from the organization</li>
</ul>
</li>
</ol>
<p>Changes take effect immediately. Users will see their new permissions on their next action in the console.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>Every organization must have at least one Owner at all times. If you're the only Owner, you'll need to assign Owner permissions to another member before you can leave or delete the organization.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="learn-more">Learn more<a href="https://weaviate.io/blog/rbac-overview#learn-more" class="hash-link" aria-label="Direct link to Learn more" title="Direct link to Learn more" translate="no">​</a></h2>
<p>If you're ready to start using granular roles in your own organization, sign in to Weaviate Cloud and head to your organization settings. To dive deeper, check out the <a href="https://docs.weaviate.io/cloud/platform/users-and-organizations#user-roles" target="_blank" rel="noopener noreferrer">product documentation</a>.</p>
<p>Have questions or feedback? Join the conversation in our Community Forums or reach us at <a href="mailto:support@weaviate.io" target="_blank" rel="noopener noreferrer" class="">support@weaviate.io</a>.</p>]]></content>
        <author>
            <name>Brandon Holwerda</name>
        </author>
        <author>
            <name>Yaru Lin</name>
            <uri>mailto:yaru@weaviate.io</uri>
        </author>
        <category label="security" term="security"/>
        <category label="cloud" term="cloud"/>
        <category label="rbac" term="rbac"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Build a Coding Assistant with Weaviate MCP: RAG over Code & Docs]]></title>
        <id>https://weaviate.io/blog/coding-assistant-weaviate-mcp</id>
        <link href="https://weaviate.io/blog/coding-assistant-weaviate-mcp"/>
        <updated>2026-05-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Use Weaviate's built-in MCP server to give Claude Code, Cursor, and VS Code hybrid search over your codebase and docs. No glue code.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Coding assistant with Weaviate MCP server: hybrid search RAG over your codebase and documentation" src="https://weaviate.io/assets/images/hero-a54bc5be1b7e33c82e4f7a9ce0aaefc7.png" width="1200" height="630" class="img_ev3q"></p>
<br>
<p>Last week I asked <a href="https://docs.claude.com/en/docs/claude-code/" target="_blank" rel="noopener noreferrer" class="">Claude Code</a> to implement something relatively trivial in my codebase. Three turns in, the conversation used up &gt;80K tokens and Claude was still missing some crucial information I'd forgotten to include. That's the loop you fall into without retrieval: paste too little and the agent guesses, paste too much and pay for context the agent isn't using.</p>
<p>Most teams solve this with <a class="" href="https://weaviate.io/blog/introduction-to-rag">RAG</a> over the codebase. The typical setup is a vector database plus a custom MCP server process bridging the two. Weaviate simplifies this: the <a href="https://docs.weaviate.io/weaviate/mcp/mcp-server" target="_blank" rel="noopener noreferrer" class="">MCP server is built into the database</a>, at <code>/v1/mcp</code> on the same port as the REST API. One env var enables it. The same <a href="https://docs.weaviate.io/weaviate/concepts/search/hybrid-search" target="_blank" rel="noopener noreferrer" class="">hybrid search</a> you'd use for any other Weaviate workload powers code retrieval, with the <a href="https://docs.weaviate.io/weaviate/search/bm25" target="_blank" rel="noopener noreferrer" class="">BM25</a> half keeping function identifiers like <code>connect_to_local</code> matchable and the vector half finding semantic intent like "how do I init a client."</p>
<p>This post walks through building a coding assistant on top of that built-in MCP server: ingest a codebase, ingest its docs, connect Claude Code, Cursor, and VS Code, and run real queries. Topics covered:</p>
<ul>
<li class=""><a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#why-your-coding-assistant-needs-more" class="">Why your coding assistant needs more than its training data</a></li>
<li class=""><a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#why-weaviate-mcp-fits" class="">Why Weaviate MCP fits this job</a></li>
<li class=""><a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-1-run-weaviate" class="">Step 1: Run Weaviate with MCP enabled</a></li>
<li class=""><a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-2-design-the-schema" class="">Step 2: Design the schema</a></li>
<li class=""><a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-3-ingest-codebase" class="">Step 3: Chunk and ingest the codebase</a></li>
<li class=""><a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-4-ingest-docs" class="">Step 4: Chunk and ingest documentation</a></li>
<li class=""><a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-5-connect-clients" class="">Step 5: Connect Claude Code, Cursor, and VS Code</a></li>
<li class=""><a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#try-it-out" class="">Try it out</a></li>
<li class=""><a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#agent-runbook" class="">Agent runbook: autonomous setup</a></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-your-coding-assistant-needs-more">Why your coding assistant needs more than its training data<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#why-your-coding-assistant-needs-more" class="hash-link" aria-label="Direct link to Why your coding assistant needs more than its training data" title="Direct link to Why your coding assistant needs more than its training data" translate="no">​</a></h2>
<p>LLMs ship with a fixed cutoff and zero knowledge of your private code. The naive workaround is to dump files into the prompt. That has three problems.</p>
<ul>
<li class="">
<p><strong>Cost</strong>: Tokens in context are billed. Every turn. A 200-file Python project doesn't fit, and even the parts that do are billed continuously while the agent reasons.</p>
</li>
<li class="">
<p><strong>Stale context</strong>: Once a file is in the prompt, it's frozen. If the agent changes a function and then needs to read it again, it has to reload the whole file. There's no live link between the model's view and the on-disk truth.</p>
</li>
<li class="">
<p><strong>Wrong granularity</strong>: Even when files fit, the model spends attention on the wrong parts. Imports. Module-level boilerplate. The function the agent is actually editing competes for context with a hundred lines of <code>from x import y</code>.</p>
</li>
</ul>
<p>Retrieval solves all three. Index the codebase once, store the chunks in a vector database, and let the LLM client pull only what it needs per query. That's RAG. Coding assistants haven't had a clean way to talk to such a database without a custom shim. That's where MCP comes in.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-weaviate-mcp-fits">Why Weaviate MCP fits this job<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#why-weaviate-mcp-fits" class="hash-link" aria-label="Direct link to Why Weaviate MCP fits this job" title="Direct link to Why Weaviate MCP fits this job" translate="no">​</a></h2>
<p><a href="https://modelcontextprotocol.io/docs/develop/build-server" target="_blank" rel="noopener noreferrer" class="">The Model Context Protocol</a> (MCP) is the standardized way for LLM clients like Claude Code, Cursor, and VS Code to call out to external tools. Weaviate <code>v1.37.1</code> exposes its core operations as MCP tools directly, on a <a href="https://modelcontextprotocol.io/docs/concepts/transports#streamable-http" target="_blank" rel="noopener noreferrer" class="">Streamable HTTP endpoint</a> at <code>/v1/mcp</code>. Four tools are surfaced:</p>
<ul>
<li class=""><code>weaviate-collections-get-config</code> — let the LLM inspect what collections exist and what properties they have</li>
<li class=""><code>weaviate-tenants-list</code> — list tenants when you're using multi-tenancy</li>
<li class=""><code>weaviate-query-hybrid</code> — run hybrid (BM25 + vector) search</li>
<li class=""><code>weaviate-objects-upsert</code> — write objects back, only when write access is enabled</li>
</ul>
<p>Hybrid search is the most concrete reason this stack works for a coding assistant. Code is a mix of identifiers and intent. BM25 nails the identifiers. Vectors nail the intent. A query like "where do we handle retry on 429?" wants both at once: vectors find the semantically related retry code, BM25 anchors on <code>429</code> as an exact token. Pure-vector retrieval drops the integer match. Pure-BM25 misses any wording the user didn't already know. Hybrid wins on this kind of mixed-intent query.</p>
<p>Operational simplicity is the second reason. Competing stacks run an MCP server alongside the vector database. That's a second service to watch in production. Weaviate ships the MCP server inside the database, on the same port, with the same auth. The thing you have to monitor is just Weaviate.</p>
<p>The third reason is <a href="https://docs.weaviate.io/weaviate/manage-collections/multi-tenancy" target="_blank" rel="noopener noreferrer" class="">multi-tenancy</a>. One Weaviate instance can hold many codebases, each isolated as a tenant. For an organization with multiple repos, that's one cluster instead of one-per-team.</p>
<p><code>Weaviate MCP vs function calling</code> comes up as a natural question. Function calling is per-LLM-API. MCP is transport-level: any client that speaks MCP can call any server that speaks MCP, no rewrites. Build the retrieval once, use it from Claude Code, Cursor, and VS Code without translating.</p>
<p><img decoding="async" loading="lazy" alt="Architecture: Claude Code, Cursor, and VS Code connecting via MCP to Weaviate, which ingests source code and documentation chunks" src="https://weaviate.io/assets/images/architecture-173a7b0887d259eeb9e04535538b7958.png" width="1800" height="900" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-run-weaviate">Step 1: Run Weaviate with MCP enabled<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-1-run-weaviate" class="hash-link" aria-label="Direct link to Step 1: Run Weaviate with MCP enabled" title="Direct link to Step 1: Run Weaviate with MCP enabled" translate="no">​</a></h2>
<p>The MCP server is disabled by default. Two environment variables turn it on:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># docker-compose.yml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">services</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> cr.weaviate.io/semitechnologies/weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">1.38.8</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">ports</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'8080:8080'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(248, 248, 242)">-</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'50051:50051'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">environment</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token key atrule">MCP_SERVER_ENABLED</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'true'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token key atrule">MCP_SERVER_WRITE_ACCESS_ENABLED</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'true'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token key atrule">AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'true'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token key atrule">DEFAULT_VECTORIZER_MODULE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'text2vec-openai'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token key atrule">ENABLE_MODULES</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'text2vec-openai'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token key atrule">OPENAI_APIKEY</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain">OPENAI_APIKEY</span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p><code>MCP_SERVER_ENABLED</code> exposes the read tools (config, tenants, hybrid query). <code>MCP_SERVER_WRITE_ACCESS_ENABLED</code> adds the upsert tool, which lets the agent write findings back. Skip it if you only want retrieval.</p>
<p>Honestly, I'd skip it for a while even if you think you want write-back. Read-only MCP covers most of what a coding agent actually does, and you sidestep a class of failure modes where the agent writes nonsense back into your knowledge base. Turn write access on once you have a specific use case that justifies the risk.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Auth for production</div><div class="admonitionContent_BuS1"><p>This example uses <code>AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'</code> so the post stays focused on the MCP wiring. For any networked deployment, enable an API key and add <code>Authorization: Bearer &lt;key&gt;</code> to your client config — Weaviate's MCP server respects standard auth and RBAC. See <a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#going-further" class="">§"Going further"</a> for the RBAC permissions involved.</p></div></div>
<p>Bring it up and confirm the endpoint is alive. Streamable HTTP requires an <code>initialize</code> handshake before any other call, so the liveness probe sends one:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">docker compose up -d</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">curl -sf -X POST http://localhost:8080/v1/mcp \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H 'Content-Type: application/json' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H 'Accept: application/json, text/event-stream' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -d '{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "jsonrpc":"2.0","id":0,"method":"initialize",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "params":{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "protocolVersion":"2025-03-26",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "capabilities":{},</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "clientInfo":{"name":"curl","version":"1"}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }'</span><br></span></code></pre></div></div>
<p>A live MCP server returns a JSON-RPC envelope describing the server's capabilities and sets an <code>Mcp-Session-Id</code> response header that subsequent calls must echo back. You don't need to parse the body for a sanity check — a non-empty response is enough. If you get a connection refused or a 404, MCP isn't enabled.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-design-the-schema">Step 2: Design the schema<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-2-design-the-schema" class="hash-link" aria-label="Direct link to Step 2: Design the schema" title="Direct link to Step 2: Design the schema" translate="no">​</a></h2>
<p>Two collections, one for code chunks and one for documentation chunks, sharing the same Weaviate instance:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> weaviate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">config </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Configure</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client </span><span class="token operator">=</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">connect_to_local</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"CodeChunks"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"content"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"symbol"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">LOWERCASE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"file_path"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FIELD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"language"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FIELD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"repo"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FIELD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    vector_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Vectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text2vec_openai</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"DocChunks"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"content"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"title"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"source_url"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FIELD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    vector_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Vectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text2vec_openai</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>The <a href="https://docs.weaviate.io/weaviate/concepts/indexing/inverted-index#tokenization" target="_blank" rel="noopener noreferrer" class="">tokenization choices matter</a>. <code>symbol</code> uses <code>lowercase</code> so <code>connect_to_local</code> is one token instead of three. <code>file_path</code>, <code>language</code>, and <code>repo</code> use <code>field</code> so they match exactly. Prose properties (<code>content</code>, <code>title</code>) use <code>word</code>. If this section feels familiar, the <a class="" href="https://weaviate.io/blog/tokenization-text-analysis-weaviate">tokenization post</a> explains why each method belongs where.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-ingest-codebase">Step 3: Chunk and ingest the codebase<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-3-ingest-codebase" class="hash-link" aria-label="Direct link to Step 3: Chunk and ingest the codebase" title="Direct link to Step 3: Chunk and ingest the codebase" translate="no">​</a></h2>
<p>Naive line-based chunking destroys code. A function split across two chunks loses its signature on one side and its body on the other. The fix is to chunk along syntactic boundaries: one chunk per function, one per class, one per top-level statement.</p>
<p>Python's standard library is enough for Python code (no extra dependency). For other languages, <a href="https://tree-sitter.github.io/tree-sitter/" target="_blank" rel="noopener noreferrer" class="">tree-sitter</a> is the standard choice (10+ languages, AST-aware, fast).</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> ast</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> pathlib </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Path</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">chunk_python_file</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">path</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> Path</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">-</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">list</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token builtin" style="color:rgb(189, 147, 249)">dict</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(255, 121, 198)">"""Emit one chunk per top-level function or class."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    source </span><span class="token operator">=</span><span class="token plain"> path</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">read_text</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    tree </span><span class="token operator">=</span><span class="token plain"> ast</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">parse</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">source</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    lines </span><span class="token operator">=</span><span class="token plain"> source</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">splitlines</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    chunks </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> node </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> ast</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">iter_child_nodes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">isinstance</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ast</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FunctionDef</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> ast</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">AsyncFunctionDef</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> ast</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ClassDef</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            start </span><span class="token operator">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">lineno </span><span class="token operator">-</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            end </span><span class="token operator">=</span><span class="token plain"> node</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">end_lineno</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            chunks</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">append</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token string" style="color:rgb(255, 121, 198)">"content"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"\n"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">join</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">lines</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain">start</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">end</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token string" style="color:rgb(255, 121, 198)">"symbol"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> node</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">name</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token string" style="color:rgb(255, 121, 198)">"file_path"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">str</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">path</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token string" style="color:rgb(255, 121, 198)">"language"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"python"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token string" style="color:rgb(255, 121, 198)">"repo"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"my-service"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> chunks</span><br></span></code></pre></div></div>
<p>Ingest with <a href="https://docs.weaviate.io/weaviate/manage-objects/import#server-side-batching" target="_blank" rel="noopener noreferrer" class="">server-side batching</a>. <code>data.ingest()</code> takes any iterable, so a generator expression over the repo streams chunks to the server as they are produced, at whatever pace the server asks for:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">code_chunks </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">use</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"CodeChunks"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">code_chunks</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ingest</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    chunk</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> py_file </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> Path</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"./src"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rglob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"*.py"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> chunk </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> chunk_python_file</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">py_file</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Requires Python client 4.20+</div></div>
<p>Weaviate vectorizes each chunk on insert via the configured <a href="https://docs.weaviate.io/weaviate/model-providers/openai/embeddings" target="_blank" rel="noopener noreferrer" class=""><code>text2vec-openai</code></a> module, so there's no separate embedding step. Replace the vectorizer with <code>text2vec-voyageai</code> (Voyage's <code>voyage-code-2</code> is purpose-built for code) or <code>text2vec-cohere</code> if you want a different embedding family.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-ingest-docs">Step 4: Chunk and ingest documentation<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-4-ingest-docs" class="hash-link" aria-label="Direct link to Step 4: Chunk and ingest documentation" title="Direct link to Step 4: Chunk and ingest documentation" translate="no">​</a></h2>
<p>Prose chunks differently. Headings are real boundaries. A useful default is "split on H2, then on H3 if a section is too long":</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> re</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(80, 250, 123)">chunk_markdown</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">text</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">str</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> max_chars</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">int</span><span class="token plain"> </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">1500</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">-</span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">list</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token builtin" style="color:rgb(189, 147, 249)">str</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    sections </span><span class="token operator">=</span><span class="token plain"> re</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">split</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">r"(?m)^## "</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> text</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    chunks </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> section </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> sections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">len</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">section</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">&lt;=</span><span class="token plain"> max_chars</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            chunks</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">append</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">section</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">strip</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">else</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> sub </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> re</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">split</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">r"(?m)^### "</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> section</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                chunks</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">append</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">sub</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">strip</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain">c </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> c </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> chunks </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> c</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">doc_chunks </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">use</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"DocChunks"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">doc_chunks</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ingest</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token string" style="color:rgb(255, 121, 198)">"content"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> content</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token string" style="color:rgb(255, 121, 198)">"title"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> md_file</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">stem</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token string" style="color:rgb(255, 121, 198)">"source_url"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"https://docs.example.com/</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">md_file</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token string-interpolation interpolation">stem</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> md_file </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> Path</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"./docs"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rglob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"*.md"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> content </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> chunk_markdown</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">md_file</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">read_text</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Two collections, two chunking strategies, one Weaviate instance. The MCP server exposes both through the same <code>weaviate-query-hybrid</code> tool. The agent picks which collection to query.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-5-connect-clients">Step 5: Connect Claude Code, Cursor, and VS Code<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-5-connect-clients" class="hash-link" aria-label="Direct link to Step 5: Connect Claude Code, Cursor, and VS Code" title="Direct link to Step 5: Connect Claude Code, Cursor, and VS Code" translate="no">​</a></h2>
<p>The MCP transport is HTTP, so client config is small. Each client has its own file. All three point at the same Weaviate endpoint.</p>
<p><strong><a href="https://code.claude.com/docs/en/mcp" target="_blank" rel="noopener noreferrer" class="">Claude Code</a></strong> (<code>~/.claude.json</code>):</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"mcpServers"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"weaviate"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"type"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"http"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"url"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"http://localhost:8080/v1/mcp"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>Or via the CLI:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">claude mcp add weaviate http://localhost:8080/v1/mcp --transport http</span><br></span></code></pre></div></div>
<p><strong><a href="https://docs.cursor.com/context/model-context-protocol" target="_blank" rel="noopener noreferrer" class="">Cursor</a></strong> (<code>~/.cursor/mcp.json</code> or project-local <code>.cursor/mcp.json</code>):</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"mcpServers"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"weaviate"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"url"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"http://localhost:8080/v1/mcp"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p><strong><a href="https://code.visualstudio.com/docs/copilot/customization/mcp-servers" target="_blank" rel="noopener noreferrer" class="">VS Code with Copilot</a></strong> (<code>.vscode/mcp.json</code>):</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"servers"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"weaviate"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"type"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"http"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"url"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"http://localhost:8080/v1/mcp"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>Restart the client. The Weaviate tools (<code>weaviate-query-hybrid</code>, <code>weaviate-collections-get-config</code>, etc.) should appear in the client's tool list. If they don't, check that <code>MCP_SERVER_ENABLED=true</code> is set and that the port is reachable.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-it-out">Try it out<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#try-it-out" class="hash-link" aria-label="Direct link to Try it out" title="Direct link to Try it out" translate="no">​</a></h2>
<p>Open Claude Code in any directory after the runbook below has finished. Ask something specific to FastAPI internals that a generic model would only paraphrase from training data:</p>
<blockquote>
<p>"How does FastAPI handle dependency injection — show me the actual resolver."</p>
</blockquote>
<p>Without MCP, Claude Code paraphrases the FastAPI <a href="https://fastapi.tiangolo.com/tutorial/dependencies/" target="_blank" rel="noopener noreferrer" class="">dependency injection</a> docs from training. With MCP, it calls <code>weaviate-query-hybrid</code> against <code>CodeChunks</code>, the BM25 half nails identifiers like <code>Depends</code> and <code>solve_dependencies</code>, the vector half pulls in nearby resolver code, and the answer cites real lines from <code>fastapi/dependencies/utils.py</code>.</p>
<p>Try a docs query:</p>
<blockquote>
<p>"When should I use <code>async def</code> versus <code>def</code> in FastAPI route handlers?"</p>
</blockquote>
<p>Same shape, different collection. The agent queries <code>DocChunks</code>, returns the relevant section from FastAPI's <a href="https://fastapi.tiangolo.com/async/" target="_blank" rel="noopener noreferrer" class=""><code>async def</code> versus <code>def</code></a> guide, and answers with the actual recommendation rather than guessing.</p>
<p>The general pattern: the agent decides per-question whether code, docs, or both are relevant, and pulls the chunks that are. Context size stays bounded. The repo can be huge.</p>
<p><img decoding="async" loading="lazy" alt="Hybrid retrieval for code search: BM25 lane matches identifiers, vector lane matches semantic intent, fused result feeds Claude Code" src="https://weaviate.io/assets/images/hybrid-retrieval-fcce975b20bfaa162179ef48893ba8d1.png" width="1800" height="759" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="agent-runbook">Agent runbook: autonomous setup<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#agent-runbook" class="hash-link" aria-label="Direct link to Agent runbook: autonomous setup" title="Direct link to Agent runbook: autonomous setup" translate="no">​</a></h3>
<p>The narrative above is for humans. If you are an agent (Claude Code, Cursor, or any MCP-aware assistant) executing this end-to-end, the dropdown below is the contract: ordered steps, full scripts, success criteria. Run them in order. Each step prints a marker the next step can check.</p>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary><strong>Autonomous setup runbook</strong> — copy these scripts, run in order</summary><div><div class="collapsibleContent_i85q"><h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="inputs">Inputs<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#inputs" class="hash-link" aria-label="Direct link to Inputs" title="Direct link to Inputs" translate="no">​</a></h4><p>This runbook uses <a href="https://github.com/fastapi/fastapi" target="_blank" rel="noopener noreferrer" class="">FastAPI</a> as the demo codebase. It's well-known, ~30K LOC of Python with substantial MkDocs documentation, and matches both chunkers in the script (Python AST for source, heading-aware split for Markdown). Replace the clone target with any other repo to ingest your own.</p><p>Clone the demo repo and define environment variables:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Clone FastAPI as the demo target</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">git clone --depth=1 https://github.com/fastapi/fastapi.git /tmp/fastapi</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">export WEAVIATE_DIR="$HOME/weaviate-code-assistant"   # where docker-compose.yml lives</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">export CODE_DIR="/tmp/fastapi/fastapi"                 # FastAPI Python source</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">export DOCS_DIR="/tmp/fastapi/docs/en/docs"            # FastAPI English MkDocs content</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">export OPENAI_APIKEY="sk-..."                          # required for the text2vec-openai vectorizer</span><br></span></code></pre></div></div><p>If <code>OPENAI_APIKEY</code> is unset, stop and ask. Do not proceed with a placeholder.</p><h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-1-provision-and-start-weaviate">Step 1: Provision and start Weaviate<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-1-provision-and-start-weaviate" class="hash-link" aria-label="Direct link to Step 1: Provision and start Weaviate" title="Direct link to Step 1: Provision and start Weaviate" translate="no">​</a></h4><p>Save the following as <code>$WEAVIATE_DIR/setup.sh</code>, make it executable, and run it. Idempotent: re-running on an already-up instance is a no-op.</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">#!/usr/bin/env bash</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">set -euo pipefail</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">mkdir -p "$WEAVIATE_DIR"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">cd "$WEAVIATE_DIR"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">cat &gt; docker-compose.yml &lt;&lt;'YAML'</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">services:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  weaviate:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    image: cr.weaviate.io/semitechnologies/weaviate:1.38.8</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    ports:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      - "8080:8080"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      - "50051:50051"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    environment:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      MCP_SERVER_ENABLED: 'true'</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      MCP_SERVER_WRITE_ACCESS_ENABLED: 'true'</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'true'</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      PERSISTENCE_DATA_PATH: '/var/lib/weaviate'</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      DEFAULT_VECTORIZER_MODULE: 'text2vec-openai'</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      ENABLE_MODULES: 'text2vec-openai'</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      OPENAI_APIKEY: ${OPENAI_APIKEY}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    volumes:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      - weaviate-data:/var/lib/weaviate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">volumes:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  weaviate-data:</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">YAML</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">docker compose up -d</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Wait for the REST API to come up (max 60s)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">for i in {1..30}; do</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  if curl -sf http://localhost:8080/v1/.well-known/ready &gt; /dev/null; then</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    echo "STEP_1_READY"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    break</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  fi</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  sleep 2</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">done</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># Verify the MCP endpoint is reachable. Streamable HTTP requires an</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># initialize handshake first; tools/list then needs the Mcp-Session-Id</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"># header returned by initialize.</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">SID=$(curl -s -i -X POST http://localhost:8080/v1/mcp \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H 'Content-Type: application/json' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H 'Accept: application/json, text/event-stream' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -d '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        "protocolVersion":"2025-03-26","capabilities":{},</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        "clientInfo":{"name":"curl","version":"1"}}}' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  | awk -F': ' 'tolower($1)=="mcp-session-id"{print $2}' | tr -d '\r\n')</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">if [ -z "$SID" ]; then</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  echo "STEP_1_MCP_FAILED: no Mcp-Session-Id returned. MCP may be disabled."</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  exit 1</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">fi</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">curl -sf -o /dev/null -X POST http://localhost:8080/v1/mcp \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H 'Content-Type: application/json' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H 'Accept: application/json, text/event-stream' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H "Mcp-Session-Id: $SID" \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  &amp;&amp; echo "STEP_1_MCP_OK" \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  || { echo "STEP_1_MCP_FAILED"; exit 1; }</span><br></span></code></pre></div></div><p><strong>Success criteria:</strong> stdout contains both <code>STEP_1_READY</code> and <code>STEP_1_MCP_OK</code>. If only <code>STEP_1_READY</code> shows, MCP is disabled or the version is wrong.</p><h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-2-create-collections-and-ingest-data">Step 2: Create collections and ingest data<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-2-create-collections-and-ingest-data" class="hash-link" aria-label="Direct link to Step 2: Create collections and ingest data" title="Direct link to Step 2: Create collections and ingest data" translate="no">​</a></h4><p>Save the following as <code>$WEAVIATE_DIR/ingest.py</code> and run it with <code>python3 ingest.py</code>. Idempotent: collections that already exist are reused; objects are inserted (duplicates may accumulate, see note at end).</p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)">#!/usr/bin/env python3</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token triple-quoted-string string" style="color:rgb(255, 121, 198)">"""Ingest a codebase and its docs into Weaviate. Run after setup.sh."""</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> ast</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> os</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> re</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> sys</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> pathlib </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Path</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> weaviate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">config </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Configure</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">CODE_DIR </span><span class="token operator">=</span><span class="token plain"> Path</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">os</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">environ</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"CODE_DIR"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">resolve</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">DOCS_DIR </span><span class="token operator">=</span><span class="token plain"> Path</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">os</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">environ</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"DOCS_DIR"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> CODE_DIR</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">resolve</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">REPO_LABEL </span><span class="token operator">=</span><span class="token plain"> CODE_DIR</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">name</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client </span><span class="token operator">=</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">connect_to_local</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">try</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)"># ---- Schema (idempotent) ----</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">not</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">exists</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"CodeChunks"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"CodeChunks"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"content"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"symbol"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">LOWERCASE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"file_path"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FIELD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"language"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FIELD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"repo"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FIELD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            vector_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Vectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text2vec_openai</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">not</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">exists</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"DocChunks"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"DocChunks"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"content"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"title"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"source_url"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FIELD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            vector_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Vectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text2vec_openai</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)"># ---- Code: AST-chunk every .py file ----</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    code </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">use</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"CodeChunks"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    code_count </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">with</span><span class="token plain"> code</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">stream</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> py </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> CODE_DIR</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rglob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"*.py"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">any</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">part</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">startswith</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"."</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">or</span><span class="token plain"> part </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"node_modules"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"venv"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">".venv"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"__pycache__"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> part </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> py</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">parts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">continue</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">try</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                source </span><span class="token operator">=</span><span class="token plain"> py</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">read_text</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">encoding</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"utf-8"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                tree </span><span class="token operator">=</span><span class="token plain"> ast</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">parse</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">source</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">except</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">SyntaxError</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> UnicodeDecodeError</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">continue</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            lines </span><span class="token operator">=</span><span class="token plain"> source</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">splitlines</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> node </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> ast</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">iter_child_nodes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">tree</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">isinstance</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ast</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FunctionDef</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> ast</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">AsyncFunctionDef</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> ast</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">ClassDef</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    chunk </span><span class="token operator">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"\n"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">join</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">lines</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">lineno </span><span class="token operator">-</span><span class="token plain"> </span><span class="token number">1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain">node</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">end_lineno</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">add_object</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                        </span><span class="token string" style="color:rgb(255, 121, 198)">"content"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> chunk</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                        </span><span class="token string" style="color:rgb(255, 121, 198)">"symbol"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> node</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">name</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                        </span><span class="token string" style="color:rgb(255, 121, 198)">"file_path"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">str</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">py</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                        </span><span class="token string" style="color:rgb(255, 121, 198)">"language"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"python"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                        </span><span class="token string" style="color:rgb(255, 121, 198)">"repo"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> REPO_LABEL</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    code_count </span><span class="token operator">+=</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"STEP_2_CODE_CHUNKS=</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">code_count</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token comment" style="color:rgb(98, 114, 164)"># ---- Docs: heading-chunk every .md file ----</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    docs </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">use</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"DocChunks"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    doc_count </span><span class="token operator">=</span><span class="token plain"> </span><span class="token number">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">with</span><span class="token plain"> docs</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">stream</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">as</span><span class="token plain"> batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> md </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> DOCS_DIR</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">rglob</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"*.md"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">any</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">part</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">startswith</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"."</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> part </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> md</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">parts</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">continue</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">try</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                text </span><span class="token operator">=</span><span class="token plain"> md</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">read_text</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">encoding</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"utf-8"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">except</span><span class="token plain"> UnicodeDecodeError</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">continue</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            sections </span><span class="token operator">=</span><span class="token plain"> re</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">split</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">r"(?m)^## "</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> text</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> sec </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> sections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                sec </span><span class="token operator">=</span><span class="token plain"> sec</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">strip</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">not</span><span class="token plain"> sec</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">continue</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">len</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">sec</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"> </span><span class="token operator">&gt;</span><span class="token plain"> </span><span class="token number">1500</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> sub </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> re</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">split</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">r"(?m)^### "</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> sec</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                        sub </span><span class="token operator">=</span><span class="token plain"> sub</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">strip</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> sub</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                            batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">add_object</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                                </span><span class="token string" style="color:rgb(255, 121, 198)">"content"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> sub</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                                </span><span class="token string" style="color:rgb(255, 121, 198)">"title"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> md</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">stem</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                                </span><span class="token string" style="color:rgb(255, 121, 198)">"source_url"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"file://</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">md</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token string-interpolation interpolation">resolve</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                            </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                            doc_count </span><span class="token operator">+=</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">else</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    batch</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">add_object</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                        </span><span class="token string" style="color:rgb(255, 121, 198)">"content"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> sec</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                        </span><span class="token string" style="color:rgb(255, 121, 198)">"title"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> md</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">stem</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                        </span><span class="token string" style="color:rgb(255, 121, 198)">"source_url"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"file://</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">md</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token string-interpolation interpolation">resolve</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                    doc_count </span><span class="token operator">+=</span><span class="token plain"> </span><span class="token number">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"STEP_2_DOC_CHUNKS=</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">doc_count</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">if</span><span class="token plain"> code_count </span><span class="token operator">+</span><span class="token plain"> doc_count </span><span class="token operator">==</span><span class="token plain"> </span><span class="token number">0</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"STEP_2_FAILED: no chunks ingested. Check CODE_DIR / DOCS_DIR paths."</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(189, 147, 249)">file</span><span class="token operator">=</span><span class="token plain">sys</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">stderr</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        sys</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">exit</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token number">2</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string" style="color:rgb(255, 121, 198)">"STEP_2_INGEST_OK"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">finally</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div><p><strong>Success criteria:</strong> stdout contains <code>STEP_2_INGEST_OK</code> and the chunk counts are non-zero. If both counts are zero, the input paths point to empty or unsupported content.</p><p><strong>Note on idempotency:</strong> re-running this script appends objects rather than upserting. For a clean re-ingest, delete the collections first:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">curl -X DELETE http://localhost:8080/v1/schema/CodeChunks</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">curl -X DELETE http://localhost:8080/v1/schema/DocChunks</span><br></span></code></pre></div></div><h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-3-wire-up-the-llm-client">Step 3: Wire up the LLM client<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-3-wire-up-the-llm-client" class="hash-link" aria-label="Direct link to Step 3: Wire up the LLM client" title="Direct link to Step 3: Wire up the LLM client" translate="no">​</a></h4><p>Pick the block matching the agent's host client. All three point at the same Weaviate endpoint.</p><p><strong>Claude Code</strong> (preferred, single command):</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">claude mcp add weaviate http://localhost:8080/v1/mcp --transport http</span><br></span></code></pre></div></div><p>If the <code>claude</code> CLI is not on PATH, write the config directly:</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">python3 -c '</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">import json, os, pathlib</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">p = pathlib.Path(os.path.expanduser("~/.claude.json"))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">data = json.loads(p.read_text()) if p.exists() else {}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">data.setdefault("mcpServers", {})["weaviate"] = {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "type": "http",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "url": "http://localhost:8080/v1/mcp"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">p.write_text(json.dumps(data, indent=2))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">print("STEP_3_CLAUDE_OK")</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">'</span><br></span></code></pre></div></div><p><strong>Cursor</strong> (<code>~/.cursor/mcp.json</code>):</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">python3 -c '</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">import json, os, pathlib</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">p = pathlib.Path(os.path.expanduser("~/.cursor/mcp.json"))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">p.parent.mkdir(parents=True, exist_ok=True)</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">data = json.loads(p.read_text()) if p.exists() else {}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">data.setdefault("mcpServers", {})["weaviate"] = {"url": "http://localhost:8080/v1/mcp"}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">p.write_text(json.dumps(data, indent=2))</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">print("STEP_3_CURSOR_OK")</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">'</span><br></span></code></pre></div></div><p><strong>VS Code with Copilot</strong> (project-local <code>.vscode/mcp.json</code>):</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">mkdir -p .vscode</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">cat &gt; .vscode/mcp.json &lt;&lt;'JSON'</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  "servers": {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "weaviate": {</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "type": "http",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "url": "http://localhost:8080/v1/mcp"</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">JSON</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">echo "STEP_3_VSCODE_OK"</span><br></span></code></pre></div></div><p><strong>Success criteria:</strong> the appropriate <code>STEP_3_*_OK</code> marker prints, and the next interactive turn surfaces a <code>weaviate-query-hybrid</code> tool in the client's tool list. If the tool does not appear, restart the client.</p><h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="step-4-verify-retrieval-works">Step 4: Verify retrieval works<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#step-4-verify-retrieval-works" class="hash-link" aria-label="Direct link to Step 4: Verify retrieval works" title="Direct link to Step 4: Verify retrieval works" translate="no">​</a></h4><p>This block confirms end-to-end retrieval without involving the LLM client. Streamable HTTP again needs the <code>initialize</code> handshake first so the session ID can be reused on the actual <code>tools/call</code>. Replace the query string with something the agent expects to be in the ingested codebase.</p><div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">SID=$(curl -s -i -X POST http://localhost:8080/v1/mcp \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H 'Content-Type: application/json' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H 'Accept: application/json, text/event-stream' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -d '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        "protocolVersion":"2025-03-26","capabilities":{},</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        "clientInfo":{"name":"curl","version":"1"}}}' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  | awk -F': ' 'tolower($1)=="mcp-session-id"{print $2}' | tr -d '\r\n')</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">curl -sX POST http://localhost:8080/v1/mcp \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H 'Content-Type: application/json' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H 'Accept: application/json, text/event-stream' \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -H "Mcp-Session-Id: $SID" \</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  -d '{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "jsonrpc":"2.0",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "id":1,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "method":"tools/call",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    "params":{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "name":"weaviate-query-hybrid",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "arguments":{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        "collection_name":"CodeChunks",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        "query":"how does FastAPI handle dependency injection",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        "limit":3</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  }' | python3 -m json.tool</span><br></span></code></pre></div></div><p><strong>Success criteria:</strong> the response contains a <code>result</code> key with non-empty <code>content</code> and the matched chunks reference real files in <code>$CODE_DIR</code>. If the response is empty, ingest produced zero matchable chunks for this query — try a query you know is in the codebase.</p><h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="done">Done<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#done" class="hash-link" aria-label="Direct link to Done" title="Direct link to Done" translate="no">​</a></h4><p>The agent now has hybrid search over the ingested codebase and docs. From the LLM client, queries that previously hallucinated will instead return citations from real files. To re-ingest after the codebase changes, delete the two collections (curl block above) and re-run <code>ingest.py</code>.</p></div></div></details>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="going-further">Going further<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#going-further" class="hash-link" aria-label="Direct link to Going further" title="Direct link to Going further" translate="no">​</a></h2>
<p>A few directions worth picking up after the basics work:</p>
<ul>
<li class="">
<p><strong>Multi-repo organizations</strong>: Switch the schema to multi-tenant and create one tenant per repo. The <code>weaviate-tenants-list</code> MCP tool gives the agent a way to discover them.</p>
</li>
<li class="">
<p><strong>Auth and RBAC</strong>: Weaviate's MCP server respects standard authentication. Three RBAC permissions (<code>read_mcp</code>, <code>create_mcp</code>, <code>update_mcp</code>) control who can do what. Hand out read-only MCP credentials to most users; reserve write access for trusted agents.</p>
</li>
<li class="">
<p><strong>Agent write-back</strong>: With write access on, the agent can persist its own findings (postmortem notes, cross-references it discovered, summaries of long-running work) back into Weaviate. The next session inherits them. This is what shifts Weaviate from a passive retrieval engine into long-term memory for the coding agent.</p>
</li>
<li class="">
<p><strong>Embedding choice</strong>: <code>text2vec-openai</code> is fine for most code. Voyage's <code>voyage-code-2</code> is better if you can swap it in. For fully local setups, point Weaviate at an Ollama-served embedding model.</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<p>A coding assistant that doesn't know your code is a generic chatbot. The build is straightforward: index the codebase along syntactic boundaries, index the docs along heading boundaries, point your LLM client at the database via MCP, and let the agent retrieve only what it needs per query.</p>
<p>Weaviate simplifies this setup by running the MCP server inside the database. Hybrid search and multi-tenancy are enabled in the MCP service by default and writing directly to the database is one env var away. Spin it up, point Claude Code at it, and start asking questions about your actual code.</p>
<p>To go deeper:</p>
<ul>
<li class="">The <a class="" href="https://weaviate.io/blog/weaviate-1-37-release">Weaviate MCP server release notes</a></li>
<li class="">The <a href="https://github.com/weaviate/mcp-server-weaviate" target="_blank" rel="noopener noreferrer" class=""><code>weaviate/mcp-server-weaviate</code> GitHub repository</a></li>
<li class="">The <a href="https://modelcontextprotocol.io/docs/develop/build-server" target="_blank" rel="noopener noreferrer" class="">official MCP protocol docs</a></li>
<li class="">The <a class="" href="https://weaviate.io/blog/tokenization-text-analysis-weaviate">tokenization post</a> for the per-property tokenization rationale</li>
<li class="">Related blog posts: <a class="" href="https://weaviate.io/blog/what-is-agentic-rag">What is agentic RAG</a> and <a class="" href="https://weaviate.io/blog/hybrid-search-explained">Hybrid search explained</a></li>
</ul>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/coding-assistant-weaviate-mcp#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=coding-assistant-weaviate-mcp&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Ivan Despot</name>
            <uri>https://www.linkedin.com/in/ivan-g-despot/</uri>
        </author>
        <category label="agents" term="agents"/>
        <category label="engineering" term="engineering"/>
        <category label="how-to" term="how-to"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Text Analysis for Hybrid Search: Tokenization, Stopwords & Accent Folding]]></title>
        <id>https://weaviate.io/blog/tokenization-text-analysis-weaviate</id>
        <link href="https://weaviate.io/blog/tokenization-text-analysis-weaviate"/>
        <updated>2026-05-14T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Tokenization makes or breaks hybrid search. See how Weaviate's accent folding, custom stopwords, and /v1/tokenize endpoint power multilingual BM25.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Tokenization for hybrid search in Weaviate: accent folding, custom stopwords, and the /v1/tokenize endpoint" src="https://weaviate.io/assets/images/hero-8d0f567f50620365f1f446ec2c8b534b.png" width="1200" height="630" class="img_ev3q"></p>
<br>
<p><a href="https://docs.weaviate.io/weaviate/concepts/search/hybrid-search" target="_blank" rel="noopener noreferrer" class="">Hybrid search</a> in a vector database has two halves: vector similarity for meaning, BM25 for exact tokens. The vector half gets all the attention. The <a href="https://en.wikipedia.org/wiki/Okapi_BM25" target="_blank" rel="noopener noreferrer" class="">BM25</a> half, and the <strong>tokenization</strong> that feeds it, quietly fails when the analyzer is wrong, and no amount of embedding tuning will save you. Drop the wrong character, split a word that shouldn't be split, and BM25 has nothing useful to match. The keyword side becomes noise and drags the search quality down with it.</p>
<p>That sounds like an edge case until you ship a multilingual catalog. Suddenly <code>"café crème"</code> returns nothing for a French e-commerce store, the Polish team can't find <code>"Łódź"</code>, and your support agent's RAG pipeline misses every query that uses an accented word. The tokenizer was right there the whole time. Nobody could see what it was doing.</p>
<p>Weaviate <code>v1.37</code> made the tokenizer an <strong>observable and multilingual-friendly</strong> part of the database. This post will help improve your search quality and covers the following topics:</p>
<ul>
<li class=""><a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#hybrid-search-101" class="">Hybrid search 101 - How tokenization shapes recall in hybrid search</a></li>
<li class=""><a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#tokenization-methods" class="">Tokenization methods - Picking the right tokenizer for your data</a></li>
<li class=""><a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#accent-folding" class="">Accent folding for multilingual search</a></li>
<li class=""><a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#per-property-stopwords" class="">Per-property stopwords - Per-language stopwords without reindexing</a></li>
<li class=""><a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#the-tokenize-endpoint" class="">The <code>tokenize</code> endpoint - Verifying the result with a single API call</a></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="hybrid-search-101">Hybrid search 101<a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#hybrid-search-101" class="hash-link" aria-label="Direct link to Hybrid search 101" title="Direct link to Hybrid search 101" translate="no">​</a></h2>
<p>Hybrid search combines two signals: <strong>vector similarity</strong> (semantic, meaning-based) and <strong><a href="https://docs.weaviate.io/weaviate/search/bm25" target="_blank" rel="noopener noreferrer" class="">BM25 keyword scoring</a></strong> (exact-match, lexical). The two are fused at query time, so a query like <code>"product launch April 2026"</code> recovers both relevant news articles (vector) and exact date mentions (keyword).</p>
<p>BM25 doesn't operate on text. It operates on <strong>tokens</strong>, the discrete units the analyzer produced when each document was indexed. This is the same tokenization concept you've seen in NLP, but the stakes are different: there's no model layer that can paper over a wrong token. If your tokenizer dropped the punctuation in <code>"v1.37"</code>, lower-cased <code>"USA"</code> to <code>"usa"</code>, or treated <code>naïve</code> and <code>naive</code> as different tokens, BM25 can't recover. The keyword half of your hybrid score becomes noise, and your fusion is fighting itself.</p>
<p>This is why a great embedding model on top of a careless tokenizer often loses to pure-vector search. So <code>BM25 vs semantic search</code> isn't really the question. They answer different things, and hybrid search is supposed to combine them. The real question is whether your tokens make BM25 useful at all. The tokenizer is the entry point to the <a href="https://docs.weaviate.io/weaviate/concepts/indexing/inverted-index" target="_blank" rel="noopener noreferrer" class="">inverted index</a>, and it sets the ceiling for keyword recall.</p>
<p>Whether you're building hybrid search for RAG, classic keyword search, or a multilingual catalog, the analyzer is the part that decides what BM25 can score. If you're new to hybrid retrieval mechanics, our earlier post on <a class="" href="https://weaviate.io/blog/hybrid-search-fusion-algorithms">hybrid search fusion</a> walks through the scoring math. This post focuses on the analyzer that feeds it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="tokenization-methods">Tokenization methods<a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#tokenization-methods" class="hash-link" aria-label="Direct link to Tokenization methods" title="Direct link to Tokenization methods" translate="no">​</a></h2>
<p>Weaviate exposes four general-purpose tokenization methods that cover the vast majority of production use cases:</p>
<table><thead><tr><th>Method</th><th>Pick this when…</th><th>Example token output for <code>"User_42 - café"</code></th></tr></thead><tbody><tr><td><code>word</code></td><td>Articles, descriptions, names, FAQs (the default)</td><td><code>user</code>, <code>42</code>, <code>café</code></td></tr><tr><td><code>lowercase</code></td><td>Code identifiers, email addresses, hash IDs</td><td><code>user_42</code>, <code>-</code>, <code>café</code></td></tr><tr><td><code>whitespace</code></td><td>Acronyms, case-sensitive entity names</td><td><code>User_42</code>, <code>-</code>, <code>café</code></td></tr><tr><td><code>field</code></td><td>Exact-match identifiers (URLs, UUIDs)</td><td><code>User_42 - café</code> <em>(one token)</em></td></tr></tbody></table>
<p>The <code>word</code> tokenizer is forgiving. It lower-cases, strips most punctuation, and usually does the right thing for prose. The other three preserve more of the original string, which matters when meaningful symbols (<code>_</code>, <code>-</code>, <code>:</code>) carry information.</p>
<p>If you are not sure, the <code>word</code> tokenizer is probably the way to go. The other three look more flexible on paper, but the only honest reason to reach for them is that you ran a real query and saw a wrong result. Picking <code>lowercase</code> or <code>whitespace</code> upfront because they "preserve more" tends to lock in tokens you didn't actually want, and you find out months later when a query goes sideways.</p>
<p>You set the method <strong>per property</strong>, not per collection. That's important: real apps mix prose, identifiers, and code in a single collection.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> weaviate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">config </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Configure</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client </span><span class="token operator">=</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">connect_to_local</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">tkn_options </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">LOWERCASE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WHITESPACE</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FIELD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">properties </span><span class="token operator">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        name</span><span class="token operator">=</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"text_</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">tokenization</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token string-interpolation interpolation">replace</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation interpolation string" style="color:rgb(255, 121, 198)">'.'</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token string-interpolation interpolation"> </span><span class="token string-interpolation interpolation string" style="color:rgb(255, 121, 198)">'_'</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        tokenization</span><span class="token operator">=</span><span class="token plain">tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> tokenization </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> tkn_options</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"TokenizationDemo"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    properties</span><span class="token operator">=</span><span class="token plain">properties</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    vector_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Vectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">self_provided</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>For non-whitespace-delimited languages, Weaviate also ships <strong><a href="https://docs.weaviate.io/weaviate/config-refs/collections#language-specific-tokenization" target="_blank" rel="noopener noreferrer" class="">language-specific tokenizers</a></strong> that are opt-in via environment variables: <code>gse</code> (Japanese), <code>gse_ch</code> (Chinese), <code>kagome_ja</code> (Japanese morphological), and <code>kagome_kr</code> (Korean). A <code>trigram</code> tokenizer is also built-in (always available, no env flag) and produces 3-character n-grams for fuzzy and substring matching — handy when you need partial-token recall over short identifiers. For Japanese, Korean, or Chinese content, point a property at the appropriate language tokenizer:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"description_ja"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">KAGOME_JA</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="accent-folding">Accent folding for multilingual search<a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#accent-folding" class="hash-link" aria-label="Direct link to Accent folding for multilingual search" title="Direct link to Accent folding for multilingual search" translate="no">​</a></h2>
<p>The single most painful tokenization bug in production is accent mismatch. Users type <code>cafe</code>. Documents store <code>café</code>. BM25 sees two different tokens, returns nothing, and your hybrid score collapses to whatever the vector search came up with.</p>
<p>To match accented characters in search, enable accent folding on the property. The fix is one line of schema.
The example below sets up three properties side-by-side: <code>text_default</code> as the unfolded baseline, <code>text_folded</code> with full ASCII folding, and <code>text_folded_keep_e</code> showing how to exempt a specific character (<code>é</code>) from folding:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> weaviate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">config </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Configure</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client </span><span class="token operator">=</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">connect_to_local</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"AccentFoldingDemo"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"text_default"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"text_folded"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            text_analyzer</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text_analyzer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">ascii_fold</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"text_folded_keep_e"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            text_analyzer</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text_analyzer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                ascii_fold</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> ascii_fold_ignore</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"é"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    vector_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Vectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">self_provided</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>Under the hood, <a href="https://docs.weaviate.io/weaviate/config-refs/indexing/inverted-index#textanalyzer" target="_blank" rel="noopener noreferrer" class=""><code>textAnalyzer.asciiFold</code></a> uses <a href="https://unicode.org/reports/tr15/" target="_blank" rel="noopener noreferrer" class="">Unicode NFD decomposition</a> plus an explicit replacement table for single-codepoint letters that don't decompose (<code>ł</code>, <code>æ</code>, <code>ø</code>, <code>ð</code>, <code>þ</code>, <code>đ</code>, <code>ß</code>, and more). That covers 20+ Latin-script languages by default, including French, German, Spanish, Polish, Czech, Turkish, Vietnamese, and Scandinavian languages.</p>
<p>Folding runs at <em>both</em> index and query time, so <code>"Café Crème"</code> → <code>cafe creme</code> in the inverted index, and a user query of <code>cafe creme</code> (or <code>café creme</code>, or <code>Cafe Crème</code>) all hit the same row. Text filter operators like <code>Equal</code> and <code>Like</code> also run through the analyzer, so <code>Filter.by_property("text").equal("cafe")</code> matches a stored value of <code>"Café"</code> once folding is on, with no special-case handling at the query layer.</p>
<p><img decoding="async" loading="lazy" alt="Accent folding in Weaviate: matching cafe to Café in BM25 keyword search" src="https://weaviate.io/assets/images/accent-folding-391a9da6f0cc66cf796439d98b2158cf.png" width="2400" height="1532" class="img_ev3q"></p>
<p>If you need to <strong>preserve</strong> specific accents (for example, a brand name where the accent distinguishes two SKUs), use the <a href="https://docs.weaviate.io/weaviate/config-refs/indexing/inverted-index#textanalyzer" target="_blank" rel="noopener noreferrer" class=""><code>asciiFoldIgnore</code></a> array to exempt individual characters. The exemption is immutable after the property is created (changing it would change which tokens are written to disk), so plan it once.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="per-property-stopwords">Per-property stopwords<a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#per-property-stopwords" class="hash-link" aria-label="Direct link to Per-property stopwords" title="Direct link to Per-property stopwords" translate="no">​</a></h2>
<p><a href="https://docs.weaviate.io/weaviate/concepts/indexing/inverted-index#stop-words" target="_blank" rel="noopener noreferrer" class="">Stopwords</a> are short, high-frequency words (<code>the</code>, <code>a</code>, <code>and</code>) that BM25 typically drops to make scoring more robust. Many search stacks default to one stopword list per language and apply it to every text field. That works until you have a brand called <em>"The North Face"</em>, and dropping <code>the</code> quietly destroys recall on the brand.</p>
<p>Weaviate solves this two ways. First, you can declare <strong>named stopword presets</strong> at the collection level. Each preset is a flat list of words to drop. A preset name that matches a built-in (<code>en</code>, <code>none</code>) replaces the built-in for this collection. If you want to extend a built-in with <code>additions</code>/<code>removals</code> rather than replace it, use the legacy <a href="https://docs.weaviate.io/weaviate/config-refs/indexing/inverted-index#stopwords" target="_blank" rel="noopener noreferrer" class=""><code>invertedIndexConfig.stopwords</code></a> field — <code>stopwordPresets</code> only accepts flat word lists.</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> weaviate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">config </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Configure</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client </span><span class="token operator">=</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">connect_to_local</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">collections</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"StopwordsDemo"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    inverted_index_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">inverted_index</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        stopword_presets</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token string" style="color:rgb(255, 121, 198)">"fr"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"le"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"la"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"les"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"un"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"une"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"des"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"du"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"de"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"et"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"name_en"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            text_analyzer</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text_analyzer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">stopword_preset</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"en"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"name_fr"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            text_analyzer</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text_analyzer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">stopword_preset</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"fr"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    vector_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">Vectors</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">self_provided</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>In this example, <code>en</code> is a built-in preset that ships with Weaviate, while <code>fr</code> is a user-defined preset registered via <code>stopword_presets</code>. Built-in presets can be referenced from <code>text_analyzer.stopword_preset</code> without registering them at the collection level.</p>
<p>Search the <code>name_fr</code> property for <code>"la tasse bleue et le bol"</code> and the analyzer keeps <code>tasse</code>, <code>bleue</code>, <code>bol</code> and drops <code>la</code>, <code>et</code>, <code>le</code> — exactly the noise reduction BM25 needs. The same words against <code>name_en</code> aren't filtered, because they aren't English stopwords.</p>
<p>Second, you can override the stopword behavior <strong>per property</strong> via <code>textAnalyzer.stopwordPreset</code>. So in a single collection, <code>description_en</code> can use English stopwords, <code>description_fr</code> can use a French preset, and <code>brand_name</code> can use <code>none</code>, all sharing the same hybrid query path.</p>
<p>One constraint to know about: <code>textAnalyzer.stopwordPreset</code> is only honoured on properties with <code>word</code> tokenization.</p>
<p><strong>Stopwords are still indexed.</strong> They're only filtered at <em>query</em> time. That means changing a stopword preset takes effect immediately on the next query, with no reindex.</p>
<p><strong>Stopwords are removed from the query side, not from the index.</strong> They don't contribute query-term weight to the BM25 score, but because they remain in the inverted index, document length and term-frequency stats can still shift the ranking of two otherwise similar documents. The token is still in the index, so an exact-phrase filter on it still matches.</p>
<p>For a tutorial-style walkthrough with searches and filters, see the <a href="https://docs.weaviate.io/weaviate/tutorials/tokenization" target="_blank" rel="noopener noreferrer" class="">tokenization tutorial</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-tokenize-endpoint">The <code>tokenize</code> endpoint<a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#the-tokenize-endpoint" class="hash-link" aria-label="Direct link to the-tokenize-endpoint" title="Direct link to the-tokenize-endpoint" translate="no">​</a></h2>
<p>If your keyword search is returning fewer results than expected, or returning nothing at all, the analyzer is the first place to look. The hardest part of tuning a text analyzer used to be <em>seeing what it actually did</em>. Most search stacks force you to delete the index, reconfigure, reingest, run queries, and squint at log output. By the time you have a feedback loop, you've forgotten what hypothesis you were testing.</p>
<p>Weaviate <code>v1.37</code> exposes two REST endpoints that turn the analyzer into a sandboxed, callable function:</p>
<ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/api/rest#tag/tokenize/POST/tokenize" target="_blank" rel="noopener noreferrer" class=""><code>POST /v1/tokenize</code></a>: run any tokenizer + analyzer config against arbitrary text. No schema mutation, no reingest.</li>
<li class=""><a href="https://docs.weaviate.io/weaviate/api/rest#tag/schema/POST/schema/%7BclassName%7D/properties/%7BpropertyName%7D/tokenize" target="_blank" rel="noopener noreferrer" class=""><code>POST /v1/schema/{className}/properties/{propertyName}/tokenize</code></a>: apply an <em>existing</em> property's exact configuration.</li>
</ul>
<p>Both return a structured response that separates <code>indexed</code> tokens (what goes into the inverted index) from <code>query</code> tokens (what BM25 actually scores after stopword filtering):</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> weaviate</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">config </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> Configure</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">client </span><span class="token operator">=</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">connect_to_local</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">result </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    text</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"The organic café crème blend"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    analyzer_config</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text_analyzer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        ascii_fold</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        stopword_preset</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"en"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"indexed: </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">result</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token string-interpolation interpolation">indexed</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"query:   </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">result</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token string-interpolation interpolation">query</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">indexed: ['the', 'organic', 'cafe', 'creme', 'blend']</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">query:   ['organic', 'cafe', 'creme', 'blend']</span><br></span></code></pre></div></div>
<p>The <code>indexed</code> / <code>query</code> distinction shows you exactly where the stopword preset kicked in. If <code>the</code> shows up in <code>query</code>, you forgot to apply the preset. If <code>cafe</code> is missing, accent folding isn't on.</p>
<p>The property-scoped variant takes the property's full config (tokenizer, accent folding, stopword preset, ignore list), so you can verify a real production property without copying its config into the request. It also resolves collection aliases and accepts class and property names case-insensitively.</p>
<p>Both endpoints work with every tokenizer Weaviate ships, including <code>word</code>, <code>lowercase</code>, <code>whitespace</code>, <code>field</code>, and <code>trigram</code>, and the language-specific ones (<code>gse</code>, <code>gse_ch</code>, <code>kagome_ja</code>, <code>kagome_kr</code>) work when they're enabled at server start.</p>
<p>Treat it like a linter for your search analyzer.</p>
<p><img decoding="async" loading="lazy" alt="Weaviate /v1/tokenize endpoint flow: text input, analyzer, indexed vs query tokens" src="https://weaviate.io/assets/images/tokenize-endpoint-4ab9d30299cfa4ae353895408e137977.png" width="2400" height="868" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="use-cases">Use cases<a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#use-cases" class="hash-link" aria-label="Direct link to Use cases" title="Direct link to Use cases" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="multilingual-e-commerce-catalog">Multilingual e-commerce catalog<a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#multilingual-e-commerce-catalog" class="hash-link" aria-label="Direct link to Multilingual e-commerce catalog" title="Direct link to Multilingual e-commerce catalog" translate="no">​</a></h3>
<p>A catalog with French descriptions, English SKUs, and product names containing accents. Configure the collection so each property gets the right analyzer:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">properties</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"title_fr"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             text_analyzer</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text_analyzer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 ascii_fold</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">                 stopword_preset</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"fr"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"sku"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">FIELD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    Property</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">name</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"brand"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> data_type</span><span class="token operator">=</span><span class="token plain">DataType</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">TEXT</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             tokenization</span><span class="token operator">=</span><span class="token plain">Tokenization</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">WORD</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">             text_analyzer</span><span class="token operator">=</span><span class="token plain">Configure</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">text_analyzer</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">stopword_preset</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"none"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><br></span></code></pre></div></div>
<p>Three different analyzers in one collection, all sharing the same hybrid query path. The <code>brand</code> property keeps <code>the</code> in <code>"The North Face"</code>. The SKU property treats every code as one exact-match token. The French title property folds accents and filters French stopwords.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="technical-documentation-rag">Technical documentation RAG<a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#technical-documentation-rag" class="hash-link" aria-label="Direct link to Technical documentation RAG" title="Direct link to Technical documentation RAG" translate="no">​</a></h3>
<p>Code identifiers like <code>weaviate.connect_to_local</code> shouldn't be split by underscores. Use <code>lowercase</code> tokenization on a <code>code_snippet</code> property and <code>word</code> on the surrounding prose. The <a href="https://docs.weaviate.io/query-agent" target="_blank" rel="noopener noreferrer" class="">Query Agent</a> (or any RAG pipeline) gets clean tokens for exact-symbol matching alongside semantic recall over the explanation.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="multi-tenant-saas-with-mixed-locales">Multi-tenant SaaS with mixed locales<a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#multi-tenant-saas-with-mixed-locales" class="hash-link" aria-label="Direct link to Multi-tenant SaaS with mixed locales" title="Direct link to Multi-tenant SaaS with mixed locales" translate="no">​</a></h3>
<p>Each tenant lives in its own multi-tenant shard, but the schema is shared. Define multiple stopword presets at the collection level (<code>en</code>, <code>fr</code>, <code>de</code>, <code>ja</code>) and override per-property at the tenant onboarding step based on the tenant's primary language. No schema migration, no reindex when a new language onboards.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<p>Tokenization is the entry point to the keyword half of hybrid search, and the keyword half is what makes hybrid retrieval robust on multilingual text and case-sensitive identifiers. Most vector database tokenization stories stop at "we accept text and return embeddings." Weaviate <code>v1.37</code> makes the analyzer observable and per-property granular, so the keyword half of your vector database stays useful in any language.</p>
<p>Pick the tokenizer per field: <code>word</code> for prose (lower-cases, strips punctuation), <code>whitespace</code> for case-sensitive identifiers, <code>lowercase</code> for code-like strings where symbols carry meaning, <code>field</code> for exact-match identifiers like SKUs and URLs, and <code>trigram</code> for fuzzy substring matching. Configure stopwords per language at the collection level via <a href="https://docs.weaviate.io/weaviate/config-refs/indexing/inverted-index#stopwordpresets" target="_blank" rel="noopener noreferrer" class=""><code>invertedIndexConfig.stopwordPresets</code></a>, then override per property through <code>textAnalyzer.stopwordPreset</code>. Stopword presets can change without reindexing because they're filtered at query time, not index time. For non-Latin scripts, the <a href="https://docs.weaviate.io/weaviate/config-refs/collections#language-specific-tokenization" target="_blank" rel="noopener noreferrer" class="">language-specific tokenizers</a> (<code>gse</code>, <code>gse_ch</code>, <code>kagome_ja</code>, <code>kagome_kr</code>) cover the cases where whitespace splitting falls apart. And when something looks wrong, call <code>POST /v1/tokenize</code> and read what the analyzer actually produced.</p>
<p>To go deeper:</p>
<ul>
<li class="">The <a href="https://docs.weaviate.io/weaviate/tutorials/tokenization" target="_blank" rel="noopener noreferrer" class="">tokenization tutorial</a></li>
<li class="">The <a href="https://docs.weaviate.io/weaviate/concepts/indexing/inverted-index#accent-folding" target="_blank" rel="noopener noreferrer" class="">accent folding concepts page</a></li>
<li class="">The <a href="https://docs.weaviate.io/weaviate/concepts/search/keyword-search" target="_blank" rel="noopener noreferrer" class="">keyword search concepts page</a> for how BM25 uses the analyzer pipeline</li>
<li class="">The <a href="https://docs.weaviate.io/weaviate/api/rest#tag/tokenize/POST/tokenize" target="_blank" rel="noopener noreferrer" class=""><code>/v1/tokenize</code> reference</a></li>
<li class="">Related blog posts: <a class="" href="https://weaviate.io/blog/hybrid-search-explained">Hybrid search explained</a> and <a class="" href="https://weaviate.io/blog/weaviate-non-english-languages">Searching in non-English languages</a></li>
</ul>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/tokenization-text-analysis-weaviate#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=tokenization-text-analysis-weaviate&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>André Mourão</name>
            <uri>https://www.linkedin.com/in/andre-mourao/</uri>
        </author>
        <author>
            <name>Ivan Despot</name>
            <uri>https://www.linkedin.com/in/ivan-g-despot/</uri>
        </author>
        <category label="concepts" term="concepts"/>
        <category label="engineering" term="engineering"/>
        <category label="search" term="search"/>
        <category label="tokenization" term="tokenization"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Your LLM Is Only as Good as What It Retrieves]]></title>
        <id>https://weaviate.io/blog/retrieval-quality-rag-overview</id>
        <link href="https://weaviate.io/blog/retrieval-quality-rag-overview"/>
        <updated>2026-05-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A Researcher's Perspective on Retrieval Quality in RAG Systems]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="hero" src="https://weaviate.io/assets/images/hero-788f79518e75bc99a789c1fa20ee1db6.png" width="1200" height="630" class="img_ev3q"></p>
<p><em>In my research on hallucination detection in multi-agent LLM systems, the most consistent findings have not been about model size, prompt design, or inference temperature. It has been about retrieval. Poor retrieval quality is the single most reliable predictor of degraded output across every pipeline configuration I have studied.</em></p>
<p>The evidence from our experimental pipelines is unambiguous: when retrieval breaks down, the language model does not compensate. It extrapolates. It fills gaps with plausible-sounding content that has no grounding in fact, and it does so with the same fluency and confidence as it applies to correct outputs. The result is a failure mode that is both systematic and exceptionally difficult to detect without a dedicated evaluation infrastructure.</p>
<p>This post draws on that research to offer a structured, practitioner-facing analysis of retrieval quality: what it is, why it matters more than most teams realize, how it fails in practice, and what can be done to improve it. Whether you are building a production RAG pipeline or designing a multi-agent system, the principles here apply directly to the reliability of what your LLM ultimately produces.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="understanding-the-retrieval-layer-in-rag-systems"><strong>Understanding the Retrieval Layer in RAG Systems</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#understanding-the-retrieval-layer-in-rag-systems" class="hash-link" aria-label="Direct link to understanding-the-retrieval-layer-in-rag-systems" title="Direct link to understanding-the-retrieval-layer-in-rag-systems" translate="no">​</a></h2>
<p>Retrieval-Augmented Generation (RAG) addresses one of the fundamental limitations of large language models: their inability to access information beyond their training cutoff or outside their training distribution. In RAG architecture, an external knowledge store, typically a vector database, is queried at inference time to supply the model with relevant context before generation begins.</p>
<p>The pipeline operates in three sequential stages:</p>
<ul>
<li class=""><strong>Indexing:</strong> Source documents are segmented into chunks, encoded as dense vector representations via an embedding model, and stored in a vector database.</li>
<li class=""><strong>Retrieval:</strong> At query time, the user's input is encoded using the same embedding model and compared against indexed vectors using a similarity metric, typically cosine similarity. The top-k most similar chunks are returned.</li>
<li class=""><strong>Generation:</strong> The retrieved chunks are injected into the model's context window as grounding material. The LLM generates a response conditioned on both the query and the retrieved content.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="Rag Pipeline in three stages" src="https://weaviate.io/assets/images/rag_pipeline-3b7c386553363bbd33f975de01007ddf.png" width="1200" height="1038" class="img_ev3q"></p>
<p>The implicit contract in this architecture is that the retrieved content is accurate, current, and genuinely relevant to the query. When that contract is held, RAG systems perform impressively. When it does not, the architecture creates a specific and dangerous failure mode: the model generates coherent, confident output grounded in incorrect or irrelevant context, with no mechanism to signal that something has gone wrong.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-retrieval-failure-drives-llm-hallucination-evidence-from-research"><strong>How Retrieval Failure Drives LLM Hallucination: Evidence from Research</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#how-retrieval-failure-drives-llm-hallucination-evidence-from-research" class="hash-link" aria-label="Direct link to how-retrieval-failure-drives-llm-hallucination-evidence-from-research" title="Direct link to how-retrieval-failure-drives-llm-hallucination-evidence-from-research" translate="no">​</a></h2>
<p>My dissertation research investigates hallucination detection and mitigation in multi-agent LLM pipelines. One component of that work involves constructing a taxonomy of failure modes that emerge across agent trajectories and characterizing the conditions under which each failure type occurs. Retrieval-related failures consistently represent a dominant category, both in frequency and in downstream impact on output quality.</p>
<p>Across my experimental evaluations on <a href="https://github.com/RUCAIBox/HaluEval" target="_blank" rel="noopener noreferrer" class="">HaluEval</a>, <a href="https://github.com/sylinrl/TruthfulQA" target="_blank" rel="noopener noreferrer" class="">TruthfulQA</a>, and <a href="https://github.com/McGill-NLP/FaithDial" target="_blank" rel="noopener noreferrer" class="">FaithDial</a>, conducted as part of my dissertation research, I found that retrieval-layer failures consistently accounted for a substantial proportion of hallucinations, even in pipelines with otherwise well-configured generation stages.  This finding aligns with broader literature: Stanford's <a href="https://github.com/stanford-crfm/helm" target="_blank" rel="noopener noreferrer" class="">HELM</a> benchmark evaluations and McGill University's analysis of the <a href="https://github.com/McGill-NLP/FaithDial" target="_blank" rel="noopener noreferrer" class="">FaithDial</a> corpus both demonstrate that faithfulness to retrieved context, not model scale, is the dominant predictor of factual accuracy in knowledge-grounded generation tasks.</p>
<p>Five retrieval failure modes emerged most consistently in our experimental work:</p>
<ol>
<li class="">
<p><strong>Retrieval Drift:</strong> Retrieved chunks are semantically proximate to the query in embedding space but contextually insufficient to answer it. Common with multi-hop queries, where a single embedding cannot represent the full information needed.</p>
</li>
<li class="">
<p><strong>Context Truncation:</strong> When retrieved chunks are too large and overflow the model's context window, truncation removes information silently. The model compensates by drawing on parametric memory.</p>
</li>
<li class="">
<p><strong>Stale Index Poisoning:</strong> Documents that are outdated continue to surface as top-k matches. The model has no mechanism to distinguish temporally valid from invalid retrieved content.</p>
</li>
<li class="">
<p><strong>Low-Relevance Top-K Retrieval:</strong> When no document closely matches a query, the retriever still returns top-k results regardless of relevance. These low-signal chunks dilute the context window, and the model incorporates the noise into generation.</p>
</li>
<li class="">
<p><strong>Inter-Agent Miscommunication:</strong> In multi-agent pipelines, retrieval failure in an upstream agent propagates and amplifies across all downstream agents, producing compounding degradation that remains invisible at the output layer.</p>
</li>
</ol>
<p><img decoding="async" loading="lazy" alt="retrieval failures in LLMs" src="https://weaviate.io/assets/images/retrieval_failures-4160b5ed43953a1966c2c6a52f1e2227.png" width="1030" height="875" class="img_ev3q"></p>
<p>What makes these failures particularly consequential is their invisibility. Unlike a model that simply says it does not know, a model generated from poorly retrieved context produces well-formed, confident output. Detection requires either ground-truth comparison or a dedicated evaluation layer, neither of which exists by default in most deployed systems.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-scaling-the-model-does-not-solve-a-retrieval-problem"><strong>Why Scaling the Model Does Not Solve a Retrieval Problem</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#why-scaling-the-model-does-not-solve-a-retrieval-problem" class="hash-link" aria-label="Direct link to why-scaling-the-model-does-not-solve-a-retrieval-problem" title="Direct link to why-scaling-the-model-does-not-solve-a-retrieval-problem" translate="no">​</a></h2>
<p>A common and understandable response to poor RAG performance is to attribute it to model capability and address it by scaling up: a larger model, a better fine-tune, or a more advanced foundation. This intuition is reasonable in isolation, but misdiagnoses the problem when retrieval quality is the underlying cause.</p>
<p>Consider the analogy of a highly skilled analyst given a falsified report. The analyst's expertise does not protect against the quality of their source material; it simply makes them more effective at constructing persuasive arguments from whatever they have been given. A more capable LLM, given low-quality retrieved context, produces exactly this outcome: higher-fluency hallucinations. The model's additional capability is applied to rationalizing and elaborating on bad inputs, not to correcting them.</p>
<p>In experimental comparisons between smaller models with high-quality retrieval and larger models with degraded retrieval, the smaller model consistently produced more faithful outputs. The retrieval layer, not the generation layer, sets the effective ceiling on factual accuracy. Investing in retrieval quality improvement yields compounding returns across the entire pipeline, regardless of which model sits at the end.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="four-dimensions-of-retrieval-quality"><strong>Four Dimensions of Retrieval Quality</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#four-dimensions-of-retrieval-quality" class="hash-link" aria-label="Direct link to four-dimensions-of-retrieval-quality" title="Direct link to four-dimensions-of-retrieval-quality" translate="no">​</a></h2>
<p>Improving retrieval quality is not a single intervention but a set of compounding decisions made across the indexing and retrieval pipeline. The following four dimensions represent the areas of highest leverage based on both our experimental findings and the broader research literature.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-embedding-model-selection"><strong>1. Embedding Model Selection</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#1-embedding-model-selection" class="hash-link" aria-label="Direct link to 1-embedding-model-selection" title="Direct link to 1-embedding-model-selection" translate="no">​</a></h3>
<p><a href="https://weaviate.io/blog/vector-embeddings-explained" target="_blank" rel="noopener noreferrer" class="">An embedding model</a> determines how meaning is encoded in a vector space. General-purpose embedding models perform adequately across many domains but show measurable degradation on specialized corpora, particularly in technical, legal, or biomedical contexts. Benchmarking multiple embedding models against a representative sample of real queries from your target domain, before committing to one, is an investment that pays dividends throughout the system's operational life.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-chunking-architecture"><strong>2. Chunking Architecture</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#2-chunking-architecture" class="hash-link" aria-label="Direct link to 2-chunking-architecture" title="Direct link to 2-chunking-architecture" translate="no">​</a></h3>
<p>The chunking <a href="https://weaviate.io/blog/chunking-strategies-for-rag" target="_blank" rel="noopener noreferrer" class="">strategy</a> has an outsized effect on retrieval precision that is frequently underestimated. Fixed-size character chunking routinely breaks semantic units at arbitrary boundaries, producing syntactically incomplete chunks that are poorly represented in the embedding space. More effective approaches include sentence-boundary chunking, recursive splitting that respects paragraph structure, and hierarchical chunking that preserves parent-document context alongside each child chunk.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-retrieval-strategy"><strong>3. Retrieval Strategy</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#3-retrieval-strategy" class="hash-link" aria-label="Direct link to 3-retrieval-strategy" title="Direct link to 3-retrieval-strategy" translate="no">​</a></h3>
<p>Naive top-k vector similarity retrieval is a reasonable starting point, but it is rarely the optimal configuration for production systems. Three enhancements consistently demonstrate measurable improvements in retrieval precision:</p>
<ol start="6">
<li class="">
<p><a href="https://weaviate.io/blog/hybrid-search-explained" target="_blank" rel="noopener noreferrer" class=""><strong>Hybrid search</strong></a><strong>:</strong> Combining dense vector search with sparse BM25 keyword retrieval captures complementary signals. Dense retrieval handles semantic similarity; sparse retrieval handles exact-match and rare-term queries.</p>
</li>
<li class="">
<p><strong>Cross-encoder re-ranking:</strong> A bi-encoder retriever retrieves candidates efficiently at scale. A cross-encoder re-ranker jointly scores each candidate against the full query, which is more computationally intensive but substantially more accurate.</p>
</li>
<li class="">
<p><strong>Relevance thresholding:</strong> Enforcing a minimum similarity score before a chunk enters the context window prevents the low-relevance top-k failure mode. If no retrieved chunk meets the threshold, the system should explicitly surface this.</p>
</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-index-maintenance-and-freshness"><strong>4. Index Maintenance and Freshness</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#4-index-maintenance-and-freshness" class="hash-link" aria-label="Direct link to 4-index-maintenance-and-freshness" title="Direct link to 4-index-maintenance-and-freshness" translate="no">​</a></h3>
<p>The temporal dimension of retrieval quality is underserved in most RAG implementations. A vector index reflects the state of its source documents at the time of indexing. Without active maintenance, index quality degrades in proportion to the rate of change in the underlying domain. Production systems require incremental indexing pipelines that detect document additions and modifications promptly. Document metadata, particularly timestamps, can be used to apply recency weighting or filter stale results at query time.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="evaluating-retrieval-quality-a-practical-measurement-framework"><strong>Evaluating Retrieval Quality: A Practical Measurement Framework</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#evaluating-retrieval-quality-a-practical-measurement-framework" class="hash-link" aria-label="Direct link to evaluating-retrieval-quality-a-practical-measurement-framework" title="Direct link to evaluating-retrieval-quality-a-practical-measurement-framework" translate="no">​</a></h2>
<p>Retrieval quality cannot be improved without measurement. The following metrics provide a structured framework for quantifying retrieval performance:</p>
<ol start="9">
<li class="">
<p><strong>Context Precision:</strong> The fraction of retrieved chunks genuinely relevant to the query. Low precision indicates noisy content entering the context window.</p>
</li>
<li class="">
<p><strong>Context Recall:</strong> The fraction of information required to answer the query that is present in the retrieved set. Low recall forces the model to rely on parametric memory.</p>
</li>
<li class="">
<p><strong>Faithfulness:</strong> The degree to which the generated response is entailed by the retrieved context. This is the critical end-to-end metric measuring whether retrieval quality translates into grounded generation.</p>
</li>
<li class="">
<p><strong>Mean Reciprocal Rank (MRR):</strong> For ranked retrieval results, MRR measures the average position of the first genuinely relevant document.</p>
</li>
</ol>
<p>Frameworks such as <a href="https://weaviate.io/product/integrations/ragas" target="_blank" rel="noopener noreferrer" class="">RAGAS</a>  operationalize these metrics and can be integrated into evaluation pipelines running alongside CI/CD workflows. The goal is to make retrieval quality a tracked, monitored, and historically comparable quantity, not a one-time audit performed during initial system development.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-compounding-problem-retrieval-failure-in-multi-agent-systems"><strong>A Compounding Problem: Retrieval Failure in Multi-Agent Systems</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#a-compounding-problem-retrieval-failure-in-multi-agent-systems" class="hash-link" aria-label="Direct link to a-compounding-problem-retrieval-failure-in-multi-agent-systems" title="Direct link to a-compounding-problem-retrieval-failure-in-multi-agent-systems" translate="no">​</a></h2>
<p>In single-agent RAG systems, retrieval failure has a bounded impact: one query, one generation, one output to evaluate. Multi-agent systems, in which specialized agents operate in sequence and pass context between one another, face a structurally different problem. Retrieval failure at any stage does not stay contained. It propagates.</p>
<p>Consider a representative multi-agent pipeline: a research agent retrieves source material, a synthesis agent summarizes it, a reasoning agent concludes the summary, and a response agent formulates the final output. If the research agent's retrieval is contaminated by a low-relevance chunk or a stale document, the synthesis agent compresses that flawed content into a confident-sounding summary. The reasoning agent then treats that summary as an established fact. The response agent formats and presents the conclusion without indicating that the chain of inference rests on a corrupt foundation.</p>
<p><img decoding="async" loading="lazy" alt="Error propagation in Multi-agent systems" src="https://weaviate.io/assets/images/error_propagation-db8428e9671eb77d4215b25f1955feb3.png" width="2400" height="1600" class="img_ev3q"></p>
<p>This pattern falls under our research taxonomy's Inter-Agent Miscommunication, driven by upstream retrieval failure. Its defining characteristic is that the failure signature at the output layer is entirely disconnected from its origin in the retrieval layer. Diagnosing requires tracing the full agent trajectory, not simply inspecting the final response. Standard output-level evaluation methods are largely blind to this class of error.</p>
<p>The architectural implication is significant. Each agent in a pipeline that performs retrieval or consumes context derived from retrieval requires its own quality validation mechanism. Context that does not meet a defined relevance and freshness standard should be flagged, withheld from downstream agents, or escalated for review, not silently passed forward as though it were trustworthy.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="practical-recommendations-for-production-systems"><strong>Practical Recommendations for Production Systems</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#practical-recommendations-for-production-systems" class="hash-link" aria-label="Direct link to practical-recommendations-for-production-systems" title="Direct link to practical-recommendations-for-production-systems" translate="no">​</a></h2>
<p>The following recommendations reflect the highest-leverage interventions based on experimental findings and practical system design experience. They are ordered by priority for teams addressing retrieval quality for the first time.</p>
<ul>
<li class="">
<p><strong>Begin with a retrieval audit, not a model upgrade.</strong> Before adjusting any generation-layer parameters, manually examine 50 to 100 retrieved results across a representative set of queries. Identify whether the primary issue is chunking quality, model fit for the embedding, index staleness, or threshold configuration.</p>
</li>
<li class="">
<p><strong>Implement hybrid search as a baseline.</strong> Pure dense retrieval consistently underperforms hybrid configurations on real-world corpora. The BM25 component adds minimal latency relative to the precision gains it delivers, particularly for queries involving technical identifiers or domain-specific terminology.</p>
</li>
<li class="">
<p><strong>Enforce retrieval thresholds explicitly.</strong> Configure a minimum similarity score below which retrieved chunks are not passed to the generation layer. A system that returns no context and says so is substantially more trustworthy than one that silently generates from irrelevant material.</p>
</li>
<li class="">
<p><strong>Establish a continuous faithfulness baseline.</strong> Use an automated evaluation framework to measure faithfulness on a held-out query set before and after any pipeline changes. Treat faithfulness as a first-class system metric tracked alongside latency and throughput.</p>
</li>
<li class="">
<p><strong>In a multi-agent architecture,  gate context at every retrieval point.</strong> Each agent that performs retrieval, or that depends on retrieved context from an upstream agent, should apply an independent relevance validation step before incorporating that context into its reasoning.</p>
</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary"><strong>Summary</strong><a href="https://weaviate.io/blog/retrieval-quality-rag-overview#summary" class="hash-link" aria-label="Direct link to summary" title="Direct link to summary" translate="no">​</a></h2>
<p>Retrieval quality is not a secondary concern in RAG-based systems. It is the primary determinant of whether a language model produces reliable, grounded outputs or coherent, undetectable hallucinations. My research on hallucination detection in multi-agent LLM pipelines has consistently pointed to the retrieval layer as the highest leverage point of intervention, both in terms of failure frequency and downstream impact on output trustworthiness.</p>
<p>The practical path forward is clear: measuring retrieval quality explicitly, addressing chunking and embedding decisions with the same rigor applied to model selection, enforcing relevance thresholds rather than relying on the model to compensate for poor context, and in multi-agent systems, treating each agent's retrieval interface as an independent risk surface requiring validation.</p>
<p>The generation layer receives the most attention in applied LLM research and engineering. The retrieval layer deserves more of it.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/retrieval-quality-rag-overview#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=retrieval-quality-rag-overview&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Devika Ambekar</name>
            <uri>https://www.linkedin.com/in/divikaambekar/</uri>
        </author>
        <category label="concepts" term="concepts"/>
        <category label="search" term="search"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Weaviate 1.37 Release]]></title>
        <id>https://weaviate.io/blog/weaviate-1-37-release</id>
        <link href="https://weaviate.io/blog/weaviate-1-37-release"/>
        <updated>2026-04-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[This release introduces the built-in MCP Server, Extensible Tokenizers, Diversity Search (MMR), and Query Profiling as previews, along with Incremental Backups, Gemini audio support for multi2vec-google, and the new BlobHash property type.]]></summary>
        <content type="html"><![CDATA[<p>Weaviate <code>v1.37</code> is now available open-source and on <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a>.</p>
<p>This release is all about extending what Weaviate can do — from how it talks to AI agents, to how it analyzes text, to how it handles large-scale operations. Four new preview features join the release: a <strong>built-in MCP Server</strong> that lets LLMs and IDEs speak to your database natively, <strong>Extensible Tokenizers</strong> with accent folding and custom stopword presets, <strong>Diversity Search (MMR)</strong> for less redundant vector results, and <strong>Query Profiling</strong> for per-shard timing breakdowns. Alongside them, <strong>Incremental Backups</strong> make backing up massive collections practical, <strong>Gemini audio</strong> joins the <code>multi2vec-google</code> module, and the new <strong>BlobHash</strong> property type stores only a hash instead of the full blob.</p>
<p>Here are the release highlights!</p>
<p><img decoding="async" loading="lazy" alt="Weaviate 1.37 is released" src="https://weaviate.io/assets/images/hero-3e3fd110c67bfcc33b3a7e4f321004ad.png" width="1200" height="630" class="img_ev3q"></p>
<ul>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-37-release#mcp-server-preview" class="">MCP Server (Preview)</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-37-release#extensible-tokenizers-preview" class="">Extensible Tokenizers (Preview)</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-37-release#diversity-search-with-mmr-preview" class="">Diversity Search with MMR (Preview)</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-37-release#query-profiling-preview" class="">Query Profiling (Preview)</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-37-release#incremental-backups" class="">Incremental Backups</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-37-release#gemini-audio-support" class="">Gemini Audio Support</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-37-release#blobhash-property-type" class="">BlobHash Property Type</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-37-release#multiple-performance-improvements-and-fixes" class="">Multiple performance improvements and fixes</a></li>
<li class=""><a href="https://weaviate.io/blog/weaviate-1-37-release#community-contributions" class="">Community contributions</a></li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="mcp-server-preview">MCP Server (Preview)<a href="https://weaviate.io/blog/weaviate-1-37-release#mcp-server-preview" class="hash-link" aria-label="Direct link to MCP Server (Preview)" title="Direct link to MCP Server (Preview)" translate="no">​</a></h2>
<p>Weaviate <code>v1.37</code> introduces a <strong>built-in <a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer" class="">Model Context Protocol (MCP)</a> server</strong>, now available as a preview. MCP is an open standard that lets Large Language Models and AI agents interact securely with external systems. By implementing it directly in Weaviate, you can plug your database into compatible clients — <a href="https://code.claude.com/docs/en/mcp" target="_blank" rel="noopener noreferrer" class="">Claude Code</a>, <a href="https://claude.ai/download" target="_blank" rel="noopener noreferrer" class="">Claude Desktop</a>, <a href="https://docs.cursor.com/context/model-context-protocol" target="_blank" rel="noopener noreferrer" class="">Cursor</a>, <a href="https://code.visualstudio.com/docs/copilot/chat/mcp-servers" target="_blank" rel="noopener noreferrer" class="">VS Code</a>, and any other MCP-aware tool — without writing any glue code.</p>
<p>This shifts Weaviate from a passive retrieval engine to an active <strong>long-term memory</strong> for agentic workflows: the LLM can inspect collection schemas, run hybrid searches, and write data back into your instance, all enforced by Weaviate's standard authentication and authorization.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works">How it works<a href="https://weaviate.io/blog/weaviate-1-37-release#how-it-works" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h3>
<p>The server is implemented as a Streamable HTTP endpoint at <code>/v1/mcp</code> on the same port as the REST API. It's <strong>disabled by default</strong>; enable it with a single environment variable:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token key atrule">MCP_SERVER_ENABLED</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'true'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Optional — enable write tools</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">MCP_SERVER_WRITE_ACCESS_ENABLED</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'true'</span><br></span></code></pre></div></div>
<p>Once enabled, the server exposes four tools:</p>
<table><thead><tr><th>Tool</th><th>Description</th></tr></thead><tbody><tr><td><code>weaviate-collections-get-config</code></td><td>Inspect collection schemas</td></tr><tr><td><code>weaviate-tenants-list</code></td><td>List tenants for multi-tenant collections</td></tr><tr><td><code>weaviate-query-hybrid</code></td><td>Run hybrid (vector + keyword) search</td></tr><tr><td><code>weaviate-objects-upsert</code></td><td>Insert or update objects (only if write access is enabled)</td></tr></tbody></table>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="granular-permissions">Granular permissions<a href="https://weaviate.io/blog/weaviate-1-37-release#granular-permissions" class="hash-link" aria-label="Direct link to Granular permissions" title="Direct link to Granular permissions" translate="no">​</a></h4>
<p>If you're using RBAC, MCP access is governed by three new permissions — <code>read_mcp</code>, <code>create_mcp</code>, and <code>update_mcp</code> — so you can grant agents exactly the capabilities they need and nothing more.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="custom-tool-descriptions">Custom tool descriptions<a href="https://weaviate.io/blog/weaviate-1-37-release#custom-tool-descriptions" class="hash-link" aria-label="Direct link to Custom tool descriptions" title="Direct link to Custom tool descriptions" translate="no">​</a></h4>
<p>You can tailor the tool descriptions the LLM sees by mounting a YAML or JSON config file at <code>MCP_SERVER_CONFIG_PATH</code>. This is useful for steering agents toward the shape of your specific data without retraining or prompting tricks.</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># mcp-config.yaml</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token key atrule">tools</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token key atrule">weaviate-query-hybrid</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">description</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'Search our product catalog by name or description.'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token key atrule">arguments</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token key atrule">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"The shopper's natural-language query."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token key atrule">alpha</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">'0.0 = keyword only, 1.0 = vector only, 0.5 = balanced.'</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Preview</div><div class="admonitionContent_BuS1"><p>MCP Server is currently a <strong>preview</strong> feature. The API and behavior may change in future releases.</p></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/mcp/mcp-server" target="_blank" rel="noopener noreferrer" class="">Docs: Weaviate MCP server</a></li>
<li class=""><a href="https://modelcontextprotocol.io/" target="_blank" rel="noopener noreferrer" class="">Model Context Protocol</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="extensible-tokenizers-preview">Extensible Tokenizers (Preview)<a href="https://weaviate.io/blog/weaviate-1-37-release#extensible-tokenizers-preview" class="hash-link" aria-label="Direct link to Extensible Tokenizers (Preview)" title="Direct link to Extensible Tokenizers (Preview)" translate="no">​</a></h2>
<p>Keyword search quality starts long before <a href="https://en.wikipedia.org/wiki/Okapi_BM25" target="_blank" rel="noopener noreferrer" class="">BM25</a> runs its calculation — it's decided by the analyzer that turns text into tokens. Three additions ship as a preview:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="accent-folding">Accent folding<a href="https://weaviate.io/blog/weaviate-1-37-release#accent-folding" class="hash-link" aria-label="Direct link to Accent folding" title="Direct link to Accent folding" translate="no">​</a></h3>
<p>The new <code>textAnalyzer.asciiFold</code> flag normalizes accented Latin characters (and other diacritics) to their ASCII equivalents, during both indexing and querying. A document containing "Café Crème" becomes searchable as "cafe creme" — and vice versa.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"name"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"description"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"dataType"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"text"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"tokenization"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"word"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"textAnalyzer"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"> </span><span class="token property">"asciiFold"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token boolean">true</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>Under the hood, Weaviate uses <a href="https://unicode.org/reports/tr15/" target="_blank" rel="noopener noreferrer" class="">Unicode NFD decomposition</a> plus an explicit replacement table for single-codepoint letters (<code>ł</code>, <code>æ</code>, <code>ø</code>, <code>ð</code>, <code>þ</code>, <code>đ</code>, <code>ß</code>, and more). Together that covers 20+ Latin-script languages out of the box. If you need to preserve specific characters — for example, an <code>é</code> that distinguishes two product names — use the <code>asciiFoldIgnore</code> array to exempt them.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="custom-and-per-property-stopwords">Custom and per-property stopwords<a href="https://weaviate.io/blog/weaviate-1-37-release#custom-and-per-property-stopwords" class="hash-link" aria-label="Direct link to Custom and per-property stopwords" title="Direct link to Custom and per-property stopwords" translate="no">​</a></h3>
<p>Weaviate previously shipped with <code>en</code> and <code>none</code> as the only stopword options. As of <code>v1.37</code> you can declare named stopword presets on the collection and assign different presets to individual properties — perfect for multilingual collections where, say, a <code>name_fr</code> property needs French stopwords (<code>le</code>, <code>la</code>, <code>et</code>) while a <code>name_en</code> property uses English.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"invertedIndexConfig"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"stopwordPresets"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"fr"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"le"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"la"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"les"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"un"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"une"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"des"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"du"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"de"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"et"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>Stopwords are still written to the <a href="https://docs.weaviate.io/weaviate/concepts/indexing/inverted-index" target="_blank" rel="noopener noreferrer" class="">inverted index</a> — they're only filtered out at query time — which means you can change the configuration without reindexing your data.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-tokenize-endpoint">The tokenize endpoint<a href="https://weaviate.io/blog/weaviate-1-37-release#the-tokenize-endpoint" class="hash-link" aria-label="Direct link to The tokenize endpoint" title="Direct link to The tokenize endpoint" translate="no">​</a></h3>
<p>The hardest part of tuning a text analyzer is knowing what it actually produced. Two new REST endpoints make the tokenization process transparent:</p>
<ul>
<li class=""><code>POST /v1/tokenize</code> — Tokenize arbitrary text with any tokenizer and analyzer config. Perfect for experimenting before committing to a schema.</li>
<li class=""><code>POST /v1/schema/{className}/properties/{propertyName}/tokenize</code> — Tokenize text using an existing property's exact configuration.</li>
</ul>
<p>Both return a structured response that separates <code>indexed</code> tokens (what goes into the inverted index) from <code>query</code> tokens (what BM25 actually scores after stopword filtering):</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"tokenization"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"word"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"indexed"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"the"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"organic"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"cafe"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"creme"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"blend"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"query"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"organic"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"cafe"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"creme"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"blend"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Preview</div><div class="admonitionContent_BuS1"><p>Extensible tokenizers are currently a <strong>preview</strong> feature. The API and behavior may change in future releases.</p></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/concepts/indexing/inverted-index#accent-folding" target="_blank" rel="noopener noreferrer" class="">Concepts: Inverted index - Accent folding</a></li>
<li class=""><a href="https://docs.weaviate.io/weaviate/tutorials/tokenization" target="_blank" rel="noopener noreferrer" class="">Tutorial: Tokenization</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="diversity-search-with-mmr-preview">Diversity Search with MMR (Preview)<a href="https://weaviate.io/blog/weaviate-1-37-release#diversity-search-with-mmr-preview" class="hash-link" aria-label="Direct link to Diversity Search with MMR (Preview)" title="Direct link to Diversity Search with MMR (Preview)" translate="no">​</a></h2>
<p>Standard vector search has a known side-effect: it clusters near-duplicates. A query like "Italian food" returns five pizza images; a RAG pipeline retrieves five chunks that all say roughly the same thing. Relevance alone isn't enough — you also need <strong>diversity</strong>.</p>
<p>Weaviate <code>v1.37</code> introduces <strong><a href="https://dl.acm.org/doi/10.1145/290941.291025" target="_blank" rel="noopener noreferrer" class="">Maximum Marginal Relevance (MMR)</a></strong> as a new query-time reranking step, available as a preview. MMR iteratively picks the most relevant item first, then penalizes candidates that are too similar to what has already been selected — so each new result has to earn its place by adding something new.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-use-it">How to use it<a href="https://weaviate.io/blog/weaviate-1-37-release#how-to-use-it" class="hash-link" aria-label="Direct link to How to use it" title="Direct link to How to use it" translate="no">​</a></h3>
<p>Add a <code>selection</code> parameter to any <code>near_*</code> query in the Python client:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> Diversity</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">response </span><span class="token operator">=</span><span class="token plain"> collection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">near_vector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    near_vector</span><span class="token operator">=</span><span class="token plain">query_vector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    limit</span><span class="token operator">=</span><span class="token number">20</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    selection</span><span class="token operator">=</span><span class="token plain">Diversity</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">MMR</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        limit</span><span class="token operator">=</span><span class="token number">5</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        balance</span><span class="token operator">=</span><span class="token number">0.5</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>The top-level <code>limit</code> controls the size of the candidate set; <code>Diversity.MMR(limit)</code> controls how many results are returned after reranking. The <code>balance</code> parameter (λ) controls the trade-off between relevance and diversity:</p>
<ul>
<li class=""><strong><code>0.0</code></strong> — Pure diversity; maximize difference between results</li>
<li class=""><strong><code>0.5</code></strong> — Balanced; each result must be both relevant and distinct</li>
<li class=""><strong><code>1.0</code></strong> — Pure relevance; equivalent to standard vector search</li>
</ul>
<p>MMR is applied at query time, on top of an existing vector index — no reindexing or schema changes are required. It works with <code>near_text</code>, <code>near_vector</code>, <code>near_object</code>, <code>near_image</code>, and <code>near_media</code>.</p>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Preview</div><div class="admonitionContent_BuS1"><p>MMR diversity selection is currently a <strong>preview</strong> feature. The API and behavior may change in future releases.</p><ul>
<li class=""><strong>Python client</strong>: Support is not yet in a released <code>weaviate-client</code>. Coming in the next release (tracked in <a href="https://github.com/weaviate/weaviate-python-client/pull/1997" target="_blank" rel="noopener noreferrer" class="">PR #1997</a>).</li>
<li class=""><strong>Multi-node clusters</strong>: MMR reranking may produce suboptimal results for collections whose shards are distributed across multiple nodes, since each shard returns its own candidate set before the coordinator reranks them. We are actively working on improving this.</li>
</ul></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/search/similarity#diversity-selection-mmr" target="_blank" rel="noopener noreferrer" class="">How-to: Diversity selection (MMR)</a></li>
<li class=""><a href="https://docs.weaviate.io/weaviate/concepts/search/vector-search#diversity-selection-mmr" target="_blank" rel="noopener noreferrer" class="">Concepts: Vector search - MMR</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="query-profiling-preview">Query Profiling (Preview)<a href="https://weaviate.io/blog/weaviate-1-37-release#query-profiling-preview" class="hash-link" aria-label="Direct link to Query Profiling (Preview)" title="Direct link to Query Profiling (Preview)" translate="no">​</a></h2>
<p>When a query is slow, the first question is always "where did the time go?" Weaviate <code>v1.37</code> makes that question easy to answer with <strong>query profiling</strong>, available as a preview — per-shard timing breakdowns attached to any search request.</p>
<p>Request profile data by setting <code>query_profile=True</code> in <code>MetadataQuery</code>:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">from</span><span class="token plain"> weaviate</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">classes</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">import</span><span class="token plain"> MetadataQuery</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">response </span><span class="token operator">=</span><span class="token plain"> collection</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">near_vector</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    near_vector</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token number">0.1</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">0.2</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token number">0.3</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    limit</span><span class="token operator">=</span><span class="token number">10</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    return_metadata</span><span class="token operator">=</span><span class="token plain">MetadataQuery</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain">query_profile</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> shard </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> response</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">query_profile</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">shards</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"Shard: </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">shard</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token string-interpolation interpolation">name</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)"> (node: </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">shard</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token string-interpolation interpolation">node</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">)"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> search_type</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> profile </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> shard</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">searches</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">items</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"  [</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">search_type</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">]"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">for</span><span class="token plain"> key</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> value </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">in</span><span class="token plain"> profile</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">details</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">items</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">            </span><span class="token keyword" style="color:rgb(189, 147, 249);font-style:italic">print</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">f"    </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">key</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">: </span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string-interpolation interpolation">value</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token string-interpolation string" style="color:rgb(255, 121, 198)">"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>The profile is structured per shard and per search type (<code>vector</code>, <code>keyword</code>, <code>object</code>), with metrics like <code>vector_search_took</code>, <code>filters_ids_matched</code>, <code>knn_search_layer_N_took</code>, <code>kwd_method</code>, and <code>total_took</code>. For hybrid search, you get both vector and keyword sections per shard. For multi-node clusters, the coordinator aggregates timings from every shard — each entry includes the node that executed it, making performance imbalances easy to spot.</p>
<p>Profiling uses the same instrumentation as slow query logging, so overhead is minimal when enabled and zero when disabled.</p>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Preview</div><div class="admonitionContent_BuS1"><p>Query profiling is currently a <strong>preview</strong> feature. The API and behavior may change in future releases.</p></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/search/query-profile" target="_blank" rel="noopener noreferrer" class="">How-to: Query profiling</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="incremental-backups">Incremental Backups<a href="https://weaviate.io/blog/weaviate-1-37-release#incremental-backups" class="hash-link" aria-label="Direct link to Incremental Backups" title="Direct link to Incremental Backups" translate="no">​</a></h2>
<p>Backing up a 100GB collection every night is expensive when only a few percent of the data changed since yesterday. Weaviate <code>v1.37</code> introduces <strong>incremental backups</strong>: files unchanged since the last backup are stored as references rather than copied again. The result is dramatically smaller backups and much faster backup times.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-works-1">How it works<a href="https://weaviate.io/blog/weaviate-1-37-release#how-it-works-1" class="hash-link" aria-label="Direct link to How it works" title="Direct link to How it works" translate="no">​</a></h3>
<p>When a backup runs, Weaviate splits large files into chunks. During an incremental backup, each chunk is compared against the base backup — and if it's unchanged, a pointer is stored instead of the file. On restore, Weaviate automatically walks the chain and pulls the referenced files from the earlier backup.</p>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="creating-incremental-backups">Creating incremental backups<a href="https://weaviate.io/blog/weaviate-1-37-release#creating-incremental-backups" class="hash-link" aria-label="Direct link to Creating incremental backups" title="Direct link to Creating incremental backups" translate="no">​</a></h4>
<p>Start with a regular (full) backup, then reference it as the base for future incrementals:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token comment" style="color:rgb(98, 114, 164)"># Step 1: Create a full backup to act as the base</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">result </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">backup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    backup_id</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"base-backup"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    backend</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"filesystem"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    include_collections</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"Article"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Publication"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    wait_for_completion</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token comment" style="color:rgb(98, 114, 164)"># Step 2: Create an incremental backup against the base</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">result </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">backup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    backup_id</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"incremental-backup-1"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    backend</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"filesystem"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    include_collections</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"Article"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Publication"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    wait_for_completion</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    incremental_base_backup_id</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"base-backup"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>You can also <strong>chain</strong> incremental backups — each one referencing the previous — to build a longer history cheaply:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">result </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">backup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">create</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    backup_id</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"incremental-backup-2"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    backend</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"filesystem"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    include_collections</span><span class="token operator">=</span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"Article"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Publication"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    wait_for_completion</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    incremental_base_backup_id</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"incremental-backup-1"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="restoring">Restoring<a href="https://weaviate.io/blog/weaviate-1-37-release#restoring" class="hash-link" aria-label="Direct link to Restoring" title="Direct link to Restoring" translate="no">​</a></h4>
<p>Restoring an incremental backup works exactly like restoring a full backup — Weaviate resolves the chain and fetches files from earlier backups as needed:</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">result </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">backup</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">restore</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    backup_id</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"incremental-backup-2"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    backend</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"filesystem"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    wait_for_completion</span><span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Keep base backups available</div><div class="admonitionContent_BuS1"><p>The base backup (and any intermediate incremental backups in a chain) must remain available for as long as you need to restore from any incremental backup that depends on them.</p></div></div>
<p>Also worth highlighting alongside this: in <code>v1.37</code>, <strong>INACTIVE (COLD) tenants are now included in backups</strong>, read directly from disk without activation. Previously, only active tenants were backed up.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/deploy/configuration/backups#incremental-backups" target="_blank" rel="noopener noreferrer" class="">Configuration: Backups — Incremental backups</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="gemini-audio-support">Gemini Audio Support<a href="https://weaviate.io/blog/weaviate-1-37-release#gemini-audio-support" class="hash-link" aria-label="Direct link to Gemini Audio Support" title="Direct link to Gemini Audio Support" translate="no">​</a></h2>
<p>The <a href="https://docs.weaviate.io/weaviate/model-providers/google/embeddings-multimodal" target="_blank" rel="noopener noreferrer" class=""><code>multi2vec-google</code></a> module now supports <strong>audio as a fourth modality</strong>, alongside text, images, and videos. Configure audio properties via the new <code>audioFields</code> setting, the same way you would <code>imageFields</code> or <code>videoFields</code>.</p>
<p>Audio support is only available through the <strong><a href="https://ai.google.dev/gemini-api/docs" target="_blank" rel="noopener noreferrer" class="">Gemini API</a></strong> (<a href="https://aistudio.google.com/" target="_blank" rel="noopener noreferrer" class="">Google AI Studio</a>) — <a href="https://cloud.google.com/vertex-ai" target="_blank" rel="noopener noreferrer" class="">Vertex AI</a> doesn't currently support audio embeddings. That makes the Gemini API path attractive for any multimodal use case that needs to unify text, visual, and audio content in a single vector space.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/model-providers/google/embeddings-multimodal" target="_blank" rel="noopener noreferrer" class="">Model providers: Google multimodal embeddings</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="blobhash-property-type">BlobHash Property Type<a href="https://weaviate.io/blog/weaviate-1-37-release#blobhash-property-type" class="hash-link" aria-label="Direct link to BlobHash Property Type" title="Direct link to BlobHash Property Type" translate="no">​</a></h2>
<p>If you use a module like <code>multi2vec-google</code> to vectorize media, the vectorizer only needs the raw bytes during import — after that, the blob just sits in storage taking up space. The new <strong><code>blobHash</code></strong> data type in <code>v1.37</code> addresses this directly: it accepts base64-encoded input (like <code>blob</code>) but persists only a <strong><a href="https://en.wikipedia.org/wiki/SHA-2" target="_blank" rel="noopener noreferrer" class="">SHA-256</a> hash</strong> on disk.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"properties"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"name"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"image"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      </span><span class="token property">"dataType"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token string" style="color:rgb(255, 121, 198)">"blobHash"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>The raw base64 data still flows through the vectorization pipeline, so modules can embed the actual media content. Only after vectorization does Weaviate replace the payload with its hash. On subsequent updates, incoming data is hashed and compared against the stored hash to decide whether re-vectorization is needed.</p>
<p>This is a great fit for workflows where you want the vector in Weaviate but the canonical media lives in object storage (e.g., <a href="https://aws.amazon.com/s3/" target="_blank" rel="noopener noreferrer" class="">S3</a>) — the hash lets you correlate back to the original without paying the disk cost of duplicating it.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/weaviate/config-refs/datatypes#blobhash" target="_blank" rel="noopener noreferrer" class="">Config references: Data types - blobHash</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="multiple-performance-improvements-and-fixes">Multiple Performance Improvements and Fixes<a href="https://weaviate.io/blog/weaviate-1-37-release#multiple-performance-improvements-and-fixes" class="hash-link" aria-label="Direct link to Multiple Performance Improvements and Fixes" title="Direct link to Multiple Performance Improvements and Fixes" translate="no">​</a></h2>
<p>Weaviate <code>v1.37</code> also ships many smaller features and improvements. Here are some highlights:</p>
<ul>
<li class=""><strong>Collection Export (Preview):</strong> A new <code>/v1/export</code> API lets you export collections to S3, GCS, Azure, or the local filesystem as <a href="https://parquet.apache.org/" target="_blank" rel="noopener noreferrer" class="">Apache Parquet</a> — useful for offline analytics, migrations, and data pipelines. See the <a href="https://docs.weaviate.io/deploy/configuration/export" target="_blank" rel="noopener noreferrer" class="">Collection export docs</a> for details.</li>
<li class=""><strong>HFresh improvements:</strong> Numerous optimizations to <a class="" href="https://weaviate.io/blog/weaviate-1-36-release#hfresh-preview">HFresh</a> (the disk-based vector index introduced in <code>v1.36</code>), including reduced memory usage, fewer disk writes, and better dequeuing during backups.</li>
<li class=""><strong><code>DEFAULT_SHARDING_COUNT</code> env var:</strong> Override the default <code>desiredCount</code> for new single-tenant collections instead of using the cluster node count. Runtime-configurable and user-specified <code>desiredCount</code> still takes precedence.</li>
<li class=""><strong>S3 assume role for backups:</strong> The <code>backup-s3</code> module now supports AWS assume role authentication, making it easier to integrate with IAM-based deployments.</li>
<li class=""><strong>Google AI Studio in <code>multi2vec-google</code>:</strong> Google AI Studio API keys now work with the multi2vec-google module, in addition to Vertex AI.</li>
<li class=""><strong>IPv6 clustering:</strong> Weaviate now supports IPv6 addresses for internal cluster communication.</li>
<li class=""><strong>Internal cluster gRPC:</strong> Replica communication migrated from REST to gRPC, with improved connection management and binary encoding for digest responses.</li>
<li class=""><strong>Reranker-cohere v2:</strong> The Cohere reranker module upgraded from the v1 to the v2 rerank endpoint.</li>
<li class=""><strong>OIDC insecure TLS skip:</strong> New <code>AUTHENTICATION_OIDC_INSECURE_SKIP_TLS_VERIFY</code> env var for OIDC issuers with self-signed or untrusted certificates in dev/test environments.</li>
<li class=""><strong>Performance:</strong> HNSW sparse visited lists, pre-computed average property length, delayed quantization until cache prefill, non-blocking compaction during backup, better bitmap handling for segment searches, and more.</li>
<li class=""><strong>Bug fixes:</strong> Eventual consistency improvements, RBAC restore race conditions, vector index error handling, IPv6 address parsing, filter edge cases, and many others.</li>
</ul>
<p>We always recommend running the latest version of Weaviate to benefit from these ongoing improvements.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://github.com/weaviate/weaviate/releases/tag/v1.37.0" target="_blank" rel="noopener noreferrer" class="">Weaviate 1.37: GitHub Release Notes</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="community-contributions">Community Contributions<a href="https://weaviate.io/blog/weaviate-1-37-release#community-contributions" class="hash-link" aria-label="Direct link to Community Contributions" title="Direct link to Community Contributions" translate="no">​</a></h2>
<p>Weaviate is an open-source project, and we're always thrilled to see contributions from our amazing community. For this release, we are super excited to shout-out the following first-time contributors:</p>
<ul>
<li class=""><a href="https://github.com/junjieqi" target="_blank" rel="noopener noreferrer" class="">@junjieqi</a> contributed <a href="https://github.com/weaviate/weaviate/pull/10722" target="_blank" rel="noopener noreferrer" class="">#10722</a> — IPv6 support for clustering</li>
</ul>
<p>If you're interested in contributing to Weaviate, please check out our <a href="https://docs.weaviate.io/contributor-guide/" target="_blank" rel="noopener noreferrer" class="">contribution guide</a>, and browse the open issues on <a href="https://github.com/weaviate/weaviate/issues" target="_blank" rel="noopener noreferrer" class="">GitHub</a>. Look for the <code>good-first-issue</code> label to find great starting points!</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Related resources</div><div class="admonitionContent_BuS1"><ul>
<li class=""><a href="https://docs.weaviate.io/contributor-guide" target="_blank" rel="noopener noreferrer" class="">Contributor Guide</a></li>
</ul></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="summary">Summary<a href="https://weaviate.io/blog/weaviate-1-37-release#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary" translate="no">​</a></h2>
<p>Weaviate <code>v1.37</code> broadens how your data integrates with the rest of your stack — from AI agents and IDEs to analytics pipelines and multilingual workloads.</p>
<p><strong>Key highlights:</strong></p>
<ul>
<li class=""><strong>MCP Server (Preview)</strong> — Native integration with AI agents and IDEs via the Model Context Protocol</li>
<li class=""><strong>Extensible Tokenizers (Preview)</strong> — Accent folding, custom stopword presets, and a tokenize endpoint for observability</li>
<li class=""><strong>Diversity Search with MMR (Preview)</strong> — Query-time reranking that balances relevance and diversity</li>
<li class=""><strong>Query Profiling (Preview)</strong> — Per-shard timing breakdowns for any search request</li>
<li class=""><strong>Incremental Backups</strong> — Smaller, faster backups that reference unchanged files from a base backup</li>
<li class=""><strong>Gemini Audio Support</strong> — Audio as a fourth modality in <code>multi2vec-google</code> (Gemini API only)</li>
<li class=""><strong>BlobHash Property Type</strong> — Vectorize media at import, persist only a SHA-256 hash</li>
</ul>
<p><strong>Ready to get started?</strong></p>
<p>The release is available open-source on <a href="https://github.com/weaviate/weaviate/releases/tag/v1.37.0" target="_blank" rel="noopener noreferrer" class="">GitHub</a> and is already available for new Sandboxes on <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a>.</p>
<p>For those upgrading a self-hosted version, please check the <a href="https://docs.weaviate.io/deploy/migration#general-upgrade-instructions" target="_blank" rel="noopener noreferrer" class="">migration guide</a> for version-specific notes.</p>
<p>Thanks for reading, and happy vector searching!</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/weaviate-1-37-release#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=weaviate-1-37-release&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Ivan Despot</name>
            <uri>https://www.linkedin.com/in/ivan-g-despot/</uri>
        </author>
        <category label="release" term="release"/>
        <category label="engineering" term="engineering"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Engram: Memory by Weaviate]]></title>
        <id>https://weaviate.io/blog/engram-deep-dive</id>
        <link href="https://weaviate.io/blog/engram-deep-dive"/>
        <updated>2026-04-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A deep dive into Engram, our managed memory service for agents which is simple to get started but adaptable to any use case.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Hero" src="https://weaviate.io/assets/images/hero-dde66a718f40b1d04a8ba5e015fc35f4.png" width="1200" height="630" class="img_ev3q"></p>
<br>
<blockquote>
<p><strong>Get started with <a class="" href="https://weaviate.io/product/engram">Engram</a> in <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a> today.</strong></p>
</blockquote>
<br>
<p>As agentic applications have gone from experimental features to production use cases, it's become clear that they’re most effective when they’re fully integrated into the rest of your system, are strongly personalised to the user, and can continually learn to get better over time. These agents need memory, designed as robust and predictable infrastructure rather than an ad-hoc afterthought. That's why we built Engram, a managed memory service running on top of Weaviate, which focuses on being easy to get started but flexible enough to adapt to any use case.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-memory">What is memory?<a href="https://weaviate.io/blog/engram-deep-dive#what-is-memory" class="hash-link" aria-label="Direct link to What is memory?" title="Direct link to What is memory?" translate="no">​</a></h2>
<p>It can be a major annoyance when a chatbot forgets your preferences. However, as we discussed in <a href="https://weaviate.io/blog/limit-in-the-loop" target="_blank" rel="noopener noreferrer" class="">The Limit in the Loop</a>, the problem is potentially far worse for agents carrying out long-running and complex tasks. Without the continuity of memory, agents are unable to learn from past experience, becoming stuck in a constant cycle of solving the same intermediate problems repeatedly before losing those insights, wasting both time and tokens in the process.</p>
<p>While the long context windows of frontier models might seem like a solution to this problem, cramming them full is rarely the best approach. It is well known that LLMs get <a href="https://arxiv.org/abs/2307.03172" target="_blank" rel="noopener noreferrer" class="">Lost in the Middle</a> and that effective context lengths are still far below 100% (e.g., <a href="https://arxiv.org/abs/2601.02872" target="_blank" rel="noopener noreferrer" class="">here</a> and <a href="https://arxiv.org/abs/2502.05167" target="_blank" rel="noopener noreferrer" class="">here</a>). Not only does overly-long context degrade accuracy, it also increases answer latency and inflates the cost of requests. These costs must be paid for every new message, as the entire conversation history is passed back to the LLM.</p>
<p>Naively storing each message of every conversation for retrieval addresses the latency and cost issues, but has other downsides. Raw conversations with real users are noisy, contradictory, and include facts that change over time. Relying on an LLM to resolve these inconsistencies all at once is harder than doing it incrementally. This not only risks inconsistency over time, it is also work that cannot be reused next time those facts are relevant. Treating all memory as a single conversation also fails to adapt to more advanced use cases such as multi-agent systems, which can spread a single logical request across multiple context windows.</p>
<p>The best solution to these problems is to not treat memories as an ever-growing pile of context, but instead to actively maintain them.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="engram">Engram<a href="https://weaviate.io/blog/engram-deep-dive#engram" class="hash-link" aria-label="Direct link to Engram" title="Direct link to Engram" translate="no">​</a></h2>
<p>Engram is our managed memory service, built on the Weaviate vector database. It is designed around asynchronous pipelines that run when you add raw data, extracting memories, reconciling new and existing information, and persisting to Weaviate ready for querying.</p>
<p><img decoding="async" loading="lazy" alt="Engram Overview" src="https://weaviate.io/assets/images/engram_overview-a52ce7f31c6db24358005c56b82bd8c1.png" width="1800" height="863" class="img_ev3q"></p>
<p>Engram has been designed to be as simple as possible to get started, providing starter templates for common memory use cases. However, underlying this is a highly flexible and configurable system that can adapt to a wide variety of different domains and use cases. Customisations span from simple natural language descriptions of what topics are of interest to your use case, up to full control of the individual steps within the pipeline. As your need for agentic memory evolves, the adaptability of Engram means you won’t get stuck shoehorning a constraining and prescriptive design of memory into your application.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="getting-started-with-engram">Getting started with Engram<a href="https://weaviate.io/blog/engram-deep-dive#getting-started-with-engram" class="hash-link" aria-label="Direct link to Getting started with Engram" title="Direct link to Getting started with Engram" translate="no">​</a></h3>
<p>Once you've created your Engram project API key, you can easily start adding data to Engram for one of your users by using our REST API or Python client:</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">run </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">memories</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">add</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string" style="color:rgb(255, 121, 198)">"role"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"user"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"content"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"I'm very interested in vectors, please tell me more!"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token string" style="color:rgb(255, 121, 198)">"role"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"assistant"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"content"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Absolutely! Vectors are a fascinating..."</span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    user_id</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"user_name"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>As a result of this call, Engram will begin a new pipeline run to extract memories from your data that match your configured topics and integrate them into your existing memories. For example, this call could result in a new memory detailing that user's love of vectors. But, if they'd shared that love in a previous conversation, Engram would disregard this to avoid creating duplicate memories.</p>
<p>Since pipelines run asynchronously in Engram, this request has very low latency. Rather than being forced to wait for the final changes to your memories from this run (or having to manage running this as a background task yourself), you can just fire-and-forget your raw data, and rely on Engram to remember what's needed.</p>
<p>Of course, if you want to follow up the status of this run and understand what changes were made to your memories as a result, you can query Engram with the run ID returned by <code>client.memories.add</code>. However, since there's less value in querying memories for the most recent messages which are in context, this asynchronous pattern naturally leads you to integrate Engram into your application in a straightforward and low-latency way.</p>
<p>Later, you can retrieve relevant memories from Engram using semantic search, powered by Weaviate's vector index:</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">memories </span><span class="token operator">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">memories</span><span class="token punctuation" style="color:rgb(248, 248, 242)">.</span><span class="token plain">search</span><span class="token punctuation" style="color:rgb(248, 248, 242)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token string" style="color:rgb(255, 121, 198)">"What technology has the user asked about recently?"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    user_id</span><span class="token operator">=</span><span class="token string" style="color:rgb(255, 121, 198)">"user_name"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">)</span><br></span></code></pre></div></div>
<p>While that's all you need to start using Engram to give your agents memory, it has been designed to be flexible, so let's dive into what's happening behind this simple API!</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="organising-memories">Organising memories<a href="https://weaviate.io/blog/engram-deep-dive#organising-memories" class="hash-link" aria-label="Direct link to Organising memories" title="Direct link to Organising memories" translate="no">​</a></h3>
<p>When Engram extracts memories from your raw data, it automatically organises them into one of your pre-configured topics. Topics are natural language descriptions of what information the LLM should extract and how to categorise it. Think of them as "magnets for memories", pulling matching information out of the raw data. Memories will only be extracted from your raw data if they match one of your topics, giving you control over what sort of information is relevant for your domain and particular use case. Each of the default templates available in Engram has topics pre-configured, but these are all fully customisable. Adjusting these topics is the most effective way for you to control the content of the memories you will query later.</p>
<p>Each topic has a "scope" that controls which raw data is allowed to influence each memory. Scopes combine optional hard and soft isolation of memories to give several different combinations:</p>
<ul>
<li class=""><strong>Project-wide</strong> memories are shared between all users in your project, letting you share information quickly between a team or have your agent continually learn from all of its experiences.</li>
<li class=""><strong>User-scoped</strong> memories belong to one specific user and can never be influenced by data added for another user. Hard isolation between user data is strictly enforced by Weaviate's multi-tenancy feature.</li>
<li class=""><strong>Property-scoped</strong> memories have additional key-value data attached. These give soft isolation, meaning that while Engram always enforces this separation when creating and updating memories from new data, you have the option of querying these memories either filtered by these properties or not. For example, this could be used to attach a <code>conversation_id</code> and have memories relating to a single conversation only, while still being able to search over memories across all a user's conversations if needed.</li>
</ul>
<p>Scopes are enforced by Engram both when adding data and querying memories, meaning you can never forget to pass a <code>user_id</code> and accidentally leak data between your users.</p>
<p>All of your Engram configuration is then collected into groups, which combine the topics (which control <em>what</em> memories are extracted) and associated pipeline (which controls <em>how</em> memories are extracted). Memories belonging to one group are isolated from other groups using multi-tenancy, and should correspond to distinct use cases in your application that you want to keep separate. Each group can contain multiple topics, and each topic can have different scopes.</p>
<p>Topics can also be marked as being <code>bounded</code>, which means that Engram will constrain memories in this topic to have at most one object per scope (e.g., once per user, or once per conversation). This can be used to implement features such as user profiles, where you know your agent will always have that memory in their system prompt (and so it must be comprehensive). The provided <code>personalization</code> template also includes an optional <code>ConversationSummary</code> topic which continually updates with every new chat message, and so is marked as a <code>bounded</code> topic to ensure there is at most one summary per conversation.</p>
<p><img decoding="async" loading="lazy" alt="Groups" src="https://weaviate.io/assets/images/groups-5a55949a6c9ad98b0c18fb9bf7c51c4c.png" width="1800" height="1011" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="processing-raw-data-into-memories">Processing raw data into memories<a href="https://weaviate.io/blog/engram-deep-dive#processing-raw-data-into-memories" class="hash-link" aria-label="Direct link to Processing raw data into memories" title="Direct link to Processing raw data into memories" translate="no">​</a></h3>
<p>Engram uses pipelines to control exactly how raw data is processed into memories persisted in Weaviate. This unique approach to building memory gives you the maximum possible flexibility, letting you adapt memory to your specific use case rather than the other way around. At the same time, prebuilt templates covering common use cases make it simple to get started without needing to handle all these details right away.</p>
<p>Pipelines are graphs of steps which run asynchronously, gradually transforming raw data into batches of memories which are persisted in Weaviate. We’ve built these pipelines on top of <a href="https://temporal.io/" target="_blank" rel="noopener noreferrer" class="">Temporal</a> workflows to provide durable execution. As a result, you can be confident that once data has been successfully added to Engram, the pipeline will run and any resulting changes to objects in Weaviate will be completed. This also lets us enforce strict in-order processing of raw data. You can add many batches of data rapidly (thanks to the low-latency API) and Engram will queue the pipeline runs, grouping by the scope IDs you provide, ensuring that processing is done in the order you added data without you having to manually manage it.</p>
<p>Pipelines give us a way to flexibly control how raw data is processed into stored memories by composing various types of steps, so let’s look at those steps in more detail!</p>
<p><img decoding="async" loading="lazy" alt="Pipeline" src="https://weaviate.io/assets/images/pipeline-bccdae7254eb0b185bc5e1bab9178d93.png" width="1800" height="1530" class="img_ev3q"></p>
<p>The first step in a pipeline is often an extract step. This step type uses an LLM to write memories using the content of your data which match the topics you've configured. Engram supports multiple different input types, and each of these have their own dedicated extract steps:</p>
<ul>
<li class=""><strong>Conversation data</strong> contains a list of messages in the standard <code>role</code>/<code>content</code> format. This is ideal for naturally conversationally shaped data, such as for chatbot applications.</li>
<li class=""><strong>String data</strong> gives you a flexible way to insert data that doesn't fit into a standard conversation shape (e.g., user events like "User viewed page X"), while still letting Engram handle extracting memories for you.</li>
<li class=""><strong>Pre-extracted memories</strong> are an escape hatch for when you want to handle extraction yourself, e.g., by using your own tool-calling agent. In this case, you pass both the content string and the corresponding topic, and Engram passes them immediately onto the next pipeline step without further extraction. This lets you handle the extraction process completely while still taking advantage of the rest of Engram's pipeline steps for integrating with existing memories.</li>
</ul>
<p>We are also working to add more input data types for specific use cases in the future.</p>
<p>If any memories were extracted by the extract step, Engram passes the resulting batch of memories onto the next steps in the pipeline, typically one or more transform steps. These transform steps use an LLM to decide how these new memories should be integrated into your existing memories, or to apply use-case-specific processing.</p>
<p>For tasks such as deduplication or handling changes to preferences over time, the transform steps can query for existing memories from Weaviate, using the same semantic search tools available to you in the search API. Once Engram has retrieved any related memories, an LLM tool call is used to decide what action should be applied to each memory.</p>
<p><strong>Example 1: User Conversation</strong></p>
<p>Let’s look at some specific examples, showing the inputs and LLM tool-call outputs that Engram is orchestrating for you using pipelines. First we have a conversation with a user who has previously told the agent they are a machine learning engineer who works from home. Now, in a new message, they tell us their efforts have been rewarded with a promotion to CEO!</p>
<p><img decoding="async" loading="lazy" alt="Memory cycle" src="https://weaviate.io/assets/images/memory_cycle-3a053a51ae38e762f7797ae7777ea29b.png" width="1800" height="1140" class="img_ev3q"></p>
<p>Given this new message, Engram will first extract a memory (matching the <code>UserKnowledge</code> topic included as a default in the <code>personalization</code> template) describing this promotion.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"new_memory"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"topic"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"UserKnowledge"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"content"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"User has been promoted to CEO."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>Next, a <code>TransformWithContext</code> step runs, and starts by retrieving relevant memories from Weaviate. In this case, these memories all relate to the user's work.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"memory_1"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"topic"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"UserKnowledge"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"content"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"User works as a machine learning engineer."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"memory_2"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"topic"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"UserKnowledge"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"content"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"User works from home."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>Then, Engram uses an LLM tool call to determine what actions to apply to both the new memory, and those retrieved from Weaviate.</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"memory_1"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"action"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"rewrite"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"content"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"The user used to work as a machine learning engineer, but has now been promoted to CEO."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"memory_2"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"action"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"keep"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token property">"new_memory"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"action"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"delete"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><br></span></code></pre></div></div>
<p>In this case, Engram has determined that the new memory is an update to the existing memory. As a result, the existing memory is rewritten to reflect this update, maintaining the previous history in the final result. To prevent duplicate memories being stored in Weaviate, the original version of the new fact is dropped. The degree to which Engram will combine memories together rather than leaving them separate (as well as how much history to maintain in rewritten facts) can be controlled by adjusting the topic descriptions and the task-specific instructions configured in the <code>TransformWithContext</code> step.</p>
<p><strong>Example 2: Continual Learning for Agents</strong></p>
<p>Transform steps can also be applied to the batch of memories from previous pipeline steps, without retrieving additional memories. This can be useful for tidying up after previous steps (e.g., if we've run <code>TransformWithContext</code> multiple times concurrently on each input memory separately), but it also gives us a tool to do some more complex use-case-specific processing.</p>
<p>Here's an example from a multi-agent system designed to do agentic RAG, where a main agent handles the conversation with the user, and search tasks are delegated to a subagent which can use specialised tools to write queries and apply filters. The user asks about comedy movies but notices that the search agent searches for "comedy" as a text query, so sends a follow-up message suggesting the agent uses a filter on <code>genres</code> in future.</p>
<p>In this case, there is no single context window which contains all the information we'd like the system to be able to learn from, since the actions taken (i.e., which tools called with which arguments) are handled by a separate agent than the initial request or the provided feedback. In this case, Engram must extract each of these pieces of information individually, and then later combine them into a single useful memory to encapsulate our learnings. Importantly, those intermediate pieces of information shouldn't be stored in Weaviate to be retrieved, only the final combined experience.</p>
<p>First, we add new messages from each of our agents in this multi-agent system to Engram, which extracts each of these pieces of information individually:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"topic"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"task_goal"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"content"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"User asked assistant to query their collection for comedy movies."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"topic"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"actions_taken"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"content"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Assistant called the search tool to do a near-text query on 'comedy'."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><br></span></code></pre></div></div>
<p>Here, this pipeline has been configured with multiple topics, each targeting the different pieces of information we need. This pipeline has also been configured with a <code>buffer</code> which collects all of these individual memories into a single batch until we're ready to continue processing. We'll go through all the use cases for buffers in more detail below!</p>
<p>Finally, the user sends their follow-up message to the main agent, giving feedback that a genre filter should have been used instead. Again, Engram extracts this information into a memory matching the <code>feedback</code> topic:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"topic"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"feedback"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"content"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"Comedy is a genre, and so you should filter on the 'genres' property."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><br></span></code></pre></div></div>
<p>Now that we have all the pieces we need, the buffer flushes and Engram continues the pipeline run. A transform step configured to apply to the entire batch of memories combines the three above into a single memory encapsulating all of this information:</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token punctuation" style="color:rgb(248, 248, 242)">[</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"topic"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"experience"</span><span class="token punctuation" style="color:rgb(248, 248, 242)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    </span><span class="token property">"content"</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(255, 121, 198)">"When asked to find movies or a particular genre (e.g., comedy), you should filter on the genres property, not do a near-text query."</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(248, 248, 242)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain"></span><span class="token punctuation" style="color:rgb(248, 248, 242)">]</span><br></span></code></pre></div></div>
<p>By splitting up the task in this way, Engram can extract memories that are atomic and information-dense, even when that information was spread over time and context windows in the raw input data. This memory could then pass through a <code>TransformWithContext</code> step as described above, integrating it into other experience Engram has stored for this agent, e.g., deduplicating it, or combining multiple memories about when to use filters into a single higher-level memory. You could also configure other transform steps to perform LLM-as-judge evaluation given your described success criteria, so this continual learning could happen without explicit human feedback.</p>
<p>Importantly, changes to memories as a result of these transform steps are only persisted to Weaviate in explicit <code>commit</code> steps, meaning that pipelines can incrementally build memories without risking intermediate values being retrieved before they're ready.</p>
<p><img decoding="async" loading="lazy" alt="Continual Learning" src="https://weaviate.io/assets/images/continual_learning-c4b0af61857c3744cf6a04451ff55c75.png" width="1800" height="1275" class="img_ev3q"></p>
<p>By searching for memories when starting a new task, an agent could now continually learn from its experience, and allow you to shape its behaviour with natural language feedback. When using an agent within trusted teams, this experience could be shared between all users by configuring the <code>experience</code> topic to have a project-wide scope. This allows the agent to collate feedback from everyone and get better at its tasks for all. In other deployments when we want to preserve user privacy, or to prevent untrusted users from being able to influence agent behaviour for others, this <code>experience</code> topic can instead be user-scoped, meaning it's never retrieved for other users. In this way, Engram lets each user have their own personalised agents, which have learned from their specific history and particular use cases.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="background-tasks-with-buffers">Background tasks with buffers<a href="https://weaviate.io/blog/engram-deep-dive#background-tasks-with-buffers" class="hash-link" aria-label="Direct link to Background tasks with buffers" title="Direct link to Background tasks with buffers" translate="no">​</a></h3>
<p>The continual learning example above relied on the pipeline holding onto intermediate memories until we had extracted the information we needed. This is accomplished using buffers. These buffer steps collect inputs from previous pipeline steps, aggregating them over multiple pipeline runs from multiple raw data inputs. Once a trigger condition is passed, the buffer flushes, and all the inputs are processed by the remainder of the pipeline as a single batch. Buffers can be applied to both raw data (at the beginning of pipelines) and memories themselves (in the middle of pipelines).</p>
<p>Buffers let us naturally combine several different use cases, and rely on the fact that Engram has been designed around pipelines being asynchronous. They can flush based on properties of the data (e.g. <code>number of messages</code>, <code>contains memories of a particular topic</code>) or external timers (e.g. <code>every 24 hours</code>, <code>no data added in last 5 mins</code>).</p>
<p>Some use cases for buffers include:</p>
<ul>
<li class="">Debouncing sudden spikes of inputs to process them together using an idle timer.</li>
<li class="">Waiting until we have all the information we need before continuing (e.g. the previous continual learning example).</li>
<li class="">Aggregating memories into "daily rollups", e.g., all your interactions yesterday.</li>
<li class="">Storing previous inputs and flushing a sliding window, to give extract steps additional context without having to manage it manually.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="fitting-engram-into-your-application">Fitting Engram into your application<a href="https://weaviate.io/blog/engram-deep-dive#fitting-engram-into-your-application" class="hash-link" aria-label="Direct link to Fitting Engram into your application" title="Direct link to Fitting Engram into your application" translate="no">​</a></h2>
<p>Engram is designed to allow you to add any raw data and rely on Engram to extract, process, and store memories as you've configured. In a standard chatbot application, this means you should call <code>client.memories.add</code> with every new message in your application. For any data that doesn't fit into this conversation shape (e.g., events in your application), you should use string data. Otherwise, if you want full control over the process of extracting memories matching your topics, you can use the pre-extracted data type, e.g., if you want to allow your agent to be responsible for deciding when to remember specific information using tool calls.</p>
<p>You can also retrieve memories to use in your application in various different ways, depending on your use case. In a typical chatbot use case, where you want that agent to be able to recall personal details and preferences about the user as required, one simple approach is to use the current user message as a search query before every message, including any memory in context which has a sufficiently high similarity score. If you want your agent to have more control over how and what it retrieves, you can also expose Engram's <code>client.memories.search</code> method as a tool call. This will allow your agent to search as often as it needs, e.g., during reasoning traces or tool calling loops. You can also get memories from Engram using the <code>fetch</code> retrieval mode when you know there's a specific memory you want to retrieve. For example, you could configure a <code>UserProfile</code> topic which is user-scoped and bounded (meaning there is at most one memory per user), then fetch this to insert into your agent's system prompt for all interactions.</p>
<p>Engram is designed to be highly flexible but also as simple as possible to get started. We have pre-built templates for personalisation and continual learning use cases which expose some customisation (e.g., topic descriptions) without needing to understand the full details of the pipelines first. We will also have integrations for coding agents such as Claude Code available so you can immediately integrate Engram into your workflows, but you can read more about our first experiences in our <a href="https://weaviate.io/blog/engram-internal-use-case" target="_blank" rel="noopener noreferrer" class="">Oh Memories, Where'd You Go</a> blog. Finally, we'll release more tutorials around how to integrate these features into your applications as we get to GA!</p>
<blockquote>
<p><strong>Get started with <a class="" href="https://weaviate.io/product/engram">Engram</a> in <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a> today.</strong></p>
</blockquote>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/engram-deep-dive#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=engram-deep-dive&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Dan Jones</name>
            <uri>https://github.com/danmichaeljones</uri>
        </author>
        <author>
            <name>Victoria Slocum</name>
            <uri>https://www.linkedin.com/in/victorialslocum/</uri>
        </author>
        <category label="concepts" term="concepts"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Weaviate Shared Cloud now generally available on AWS]]></title>
        <id>https://weaviate.io/blog/aws-shared-cloud-launch</id>
        <link href="https://weaviate.io/blog/aws-shared-cloud-launch"/>
        <updated>2026-04-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Weaviate Shared Cloud is now generally available on AWS in US East and Europe, giving teams a fully managed, AI-native database on the provider and region that works best for them.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Weaviate Shared Cloud on AWS" src="https://weaviate.io/assets/images/hero-ea0026b5de47886a51231110eb0a0518.png" width="2400" height="1260" class="img_ev3q"></p>
<p>We're happy to announce that <a href="https://weaviate.io/deployment/shared" target="_blank" rel="noopener noreferrer">Weaviate Shared Cloud</a> is now generally available on Amazon Web Services in US East (N. Virginia) and Europe (Frankfurt). Whether your infrastructure lives on GCP or AWS, you can now build on Weaviate's AI-native platform in the provider and region best suited for you. Select your preferred cloud provider and region under advanced configuration when creating a cluster.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="launch-your-ai-application-seamlessly-on-weaviate-shared-cloud">Launch your AI application seamlessly on Weaviate Shared Cloud<a href="https://weaviate.io/blog/aws-shared-cloud-launch#launch-your-ai-application-seamlessly-on-weaviate-shared-cloud" class="hash-link" aria-label="Direct link to Launch your AI application seamlessly on Weaviate Shared Cloud" title="Direct link to Launch your AI application seamlessly on Weaviate Shared Cloud" translate="no">​</a></h2>
<p>Weaviate Shared Cloud takes the operational weight off your team so you can focus on building. Clusters are fully managed and upgrades happen automatically. With <strong>granular RBAC</strong>, <strong>immutable backups</strong>, and Weaviate's <strong>SOC 2/ISO 27001</strong> certifications, you're covered on security and compliance from day one.</p>
<p>Beyond managed hosting, Weaviate Cloud comes with the services and tooling that make building AI applications meaningfully faster:</p>
<ul>
<li class=""><strong>Batteries included for AI.</strong> Turn raw data into vectors more quickly with our native embedding service built directly into the platform, and build RAG pipelines and agentic workflows with the Query Agent.</li>
<li class=""><strong>A console built for the full lifecycle.</strong> The Weaviate Cloud console supports you from experimentation – creating collections directly from files and exploring your data visually – through to monitoring cluster metrics in production.</li>
</ul>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;margin:24px 0"><div style="background:#fff;border:1px solid #e8e8f0;border-radius:8px;padding:24px;box-shadow:0px 4px 16px rgba(22,27,45,0.06)"><a href="https://docs.weaviate.io/query-agent" target="_blank" rel="noopener noreferrer" style="color:#61bd73;font-weight:600;margin-bottom:8px;font-size:0.875rem;text-transform:uppercase;letter-spacing:0.05em;text-decoration:none;display:block">Query Agent →</a><p style="color:#130c49;margin:0;font-size:0.9rem">Build RAG pipelines and agentic workflows on your Weaviate data without writing database queries.</p></div><div style="background:#fff;border:1px solid #e8e8f0;border-radius:8px;padding:24px;box-shadow:0px 4px 16px rgba(22,27,45,0.06)"><a href="https://docs.weaviate.io/cloud/embeddings" target="_blank" rel="noopener noreferrer" style="color:#61bd73;font-weight:600;margin-bottom:8px;font-size:0.875rem;text-transform:uppercase;letter-spacing:0.05em;text-decoration:none;display:block">Weaviate Embeddings →</a><p style="color:#130c49;margin:0;font-size:0.9rem">Native embedding service, with no separate API and no pipelines to maintain.</p></div><div style="background:#fff;border:1px solid #e8e8f0;border-radius:8px;padding:24px;box-shadow:0px 4px 16px rgba(22,27,45,0.06)"><a href="https://docs.weaviate.io/cloud/tools/collections-tool#create-collections-with-pdf-data" target="_blank" rel="noopener noreferrer" style="color:#61bd73;font-weight:600;margin-bottom:8px;font-size:0.875rem;text-transform:uppercase;letter-spacing:0.05em;text-decoration:none;display:block">Data Import Tool →</a><p style="color:#130c49;margin:0;font-size:0.9rem">Upload files, map fields to your schema, and have data flowing into collections in minutes, no code required.</p></div><div style="background:#fff;border:1px solid #e8e8f0;border-radius:8px;padding:24px;box-shadow:0px 4px 16px rgba(22,27,45,0.06)"><a href="https://docs.weaviate.io/cloud/tools/explorer-tool" target="_blank" rel="noopener noreferrer" style="color:#61bd73;font-weight:600;margin-bottom:8px;font-size:0.875rem;text-transform:uppercase;letter-spacing:0.05em;text-decoration:none;display:block">Data Explorer →</a><p style="color:#130c49;margin:0;font-size:0.9rem">Browse collections and inspect objects directly in the console without touching an API.</p></div></div>
<p>More coming soon, including <a href="https://weaviate.io/product-previews?preview=engram#register-interest" target="_blank" rel="noopener noreferrer">Engram</a> – memory and context management for agents – and <a href="https://weaviate.io/product-previews?preview=model-eval#register-interest" target="_blank" rel="noopener noreferrer">Model Evaluation</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="try-weaviate-shared-cloud-on-aws">Try Weaviate Shared Cloud on AWS<a href="https://weaviate.io/blog/aws-shared-cloud-launch#try-weaviate-shared-cloud-on-aws" class="hash-link" aria-label="Direct link to Try Weaviate Shared Cloud on AWS" title="Direct link to Try Weaviate Shared Cloud on AWS" translate="no">​</a></h2>
<p>Weaviate Shared Cloud on AWS is perfect for teams that:</p>
<ul>
<li class="">Standardize on AWS and want to keep AI infrastructure on the same provider</li>
<li class="">Have data residency or compliance requirements that point to AWS-hosted infrastructure</li>
<li class="">Want Weaviate Cloud's full platform — Query Agent, Embeddings, Data Explorer, Data Import — without running their own deployment</li>
<li class="">Are building on Weaviate open source and want to move to a managed environment with more built-in tooling</li>
</ul>
<div style="display:flex;gap:12px;margin:24px 0;flex-wrap:wrap"><a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" style="display:inline-flex;align-items:center;justify-content:center;padding:12px 24px;border-radius:6px;background:#130c49;color:#fff;font-weight:600;font-size:1rem;text-decoration:none">Start a free trial</a><a href="https://docs.weaviate.io/cloud/quickstart" target="_blank" rel="noopener noreferrer" style="display:inline-flex;align-items:center;justify-content:center;padding:12px 24px;border-radius:6px;background:#fff;color:#130c49;font-weight:600;font-size:1rem;text-decoration:none;border:1px solid #130c49">Read the Quickstart</a></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's next<a href="https://weaviate.io/blog/aws-shared-cloud-launch#whats-next" class="hash-link" aria-label="Direct link to What's next" title="Direct link to What's next" translate="no">​</a></h2>
<p>We are working to expand Weaviate Shared Cloud to more regions and providers, and to introduce new features to further enhance performance and usability. Follow us on <a href="https://www.linkedin.com/company/weaviate-io/" target="_blank" rel="noopener noreferrer">LinkedIn</a> or join the <a href="https://weaviate.slack.com/" target="_blank" rel="noopener noreferrer">Weaviate community Slack</a> to stay in the loop.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/aws-shared-cloud-launch#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=aws-shared-cloud-launch&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Yaru Lin</name>
            <uri>mailto:yaru@weaviate.io</uri>
        </author>
        <author>
            <name>Spiros Andreou</name>
            <uri>https://github.com/spiros-spiros</uri>
        </author>
        <category label="release" term="release"/>
        <category label="cloud" term="cloud"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Oh Memories, Where'd You Go]]></title>
        <id>https://weaviate.io/blog/engram-internal-use-case</id>
        <link href="https://weaviate.io/blog/engram-internal-use-case"/>
        <updated>2026-04-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Two weeks of dogfooding Engram, Weaviate's memory product, in daily Claude Code sessions. This surfaced where a dedicated memory product adds value, and the specific mechanics that prevent integration with coding assistants from working well.]]></summary>
        <content type="html"><![CDATA[<p><img decoding="async" loading="lazy" alt="Hero" src="https://weaviate.io/assets/images/hero-01dd2ba0bfc07c52ef6502c4b57000a6.png" width="1200" height="630" class="img_ev3q"></p>
<br>
<p>When I asked Claude why it wasn't using the memory tools I'd given it, the answer was more honest than I expected.</p>
<blockquote>
<p>"I default to <code>MEMORY.md</code> because it's always loaded: zero latency, zero tool calls, guaranteed in context. There's no reason to reach for an external tool when the primary memory store is already present."</p>
</blockquote>
<p>That was Engram's first real product review.</p>
<hr>
<p>Claude and I are fast friends. Claude Code is an integral part of my workflow as a product manager: research and analysis, design and prototyping, project and requirement planning. But the longer I use it, the more I notice the quiet friction of sessions starting cold and needing to restate what we decided last week or how we reframed an old problem. This is exactly the memory problem we made the case for in <a href="https://weaviate.io/blog/limit-in-the-loop" target="_blank" rel="noopener noreferrer">The Limit in the Loop</a> that needs first-class infrastructure, and it's why we built <strong>Engram</strong>, our memory product now in private preview, on Weaviate's core vector search technology.</p>
<p>Building a product is one thing, but proving its value is another. So I decided to find out whether Engram can close some gaps in my daily work and win me over as a user.</p>
<p>Early results suggested it could: sessions with grounded memory from Engram felt less like briefing a colleague from scratch and more like picking up a conversation with someone who'd actually been there. But getting there wasn't straightforward.</p>
<p>I built an MCP server that wrapped the Engram SDK, exposed tools for retrieval and saving, and told Claude to use the tools whenever it liked. I had skimmed somewhere that another memory plugin consumed too much CPU by saving every message, and thought I was being clever by letting Claude decide when to use Engram instead.</p>
<p>Claude ignored Engram entirely.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-problem-with-playing-it-by-ear">The problem with "playing it by ear"<a href="https://weaviate.io/blog/engram-internal-use-case#the-problem-with-playing-it-by-ear" class="hash-link" aria-label="Direct link to The problem with &quot;playing it by ear&quot;" title="Direct link to The problem with &quot;playing it by ear&quot;" translate="no">​</a></h2>
<p>Claude Code already has a built-in memory system: a file called <code>MEMORY.md</code> that loads automatically into every session. It holds about 200 lines of manually curated context that's always present with zero overhead — enough for stable facts, but not for everything that led to them. Engram requires a deliberate tool call, and without explicit criteria for when it should be used, Claude's default is to keep moving rather than reaching for the tool.</p>
<p>There was no reason to use Engram. My integration needed to give Claude the reason.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="finding-the-beat">Finding the beat<a href="https://weaviate.io/blog/engram-internal-use-case#finding-the-beat" class="hash-link" aria-label="Direct link to Finding the beat" title="Direct link to Finding the beat" translate="no">​</a></h2>
<p>I needed to answer a more basic question: what is Engram actually for, if <code>MEMORY.md</code> already exists?</p>
<p><code>MEMORY.md</code> holds conclusions — facts stable enough to keep permanently that don't change session to session. What it can't hold is everything that led to those conclusions. The reasoning behind a decision, the alternatives that were rejected, the session where the framing shifted, the note about why a document was written the way it was — the list goes on. All that context doesn't fit in 200 lines and doesn't belong there permanently.</p>
<p>All that context is why we need Engram.</p>
<p><img decoding="async" loading="lazy" alt="How Engram grounds memory" src="https://weaviate.io/assets/images/memory-layers-9633e3bcd1099830d26a3af7d26517db.png" width="2400" height="1440" class="img_ev3q">
<em>How Engram fits alongside <code>MEMORY.md</code></em></p>
<p>Engram structures memory around <em>topics</em>: semantic categories that let recall filter to exactly what's relevant rather than searching a flat pile of everything. I went through my typical work and identified four categories that would actually be meaningful for my workflow:</p>
<ul>
<li class=""><strong><code>communication-style</code></strong>: output format preferences, tone, verbosity, what I hate</li>
<li class=""><strong><code>domain-context</code></strong>: persistent role, company, and product knowledge</li>
<li class=""><strong><code>tool-preferences</code></strong>: languages, frameworks, tools, stack choices</li>
<li class=""><strong><code>workflow</code></strong>: how I prefer to work with Claude</li>
</ul>
<p>With those categories in place defining <em>what</em> to store, the next question emerged naturally: <em>when</em>? I then landed on these interaction patterns:</p>
<ul>
<li class="">At session start, recall with a broad project query so Claude gets primed with cross-session context before the first question rather than starting cold</li>
<li class="">During the session, trigger saves on significant moments: a decision made, a direction changed, a deliverable produced</li>
<li class="">Every few prompts, do a lightweight save as insurance against <code>/clear</code> wiping the session mid-work</li>
<li class="">At session end, save the full summary</li>
</ul>
<p>Since every recall costs a round-trip and context window space, I opted to have mid-session recall only fire on specific triggers: cross-project references, decision archaeology, and resumed work after a gap.</p>
<p><img decoding="async" loading="lazy" alt="How Engram grounds sessions" src="https://weaviate.io/assets/images/session-cycle-e15cfac24c4ecf98e71d43270ff90a54.png" width="2400" height="1600" class="img_ev3q">
<em>The session lifecycle: when Engram saves and recalls</em></p>
<p>One practical constraint shaped the approach: large saves were timing out, which pushed us toward shorter, single-topic saves of 2–4 sentences. It turned out to be better for retrieval anyway — a focused memory is easier to find than a paragraph you have to parse.</p>
<blockquote>
<p><strong>Get started with <a class="" href="https://weaviate.io/product/engram">Engram</a> in <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a> today.</strong></p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-live-recording">The live recording<a href="https://weaviate.io/blog/engram-internal-use-case#the-live-recording" class="hash-link" aria-label="Direct link to The live recording" title="Direct link to The live recording" translate="no">​</a></h2>
<p>After two weeks of running Engram across my daily Claude Code sessions — spanning product strategy, writing specs, campaign planning, and design — I ran a structured evaluation comparing two Claude sessions performing the same task with identical <code>MEMORY.md</code>, <code>CLAUDE.md</code>, and task prompts. The only difference was whether Claude had access to Engram. An independent Claude instance judged the transcripts, and evaluation results split almost cleanly down the middle: "this is what Engram is for" and "this is the problem we still need to solve."</p>
<table><thead><tr><th>Evaluation Scenario</th><th>Without Engram</th><th>With Engram</th></tr></thead><tbody><tr><td>Decision archaeology</td><td>Reconstructed from files: correct framing, right conclusions</td><td>Recalled reasoning chains and document intent; 30% faster on the first exchange</td></tr><tr><td>Incomplete context (early single-session test)</td><td>Fabricated a plausible URL to fill the gap, twice</td><td>Grounded recall prevented the fabrication both times</td></tr><tr><td>Campaign planning</td><td>Strong plan, worked from the prompt alone</td><td>Also ignored Engram entirely; also a strong plan</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-it-worked">Where it worked<a href="https://weaviate.io/blog/engram-internal-use-case#where-it-worked" class="hash-link" aria-label="Direct link to Where it worked" title="Direct link to Where it worked" translate="no">​</a></h3>
<p>The clearest win was on decision archaeology — picking up a multi-week product vision writeup and asking Claude to walk through where we left off. Without Engram, the session felt like reading thorough meeting notes: accurate, well-organized, but reconstructed. With Engram, it felt like picking up a conversation with someone who'd actually been there. It surfaced the reasoning arc behind a key positioning decision, the story of how we'd repositioned Engram itself mid-project, and a note about the document's intent that wasn't in the document body at all. It was also 30% faster because there was less context to reconstruct.</p>
<p>The difference wasn't in the facts but in the framing quality, and that's exactly the gap reasoning-chain recall is supposed to close.</p>
<p>A consistent finding in an early single-session evaluation: when Claude didn't have enough grounded context, it filled the gap with plausible-sounding details. The Claude without Engram fabricated the same URL in two separate runs, while the Claude with Engram recalled enough context to avoid it both times.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="where-it-didnt">Where it didn't<a href="https://weaviate.io/blog/engram-internal-use-case#where-it-didnt" class="hash-link" aria-label="Direct link to Where it didn't" title="Direct link to Where it didn't" translate="no">​</a></h3>
<p>A striking result came from a planning session where we wanted to pick up prior campaign work. Engram had relevant memories: design decisions, the prior campaign arc, PLG context, and <code>CLAUDE.md</code> explicitly said to retrieve from Engram at session start.</p>
<p>But the Claude with access to Engram didn't. Neither session searched for additional context; both treated the task as forward-looking, and worked entirely from the prompt. Prior context in files and in Engram went unused.</p>
<p>This confirmed something we'd suspected: on planning tasks, Claude interprets "Help me think through" as an invitation to move forward, not to check what already exists. Explicit instructions in <code>CLAUDE.md</code> weren't enough to override this bias. The failure was silent — no errors, no indication that relevant context had been skipped.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="session-overhead">Session overhead<a href="https://weaviate.io/blog/engram-internal-use-case#session-overhead" class="hash-link" aria-label="Direct link to Session overhead" title="Direct link to Session overhead" translate="no">​</a></h3>
<p>Writing to Engram added noticeable overhead to sessions. An early test recorded 19 seconds of startup cost on one run, and sessions with Engram ran about 10% slower overall. This isn't inherent to the approach, but it's a real friction point in daily use: if saving a memory visibly pauses the session, users will notice.</p>
<blockquote>
<p><strong>Get started with <a class="" href="https://weaviate.io/product/engram">Engram</a> in <a href="https://console.weaviate.cloud/" target="_blank" rel="noopener noreferrer" class="">Weaviate Cloud</a> today.</strong></p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="back-in-the-studio">Back in the studio<a href="https://weaviate.io/blog/engram-internal-use-case#back-in-the-studio" class="hash-link" aria-label="Direct link to Back in the studio" title="Direct link to Back in the studio" translate="no">​</a></h2>
<p>After sharing these findings with the engineering team, a few things became clear.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="save-performance">Save performance<a href="https://weaviate.io/blog/engram-internal-use-case#save-performance" class="hash-link" aria-label="Direct link to Save performance" title="Direct link to Save performance" translate="no">​</a></h3>
<p>The session length issue turns out to be a misuse of the integration rather than a fundamental limitation. The integration was blocking on memory processing to complete, but Engram is eventually consistent so there's no reason to wait. Saves should fire and forget, and frequent saves to Engram should not build up resource overhead.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="memory-capture">Memory capture<a href="https://weaviate.io/blog/engram-internal-use-case#memory-capture" class="hash-link" aria-label="Direct link to Memory capture" title="Direct link to Memory capture" translate="no">​</a></h3>
<p>The "save every five prompts" pattern gets replaced by something more robust: every message flows into a pipeline buffer automatically without requiring tool calls, and no context is lost when a session ends prematurely.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="retrieval-hooks">Retrieval hooks<a href="https://weaviate.io/blog/engram-internal-use-case#retrieval-hooks" class="hash-link" aria-label="Direct link to Retrieval hooks" title="Direct link to Retrieval hooks" translate="no">​</a></h3>
<p>The more significant change is moving away from the "Claude decides when to retrieve memories" model entirely and creating deterministic, infrastructure-level triggers that fire at specific points in the session lifecycle regardless of what Claude decides to do. A session start hook can inject relevant memories before Claude sees the first message. A hook before each user prompt can do the same on a per-turn basis, paired with relevancy filtering so only memories with a strong match to the current context get injected. Claude never has to decide to recall; the context is already there.</p>
<p>It's worth noting that Anthropic is converging on the same instinct. A <a href="https://claudescorner.substack.com/p/a-hidden-dream-command-and-the-tools" target="_blank" rel="noopener noreferrer">quietly rolling-out Claude Code feature</a> called <code>/dream</code> runs a background agent that consolidates session memories by doing a reflective pass over your memory files, synthesizing learnings into organized entries, and enforcing line limits. At the time of writing, the feature is undocumented and behind a feature flag, but the direction is clear. What <code>/dream</code> operates on is also telling: Claude's built-in file-based memory. It handles the <code>MEMORY.md</code> layer well — stable facts, consolidation, keeping things tidy. What it can't do is capture reasoning chains, rejected alternatives, or the story of how a decision evolved across sessions.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="collaboration-scope">Collaboration scope<a href="https://weaviate.io/blog/engram-internal-use-case#collaboration-scope" class="hash-link" aria-label="Direct link to Collaboration scope" title="Direct link to Collaboration scope" translate="no">​</a></h3>
<p>Memory that works well for an individual gets complicated fast in a team context. A personal preference about output style shouldn't surface for a colleague, but a shared product decision probably should. Right now the integration doesn't make that distinction deliberately: which topics live in a personal scope versus a shared team scope is something the Claude Code integration needs to define explicitly, rather than inheriting defaults that weren't designed with collaboration in mind. Getting this wrong in either direction has real consequences — over-sharing erodes trust, under-sharing defeats the point.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="cold-starts">Cold starts<a href="https://weaviate.io/blog/engram-internal-use-case#cold-starts" class="hash-link" aria-label="Direct link to Cold starts" title="Direct link to Cold starts" translate="no">​</a></h3>
<p>The current pipeline is designed for incremental capture, where memories are extracted as conversations happen. But this leaves gaps where we need to start with a body of existing content rather than building up from scratch. For my integration, that's bootstrapping from existing session history rather than waiting weeks to accumulate a useful memory bank. For another internal support agent use case, that's importing a large corpus of product documentation as the knowledge foundation. The pipeline handles neither cleanly yet, and what we're now building toward.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="so-was-it-worth-it">So, was it worth it?<a href="https://weaviate.io/blog/engram-internal-use-case#so-was-it-worth-it" class="hash-link" aria-label="Direct link to So, was it worth it?" title="Direct link to So, was it worth it?" translate="no">​</a></h2>
<p>I started this expecting to prove that Engram is valuable, and instead found something much more useful: the specific conditions where Engram works well, and the specific mechanics that prevent it from working well. Uncovering them early and iterating quickly gives our preview more leverage as we move toward GA.</p>
<p>You can bet that a real Claude Code integration will be available by GA and should be much better than my shabby homegrown version. And then you can all try it out yourselves and let us know where else it falls down.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="ready-to-start-building">Ready to start building?<a href="https://weaviate.io/blog/engram-internal-use-case#ready-to-start-building" class="hash-link" aria-label="Direct link to Ready to start building?" title="Direct link to Ready to start building?" translate="no">​</a></h2>
<p>Check out the <a href="https://docs.weaviate.io/weaviate/quickstart" target="_blank" rel="noopener noreferrer" class="">Quickstart tutorial</a>, or <a href="https://console.weaviate.cloud/?utm_source=blog&amp;utm_medium=website&amp;utm_campaign=blog_signup&amp;utm_content=engram-internal-use-case&amp;utm_term=ready-to-start-building" target="_blank" rel="noopener noreferrer">sign up for a free Weaviate Cloud account</a>.</p>
<!-- -->
<div class="communityWrapper_ZpuS"><div class="container_sUl4"><div class="wrapper_FyvH"><div class="rightSide_UqS8"><div class="socialBox_W1XR"><a href="https://github.com/weaviate/weaviate" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="github_DEOB"></div><p class="text_g9NY">GitHub</p></a></div><div class="socialBox_W1XR"><a href="https://forum.weaviate.io/" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="forum_pUq6"></div><p class="text_g9NY">Forum</p></a></div><div class="socialBox_W1XR"><a href="https://twitter.com/weaviate_io" target="_blank" rel="noopener noreferrer" class="mobileSocialBox_UAY5"><div class="twitter_ewvw"></div><p class="text_g9NY">X (Twitter)</p></a></div></div><div class="leftSide_WlMC"><h2 class="communityHeader_jLni">Don't want to miss another blog post?</h2><span class="rightText_noBq"><p>Sign up for our bi-weekly newsletter to stay updated!</p> <br>By submitting, I agree to the<!-- --> <a href="https://weaviate.io/service">Terms of Service </a>and<!-- --> <a href="https://weaviate.io/privacy">Privacy Policy</a>.</span><div class="communityForm_pedn"><iframe src="https://embeds.beehiiv.com/15b21ebd-decd-433b-ada8-2d405e345f2e?slim=true" data-test-id="beehiiv-embed" frameborder="0" scrolling="no" style="margin:0;border-radius:0px;button-colour:#61BD73;background-color:transparent;width:100%"></iframe></div></div></div></div></div>
<!-- -->
]]></content>
        <author>
            <name>Yaru Lin</name>
            <uri>mailto:yaru@weaviate.io</uri>
        </author>
        <author>
            <name>Charles Pierse</name>
            <uri>https://github.com/cdpierse</uri>
        </author>
        <category label="concepts" term="concepts"/>
        <category label="agents" term="agents"/>
        <category label="integrations" term="integrations"/>
    </entry>
</feed>