diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/README.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/README.md index e4e559edd..76f5fc452 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/README.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/README.md @@ -76,19 +76,19 @@ Complete the following before the hack session: - No local software installation required — all participant work is browser-based. > [!NOTE] -> Your Foundry project, gpt-5.4-mini model deployment, and your **own Fabric F2 capacity** are provisioned for you by the lab automation. In **Challenge 1** you stand up your own Fabric workspace and publish your **Fabric Data Agent** by running one notebook (Run All). You'll be handed a project endpoint and your capacity name at the start of the hack. Web Search is optional and may need project-level enablement. +> Your Foundry project, gpt-5.4-mini model deployment, and your **own Fabric capacity** are provisioned for you by the lab automation. In **Challenge 1** you stand up your own Fabric workspace and publish your **Fabric Data Agent** by running one notebook (Run All). You'll be handed a project endpoint and your capacity name at the start of the hack. Web Search is optional and may need project-level enablement. > [!TIP] > **You're ready to start when**, in the Foundry portal, you can: (1) see `gpt-5.4-mini` in your **model deployments** with status *Succeeded*, and (2) add the **Fabric Data Agent** tool to an agent and create the `inventory-hack-agent` connection (you do this in Challenge 2). If `gpt-5.4-mini` is missing, flag your facilitator before starting. > [!IMPORTANT] -> **Facilitators:** there is **no shared Fabric backend** — [`labautomation/deploy-lab.ps1`](labautomation/deploy-lab.ps1) provisions each attendee's Foundry project, model, and their **own Fabric F2 capacity**, and each attendee builds their workspace + Data Agent in Challenge 1. Ensure: the platform service principal has **Owner** on the attendee resource groups; [`lab-defaults.json`](labautomation/lab-defaults.json) sets **`groups: ["M365-E5-Users"]`** so attendees get a Power BI Pro license for the Fabric portal; the **lab tenant has Fabric enabled** (tenant-admin setting *“Users can create Fabric items / workspaces”* — **not** settable via `lab-defaults.json`); and the subscription has **Fabric F-SKU quota** (F2 = 2 CU; ~256 attendees per 512-CU subscription). See [`labautomation/README.md`](labautomation/README.md). +> **Facilitators:** there is **no shared Fabric backend** — [`labautomation/deploy-lab.ps1`](labautomation/deploy-lab.ps1) provisions each attendee's Foundry project, model, and their **own Fabric capacity**, and each attendee builds their workspace + Data Agent in Challenge 1. Ensure: the platform service principal has **Owner** on the attendee resource groups; [`lab-defaults.json`](labautomation/lab-defaults.json) sets **`groups: ["M365-E5-Users"]`** so attendees get a Power BI Pro license for the Fabric portal; the **lab tenant has Fabric enabled** (tenant-admin setting *“Users can create Fabric items / workspaces”* — **not** settable via `lab-defaults.json`); and the subscription has **Fabric F-SKU quota** (F4 = 4 CU; ~128 attendees per 512-CU subscription). See [`labautomation/README.md`](labautomation/README.md). > [!NOTE] > **Facilitator guidance (from run feedback):** > - **Audience & expectations:** pitch this at a **no-code / low-code** audience (e.g. technical decision-makers, level 150–200) and set that expectation in the invite — it is *not* a hardcore-developer hack. > - **Token throughput:** the model deploys at **200K TPM** and the lab packs **5 attendees per subscription**. If attendees hit rate limits, prefer **one subscription per attendee** (or raise the deployment's TPM). See [`labautomation/README.md`](labautomation/README.md). -> - **Fabric capacity:** the per-attendee **F2** covers this hack. If attendees hit **capacity throttling** (e.g. the parquet-load contention or intermittent Data Agent failures), bump to **F4** — either **resize live** (F SKUs support on-demand resize, no redeploy) or deploy with **`-FabricSkuName F4`**, and raise `estimatedDailyCostsUsd` to match (each SKU step roughly doubles the Fabric cost). For the **ontology** feature, F2 is likely undersized — size up (F4+) for that path. +> - **Fabric capacity:** the per-attendee **F4** default covers this hack comfortably, including capacity-heavy steps (parquet-load contention, intermittent Data Agent calls). To cut cost, drop to **F2** (`-FabricSkuName F2`, or **resize live** — F SKUs support on-demand resize, no redeploy) if attendees aren't hitting throttling, and lower `estimatedDailyCostsUsd` to match (each SKU step roughly doubles the Fabric cost). For the **ontology** feature, size up further (F8+) for that path. ### Challenge overview diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-01.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-01.md index 3d8faafe5..7451d9b02 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-01.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-01.md @@ -44,7 +44,11 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem > **Shared tenant — make sure you open *your* project.** Every attendee's projects are listed together at [ai.azure.com](https://ai.azure.com) and the names look alike. To find yours, match the **`FoundryProjectEndpoint`** on your lab dashboard (the **Credentials** tab of the MicroHack portal) to the project's **Parent resource** shown in Foundry. Work only in that project. - Locate your **model deployments** — confirm `gpt-5.4-mini` is deployed. - - Open a **deployed model → Playground** and send a test message: *"What can you do?"* (In the current Foundry portal you open the Playground from a model or an agent — there is no top-level *Agents → Playground* menu.) + - Open a **deployed model → Playground** and send this test message (in the current Foundry portal you open the Playground from a model or an agent — there is no top-level *Agents → Playground* menu): + + ```text + What can you do? + ``` - You will inspect agent decisions in Challenges 3 and 4 via **Traces → Response view** on an agent (not a top-level *Tracing* menu). ![Models and endpoints view in the Foundry portal showing gpt-5.4-mini deployed with status Succeeded](../images/challenge-00-model-deployments.png) @@ -56,9 +60,9 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem 3. **Provision your own Fabric workspace and lakehouse.** *(~5 min)* - Your lab dashboard gives you a **`FabricCapacityName`** — your own Fabric **F2 capacity**. You'll stand up a workspace on it and publish your own Data Agent by running one notebook. Follow each step carefully — this is the data backend every later challenge depends on. + Your lab dashboard gives you a **`FabricCapacityName`** — your own Fabric **capacity**. You'll stand up a workspace on it and publish your own Data Agent by running one notebook. Follow each step carefully — this is the data backend every later challenge depends on. - **a. Create your workspace on your F2 capacity.** + **a. Create your workspace on your Fabric capacity.** Go to [app.fabric.microsoft.com](https://app.fabric.microsoft.com) → **Workspaces** (left rail) → **+ New workspace**. ![Fabric left navigation with Workspaces open and the New workspace button highlighted](../images/challenge-00-new-workspace-button.png) @@ -68,7 +72,7 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem > [!NOTE] > Wherever the rest of this hack refers to the **`inventory-hack`** workspace, it means **your** uniquely-named workspace. The Lakehouse (`InventoryLakehouse`) and Data Agent (`inventory-hack-agent`) names live *inside* your workspace, so keep those exactly as written. - ![Create a workspace dialog with Workspace type set to Fabric and the attendee's F2 capacity selected under Details](../images/challenge-00-create-workspace.png) + ![Create a workspace dialog with Workspace type set to Fabric and the attendee's Fabric capacity selected under Details](../images/challenge-00-create-workspace.png) > If your capacity isn't in the dropdown: it must be **running** (Azure portal → your Fabric capacity → **Resume**), and you must be signed in as the lab user it was assigned to. Ask your facilitator if it still doesn't appear. @@ -84,8 +88,8 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem > [!NOTE] > Follow either this section or section 4(b) if you'd like to load the data and create the data agent using code. - **a. Download and upload the seed data.** - Download all seven `.parquet` files from the hack repo's [`data/`](../data/) folder to your computer. Open **`InventoryLakehouse`**, select **Upload files**, and use the folder button to select all seven files. Click **Upload** and wait until every file shows a green completion check. + **a. Upload the seed data.** + The seven `.parquet` files are in the hack repo's [`data/`](../data/) folder. Open **`InventoryLakehouse`**, select **Upload files**, use the folder button to select all seven files, click **Upload**, and wait until every file shows a green completion check. ![The InventoryLakehouse home page with Upload files selected](../images/challenge-00-lakehouse-upload-files.png) @@ -99,7 +103,11 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem Keep the schema as **`dbo`**, set the table name to the file name without the `.parquet` extension, and click **Load**. For example, load `demandhistory.parquet` into a table named `demandhistory`. Repeat this for all seven files. > [!NOTE] - > **Load the files one at a time.** *Load to tables* runs as a background job; starting the next load before the previous one finishes can fail with a *load already in progress* error. If a load errors, open **Monitor** (left rail), **cancel** any still-running load activity, then retry that file into a new table. + > **Load the files one at a time.** *Load to tables* runs as a background Spark job; starting the next load before the previous one finishes can fail with a *load already in progress* error. If a load errors, cancel the stuck job first: + > 1. Open the **Monitor** hub from the left navigation rail. + > 2. Find the running **Load to tables** / Spark activity for `InventoryLakehouse` (Status **In progress**). + > 3. Select it (or its **…** menu) and choose **Cancel**, then confirm. + > 4. Wait until the status shows **Cancelled**, then retry that file into a new table. ![The Load file to new table dialog using the dbo schema and demandhistory table name](../images/challenge-00-lakehouse-load-table.png) @@ -125,17 +133,26 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem You answer questions about Zava retail inventory. Use these tables: Inventory (onHand, reorderPoint, safetyStock per product per location), Products (name, category, unitCost, leadTimeDays, supplierId), Stores (retail stores and warehouses with region/city/state), DemandHistory (weekly units sold per product per store), ExternalSignals (market signals with affectedCategories), Suppliers, and ReplenishmentOrders (past purchase/transfer orders). Category values are stored as lowercase snake_case: garden_and_lawn, outdoor_power_tools, paint_and_supplies, smart_home. When a question names a category in plain English (e.g. "Outdoor Power Tools"), map it to the exact snake_case value before filtering; the same applies to affectedCategories in ExternalSignals. Prefer filtering by productId/SKU (e.g. P004) when the question names specific products. Always return exact numbers. Flag a product as CRITICAL when onHand is below safetyStock. ``` - Save the Data Agent. - ![The Agent instructions page containing the Zava retail inventory grounding instructions](../images/challenge-00-agent-add-instructions.png) - **g. Publish the Data Agent.** + **g. Test the Data Agent (before publishing).** + Open the **Test data agent** pane and ask: + + ```text + How many Leaf Blower X2 units are on hand at the Portland and Seattle stores, and are they below safety stock? + ``` + + You should get exact numbers with **CRITICAL** flags — proof your tables are selected and the agent reasons correctly. Testing the draft here confirms it works *before* you publish. + + ![The published data agent answering the Leaf Blower X2 test question with exact CRITICAL stock levels for Portland and Seattle](../images/challenge-00-agent-test.png) + + **h. Publish the Data Agent.** Click **Publish** in the top toolbar. In the **Publish data agent** dialog, enter a short description of the agent's purpose and capabilities, for example: `Zava inventory data agent for the Agentic Inventory Planning MicroHack.` Leave **Also publish to the Agent Store in Microsoft 365 Copilot** turned off, then click **Publish**. ![Publish data agent dialog with a purpose description entered and the Publish button highlighted](../images/challenge-00-agent-publish.png) - **h. Get your two IDs.** + **i. Get your two IDs.** After publishing, click the **Settings** gear in the data agent toolbar. Select **Model Context Protocol (MCP)**, then copy the **MCP server URL** using the copy icon. @@ -159,11 +176,6 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem ![MCP server URL with the Workspace ID and Agent ID segments identified](../images/challenge-00-agent-ids.png) - **i. Verify your agent answers.** *(1 min)* - Open the data agent's **Test data agent** pane and ask: *"How many Leaf Blower X2 units are on hand at the Portland and Seattle stores, and are they below safety stock?"* You should get exact numbers with **CRITICAL** flags — proof that your tables are selected and the agent is published. - - ![The published data agent answering the Leaf Blower X2 test question with exact CRITICAL stock levels for Portland and Seattle](../images/challenge-00-agent-test.png) - 4(b). **Load the data and create a Data Agent (with code).** *(~20 min)* > [!NOTE] @@ -189,7 +201,7 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem ![The notebook with InventoryLakehouse attached as the default Lakehouse and the Run all button highlighted](../images/challenge-00-run-all.png) > [!IMPORTANT] - > **First run on a fresh capacity — the table-selection step may need a moment (or a manual tick).** The publish cell selects your 7 tables automatically, but on a **cold F2 capacity** the Lakehouse's **SQL analytics endpoint** can take a couple of minutes to expose the newly-written tables. Until that schema sync finishes you may see **either**: + > **First run on a fresh capacity — the table-selection step may need a moment (or a manual tick).** The publish cell selects your 7 tables automatically, but on a **cold capacity** the Lakehouse's **SQL analytics endpoint** can take a couple of minutes to expose the newly-written tables. Until that schema sync finishes you may see **either**: > - the notebook raise **`No tables were selected (schema may still be syncing)`**, or > - an **`Error updating data agent data source selection(s)`** toast if you tick tables in the portal too early. > @@ -203,7 +215,13 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem ![Final notebook cell output printing the Workspace ID and Data Agent ID](../images/challenge-00-notebook-ids.png) **e. Verify your agent answers.** *(1 min)* - Open the data agent's **Test data agent** pane and ask: *"How many Leaf Blower X2 units are on hand at the Portland and Seattle stores, and are they below safety stock?"* You should get exact numbers with **CRITICAL** flags — proof that your tables are selected and the agent is published. + Open the data agent's **Test data agent** pane and ask: + + ```text + How many Leaf Blower X2 units are on hand at the Portland and Seattle stores, and are they below safety stock? + ``` + + You should get exact numbers with **CRITICAL** flags — proof that your tables are selected and the agent is published. ![The published data agent answering the Leaf Blower X2 test question with exact CRITICAL stock levels for Portland and Seattle](../images/challenge-00-agent-test.png) @@ -216,9 +234,6 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem > [!NOTE] > You attach the **Fabric Data Agent** as a *tool* on each Foundry agent, and the connection is created the **first time** you add it (Challenge 2). After that you simply **select** it. It points your Foundry agents at the data agent on top of **your** inventory Lakehouse. - > [!TIP] - > **No "Fabric Data Agent" in the Foundry tool catalogue later?** Your F2 capacity must be **running** (Azure portal → your Fabric capacity → **Resume**) and the setup notebook must have finished publishing the agent. - 5. **Understand the three-agent pattern.** Draw (on paper or a whiteboard) the flow: ``` @@ -242,7 +257,7 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem - [ ] You can name the key inventory tables and explain what each one is used for. - [ ] You have confirmed the `gpt-5.4-mini` model is deployed in your Foundry project. -- [ ] You have created your own Fabric workspace on your F2 capacity, run the setup notebook, and published your `inventory-hack-agent` Data Agent — and noted its **Workspace ID** and **Agent ID** (used in Challenge 2). +- [ ] You have created your own Fabric workspace on your Fabric capacity, run the setup notebook, and published your `inventory-hack-agent` Data Agent — and noted its **Workspace ID** and **Agent ID** (used in Challenge 2). - [ ] You can describe, in one sentence each, what each of the three agents does. - [ ] You can explain why combining web signals with governed data produces better decisions than either source alone. @@ -251,22 +266,25 @@ The data lives in **Microsoft Fabric** (a governed Lakehouse with inventory, dem | Symptom | Fix | |---------|-----| | `gpt-5.4-mini` is missing from your **model deployments** | Flag your facilitator before starting — the model deployment is part of your provisioned lab. | -| Your **`FabricCapacityName`** isn't selectable when creating the workspace | The F2 capacity must be **running** — resume it (Azure portal → your Fabric capacity → **Resume**). | -| The setup notebook errors on `%pip install` or the publish cell | Preview SDK drift — re-run the failed cell; if a method name differs, check the [SDK reference](https://learn.microsoft.com/fabric/data-science/fabric-data-agent-sdk). Make sure your F2 capacity is **running**. | -| **Fabric Data Agent** isn't in the tool catalogue (previewing ahead) | Your F2 capacity must be running, and the setup notebook must have **published** the agent. | +| Your **`FabricCapacityName`** isn't selectable when creating the workspace | The capacity must be **running** — resume it (Azure portal → your Fabric capacity → **Resume**). | +| The setup notebook errors on `%pip install` or the publish cell | Preview SDK drift — re-run the failed cell; if a method name differs, check the [SDK reference](https://learn.microsoft.com/fabric/data-science/fabric-data-agent-sdk). Make sure your Fabric capacity is **running**. | | The agent replies *"I'm unable to access the data source"* (or *"No tables selected yet"*) | Its tables aren't selected. The setup notebook selects all seven automatically, but if it didn't: open the data agent → **Data** tab → tick **all** tables under `InventoryLakehouse → dbo` → **Publish**, then re-test. | | Loading a `.parquet` file fails with a *load already in progress* error | Load the files **one at a time**. Open **Monitor** (left rail), **cancel** the still-running load activity, then retry that file into a new table. | | The agent returns nothing when you name a category (e.g. *"Outdoor Power Tools"*) | Category values are lowercase snake_case (`outdoor_power_tools`). Ask by the exact value or by **SKU/productId** (e.g. `P004`), and confirm the agent instructions include the category-mapping line from step 4(a)f / the setup notebook. | -| The publish cell raises **`No tables were selected (schema may still be syncing)`** | Expected on a **cold F2** — the 7 tables wrote fine, but the Lakehouse **SQL analytics endpoint** hasn't exposed them yet. Open `InventoryLakehouse` → **SQL analytics endpoint** → confirm all 7 tables under `dbo`, then **re-run the publish cell** (idempotent) or tick the tables in the data agent's **Explorer** and **Publish**. | +| The publish cell raises **`No tables were selected (schema may still be syncing)`** | Expected on a **cold capacity** — the 7 tables wrote fine, but the Lakehouse **SQL analytics endpoint** hasn't exposed them yet. Open `InventoryLakehouse` → **SQL analytics endpoint** → confirm all 7 tables under `dbo`, then **re-run the publish cell** (idempotent) or tick the tables in the data agent's **Explorer** and **Publish**. | | Ticking tables in the data agent shows **`Error updating data agent data source selection(s)`** | Same root cause — the SQL endpoint schema isn't fully synced. Wait until all 7 tables show under the Lakehouse's **SQL analytics endpoint**, **refresh** the data agent page (F5), then re-tick and **Publish**. If it persists, remove and re-add the `InventoryLakehouse` data source (**+ Add data source → OneLake catalog**), tick the 7 tables, and **Publish**. | -| The agent answers in the **Test data agent** pane but a Foundry agent later errors **`Stage configuration not found`** | The test pane runs the **draft/Preview** runtime; Foundry consumes the **published** version. On a cold F2 the notebook's publish can leave the agent in draft. Open `inventory-hack-agent` → confirm all 7 tables → click **Publish**, then retry. | +| The agent answers in the **Test data agent** pane but a Foundry agent later errors **`Stage configuration not found`** | The test pane runs the **draft/Preview** runtime; Foundry consumes the **published** version. On a cold capacity the notebook's publish can leave the agent in draft. Open `inventory-hack-agent` → confirm all 7 tables → click **Publish**, then retry. | ![The data agent's Data tab showing InventoryLakehouse tables unselected and the agent replying that it cannot access the data source](../images/challenge-00-no-tables.png) ## 🚀 Go further - Sketch the three-agent flow from memory and label which tool each agent uses and why. -- In the playground, ask the agent *“What data can you see?”* and compare its answer to the table list above. +- In the playground, ask the agent this and compare its answer to the table list above: + + ```text + What data can you see? + ``` - Predict which tables Challenge 3 and Challenge 4 will lean on before you get there. ## 🧠 Reflection diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-02.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-02.md index 55abb8c9f..d8fd98b1c 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-02.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-02.md @@ -8,7 +8,7 @@ Build your first Foundry prompt agent. Configure it with two tools — **Web Sea ## 🧭 Context -Your facilitator will announce a scenario at the start of this challenge — for example: +Use this scenario throughout the challenge: > *"A prolonged heatwave and early spring across the Pacific Northwest is driving a surge in demand for garden and outdoor power equipment. Retailer search trends and social media show spikes for leaf blowers and lawn tools. Our planning team needs to know if current stock levels can absorb this demand or if we are already exposed."* @@ -59,28 +59,16 @@ Your agent must sense this signal from the web, query the governed inventory dat ![New agent editor showing the name, gpt-5.4-mini model selection, and instructions field](../images/challenge-01-new-agent.png) -### Part B — Add the Web Search tool (optional, 10 min) +### Part B — Confirm the Web Search tool (5 min) -> [!NOTE] -> Web Search is **optional**. It enriches the demand signal with live external context, but if it is not enabled in your project, skip this part — the Fabric Data Agent alone still completes the challenge (the `ExternalSignals` table carries pre-loaded market signals). - -1. In the agent editor, click **+ Add tool**. -2. Select **Web Search** from the tool catalogue. -3. Leave the default configuration — no API key required for the built-in preview tool. -4. Click **Save**. +**Web Search** is added to prompt agents by default and needs no configuration — it grounds the demand signal in live external context (news, market trends). Confirm it's listed under **Tools** in the agent editor. If it isn't there, add it via **+ Add tool → Web Search** (no API key required), then **Save**. ![Tool catalogue in the agent editor showing Web Search and Fabric Data Agent available to add](../images/challenge-01-add-tool.png) -> [!TIP] -> **Web Search not appearing in the catalogue?** It is in Public Preview and may need project-level enablement — ask your facilitator, or simply skip it and continue with the Fabric Data Agent. - ### Part C — Add the Fabric Data Agent tool (10 min) This is the first agent where you attach the Fabric Data Agent, so you'll **create** the `inventory-hack-agent` connection here using the two IDs from Challenge 1. Every later challenge just selects it. -> [!IMPORTANT] -> **Use the *Fabric Data Agent* connector — not auto-suggested function tools.** When you create an agent from instructions, the New Foundry portal may **auto-generate custom `fx` function stubs** (e.g. `query_inventory`, `list_low_stock`, `get_external_signals`). These are **empty placeholders** — they don't reach your Lakehouse, so the agent replies that it *"can't verify inventory"* even with perfect instructions. **Delete any such `fx` functions** (each tool row → **⋮ → Remove**) and add the **Fabric Data Agent** tool as below instead. - 1. In the agent editor, expand **Tools** and select **Add**. 2. Choose **Fabric Data Agent** from the tool catalogue. 3. Create the connection with the two IDs your **setup notebook printed in Challenge 1**: @@ -92,7 +80,7 @@ This is the first agent where you attach the Fabric Data Agent, so you'll **crea ![The Add tool → Fabric Data Agent connection dialog with the Workspace ID and Artifact ID fields, named inventory-hack-agent](../images/challenge-01-new-connection.png) > [!TIP] -> **No "Fabric Data Agent" in the catalogue?** Your F2 capacity must be running (Azure portal → your Fabric capacity → **Resume**) and the setup notebook must have published the agent. +> **No "Fabric Data Agent" in the catalogue?** Your Fabric capacity must be running (Azure portal → your Fabric capacity → **Resume**) and the setup notebook must have published the agent. > [!NOTE] > **Why two tools?** Web Search gives the agent access to what is happening *outside* the business. The Fabric Data Agent gives access to what is happening *inside* — including the `ExternalSignals` table of pre-loaded market signals. Combining live web context with governed internal data is the core pattern of this hack. @@ -100,7 +88,11 @@ This is the first agent where you attach the Fabric Data Agent, so you'll **crea ### Part D — Test the agent (20 min) 1. Open the **Agents playground** (click **Test in playground**). -2. Send the facilitator's scenario as your first message. +2. Send this scenario as your first message: + + ```text + A prolonged heatwave and early spring across the Pacific Northwest is driving a surge in demand for garden and outdoor power equipment. Retailer search trends and social media show spikes for leaf blowers and lawn tools. Our planning team needs to know if current stock levels can absorb this demand or if we are already exposed. + ``` 3. Observe the agent's response — look for: - At least one web source cited with a URL. - At least one inventory query result from Fabric (stock level or sales velocity). @@ -110,8 +102,16 @@ This is the first agent where you attach the Fabric Data Agent, so you'll **crea > [!TIP] > **Agent answered from web only and said it "couldn't verify inventory"?** It skipped the Fabric Data Agent call — `gpt-5.4-mini` is a reasoning model and occasionally skips an available tool. Recover it by replying: *"Call the Fabric Data Agent now and pull current stock and sales velocity for the affected SKUs (e.g. P004, P006) before giving your assessment."* If it keeps skipping, set **tool choice = required** in the agent's tool/run settings so a tool call is mandatory. The strengthened instructions above make this rare. -4. Ask a follow-up question: *"Which store or warehouse has the lowest stock of outdoor power tools relative to its reorder point?"* -5. Ask: *"What external signals in the last 30 days could affect demand for outdoor power tools in the Pacific Northwest?"* +4. Ask a follow-up question: + + ```text + Which store or warehouse has the lowest stock of outdoor power tools relative to its reorder point? + ``` +5. Ask: + + ```text + What external signals in the last 30 days could affect demand for outdoor power tools in the Pacific Northwest? + ``` ## 🏁 Success criteria @@ -124,18 +124,20 @@ This is the first agent where you attach the Fabric Data Agent, so you'll **crea | Symptom | Fix | |---------|-----| -| **Web Search** isn't in the tool catalogue | It's in Public Preview and may need project-level enablement — ask your facilitator, or skip it and rely on the `ExternalSignals` table via the Fabric Data Agent. | -| **Fabric Data Agent** isn't in the catalogue | The integration needs **your** F2 Fabric capacity to be running — resume it (Azure portal → your Fabric capacity → **Resume**) and confirm the setup notebook published the agent. | +| **Web Search** isn't listed on the agent | Add it via **+ Add tool → Web Search** — it needs no extra configuration. | +| **Fabric Data Agent** isn't in the catalogue | The integration needs **your** Fabric capacity to be running — resume it (Azure portal → your Fabric capacity → **Resume**) and confirm the setup notebook published the agent. | | The agent answers inventory questions from memory | Strengthen the *IMPORTANT – tool use* line in the instructions; it must call the Fabric Data Agent for any stock number. | | The agent gives a demand assessment from web signals only (says it *"couldn't verify inventory"*) | It skipped the Fabric call. Reply *"Call the Fabric Data Agent now for current stock + sales velocity of the affected SKUs before assessing,"* or set **tool choice = required** in the agent's tool settings. `gpt-5.4-mini` (a reasoning model) sometimes skips available tools. | | The agent has `fx` functions like `query_inventory` / `list_low_stock` instead of the Fabric Data Agent | The portal **auto-generated stub functions** from your instructions — they're empty and never reach your Lakehouse. Remove them (each tool row → **⋮ → Remove**) and add the **Fabric Data Agent** connector (Part C). | +| You didn't copy the **Workspace ID / Agent ID** in Challenge 1 | Reopen `inventory-hack-agent` in Fabric → **Settings → Model Context Protocol → MCP server URL** (both IDs are in the URL), or re-run the setup notebook's last cell. | +| *"Your requests to gpt-5.4-mini … exceeded rate limit"* | You hit the model's tokens-per-minute (TPM) limit. Wait ~30–60s and retry, and avoid firing many runs back-to-back. Facilitators can raise the deployment TPM or give each attendee their own subscription (see [`labautomation/README.md`](../labautomation/README.md)). | | The run fails with **`Stage configuration not found`** (or *configuration not found*) | Your Fabric Data Agent works in Fabric's **Test data agent** pane but isn't **published** — the Foundry tool consumes the *published* stage, not the draft/Preview runtime. In Fabric, open `inventory-hack-agent` → confirm the 7 tables → click **Publish**, then retry. | | The connection dialog asks for IDs you don't have | Copy the **Workspace ID** and **Agent ID** your setup notebook printed in its last cell (Challenge 1). | ## 🚀 Go further - Ask the agent to rank **all** warehouses by demand exposure, not just the most exposed one. -- Add a second scenario (e.g. a supplier delay) and see whether the agent changes its assessment. +- **Stretch:** invent your own scenario (e.g. a supplier delay or a competitor stockout) and see whether the agent changes its assessment. - Have the agent state its confidence and list exactly which data points drove the conclusion. ## 🧠 Reflection diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-03.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-03.md index 728d13550..6f4a2be44 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-03.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-03.md @@ -59,25 +59,33 @@ Your Inventory Optimisation Agent answers these questions by querying the Fabric If you cannot find a SKU in the data, say so clearly - do not invent numbers. ``` -5. Add the **Fabric Data Agent** tool and select the existing **`inventory-hack-agent`** connection (created in Challenge 2). Do **not** add Web Search — this agent works only with internal data. - - > [!NOTE] - > If the portal auto-added custom `fx` function stubs (e.g. `query_inventory`), **remove them** and use only the **Fabric Data Agent** connector — see Challenge 2, Part C. -6. Click **Save**. +5. Add the **Fabric Data Agent** tool and select the existing **`inventory-hack-agent`** connection (created in Challenge 2). +6. **Remove the Web Search tool.** New prompt agents ship with **Web Search** attached by default, and `gpt-5.4-mini` will happily reach for it instead of the governed data. Under **Tools**, delete **Web Search** so the **only** tool is the Fabric Data Agent — this agent works from internal data only. +7. Click **Save**. ### Part B — Run the agent (15 min) 1. Open the **Agents playground**. 2. Paste the demand assessment you received in Challenge 2 as your first message. Copy it directly from your Challenge 2 playground chat, for example: - > *"Outdoor power tools are critically exposed. For SKU P004 at Portland and P006 at Seattle, query current stock, reorder point, and average weekly units sold, then return the reorder recommendation table (SKU, Location, Current Stock, Suggested Reorder Qty, Priority). Flag any SKU below its reorder point as CRITICAL."* + ```text + Outdoor power tools are critically exposed. For SKU P004 at Portland and P006 at Seattle, query current stock, reorder point, and average weekly units sold, then return the reorder recommendation table (SKU, Location, Current Stock, Suggested Reorder Qty, Priority). Flag any SKU below its reorder point as CRITICAL. + ``` > [!TIP] > **Phrasing matters — name the SKUs.** A purely prose prompt (e.g. *"leaf blowers and chainsaws are exposed"*) often makes the Fabric Data Agent generate a query that filters on a friendly category label and returns **nothing**. Naming the **SKUs/productIds** (e.g. `P004`, `P006`) and the exact fields you want — as in the example above — reliably returns data. If a prompt comes back empty, re-ask it by SKU. 3. The agent should query Fabric and return a recommendation table. -4. Ask a follow-up: *"Show me only the CRITICAL items."* -5. Ask: *"Can the Chicago warehouse cover Portland's shortfall with a transfer instead of a new purchase order?"* +4. Ask a follow-up: + + ```text + Show me only the CRITICAL items. + ``` +5. Ask: + + ```text + Can the Chicago warehouse cover Portland's shortfall with a transfer instead of a new purchase order? + ``` ![Playground showing a structured reorder recommendation table with a CRITICAL item flagged](../images/challenge-02-recommendation.png) @@ -116,7 +124,7 @@ Your Inventory Optimisation Agent answers these questions by querying the Fabric |---------|-----| | The run doesn't appear under **Traces** | Give it a few seconds and refresh; make sure you ran the agent from the playground, not just saved it. | | The agent invents stock numbers | Reinforce the *IMPORTANT – tool use* instruction — every inventory number must come from a Fabric Data Agent call. | -| The agent replies it can't reach Fabric / the tool call errors intermittently | Known preview flake. Start a **new playground session** and retry the same prompt (it usually succeeds within a try or two); confirm your F2 capacity is **running**. | +| The agent replies it can't reach Fabric / the tool call errors intermittently | Known preview flake. Start a **new playground session** and retry the same prompt (it usually succeeds within a try or two); confirm your Fabric capacity is **running**. | | A prompt returns no data (empty table) | The generated query likely filtered on a friendly category label. Re-ask by **SKU/productId** (e.g. `P004`) and name the exact fields; ensure the Data Agent instructions include the snake_case category-mapping line from Challenge 1. | | No item is flagged **CRITICAL** | Use a scenario/SKU that is genuinely below reorder point (e.g. leaf blowers at Portland/Seattle), or ask the agent to list items below their reorder point. | | The reorder quantity looks wrong | Check the trace — confirm the agent used `average_daily_sales × 30 − current_stock` and pulled real numbers from Fabric. | diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-04.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-04.md index 4a1ecab65..9ff552836 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-04.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-04.md @@ -75,14 +75,11 @@ This human-in-the-loop pattern is critical for **agentic AI in enterprise settin The "act" step — submitting the purchase order — is **simulated by the agent itself**. In the current **New Foundry** portal, prompt agents don't expose a no-code custom-function tool: the tool catalogue's **Custom** tab offers only **OpenAPI**, **MCP**, and **Agent2Agent (A2A)** connectors, which all require a hosted endpoint. Because the Fabric Data Agent is **read-only**, the agent closes the loop by *generating* a submission confirmation on approval — which delivers the exact human-in-the-loop teaching point with zero infrastructure. -You only need one tool here: +You need exactly **one** tool here — the Fabric Data Agent — so you must also remove the Web Search tool that new prompt agents ship with by default: -1. In the agent editor, expand **Tools** and select **Add**. -2. On the **Configured** tab, choose **Fabric Data Agent** and connect the existing **`inventory-hack-agent`** connection — the agent needs it to look up unit costs from the `Products` table when building the PO. -3. Select **Add tool**, then **Save**. - -> [!NOTE] -> If the portal auto-added custom `fx` function stubs (e.g. `query_inventory`), **remove them** and use only the **Fabric Data Agent** connector — see Challenge 2, Part C. +1. In the agent editor, expand **Tools**. New prompt agents ship with **Web Search** attached by default — **delete it**, or `gpt-5.4-mini` will reach for the web instead of the governed cost data. +2. Select **Add**, and on the **Configured** tab choose **Fabric Data Agent** and connect the existing **`inventory-hack-agent`** connection — the agent needs it to look up unit costs from the `Products` table when building the PO. +3. Select **Add tool**, then **Save**. Confirm the **only** tool left is the Fabric Data Agent. > [!NOTE] > **Want a *real* submit action?** In production you'd add an **OpenAPI tool** (New Foundry) or a custom function that writes to the `ReplenishmentOrders` table / your ERP. That needs a hosted endpoint, so it's out of scope for this no-code lab — see **Part E — Stretch** at the end of this challenge. @@ -93,7 +90,15 @@ You only need one tool here: > This is the payoff: running the full sense → plan → approve → act cycle in one session. 1. Open a **new chat** in the Agents playground with `replenishment-action-agent`. -2. Paste the recommendation table from Challenge 3 as your first message. +2. Paste the recommendation table from Challenge 3 as your first message. If you don't have it handy, use this sample: + + ```text + | SKU | Location | Current Stock | Suggested Reorder Qty | Priority | + |------|----------|---------------|-----------------------|----------| + | P004 | Seattle | 6 | 18 | CRITICAL | + | P004 | Portland | 8 | 16 | CRITICAL | + | P006 | Portland | 12 | 8 | CRITICAL | + ``` 3. The agent should present a formatted purchase order proposal. 4. **Test the approval flow:** - First, reply `MODIFY 1 50` — adjust the first line quantity. Verify the agent updates and re-presents the order. @@ -130,7 +135,7 @@ Either path turns the simulated confirmation into a genuine side effect while ke ## 🏁 Success criteria -- [ ] The `replenishment-action-agent` prompt agent exists on `gpt-5.4-mini` with the Fabric Data Agent tool attached. +- [ ] The `replenishment-action-agent` prompt agent exists on `gpt-5.4-mini` with the Fabric Data Agent tool attached (and the default Web Search tool removed). - [ ] A test run successfully presents a formatted purchase order proposal (per-line cost table with a total). - [ ] The MODIFY flow works correctly — the agent updates the specified line, recalculates the total, and re-presents. - [ ] A YES reply produces the simulated submission confirmation (`✅ Purchase order PO-... submitted`). diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-05.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-05.md index 8081cee4f..9cb3ebeac 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-05.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/challenges/challenge-05.md @@ -7,7 +7,7 @@ ## 🎯 Objective -Wire your three agents together in a Foundry **Workflow** so the entire sense → plan → approve → act loop runs from one prompt. You'll use the visual workflow designer to chain the agents in sequence with a human-approval gate, then read the trace to see each node execute. This is Microsoft's sanctioned replacement for the older "connected agents" tool and the pattern behind real multi-agent systems. +Wire your three agents together in a Foundry **Workflow** so the entire sense → plan → approve → act loop runs from one prompt. You'll use the visual workflow designer to chain the agents in sequence with a human-approval gate, then read the trace to see each node execute — the pattern behind real multi-agent systems. ## 🧭 Context @@ -18,11 +18,11 @@ The planning team doesn't want to talk to three separate agents. They want to ty ### Part A — Create the workflow (15 min) > [!NOTE] -> The classic **connected agents** tool (adding one agent as another's tool) is **not available** in the New Foundry portal — Microsoft replaced it with **Workflows** for multi-agent orchestration. The visual workflow designer is in preview and is supported in-portal until **1 December 2026**, after which you run the same logic by exporting the workflow **YAML** and deploying it as a hosted agent (see Learning resources). For this hack's timeframe the visual designer is the fastest no-code path. +> The visual workflow designer is in preview and is supported in-portal until **1 December 2026**, after which you run the same logic by exporting the workflow **YAML** and deploying it as a hosted agent (see Learning resources). For this hack's timeframe the visual designer is the fastest no-code path. 1. In the Foundry portal, go to **Agents → Workflows → + New workflow** (or **Create**). -2. Choose the **Sequential** template (it pre-wires a Start node you can extend). If you start from **Blank**, you'll add the Start node yourself. -3. Name it `inventory-planning-workflow` and open the **Build** canvas (Visualizer view). +2. Choose the **Blank** workflow — it already includes a **Start** node you extend. +3. Open the **Build** canvas (Visualizer view). You'll name it `inventory-planning-workflow` when you **Save** in Part B. ### Part B — Add and wire the three agent nodes (20 min) @@ -54,10 +54,12 @@ You'll chain the three specialist agents you built in Challenges 2–4. **You do ### Part C — Run the full loop from one prompt (20 min) -1. Click **Preview** (or **Run**) to open the workflow playground. +1. Click **Preview** to open the workflow playground. 2. Send a single request, e.g.: - > *"A prolonged heatwave is hitting the Pacific Northwest. Check our exposure on outdoor power tools and prepare a replenishment order for approval."* + ```text + A prolonged heatwave is hitting the Pacific Northwest. Check our exposure on outdoor power tools and prepare a replenishment order for approval. + ``` 3. Watch the nodes execute in order: demand sensing → optimisation → replenishment. When the replenishment node presents the PO proposal, reply `YES` (or `MODIFY `). 4. Open **Traces** and find the run. Confirm you can see the **node-by-node execution** — each agent node's model call with its **Fabric Data Agent** tool call underneath, and the human approval turn on the replenishment node. @@ -83,22 +85,24 @@ If you want a second stretch (or the visual designer is unavailable), evaluate o > [!NOTE] > This part is a **look-ahead showcase**, not a required lab step. You don't need to publish anything to finish the hack — it's here to show where a working workflow goes next and what a business rollout looks like. -Everything so far lives in the Foundry portal — great for builders, but the **planners who actually place orders live in Teams**. Publishing the workflow to **Microsoft 365 Copilot & Teams** would let a non-technical user run the whole sense → plan → approve → act loop by typing one sentence in a Teams chat, and approve the PO right there. +Everything so far lives in the Foundry portal — great for builders, but the **planners who actually place orders live in Teams**. Publishing an agent to **Microsoft 365 Copilot & Teams** lets a non-technical user chat with it right inside a Teams conversation. -> [!NOTE] -> Publishing to Microsoft 365 Copilot and Teams is an **Early Access Preview**. Org-wide publishing needs a **Microsoft 365 admin** to approve the agent — so if you *do* try it, use the **Just you** scope, which is available immediately with no approval. +> [!IMPORTANT] +> **Publish a *prompt agent*, not the workflow.** Teams / Microsoft 365 publishing supports only **prompt and hosted agents** — a **workflow** can't be chatted through the published endpoint (you'll get *"Agent kind 'workflow' is not supported"*). For this showcase, publish one of your prompt agents (e.g. **`demand-sensing-agent`**). Org-wide publishing needs a **Microsoft 365 admin** to approve the agent, so use the **Just you** scope — available immediately with no approval. -1. Open your published `inventory-planning-workflow` (or any of the agents), select **Publish → Publish to Teams and Microsoft 365 Copilot**. Foundry provisions an **Azure Bot Service** resource behind the scenes. +1. Open your **`demand-sensing-agent`** (a prompt agent) and select **Publish → Publish to Teams and Microsoft 365 Copilot**. Foundry provisions an **Azure Bot Service** resource behind the scenes. - ![The inventory-planning-workflow with the Publish menu open, showing the Teams & Microsoft 365 Copilot publish target](../images/challenge-04-teams.png) -2. Fill in the metadata: **Name** (e.g. *Inventory Planning Assistant*), **Publish version** `1.0.0`, a one-line **Short description**, a longer **Description**, and your **Developer** name. + ![A prompt agent with the Publish menu open, showing the Teams & Microsoft 365 Copilot publish target](../images/challenge-04-teams.png) +2. Fill in the metadata: **Name** (e.g. *Inventory Planning Assistant*), **Publish version** `1.0.0`, **Short description** (e.g. *"Senses demand signals and checks inventory exposure over governed data."*), a longer **Description** (e.g. *"Chats over governed Zava inventory data to sense demand and report whether stock is adequate, at risk, or critically exposed."*), and your **Developer** name (your name or team). > Don't put secrets/keys in any field — this metadata is user-visible. 3. Select **Next: Publish options → Direct publish**, choose **Just you** under *Choose who can use this agent*, then **Publish**. (Org-wide = *People in your organization* → M365 admin approval → appears under **Built by your org** in the agent store.) -4. In **Microsoft 365 Copilot** or **Teams**, open the **agent store → Your agents**, pick your agent, and chat like a business user: +4. Open **Microsoft 365 Copilot** ([m365.cloud.microsoft](https://m365.cloud.microsoft)) or **Teams** ([teams.microsoft.com](https://teams.microsoft.com)) — **sign in with the same lab user** you used in Foundry, not your corporate account — then open the **agent store → Your agents**, pick your agent, and chat like a business user: - > *"A heatwave is hitting the Pacific Northwest — check our outdoor power tool exposure and prepare a replenishment order for approval."* + ```text + A heatwave is hitting the Pacific Northwest — check our outdoor power tool exposure and tell me whether we're covered or exposed. + ``` -5. Watch the loop run inside the Teams chat and reply `YES` at the approval gate — no portal, no code. +5. The agent responds in the Teams chat, grounded in your Fabric data — no portal, no code. *(Running the full sense → plan → approve loop as one Teams conversation needs the **workflow** published, which isn't supported yet — see the note above.)* **Discuss:** what governance would you add before letting hundreds of planners trigger real purchase orders from Teams? (Think: the approval gate, a spend cap, `BotServiceRbac` vs `BotServiceTenant` calling scope, and audit via the trace.) @@ -106,7 +110,7 @@ Everything so far lives in the Foundry portal — great for builders, but the ** | Symptom | Fix | |---------|-----| -| There's no **connected agents** tool | Correct — the New Foundry portal replaced it with **Workflows**. Use the visual workflow designer as described above. | +| Chatting a published **workflow** in Teams/M365 fails: *"Agent kind 'workflow' is not supported"* | Teams / Microsoft 365 publishing supports only **prompt and hosted agents**. Publish a **prompt agent** (e.g. `demand-sensing-agent`) instead — see Part E. | | The replenishment node never stops looping | The **Loop condition** `Find` is **case-sensitive** — keep the Challenge 4 confirmation wording (`submitted to ERP`, `Order cancelled`) exactly. | | A node doesn't receive the previous agent's output | Set **Save agent output message as** on the upstream node and reference that variable in the next node's **Input message**. | | The visual designer isn't available | Do the **Part D** evaluation bonus instead, or export the workflow **YAML** and run it as a hosted agent (see Learning resources). | @@ -114,7 +118,7 @@ Everything so far lives in the Foundry portal — great for builders, but the ** ## 🚀 Go further - Do the **Part D** evaluation pass to score `inventory-optimisation-agent` on groundedness and relevance. -- Follow the **Part E** showcase to publish the workflow to **Teams & Microsoft 365 Copilot** (use the *Just you* scope). +- Follow the **Part E** showcase to publish a **prompt agent** to **Teams & Microsoft 365 Copilot** (use the *Just you* scope). - Swap the **Sequential** template for **Group chat** and observe how dynamic hand-off changes the run. ## 🧠 Reflection diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/dev/run-local.ps1 b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/dev/run-local.ps1 index 11fe3c3e9..11869df1b 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/dev/run-local.ps1 +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/dev/run-local.ps1 @@ -5,7 +5,7 @@ # # Prereqs: Connect-AzAccount (Az) AND az login (CLI) to the SAME subscription. # deploy-lab.ps1 provisions the signed-in user's Foundry project + their own Fabric -# F2 capacity; you then build your workspace + Data Agent by running +# Fabric capacity; you then build your workspace + Data Agent by running # setup/Setup-InventoryDataAgent.ipynb (see Challenge 1). param( diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/images/README.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/images/README.md index ede45bcc4..6e1ce9d65 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/images/README.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/images/README.md @@ -11,7 +11,7 @@ This folder holds the screenshots embedded throughout the challenge guides and w | `challenge-00-model-deployments.png` | 0 | Foundry **Models + endpoints** with `gpt-5.4-mini` deployed, status **Succeeded**. | | `challenge-00-playground-what-can-you-do.png` | 0 | Agents playground grounding test — *"What can you do?"* and the agent's reply. | | `challenge-00-new-workspace-button.png` | 0 | Fabric left navigation with **Workspaces** open and the **+ New workspace** button highlighted. | -| `challenge-00-create-workspace.png` | 0 | The Fabric **Create a workspace** dialog: **Advanced** expanded, **Workspace type: Fabric**, and the attendee's `invcap…` F2 capacity selected under **Details**. | +| `challenge-00-create-workspace.png` | 0 | The Fabric **Create a workspace** dialog: **Advanced** expanded, **Workspace type: Fabric**, and the attendee's `invcap…` Fabric capacity selected under **Details**. | | `challenge-00-new-lakehouse.png` | 0 | The **+ New item** panel filtered to *"lake"* with the **Lakehouse** tile selected, inside the `inventory-hack` workspace. | | `challenge-00-lakehouse-name.png` | 0 | The **New Lakehouse** dialog with the name **`InventoryLakehouse`** and Location `inventory-hack`. | | `challenge-00-import-notebook.png` | 0 | The workspace **Import → Notebook → From this computer** menu, for `Setup-InventoryDataAgent.ipynb`. | diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/README.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/README.md index 514633b78..523387b79 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/README.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/README.md @@ -1,6 +1,6 @@ # Lab Automation — Agentic Inventory Planning MicroHack -Everything for this hack is provisioned per attendee by [`deploy-lab.ps1`](deploy-lab.ps1) — there is **no shared Fabric backend**. Each attendee gets their own Foundry project **and** their own Fabric F2 capacity, then builds their own Fabric workspace + Data Agent by running [`Setup-InventoryDataAgent.ipynb`](../setup/Setup-InventoryDataAgent.ipynb) in Challenge 1. +Everything for this hack is provisioned per attendee by [`deploy-lab.ps1`](deploy-lab.ps1) — there is **no shared Fabric backend**. Each attendee gets their own Foundry project **and** their own Fabric F4 capacity, then builds their own Fabric workspace + Data Agent by running [`Setup-InventoryDataAgent.ipynb`](../setup/Setup-InventoryDataAgent.ipynb) in Challenge 1. ## What `deploy-lab.ps1` provisions (per attendee) @@ -9,13 +9,14 @@ Everything for this hack is provisioned per attendee by [`deploy-lab.ps1`](deplo | Azure AI Foundry account | `Microsoft.CognitiveServices/accounts` | One per attendee (AIServices kind) | | Foundry project | `…/projects/inventory-hack` | System-assigned managed identity; provisioning is verified before the lab continues | | gpt-5.4-mini model deployment | GlobalStandard, 200K TPM | Used by all three hack agents | -| Fabric capacity (default **F2**) | `Microsoft.Fabric/capacities` | One per attendee; attendee set as **capacity admin**. SKU via `-FabricSkuName` (F2 default; use F4 if attendees hit throttling). | +| Fabric capacity (default **F4**) | `Microsoft.Fabric/capacities` | One per attendee; attendee set as **capacity admin**. SKU via `-FabricSkuName` (F4 default; drop to F2 to halve cost if attendees don't hit throttling). | +| Application Insights (+ Log Analytics) | `Microsoft.Insights/components` + `Microsoft.OperationalInsights/workspaces` | Connected to the project as an `AppInsights` connection so the **Traces** tab works in Challenges 3–5 with no manual setup. Non-fatal if it fails. | -The script grants the **Foundry User** role to each attendee and to the Foundry project's managed identity at the Foundry account scope. It also sets each attendee as **admin of their own F2 capacity** (resolving their Entra object ID to a UPN via the platform `Get-MhhLabUser` helper), so they can create a workspace, assign it to the capacity, and publish their own Data Agent — no shared state, no cross-attendee contention. +The script grants the **Foundry User** role to each attendee and to the Foundry project's managed identity at the Foundry account scope. It also sets each attendee as **admin of their own F4 capacity** (resolving their Entra object ID to a UPN via the platform `Get-MhhLabUser` helper), so they can create a workspace, assign it to the capacity, and publish their own Data Agent — no shared state, no cross-attendee contention. ## What the attendee does themselves (Challenge 1) -1. Create a Fabric **workspace** and assign it to their **F2 capacity** (`FabricCapacityName`). +1. Create a Fabric **workspace** and assign it to their **F4 capacity** (`FabricCapacityName`). 2. Create a Lakehouse named **`InventoryLakehouse`** and attach it to the notebook. 3. Import and **Run All** [`Setup-InventoryDataAgent.ipynb`](../setup/Setup-InventoryDataAgent.ipynb) — it loads its **embedded** seed data, writes 7 tables, publishes their **`inventory-hack-agent`** Data Agent, and prints **their** Workspace ID + Agent ID. 4. Use those two IDs when adding the Fabric Data Agent tool to their Foundry agent (Challenge 2). @@ -27,7 +28,7 @@ The script grants the **Foundry User** role to each attendee and to the Foundry | `FoundryProjectUrl` | Clickable deep-link to the attendee's `inventory-hack` project in the Foundry portal (`ai.azure.com`) — where they build the agents in Challenges 2-5 | | `FoundryProjectEndpoint` | `https://.services.ai.azure.com/api/projects/inventory-hack` (SDK/API endpoint; optional — the hack is done in the portal) | | `ModelDeploymentName` | `gpt-5.4-mini` | -| `FabricCapacityName` | The attendee's own F2 capacity (assign your workspace to it in Challenge 1) | +| `FabricCapacityName` | The attendee's own F4 capacity (assign your workspace to it in Challenge 1) | | `FabricPortalUrl` | Link to the Fabric portal (`app.fabric.microsoft.com`) to create the workspace on `FabricCapacityName` — the workspace URL itself only exists once the attendee creates it in Challenge 1 | | `ResourceGroupName` | The attendee's resource group | @@ -38,15 +39,16 @@ Attendees use these in the Foundry and Fabric portals — no SDK or code require - The deploying identity (the platform **service principal**) needs **Owner** on each attendee resource group so it can create resources and assign the **Foundry User** role to the attendee and project managed identity — the platform grants this automatically for `resourcegroup` deployments. - **`groups: ["M365-E5-Users"]`** in [`lab-defaults.json`](lab-defaults.json) — each attendee's lab Entra user gets a **Microsoft 365 E5** license (includes **Power BI Pro**), which is what lets them sign into the Fabric portal ([app.fabric.microsoft.com](https://app.fabric.microsoft.com)) and create a workspace. Without a Fabric/Power BI license the attendee cannot open the portal. - **The lab tenant must have Fabric enabled** — a Fabric **tenant-admin** setting (*“Users can create Fabric items”* / workspaces). This is **not** settable via `lab-defaults.json`; the tenant administrator for the lab tenant must turn it on, or attendees cannot create a workspace even with a license. -- **Fabric F-SKU quota** in a preferred region (F2 = 2 CU → ~256 attendees per 512-CU subscription; F4 = 4 CU halves that). `swedencentral` and `norwayeast` are good defaults. +- **Fabric F-SKU quota** in a preferred region (F4 = 4 CU → ~128 attendees per 512-CU subscription; drop to F2 = 2 CU to double that). `swedencentral` and `norwayeast` are good defaults. - **Model TPM vs. subscription packing** — each attendee's `gpt-5.4-mini` deploys at **200K TPM** (GlobalStandard capacity 200) and [`lab-defaults.json`](lab-defaults.json) packs **`labsPerSubscription: 5`** (5 × 200 = 1,000, right at the ~1,000 GlobalStandard quota ceiling per region). If attendees hit token rate limits, request a GlobalStandard quota increase or use **one subscription per attendee**. -- The **`Microsoft.Fabric`** resource provider is registered on the subscription (the script registers it if needed). +- The **`Microsoft.Fabric`**, **`Microsoft.Insights`**, and **`Microsoft.OperationalInsights`** resource providers are registered on the subscription (the script registers them if needed). > [!NOTE] > Attendee object IDs → UPNs are resolved with the platform **`Get-MhhLabUser`** helper (served from a platform-seeded cache), so the service principal does **not** need Microsoft Graph directory-read permission. ## Cost estimate -- **Fabric capacity** (default **F2**, ~$0.36/hr pay-as-you-go) is the dominant cost — roughly **$8–9/attendee/day** if left running. Attendees (or facilitators) should **suspend** the capacity when idle. Bumping to **F4** (`-FabricSkuName F4`, or a live **on-demand resize** when throttling appears) roughly **doubles** this — update `estimatedDailyCostsUsd` in [`lab-defaults.json`](lab-defaults.json) accordingly. +- **Fabric capacity** (default **F4**, ~$0.72/hr pay-as-you-go) is the dominant cost — roughly **$16–17/attendee/day** if left running. Attendees (or facilitators) should **suspend** the capacity when idle. Dropping to **F2** (`-FabricSkuName F2`) roughly **halves** this — update `estimatedDailyCostsUsd` in [`lab-defaults.json`](lab-defaults.json) accordingly. - gpt-5.4-mini (GlobalStandard, 200K TPM) — a few cents of tokens per attendee across the hack's ~50 agent calls; Foundry account base ~$2/day. -- Total ≈ **$9/attendee/day** — reflected in [`lab-defaults.json`](lab-defaults.json) (`estimatedDailyCostsUsd`). +- **Application Insights + Log Analytics** — trace ingestion for the hack's ~50 agent calls is a few MB; effectively **negligible** (well within the Log Analytics free ingestion allowance). +- Total ≈ **$18/attendee/day** — reflected in [`lab-defaults.json`](lab-defaults.json) (`estimatedDailyCostsUsd`). diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/deploy-lab.ps1 b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/deploy-lab.ps1 index 54e344a9e..125f79ed3 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/deploy-lab.ps1 +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/deploy-lab.ps1 @@ -9,7 +9,8 @@ - Azure AI Services account (AIServices kind — this is the Foundry account) - Azure AI Foundry project inside the account - gpt-5.4-mini model deployment (capacity 200 GlobalStandard = 200K TPM) - - A per-attendee Fabric capacity (default F2; -FabricSkuName to override), with the attendee set as capacity admin + - A per-attendee Fabric capacity (default F4; -FabricSkuName to override), with the attendee set as capacity admin + - Application Insights (+ Log Analytics) connected to the project for agent tracing Each attendee gets their OWN Fabric capacity (no shared backend, no shared Spark contention). The attendee then creates a workspace, assigns it to their @@ -42,10 +43,10 @@ Entra user object IDs for this lab — passed in by the platform. .PARAMETER FabricSkuName - Per-attendee Fabric capacity SKU (default F2). Bump to F4 if attendees hit - capacity throttling. If you override it, ALSO raise estimatedDailyCostsUsd in - lab-defaults.json to match — Fabric is the dominant cost and each SKU step - roughly doubles it. + Per-attendee Fabric capacity SKU (default F4). Drop to F2 to halve cost if + attendees don't hit capacity throttling. If you change it, ALSO adjust + estimatedDailyCostsUsd in lab-defaults.json to match — Fabric is the dominant + cost and each SKU step roughly doubles it. #> param( [Parameter(Mandatory=$true)] @@ -61,12 +62,12 @@ param( [string[]]$AllowedEntraUserIds = @(), - # Per-attendee Fabric capacity SKU. Default F2 keeps cost low; bump to F4 if - # attendees hit capacity throttling. If you override this, ALSO raise - # estimatedDailyCostsUsd in lab-defaults.json (Fabric is the dominant cost; - # each SKU step roughly doubles it). + # Per-attendee Fabric capacity SKU. Default F4 avoids capacity throttling; drop + # to F2 to halve cost. If you change this, ALSO adjust estimatedDailyCostsUsd + # in lab-defaults.json (Fabric is the dominant cost; each SKU step roughly + # doubles it). [ValidateSet('F2','F4','F8','F16','F32','F64')] - [string]$FabricSkuName = "F2" + [string]$FabricSkuName = "F4" ) $scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition @@ -283,6 +284,63 @@ Grant-FoundryUserRole ` -PrincipalId $projectResource.identity.principalId ` -PrincipalDescription "project managed identity '$($projectResource.identity.principalId)'" +# --------------------------------------------------------------------------- +# Application Insights for agent tracing (per attendee). +# The Foundry portal Traces tab (and server-side tracing) only lights up once the +# project is connected to an Application Insights resource. We create a +# workspace-based App Insights and add it as an 'AppInsights' project connection so +# attendees see agent + Fabric Data Agent traces in Challenges 3-5 with no manual +# setup. Non-fatal: a failure here doesn't block the rest of the lab (attendees can +# still connect one via Agents -> Traces -> Connect). +# --------------------------------------------------------------------------- +try { + foreach ($ns in 'Microsoft.OperationalInsights', 'Microsoft.Insights') { + $prov = Invoke-AzRestMethod -Method GET -Path "/subscriptions/$SubscriptionId/providers/$ns`?api-version=2021-04-01" + if ($prov.StatusCode -eq 200 -and ($prov.Content | ConvertFrom-Json).registrationState -ne 'Registered') { + Invoke-AzRestMethod -Method POST -Path "/subscriptions/$SubscriptionId/providers/$ns/register?api-version=2021-04-01" | Out-Null + } + } + + $laName = "inv-la-$stableHash" + $aiName = "inv-appi-$stableHash" + $laId = "/subscriptions/$SubscriptionId/resourceGroups/$effectiveRG/providers/Microsoft.OperationalInsights/workspaces/$laName" + $aiId = "/subscriptions/$SubscriptionId/resourceGroups/$effectiveRG/providers/Microsoft.Insights/components/$aiName" + + $laBody = @{ location = $effectiveLocation; properties = @{ sku = @{ name = 'PerGB2018' }; retentionInDays = 30 } } | ConvertTo-Json -Depth 5 + $laResp = Invoke-AzRestMethod -Method PUT -Path "$laId`?api-version=2023-09-01" -Payload $laBody + if ($laResp.StatusCode -ge 400) { throw "Log Analytics workspace create failed (HTTP $($laResp.StatusCode)): $($laResp.Content)" } + + # Workspace-based App Insights (classic is retired); WorkspaceResourceId links it to the Log Analytics workspace. + $aiBody = @{ location = $effectiveLocation; kind = 'web'; properties = @{ Application_Type = 'web'; WorkspaceResourceId = $laId } } | ConvertTo-Json -Depth 5 + $aiResp = Invoke-AzRestMethod -Method PUT -Path "$aiId`?api-version=2020-02-02" -Payload $aiBody + if ($aiResp.StatusCode -ge 400) { throw "Application Insights create failed (HTTP $($aiResp.StatusCode)): $($aiResp.Content)" } + + # ConnectionString populates asynchronously — poll briefly. + $aiConnString = $null + for ($i = 0; $i -lt 6 -and -not $aiConnString; $i++) { + Start-Sleep -Seconds 5 + $aiConnString = ((Invoke-AzRestMethod -Method GET -Path "$aiId`?api-version=2020-02-02").Content | ConvertFrom-Json).properties.ConnectionString + } + if (-not $aiConnString) { throw "Application Insights connection string not available yet." } + + # Connect App Insights to the project (category 'AppInsights') — same as the portal's Traces -> Connect. + $aiConnUri = "/subscriptions/$SubscriptionId/resourceGroups/$effectiveRG/providers/Microsoft.CognitiveServices/accounts/$foundryAccountName/projects/$foundryProjectName/connections/appinsights?api-version=2025-04-01-preview" + $aiConnBody = @{ properties = @{ + category = 'AppInsights' + target = $aiId + authType = 'ApiKey' + isSharedToAll = $true + credentials = @{ key = $aiConnString } + metadata = @{ ApiType = 'Azure'; ResourceId = $aiId } + } } | ConvertTo-Json -Depth 6 + $aiConnResp = Invoke-AzRestMethod -Method PUT -Path $aiConnUri -Payload $aiConnBody + if ($aiConnResp.StatusCode -ge 400) { throw "App Insights project connection failed (HTTP $($aiConnResp.StatusCode)): $($aiConnResp.Content)" } + + Write-Host "[OK] Application Insights '$aiName' connected to the project for agent tracing." +} catch { + Write-Warning "Application Insights tracing setup skipped: $_ - attendees can still connect one manually (Agents -> Traces -> Connect)." +} + # --------------------------------------------------------------------------- # gpt-5.4-mini model deployment (ACCOUNT-scoped, GlobalStandard capacity 200). # Matches the pro-code inventory hack: a low-cost GPT-5 model whose Foundry model @@ -331,9 +389,9 @@ if ($existingDeploy.StatusCode -ne 200) { # Per-attendee Fabric capacity (ARM REST — no az CLI / Fabric extension needed). # The attendee is set as capacity ADMIN so they can create a workspace, assign it # to this capacity, and Run All the setup notebook themselves (Challenge 1). -# Default F2 = 2 CU; a 512-CU subscription supports ~256 attendees. F4 doubles CU -# (halving attendees/subscription) — override with -FabricSkuName and raise -# estimatedDailyCostsUsd in lab-defaults.json to match. +# Default F4 = 4 CU; a 512-CU subscription supports ~128 attendees. Drop to F2 (2 CU) +# to double attendees/subscription and halve cost — override with -FabricSkuName and +# adjust estimatedDailyCostsUsd in lab-defaults.json to match. # # Capacity admin members must be UPNs (or service principals) — bare object IDs are # rejected — so resolve each attendee object ID to a UPN with the platform helper @@ -438,7 +496,7 @@ Write-Host "[OK] Lab provisioning complete." @{ HackboxCredential = @{ name = "FabricCapacityName" value = $fabricCapacityName - note = "Your own Fabric F2 capacity. In Challenge 1 you create a workspace and assign it to this capacity, then Run All the setup notebook to publish your Data Agent." + note = "Your own Fabric $FabricSkuName capacity. In Challenge 1 you create a workspace and assign it to this capacity, then Run All the setup notebook to publish your Data Agent." } } @{ HackboxCredential = @{ diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/lab-defaults.json b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/lab-defaults.json index b5a19162f..14a3e650d 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/lab-defaults.json +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/labautomation/lab-defaults.json @@ -4,5 +4,5 @@ "deploymentType": "resourcegroup", "labsPerSubscription": 5, "preferredLocation": "swedencentral, westeurope, norwayeast", - "estimatedDailyCostsUsd": 9.0 + "estimatedDailyCostsUsd": 18.0 } diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/setup/Setup-InventoryDataAgent.ipynb b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/setup/Setup-InventoryDataAgent.ipynb index 1e3270367..664a3d565 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/setup/Setup-InventoryDataAgent.ipynb +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/setup/Setup-InventoryDataAgent.ipynb @@ -7,10 +7,10 @@ "source": [ "# Setup — your inventory data + Fabric Data Agent (run once)\n", "\n", - "Run this notebook **inside your own Fabric workspace** — the one you created and assigned to your F2 capacity (see Challenge 1).\n", + "Run this notebook **inside your own Fabric workspace** — the one you created and assigned to your Fabric capacity (see Challenge 1).\n", "\n", "**Prerequisites**\n", - "1. Your **F2 capacity** (`FabricCapacityName` from your lab dashboard) is **running**, and this workspace is assigned to it.\n", + "1. Your **Fabric capacity** (`FabricCapacityName` from your lab dashboard) is **running**, and this workspace is assigned to it.\n", "2. A Lakehouse named **`InventoryLakehouse`** exists in this workspace and is attached to this notebook (Explorer → **Add Lakehouse**).\n", "3. That's it — the seed data is **embedded in this notebook**, so there is no upload or download.\n", "\n", diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-02/solution-02.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-02/solution-02.md index 73ac84ddc..11b2da207 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-02/solution-02.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-02/solution-02.md @@ -18,7 +18,7 @@ Navigate to **Agents → + New agent**. If the portal shows a wizard, select **P | Symptom | Cause | Fix | |---------|-------|-----| -| Fabric tool call returns "unauthorized" | The Fabric Data Agent isn't published, or your F2 capacity is paused | You own this agent — confirm the setup notebook finished **publishing** it (Challenge 1) and that your F2 capacity is **running** (Azure portal → your Fabric capacity → **Resume**) | +| Fabric tool call returns "unauthorized" | The Fabric Data Agent isn't published, or your Fabric capacity is paused | You own this agent — confirm the setup notebook finished **publishing** it (Challenge 1) and that your Fabric capacity is **running** (Azure portal → your Fabric capacity → **Resume**) | | Web Search returns no results | Web Search tool not enabled in the project | Go to **Project settings** and verify Web Search is listed under enabled tools | | Agent ignores the Fabric tool (trace shows only Web Search, or it replies "I can't access your data") | `gpt-5.4-mini` is a GPT-5 reasoning model and may skip a tool it treats as optional; the portal may also flag the Fabric tool as "not supported" (cosmetic — it still runs via the Responses API) | Keep the **IMPORTANT - tool use** block in the instructions **and set tool choice = required** in the run settings so the Fabric Data Agent tool is always invoked. | diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-03/solution-03.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-03/solution-03.md index 2ec127110..3f296a254 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-03/solution-03.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-03/solution-03.md @@ -12,7 +12,7 @@ Build the Inventory Optimisation Agent and use agent tracing to inspect its reas ### Agent — key configuration point -This agent should have **only the Fabric Data Agent tool** — no Web Search. If attendees add Web Search, the agent may use it unnecessarily. The instructions say "governed data only" for a reason: optimisation decisions should be traceable to authoritative internal data, not unverified web content. +This agent should have **only the Fabric Data Agent tool** — no Web Search. New prompt agents ship with **Web Search attached by default**, so the key step is to **remove it**; otherwise `gpt-5.4-mini` tends to reach for the web instead of the governed data. The instructions say "governed data only" for a reason: optimisation decisions should be traceable to authoritative internal data, not unverified web content. ### Reading the trace — what to look for diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-04/solution-04.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-04/solution-04.md index b6ed496bc..f74aa05a8 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-04/solution-04.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-04/solution-04.md @@ -10,6 +10,10 @@ Build the Replenishment Action Agent, implement the human approval loop, and tra ## Solution walkthrough +### Tools — one tool, and remove the default Web Search + +This agent needs **only the Fabric Data Agent tool** (to look up unit costs from the `Products` table). New prompt agents ship with **Web Search attached by default** — **remove it**, or `gpt-5.4-mini` will reach for the web instead of the governed cost data. After configuring, confirm the Fabric Data Agent is the only tool listed. + ### Simulated submission (no function tool) The current **New Foundry** portal has no no-code custom-function tool — the Custom tab offers only OpenAPI, MCP, and A2A connectors, which all need a hosted endpoint. Because the Fabric Data Agent is read-only, the "act" step is **simulated by the agent**: on `YES`, its instructions have it generate a confirmation message (`✅ Purchase order PO-... submitted`). This keeps the lab fully no-code while still demonstrating the approve → act gate. In production you'd swap this for an OpenAPI tool that writes to the `ReplenishmentOrders` table / ERP (see Challenge 4, Part E). diff --git a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-05/solution-05.md b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-05/solution-05.md index 238fd2be1..4e3187297 100644 --- a/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-05/solution-05.md +++ b/03-Azure/01-04-AI/02_Inventory_Planning_Fabric/walkthrough/challenge-05/solution-05.md @@ -10,9 +10,9 @@ Chain the three agents in a Foundry **Workflow** (Sequential pattern + human-in- ## Solution walkthrough -### Why a workflow, not connected agents +### Why a workflow -The classic **connected agents** tool (one agent added as another's tool) is **not available** in the New Foundry portal — Microsoft replaced it with **Workflows** for multi-agent orchestration. A workflow is a *deterministic* graph: each agent is a **node**, and edges pass one node's output to the next. That's a better fit than an LLM-driven orchestrator for this hack's fixed sense → plan → approve → act chain, and it keeps everything no-code. +Use a Foundry **Workflow** for multi-agent orchestration. A workflow is a *deterministic* graph: each agent is a **node**, and edges pass one node's output to the next. That's a better fit than an LLM-driven orchestrator for this hack's fixed sense → plan → approve → act chain, and it keeps everything no-code. Wire the three specialists in order and name each node's output so the next node can consume it: - `demand-sensing-agent` → output `demandAssessment`