Agent Governance & Evaluation8 min readยท

Why Your Agent Needs Both Keywords and Meaning

A user asks your support agent for "trail runners under $150, in stock at the Portland warehouse, men's size 11." A pure-vector retrieval layer reads the vibe of "trail runners" perfectly and ignores every constraint that actually matters.

A user asks your support agent for "trail runners under $150, in stock at the Portland warehouse, men's size 11." A pure-vector retrieval layer reads the vibe of "trail runners" perfectly and ignores every constraint that actually matters. It returns size 9s, out-of-stock styles, and a $240 boot, because vector similarity does not respect price, stock location, or size. The query comes back wrong, and the model either hallucinates a confident answer or hedges into uselessness. That is where most agents fail, and the fix is almost never a better model.

Sanity Context (previously Agent Context) starts from a blunter premise: retrieval, not reasoning, is where agents break, and "we have embeddings" is not a retrieval strategy. Sanity Context is the intelligent backend that gives agents structured, governed access to your content, the Content Operating System for the AI era applied to the moment an agent reaches into your data and has to come back with the right rows.

This article reframes the keywords-versus-meaning debate as a false choice. Keyword search nails literal matches and exact identifiers. Embeddings handle fuzzy intent. Structured predicates enforce the filters that have to hold. Your agent needs all three, blended, in one pass, and the evidence that it does is now quantified.

The four ways to find something, and why three of them fail alone

There are four ways an agent can find things in your data, and a field guide taxonomy makes the tradeoffs unmissable. Pure structured query (GROQ, SQL, GraphQL) is the first. You write the predicate, you get exactly what you asked for, and it falls over the moment a user says "something like X" or "the cozy one" or anything else that lives in vibes, not fields. It also assumes you know exactly what you are looking for, which is rarely true when someone is exploring and chatting with an agent.

Pure keyword search (BM25) is the second. It surfaces documents based on the presence of exact terms, which makes it highly effective for literal matches and specific identifiers like a SKU or a version number. But because it treats tokens as discrete units with no semantic understanding, it cannot interpret the intent behind "something like X" or synonyms that do not share lexical roots. "Sofa" and "couch" are strangers to BM25.

Pure embeddings are the third, and the one most "AI-powered search" products ship as their whole offering. Encode your content as vectors, encode the query as a vector, return the nearest neighbors. It works for fuzzy semantic match like "find me something like a trail runner." It falls over for anything structural: under $150, in stock at the Portland warehouse, men's size 11. The fourth way, hybrid, is the only one that survives a real question, because real questions carry vibe and constraint in the same sentence.

Illustration for Why Your Agent Needs Both Keywords and Meaning
Illustration for Why Your Agent Needs Both Keywords and Meaning

Anthropic measured it: no single layer is enough

The argument that an agent needs both keywords and meaning is not a matter of taste. It has been measured directly. Anthropic's contextual retrieval research layered the techniques one at a time and watched the failure rate fall at each step. Contextual embeddings alone cut top-20 retrieval failures by 35 percent. Adding contextual BM25 on top took that improvement to 49 percent. Adding a reranking step on top of both brought it to 67 percent.

Read the numbers closely or just notice the shape of them. None of the three layers alone was enough. Embeddings got you a third of the way. Keywords plus embeddings got you to roughly half. Only the full stack, semantic ranking and keyword matching and a reranker, closed most of the gap. This is the strongest quantified evidence available that the keywords-versus-meaning framing is the wrong question. The right question is how cleanly you can combine them.

The practical consequence is that any agent retrieval design that picks a side is choosing to leave a large fraction of queries broken. A pure-embeddings stack ships with a 65 percent residual failure rate on the hard cases that the full stack resolves. For a support agent or a commerce agent answering thousands of questions a day, that residual is not a rounding error. It is the difference between an agent users trust and one they learn to route around.

What hybrid retrieval looks like when it lives in one query

Hybrid retrieval is not three systems wired together. Inside the Content Lake it is a single GROQ query, and the structure of that query is worth reading line by line. The predicates do the filtering that has to hold. The score pipeline does the ranking that respects the vibe.

