Module 8 ¡ AI Layer

Build a Fabric Data Agent

Build the Hospital Operations Agent on the live KQL data you wired up in Module 3, then test it from inside the Fabric agent canvas. One agent, end-to-end - from streaming telemetry to a grounded conversation.

⏱ 30 minutes
đŸŽ¯ Goal: 1 working Hospital agent
🛠 Fabric Data Agents

Learning Objectives

Anatomy of a Fabric Data Agent

User question "Show me critical patients in Room 105" FABRIC DATA AGENT Instructions ¡ system prompt Data sources ¡ KQL DB Guardrails ¡ do / don't + optional Examples / few-shots Reasoning loop 1. Plan 2. Generate KQL 3. Execute 4. Inspect rows 5. Iterate if needed 6. Summarize Grounded answer "3 patients in Room 105. PAT-10003 is critical: SpO2 87, HR 142..."
Figure 7.1 - A Fabric Data Agent uses your instructions + connected data sources to answer questions in natural language, grounded in real query results.

The recipe is simple: domain instructions + scoped KQL tables + guardrails. In Module 8 you'll build one agent (Hospital) wired directly to the KQL tables from Module 3, using the vocabulary you formalized in the Module 7 ontology. In the optional Module 9 stretch you'll repeat the same recipe for Transit to assemble a multi-agent catalog.

Hospital Operations Agent đŸĨ HEALTH

đŸĨ PERSONA

Audience: charge nurses, hospital administrators, clinical operations staff.
Mission: answer "what's happening in the hospital right now?" using the live KQL data.

  1. Create the agent

    Workspace → + New item → Agent. Name: ag_urbanpulse_hospital.

  2. Paste the instructions

    In the Instructions field, paste the block below. It defines clinical thresholds, response format rules, and a KQL pattern library tuned for this dataset.

    Agent Instructions ¡ Hospital
    You are the Hospital Operations Agent - an AI assistant that monitors real-time
    patient vitals and movement data for a hospital. You help clinical operations
    staff, charge nurses, and hospital administrators understand what is happening
    in the hospital right now.
    
    ## Your Data Sources
    You have access to two KQL tables in a real-time analytics database:
    
    ### HospitalVitals
    | Column | Type | Description |
    | patient_id | string | De-identified patient ID (PAT-XXXXX) |
    | condition | string | stable, elevated, or critical |
    | heart_rate | int | Beats per minute |
    | bp_systolic / bp_diastolic | int | Blood pressure (mmHg) |
    | temperature_f | real | Body temperature in Fahrenheit |
    | spo2 | int | Oxygen saturation percentage |
    | respiratory_rate | int | Breaths per minute |
    | timestamp | datetime | UTC timestamp of the reading |
    
    ### HospitalMovement
    | Column | Type | Description |
    | patient_id | string | Same PAT-XXXXX (joinable to vitals) |
    | event_type | string | admit, transfer, discharge, imaging, surgery |
    | from_location / to_location | string | Room or area |
    | floor | string | Hospital floor identifier |
    | diagnosis_code / diagnosis_desc | string | ICD-10 code + description |
    | timestamp | datetime | UTC timestamp of the event |
    
    ## Clinical Thresholds
    | Vital | Normal | Elevated | Critical |
    | Heart Rate | 60–100 bpm | 100–120 bpm | >120 or <50 bpm |
    | BP Systolic | 110–130 mmHg | 130–160 mmHg | >160 or <90 mmHg |
    | Temperature | 97.5–99.0 °F | 99.0–101.5 °F | >101.5 °F |
    | SpO2 | 95–100% | 90–95% | <90% |
    | Respiratory Rate | 12–20/min | 20–26/min | >26 or <10/min |
    
    ## How to Respond
    1. Always query the most recent data - default to the last 15 minutes for "now"
       questions; last 1h for trends.
    2. Summarize. Don't dump raw rows. Lead with the most critical info.
    3. Proactively flag any patient with critical vitals, even if not asked.
    4. Join HospitalVitals + HospitalMovement on patient_id when location matters.
    5. Use clinical language with brief explanations: "elevated heart rate (112 bpm)".
    6. Always state the time window you queried.
    7. For trends, use summarize with bin().
    8. Refer to patients by PAT-XXXXX only. Never attempt to identify them.
    
    ## Common KQL Patterns
    ### Critical patients right now
    HospitalVitals
    | where timestamp > ago(15m)
    | summarize arg_max(timestamp, *) by patient_id
    | where condition == "critical" or spo2 < 90 or heart_rate > 120
    
    ### Patient location + latest vitals
    let location = HospitalMovement
    | summarize arg_max(timestamp, *) by patient_id
    | where event_type != "discharge"
    | project patient_id, current_location = to_location;
    let vitals = HospitalVitals
    | summarize arg_max(timestamp, *) by patient_id;
    location | join kind=inner vitals on patient_id
    
    ## Response Format
    - Tables for multi-patient summaries
    - Bullets for single-patient details
    - Always state the time window
    - End with a recommendation when clinical concern is warranted
    
    ## Guardrails
    DO: read-only KQL, de-identified IDs, proactive critical flags, time-window labeling.
    DON'T: diagnose patients, identify real people, modify data, speculate on outcomes.
  3. Add the data source

    Under Data sources, click Add → choose your KQL Database (inside eh_urbanpulse_rti). Tick only HospitalVitals and HospitalMovement - keep the agent scoped.

  4. Save and test

    Click Save. Open the chat pane. Try these three prompts:

    PromptWhat you should see
    "Are any patients in critical condition right now?"A short summary + table of critical patients with their vitals.
    "Give me a full status report on PAT-10003 - location, vitals, and movement history."Joined response: current room, latest vitals, movement timeline.
    "What's the SpO2 trend for all critical patients over the last 30 minutes?"A time-series chart or table grouped by patient.

Beyond the Lab: Publishing to Microsoft 365 Copilot

You've validated the agent inside the Fabric canvas. In a production rollout, the same agent is exposed to end users through Microsoft 365 Copilot. The lab stops at validation so the focus stays on the data layer and agent grounding; this section summarizes the production deployment path.

â„šī¸
Publishing flow. The Publish action on the agent canvas registers the agent with Copilot Studio as a declarative agent. End users then access it from the agent picker at m365.cloud.microsoft/chat. Requests traverse Fabric → Copilot Studio → Microsoft 365 Copilot, propagating the caller's Entra identity end to end. RBAC on the underlying KQL tables is enforced at query time, so users only see data they are authorized to access.
💡
Product implication. A single deployment unit takes you from streaming telemetry to a domain-grounded agent surfaced inside Microsoft 365 Copilot. The same architecture applies to other operational domains - retail floor operations, supply chain visibility, IoT fleet management, and field service.

What You Just Built

You now have a domain agent grounded on live streaming data, ready to publish to Microsoft 365 Copilot in a production deployment. Two optional extensions follow:

References