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.

Vytvoření vlastního prostředí Human-in-the-Loop pro workflow v Copilot Studio

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.

Webová konzole se třemi čekajícími požadavky v přehledné frontě 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:

  1. x-ms-notification-url: true u parametru notificationUrl říká platformě, aby vygenerovala callback URL a automaticky ji doplnila
  2. x-ms-notification-content na úrovni path definuje schéma callback payloadu (tedy co flow dostane ve chvíli, kdy se znovu rozběhne)
  3. Chybějící x-ms-trigger je 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 Human-in-the-Loop ve workflow v Copilot Studio – pole title, message a assigned-to 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. notificationUrl je 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í.