Vytvoření vlastního prostředí Human-in-the-Loop pro workflow v Copilot Studio
Když je každé schválení ve workflow jen dalším e‑mailem v něčí schránce, je něco špatně. Vzor s vlastním konektorem umožní workflow v Copilot Studio pozastavit kvůli lidskému vstupu a následně je obnovit přes libovolné uživatelské rozhraní, které si zvolíte.
Workflows in Copilot Studio se často potřebují zastavit a počkat na člověka: schválení, kontrolu, doplnění informací. Vestavěné možnosti (e-mail přes Human Review, Teams adaptive cards) fungují, ale ve větším měřítku z toho rychle vznikne šum. Desítky požadavků denně napříč více workflows, všechno končí v jednom inboxu nebo chatu, bez možnosti si to prioritizovat nebo vyřizovat po dávkách. A pak si člověk postaví agenta na třídění požadavků, který začne posílat další požadavky na lidský vstup, a… asi tušíte, kam to vede.
Microsoft připravil ukázkový custom connector, díky kterému můžete pro lidské odpovědi napojit jakékoli vlastní UI. Součástí je webová konzole, ale stejný vzor použijete i pro vlastní aplikaci, integraci do Slacku (ano, Slack!), nebo cokoli, co umí volat REST endpoint.
Ukázková webová konzole. Všechny čekající požadavky na jednom místě, seřazené podle času, se záložkami Pending/Completed/All.
Problém vestavěných možností
Out-of-the-box konektory, které umí „pause and wait for a human“, mají společné jedno omezení: samy určují doručovací kanál.
- Human Review posílá e-mail. Každý požadavek je další zpráva v něčím inboxu, promíchaná se vším ostatním.
- Post adaptive card and wait for a response (Teams connector) posílá kartu do Teams. Je to lepší než e-mail, ale pořád jde o proud jednotlivých karet bez možnosti vidět, co čeká napříč workflows.
Pro občasné, „high-signal“ požadavky je to v pořádku. Jakmile ale workflows naberou objem a máte desítky běhů denně, které potřebují lidský vstup, tyto kanály se změní v šum. Člověk nemá jak prioritizovat, nevidí, co čeká v různých workflows, a nemůže odpovědi vyřizovat po dávkách.
Cíl byl zachovat stejné chování pause-and-resume, ale napojit vlastní UI. To znamená postavit custom connector. Jenže jak udělat akci v konektoru, která flow skutečně pozastaví?
Zjištění: Webhook Actions
Akce v Teams connectoru „Post adaptive card and wait for a response“ používá méně známý postup, který funguje i u custom connectors: webhook action. Na rozdíl od webhook trigger (který spustí nový běh flow) webhook action aktuální flow pozastaví a pokračuje až ve chvíli, kdy backend pošle callback. Flow se při čekání kompletně „dehydratuje“, takže nespotřebovává žádné prostředky.
OpenAPI vzor
Funguje to díky třem věcem v OpenAPI definici connectoru:
-
x-ms-notification-url: trueu parametrunotificationUrlříká platformě, aby vygenerovala callback URL a automaticky ji doplnila -
x-ms-notification-contentna úrovni path definuje schéma callback payloadu (tedy co flow dostane ve chvíli, kdy se znovu rozběhne) -
Chybějící
x-ms-triggerje zásadní rozdíl. Bez něj to platforma bere jako akci, která se pozastaví, ne jako trigger, který něco startuje
Connector navíc potřebuje i DELETE endpoint pro webhook unsubscribe (volá se ve chvíli, kdy je flow zrušeno).
Kompletní OpenAPI definice
paths:
/api/requests/$subscriptions:
x-ms-notification-content:
description: Human's response
schema:
type: object
properties:
responseText:
type: string
description: The primary response text
response:
type: object
description: All response fields
respondedAt:
type: string
description: When the human responded
post:
operationId: RequestHumanInput
summary: Request human input and wait for a response
# No x-ms-trigger — this makes it an ACTION, not a trigger
parameters:
- name: body
in: body
required: true
schema:
type: object
required:
- notificationUrl
- body
properties:
notificationUrl:
type: string
x-ms-notification-url: true
x-ms-visibility: internal
body:
type: object
required:
- title
properties:
title:
type: string
description: Title shown to the human
message:
type: string
description: Instructions for the human
responses:
'201':
description: Created — waiting for response
/api/requests/{id}:
delete:
operationId: DeleteRequest
x-ms-visibility: internal
# Webhook unsubscribe — called when flow is cancelled
Jak to funguje od začátku do konce
sequenceDiagram
participant Agent as Copilot Studio Workflow
participant Backend as HITL Backend
participant Human as Human (Browser)
Agent->>Backend: POST /api/requests/$subscriptions
Backend-->>Agent: 201 Created
Note over Agent: Flow pauses (dehydrated)
Backend->>Human: Shows form in web console
Human->>Backend: Fills in form, clicks Submit
Backend->>Agent: POST to notificationUrl
Note over Agent: Flow resumes with response
Flow nic nepolluje. Kompletně se „dehydratuje“, takže během čekání nespotřebovává žádné prostředky. Může čekat minuty, hodiny i dny. Jakmile backend pošle POST na notificationUrl, Power Platform flow znovu „rehydratuje“ a pokračuje dál s daty z odpovědi.
Co musí Váš backend implementovat
Váš backend musí pro connector implementovat dva endpointy:
| Endpoint | Účel |
|---|---|
POST /api/requests/$subscriptions |
Přijme požadavek z connectoru, uloží ho (včetně notificationUrl) a vrátí 201 |
DELETE /api/requests/:id |
Odhlášení webhooku. Platforma tento endpoint zavolá, když se flow zruší |
Když člověk odpoví, Vaše aplikace musí poslat POST s odpovědí na uložený notificationUrl a dodržet schéma definované v x-ms-notification-content. Právě tím se flow znovu rozběhne. Všechno ostatní je na Vás: jak budete zobrazovat čekající požadavky, jak budou lidé odesílat odpovědi, jak bude vypadat UI. Ukázka obsahuje implementaci v Node.js/Express (~190 řádků) s jednoduchou webovou konzolí, ale nad těmito dvěma endpointy můžete postavit libovolné UI.
Nastavení
Tento sample rozběhnete zhruba do 5 minut.
1. Naklonujte repo a spusťte backend:
1
2
cd extensibility/human-in-the-loop
node setup.js
Skript nainstaluje závislosti, vytvoří dev tunnel (veřejnou HTTPS URL), spustí server a vypíše URL hostitele tunelu.
2. Importujte solution:
Přejděte na make.powerapps.com → Solutions → Import → nahrajte solution/customHIL_1_0_0_3.zip. Až budete vyzváni, nastavte HitlHostUrl na URL hostitele tunelu z kroku 1.
3. Použijte connector:
V Copilot Studio přidejte do workflow akci konektoru “Human-in-the-Loop”. Nastavte title, message a případně ji přiřaďte konkrétní osobě. Workflow se pozastaví, dokud člověk neodpoví.
Akce konektoru ve workflow v Copilot Studio. Workflow se v tomto kroku pozastaví, dokud neodpoví člověk.
4. Odpovězte:
Otevřete lokální URL nebo URL tunelu v prohlížeči. Všechny čekající požadavky uvidíte ve webové konzoli. Vyplňte formulář, klikněte na Submit a workflow pokračuje dál s daty z odpovědi.
Provozní doporučení pro produkci
Ukázka používá in-memory úložiště a dev tunnels, což je pro demo v pořádku. Pro produkční nasazení zvažte:
- Perzistentní úložiště (databáze místo in-memory mapy)
- OAuth autentizaci na backendu
- Autorizaci uživatelů (ověřit, kdo může odpovídat na které požadavky)
- Push notifikace (místo pollingu webové konzole)
- HTTPS hosting na Azure App Service, Azure Functions nebo podobné službě
-
Chraňte callback URL.
notificationUrlje podepsaná přes SAS od Power Platform, ale nevyžaduje autentizaci. Kdokoli, kdo URL získá, může flow znovu spustit. Držte ji pouze na serveru – nikdy ji nevystavujte do prohlížeče ani koncovým uživatelům.
Kompletní ukázku najdete na CopilotStudioSamples/extensibility/human-in-the-loop. Obsahuje kompletní OpenAPI definici, Node.js backend, importovatelné Power Platform solution a lokální test harness.
V jakých scénářích byste vlastní HITL connector použili Vy? Narazili jste u vestavěných approval channels na stejný limit? Napište do komentářů.
Tento článek vznikl s využitím materiálu z microsoft.github.io. Osobní postřehy a komentáře jsou moje vlastní.