Repository navigation
EN lab 05
Lab index | Français | Infrastructure prerequisite | Next: Foundry IQ
Build a retrieval-augmented generation (RAG) pipeline: ingest documents, split them into passages, generate vectors, retrieve relevant passages, and ground an answer in those passages. Allow 90–120 minutes after infrastructure is available. Retrieval and answer generation are different stages; a plausible answer does not prove retrieval worked.
Important
Actual Free-tier Search execution now supplements the original review.
Three supplied PDFs were indexed and queried with lexical, filter, facet,
semantic, vector-contract, hybrid and negative checks. All 17 hotel checks passed
after removing unsupported queryLanguage from the current API request.
Those Free-run vectors were explicit city features, not semantic embeddings.
A later approved paid run passed 14 keyless checks with real 1,536-dimensional
embeddings, managed-identity query vectorization and semantic hybrid retrieval.
That first run used local chunking. A subsequent private Basic Search run passed
25 checks with the three original PDFs, a private Blob indexer, nine child
projections, integrated embeddings and semantic hybrid retrieval. The Copilot
connection was not executed in those runs. See the detailed private procedure, cleanup and the
actual results.
These are original teaching instructions, not a republication of protected workshop text or code. The original three PDF demonstration files exist locally but are not distributed here. No protected screenshots are included.
The later isolated keyless setup indexed the three original hotel documents and passed a genuine natural-language query vectorizer check. Copilot's Entra connection attempt was blocked before sign-in by the hosting browser's pop-up restriction; no connected question ran. Hotel source URLs also remain unavailable, so navigation would require separate proof even after sign-in recovery. See the connection record.
The fresh synthetic-fixture execution
now passes S5-03, S5-05 and S5-06 using the exact fictional Harbor/Forest text
below. Lexical, real natural-language vector, hybrid and semantic-hybrid queries
all return Harbor first. The parent filter returns only Harbor; the nonfilterable
field returns HTTP 400 identifying chunk. Both attempts' disposable indexes
were deleted and the three original index schemas independently verified unchanged.
No existing route, role or authentication setting changed.
The initial attempt uploaded both documents but stopped when index statistics stayed at zero. The explicit second attempt verified readiness through actual document-search count, reusing the exact input embeddings rather than generating them again. This is direct document loading, not a Blob/indexer run or a connected agent test. That direct-load fixture uses source URNs, not navigable citations.
The later public-path ingestion attempt
confirms that enforced Storage policy disables public networking. Container-scoped
RBAC cannot override that boundary: upload returns HTTP 403. No policy exception
or key-authentication fallback is used; the temporary account and roles are removed.
The private upload
uses a managed-identity job without a public IP, a private endpoint and private
DNS. Exactly forest.txt and harbor.txt round-trip with matching hashes,
closing S5-01. Its interrupted indexer-resume attempt fails before indexer creation.
An asynchronous DNS-link cleanup race is preserved; subsequent owned-zone cleanup
and the restored original four-resource inventory are independently verified.
S5-02 and connected-answer/citation acceptance are not established by that upload.
The separately guarded private retry does run the Blob indexer through an approved Search shared private link, processing two files successfully with zero failed items and zero warnings. Its document readback returns HTTP 400 because the selected vector field was not explicitly retrievable. The failure is retained rather than treating indexer success as readable-chunk acceptance. All temporary resources, roles and shared links are deleted; original Search objects and ARM inventory are verified unchanged.
The corrected private readback run explicitly makes the disposable vector field retrievable. After supported Azure CLI authentication recovery, it resumes without redeployment or re-upload. The original expired-token failure and initial cleanup errors remain in private evidence. Private indexing succeeds with two processed files, zero failed items and zero warnings. Both projected passages exactly match the fictional input, with parent/source metadata and real 1,536-dimensional vectors: S5-02 passes. All disposable infrastructure, roles and shared links are removed; original Search objects, identity roles, shared links and four-resource ARM inventory are verified unchanged. Storage public networking, keys and anonymous access remain disabled. At that ingestion checkpoint, five connected/navigation/French/ denied-identity criteria and whole-lab certification remained open.
The native connected run
recovers the real formal Entra connection without keys or a policy exception.
The documented ai:// form fails its native test without saving a connection;
a separately guarded actual HTTPS service endpoint succeeds. An unpublished
isolated Standard draft connects only the exact two-document fictional index,
using the real immutable published corpus permalink, not invented PDF URLs.
Knowledge is Ready; official clones verify web and general knowledge Off.
The first frozen cohort passes 3/4 but answers the French question in English.
No secondary language was configured. That failure remains. After adding
French and selecting the French test-session language, a distinct frozen
cohort passes 4/4: Harbor 07:00 opening, Forest 21:00 closing, explicit
price abstention and French answers with individual source citations.
Actual native Search traces and citation snippets match the intended source.
The abstention cites the real consulted Forest record, not evidence of a price.
No automatic language detection or combined cross-configuration pass is claimed.
Eight official snapshots are preserved privately. One bicycle snapshot has
an empty configuration payload; three other recovery payloads match and
independent before/after official clones confirm all 17 authored files unchanged.
The validator's Cannot find module '@azure/msal-node-extensions' error remains,
without bundle modification or a claim of successful YAML schema validation.
One native citation click opens the exact immutable public fictional source,
with both facts visible, but omits its section fragment. Draft, formal connection
and temporary index are deleted; original objects and schema hashes are preserved.
This closes four fictional native criteria, not original hotel PDF navigation,
genuine denied identity, original-corpus acceptance or whole-lab certification.
The fresh guarded native observation
runs one closing-time question after independently confirmed Reader removal,
600.002 seconds before new connection creation, actual fresh connector sign-in
and a passing public guard. Direct Search is 403; the native source reports
ConnectorRequestFailure / AzureAISearchClientError, zero returned/verified
records and zero citations. Its trace does not expose a native HTTP status.
The parent asks generically to rephrase, with an additional no-information notice.
No source fact is returned in that single response.
This is a direct authorized baseline plus native denied-from-first-use, not a paired native authorized/removal test, an independently unprivileged identity or verified permission-specific parent error handling. S5-10/T014 remain open. Earlier failure/blocker results are preserved separately. Official configuration is unchanged; owned cleanup and original agents/connections/schemas/account/roles are independently verified, with the owned browser closed normally.
The later isolated permission-removal test fails the S5-10 no-leak check. A separate new keyless Search service contains only the two fictional records. The same approved administrator has a new index-scoped Reader grant; no original working permission is removed. This is not an independently unprivileged-user test.
One authorized native question returns Harbor 07:00 with its actual citation.
After removing only the owned Reader grant, direct document queries return
HTTP 403 with both token requests. The CLI returns the same cached JWT, not
proof of a newly issued token. In a distinct native conversation, the one
denied-phase question nevertheless returns 07:00 and the Harbor citation.
Its official Search trace contains both actual fixture records and no Search
error. Direct denial therefore does not establish native isolation.
The effective native principal and root cause remain unproved; no cache,
propagation or privilege explanation is asserted.
The post-submission read times out. Recovery exports that existing conversation without replaying the question. Both official configuration payloads match; the independent after-native clone preserves all 17 authored files. The owned draft, connection, four role assignments, Search service/index and independently empty group are removed. A CLI connection deletion rejects an environment route/filter mismatch; a correctly scoped first-party request then succeeds, with absence verified. Original inventories, embedding account, roles and three Search schemas are preserved. The owned browser closes normally. Actual spending is not finalized. S5-10, T014 and whole-lab acceptance stay open.
The subsequent formal AccessKey connection did run two actual isolated hotel questions. The answer Qatar matched the source's location field; the interplanetary-shuttle question abstained. The original fixture's city expectation was corrected to a source-stated location, not by rewriting the corpus. The connected results prove source grounding, not navigation to an original hotel PDF.
Figure 1. Newly authored explanatory diagram, not a screenshot or evidence of a deployed system.
You need:
- An approved Azure subscription, resource group, region, budget, and available embedding-model quota
- Azure AI Search, preferably Basic or higher for outbound managed identity, and a private Blob container
- An embedding deployment whose model and dimensions match both indexing and query-time vectorization
- Search Service Contributor for object management, Search Index Data Contributor for document loading, and Search Index Data Reader for queries, as applicable
- Storage Blob Data Contributor for your upload identity; Storage Blob Data Reader for the Search service identity reading blobs
- A standard-harness Copilot Studio agent, environment access, suitable licensing, and permission to create connections or agent flows
- Completion of Lab 5.1, or an administrator-provided equivalent
Contributor on a resource group does not by itself grant Search document access. Roles, networking, and authentication are independent checks. Use the Search RBAC role definitions, not a similarly named role selected by guesswork.
Open the standard agents experience for the Topics, Knowledge, and agent-flow steps below. A harness is the runtime; generative versus classic orchestration is a separate setting within the standard agent experience. Prefer generative orchestration for automatic tool selection; use an explicit topic call if you need deterministic routing.
-
Record an inventory of your approved files, expected titles, language, and intended reader permissions. Do not upload real customer information or documents you cannot redistribute.
-
For a predictable beginner exercise, create two UTF-8 text files locally with the following original, fictional contents. These invented properties are test fixtures, not hotel recommendations.
-
Name the first file
harbor.txt:Harbor Training Hotel City: Harbor City The training hotel has a rooftop garden and bicycle storage. The bicycle desk opens at 07:00. -
Name the second file
forest.txt:Forest Training Lodge City: Pine Town The training lodge has a reading room and indoor pool. The reading room closes at 21:00. -
In Azure portal, open the approved storage account, select Containers, and create a container named
training-documentswith anonymous access disabled. -
Upload only these two files for the controlled test. Confirm that the blob list contains exactly
harbor.txtandforest.txt. Use a separate container if you later evaluate the authorized workshop PDFs.
Keep the fixture set separate from the workshop corpus. Two input files do not imply exactly two indexed chunks; chunk count depends on splitting and extraction.
- Open your Azure AI Search service and start the current Import data wizard. Older workshop UI labels say Import and vectorize data. Select a vectorization/RAG path, not a keyword-only import.
- Select Azure Blob Storage and the private container. Prefer the Search service managed identity for reading storage. Configure the necessary identity and roles before running the wizard.
- Select text extraction and chunking. A useful starting experiment is 1,000 characters per chunk with 200 characters of overlap. Record the actual unit; characters and tokens are not interchangeable.
- Select an approved embedding deployment. Confirm its model name, deployment name, and actual output dimensions. The reviewed deployment uses
text-embedding-ada-002with 1,536 dimensions. A different model is acceptable only if the index, embedding skill, and query vectorizer agree. - Name the new index
training-rag, and record the generated names of the data source, skillset, and indexer. Do not assume generated names equal those in an older lab. - Review the schema before creation. Retain retrievable text and document metadata, a searchable vector field, and a semantic configuration that prioritizes the title and passage text.
- Preserve a retrievable citation URL such as
metadata_storage_path, with a usable authorized document link. A title alone is not a resolvable citation, and a private blob URL is not automatically accessible to every agent user. - Create the objects and run the indexer. Wait for its final status; inspect individual warnings and errors rather than accepting only a green overview badge.
- Open Search explorer and retrieve a few documents. Confirm nonempty passage text, nonempty title or source identity, and a populated vector field if the field is retrievable.
The current portal quickstart is the preferred supported starting point. Its wizard may generate different field names; the query examples below assume you map them to chunk, title, and text_vector.
If you need to learn the individual objects, use the official integrated vectorization procedure instead of copying a legacy JSON schema.
- Create the Blob data source, then an index with an
Edm.Stringkey for each chunk, a filterableparent_id, searchable passage text, and aCollection(Edm.Single)vector. - In the skillset, split document content and embed each child passage. Configure one-to-many index projections from the passage context.
- Map passage text, vectors, title, and citation metadata into the child index. Let projection processing manage the parent association rather than hand-mapping the parent key.
- Set
projectionModetoskipIndexingParentDocumentswhen the index should contain only chunks. Ensure the projection and indexer target the same intended index. - Attach the skillset to the indexer. Merely creating a data source and an index does not populate either vectors or text.
See index projections. Do not assume the original chunk schema provides citation metadata: its title/text/vector fields need an explicit source-URL addition for clickable citations.
-
Open Search explorer in JSON mode. Confirm the selected index and use field names from its actual schema.
-
Run a lexical baseline:
{ "search": "rooftop garden", "select": "title,chunk,parent_id", "top": 3, "count": true } -
Run a vector-only query with a configured query-time vectorizer:
{ "vectorQueries": [ { "kind": "text", "text": "Where can I store a bicycle?", "fields": "text_vector", "k": 50 } ], "select": "title,chunk,parent_id", "top": 3 } -
Add
"search": "bicycle storage"to that object for hybrid retrieval. Hybrid search merges lexical and vector results using reciprocal rank fusion, not by adding unrelated raw scores. -
To test semantic reranking, add
"queryType": "semantic"and"semanticConfiguration": "YOUR_CONFIGURATION_NAME"to the hybrid object. Replace that placeholder with the real configuration. Keep meaningful search text and enough candidates for reranking. -
Test a filter on a field actually declared filterable. Copy one returned
parent_idand use"filter": "parent_id eq 'COPIED_PARENT_ID'". Escape an embedded apostrophe by doubling it. Results must all have that same parent ID. -
As a negative test, filter on
chunkwhen it is not filterable. Expect HTTP 400 with a field-validation error, not an empty successful response. -
Save query text, selected method, top results, latency, and expected supporting passage. Repeat the same query set after any change.
For REST or HTTP-flow requests, the document-search API version 2025-09-01 remains listed as stable; 2026-04-01 is the latest stable version in the API-version reference. Use one supported version consistently. Do not transplant preview-only schema properties into a stable request.
The reviewed lab index declares an empty scoring-profile list. That is not a completed scoring-profile exercise.
- In a separate test index or reviewed schema update, add a text-weight scoring profile that gives
titlea higher weight thanchunk. - Use the same lexical query with and without
scoringProfile. Record the profile definition and the changed ordering. - Compare relevance, not raw score magnitudes across BM25, hybrid, and semantic results. Keep the profile only if your labeled test set improves.
The hybrid query guidance explains candidate selection and reranking. Extra replicas do not fix a wrong vector dimension or an unusable citation.
- Open the intended environment and standard agent. Confirm you are editing a disposable training agent, not a production agent.
- Select Knowledge, Add knowledge, Featured, and Azure AI Search. Create a formal data connection using the authentication options supported by your environment.
- Prefer Microsoft Entra ID where available. Do not paste credentials into agent instructions, index descriptions, screenshots, or this repository.
- Select the single intended vector index and add it to the agent. Wait for knowledge status
Ready. - Give the agent original instructions: answer accommodation questions only from the training documents, identify the source, and say that information is unavailable when the documents do not support a claim.
- Disable web search and Allow ungrounded responses, and avoid unrelated knowledge during the controlled evaluation. Independently verify the saved settings; source-only instructions alone are not a configuration check.
- Ask the fixture questions in the test matrix. Inspect the activity trace and citations; an answer alone does not identify the route used.
- For French testing, add French (France) under Settings, Languages, then select it through the test pane's More, Language menu and start a fresh conversation. Typing French alone did not switch the English-only draft. Return the test pane to the primary language before authoring. Follow the multilingual agent guide; recorded client locale is not proof of the selected conversation language.
The official connection guide currently contains both key-based examples and Entra-based recovery advice. Use its formal connection workflow and the authentication choice allowed by your tenant. Do not create a hand-built, unsupported knowledge connection as a workaround.
Choose this route when the exercise requires explicit filters or query parameters. Evaluate it separately from the knowledge route so you can tell which path answered.
- Create a standard agent flow with the agent-request trigger and a text input named
question. - Add an HTTP action that sends a POST to the document-search operation for your index. Store endpoint and credentials in an approved connection/configuration facility; enable secure input/output handling where available.
- Set JSON content type. Use an approved Entra connection/token flow, or a query key for document queries if key authentication is explicitly approved. Never expose an admin key to conversation users.
- Construct a JSON object with the question as a value, not by concatenating unescaped user text into JSON. Set
top,select, and any fixed authorization filters on the server side. - Parse the response's
valuearray and return bounded passage text, source titles, and citation URLs. Return an explicit empty-results state if the array is empty. - Add the flow as an agent tool. Describe when to call it and ground the answer in its returned passages. Do not treat a successful HTTP request as proof of a supported answer.
- For deterministic testing, invoke the flow explicitly from a topic and inspect its run. For generative routing, inspect the chosen tool in the activity trace.
- If a custom connector is required, define this same POST operation, authenticated connection, typed input, and bounded response. Importing an operation alone does not create a real-time knowledge source.
HTTP actions, custom connectors, and connection types can have separate licensing and data-loss-prevention constraints. No flow or connector was created during this review.
For S5-10, use a disposable test connection identity, not the administrator's existing roles. The identity used by Search can differ from the person chatting with the agent: a maker-owned connection does not automatically impersonate each end user.
- Record the actual connection principal and its approved, index-scoped Search Index Data Reader assignment. The RBAC guide documents single-index scopes. Do not grant access to unrelated indexes.
- Establish a successful authorized baseline on the fictional fixture through both the direct query and the intended connected route.
- Remove only that test assignment. Allow bounded propagation, refresh the test authentication and start a new conversation without prior retrieved content.
- Verify both direct denial and the connected error path. No fixture text may appear from cached context, another source or a fallback. A direct HTTP 403 alone does not prove agent-level isolation, and an authorization failure must not be silently treated as an empty search.
- Delete or restore only the disposable resources approved for this test. Record final role state and leave the administrator's permissions unchanged.
Exact values below belong to the original synthetic fixture only. Natural-language wording and generated scores are not exact-match contracts.
| ID | Action | Expected assertion | Current result |
|---|---|---|---|
| S5-01 | Inspect the fixture container | Exactly two named input files | Pass: private list and two hash roundtrips |
| S5-02 | Inspect the latest indexer run |
status is success; itemsFailed is 0; readable chunks exist |
Pass: private indexer, two exact chunks |
| S5-03 | Search rooftop garden
|
A supporting Harbor passage appears in the top three | Pass: Harbor first |
| S5-04 | Ask about bicycle-desk opening | Answer includes 07:00 and a Harbor citation |
Pass: native fictional fixture |
| S5-05 | Apply the copied-parent filter | Every result has the exact selected parent_id
|
Pass: Harbor only |
| S5-06 | Filter on nonfilterable chunk
|
HTTP 400; useful field error |
Pass: field error |
| S5-07 | Ask for the lodge's airport shuttle price | Explicit lack of source support; no invented price | Pass: native explicit abstention |
| S5-08 | Inspect knowledge/flow trace | The intended source or tool was invoked; citation opens for the authorized tester | Pass: native trace and fictional source click |
| S5-09 | Repeat in French | Supported facts remain 07:00 and 21:00; sources remain correct |
Pass: separate French-enabled cohort |
| S5-10 | Remove the tester's data permission in an approved test | Access is denied; no content leaks through a fallback | Failed: native fact/citation after direct 403 |
For at least ten labeled questions, record supporting-document IDs before testing. Calculate hit@3 as questions with a relevant passage in the first three results divided by questions tested. Calculate citation correctness as supported cited claims divided by cited claims inspected. Record median/p95 latency only after collecting enough timed runs, plus the sample count. Do not publish a percentage from an unexecuted test.
| Symptom | Check and safe response |
|---|---|
| Blob upload denied | Your upload identity needs data-plane permission; refresh credentials after propagation |
| Indexer cannot read storage | Check the Search identity's reader role and network path separately |
| Vector length error | Compare deployment output length, skill dimensions, and index dimensions; reindex into a compatible index |
| Empty results | Inspect indexer errors, extracted text, index name, filter, and query language before changing prompts |
| Semantic error or throttling | Check configuration name, quota, tier, and request limits; reduce test concurrency |
| Citations cannot open | Correct URL mapping and reader access; do not enable anonymous blob access |
| Knowledge dialog fails | Use the official connection recovery guidance with the environment administrator |
| Fluent but unsupported answer | Isolate knowledge sources, disable web search, inspect actual retrieval and enforce abstention |
- Export only sanitized test evidence: method, assertion, status, anonymized source label, and timestamps. Do not store keys, tokens, protected text, or private URLs.
- Remove the test flow/connector or its agent association, and remove training knowledge from the disposable agent.
- Delete only the indexer, skillset, data source, index, and fixture blobs created for this run, after confirming they are not shared.
- If infrastructure belongs to Lab 5.1, follow its reviewed Terraform cleanup plan. Deleting an index alone does not stop Search service billing.
Historical subsystem results establish S5-01/S5-02/S5-03/S5-05/S5-06. The separate native fictional run establishes S5-04/S5-07/S5-08/S5-09. These scoped executions are not a single original-corpus end-to-end cohort or whole-lab acceptance. Original hotel URL/corpus acceptance and S5-10 through the intended authenticated native route remain open. The disposable ingestion and connected objects are cleaned up; do not redeploy merely to repeat passes. No production-readiness, cost saving or relevance improvement is claimed.
Source screenshots are not new executions. Les captures d'origine ne sont pas de nouvelles exécutions. See validation / voir le registre.