,

Azure AI Search and RAG, from Index to Answer (Azure Gen AI Series, Part 12)

How Azure AI Search grounds a model in your own documents: the ingestion pipeline, keyword and vector retrieval, RRF hybrid merging, and the semantic ranker that decides what the model actually reads.

Azure Gen AI Series · Part 12 of 30

The answer was fluent, confident, and quoted a refund window we retired eighteen months ago. The model did nothing wrong. It answered from the paragraph it was handed, and the retrieval step handed it a stale chunk that keyword search had ranked first. That is the failure mode this part is about. A grounded assistant is only ever as good as what its search index returns on the query, and on Azure that index is Azure AI Search.

Who this is for: You can already call a model from code (Part 11 covered the request itself) and you want the model to answer from your own documents instead of its training data. No prior search or vector experience is assumed. Retrieval-augmented generation, chunking, embeddings, and reranking are each defined here on first use. You have a model deployed and can reach it, and you have some documents worth grounding on.
Key takeaways: RAG does not teach the model anything. It finds the right passages at query time and pastes them into the prompt, so the quality of the answer is set by the quality of retrieval. Azure AI Search does that retrieval. Let it chunk and embed your documents for you with integrated vectorization instead of building a pipeline by hand. Run hybrid search, keyword and vector together, merged with Reciprocal Rank Fusion, because it beats either one alone. Turn on the semantic ranker to reorder the top results with a stronger model, and budget for it, because the first thousand queries a month are free and the rest are billed. Reach for agentic retrieval only when single queries stop being enough.

What RAG is, and why the index does the work

Retrieval-augmented generation, RAG, is a pattern where you search a knowledge store for text relevant to the user question, then send that text to the model along with the question and ask it to answer from what you gave it. The model is not retrained and it learns nothing permanent. Each request is a fresh prompt that happens to carry a few paragraphs of your data. That is the entire trick, and it is why a company can ground a general model on private documents without ever touching the model weights.

Because the model only sees what retrieval selected, the search step is where accuracy is won or lost. Azure AI Search is the managed search service that holds your indexed content and answers those queries, over plain keywords, over vectors, or both at once. It is a separate resource from Azure OpenAI, billed on its own tier, and it does the unglamorous half of RAG: store the chunks, find the right ones, hand back a ranked list. Get that list right and a small model looks brilliant. Get it wrong and the best model on the market quotes your retired refund policy with total confidence.

Where retrieval sits in a RAG answerThe model only ever sees what the search index returnedQuestionfrom the userAzure AI Searchranks the chunksreturns the top fewPromptchunks plus questionModelgrounded replycites its source
Nothing the model says can be better than the chunks the middle box handed it.

From documents to a searchable index

Before you can search anything, raw files have to become index records. Two operations make that happen. Chunking splits a long document into passages small enough for a model to embed and for the prompt to hold, because a fifty page PDF is useless as a single retrieval unit. Embedding turns each chunk into a vector, a list of numbers that places similar meanings near each other in space, so a query about refunds lands next to a passage about returns even when the words differ. You can write both steps yourself, or you can let Azure AI Search do them inside its indexing pipeline.

That built-in path is called integrated vectorization, and it is the one I reach for first. You point an indexer at a data source such as Blob Storage, attach a Text Split skill to chunk and an AzureOpenAIEmbedding skill to vectorize, and the indexer runs the whole thing on a schedule. When a document changes, the indexer notices, re-chunks only what moved, calls your embedding deployment, and writes both the text and its vector into the index. It is available on every tier and region, and it removes the standing pipeline that teams otherwise babysit. The embedding skill calls a model you deployed, so the same deployment choices from Part 3 apply here.

Integrated vectorization, end to endThe indexer chunks and embeds so you do not run a pipeline yourselfdata sourceblob, filestext splitchunkingembedding skilltext to vectorsearch indextext plus vectorthe indexer drives every box on a schedule
Change a source document and only the affected chunks are re-embedded on the next run.
In practice: Chunk size is the setting people skip and then regret. Too large and one chunk covers three topics, so retrieval pulls in noise and the model wanders. Too small and a single fact splits across two chunks, so neither one answers the question. I start around 300 to 500 tokens per chunk with a small overlap between neighbors, then adjust after reading what actually comes back for real queries. The embedding model caps input near 8,000 tokens, so oversized chunks fail the embed step outright.

Keyword, vector, or both?

