Blog Post

Microsoft Foundry Blog
6 MIN READ

Orchestrating Multi-Agent Conversations with Microsoft Foundry Workflows

notanaha's avatar
notanaha
Icon for Microsoft rankMicrosoft
Nov 25, 2025

Why Workflows?

Today, we have access to many frameworks that enable a wide range of multi-agent interactions, including group conversations, concurrent conversations, fully autonomous agent flows, and more.

These styles of multi-agent development are exciting and can be valuable in many scenarios. However, they often conflict with real business environments, where users expect to preserve their existing workflows exactly as is and require agents to behave in a declarative and deterministic manner.

In such cases, Microsoft Foundry Workflows provides precisely what is needed.

 

Quick start creating workflows

Starting with the sample workflows

You can access Microsoft Foundry Workflows from the new Foundry control plane by selecting the Build section and then the Workflows blade.
From the Create menu, there are three basic samples; start with the Human-in-Loop sample.

 

The Human-in-Loop sample doesn’t require any agents. First, click Save and name your “Human-in-Loop” workflow.
Next, click Preview to run the workflow.

These samples help you build a basic understanding of how to pass variables between nodes.
For example, focus on the Set variable node where Local.OriginalInput is set to System.LastMessage.Text.
You can define any variable with the Local prefix and use it across the workflow.

 

There are also a variety of system variables available to manage workflows. You can see them in the dropdown of the Set variable node in the screenshot above. Please note these system variables are read-only.

In another sample, group-chat-workflow, you can see how to include agents in a workflow.
As noted in the sample, you need to create two agents - student-agent and teacher-agent - and you’ll find their instructions in the sample’s notes (see the screenshot).

 

 

Track How Variables Move Between Nodes

In both the student-agent and teacher-agent nodes, the previous message is passed using the Local.LatestMessage variable.
In the screenshot, you can see Local.LatestMessage used in the Input message and Save agent output message as fields of the teacher-agent node. The same variable is then used in an IF condition to check whether the message includes the string COMPLETED.

Please note: expressions in IF conditions use Power Fx. See the Learn documentation for more details.

 

 

Let's create more practical scenario

Consider a workflow that handles a customer request at a bank - for example, updating a customer’s address.
Note that this demo aims to illustrate the Foundry Workflow mechanics, so the algorithm and agent instrumentation are intentionally simplified. In production, an agent would typically use Tools to ground against actual customer data; that is out of scope here.

First, create a blank workflow. In the blank workflow, open the YAML tab.

 

 

Then copy and paste the following YAML, replacing the default contents provided by the template.

 

kind: workflow
trigger:
  kind: OnConversationStart
  id: trigger_wf
  actions:
    - kind: SetVariable
      id: init_latest
      variable: Local.LatestMessage
      value: =UserMessage(System.LastMessageText)
    - kind: InvokeAzureAgent
      id: action-1762335398123
      agent:
        name: Bank-Receptionist
      conversationId: =System.ConversationId
      input:
        messages: =Local.LatestMessage
      output:
        messages: Local.LatestMessage
        autoSend: true
    - kind: ConditionGroup
      id: action-1763615340027
      conditions:
        - id: if-action-1763615340027-0
          condition: =!IsBlank(Find("[ADDRESS CHANGE]", Upper(Last(Local.LatestMessage).Text)))
          actions:
            - kind: Question
              variable: Local.LatestMessage
              id: action-1763621797686
              entity: StringPrebuiltEntity
              skipQuestionMode: SkipOnFirstExecutionIfVariableHasValue
              prompt: "{Last(Local.LatestMessage).Text}"
            - kind: InvokeAzureAgent
              id: action-1763617076411
              agent:
                name: Bank-AddressUpdater
              conversationId: =System.ConversationId
              input:
                messages: =Local.LatestMessage
              output:
                messages: Local.LatestMessage
            - kind: ConditionGroup
              conditions:
                - condition: =!IsBlank(Find("[COMPLETED]", Upper(Last(Local.LatestMessage).Text)))
                  actions:
                    - kind: SendActivity
                      activity: "{Last(Local.LatestMessage).Text}"
                      id: action-1763624289978
                  id: if-action-1763624256745-0
              id: action-1763624256745
              elseActions:
                - kind: GotoAction
                  actionId: action-1763615340027
                  id: action-1763625609628
        - id: if-action-1763615340027-vjsqzvm4
          condition: =!IsBlank(Find("[OTHER TASKS]", Upper(Last(Local.LatestMessage).Text)))
          actions:
            - kind: InvokeAzureAgent
              id: action-1763616482991
              agent:
                name: Bank-OtherTaskOperator
              conversationId: =System.ConversationId
              input:
                messages: =Local.LatestMessage
              output:
                messages: Local.LatestMessage
            - kind: SendActivity
              id: action-1763616797157
              activity: =Last(Local.LatestMessage).Text
            - kind: EndConversation
              id: action-1763616664099
      elseActions:
        - kind: Question
          id: action-1763617461488
          variable: Local.LatestMessage
          entity: StringPrebuiltEntity
          skipQuestionMode: SkipOnFirstExecutionIfVariableHasValue
          prompt: "{Last(Local.LatestMessage).Text}"
        - kind: GotoAction
          id: action-1763617481845
          actionId: action-1762335398123