A product lookup looks like this: `*[ _type == "product" && category == $category && price < $maxPrice && stockLocation == $warehouse ] | score( boost([title] match text::query($queryText), 2), text::semanticSimilarity($queryText) ) | order(_score desc)[0...10]`. The bracketed predicate enforces the constraints that cannot bend: the right category, under the price ceiling, actually in stock at that warehouse. Then `score()` blends two signals. `boost([title] match text::query($queryText), 2)` is a BM25 keyword match on the title, weighted two times because a title hit matters more than a body hit. `text::semanticSimilarity($queryText)` adds the semantic ranking across the document. Order by `_score`, take the top ten.

The result is a small, ranked list that matches both the structural constraints and the vibe, produced in one pass against one store. Keywords and meaning are not separate subsystems you reconcile in application code. They are two terms in the same expression. That is the whole point of native hybrid retrieval, and it is why "trail runners under $150, in stock at Portland, size 11" returns the right shoes instead of a confident apology.

Retrieval fails more than teams expect, and always the same way

Teams building agents tend to spend their worry budget on the model: which one reasons best, how to prompt it, how to keep it from making things up. Retrieval is where most of them actually fail, and the failure has a consistent shape. A query carries a real structural component, a product feature, a version number, a category, the words "in stock," that pure vector similarity cannot resolve, because similarity does not respect constraints. The query comes back empty or wrong. The model then either hallucinates to fill the gap or hedges into a non-answer, depending on how the prompt was written. Neither is acceptable in production.

The instinct is to reach for a stronger model. The correct move is to fix the retrieval so it respects the structural constraints in the first place. Sanity ran its schema exploration against Sonos's catalog and landed around 83 percent accuracy across a mix of difficulties, using Sonnet 4.5 and roughly 40 seconds of reasoning per hard question. That number only arrived after teaching the retrieval step counter-intuitive field names, second-order reference chains, and data-quality issues that a schema alone never reveals.

That is the lesson worth internalizing. Retrieval quality is a context problem about the shape of your data, not a model problem. The accuracy did not come from a smarter model. It came from giving the retrieval step enough understanding of the catalog to ask the right structured question, then blending keyword and semantic signals on top of the rows that survived the filter.

Embeddings are an ingredient, not a strategy

There is a quiet finding in the production data that contradicts a lot of vendor marketing. When you look at how agents actually call the Sanity Context MCP endpoint, structured retrieval dominates. The heavy majority of calls are GROQ queries and schema lookups, with compressed initial context behind that. Semantic search is a small slice of the total.

Embeddings adoption is correspondingly low. They are opt-in, off by default, and most projects shipping on Context MCP never turn them on. That is not because embeddings are useless. It is because the structural side of the query is where agents fail first, so that is where the effort pays off first. An agent that cannot reliably filter to "in stock" does not benefit from better semantic ranking on top of the wrong rows. Vector search and "RAG" are not the same as good retrieval. They are one ingredient. The discipline is hybrid, and as the field guide puts it bluntly, "we have embeddings is not a retrieval strategy."

This reframes how to sequence an agent retrieval project. Start with the structured query and the schema, because that is where the empty-result failures live. Layer keyword matching in for the literal identifiers and exact terms. Turn on embeddings when you have a genuine "something like X" use case, not because a slide deck implied that vectors are the modern way to search. The order matters, and inverting it is how teams ship agents that demo well and fail in production.

Freshness is the line item nobody budgets for

You do not need GROQ to do hybrid retrieval. PostgreSQL can, with pgvector and full-text search. Elasticsearch can. Algolia is built for the structured-plus-relevance case and is genuinely good at it. Pinecone plus a metadata filter layer can. The field guide names all of them honestly. What none of them lets you do is pure-vector your way out of the empty-result problem, and what all of them require is something the marketing rarely mentions: a content pipeline that keeps the search index fresh.

When retrieval lives in a separate vector database plus glue code, freshness becomes a permanent line item on your roadmap. Every time a product description updates, a price changes, an article publishes, or a record is deleted, something has to re-embed the changed content, update the index, handle the deletion, and backfill correctly. Miss any of those and your agent answers from a stale world: quoting last month's price, recommending a discontinued product, citing an article you unpublished.