Two retrieval styles live in the same index, and they fail in opposite ways. Keyword search, scored by an algorithm called BM25, matches the literal terms in the query. It is exact and unbeatable on part numbers, error codes, and proper nouns, and it goes blind the moment the user asks for a refund while your document says return. Vector search matches on meaning, so it connects refund and return with no shared word, and it degrades on rare exact strings because a product code has no semantic neighborhood to sit in. Each covers the other one gap.

Hybrid search runs both at once against the same index and combines the two ranked lists into one. You almost always want it. The keyword leg keeps you honest on identifiers and quotes, the vector leg rescues the paraphrased and the synonym-heavy question, and the merge gives you a single ordering that is better than either input. The cost is small: two searches instead of one over the same data, and a merge step measured in milliseconds. The table below is the mental model I use when someone asks why we are not just doing vectors.

ModeMatches onStrong atWeak at
Keyword, BM25Literal termsCodes, names, exact quotesSynonyms, paraphrase
VectorMeaningRephrased questionsRare exact strings
HybridBoth, then mergedMost real questionsSlightly more compute

The weak column is why I have never shipped vector-only retrieval to production. Someone always pastes an order number.

How hybrid search merges two rankings

The two legs produce scores that live on different scales, so you cannot just add them. BM25 scores are unbounded and vary with term frequency; vector similarity sits in a fixed range. Azure AI Search sidesteps the mismatch with Reciprocal Rank Fusion, RRF, which throws away the raw scores and keeps only the rank position. Each document gets a contribution of one divided by a constant plus its rank in each list, and the contributions are summed. The constant, k, is set to 60 in the service. A document ranked first in a list contributes one over sixty one; ranked eighth, one over sixty eight.

The effect is that agreement wins. A chunk that both legs like, even at middling ranks, floats above a chunk that one leg loved and the other never surfaced. That is exactly the behavior you want for grounding, because a passage two different methods both consider relevant is a safer thing to feed the model than a single method fluke. RRF is not tunable in the usual sense; you influence the merge by improving each leg, not by turning a fusion dial.

Worked example

Take four candidate chunks for one query. Chunk A ranks first on vector and eighth on keyword, so its RRF score is 1/61 plus 1/68, about 0.0311. Chunk B ranks second on keyword and fifteenth on vector, 1/62 plus 1/75, about 0.0294. Chunk C shows up only on keyword at rank third, 1/63, about 0.0159, and Chunk D only on vector at rank second, 1/62, about 0.0161. Final order: A, then B, then D, then C. The chunk both legs ranked well, A, wins even though neither leg put it strictly on top. The chart below plots those four scores.

RRF scores for four candidate chunksAgreement across both legs wins. Higher is better00.010.020.030.031A0.029B0.016D0.016C
A and B were found by both legs. C and D by one leg each, so they sink.

Reranking the shortlist with the semantic ranker

RRF gives you a good ordering cheaply, but it never reads the passages against the question; it only fuses ranks. The semantic ranker does read them. It takes the top results from the BM25 or RRF pass, up to 50 of them, and rescores each one with a language model trained to judge how well a passage answers a query, producing a reranker score on a scale from 0 to about 4. Results that fooled the first pass on shallow term overlap fall; results that truly answer the question rise. This second stage is where a lot of the felt quality of a RAG system comes from.

It also offers query rewriting, where the ranker expands the original query into as many as ten variants that fix typos or add synonyms before searching, which lifts recall on messy human phrasing. The trade is cost and latency. The semantic ranker is a billed add-on: the first 1,000 queries each month are free, and past that you pay per thousand, and it needs a Basic tier search service or higher, not the free one. It adds a little time per query too. So you turn it on for the user-facing path and leave it off for bulk or internal jobs that do not need the extra precision.

Relevance at rank five as you add stagesIllustrative round figures, one corpus. Higher is better00.250.500.750.900.62keyword0.71vector0.79hybrid0.86hybrid plus semantic
Each stage adds less than the one before. Measure on your own corpus; the shape holds, the numbers will not.
Gotcha: The semantic ranker is metered separately from your search tier, and the meter is easy to miss until the bill lands. A chatty front end firing several searches per user turn burns through the free 1,000 monthly queries in an afternoon, then charges per thousand after. Watch the reranker_score field too: if it comes back null, semantic ranking was requested but not applied, usually because the service is on the free tier or the plan is disabled, and you are silently back to plain RRF.

A retrieval query in Python

Here is one hybrid query with the semantic ranker turned on, using the azure-search-documents library and no key, the same identity-based auth from Part 10. Because the index was built with integrated vectorization, the query text is embedded for you server side through a VectorizableTextQuery, so you send words, not vectors.

from azure.identity import DefaultAzureCredential
from azure.search.documents import SearchClient
from azure.search.documents.models import VectorizableTextQuery

