Skip to main content

QRG Generation Deep Dive

This page is a self-contained developer reference for integrating with the QRG (Quick Reference Guide) generation API. It covers the full lifecycle from kickoff to result retrieval, including the 4-step AI processing pipeline, form processing rules, error handling, and cancellation.


Overview

The QRG generation system transforms Emergency Operation Plan (EOP) annex forms into role-specific Quick Reference Guides. Each QRG contains three phases of instructions -- BEFORE (preparation), DURING (response), and AFTER (recovery) -- tailored to a specific role such as Teacher, Administrator, or Support Staff.

A single EOP can produce dozens of QRGs. For example, an EOP with 5 annexes and 4 roles generates up to 20 QRGs (one per role per annex).

The workflow is asynchronous. A kickoff request returns immediately with tracking identifiers. Consumers poll for status and retrieve the result when processing completes.


Generation Lifecycle


Authentication

note

See Authentication and Setup for full details on obtaining credentials, token acquisition, and environment base URLs.

Every request requires three headers:

HeaderValue
AuthorizationBearer {access_token} (OAuth 2.0 client credentials)
Ocp-Apim-Subscription-Key{subscription_key}
Content-Typeapplication/json

All examples on this page use the Development base URL (https://dev-k12-aitools-t27p-apim.azure-api.net). Replace it with the appropriate URL for your target environment.


Kickoff

Start QRG generation by submitting an EOP identifier.

Endpoint: POST /ai/api/tools/k12-qrg-generation-kickoff/execute

Request Body

{
"data": {
"emergencyOperationPlanId": "d4e5f6a7-b8c9-0123-d456-e78901234567",
"generalUserTagIds": ["a1b2c3d4-e5f6-7890-abcd-100000000001", "a1b2c3d4-e5f6-7890-abcd-100000000002"],
"sessionId": null,
"waitForResult": false
}
}

Request Fields

FieldTypeRequiredDescription
emergencyOperationPlanIdstring (UUID)YesThe EOP to generate QRGs from
generalUserTagIdsarray of string (UUID)NoFilter generation to specific role tags. When omitted, all roles assigned to the EOP are used.
sessionIdstringNoCaller-provided session identifier for correlation. A new one is generated if null.
waitForResultbooleanNoWhen true, the response blocks until processing completes. Default: false.

Accepted Response

{
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"sessionId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"status": "accepted"
}

curl Example

curl -X POST "https://dev-k12-aitools-t27p-apim.azure-api.net/ai/api/tools/k12-qrg-generation-kickoff/execute" \
-H "Authorization: Bearer $TOKEN" \
-H "Ocp-Apim-Subscription-Key: $SUBSCRIPTION_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"emergencyOperationPlanId": "d4e5f6a7-b8c9-0123-d456-e78901234567",
"generalUserTagIds": ["a1b2c3d4-e5f6-7890-abcd-100000000001"],
"sessionId": null,
"waitForResult": false
}
}'

The AI Processing Pipeline

For each annex form in the EOP, the system runs four sequential AI steps. Each step feeds its output into the next.

Step 1: Category Classification

The system analyzes the annex text and assigns a single emergency or functional category.

Input: Cleaned annex form content

Output:

  • category -- The specific category (e.g., FIRE, LOCKDOWN)
  • type -- Either EMERGENCY (hazard-based) or FUNCTIONAL (procedure-based)
  • confidence -- high, medium, or low
  • reasoning -- Brief explanation of the classification decision

See QRG Types and Categories for the full list of valid categories.

Step 2: Group Extraction

The system reads the annex content and identifies all audience groups or roles referenced in the procedures.

Input: Full annex content plus the classification from Step 1

Output: An array of group names found in the text

Example:

Given annex text containing:

"Teachers should lead students to the assembly point. Administrators coordinate with emergency services. Bus Drivers secure their vehicles."

The system extracts: ["Teachers", "Administrators", "Bus Drivers"]

Step 3: Role Mapping

The system maps the informal group names extracted in Step 2 to the organization's official role tag identifiers.

Input:

  • Extracted group names from Step 2
  • The list of available role tags assigned to the EOP

Output: A mapping from each group name to one or more role tag UUIDs

Example:

