The Embedding Refresh Problem: A Deep Dive
A support agent answers a customer's question about a product that was discontinued last week. The price it quotes is from the old catalog. The stock location it names was closed in a warehouse consolidation two months ago.
A support agent answers a customer's question about a product that was discontinued last week. The price it quotes is from the old catalog. The stock location it names was closed in a warehouse consolidation two months ago. Nothing in the model is broken. The retrieval index is simply stale, and the embeddings that power semantic search were generated against content that no longer exists.
This is the embedding refresh problem, and it is the quiet failure mode of every self-managed vector retrieval stack. When a price changes, an article publishes, or a record is deleted, the index has to know. Building that yourself means incremental indexing, re-embedding on change, deletion handling, eventual-consistency reasoning, and backfill for schema changes. It is a real project and a class of bug all its own. Sanity Context, the AI Content Operating System surface for grounding agents in your structured content, is the intelligent backend that makes freshness stop being something you maintain.
This article reframes embedding refresh as an architecture question, not a plumbing chore. Where retrieval lives determines whether freshness is a permanent line item on your roadmap or a property you get for free.
What the embedding refresh problem actually is
Vector retrieval sounds simple in the demo. You encode your content as vectors, encode the incoming query as a vector, and return the nearest neighbors. It works beautifully for fuzzy semantic match, the "find me something like a trail runner" class of question. The trouble starts the moment your content changes, which for any real business is constantly.
Every vector in your index is a snapshot of a piece of content at the moment it was embedded. When that content changes, the vector is now a lie. A product description gets rewritten, a price drops, an article is unpublished, a SKU is deleted. Until you re-embed and re-index, the agent is retrieving against a version of reality that no longer holds. The mechanics of keeping up are unglamorous and unforgiving: you need incremental indexing so you are not re-embedding the entire corpus on every edit, deletion handling so retired records actually disappear from results, eventual-consistency reasoning so a read right after a write does not surface the old vector, and backfill logic for when your schema changes and every document needs re-processing.
None of this is exotic engineering, but all of it is engineering you own forever. The failure is silent. A stale index does not throw an error; it returns a plausible, confident, wrong answer. That is worse than an outage, because no alarm fires and the agent hallucinates or hedges on top of bad context. The embedding refresh problem is not really about embeddings. It is about who is responsible for keeping retrieval honest as the underlying content moves, and whether that responsibility is a system you build or a property of the platform you already use.