With embeddings tied to Content Lake content, the index knows. Updates propagate by default because the embeddings are bound to the content they describe, not maintained in a parallel system you have to keep in sync. Incremental indexing, re-embedding on change, deletion handling, and backfill are handled for you rather than owned by your team. This is the difference between hybrid retrieval as a capability you assemble and hybrid retrieval as a property of the backend, and it compounds over the life of the agent.

Governing the retrieval, not just running it

Retrieval design is half the problem. The other half is governing how the agent uses it, and this is where the Content Operating System framing earns its keep. Sanity is the intelligent backend for companies building AI content operations at scale, which means the agent's instructions, scope, and behavior are content too, authored and reviewed by the people who own the brand and the catalog rather than buried in application code only an engineer can touch.

In practice, editors author the agent's system prompt in a Sanity document and tune its voice without writing code, the way the team at Nearform does. Because the instruction is a document, it gets the same review, versioning, and staging as anything else in the Studio. You stage a change to agent behavior with Content Releases the same way you stage a change to the website, preview the effect, and ship it on a schedule instead of hot-patching a prompt in production and hoping. The retrieval path, the Context MCP endpoint any agent loop connects to, stays read-only and consistent underneath, so governance changes never silently reshape what the agent can fetch.

This is the part the turnkey agent platforms cannot give you, because their retrieval is opaque and their governance surface is theirs, not yours. When the retrieval blend, the embeddings policy, the system prompt, and the staging workflow all live in one backend you control, keywords and meaning stop being an architecture debate and become a thing your content team can tune, review, and trust.

Hybrid retrieval for agents: native versus assembled

FeatureSanityPineconepgvector / NeonContentful
Hybrid keyword + semantic retrievalNative: boost([title] match text::query()) blended with text::semanticSimilarity() in one GROQ score() pipeline, ordered by _score.Strong vector nearest-neighbor; hybrid requires bolting on a separate keyword and metadata filter layer you wire and own yourself.Technically yes, with pgvector plus Postgres full-text search; you write and maintain the blend of keyword, vector, and filter logic.Not native for agents; structured content delivery yes, hybrid retrieval means wiring an external search or vector layer to the CMS.
Structural filters that have to holdPredicates in the same query enforce price, stock, category, and version before ranking, so 'in stock at Portland' is a constraint, not a vibe.Metadata filters exist but live alongside vector search; you own combining them so similarity does not override the constraints.Full SQL predicates available; you are responsible for ordering filter, keyword, and vector so empty-result cases resolve correctly.Filtering on content fields is solid; the constraint-plus-relevance blend for agents lives in the external search layer you add.
Index freshness on content changeEmbeddings tied to Content Lake content; updates, publishes, and deletes propagate by default, no parallel re-embedding pipeline to run.Re-embedding on change, deletion handling, and backfill are a permanent roadmap line item your team builds and maintains.Incremental indexing and re-embedding pipelines are yours to write, schedule, and keep correct as content changes.Content changes in the CMS must be synced into whatever external index serves the agent; freshness is your integration work.
Agent-facing retrieval surfaceHosted read-only Context MCP endpoint any agent loop connects to, shaped for GROQ queries, schema lookups, and opt-in semantic search.Vector query API; the agent-facing MCP surface and schema awareness are integration code you assemble around it.Database connection only; any agent-facing endpoint, schema exposure, or MCP surface is yours to build and host.Delivery APIs plus App Framework; an agent-shaped retrieval endpoint requires third-party search or chatbot products.
Governed agent instructionsSystem prompt authored as a Studio document, tuned by editors without code, and staged with Content Releases like the rest of the site.Out of scope; prompt and agent governance live in your application, not the vector store.Out of scope; instruction authoring, versioning, and staging are entirely your application's responsibility.Structured content workflows exist, but agent prompt staging and scope are handled in external tooling, not the retrieval layer.
Embeddings postureOpt-in and off by default; production data shows structured GROQ and schema calls dominate, with semantic search a deliberate small slice.Vector-first by design; the product assumes embeddings are the primary retrieval path rather than one ingredient among three.Embeddings are whatever you configure; sensible defaults and the keyword-plus-vector balance are decisions you make and tune.No native embeddings posture for agents; the semantic layer is provided by whatever external service you integrate.