Extracted GroupMapped Role Tag ID
Teachersa1b2c3d4-e5f6-7890-abcd-100000000001
Administratorsa1b2c3d4-e5f6-7890-abcd-100000000002
Bus Driversa1b2c3d4-e5f6-7890-abcd-100000000003

Role tag scoping: The system only considers role tags assigned to the specific EOP, not all roles in the organization. This prevents QRGs from being assigned to irrelevant roles. After AI mapping completes, all returned role IDs are validated against the EOP's tag list. Any IDs not matching a valid EOP tag are silently removed.

Role tag priority order:

  1. Tags passed in the kickoff request (generalUserTagIds parameter)
  2. Tags from the EOP snapshot
  3. Organization-level tags (rare fallback when the EOP snapshot contains none)

Automatic batching for large role lists: When the EOP has more than 12 role tags, the system automatically splits them into batches of 12 and runs the AI mapping step for each batch in parallel. Results are merged with deduplication, so the same group can map to roles discovered in different batches. This prevents LLM refusal on oversized prompts while maintaining mapping accuracy. The batching is transparent to the caller -- the final output is a single unified mapping regardless of how many batches were processed.

Step 4: Content Generation

The system generates one QRG for each role mapped in Step 3. Each QRG contains three structured content blocks.

Input:

  • Full cleaned annex content
  • Category classification from Step 1
  • Group extraction from Step 2
  • Validated role mappings from Step 3

Output per QRG:

  • QRG display name (e.g., "Fire Safety - Teacher")
  • QRG type (EMERGENCY or FUNCTIONAL)
  • Category identifier (e.g., FIRE)
  • Assigned role tag IDs
  • Three content blocks: BEFORE, DURING, AFTER

Content blocks contain HTML-formatted lists of role-specific instructions.


Form Processing Rules

The system applies the following rules when processing annex forms:

RuleBehavior
Forms with no state.data objectSkipped with a validation error
Forms with an empty data object (state.data has zero fields)Skipped with a validation error
Forms where all fields contain only HTML tags with no text contentSkipped after cleaning yields no usable content
Individual fields shorter than 10 characters after HTML strippingExcluded from the cleaned content
Forms where all fields are excluded after cleaningSkipped with a validation error
Forms with status IN_PROGRESS or NOT_STARTEDProcessed normally if they contain content
Forms with status COMPLETED but empty dataValid -- the user accepted default values
note

All form fields are considered for QRG generation. The system does not prioritize or filter by field name. It is template-agnostic and works with any form structure.

Content Cleaning

Before any AI processing, form content is cleaned:

  1. HTML tags and style blocks are removed
  2. HTML entities are decoded or removed
  3. Whitespace is normalized
  4. Fields with fewer than 10 characters of text are discarded

This cleaning typically reduces payload size by approximately 70%, improving AI processing speed and accuracy.


Result Structure

Polling for Status

Endpoint: POST /ai/api/tools/k12-qrg-generation-status/execute