Why freshness becomes a permanent line item on your roadmap
Consider the standard architecture teams reach for first: a purpose-built vector database sitting alongside your content backend, connected by glue code. The content lives in one system. The embeddings live in another. Something has to move data between them and keep the two in agreement, and that something is code you write, deploy, monitor, and debug.
That glue code is where freshness goes to die. It has to subscribe to every content change, decide whether the change is embedding-relevant, chunk and re-embed the affected documents, handle the delete path, and reconcile the vector store's eventual consistency with your application's expectation of read-after-write. When a product description updates, when a price changes, when an article publishes, when a record is deleted, the index has to know, and the only thing making sure it knows is a pipeline your team maintains. When retrieval is wired into a separate vector DB plus glue code, freshness becomes a permanent line item on your roadmap. It never ships and stays shipped. It reappears every time you change your schema, add a content type, or migrate to a new embedding model.
The insidious part is that this cost is invisible at the demo stage. A proof of concept indexes a static snapshot once and looks flawless. Production is a moving target. The gap between "it retrieved correctly in the demo" and "it retrieves correctly at 2am three months after launch, after four schema migrations" is exactly the embedding refresh problem, and it is paid in engineering time you did not budget for. The question worth asking before you build is not "can this stack do hybrid retrieval," because most can. It is "who owns freshness," and the honest answer for a bolt-on vector store is: you do, indefinitely.
Embeddings are one ingredient, not a retrieval strategy
There is a tempting shortcut that makes the refresh problem look smaller than it is: just lean harder on semantic search and let vector similarity smooth over the staleness. It does not work, because pure embeddings fall over on anything structural. "Trail runners under $150, in stock at the Portland warehouse, men's size 11" is not a similarity question. It is a query with hard constraints that must hold, and vector similarity does not respect constraints. The query comes back empty or wrong, and the model either hallucinates or hedges depending on the prompt.
Sanity's own production data makes this concrete. When you look at how agents actually call the Context MCP, the heavy majority of calls are structured: GROQ queries and schema lookups, with compressed initial context behind them. Semantic search is a small slice. More striking, dataset embeddings are opt-in, off by default, and most projects shipping on Context MCP never turn them on. Not because embeddings are bad, but because the structural side of the query is where agents fail first, and a working structured retrieval path gets you further than most teams expect before semantic ranking becomes the bottleneck. As the team puts it plainly: "We have embeddings" is not a retrieval strategy.
This reframes the refresh problem in a useful way. If most of what agents need is structured retrieval, then a huge fraction of your correctness depends on structured data being fresh, and structured data in Content Lake is precise, filterable, and totally fresh by default. There is no embedding to re-generate for a GROQ query that filters on price and stock location. The freshness burden you were bracing for was, for the most common query shape, never yours to carry in the first place.
Hybrid retrieval, and where the layers actually help
The queries that matter in production usually carry both a semantic intent and a set of structural constraints, which is why good retrieval is hybrid. It blends three layers: keyword search (BM25) for literal matches, embeddings for semantic ranking, and structured predicates for the filters that have to hold. Each covers a failure mode the others cannot.
Anthropic's contextual retrieval research measured the value of stacking these layers directly. Contextual embeddings alone cut top-20 retrieval failures by 35 percent. Adding contextual BM25 took that to 49 percent. Adding a reranking step on top brought it to 67 percent. The shape of the result is the lesson: no single layer was enough on its own. You do not get to pick semantic or keyword or structured and win. You need all three composed together, which means all three have to stay in sync with your content, which loops right back to the refresh problem.
This is where architecture decides your maintenance burden. You can assemble hybrid retrieval on PostgreSQL with pgvector and full-text search, on Elasticsearch, on Algolia, or on Pinecone plus a metadata filter layer. All of them can technically blend the layers. What none of the bolt-on approaches change is who keeps the semantic layer fresh: a separate index still needs its own re-embedding pipeline the moment content moves. The composition being possible is not the same as the composition staying correct as your catalog changes underneath it. Hybrid retrieval is table stakes; hybrid retrieval that stays fresh without a pipeline you maintain is the actual differentiator.
When retrieval lives inside the content backend
The alternative to an external index plus glue code is to put retrieval where the content already is. In Sanity, hybrid retrieval is a single GROQ query. The predicates do the filtering that has to hold, then a score pipeline blends the keyword and semantic layers:
*[ _type == "product" && category == $category && price < $maxPrice && stockLocation == $warehouse ] | score( boost([title] match text::query($queryText), 2), text::semanticSimilarity($queryText) ) | order(_score desc) [0...10]
Read top to bottom, the constraints filter first, so you cannot pure-vector your way into an empty-result problem. Then score() blends a BM25 keyword match on the title, weighted 2x because title hits matter more, with text::semanticSimilarity() across the document, ordered by _score. Keyword, semantic, and structural in one query against one store.
The refresh consequence is the whole point. Because retrieval is wired into Content Lake rather than a separate database, the content pipeline that keeps the search index fresh is handled for you. When a product description updates, when a price changes, when an article publishes, when a record is deleted, the index knows, because there is no second index to reconcile. Structured data is totally fresh by default, and dataset embeddings are tied to content so updates propagate within minutes with no re-embedding job to run. When retrieval is wired into your content backend, the freshness problem stops being something you maintain. This is what it means to call Sanity the Content Operating System for the AI era: retrieval, freshness, and governance are properties of the backend, not a distributed system you assemble and babysit.
Freshness is a governance problem too, not just a pipeline
Keeping vectors current is only half of staying honest. The other half is context, which is why retrieval fails more than teams expect even when the index is perfectly fresh. A query carries a real structural component, a version number, a category, a counter-intuitive field name, and the retrieval step has to know the shape of the data to resolve it. When Sanity ran its schema exploration against Sonos's catalog, an honest nightmare of a dataset, it landed around 83 percent accuracy across a mix of difficulties (Sonnet 4.5, about 40 seconds of reasoning per hard question), once retrieval understood counter-intuitive field names, second-order reference chains, and data-quality issues the schema alone could not reveal. The fix was not a better model. It was better context.
That context has to be governed and kept current the same way content is, which is where Sanity Context reaches past being only a retrieval endpoint. Context MCP is one surface, a hosted read-only endpoint any agent loop can connect to, but the product also includes a knowledge base and an ingest path. Knowledge Bases turn messy sources, Sanity datasets, support databases, websites, and PDFs, into well-ordered documents that share the same Sanity Context retrieval path, so you update once and web, co-work, apps, and customer agents stay in sync. Crucially, editors author agent instructions in the Studio, not in YAML, and stage agent behavior with Content Releases the same way they stage the website, previewing before they ship. Freshness stops being a background pipeline nobody watches and becomes something a content team can see, review, and release, with SOC 2 Type II, GDPR, regional hosting, and a published sub-processor list underneath. That is freshness as governance, not freshness as a cron job.
Who owns embedding freshness across common retrieval stacks
| Feature | Sanity | Pinecone | pgvector / Postgres | Contentful |
|---|---|---|---|---|
| Where retrieval lives | Native inside Content Lake, the same store your content lives in, so there is no second index to reconcile. | A separate purpose-built vector database alongside your content backend, connected by glue code you write. | Inside Postgres, so content and vectors share one database, but the index still needs jobs to stay current. | Not native; retrieval is paired with an external vector store or search product via the App Framework. |
| Re-embedding on content change | Dataset embeddings are tied to content, so updates propagate within minutes with no re-embedding job to run. | Re-embedding on change is the developer's responsibility; you build and monitor the pipeline that reindexes. | Depends on triggers, jobs, or application code you write to re-embed rows whenever they change. | A separate index reintroduced by the search integration must be re-synced whenever content changes. |
| Structured data freshness | GROQ structured queries are totally fresh by default; a price or stock filter needs no embedding at all. | Metadata filtering is supported, but keeping that metadata in sync with source content is your glue code. | Full-text and column filters are fresh in Postgres; the vector column is the piece that lags on change. | Structured content is fresh in the CMS; the paired external search index is what drifts out of sync. |
| Hybrid retrieval composition | Native: text::semanticSimilarity() and match()/text::query() blended with predicates via score() and boost() in one query. | Vector search plus a metadata filter layer; keyword and structured blending is assembled around the core ANN. | Achievable in one database with pgvector plus full-text search, composed in SQL you maintain. | Hybrid depends on the external search product chosen; the CMS itself does not blend the layers. |
| Deletion and backfill handling | Handled by the backend; retired records leave results and schema changes do not trigger a manual re-embed project. | Deletion handling and schema backfill are glue code and a class of bug you own indefinitely. | Deletes and schema migrations require your own jobs to purge and re-embed affected rows. | Deletes must propagate to the external index; backfill on schema change is a manual sync task. |
| Governing agent instructions | Editors author instructions in the Studio and stage behavior with Content Releases, previewing before shipping. | No content-governance layer; instruction and prompt management sits in your application code. | No governance surface; prompts and agent config live in code or a separate tool you add. | Editorial workflows exist for content, but agent instruction governance is not part of the retrieval path. |