Compartilhar via


Fluxos de trabalho declarativos – Visão geral

Fluxos de trabalho declarativos permitem definir a lógica de fluxo de trabalho usando arquivos de configuração YAML em vez de escrever código programático. Essa abordagem torna os fluxos de trabalho mais fáceis de ler, modificar e compartilhar entre equipes.

Visão geral

Com fluxos de trabalho declarativos, você descreve o que seu fluxo de trabalho deve fazer em vez de como implementá-lo. A estrutura manipula a execução subjacente, convertendo suas definições YAML em grafos de fluxo de trabalho executáveis.

Principais benefícios:

  • Formato legível: a sintaxe YAML é fácil de entender, mesmo para não desenvolvedores
  • Portátil: definições de fluxo de trabalho podem ser compartilhadas, com controle de versão e modificadas sem alterações de código
  • Iteração rápida: modificar o comportamento do fluxo de trabalho editando arquivos de configuração
  • Estrutura consistente: tipos de ação predefinidos garantem que os fluxos de trabalho sigam as práticas recomendadas

Quando usar fluxos de trabalho declarativos versus programáticos

Scenario Abordagem recomendada
Padrões de orquestração padrão Declarativo
Fluxos de trabalho que mudam com frequência Declarativo
Não desenvolvedores precisam modificar fluxos de trabalho Declarativo
Lógica personalizada complexa Programmatic
Máxima flexibilidade e controle Programmatic
Integração com o código python existente Programmatic

Estrutura YAML básica

A estrutura YAML difere ligeiramente entre implementações de C# e Python. Confira as seções específicas do idioma abaixo para obter detalhes.

Tipos de ação

Fluxos de trabalho declarativos dão suporte a vários tipos de ação. A tabela a seguir mostra a disponibilidade por idioma:

Categoria Ações C# Python
Gerenciamento de variáveis SetVariable SetMultipleVariables ResetVariable
Gerenciamento de variáveis AppendValue
Gerenciamento de variáveis SetTextVariable, ClearAllVariables, , ParseValueEditTableV2
Fluxo de controle If, ConditionGroup, Foreach, BreakLoop, ContinueLoop, , GotoAction
Fluxo de controle RepeatUntil
Saída SendActivity
Saída EmitEvent
Invocação do Agente InvokeAzureAgent
Invocação de Ferramenta InvokeFunctionTool
Invocação de Ferramenta InvokeMcpTool
Human-in-the-Loop Question, RequestExternalInput
Human-in-the-Loop Confirmation, WaitForInput
Controle de fluxo de trabalho EndWorkflow EndConversation CreateConversation
Conversa AddConversationMessage, CopyConversationMessages, , RetrieveConversationMessageRetrieveConversationMessages

Estrutura YAML do C#

Os fluxos de trabalho declarativos do C# usam uma estrutura baseada em gatilho:

#
# Workflow description as a comment
#
kind: Workflow
trigger:

  kind: OnConversationStart
  id: my_workflow
  actions:

    - kind: ActionType
      id: unique_action_id
      displayName: Human readable name
      # Action-specific properties

Elementos de estrutura

Elemento Obrigatório DESCRIÇÃO
kind Yes Deve ser Workflow
trigger.kind Yes Tipo de gatilho (normalmente OnConversationStart)
trigger.id Yes Identificador exclusivo para o fluxo de trabalho
trigger.actions Yes Lista de ações a serem executadas

Estrutura YAML do Python

Os fluxos de trabalho declarativos do Python usam uma estrutura baseada em nome com entradas opcionais:

name: my-workflow
description: A brief description of what this workflow does

inputs:
  parameterName:
    type: string
    description: Description of the parameter

actions:
  - kind: ActionType
    id: unique_action_id
    displayName: Human readable name
    # Action-specific properties

Elementos de estrutura

Elemento Obrigatório DESCRIÇÃO
name Yes Identificador exclusivo para o fluxo de trabalho
description Não Descrição legível por humanos
inputs Não Parâmetros de entrada que o fluxo de trabalho aceita
actions Yes Lista de ações a serem executadas

Pré-requisitos

Antes de começar, verifique se você tem:

  • .NET 8.0 ou posterior
  • Um projeto do Microsoft Foundry com pelo menos um agente implantado
  • Os seguintes pacotes NuGet instalados:
dotnet add package Microsoft.Agents.AI.Workflows.Declarative --prerelease
dotnet add package Microsoft.Agents.AI.Workflows.Declarative.AzureAI --prerelease
  • Se você pretende adicionar a ação de invocação da ferramenta MCP ao fluxo de trabalho, instale também o seguinte pacote NuGet:
dotnet add package Microsoft.Agents.AI.Workflows.Declarative.Mcp --prerelease

Seu primeiro fluxo de trabalho declarativo

Vamos criar um fluxo de trabalho simples que receba um usuário com base em sua entrada.

Etapa 1: Criar o arquivo YAML

Crie um arquivo chamado greeting-workflow.yaml:

#
# This workflow demonstrates a simple greeting based on user input.
# The user's message is captured via System.LastMessage.
#
# Example input: 
# Alice
#
kind: Workflow
trigger:

  kind: OnConversationStart
  id: greeting_workflow
  actions:

    # Capture the user's input from the last message
    - kind: SetVariable
      id: capture_name
      displayName: Capture user name
      variable: Local.userName
      value: =System.LastMessage.Text

    # Set a greeting prefix
    - kind: SetVariable
      id: set_greeting
      displayName: Set greeting prefix
      variable: Local.greeting
      value: Hello

    # Build the full message using an expression
    - kind: SetVariable
      id: build_message
      displayName: Build greeting message
      variable: Local.message
      value: =Concat(Local.greeting, ", ", Local.userName, "!")

    # Send the greeting to the user
    - kind: SendActivity
      id: send_greeting
      displayName: Send greeting to user
      activity: =Local.message

Etapa 2: Configurar o provedor de agente

Crie um aplicativo de console C# para executar o fluxo de trabalho. Primeiro, configure o provedor de agente que se conecta ao Foundry:

using Azure.Identity;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Agents.AI.Workflows.Declarative;
using Microsoft.Extensions.Configuration;

// Load configuration (endpoint should be set in user secrets or environment variables)
IConfiguration configuration = new ConfigurationBuilder()
    .AddUserSecrets<Program>()
    .AddEnvironmentVariables()
    .Build();

string foundryEndpoint = configuration["FOUNDRY_PROJECT_ENDPOINT"] 
    ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT not configured");

// Create the agent provider that connects to Foundry
// WARNING: DefaultAzureCredential is convenient for development but requires 
// careful consideration in production environments.
AzureAgentProvider agentProvider = new(
    new Uri(foundryEndpoint), 
    new DefaultAzureCredential());

Etapa 3: compilar e executar o fluxo de trabalho

// Define workflow options with the agent provider
DeclarativeWorkflowOptions options = new(agentProvider)
{
    Configuration = configuration,
    // LoggerFactory = loggerFactory, // Optional: Enable logging
    // ConversationId = conversationId, // Optional: Continue existing conversation
};

// Build the workflow from the YAML file
string workflowPath = Path.Combine(AppContext.BaseDirectory, "greeting-workflow.yaml");
Workflow workflow = DeclarativeWorkflowBuilder.Build<string>(workflowPath, options);

Console.WriteLine($"Loaded workflow from: {workflowPath}");
Console.WriteLine(new string('-', 40));

// Create a checkpoint manager (in-memory for this example)
CheckpointManager checkpointManager = CheckpointManager.CreateInMemory();

// Execute the workflow with input
string input = "Alice";
StreamingRun run = await InProcessExecution.RunStreamingAsync(
    workflow, 
    input, 
    checkpointManager);

// Process workflow events
await foreach (WorkflowEvent workflowEvent in run.WatchStreamAsync())
{
    switch (workflowEvent)
    {
        case MessageActivityEvent activityEvent:
            Console.WriteLine($"Activity: {activityEvent.Message}");
            break;
        case AgentResponseEvent responseEvent:
            Console.WriteLine($"Response: {responseEvent.Response.Text}");
            break;
        case WorkflowErrorEvent errorEvent:
            Console.WriteLine($"Error: {errorEvent.Data}");
            break;
    }
}

Console.WriteLine("Workflow completed!");

Saída esperada

Loaded workflow from: C:\path\to\greeting-workflow.yaml
----------------------------------------
Activity: Hello, Alice!
Workflow completed!

Conceitos principais

Namespaces de Variáveis

Os fluxos de trabalho declarativos em C# usam variáveis com espaçamento de nomes para organizar o estado:

Namespace DESCRIÇÃO Example
Local.* Variáveis locais para o fluxo de trabalho Local.message
System.* Valores fornecidos pelo sistema System.ConversationId, System.LastMessage

Observação

Fluxos de trabalho declarativos em C# não usam Workflow.Inputs nem Workflow.Outputs namespaces. A entrada é recebida por meio System.LastMessage e a saída é enviada por meio de SendActivity ações.

Variáveis do sistema

Variable DESCRIÇÃO
System.ConversationId Identificador de conversa atual
System.LastMessage A mensagem de usuário mais recente
System.LastMessage.Text Conteúdo de texto da última mensagem