client = SearchClient(
    endpoint="https://my-search.search.windows.net",
    index_name="kb-docs",
    credential=DefaultAzureCredential(),
)

vector_q = VectorizableTextQuery(
    text="what is the refund window",   # service embeds this text
    k_nearest_neighbors=50,
    fields="content_vector",
)

results = client.search(
    search_text="refund window",          # BM25 keyword leg
    vector_queries=[vector_q],            # vector leg
    query_type="semantic",                 # reranker on
    semantic_configuration_name="default",
    top=5,
)
for r in results:
    print(round(r["@search.reranker_score"], 2), r["title"])

Expected output: up to five lines, each a reranker score on the 0 to 4 scale next to a document title, ordered highest score first. The top line is the passage the model should ground on.

Failure mode: a KeyError or None on reranker_score means semantic ranking did not run, so check the tier and the semantic plan. An error on VectorizableTextQuery means the index has no vectorizer defined, so either add one or pass a precomputed vector instead. A 403 means the identity lacks the Search Index Data Reader role on the service.

Agentic retrieval for the hard questions

Single-query retrieval, even hybrid with a reranker, breaks on a question that secretly contains three. Ask which plan changed the most between two releases and also whether it affects enterprise customers, and one search string cannot serve all of it. Agentic retrieval is Azure AI Search answering that class of question by decomposing it. A newer Knowledge Base object, exposed through a preview API version, takes the full question, splits it into focused sub-queries, runs each as its own hybrid search with a semantic rerank over the top candidates, and merges the results into one grounded set for the model.

It is genuinely better on multi-part and comparison questions, and it costs more, because you are now paying for several searches and rerank passes per user turn instead of one. I treat it as the third thing to try, not the first. Get hybrid plus semantic solid and measured, and only reach for agentic retrieval when your evaluation shows single queries failing on real multi-part questions. Because it rides a preview surface, confirm the current API version and object names before you build on it, since preview contracts move [VERIFY preview API version and Knowledge Base naming].

Sizing the index and its cost

The vector field carries most of the storage weight, and its size is set by the embedding model you chose. Each vector holds one float per dimension, so a model with more dimensions makes a bigger index and a heavier search. The two common Azure OpenAI text embedding models sit far apart here, and the larger one is not automatically the right call. More dimensions can mean better recall on subtle distinctions, but it also multiplies the bytes you store and move on every query.

Embedding modelDimensionsRelative index sizeReach for it when
text-embedding-3-small1536BaselineDefault, cost-sensitive corpora
text-embedding-3-large3072About twice the vector bytesRecall matters more than storage

One hard rule: the dimensions on the index field must match the model exactly. Configure a field for 3072 and feed it vectors from the 1536 model and the index rejects the write. Pick the model first, set the field to its dimension count, and do not mix models in one field. If you later switch models, you reindex; there is no in-place resize of a vector field.

My take: I start almost every index on text-embedding-3-small and hybrid retrieval, then measure before spending anything more. Most of the recall gap people blame on the embedding model is really a chunking problem, and moving to the large model doubles your storage to paper over a split-fact issue that a better chunk boundary would have fixed for free. Change one variable at a time, and change the cheap one first.

Start hybrid, add the semantic ranker, measure before agentic

If you build one thing from this part, build an index with integrated vectorization on text-embedding-3-small, query it hybrid, and turn the semantic ranker on for the user-facing path. That combination handles the large majority of grounding work, and every piece of it is a setting, not a pipeline you maintain. Keep the ranker off for batch and internal retrieval so the meter only runs where precision pays. Leave agentic retrieval for later, gated behind an evaluation that shows single queries actually failing on multi-part questions, and confirm its preview contract before you commit code to it.

The retrieval decisions here mirror the ones on other clouds; if you also run AWS, the same pattern is managed for you in Amazon Bedrock Knowledge Bases, and the vendor-neutral view lives in the core series. Next in this series we hand this retrieval to something that can act on it: the Azure AI Agent Service, where the model calls search as a tool inside a loop rather than in a single hop. Before then, index a folder of your own documents today, run one hybrid query with the ranker on, and read the top reranker score. If it is not pointing at the passage you would have picked, fix chunking before you touch anything else.

Azure Gen AI Series · Part 12 of 30
« Previous: Part 11  |  Guide  |  Next: Part 13 »

References

About The Author


Discover more from Journal of Intelligent Infrastructure – By Dr Pranay Jha

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure - By Dr Pranay Jha

Subscribe now to keep reading and get access to the full archive.

Continue reading