{
"data": {
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}

curl Example (Status)

curl -X POST "https://dev-k12-aitools-t27p-apim.azure-api.net/ai/api/tools/k12-qrg-generation-status/execute" \
-H "Authorization: Bearer $TOKEN" \
-H "Ocp-Apim-Subscription-Key: $SUBSCRIPTION_KEY" \
-H "Content-Type: application/json" \
-d '{"data": {"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}'

Fetching the Result

Endpoint: POST /ai/api/tools/k12-qrg-generation-result/execute

{
"data": {
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
}

curl Example (Result)

curl -X POST "https://dev-k12-aitools-t27p-apim.azure-api.net/ai/api/tools/k12-qrg-generation-result/execute" \
-H "Authorization: Bearer $TOKEN" \
-H "Ocp-Apim-Subscription-Key: $SUBSCRIPTION_KEY" \
-H "Content-Type: application/json" \
-d '{"data": {"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}}'

Successful Result Response

{
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"sessionId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"status": "SUCCESS",
"data": {
"root": [
{
"name": "Fire Safety - Teacher",
"organizationId": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"type": "EMERGENCY",
"functionality": null,
"hazard": "FIRE",
"generalUserTagManagementType": "ASSIGN_SELECTED",
"generalUserTagIds": ["a1b2c3d4-e5f6-7890-abcd-100000000001"],
"contentBlocks": [
{
"type": "BEFORE",
"content": "<ul><li>Know your primary and secondary evacuation routes</li><li>Verify fire extinguisher locations in your area</li><li>Review student roster for accountability purposes</li></ul>"
},
{
"type": "DURING",
"content": "<ul><li>Alert students calmly and begin evacuation immediately</li><li>Lead students to the designated assembly point via the nearest safe exit</li><li>Bring your class roster for student accounting</li></ul>"
},
{
"type": "AFTER",
"content": "<ul><li>Account for all students using your roster</li><li>Report any missing students to the Incident Commander immediately</li><li>Await further instructions before allowing re-entry to the building</li></ul>"
}
]
},
{
"name": "Fire Safety - Administrator",
"organizationId": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"type": "EMERGENCY",
"functionality": null,
"hazard": "FIRE",
"generalUserTagManagementType": "ASSIGN_SELECTED",
"generalUserTagIds": ["a1b2c3d4-e5f6-7890-abcd-100000000002"],
"contentBlocks": [
{
"type": "BEFORE",
"content": "<ul><li>Ensure fire alarm systems are tested and operational</li><li>Coordinate fire drill schedule with local fire department</li><li>Maintain updated emergency contact lists for all staff</li></ul>"
},
{
"type": "DURING",
"content": "<ul><li>Activate the building fire alarm if not already triggered</li><li>Call 911 and provide building address and situation details</li><li>Coordinate with emergency responders upon arrival</li></ul>"
},
{
"type": "AFTER",
"content": "<ul><li>Collect accountability reports from all teachers</li><li>Communicate status updates to district office and parents</li><li>Coordinate building re-entry clearance with fire department</li></ul>"
}
]
}
]
},
"aiStats": {
"totalAnnexes": 5,
"aiClassifySuccess": 5,
"aiClassifyError": 0,
"aiGroupsSuccess": 5,
"aiGroupsError": 0,
"aiRolesSuccess": 5,
"aiRolesError": 0,
"aiGenerateSuccess": 18,
"aiGenerateError": 0
}
}

Result Fields -- QRG Object

FieldTypeDescription
namestringDisplay name of the generated QRG (e.g., "Fire Safety - Teacher")
organizationIdstring (UUID)The facility organization the QRG belongs to
typestringEMERGENCY (hazard-based) or FUNCTIONAL (procedure-based)
functionalitystring or nullThe functional category when type is FUNCTIONAL (e.g., EVACUATION). Null for emergency types.
hazardstring or nullThe hazard category when type is EMERGENCY (e.g., FIRE). Null for functional types.
generalUserTagManagementTypestringAlways ASSIGN_SELECTED for generated QRGs
generalUserTagIdsarray of string (UUID)Role tag IDs this QRG is assigned to
contentBlocksarray of objectThe three content phases (see below)

Result Fields -- Content Block

FieldTypeDescription
typestringPhase identifier: BEFORE, DURING, or AFTER
contentstringHTML-formatted instructions for this phase

Result Fields -- AI Statistics

FieldTypeDescription
totalAnnexesnumberTotal annex forms processed
aiClassifySuccessnumberAnnexes successfully classified (Step 1)
aiClassifyErrornumberAnnexes that failed classification
aiGroupsSuccessnumberAnnexes with successful group extraction (Step 2)
aiGroupsErrornumberAnnexes that failed group extraction
aiRolesSuccessnumberAnnexes with successful role mapping (Step 3)
aiRolesErrornumberAnnexes that failed role mapping
aiGenerateSuccessnumberIndividual QRGs successfully generated (Step 4)
aiGenerateErrornumberIndividual QRGs that failed generation
note

The aiGenerateSuccess count is typically higher than totalAnnexes because each annex produces multiple QRGs (one per matched role).

Error Result Response

{
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"sessionId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"status": "ERROR",
"message": "AI processing failed: 6/6 annexes failed AI classification",
"errors": [
"[classify:Fire Safety Annex] AI classification failed: PermissionDenied",
"[classify:Evacuation Annex] AI classification failed: PermissionDenied",
"[classify:Lockdown Annex] AI classification failed: PermissionDenied",
"[classify:Shelter in Place Annex] AI classification failed: PermissionDenied",
"[classify:Active Assailant Annex] AI classification failed: PermissionDenied",
"[classify:Severe Weather Annex] AI classification failed: PermissionDenied"
],
"aiStats": {
"totalAnnexes": 6,
"aiClassifySuccess": 0,
"aiClassifyError": 6,
"aiGroupsSuccess": 0,
"aiGroupsError": 0,
"aiRolesSuccess": 0,
"aiRolesError": 0,
"aiGenerateSuccess": 0,
"aiGenerateError": 0
}
}

Status Lifecycle

StatusMeaningTerminal
acceptedRequest received and queued for processingNo
processingAI pipeline is actively working on annexesNo
SUCCESSAll annexes processed; QRGs generated and savedYes
ERRORProcessing failed; see errors array for detailsYes
CANCELLEDJob was cancelled via the cancel endpointYes
warning

The kickoff response uses lowercase "accepted". All subsequent statuses (from the status and result endpoints) use UPPERCASE values (SUCCESS, ERROR, PROCESSING, CANCELLED).


Error Handling

Per-Annex Isolation

Each annex is processed independently. A failure in one annex does not stop processing of the remaining annexes. The final status reflects the aggregate outcome:

  • All annexes succeed: SUCCESS
  • Some annexes succeed, some fail: SUCCESS (with partial AI stats showing errors)
  • All annexes fail: ERROR

No Fallback Content

When an AI step fails for any annex, no placeholder or generic content is generated. The failure is recorded with a specific error message, and the annex is excluded from the result.

AI Statistics for Diagnostics

The aiStats object in every result response provides per-step success and error counts. This allows integrators to determine exactly which pipeline step encountered problems:

Failure PatternLikely Cause
aiClassifyError is highAI service authorization issue or model unavailability
aiGroupsError is highAnnex content too short or ambiguous for group identification
aiRolesError is highNo role tags configured on the EOP, or group names too dissimilar to tag names
aiGenerateError is highAI service timeout under heavy load

Error Messages

The errors array in an ERROR response contains specific messages prefixed with the step name and annex title:

  • [classify:Annex Name] ... -- Classification failure
  • [groups:Annex Name] ... -- Group extraction failure
  • [roles:Annex Name] ... -- Role mapping failure
  • [generate:Annex Name] ... -- Content generation failure

Common Error Scenarios

ScenarioBehavior
Annex form has no contentSkipped with validation error; other annexes continue
No groups extracted from annex textNo QRGs generated for that annex; other annexes continue
Groups extracted but no roles matchedQRG still generates but with empty generalUserTagIds
AI service timeoutStep fails for that annex; other annexes continue
EOP belongs to a DISTRICT organizationRequest fails immediately (QRGs can only be saved to FACILITY organizations)

Cancellation

Cancel an in-progress generation job using the cancel endpoint.

Endpoint: POST /ai/api/tools/k12-qrg-cancel/execute

Request Body

{
"data": {
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"jobType": "generation"
}
}

Request Fields

FieldTypeRequiredDescription
requestIdstringYesThe request identifier returned by kickoff
jobTypestringNogeneration (default) or editing

Response

{
"status": "success"
}

Or if the job has already completed or does not exist:

{
"status": "error"
}

curl Example (Cancel)

curl -X POST "https://dev-k12-aitools-t27p-apim.azure-api.net/ai/api/tools/k12-qrg-cancel/execute" \
-H "Authorization: Bearer $TOKEN" \
-H "Ocp-Apim-Subscription-Key: $SUBSCRIPTION_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"jobType": "generation"
}
}'
note