Linguagem de expressão

Os valores prefixados com = são avaliados como expressões usando a linguagem de expressão PowerFx:

# Literal value (no evaluation)
value: Hello

# Expression (evaluated at runtime)
value: =Concat("Hello, ", Local.userName)

# Access last message text
value: =System.LastMessage.Text

As funções comuns incluem:

  • Concat(str1, str2, ...) - Concatenar cadeias de caracteres
  • If(condition, trueValue, falseValue) - Expressão condicional
  • IsBlank(value) – Verificar se o valor está vazio
  • Upper(text) / Lower(text) – Conversão de maiúsculas e minúsculas
  • Find(searchText, withinText) - Localizar texto dentro da cadeia de caracteres
  • MessageText(message) – Extrair texto de um objeto de mensagem
  • UserMessage(text) - Criar uma mensagem de usuário com base no texto
  • AgentMessage(text) - Criar uma mensagem de agente com base no texto

Opções de configuração

A DeclarativeWorkflowOptions classe fornece configuração para execução de fluxo de trabalho:

DeclarativeWorkflowOptions options = new(agentProvider)
{
    // Application configuration for variable substitution
    Configuration = configuration,

    // Continue an existing conversation (optional)
    ConversationId = "existing-conversation-id",

    // Enable logging (optional)
    LoggerFactory = loggerFactory,

    // MCP tool handler for InvokeMcpTool actions (optional)
    McpToolHandler = mcpToolHandler,

    // PowerFx expression limits (optional)
    MaximumCallDepth = 50,
    MaximumExpressionLength = 10000,

    // Telemetry configuration (optional)
    ConfigureTelemetry = opts => { /* configure telemetry */ },
    TelemetryActivitySource = activitySource,
};

Instalação do provedor de agente

O AzureAgentProvider conecta seu fluxo de trabalho aos agentes do Foundry:

using Azure.Identity;
using Microsoft.Agents.AI.Workflows.Declarative;

// Create the agent provider with Azure credentials
AzureAgentProvider agentProvider = new(
    new Uri("https://your-project.api.azureml.ms"), 
    new DefaultAzureCredential())
{
    // Optional: Define functions that agents can automatically invoke
    Functions = [
        AIFunctionFactory.Create(myPlugin.GetData),
        AIFunctionFactory.Create(myPlugin.ProcessItem),
    ],

    // Optional: Allow concurrent function invocation
    AllowConcurrentInvocation = true,

    // Optional: Allow multiple tool calls per response
    AllowMultipleToolCalls = true,
};

Execução de fluxo de trabalho

Use InProcessExecution para executar fluxos de trabalho e manipular eventos:

using Microsoft.Agents.AI.Workflows;
using Microsoft.Agents.AI.Workflows.Checkpointing;

// Create checkpoint manager (choose in-memory or file-based)
CheckpointManager checkpointManager = CheckpointManager.CreateInMemory();
// Or persist to disk:
// var checkpointFolder = Directory.CreateDirectory("./checkpoints");
// var checkpointManager = CheckpointManager.CreateJson(
//     new FileSystemJsonCheckpointStore(checkpointFolder));

// Start workflow execution
StreamingRun run = await InProcessExecution.RunStreamingAsync(
    workflow, 
    input, 
    checkpointManager);

// Process events as they occur
await foreach (WorkflowEvent workflowEvent in run.WatchStreamAsync())
{
    switch (workflowEvent)
    {
        case MessageActivityEvent activity:
            Console.WriteLine($"Message: {activity.Message}");
            break;

        case AgentResponseUpdateEvent streamEvent:
            Console.Write(streamEvent.Update.Text); // Streaming text
            break;

        case AgentResponseEvent response:
            Console.WriteLine($"Agent: {response.Response.Text}");
            break;

        case RequestInfoEvent request:
            // Handle external input requests (human-in-the-loop)
            var userInput = await GetUserInputAsync(request);
            await run.SendResponseAsync(request.Request.CreateResponse(userInput));
            break;

        case SuperStepCompletedEvent checkpoint:
            // Checkpoint created - can resume from here if needed
            var checkpointInfo = checkpoint.CompletionInfo?.Checkpoint;
            break;

        case WorkflowErrorEvent error:
            Console.WriteLine($"Error: {error.Data}");
            break;
    }
}

Retomada de Pontos de Verificação

Os fluxos de trabalho podem ser retomados a partir dos pontos de verificação para garantir a tolerância a falhas.

// Save checkpoint info when workflow yields
CheckpointInfo? lastCheckpoint = null;

await foreach (WorkflowEvent workflowEvent in run.WatchStreamAsync())
{
    if (workflowEvent is SuperStepCompletedEvent checkpointEvent)
    {
        lastCheckpoint = checkpointEvent.CompletionInfo?.Checkpoint;
    }
}

// Later: Resume from the saved checkpoint
if (lastCheckpoint is not null)
{
    // Recreate the workflow (can be on a different machine)
    Workflow workflow = DeclarativeWorkflowBuilder.Build<string>(workflowPath, options);

    StreamingRun resumedRun = await InProcessExecution.ResumeStreamingAsync(
        workflow, 
        lastCheckpoint, 
        checkpointManager);

    // Continue processing events...
}

Referência de ações

As ações são os blocos de construção de fluxos de trabalho declarativos. Cada ação executa uma operação específica e as ações são executadas sequencialmente na ordem em que aparecem no arquivo YAML.

Estrutura de ação

Todas as ações compartilham propriedades comuns:

- kind: ActionType      # Required: The type of action
  id: unique_id         # Optional: Unique identifier for referencing
  displayName: Name     # Optional: Human-readable name for logging
  # Action-specific properties...

Ações de gerenciamento de variáveis

DefinirVariável

Define uma variável como um valor especificado.

- kind: SetVariable
  id: set_greeting
  displayName: Set greeting message
  variable: Local.greeting
  value: Hello World

Com uma expressão:

- kind: SetVariable
  variable: Local.fullName
  value: =Concat(Local.firstName, " ", Local.lastName)

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
variable Yes Caminho da variável (por exemplo, Local.name, Workflow.Outputs.result)
value Yes Valor a ser definido (literal ou expressão)

SetMultipleVariables

Define várias variáveis em uma única ação.

- kind: SetMultipleVariables
  id: initialize_vars
  displayName: Initialize variables
  variables:
    Local.counter: 0
    Local.status: pending
    Local.message: =Concat("Processing order ", Local.orderId)

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
variables Yes Mapa de caminhos variáveis para valores