id: ""
name: bank-teller-workflow
description: ""

# Sticky Notes
# STICKY_NOTE: {"id":"sticky_1763708469729_k0zzzfgxm","text":"Bank-Receptionist\n\nYou are the receptionist at the bank, managing the process of accepting and completing customer requests.\nYour goal is to hear requests from customers, assign tasks to the right personnel, and check if their requests have been resolved.\nCurrently, the only task that banks can perform is to change the address.\n\nIf customer's request is one of the following, reply with a key word enclosed with [].\n- Address Change [Address Change]\n- Other Tasks [Other Tasks]\n\nWhen you receive a request from a customer, first ask the customer for their bank card number to verify their identity.\nWith the bank card number as the key, we will get the customer master's information, return the customer's name, address, and phone number, and check if it is correct.\n\nReturn the reply in the same language as the requester.","width":331,"height":191,"x":-201,"y":22}
# STICKY_NOTE: {"id":"sticky_1763708527334_mhangsr86","text":"Bank-AddressUpdater\n\nYou are the person in charge of changing the customer's address.\nYour task is to get the customer to present the necessary documents for the address change and change the address of the customer registered in the customer master.\nFirst, ask the customer to present the necessary documents for the change of address.\nWhen the task is complete, return the updated customer master's name, address, and phone number.\nThe documents required to change your address are one of the following:\n- Driver's license\n- Health insurance card\n\nWhen you ask a reply for the requester, include a phrase [Address Change].\nWhen your task completed successfully, return a phrase [completed].\nIf you consider that your task has completed, do not ask further questions. Say \"Thank you and Have a nice day!\" instead.\nReturn the reply in the same language as the requester.","width":336,"height":189,"x":138,"y":24}
# STICKY_NOTE: {"id":"sticky_1763708554139_71ve4b59s","text":"Bank-OtherTaskOperator\n\nYou are the person in charge of other tasks.\nYou are not currently in charge of anything.\nWhen the request comes, do nothing and return a phrase [good night].\n\nReturn the reply in the same language as the requester.","width":349,"height":184,"x":494.3033707865168,"y":26.263695158124165}

 

After pasting the YAML, you can switch back to the Visualizer tab and save it as bank-teller-workflow.
As with group-chat-workflow, prepare three agents with the instructions shown in the Notes for this workflow.

 

How to use this Demo workflow

This workflow supports only the address-update path. Start by saying “Hello” to the receptionist, then say “Address Change.”
The receptionist asks for your bank account number; you can respond with any sequence of digits for this demo.
Next, the Address Updater asks for an ID document to confirm your address, and you’ll then be asked for your new address and phone number.
If you omit any required information, the workflow will keep prompting until you provide it.
Once you’ve supplied everything, the workflow terminates.

Conclusion

Foundry Workflows enables you to leverage the flexibility of agents while building precise business procedures as Agent Workflows.
You can construct human-in-the-loop processes and step control using rule-based logic.
In addition, by using Power FX for message manipulation, you can build flows that remain predictable and easy to maintain even when multiple agents and human steps are involved.

In this sample, we used strings for flow control, but it is also possible to pass messages using JSON structures.
Please refer to the official documentation for details.

Furthermore, by equipping each agent with Knowledge Bases or Tools, you can organically utilize information from enterprise systems as well as the internet.

Use Foundry Workflows to bridge your existing business processes into agent-based AI.

Updated Nov 25, 2025
Version 1.0
No CommentsBe the first to comment