Cancellation is best-effort. If the AI pipeline is mid-step when cancellation is received, the current step may complete before the job terminates. Always verify the final status via the status endpoint after issuing a cancel.


Expected Timelines

EOP SizeAnnex CountApproximate Duration
Small1-330 seconds - 1 minute
Medium4-81-3 minutes
Large10+3-5 minutes

Processing time depends on:

  • Number of annexes in the EOP
  • Volume of content in each annex form
  • Number of roles to generate QRGs for (more roles = more QRGs per annex)
  • Current AI service load

Integrators should implement polling with a reasonable interval (e.g., every 5 seconds) and set a maximum timeout appropriate for the expected EOP size.


QRG Types and Categories

Every generated QRG is classified as either FUNCTIONAL (procedure-based) or EMERGENCY (hazard-based). The classification determines which category field is populated in the result.

Functional Categories

Functional QRGs describe standard safety procedures that apply across multiple hazard types.

CategoryDescription
EVACUATIONBuilding evacuation procedures
REVERSE_EVACUATIONProcedures for moving people back into a building
LOCKDOWNFacility lockdown procedures
SHELTER_IN_PLACESheltering procedures for various threats
ACCOUNTING_FOR_ALL_PERSONSAccounting for all persons after an incident
COMMUNICATIONS_AND_WARNINGEmergency communications and warning procedures
FAMILY_REUNIFICATIONParent/guardian reunification procedures
RECOVERYPost-incident recovery procedures
CONTINUITY_OF_OPERATIONS_COOPContinuity of operations planning
PUBLIC_HEALTH_MEDICAL_AND_MENTAL_HEALTHPublic health, medical, and mental health response
SECURITYSecurity procedures
OTHEROther functional procedures