SetTextVariable (somente C#)

Define uma variável de texto como um valor de cadeia de caracteres especificado.

- kind: SetTextVariable
  id: set_text
  displayName: Set text content
  variable: Local.description
  value: This is a text description

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
variable Yes Caminho da variável para o valor de texto
value Yes Valor de texto a ser definido

ResetVariable

Limpa o valor de uma variável.

- kind: ResetVariable
  id: clear_counter
  variable: Local.counter

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
variable Yes Caminho da variável a ser redefinido

ClearAllVariables (apenas para C#)

Redefine todas as variáveis no contexto atual.

- kind: ClearAllVariables
  id: clear_all
  displayName: Clear all workflow variables

ParseValue (somente C#)

Extrai ou converte dados em um formato utilizável.

- kind: ParseValue
  id: parse_json
  displayName: Parse JSON response
  source: =Local.rawResponse
  variable: Local.parsedData

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
source Yes Expressão retornando o valor para analisar
variable Yes Caminho da variável para armazenar o resultado analisado

EditTableV2 (somente C#)

Modifica dados em um formato de tabela estruturado.

- kind: EditTableV2
  id: update_table
  displayName: Update configuration table
  table: Local.configTable
  operation: update
  row:
    key: =Local.settingName
    value: =Local.settingValue

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
table Yes Caminho variável para a tabela
operation Yes Tipo de operação (adicionar, atualizar, excluir)
row Yes Dados de linha para a operação

Ações de fluxo de controle

If

Executa ações condicionalmente com base em uma condição.

- kind: If
  id: check_age
  displayName: Check user age
  condition: =Local.age >= 18
  then:
    - kind: SendActivity
      activity:
        text: "Welcome, adult user!"
  else:
    - kind: SendActivity
      activity:
        text: "Welcome, young user!"

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
condition Yes Expressão que é avaliada como verdadeiro/falso
then Yes Ações a serem executadas se a condição for verdadeira
else Não Ações a serem executadas se a condição for falsa

ConditionGroup

Avalia várias condições, como uma instrução switch/case.

- kind: ConditionGroup
  id: route_by_category
  displayName: Route based on category
  conditions:
    - condition: =Local.category = "electronics"
      id: electronics_branch
      actions:
        - kind: SetVariable
          variable: Local.department
          value: Electronics Team
    - condition: =Local.category = "clothing"
      id: clothing_branch
      actions:
        - kind: SetVariable
          variable: Local.department
          value: Clothing Team
  elseActions:
    - kind: SetVariable
      variable: Local.department
      value: General Support

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
conditions Yes Lista de pares de condição/ações (vitórias na primeira partida)
elseActions Não Ações caso nenhuma condição seja correspondente

Foreach

Itera sobre uma coleção.

- kind: Foreach
  id: process_items
  displayName: Process each item
  source: =Local.items
  itemName: item
  indexName: index
  actions:
    - kind: SendActivity
      activity:
        text: =Concat("Processing item ", index, ": ", item)

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
source Yes Expressão que retorna uma coleção
itemName Não Nome da variável para item atual (padrão: item)
indexName Não Nome da variável para o índice atual (padrão: index)
actions Yes Ações a serem executadas para cada item

BreakLoop

Sai do loop atual imediatamente.

- kind: Foreach
  source: =Local.items
  actions:
    - kind: If
      condition: =item = "stop"
      then:
        - kind: BreakLoop
    - kind: SendActivity
      activity:
        text: =item

ContinueLoop

Passa para a próxima iteração do loop.

- kind: Foreach
  source: =Local.numbers
  actions:
    - kind: If
      condition: =item < 0
      then:
        - kind: ContinueLoop
    - kind: SendActivity
      activity:
        text: =Concat("Positive number: ", item)

GotoAction

Salta para uma ação específica usando o ID.

- kind: SetVariable
  id: start_label
  variable: Local.attempts
  value: =Local.attempts + 1

- kind: SendActivity
  activity:
    text: =Concat("Attempt ", Local.attempts)

- kind: If
  condition: =And(Local.attempts < 3, Not(Local.success))
  then:
    - kind: GotoAction
      actionId: start_label

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
actionId Yes Identificador da ação para pular para

Ações de saída

SendActivity

Envia uma mensagem ao usuário.

- kind: SendActivity
  id: send_welcome
  displayName: Send welcome message
  activity:
    text: "Welcome to our service!"

Com uma expressão:

- kind: SendActivity
  activity:
    text: =Concat("Hello, ", Local.userName, "! How can I help you today?")

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
activity Yes A atividade a ser enviada
activity.text Yes Texto da mensagem (literal ou expressão)

Ações de invocação do agente

InvokeAzureAgent

Invoca um agente do Foundry.

Invocação básica:

- kind: InvokeAzureAgent
  id: call_assistant
  displayName: Call assistant agent
  agent:
    name: AssistantAgent
  conversationId: =System.ConversationId

Na configuração de entrada e saída:

- kind: InvokeAzureAgent
  id: call_analyst
  displayName: Call analyst agent
  agent:
    name: AnalystAgent
  conversationId: =System.ConversationId
  input:
    messages: =Local.userMessage
    arguments:
      topic: =Local.topic
  output:
    responseObject: Local.AnalystResult
    messages: Local.AnalystMessages
    autoSend: true

Com loop externo (continua até que a condição seja atendida):

- kind: InvokeAzureAgent
  id: support_agent
  agent:
    name: SupportAgent
  input:
    externalLoop:
      when: =Not(Local.IsResolved)
  output:
    responseObject: Local.SupportResult

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
agent.name Yes Nome do agente registrado
conversationId Não Identificador de contexto de conversa
input.messages Não Mensagens a serem enviadas ao agente
input.arguments Não Argumentos adicionais para o agente
input.externalLoop.when Não Condição para continuar o loop do agente
output.responseObject Não Caminho para armazenar a resposta do agente
output.messages Não Caminho para armazenar mensagens de conversa
output.autoSend Não Enviar resposta automaticamente ao usuário

Ações de Invocação de Ferramentas (somente C#)

InvokeFunctionTool

Invoca uma ferramenta de função diretamente do fluxo de trabalho sem passar por um agente de IA.

- kind: InvokeFunctionTool
  id: invoke_get_data
  displayName: Get data from function
  functionName: GetUserData
  conversationId: =System.ConversationId
  requireApproval: true
  arguments:
    userId: =Local.userId
  output:
    autoSend: true
    result: Local.UserData
    messages: Local.FunctionMessages

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
functionName Yes Nome da função a ser invocada
conversationId Não Identificador de contexto de conversa
requireApproval Não Se é necessário exigir aprovação do usuário antes da execução
arguments Não Argumentos a serem passados para a função
output.result Não Caminho para armazenar o resultado da função
output.messages Não Caminho para armazenar mensagens de função
output.autoSend Não Enviar automaticamente o resultado para o usuário

Configuração do C# para InvokeFunctionTool:

As funções devem ser registradas com WorkflowRunner ou manipuladas por meio de entrada externa:

// Define functions that can be invoked
AIFunction[] functions = [
    AIFunctionFactory.Create(myPlugin.GetUserData),
    AIFunctionFactory.Create(myPlugin.ProcessOrder),
];

// Create workflow runner with functions
WorkflowRunner runner = new(functions) { UseJsonCheckpoints = true };
await runner.ExecuteAsync(workflowFactory.CreateWorkflow, input);

InvokeMcpTool

Invoca uma ferramenta em um servidor MCP (Model Context Protocol).

- kind: InvokeMcpTool
  id: invoke_docs_search
  displayName: Search documentation
  serverUrl: https://learn.microsoft.com/api/mcp
  serverLabel: microsoft_docs
  toolName: microsoft_docs_search
  conversationId: =System.ConversationId
  requireApproval: false
  headers:
    X-Custom-Header: custom-value
  arguments:
    query: =Local.SearchQuery
  output:
    autoSend: true
    result: Local.SearchResults

Com o nome da conexão para cenários hospedados:

- kind: InvokeMcpTool
  id: invoke_hosted_mcp
  serverUrl: https://mcp.ai.azure.com
  toolName: my_tool
  # Connection name is used in hosted scenarios to connect to a ProjectConnectionId in Foundry.
  # Note: This feature is not fully supported yet.
  connection:
    name: my-foundry-connection
  output:
    result: Local.ToolResult

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
serverUrl Yes URL do servidor MCP
serverLabel Não Rótulo legível para o servidor
toolName Yes Nome da ferramenta a ser invocada
conversationId Não Identificador de contexto de conversa
requireApproval Não Se é necessário exigir aprovação do usuário
arguments Não Argumentos a serem passados para a ferramenta
headers Não Cabeçalhos HTTP personalizados para a solicitação
connection.name Não Conexão nomeada para cenários hospedados (conecta-se ao ProjectConnectionId na Foundry; ainda não tem suporte total)
output.result Não Caminho para armazenar o resultado da ferramenta
output.messages Não Caminho para armazenar mensagens de resultado
output.autoSend Não Enviar automaticamente o resultado para o usuário

Instalação do C# para InvokeMcpTool:

Configure o McpToolHandler na sua fábrica de fluxo de trabalho:

using Azure.Core;
using Azure.Identity;
using Microsoft.Agents.AI.Workflows.Declarative;

// Create MCP tool handler with authentication callback
DefaultAzureCredential credential = new();
DefaultMcpToolHandler mcpToolHandler = new(
    httpClientProvider: async (serverUrl, cancellationToken) =>
    {
        if (serverUrl.StartsWith("https://mcp.ai.azure.com", StringComparison.OrdinalIgnoreCase))
        {
            // Acquire token for Azure MCP server
            AccessToken token = await credential.GetTokenAsync(
                new TokenRequestContext(["https://mcp.ai.azure.com/.default"]),
                cancellationToken);

            HttpClient httpClient = new();
            httpClient.DefaultRequestHeaders.Authorization =
                new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token.Token);
            return httpClient;
        }

        // Return null for servers that don't require authentication
        return null;
    });

// Configure workflow factory with MCP handler
WorkflowFactory workflowFactory = new("workflow.yaml", foundryEndpoint)
{
    McpToolHandler = mcpToolHandler
};

Ações com Intervenção Humana

Pergunta

Faz uma pergunta ao usuário e armazena a resposta.

- kind: Question
  id: ask_name
  displayName: Ask for user name
  question:
    text: "What is your name?"
  variable: Local.userName
  default: "Guest"

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
question.text Yes A pergunta a ser feita
variable Yes Caminho para armazenar a resposta
default Não Valor padrão se nenhuma resposta

SolicitarEntradaExterna

Solicita a entrada de um sistema ou processo externo.

- kind: RequestExternalInput
  id: request_approval
  displayName: Request manager approval
  prompt:
    text: "Please provide approval for this request."
  variable: Local.approvalResult
  default: "pending"

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
prompt.text Yes Descrição da entrada necessária
variable Yes Caminho para armazenar a entrada
default Não Valor padrão

Ações de controle de fluxo de trabalho

EndWorkflow

Encerra a execução do fluxo de trabalho.

- kind: EndWorkflow
  id: finish
  displayName: End workflow

EndConversation

Termina a conversa atual.

- kind: EndConversation
  id: end_chat
  displayName: End conversation

CreateConversation

Cria um novo contexto de conversa.

- kind: CreateConversation
  id: create_new_conv
  displayName: Create new conversation
  conversationId: Local.NewConversationId

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
conversationId Yes Caminho para armazenar a nova ID de conversa

Ações de Conversa (somente C#)

AdicionarMensagemConversa

Adiciona uma mensagem a um thread de conversa.

- kind: AddConversationMessage
  id: add_system_message
  displayName: Add system context
  conversationId: =System.ConversationId
  message:
    role: system
    content: =Local.contextInfo

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
conversationId Yes Identificador de conversação de destino
message Yes Mensagem a ser adicionada
message.role Yes Função de mensagem (sistema, usuário, assistente)
message.content Yes Conteúdo da mensagem

CopiarMensagensDaConversa

Copia mensagens de uma conversa para outra.

- kind: CopyConversationMessages
  id: copy_context
  displayName: Copy conversation context
  sourceConversationId: =Local.SourceConversation
  targetConversationId: =System.ConversationId
  limit: 10

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
sourceConversationId Yes Identificador da conversa de origem
targetConversationId Yes Identificador de conversação de destino
limit Não Número máximo de mensagens a serem copiadas

RecuperarMensagemDeConversa

Recupera uma mensagem específica de uma conversa.

- kind: RetrieveConversationMessage
  id: get_message
  displayName: Get specific message
  conversationId: =System.ConversationId
  messageId: =Local.targetMessageId
  variable: Local.retrievedMessage

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
conversationId Yes Identificador de conversa
messageId Yes Identificador de mensagem a ser recuperado
variable Yes Caminho para armazenar a mensagem recuperada

RecuperarMensagensDeConversa

Recupera várias mensagens de uma conversa.

- kind: RetrieveConversationMessages
  id: get_history
  displayName: Get conversation history
  conversationId: =System.ConversationId
  limit: 20
  newestFirst: true
  variable: Local.conversationHistory

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
conversationId Yes Identificador de conversa
limit Não Máximo de mensagens a serem recuperadas (padrão: 20)
newestFirst Não Retornar em ordem decrescente
after Não Cursor para paginação
before Não Cursor para paginação
variable Yes Caminho para armazenar mensagens recuperadas

Referência rápida de ações

Ação Categoria C# Python DESCRIÇÃO
SetVariable Variable Definir uma única variável
SetMultipleVariables Variable Definir várias variáveis
SetTextVariable Variable Definir uma variável de texto
AppendValue Variable Acrescentar à lista/string
ResetVariable Variable Limpar uma variável
ClearAllVariables Variable Limpar todas as variáveis
ParseValue Variable Analisar/transformar dados
EditTableV2 Variable Modificar dados da tabela
If Fluxo de controle Ramificação condicional
ConditionGroup Fluxo de controle Comutador de várias ramificações
Foreach Fluxo de controle Iterar pela coleção
RepeatUntil Fluxo de controle Repita o loop enquanto a condição for verdadeira
BreakLoop Fluxo de controle Sair do loop atual
ContinueLoop Fluxo de controle Pular para a próxima iteração
GotoAction Fluxo de controle Saltar para a ação por ID
SendActivity Saída Enviar mensagem ao usuário
EmitEvent Saída Emitir evento personalizado
InvokeAzureAgent Agente Chamar o agente de IA do Azure
InvokeFunctionTool Tool Invocar função diretamente
InvokeMcpTool Tool Invocar ferramenta de servidor MCP
Question Human-in-the-Loop Fazer uma pergunta ao usuário
Confirmation Human-in-the-Loop Confirmação sim/não
RequestExternalInput Human-in-the-Loop Solicitar entrada externa
WaitForInput Human-in-the-Loop Aguarde a entrada
EndWorkflow Controle de fluxo de trabalho Encerrar fluxo de trabalho
EndConversation Controle de fluxo de trabalho Encerrar conversa
CreateConversation Controle de fluxo de trabalho Criar uma nova conversa
AddConversationMessage Conversa Adicionar mensagem ao thread
CopyConversationMessages Conversa Copiar mensagens
RetrieveConversationMessage Conversa Obter uma única mensagem
RetrieveConversationMessages Conversa Obter várias mensagens

Padrões Avançados

Orquestração de múltiplos agentes

Pipeline do Agente Sequencial

Passe o trabalho por vários agentes em sequência.

#
# Sequential agent pipeline for content creation
#
kind: Workflow
trigger:

  kind: OnConversationStart
  id: content_workflow
  actions:

    # First agent: Research
    - kind: InvokeAzureAgent
      id: invoke_researcher
      displayName: Research phase
      conversationId: =System.ConversationId
      agent:
        name: ResearcherAgent

    # Second agent: Write draft
    - kind: InvokeAzureAgent
      id: invoke_writer
      displayName: Writing phase
      conversationId: =System.ConversationId
      agent:
        name: WriterAgent

    # Third agent: Edit
    - kind: InvokeAzureAgent
      id: invoke_editor
      displayName: Editing phase
      conversationId: =System.ConversationId
      agent:
        name: EditorAgent

Instalação do C#:

using Azure.AI.Projects;
using Azure.AI.Projects.OpenAI;
using Azure.Identity;

// Ensure agents exist in Foundry
AIProjectClient aiProjectClient = new(foundryEndpoint, new DefaultAzureCredential());

await aiProjectClient.CreateAgentAsync(
    agentName: "ResearcherAgent",
    agentDefinition: new DeclarativeAgentDefinition(modelName)
    {
        Instructions = "You are a research specialist..."
    },
    agentDescription: "Research agent for content pipeline");

// Create and run workflow
WorkflowFactory workflowFactory = new("content-pipeline.yaml", foundryEndpoint);
WorkflowRunner runner = new();
await runner.ExecuteAsync(workflowFactory.CreateWorkflow, "Create content about AI");

Roteamento de Agente Condicional

Encaminhe solicitações para diferentes agentes com base nas condições.

#
# Route to specialized support agents based on category
#
kind: Workflow
trigger:

  kind: OnConversationStart
  id: support_router
  actions:

    # Capture category from user input or set via another action
    - kind: SetVariable
      id: set_category
      variable: Local.category
      value: =System.LastMessage.Text

    - kind: ConditionGroup
      id: route_request
      displayName: Route to appropriate agent
      conditions:
        - condition: =Local.category = "billing"
          id: billing_route
          actions:
            - kind: InvokeAzureAgent
              id: billing_agent
              agent:
                name: BillingAgent
              conversationId: =System.ConversationId
        - condition: =Local.category = "technical"
          id: technical_route
          actions:
            - kind: InvokeAzureAgent
              id: technical_agent
              agent:
                name: TechnicalAgent
              conversationId: =System.ConversationId
      elseActions:
        - kind: InvokeAzureAgent
          id: general_agent
          agent:
            name: GeneralAgent
          conversationId: =System.ConversationId

Padrões de integração de ferramentas

Pré-carregamento de dados com InvokeFunctionTool

Buscar dados antes de chamar um agente:

#
# Pre-fetch menu data before agent interaction
#
kind: Workflow
trigger:

  kind: OnConversationStart
  id: menu_workflow
  actions:
    # Pre-fetch today's specials
    - kind: InvokeFunctionTool
      id: get_specials
      functionName: GetSpecials
      requireApproval: true
      output:
        autoSend: true
        result: Local.Specials

    # Agent uses pre-fetched data
    - kind: InvokeAzureAgent
      id: menu_agent
      conversationId: =System.ConversationId
      agent:
        name: MenuAgent
      input:
        messages: =UserMessage("Describe today's specials: " & Local.Specials)

Integração de ferramentas do MCP

Chame o servidor externo usando o MCP:

#
# Search documentation using MCP
#
kind: Workflow
trigger:

  kind: OnConversationStart
  id: docs_search
  actions:

    - kind: SetVariable
      variable: Local.SearchQuery
      value: =System.LastMessage.Text

    # Search Microsoft Learn
    - kind: InvokeMcpTool
      id: search_docs
      serverUrl: https://learn.microsoft.com/api/mcp
      toolName: microsoft_docs_search
      conversationId: =System.ConversationId
      arguments:
        query: =Local.SearchQuery
      output:
        result: Local.SearchResults
        autoSend: true

    # Summarize results with agent
    - kind: InvokeAzureAgent
      id: summarize
      agent:
        name: SummaryAgent
      conversationId: =System.ConversationId
      input:
        messages: =UserMessage("Summarize these search results")

Pré-requisitos

Antes de começar, verifique se você tem:

  • O Python 3.10 – 3.13 (o Python 3.14 ainda não tem suporte devido à compatibilidade do PowerFx)
  • O pacote declarativo do Agent Framework instalado:
pip install agent-framework-declarative --pre

Este pacote incorpora o subjacente automaticamente agent-framework-core.

Seu primeiro fluxo de trabalho declarativo

Vamos criar um fluxo de trabalho simples que receba um usuário pelo nome.

Etapa 1: Criar o arquivo YAML

Crie um arquivo chamado greeting-workflow.yaml:

name: greeting-workflow
description: A simple workflow that greets the user

inputs:
  name:
    type: string
    description: The name of the person to greet

actions:
  # Set a greeting prefix
  - kind: SetVariable
    id: set_greeting
    displayName: Set greeting prefix
    variable: Local.greeting
    value: Hello

  # Build the full message using an expression
  - kind: SetVariable
    id: build_message
    displayName: Build greeting message
    variable: Local.message
    value: =Concat(Local.greeting, ", ", Workflow.Inputs.name, "!")

  # Send the greeting to the user
  - kind: SendActivity
    id: send_greeting
    displayName: Send greeting to user
    activity:
      text: =Local.message

  # Store the result in outputs
  - kind: SetVariable
    id: set_output
    displayName: Store result in outputs
    variable: Workflow.Outputs.greeting
    value: =Local.message

Etapa 2: Carregar e executar o fluxo de trabalho

Crie um arquivo Python para executar o fluxo de trabalho:

import asyncio
from pathlib import Path

from agent_framework.declarative import WorkflowFactory


async def main() -> None:
    """Run the greeting workflow."""
    # Create a workflow factory
    factory = WorkflowFactory()

    # Load the workflow from YAML
    workflow_path = Path(__file__).parent / "greeting-workflow.yaml"
    workflow = factory.create_workflow_from_yaml_path(workflow_path)

    print(f"Loaded workflow: {workflow.name}")
    print("-" * 40)

    # Run with a name input
    result = await workflow.run({"name": "Alice"})
    for output in result.get_outputs():
        print(f"Output: {output}")


if __name__ == "__main__":
    asyncio.run(main())

Saída esperada

Loaded workflow: greeting-workflow
----------------------------------------
Output: Hello, Alice!

Conceitos principais

Namespaces de Variáveis

Fluxos de trabalho declarativos usam variáveis com espaçamento de nomes para organizar o estado:

Namespace DESCRIÇÃO Example
Local.* Variáveis locais para o fluxo de trabalho Local.message
Workflow.Inputs.* Parâmetros de entrada Workflow.Inputs.name
Workflow.Outputs.* Valores de saída Workflow.Outputs.result
System.* Valores fornecidos pelo sistema System.ConversationId

Linguagem de expressão

Os valores prefixados com = são avaliados como expressões:

# Literal value (no evaluation)
value: Hello

# Expression (evaluated at runtime)
value: =Concat("Hello, ", Workflow.Inputs.name)

As funções comuns incluem:

  • Concat(str1, str2, ...) - Concatenar cadeias de caracteres
  • If(condition, trueValue, falseValue) - Expressão condicional
  • IsBlank(value) – Verificar se o valor está vazio

Tipos de ação

Os fluxos de trabalho declarativos dão suporte a vários tipos de ação:

Categoria Ações
Gerenciamento de variáveis SetVariable, SetMultipleVariables, , AppendValueResetVariable
Fluxo de controle If, ConditionGroup, Foreach, RepeatUntil, , BreakLoop, ContinueLoop, GotoAction
Saída SendActivity, EmitEvent
Invocação do Agente InvokeAzureAgent
Invocação de Ferramenta InvokeFunctionTool
Human-in-the-Loop Question, Confirmation, , RequestExternalInputWaitForInput
Controle de fluxo de trabalho EndWorkflow EndConversation CreateConversation

Referência de ações

As ações são os blocos de construção de fluxos de trabalho declarativos. Cada ação executa uma operação específica e as ações são executadas sequencialmente na ordem em que aparecem no arquivo YAML.

Estrutura de ação

Todas as ações compartilham propriedades comuns:

- kind: ActionType      # Required: The type of action
  id: unique_id         # Optional: Unique identifier for referencing
  displayName: Name     # Optional: Human-readable name for logging
  # Action-specific properties...

Ações de gerenciamento de variáveis

DefinirVariável

Define uma variável como um valor especificado.

- kind: SetVariable
  id: set_greeting
  displayName: Set greeting message
  variable: Local.greeting
  value: Hello World

Com uma expressão:

- kind: SetVariable
  variable: Local.fullName
  value: =Concat(Workflow.Inputs.firstName, " ", Workflow.Inputs.lastName)

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
variable Yes Caminho da variável (por exemplo, Local.name, Workflow.Outputs.result)
value Yes Valor a ser definido (literal ou expressão)

Observação

Python também dá suporte ao tipo de ação SetValue, que usa path em vez da propriedade-alvo variable. Ambos SetVariable (com variable) e SetValue (com path) alcançam o mesmo resultado. Por exemplo:

- kind: SetValue
  id: set_greeting
  path: Local.greeting
  value: Hello World

SetMultipleVariables

Define várias variáveis em uma única ação.

- kind: SetMultipleVariables
  id: initialize_vars
  displayName: Initialize variables
  variables:
    Local.counter: 0
    Local.status: pending
    Local.message: =Concat("Processing order ", Workflow.Inputs.orderId)

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
variables Yes Mapa de caminhos variáveis para valores

AppendValue

Acrescenta um valor a uma lista ou concatena a uma string.

- kind: AppendValue
  id: add_item
  variable: Local.items
  value: =Workflow.Inputs.newItem

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
variable Yes Caminho de variável a anexar
value Yes Valor a ser acrescentado

ResetVariable

Limpa o valor de uma variável.

- kind: ResetVariable
  id: clear_counter
  variable: Local.counter

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
variable Yes Caminho da variável a ser redefinido

Ações de fluxo de controle

If

Executa ações condicionalmente com base em uma condição.

- kind: If
  id: check_age
  displayName: Check user age
  condition: =Workflow.Inputs.age >= 18
  then:
    - kind: SendActivity
      activity:
        text: "Welcome, adult user!"
  else:
    - kind: SendActivity
      activity:
        text: "Welcome, young user!"

Condições aninhadas:

- kind: If
  condition: =Workflow.Inputs.role = "admin"
  then:
    - kind: SendActivity
      activity:
        text: "Admin access granted"
  else:
    - kind: If
      condition: =Workflow.Inputs.role = "user"
      then:
        - kind: SendActivity
          activity:
            text: "User access granted"
      else:
        - kind: SendActivity
          activity:
            text: "Access denied"

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
condition Yes Expressão que é avaliada como verdadeiro/falso
then Yes Ações a serem executadas se a condição for verdadeira
else Não Ações a serem executadas se a condição for falsa

ConditionGroup

Avalia várias condições, como uma instrução switch/case.

- kind: ConditionGroup
  id: route_by_category
  displayName: Route based on category
  conditions:
    - condition: =Workflow.Inputs.category = "electronics"
      id: electronics_branch
      actions:
        - kind: SetVariable
          variable: Local.department
          value: Electronics Team
    - condition: =Workflow.Inputs.category = "clothing"
      id: clothing_branch
      actions:
        - kind: SetVariable
          variable: Local.department
          value: Clothing Team
    - condition: =Workflow.Inputs.category = "food"
      id: food_branch
      actions:
        - kind: SetVariable
          variable: Local.department
          value: Food Team
  elseActions:
    - kind: SetVariable
      variable: Local.department
      value: General Support

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
conditions Yes Lista de pares de condição/ações (vitórias na primeira partida)
elseActions Não Ações caso nenhuma condição seja correspondente

Foreach

Itera sobre uma coleção.

- kind: Foreach
  id: process_items
  displayName: Process each item
  source: =Workflow.Inputs.items
  itemName: item
  indexName: index
  actions:
    - kind: SendActivity
      activity:
        text: =Concat("Processing item ", index, ": ", item)

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
source Yes Expressão que retorna uma coleção
itemName Não Nome da variável para item atual (padrão: item)
indexName Não Nome da variável para o índice atual (padrão: index)
actions Yes Ações a serem executadas para cada item

RepeatUntil

Repete ações até que uma condição se torne verdadeira.

- kind: SetVariable
  variable: Local.counter
  value: 0

- kind: RepeatUntil
  id: count_loop
  displayName: Count to 5
  condition: =Local.counter >= 5
  actions:
    - kind: SetVariable
      variable: Local.counter
      value: =Local.counter + 1
    - kind: SendActivity
      activity:
        text: =Concat("Counter: ", Local.counter)

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
condition Yes O loop continua até que isso seja verdadeiro
actions Yes Ações a serem repetidas

BreakLoop

Sai do loop atual imediatamente.

- kind: Foreach
  source: =Workflow.Inputs.items
  actions:
    - kind: If
      condition: =item = "stop"
      then:
        - kind: BreakLoop
    - kind: SendActivity
      activity:
        text: =item

ContinueLoop

Passa para a próxima iteração do loop.

- kind: Foreach
  source: =Workflow.Inputs.numbers
  actions:
    - kind: If
      condition: =item < 0
      then:
        - kind: ContinueLoop
    - kind: SendActivity
      activity:
        text: =Concat("Positive number: ", item)

GotoAction

Salta para uma ação específica usando o ID.

- kind: SetVariable
  id: start_label
  variable: Local.attempts
  value: =Local.attempts + 1

- kind: SendActivity
  activity:
    text: =Concat("Attempt ", Local.attempts)

- kind: If
  condition: =And(Local.attempts < 3, Not(Local.success))
  then:
    - kind: GotoAction
      actionId: start_label

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
actionId Yes Identificador da ação para pular para

Ações de saída

SendActivity

Envia uma mensagem ao usuário.

- kind: SendActivity
  id: send_welcome
  displayName: Send welcome message
  activity:
    text: "Welcome to our service!"

Com uma expressão:

- kind: SendActivity
  activity:
    text: =Concat("Hello, ", Workflow.Inputs.name, "! How can I help you today?")

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
activity Yes A atividade a ser enviada
activity.text Yes Texto da mensagem (literal ou expressão)

EmitirEvento

Emite um evento personalizado.

- kind: EmitEvent
  id: emit_status
  displayName: Emit status event
  eventType: order_status_changed
  data:
    orderId: =Workflow.Inputs.orderId
    status: =Local.newStatus

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
eventType Yes Identificador de tipo para o evento
data Não Dados de carga útil do evento

Ações de invocação do agente

InvokeAzureAgent

Invoca um agente de IA do Azure.

Invocação básica:

- kind: InvokeAzureAgent
  id: call_assistant
  displayName: Call assistant agent
  agent:
    name: AssistantAgent
  conversationId: =System.ConversationId

Na configuração de entrada e saída:

- kind: InvokeAzureAgent
  id: call_analyst
  displayName: Call analyst agent
  agent:
    name: AnalystAgent
  conversationId: =System.ConversationId
  input:
    messages: =Local.userMessage
    arguments:
      topic: =Workflow.Inputs.topic
  output:
    responseObject: Local.AnalystResult
    messages: Local.AnalystMessages
    autoSend: true

Com loop externo (continua até que a condição seja atendida):

- kind: InvokeAzureAgent
  id: support_agent
  agent:
    name: SupportAgent
  input:
    externalLoop:
      when: =Not(Local.IsResolved)
  output:
    responseObject: Local.SupportResult

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
agent.name Yes Nome do agente registrado
conversationId Não Identificador de contexto de conversa
input.messages Não Mensagens a serem enviadas ao agente
input.arguments Não Argumentos adicionais para o agente
input.externalLoop.when Não Condição para continuar o loop do agente
output.responseObject Não Caminho para armazenar a resposta do agente
output.messages Não Caminho para armazenar mensagens de conversa
output.autoSend Não Enviar resposta automaticamente ao usuário

Ações de Invocação de Ferramentas

InvokeFunctionTool

Invoca uma função Python registrada diretamente do fluxo de trabalho sem passar por um agente de IA.

- kind: InvokeFunctionTool
  id: invoke_weather
  displayName: Get weather data
  functionName: get_weather
  arguments:
    location: =Local.location
    unit: =Local.unit
  output:
    result: Local.weatherInfo
    messages: Local.weatherToolCallItems
    autoSend: true

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
functionName Yes Nome da função registrada a ser invocada
arguments Não Argumentos a serem passados para a função
output.result Não Caminho para armazenar o resultado da função
output.messages Não Caminho para armazenar mensagens de função
output.autoSend Não Enviar automaticamente o resultado para o usuário

Configuração do Python para InvokeFunctionTool:

As funções devem ser registradas com o WorkflowFactory usando register_tool:

from agent_framework.declarative import WorkflowFactory

# Define your functions
def get_weather(location: str, unit: str = "F") -> dict:
    """Get weather information for a location."""
    # Your implementation here
    return {"location": location, "temp": 72, "unit": unit}

def format_message(template: str, data: dict) -> str:
    """Format a message template with data."""
    return template.format(**data)

# Register functions with the factory
factory = (
    WorkflowFactory()
    .register_tool("get_weather", get_weather)
    .register_tool("format_message", format_message)
)

# Load and run the workflow
workflow = factory.create_workflow_from_yaml_path("workflow.yaml")
result = await workflow.run({"location": "Seattle", "unit": "F"})

Ações com Intervenção Humana

Pergunta

Faz uma pergunta ao usuário e armazena a resposta.

- kind: Question
  id: ask_name
  displayName: Ask for user name
  question:
    text: "What is your name?"
  variable: Local.userName
  default: "Guest"

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
question.text Yes A pergunta a ser feita
variable Yes Caminho para armazenar a resposta
default Não Valor padrão se nenhuma resposta

Confirmação

Solicita ao usuário uma confirmação sim/não.

- kind: Confirmation
  id: confirm_delete
  displayName: Confirm deletion
  question:
    text: "Are you sure you want to delete this item?"
  variable: Local.confirmed

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
question.text Yes A pergunta de confirmação
variable Yes Caminho para armazenar o resultado booliano

SolicitarEntradaExterna

Solicita a entrada de um sistema ou processo externo.

- kind: RequestExternalInput
  id: request_approval
  displayName: Request manager approval
  prompt:
    text: "Please provide approval for this request."
  variable: Local.approvalResult
  default: "pending"

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
prompt.text Yes Descrição da entrada necessária
variable Yes Caminho para armazenar a entrada
default Não Valor padrão

WaitForInput

Pausa o fluxo de trabalho e aguarda a entrada externa.

- kind: WaitForInput
  id: wait_for_response
  variable: Local.externalResponse

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
variable Yes Caminho para armazenar os dados de entrada quando recebidos

Ações de controle de fluxo de trabalho

EndWorkflow

Encerra a execução do fluxo de trabalho.

- kind: EndWorkflow
  id: finish
  displayName: End workflow

EndConversation

Termina a conversa atual.

- kind: EndConversation
  id: end_chat
  displayName: End conversation

CreateConversation

Cria um novo contexto de conversa.

- kind: CreateConversation
  id: create_new_conv
  displayName: Create new conversation
  conversationId: Local.NewConversationId

Propriedades:

Propriedade Obrigatório DESCRIÇÃO
conversationId Yes Caminho para armazenar a nova ID de conversa

Referência rápida de ações

Ação Categoria DESCRIÇÃO
SetVariable Variable Definir uma única variável
SetMultipleVariables Variable Definir várias variáveis
AppendValue Variable Acrescentar à lista/string
ResetVariable Variable Limpar uma variável
If Fluxo de controle Ramificação condicional
ConditionGroup Fluxo de controle Comutador de várias ramificações
Foreach Fluxo de controle Iterar pela coleção
RepeatUntil Fluxo de controle Repita o loop enquanto a condição for verdadeira
BreakLoop Fluxo de controle Sair do loop atual
ContinueLoop Fluxo de controle Pular para a próxima iteração
GotoAction Fluxo de controle Saltar para a ação por ID
SendActivity Saída Enviar mensagem ao usuário
EmitEvent Saída Emitir evento personalizado
InvokeAzureAgent Agente Chamar o agente de IA do Azure
InvokeFunctionTool Tool Invocar função registrada
Question Human-in-the-Loop Fazer uma pergunta ao usuário
Confirmation Human-in-the-Loop Confirmação sim/não
RequestExternalInput Human-in-the-Loop Solicitar entrada externa
WaitForInput Human-in-the-Loop Aguarde a entrada
EndWorkflow Controle de fluxo de trabalho Encerrar fluxo de trabalho
EndConversation Controle de fluxo de trabalho Encerrar conversa
CreateConversation Controle de fluxo de trabalho Criar uma nova conversa

Sintaxe de expressão

Fluxos de trabalho declarativos usam uma linguagem de expressão semelhante ao PowerFx para gerenciar valores dinâmicos de computação e de estado. Os valores prefixados com = são avaliados como expressões em runtime.

Detalhes do namespace da variável

Namespace DESCRIÇÃO Acesso
Local.* Variáveis locais de fluxo de trabalho Leitura/gravação
Workflow.Inputs.* Parâmetros de entrada passados para o fluxo de trabalho Somente leitura
Workflow.Outputs.* Valores retornados do fluxo de trabalho Leitura/gravação
System.* Valores fornecidos pelo sistema Somente leitura
Agent.* Resultados de invocações de agente Somente leitura

Variáveis do sistema

Variable DESCRIÇÃO
System.ConversationId Identificador de conversa atual
System.LastMessage A mensagem mais recente
System.Timestamp Data/hora atual

Variáveis de agente

Depois de invocar um agente, acesse os dados de resposta por meio da variável de saída:

actions:
  - kind: InvokeAzureAgent
    id: call_assistant
    agent:
      name: MyAgent
    output:
      responseObject: Local.AgentResult

  # Access agent response
  - kind: SendActivity
    activity:
      text: =Local.AgentResult.text

Valores literais vs. de expressão

# Literal string (stored as-is)
value: Hello World

# Expression (evaluated at runtime)
value: =Concat("Hello ", Workflow.Inputs.name)

# Literal number
value: 42

# Expression returning a number
value: =Workflow.Inputs.quantity * 2

Operações de cadeia de caracteres

Concat

Concatenar várias cadeias de caracteres:

value: =Concat("Hello, ", Workflow.Inputs.name, "!")
# Result: "Hello, Alice!" (if Workflow.Inputs.name is "Alice")

value: =Concat(Local.firstName, " ", Local.lastName)
# Result: "John Doe" (if firstName is "John" and lastName is "Doe")

IsBlank

Verifique se um valor está vazio ou indefinido:

condition: =IsBlank(Workflow.Inputs.optionalParam)
# Returns true if the parameter is not provided

value: =If(IsBlank(Workflow.Inputs.name), "Guest", Workflow.Inputs.name)
# Returns "Guest" if name is blank, otherwise returns the name

Expressões condicionais

Função If

Retornar valores diferentes com base em uma condição:

value: =If(Workflow.Inputs.age < 18, "minor", "adult")

value: =If(Local.count > 0, "Items found", "No items")

# Nested conditions
value: =If(Workflow.Inputs.role = "admin", "Full access", If(Workflow.Inputs.role = "user", "Limited access", "No access"))

Operadores de comparação

Operador DESCRIÇÃO Example
= Igual a =Workflow.Inputs.status = "active"
<> Não é igual a =Workflow.Inputs.status <> "deleted"
< Menor que =Workflow.Inputs.age < 18
> Maior que =Workflow.Inputs.count > 0
<= Inferior ou igual =Workflow.Inputs.score <= 100
>= Maior ou igual =Workflow.Inputs.quantity >= 1

Funções boolianas

# Or - returns true if any condition is true
condition: =Or(Workflow.Inputs.role = "admin", Workflow.Inputs.role = "moderator")

# And - returns true if all conditions are true
condition: =And(Workflow.Inputs.age >= 18, Workflow.Inputs.hasConsent)

# Not - negates a condition
condition: =Not(IsBlank(Workflow.Inputs.email))

Operações matemáticas

# Addition
value: =Workflow.Inputs.price + Workflow.Inputs.tax

# Subtraction
value: =Workflow.Inputs.total - Workflow.Inputs.discount

# Multiplication
value: =Workflow.Inputs.quantity * Workflow.Inputs.unitPrice

# Division
value: =Workflow.Inputs.total / Workflow.Inputs.count

Exemplos de expressão prática

Categorização de usuário

name: categorize-user
inputs:
  age:
    type: integer
    description: User's age

actions:
  - kind: SetVariable
    variable: Local.age
    value: =Workflow.Inputs.age

  - kind: SetVariable
    variable: Local.category
    value: =If(Local.age < 13, "child", If(Local.age < 20, "teenager", If(Local.age < 65, "adult", "senior")))

  - kind: SendActivity
    activity:
      text: =Concat("You are categorized as: ", Local.category)

  - kind: SetVariable
    variable: Workflow.Outputs.category
    value: =Local.category

Saudação condicional

name: smart-greeting
inputs:
  name:
    type: string
    description: User's name (optional)
  timeOfDay:
    type: string
    description: morning, afternoon, or evening

actions:
  # Set the greeting based on time of day
  - kind: SetVariable
    variable: Local.timeGreeting
    value: =If(Workflow.Inputs.timeOfDay = "morning", "Good morning", If(Workflow.Inputs.timeOfDay = "afternoon", "Good afternoon", "Good evening"))

  # Handle optional name
  - kind: SetVariable
    variable: Local.userName
    value: =If(IsBlank(Workflow.Inputs.name), "friend", Workflow.Inputs.name)

  # Build the full greeting
  - kind: SetVariable
    variable: Local.fullGreeting
    value: =Concat(Local.timeGreeting, ", ", Local.userName, "!")

  - kind: SendActivity
    activity:
      text: =Local.fullGreeting

Validação de entrada

name: validate-order
inputs:
  quantity:
    type: integer
    description: Number of items to order
  email:
    type: string
    description: Customer email

actions:
  # Check if inputs are valid
  - kind: SetVariable
    variable: Local.isValidQuantity
    value: =And(Workflow.Inputs.quantity > 0, Workflow.Inputs.quantity <= 100)

  - kind: SetVariable
    variable: Local.hasEmail
    value: =Not(IsBlank(Workflow.Inputs.email))

  - kind: SetVariable
    variable: Local.isValid
    value: =And(Local.isValidQuantity, Local.hasEmail)

  - kind: If
    condition: =Local.isValid
    then:
      - kind: SendActivity
        activity:
          text: "Order validated successfully!"
    else:
      - kind: SendActivity
        activity:
          text: =If(Not(Local.isValidQuantity), "Invalid quantity (must be 1-100)", "Email is required")

Padrões Avançados

À medida que seus fluxos de trabalho aumentam em complexidade, você precisará de padrões que lidem com processos de várias etapas, coordenação de agente e cenários interativos.

Orquestração de múltiplos agentes

Pipeline do Agente Sequencial

Passe o trabalho por vários agentes em sequência, em que cada agente se baseia no resultado do agente anterior.

Caso de uso: fluxos de criação de conteúdo em que diferentes especialistas trabalham com pesquisa, escrita e edição.

name: content-pipeline
description: Sequential agent pipeline for content creation

kind: Workflow
trigger:
  kind: OnConversationStart
  id: content_workflow
  actions:
    # First agent: Research and analyze
    - kind: InvokeAzureAgent
      id: invoke_researcher
      displayName: Research phase
      conversationId: =System.ConversationId
      agent:
        name: ResearcherAgent

    # Second agent: Write draft based on research
    - kind: InvokeAzureAgent
      id: invoke_writer
      displayName: Writing phase
      conversationId: =System.ConversationId
      agent:
        name: WriterAgent

    # Third agent: Edit and polish
    - kind: InvokeAzureAgent
      id: invoke_editor
      displayName: Editing phase
      conversationId: =System.ConversationId
      agent:
        name: EditorAgent

Configuração do Python:

from agent_framework.declarative import WorkflowFactory

# Create factory and register agents
factory = WorkflowFactory()
factory.register_agent("ResearcherAgent", researcher_agent)
factory.register_agent("WriterAgent", writer_agent)
factory.register_agent("EditorAgent", editor_agent)

# Load and run
workflow = factory.create_workflow_from_yaml_path("content-pipeline.yaml")
result = await workflow.run({"topic": "AI in healthcare"})

Roteamento de Agente Condicional

Encaminhe solicitações para agentes diferentes com base nos resultados intermediários ou de entrada.

Caso de uso: sistemas de suporte que roteiam para agentes especializados com base no tipo de problema.

name: support-router
description: Route to specialized support agents

inputs:
  category:
    type: string
    description: Support category (billing, technical, general)

actions:
  - kind: ConditionGroup
    id: route_request
    displayName: Route to appropriate agent
    conditions:
      - condition: =Workflow.Inputs.category = "billing"
        id: billing_route
        actions:
          - kind: InvokeAzureAgent
            id: billing_agent
            agent:
              name: BillingAgent
            conversationId: =System.ConversationId
      - condition: =Workflow.Inputs.category = "technical"
        id: technical_route
        actions:
          - kind: InvokeAzureAgent
            id: technical_agent
            agent:
              name: TechnicalAgent
            conversationId: =System.ConversationId
    elseActions:
      - kind: InvokeAzureAgent
        id: general_agent
        agent:
          name: GeneralAgent
        conversationId: =System.ConversationId

Agente com Laço Externo

Continue a interação do agente até que uma condição seja atendida, como a resolução do problema.

Caso de uso: suporte a conversas que continuam até que o problema do usuário seja resolvido.

name: support-conversation
description: Continue support until resolved

actions:
  - kind: SetVariable
    variable: Local.IsResolved
    value: false

  - kind: InvokeAzureAgent
    id: support_agent
    displayName: Support agent with external loop
    agent:
      name: SupportAgent
    conversationId: =System.ConversationId
    input:
      externalLoop:
        when: =Not(Local.IsResolved)
    output:
      responseObject: Local.SupportResult

  - kind: SendActivity
    activity:
      text: "Thank you for contacting support. Your issue has been resolved."

Padrões de controle de loop

Conversa de um agente iterativo

Crie conversas de ida e volta entre agentes com iteração controlada.

Caso de uso: cenários de aluno-professor, simulações de debate ou refinamento iterativo.

name: student-teacher
description: Iterative learning conversation between student and teacher

kind: Workflow
trigger:
  kind: OnConversationStart
  id: learning_session
  actions:
    # Initialize turn counter
    - kind: SetVariable
      id: init_counter
      variable: Local.TurnCount
      value: 0

    - kind: SendActivity
      id: start_message
      activity:
        text: =Concat("Starting session for: ", Workflow.Inputs.problem)

    # Student attempts solution (loop entry point)
    - kind: SendActivity
      id: student_label
      activity:
        text: "\n[Student]:"

    - kind: InvokeAzureAgent
      id: student_attempt
      conversationId: =System.ConversationId
      agent:
        name: StudentAgent

    # Teacher reviews
    - kind: SendActivity
      id: teacher_label
      activity:
        text: "\n[Teacher]:"

    - kind: InvokeAzureAgent
      id: teacher_review
      conversationId: =System.ConversationId
      agent:
        name: TeacherAgent
      output:
        messages: Local.TeacherResponse

    # Increment counter
    - kind: SetVariable
      id: increment
      variable: Local.TurnCount
      value: =Local.TurnCount + 1

    # Check completion conditions
    - kind: ConditionGroup
      id: check_completion
      conditions:
        # Success: Teacher congratulated student
        - condition: =Not(IsBlank(Find("congratulations", Local.TeacherResponse)))
          id: success_check
          actions:
            - kind: SendActivity
              activity:
                text: "Session complete - student succeeded!"
            - kind: SetVariable
              variable: Workflow.Outputs.result
              value: success
        # Continue: Under turn limit
        - condition: =Local.TurnCount < 4
          id: continue_check
          actions:
            - kind: GotoAction
              actionId: student_label
      elseActions:
        # Timeout: Reached turn limit
        - kind: SendActivity
          activity:
            text: "Session ended - turn limit reached."
        - kind: SetVariable
          variable: Workflow.Outputs.result
          value: timeout

Laços Baseados em Contador

Implemente loops de contagem tradicionais usando variáveis e GotoAction.

name: counter-loop
description: Process items with a counter

actions:
  - kind: SetVariable
    variable: Local.counter
    value: 0

  - kind: SetVariable
    variable: Local.maxIterations
    value: 5

  # Loop start
  - kind: SetVariable
    id: loop_start
    variable: Local.counter
    value: =Local.counter + 1

  - kind: SendActivity
    activity:
      text: =Concat("Processing iteration ", Local.counter)

  # Your processing logic here
  - kind: SetVariable
    variable: Local.result
    value: =Concat("Result from iteration ", Local.counter)

  # Check if should continue
  - kind: If
    condition: =Local.counter < Local.maxIterations
    then:
      - kind: GotoAction
        actionId: loop_start
    else:
      - kind: SendActivity
        activity:
          text: "Loop complete!"

Saída Antecipada com BreakLoop

Utilize BreakLoop para sair das iterações mais cedo quando uma condição é atendida.

name: search-workflow
description: Search through items and stop when found

actions:
  - kind: SetVariable
    variable: Local.found
    value: false

  - kind: Foreach
    source: =Workflow.Inputs.items
    itemName: currentItem
    actions:
      # Check if this is the item we're looking for
      - kind: If
        condition: =currentItem.id = Workflow.Inputs.targetId
        then:
          - kind: SetVariable
            variable: Local.found
            value: true
          - kind: SetVariable
            variable: Local.result
            value: =currentItem
          - kind: BreakLoop

      - kind: SendActivity
        activity:
          text: =Concat("Checked item: ", currentItem.name)

  - kind: If
    condition: =Local.found
    then:
      - kind: SendActivity
        activity:
          text: =Concat("Found: ", Local.result.name)
    else:
      - kind: SendActivity
        activity:
          text: "Item not found"

Padrões de Intervenção Humana no Processo

Pesquisa Interativa

Colete várias informações do usuário.

name: customer-survey
description: Interactive customer feedback survey

actions:
  - kind: SendActivity
    activity:
      text: "Welcome to our customer feedback survey!"

  # Collect name
  - kind: Question
    id: ask_name
    question:
      text: "What is your name?"
    variable: Local.userName
    default: "Anonymous"

  - kind: SendActivity
    activity:
      text: =Concat("Nice to meet you, ", Local.userName, "!")

  # Collect rating
  - kind: Question
    id: ask_rating
    question:
      text: "How would you rate our service? (1-5)"
    variable: Local.rating
    default: "3"

  # Respond based on rating
  - kind: If
    condition: =Local.rating >= 4
    then:
      - kind: SendActivity
        activity:
          text: "Thank you for the positive feedback!"
    else:
      - kind: Question
        id: ask_improvement
        question:
          text: "What could we improve?"
        variable: Local.feedback

  # Collect additional feedback
  - kind: RequestExternalInput
    id: additional_comments
    prompt:
      text: "Any additional comments? (optional)"
    variable: Local.comments
    default: ""

  # Summary
  - kind: SendActivity
    activity:
      text: =Concat("Thank you, ", Local.userName, "! Your feedback has been recorded.")

  - kind: SetVariable
    variable: Workflow.Outputs.survey
    value:
      name: =Local.userName
      rating: =Local.rating
      feedback: =Local.feedback
      comments: =Local.comments

Fluxo de trabalho de aprovação

Solicite aprovação antes de prosseguir com uma ação.

name: approval-workflow
description: Request approval before processing

inputs:
  requestType:
    type: string
    description: Type of request
  amount:
    type: number
    description: Request amount

actions:
  - kind: SendActivity
    activity:
      text: =Concat("Processing ", Workflow.Inputs.requestType, " request for $", Workflow.Inputs.amount)

  # Check if approval is needed
  - kind: If
    condition: =Workflow.Inputs.amount > 1000
    then:
      - kind: SendActivity
        activity:
          text: "This request requires manager approval."

      - kind: Confirmation
        id: get_approval
        question:
          text: =Concat("Do you approve this ", Workflow.Inputs.requestType, " request for $", Workflow.Inputs.amount, "?")
        variable: Local.approved

      - kind: If
        condition: =Local.approved
        then:
          - kind: SendActivity
            activity:
              text: "Request approved. Processing..."
          - kind: SetVariable
            variable: Workflow.Outputs.status
            value: approved
        else:
          - kind: SendActivity
            activity:
              text: "Request denied."
          - kind: SetVariable
            variable: Workflow.Outputs.status
            value: denied
    else:
      - kind: SendActivity
        activity:
          text: "Request auto-approved (under threshold)."
      - kind: SetVariable
        variable: Workflow.Outputs.status
        value: auto_approved

Orquestração complexa

Fluxo de Trabalho de Tíquetes de Suporte

Um exemplo abrangente que combina vários padrões: roteamento de agente, lógica condicional e gerenciamento de conversa.

name: support-ticket-workflow
description: Complete support ticket handling with escalation

kind: Workflow
trigger:
  kind: OnConversationStart
  id: support_workflow
  actions:
    # Initial self-service agent
    - kind: InvokeAzureAgent
      id: self_service
      displayName: Self-service agent
      agent:
        name: SelfServiceAgent
      conversationId: =System.ConversationId
      input:
        externalLoop:
          when: =Not(Local.ServiceResult.IsResolved)
      output:
        responseObject: Local.ServiceResult

    # Check if resolved by self-service
    - kind: If
      condition: =Local.ServiceResult.IsResolved
      then:
        - kind: SendActivity
          activity:
            text: "Issue resolved through self-service."
        - kind: SetVariable
          variable: Workflow.Outputs.resolution
          value: self_service
        - kind: EndWorkflow
          id: end_resolved

    # Create support ticket
    - kind: SendActivity
      activity:
        text: "Creating support ticket..."

    - kind: SetVariable
      variable: Local.TicketId
      value: =Concat("TKT-", System.ConversationId)

    # Route to appropriate team
    - kind: ConditionGroup
      id: route_ticket
      conditions:
        - condition: =Local.ServiceResult.Category = "technical"
          id: technical_route
          actions:
            - kind: InvokeAzureAgent
              id: technical_support
              agent:
                name: TechnicalSupportAgent
              conversationId: =System.ConversationId
              output:
                responseObject: Local.TechResult
        - condition: =Local.ServiceResult.Category = "billing"
          id: billing_route
          actions:
            - kind: InvokeAzureAgent
              id: billing_support
              agent:
                name: BillingSupportAgent
              conversationId: =System.ConversationId
              output:
                responseObject: Local.BillingResult
      elseActions:
        # Escalate to human
        - kind: SendActivity
          activity:
            text: "Escalating to human support..."
        - kind: SetVariable
          variable: Workflow.Outputs.resolution
          value: escalated

    - kind: SendActivity
      activity:
        text: =Concat("Ticket ", Local.TicketId, " has been processed.")

Práticas recomendadas

Convenções de nomenclatura

Use nomes claros e descritivos para ações e variáveis:

# Good
- kind: SetVariable
  id: calculate_total_price
  variable: Local.orderTotal

# Avoid
- kind: SetVariable
  id: sv1
  variable: Local.x

Organizando fluxos de trabalho grandes

Dividir fluxos de trabalho complexos em seções lógicas com comentários:

actions:
  # === INITIALIZATION ===
  - kind: SetVariable
    id: init_status
    variable: Local.status
    value: started

  # === DATA COLLECTION ===
  - kind: Question
    id: collect_name
    # ...

  # === PROCESSING ===
  - kind: InvokeAzureAgent
    id: process_request
    # ...

  # === OUTPUT ===
  - kind: SendActivity
    id: send_result
    # ...

Tratamento de erros

Use verificações condicionais para lidar com possíveis problemas:

actions:
  - kind: SetVariable
    variable: Local.hasError
    value: false

  - kind: InvokeAzureAgent
    id: call_agent
    agent:
      name: ProcessingAgent
    output:
      responseObject: Local.AgentResult

  - kind: If
    condition: =IsBlank(Local.AgentResult)
    then:
      - kind: SetVariable
        variable: Local.hasError
        value: true
      - kind: SendActivity
        activity:
          text: "An error occurred during processing."
    else:
      - kind: SendActivity
        activity:
          text: =Local.AgentResult.message

Estratégias de teste

  1. Inicie simples: teste os fluxos básicos antes de adicionar complexidade
  2. Usar valores padrão: fornecer padrões sensatos para entradas
  3. Adicionar registro em log: usar o SendActivity para depurar durante o desenvolvimento
  4. Casos limite de teste: Verificar o comportamento com entradas ausentes ou inválidas
# Debug logging example
- kind: SendActivity
  id: debug_log
  activity:
    text: =Concat("[DEBUG] Current state: counter=", Local.counter, ", status=", Local.status)

Próximas etapas

  • Exemplos de fluxo de trabalho declarativo do C# – explore exemplos de trabalho completos, incluindo:
    • StudentTeacher – Conversa de vários agentes com aprendizado iterativo
    • InvokeMcpTool – Integração de ferramentas do servidor MCP
    • InvokeFunctionTool – Invocação de função direta de fluxos de trabalho
    • FunctionTools – Agente com ferramentas de função
    • ToolApproval – Aprovação humana para execução da ferramenta
    • CustomerSupport – Fluxo de trabalho complexo do tíquete de suporte
    • DeepResearch – Fluxo de trabalho de pesquisa com vários agentes