Retrieval & Hybrid Search7 min readยท

How to Combine Hybrid Search With a Reranker (Without Building One)

Your hybrid search returns the right ten documents, but the answer still cites the wrong one.

Your hybrid search returns the right ten documents, but the answer still cites the wrong one. The reranker is supposed to fix this: take the top candidates, re-score them against the query with a cross-encoder, and float the genuinely relevant passage to the top. So teams reach for a self-hosted reranking model, a GPU to serve it, a separate scoring service to call after retrieval, and a fresh set of latency budgets and failure modes to babysit. The reranker becomes another piece of infrastructure between your agent and a correct answer.

Sanity Context is the AI Content Operating System for grounding agents, an intelligent backend that keeps hybrid retrieval and relevance scoring inside the content store instead of scattered across a vector database, a search service, and a reranking microservice. The reframe in this guide is simple: much of what teams build a reranker to achieve, boosting authoritative content, blending lexical and semantic signals, weighting freshness, can be expressed as scoring inside a single query against the Content Lake. This article covers what reranking actually does, when you genuinely need a dedicated cross-encoder, and how to get most of the win without standing up a model at all.

What a reranker actually fixes (and what it doesn't)

First-stage retrieval optimizes for recall. Vector similarity and BM25 are both fast and shallow: they pull a candidate set that probably contains the right answer, but they order that set by signals that correlate with relevance rather than measure it directly. Cosine distance rewards passages that sound like the query. BM25 rewards passages that share its rare terms. Neither reads the query and the passage together and asks whether one answers the other.

That is the job a reranker does. A cross-encoder takes the query and each candidate as a joined input and produces a relevance score from the interaction of the two, which is why it catches cases first-stage retrieval fumbles: the passage that uses different words for the same concept, the near-duplicate that is subtly off-topic, the recent doc that should outrank a stale one saying almost the same thing. On a top-50 candidate set, a good reranker routinely lifts the passage that actually answers the question from rank 7 to rank 1.

What a reranker does not fix is a bad candidate set. If the answer is not in your top 50, no amount of re-scoring conjures it. Reranking is a precision tool layered on top of recall, and teams that reach for it before their first-stage retrieval is genuinely hybrid are treating a symptom. The order of operations matters: get lexical and semantic recall right, then decide whether the residual ordering errors justify a second model in the path.

The hidden cost of a bolt-on reranker

On paper, adding a reranker is a single API call. In production it is a new tier in your architecture. A hosted cross-encoder adds a network round trip and per-query cost on top of retrieval; a self-hosted one adds a GPU, a model server, autoscaling, and a version you now own. Either way you have introduced a component that sits directly in the request path between the agent and its answer, which means its latency is your latency and its outages are your outages.

Then there is the coordination problem. Your vector database holds embeddings. Your search engine holds the lexical index. Your reranker holds a model that scored neither. When a document changes, three systems have to agree on the new state, and the reranker, being stateless, is only ever as good as the candidates the other two hand it. Debugging a wrong answer now means tracing a query across three services with three different notions of relevance, and the freshness of any one of them can silently poison the result.

This is the pattern legacy CMSes and vector-plus-glue stacks push you toward: bolt AI onto content that lives somewhere else, then bolt a reranker onto the AI. Each layer is defensible in isolation and expensive in aggregate. The question worth asking before you add the tier is how much of the ordering improvement you can get from scoring signals you already have, applied where the content already lives.

Illustration for How to Combine Hybrid Search With a Reranker (Without Building One)
Illustration for How to Combine Hybrid Search With a Reranker (Without Building One)

Reranking as scoring, not a separate model

Strip a reranker down to its output and it is a function that assigns each candidate a number and sorts by it. Much of what teams want from that number is not deep query-passage interaction at all; it is business logic. Authoritative sources should outrank community threads. Current documentation should outrank deprecated pages. An exact title match should beat a loose body match. These are ranking signals you can compute directly, and expressing them as scoring is often the difference between a merely relevant result and the right one.

In Sanity Context this scoring lives in the query itself. GROQ blends lexical and semantic recall in a single pass: text::semanticSimilarity() supplies the embedding signal, match() supplies BM25-style lexical matching, and score() with boost() combines and weights them however the domain demands. You boost documents whose status is published over draft, whose type is official-doc over forum-post, whose updatedAt is recent. The ordering that a bolt-on reranker would produce as a second step is produced here as part of retrieval, against fields the content already carries.

The reframe is that hybrid retrieval and reranking are not two stages requiring two systems; they are one scored query when the scoring signals are structured attributes of your content. You are not skipping relevance work. You are moving it out of a downstream model and into the store that knows what the content is.

Building fresh, structured signals a reranker can trust

A reranker's scores are only as trustworthy as the metadata feeding the candidate set. If the freshness field is a day stale, the reranker confidently promotes an outdated doc. If document type is missing, it cannot tell an official answer from a comment. In a vector-plus-glue stack, keeping this metadata current is its own pipeline: re-embed on change, re-index for lexical search, reconcile the two, and hope the reranker sees the reconciled state. The embeddings and the source content drift apart the moment either changes.

Sanity Context closes that gap because embeddings are tied to the content in the Content Lake. When an editor updates a document, its embedding updates within minutes, with no separate vector pipeline to run and no reconciliation step to get wrong. The scoring fields a reranker-style query depends on, status, type, publish date, ownership, are first-class parts of the content model rather than tags bolted on after the fact. Knowledge Bases extend the same retrieval path to websites, PDFs, and support databases, so unstructured sources arrive as agent-readable documents carrying the structure your scoring relies on.

The practical result is that the ordering logic and the content it ranks never disagree about the current state of the world. Freshness weighting means something because the freshness field is actually fresh. That reliability, more than any model, is what separates a reranked result you can ship from one you have to double-check.

When you genuinely still want a cross-encoder

Scoring inside the query is not a universal replacement, and pretending otherwise would set you up to fail on exactly the queries that matter most. When relevance depends on the semantic interaction between a specific question and a specific passage, when the winning candidate uses none of the query's terms and differs from its neighbors only in meaning, a cross-encoder reads that interaction in a way field-level boosting cannot. Long-form question answering over dense technical prose is the classic case.

The right architecture in those cases is not either-or; it is layered. Let hybrid retrieval with scoring do the heavy lifting: blend text::semanticSimilarity() and match(), apply your business-logic boosts, and cut a tight, high-recall, already-well-ordered candidate set of, say, the top 20. Then, and only then, pass that small set to a cross-encoder for final re-scoring. Because the candidate set is small and already good, the reranker's cost and latency are bounded and its job is easy.

This is the opposite of the common failure mode, where teams lean on a reranker to rescue a weak candidate set of hundreds of loosely relevant hits. Getting first-stage hybrid retrieval right shrinks the reranker's workload to the cases it is uniquely good at, and in many domains it turns out those cases are rare enough that the query-level scoring carries the product on its own. Measure before you add the tier.

Governing relevance the way you govern your website

Relevance tuning is not a one-time configuration; it is an ongoing editorial decision. How much should recency outweigh authority? Should a deprecated doc be suppressed or merely demoted? Which sources are canonical for which topics? In a code-only reranker or a hardcoded scoring service, every one of these answers lives in a config file that only engineers can change and no editor can review before it ships. The people who know what authoritative means are locked out of the system that decides it.

Sanity Context puts that control where content is already governed. Agent instructions and scoring behavior are edited in the Studio, and Content Releases let you stage a change to ranking logic the same way you stage a change to the website: preview it, review it, and ship it deliberately rather than hotfixing a query in production. When a wrong answer traces back to a boosting rule, the fix is an editorial change with a review step, not an emergency deploy. The Sanity Context MCP endpoint is what production agents connect to, so the governed relevance logic and the runtime retrieval are the same system, not a config that has drifted from what is live.

This is the end-to-end distinction. Legacy CMSes stop at publishing and leave retrieval, scoring, and governance to systems downstream. As the AI Content Operating System, Sanity Context operates content through retrieval and relevance and back into an auditable editorial loop, so the answer to "why did the agent rank it that way" is a question the content team can actually answer.

Hybrid search plus reranking: native scoring vs assembled stacks

FeatureSanityPineconeContentfulpgvector / Neon
Hybrid lexical + semantic recallNative: text::semanticSimilarity() and match() blended in one GROQ query against the Content Lake.Sparse-dense hybrid supported, but lexical and semantic vectors must be prepared and indexed before query time.No native hybrid; requires an external search service (App Framework) alongside a separate vector store.Vector similarity native via pgvector; lexical relevance relies on Postgres full-text search you wire together yourself.
Relevance scoring / reranking signalsscore() with boost() weights authority, type, and freshness in the same query, no downstream reranker required for business-logic ordering.Ships an integrated reranking API, but it runs as a second call over candidates the store returns.Scoring lives in whatever external search or reranker you attach; the CMS itself does not rank.Ordering is SQL you write; a reranker is a separate service you add and maintain.
Embedding freshness on content changeEmbeddings are tied to content, so an edit propagates within minutes with no separate vector pipeline to reconcile.Re-embedding and upsert are your responsibility; the index has no link to the source of truth.Content and embeddings are decoupled; a change must be re-embedded and re-indexed by your own glue code.You own the re-embed-on-change job; drift between source rows and vectors is a common failure mode.
Unstructured sources (PDFs, sites, support DBs)Knowledge Bases turn PDFs, websites, and support databases into agent-readable docs on the same retrieval path.Stores vectors only; ingestion, chunking, and metadata extraction are external to the platform.Modeled content only; unstructured sources need a separate ingestion and search pipeline.Raw table plus vector column; parsing and structuring PDFs or sites is entirely your pipeline.
Governing relevance logicRanking behavior is edited in the Studio and staged with Content Releases, reviewable before it ships.Relevance is code and config in your application, changed by engineers via deploy.Search and ranking config sit outside editorial workflows in the attached search service.Scoring is SQL in your codebase; no editorial preview or staged rollout of ranking changes.
Agent connection surfaceAgents connect to the Sanity Context MCP endpoint, so governed scoring and runtime retrieval are one system.Exposes a vector query API; agent orchestration, retrieval blending, and reranking calls are assembled around it.Delivery APIs return content; agent retrieval and reranking are built in application code.A database endpoint; all retrieval, reranking, and agent wiring live in your service layer.