Emergency / Hazard Categories

Emergency QRGs address specific hazard scenarios with targeted response instructions.

CategoryDescription
ACTIVE_SHOOTERActive assailant response
BOMB_THREATBomb threat procedures
TORNADO_SEVERE_WEATHERSevere weather response
EARTHQUAKEEarthquake response
FIREFire emergency response
HAZARDOUS_MATERIALSHazmat incident response
PANDEMICPandemic/infectious disease response
CYBER_ATTACKCyber attack response
FLOODFlooding emergency response
WINTER_STORM_BLIZZARDWinter storm or blizzard response
GANG_VIOLENCEGang violence response
RIOT_CIVIL_DISORDER_VIOLENT_PROTESTRiot, civil disorder, or violent protest response
MISSING_STUDENT_KIDNAPPINGMissing or abducted student procedures
NUCLEAR_RADIATION_RELEASENuclear or radiation release response
SUICIDE_OR_DEATHSuicide or death response
INTRUDER_UNKNOWN_INTENTIONUnauthorized intruder response
CRIMINAL_THREATS_OR_ACTIONSCriminal threats or actions response
DOMESTIC_VIOLENCEDomestic violence response
BUS_ACCIDENTBus or vehicle emergency response
DAM_FAILUREDam failure response
GAS_LEAKGas leak response
POWER_FAILUREPower failure response
SINK_HOLESSinkhole response
DANGEROUS_ANIMALSDangerous animals response
CONTAMINATED_FOOD_WATER_SUPPLYContaminated food or water supply response
EXPLOSION_NON_CHEMICALNon-chemical explosion response
OTHEROther hazard scenarios

Type-to-Field Mapping

QRG type ValuePopulated FieldNull Field
FUNCTIONALfunctionality (e.g., EVACUATION)hazard is null
EMERGENCYhazard (e.g., FIRE)functionality is null

Integration Best Practices

  1. Always poll asynchronously. Use the kickoff endpoint to start generation, then poll the status endpoint at regular intervals. Do not set waitForResult: true for production integrations with large EOPs.

  2. Persist tracking identifiers. Store both requestId and sessionId returned by the kickoff response. Use requestId for all subsequent status and result calls.

  3. Handle partial results. Check aiStats to determine whether all annexes processed successfully. A SUCCESS status means the workflow completed, but individual annexes may have been skipped due to empty content.

  4. Expect variable QRG counts. The number of QRGs generated depends on how many roles the AI identifies in each annex. Two annexes from the same EOP may produce different numbers of QRGs.

  5. Do not assume fixed form field names. The system is template-agnostic. It processes all fields in the form's data object regardless of field naming conventions.

  6. Verify organization type. QRGs can only be saved to FACILITY-type organizations. Requests for EOPs belonging to DISTRICT organizations will fail immediately.

  7. Implement cancellation handling. For user-facing integrations, provide a way to cancel long-running generation jobs. Always verify the final status after issuing a cancel request.