Deklaratywne przepływy pracy — omówienie

Deklaratywne przepływy pracy umożliwiają definiowanie logiki przepływu pracy przy użyciu plików konfiguracji YAML zamiast pisania kodu programowego. Takie podejście ułatwia odczytywanie, modyfikowanie i udostępnianie przepływów pracy w zespołach.

Overview

W przypadku deklaratywnych przepływów pracy opisano, co powinien robić przepływ pracy, a nie sposób go implementować. Platforma obsługuje wykonywanie bazowe, konwertując definicje YAML na wykonywalne wykresy przepływu pracy.

Najważniejsze korzyści:

  • Format czytelny: składnia YAML jest łatwa do zrozumienia, nawet dla osób, które nie są programistami.
  • Przenośne: definicje przepływów pracy można udostępniać, wersjonować i modyfikować bez zmian kodu
  • Szybka iteracja: Modyfikowanie zachowania przepływu pracy przez edytowanie plików konfiguracji
  • Spójna struktura: wstępnie zdefiniowane typy akcji zapewniają, że przepływy pracy są zgodne z najlepszymi rozwiązaniami

Kiedy używać deklaratywnych a programowych przepływów pracy

Scenario Zalecane podejście
Standardowe wzorce aranżacji Deklaratywny
Przepływy pracy, które często się zmieniają Deklaratywny
Osoby niezajmujące się tworzeniem oprogramowania muszą modyfikować przepływy pracy. Deklaratywny
Złożona logika niestandardowa Programmatic
Maksymalna elastyczność i kontrola Programmatic
Integracja z istniejącym kodem w języku Python Programmatic

Podstawowa struktura YAML

Struktura YAML różni się nieco między implementacjami języka C# i Python. Szczegółowe informacje można znaleźć w poniższych sekcjach specyficznych dla języka.

Typy akcji

Deklaratywne przepływy pracy obsługują szeroką gamę rodzajów akcji obejmujących zarządzanie zmiennymi, przepływ sterowania, wywołanie agenta i narzędzia, integrację protokołu HTTP i MCP, człowieka w pętli i kontrolę konwersacji. Pełny materiał referencyjny właściwy dla danego języka znajduje się w każdej z poniższych sekcji; zbiorcze zestawienie dostępności w obu językach można znaleźć w dokumencie Skrócony przewodnik po akcjach na dole tego artykułu.

Struktura YAML w języku C#

Deklaratywne przepływy pracy języka C# używają struktury opartej na wyzwalaczach:

#
# 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

Elementy struktury

Element Wymagane Opis
kind Yes Musi być Workflow
trigger.kind Yes Typ wyzwalacza (zazwyczaj OnConversationStart)
trigger.id Yes Unikatowy identyfikator przepływu pracy
trigger.actions Yes Lista akcji do wykonania

Struktura YAML w Pythonie

Deklaratywne przepływy pracy języka Python używają struktury opartej na nazwach z opcjonalnymi danymi wejściowymi:

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

Elementy struktury

Element Wymagane Opis
name Yes Unikatowy identyfikator przepływu pracy
description No Opis czytelny dla człowieka
inputs No Parametry wejściowe, które akceptuje przepływ pracy
actions Yes Lista akcji do wykonania

Wymagania wstępne

Zanim zaczniesz, upewnij się, że masz:

  • .NET 8.0 lub nowszy
  • Projekt Firmy Microsoft Foundry z co najmniej jednym wdrożonym agentem
  • Zainstalowane następujące pakiety NuGet:
dotnet add package Microsoft.Agents.AI.Workflows.Declarative --prerelease
dotnet add package Microsoft.Agents.AI.Workflows.Declarative.AzureAI --prerelease
  • Jeśli zamierzasz dodać akcję wywołania narzędzia MCP do przepływu pracy, zainstaluj również następujący pakiet NuGet:
dotnet add package Microsoft.Agents.AI.Workflows.Declarative.Mcp --prerelease

Pierwszy deklaratywny przepływ pracy

Utwórzmy prosty przepływ pracy, który wita użytkownika na podstawie ich danych wejściowych.

Krok 1. Tworzenie pliku YAML

Utwórz plik o nazwie 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

Krok 2. Konfigurowanie dostawcy agenta

Utwórz aplikację konsolową w języku C#, aby wykonać przepływ pracy. Najpierw skonfiguruj dostawcę agenta, który łączy się z usługą 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());

Krok 3. Kompilowanie i uruchamianie przepływu pracy

// 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!");

Oczekiwane dane wyjściowe

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

Podstawowe pojęcia

Przestrzenie nazw zmiennych

Deklaratywne przepływy pracy w języku C# używają zmiennych przestrzeni nazw do organizowania stanu:

Namespace Opis Example
Local.* Zmienne lokalne w przepływie pracy Local.message
System.* Wartości dostarczone przez system System.ConversationId, System.LastMessage

Uwaga / Notatka

Deklaratywne przepływy pracy języka C# nie używają Workflow.Inputs ani Workflow.Outputs przestrzeni nazw. Dane wejściowe są odbierane przez System.LastMessage i dane wyjściowe są wysyłane przez SendActivity.

Zmienne systemowe

Variable Opis
System.ConversationId Bieżący identyfikator konwersacji
System.LastMessage Najnowszy komunikat użytkownika
System.LastMessage.Text Zawartość tekstowa ostatniej wiadomości

Język wyrażeń

Wartości poprzedzone prefiksem = są oceniane jako wyrażenia przy użyciu języka wyrażeń PowerFx:

# Literal value (no evaluation)
value: Hello

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

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

Typowe funkcje obejmują:

  • Concat(str1, str2, ...) - Łączenie ciągów
  • If(condition, trueValue, falseValue) - Wyrażenie warunkowe
  • IsBlank(value) — Sprawdzanie, czy wartość jest pusta
  • Upper(text) / Lower(text) - Konwersja wielkości liter
  • Find(searchText, withinText) - Znajdowanie tekstu w ciągu
  • MessageText(message) - Wyodrębnianie tekstu z obiektu wiadomości
  • UserMessage(text) — Tworzenie wiadomości użytkownika na podstawie tekstu
  • AgentMessage(text) — Tworzenie wiadomości agenta na podstawie tekstu

Opcje konfiguracji

Klasa DeclarativeWorkflowOptions udostępnia konfigurację wykonywania przepływu pracy:

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,

    // HTTP request handler for HttpRequestAction actions (optional)
    HttpRequestHandler = new DefaultHttpRequestHandler(),

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

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

Konfiguracja dostawcy agenta

Element AzureAgentProvider łączy przepływ pracy z agentami usługi 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,
};

Wykonywanie przepływu pracy

Użyj InProcessExecution do uruchamiania przepływów pracy i przetwarzania zdarzeń.

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;
    }
}

Wznawianie z punktów kontrolnych

Przepływy pracy można wznowić z punktów kontrolnych w celu zapewnienia odporności na awarie.

// 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...
}

Tworzenie punktów kontrolnych AOT i Trim-Aggressive

Gdy publikujesz z użyciem Native AOT (dotnet publish -p:PublishAot=true) lub w inny sposób wyłączysz awaryjny mechanizm System.Text.Json oparty na refleksji (<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>), domyślne wywołanie CheckpointManager.CreateJson(store) kończy się niepowodzeniem podczas zatwierdzania punktu kontrolnego lub rehydracji.

Pakiet declarative-workflow zawiera wygenerowaną ze źródła instancję JsonSerializerOptions, DeclarativeWorkflowJsonOptions.Default, która obejmuje każdy typ z pakietu declarative-package przechodzący przez potok przetwarzania punktów kontrolnych. Przekaż go jako drugi argument do elementu CheckpointManager.CreateJson:

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

// AOT-safe: type info is resolved via the source-generated JsonSerializerContext,
// so no runtime reflection is required.
CheckpointManager checkpointManager = CheckpointManager.CreateJson(
    store,
    DeclarativeWorkflowJsonOptions.Default);

Uwaga / Notatka

Przekazywanie DeclarativeWorkflowJsonOptions.Default jest bezpieczne także w środowiskach innych niż AOT. Jest to bezpośredni zamiennik dla CheckpointManager.CreateJson(store) — aplikacje korzystające z refleksji nie odnotują żadnej zmiany w działaniu. Zastosuj go bezwarunkowo, aby ten sam kod działał, jeśli później opublikujesz go za pomocą usługi AOT lub przycinania.

DeclarativeWorkflowJsonOptions jest oznaczony jako [Experimental("MAAI001")]. Wyłącz diagnostykę w miejscu wywołania lub w pliku projektu:

<PropertyGroup>
  <NoWarn>$(NoWarn);MAAI001</NoWarn>
</PropertyGroup>

Rejestrowanie typów zdefiniowanych przez użytkownika

Jeśli dane wejściowe przepływu pracy, niestandardowe ActionExecutorResult.Result ładunki lub nietypowe argumenty żądania zatwierdzenia są typami zdefiniowanymi przez użytkownika, sklonuj Default i dołącz własny moduł rozpoznawania wygenerowany przez źródło:

// Compose: declarative-package types + your app's source-gen context.
JsonSerializerOptions options = new(DeclarativeWorkflowJsonOptions.Default);
options.TypeInfoResolverChain.Add(MyAppJsonContext.Default);
options.MakeReadOnly();

CheckpointManager checkpointManager = CheckpointManager.CreateJson(store, options);

W tym przypadku MyAppJsonContext to JsonSerializerContext, które definiujesz dla typów swojej aplikacji:

[JsonSourceGenerationOptions(JsonSerializerDefaults.Web)]
[JsonSerializable(typeof(MyWorkflowInput))]
[JsonSerializable(typeof(MyCustomResult))]
internal sealed partial class MyAppJsonContext : JsonSerializerContext;

Tip

Aby zobaczyć kompletny przykład, który można uruchomić — obejmujący przepływ pracy w YAML, agenta opartego na AzureCliCredential oraz obserwowalny tryb „usuń opcje, aby zobaczyć błąd” — zobacz przykład AotCheckpointing w dotnet/samples/03-workflows/Declarative/AotCheckpointing. Przykład .csproj ustawia JsonSerializerIsReflectionEnabledByDefault=false, aby odtworzyć tryb awarii AOT bez konieczności pełnej publikacji AOT.

Referencja Akcji

Akcje to bloki konstrukcyjne deklaratywnych przepływów pracy. Każda akcja wykonuje określoną operację, a akcje są wykonywane sekwencyjnie w kolejności, w której są wyświetlane w pliku YAML.

Struktura akcji

Wszystkie akcje mają wspólne właściwości:

- 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...

Akcje zarządzania zmiennymi

SetVariable

Ustawia zmienną na określoną wartość.

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

Z wyrażeniem:

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

Właściwości:

Własność Wymagane Opis
variable Yes Ścieżka zmiennej (np. Local.name, Workflow.Outputs.result)
value Yes Wartość do ustawienia (literał lub wyrażenie)

SetMultipleVariables

Ustawia wiele zmiennych w jednej akcji.

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

Właściwości:

Własność Wymagane Opis
variables Yes Mapa ścieżek zmiennych do wartości

SetTextVariable

Ustawia zmienną tekstową na określoną wartość ciągu.

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

Właściwości:

Własność Wymagane Opis
variable Yes Ścieżka zmiennej dla wartości tekstowej
value Yes Wartość tekstowa do ustawienia

ResetVariable

Czyści wartość zmiennej.

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

Właściwości:

Własność Wymagane Opis
variable Yes Ścieżka zmiennej do zresetowania

Wyczyść wszystkie zmienne

Resetuje wszystkie zmienne w bieżącym kontekście.

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

ParseValue

Wyodrębnia lub konwertuje dane na format do użytku.

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

Właściwości:

Własność Wymagane Opis
source Yes Wyrażenie zwracające wartość do parsowania
variable Yes Zmienna ścieżka do przechowywania przeanalizowanego wyniku

EditTableV2

Modyfikuje dane w formacie tabeli ustrukturyzowanej.

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

Właściwości:

Własność Wymagane Opis
table Yes Ścieżka do tabeli zmiennych
operation Yes Typ operacji (dodawanie, aktualizowanie, usuwanie)
row Yes Dane wiersza dla operacji

Akcje sterowania przepływem

If

Wykonuje akcje warunkowo w zależności od spełnienia warunku.

- 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!"

Właściwości:

Własność Wymagane Opis
condition Yes Wyrażenie, które ocenia się jako prawda/fałsz
then Yes Akcje do wykonania, jeśli warunek ma wartość true
else No Akcje do wykonania, jeśli warunek ma wartość false

Grupa warunków

Ocenia wiele warunków, takich jak instrukcja 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

Właściwości:

Własność Wymagane Opis
conditions Yes Lista par warunku/akcji (pierwsze zwycięstwo meczu)
elseActions No Działania, jeśli żaden warunek nie pasuje

Foreach

Iteruje po kolekcji.

- 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)'

Właściwości:

Własność Wymagane Opis
source Yes Wyrażenie zwracające kolekcję
itemName No Nazwa zmiennej dla bieżącego elementu (wartość domyślna: item)
indexName No Nazwa zmiennej dla bieżącego indeksu (wartość domyślna: index)
actions Yes Akcje do wykonania dla każdego elementu

BreakLoop

Natychmiast przerywa bieżącą pętlę.

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

KontynuujLoop

Pomija kolejną iterację pętli.

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

GotoAction

Przechodzi do określonej akcji według identyfikatora.

- 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

Właściwości:

Własność Wymagane Opis
actionId Yes Identyfikator działania, do którego ma przejść

Akcje wyjściowe

SendActivity

Wysyła wiadomość do użytkownika.

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

Z wyrażeniem:

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

Właściwości:

Własność Wymagane Opis
activity Yes Działanie do zrealizowania w celu wysłania
activity.text Yes Tekst wiadomości (literał lub wyrażenie)

SendMessage

Wysyła do użytkownika wiadomość SMS z szablonem. Użyj SendMessage polecenia , gdy wystarczy wysłać tekst i nie potrzebujesz pełnego kształtu obiektu działania.

- kind: SendMessage
  id: show_repo_summary
  message: "Fetched repo: visibility={Local.RepoInfo.visibility}, description={Local.RepoInfo.description}"

Właściwości:

Własność Wymagane Opis
message Yes Tekst wiadomości do wysłania. Użyj symboli zastępczych {Variable.Path}, aby wstawić wartości stanu przepływu pracy.

Uwaga / Notatka

Implementacja deklaratywnego przepływu pracy języka C# obsługuje funkcję SendMessage. Użyj SendActivity do przepływów pracy w Pythonie.

Akcje wywoływania agenta

Wywołaj AzureAgent

Wywołuje agenta usługi Foundry.

Wywołanie podstawowe:

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

Z konfiguracją danych wejściowych i wyjściowych:

- 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

W przypadku pętli zewnętrznej (trwa do momentu spełnienia warunku):

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

Właściwości:

Własność Wymagane Opis
agent.name Yes Nazwa zarejestrowanego agenta
conversationId No Identyfikator kontekstu konwersacji
input.messages No Komunikaty wysyłane do agenta
input.arguments No Dodatkowe argumenty agenta
input.externalLoop.when No Warunek kontynuowania pętli agenta
output.responseObject No Ścieżka do przechowywania odpowiedzi agenta
output.messages No Ścieżka do przechowywania wiadomości
output.autoSend No Automatyczne wysyłanie odpowiedzi do użytkownika

Narzędzia i akcje HTTP

InvokeFunctionTool

Bezpośrednio z przepływu pracy wywołuje narzędzie funkcyjne bez przechodzenia przez agenta sztucznej inteligencji.

- 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

Właściwości:

Własność Wymagane Opis
functionName Yes Nazwa funkcji do wywołania
conversationId No Identyfikator kontekstu konwersacji
requireApproval No Czy należy wymagać zatwierdzenia przez użytkownika przed wykonaniem
arguments No Argumenty przekazywane do funkcji
output.result No Ścieżka do przechowywania wyniku funkcji
output.messages No Ścieżka do przechowywania komunikatów funkcji
output.autoSend No Automatyczne wysyłanie wyniku do użytkownika

Konfiguracja C# dla narzędzia InvokeFunctionTool:

Funkcje muszą być zarejestrowane w obiekcie WorkflowRunner lub obsługiwane za pośrednictwem danych wejściowych zewnętrznych:

// 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

Wywołuje narzędzie na serwerze 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

Z nazwą połączenia dla hostowanych scenariuszy:

- 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

Właściwości:

Własność Wymagane Opis
serverUrl Yes Adres URL serwera MCP
serverLabel No Czytelna dla człowieka etykieta serwera
toolName Yes Nazwa narzędzia do wywołania
conversationId No Identyfikator kontekstu konwersacji
requireApproval No Czy wymagać zatwierdzenia przez użytkownika
arguments No Argumenty przekazywane do narzędzia
headers No Niestandardowe nagłówki HTTP dla żądania
connection.name No Nazwane połączenie dla scenariuszy hostowanych (połączenie z identyfikatorem ProjectConnectionId w platformie Foundry; nie jest jeszcze w pełni obsługiwane)
output.result No Ścieżka do przechowywania wyników narzędzia
output.messages No Ścieżka do przechowywania komunikatów wyników
output.autoSend No Automatyczne wysyłanie wyniku do użytkownika

Instalator języka C# dla narzędzia InvokeMcpTool:

Skonfiguruj element McpToolHandler w fabryce przepływu pracy:

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
};

HttpRequestAction

Wysyła żądanie HTTP za pośrednictwem skonfigurowanego IHttpRequestHandlerelementu . Pomyślne odpowiedzi JSON są analizowane przed przypisaniem; odpowiedzi inne niż 2xx powodują niepowodzenie akcji.

- kind: HttpRequestAction
  id: fetch_repo_info
  method: GET
  url: "https://api.github.com/repos/Microsoft/agent-framework"
  headers:
    Accept: application/vnd.github+json
    User-Agent: agent-framework
  queryParameters:
    per_page: 10
  response: Local.RepoInfo
  responseHeaders: Local.RepoHeaders

Właściwości:

Własność Wymagane Opis
url Yes Bezwzględny adres URL żądania
method No Metoda HTTP; wartość domyślna: GET
headers No Nagłówki zapytań
queryParameters No Parametry zapytania dołączone do adresu URL
body No Treść żądania; użyj , kind: jsonrawlubnone
requestTimeoutInMilliseconds No Limit czasu przekroczenia na żądanie
conversationId No Dodaje treść pomyślnej odpowiedzi do konwersacji
response No Ścieżka do przechowywania przeanalizowanej treści odpowiedzi
responseHeaders No Ścieżka do przechowywania nagłówków odpowiedzi

Konfiguracja C# dla funkcji HttpRequestAction:

Ustaw HttpRequestHandler podczas kompilowania przepływu pracy. Użyj niestandardowego handlera, jeśli potrzebujesz ponownych prób lub listy dozwolonych URL.

DeclarativeWorkflowOptions options = new(agentProvider)
{
    HttpRequestHandler = new DefaultHttpRequestHandler(),
};

Workflow workflow = DeclarativeWorkflowBuilder.Build<string>("workflow.yaml", options);

Akcje pętli "człowiek w pętli"

Question

Zadaje użytkownikowi pytanie i przechowuje odpowiedź.

Zestawy SDK języka C# i Python używają różnych nazw pól dla monitu pytania. W tym przykładzie użyto najprostszego współdzielonego zachowania: prosi o tekst i przechowuje odpowiedź w stanie przepływu pracy.

- kind: Question
  id: ask_name
  displayName: Ask for user name
  property: Local.userName
  prompt:
    kind: Message
    text:
      - "What is your name?"
  entity:
    kind: StringPrebuiltEntity

Właściwości:

Własność Wymagane Opis
prompt Yes Szablon aktywności do wysłania jako pytanie. Użyj kind: Message z listą text dla monitów komunikatów.
property Yes Ścieżka do przechowywania wyodrębnionej odpowiedzi.
entity Yes Typ jednostki używany do analizowania i weryfikowania odpowiedzi. Użyj StringPrebuiltEntity dla odpowiedzi tekstowych.
alwaysPrompt No Wymusza zadawanie pytania nawet wtedy, gdy właściwość docelowa ma już wartość.
skipQuestionMode No Określa, czy pominąć monit, gdy właściwość docelowa ma już wartość. Obsługiwane wartości to AlwaysSkipIfVariableHasValue, SkipOnFirstExecutionIfVariableHasValuei AlwaysAsk.
repeatCount No Maksymalna liczba nieprawidłowych lub nierozpoznanych odpowiedzi przed zapisaniem defaultValue.
defaultValue No Wartość do zapisania, gdy osiągnięto repeatCount bez uzyskania prawidłowej odpowiedzi.
defaultValueResponse No Szablon działania komunikatu do wysłania, gdy jest używana wartość domyślna.
invalidPrompt No Szablon działania komunikatu do wysłania, gdy tekst odpowiedzi nie jest zgodny ze skonfigurowaną jednostką.
unrecognizedPrompt No Szablon działania komunikatu do wysłania, gdy odpowiedź nie zawiera komunikatów.
autoSend No Dodaje poprawną odpowiedź do konwersacji w przepływie pracy i aktualizuje element System.LastMessage. Wartość domyślna to true.

ŻądanieDanychZewnętrznych

Żąda danych wejściowych z systemu zewnętrznego lub procesu.

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

Właściwości:

Własność Wymagane Opis
prompt.text Yes Opis wymaganych danych wejściowych
variable Yes Ścieżka do przechowywania danych wejściowych
default No Wartość domyślna

Akcje sterowania przepływem pracy

Zakończenie przepływu pracy

Kończy działanie przepływu pracy.

- kind: EndWorkflow
  id: finish
  displayName: End workflow

EndConversation

Kończy bieżącą konwersację.

- kind: EndConversation
  id: end_chat
  displayName: End conversation

UtwórzKonwersację

Tworzy nowy kontekst konwersacji.

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

Właściwości:

Własność Wymagane Opis
conversationId Yes Ścieżka do przechowywania nowego identyfikatora konwersacji

Akcje konwersacji (tylko w języku C#)

DodajWiadomośćRozmowy

Dodaje wiadomość do wątku konwersacji.

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

Właściwości:

Własność Wymagane Opis
conversationId Yes Identyfikator konwersacji docelowej
message Yes Komunikat do dodania
message.role Yes Rola komunikatów (system, użytkownik, asystent)
message.content Yes Zawartość wiadomości

KopiujWiadomościZRozmowy

Kopiuje wiadomości z jednej konwersacji do innej.

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

Właściwości:

Własność Wymagane Opis
sourceConversationId Yes Identyfikator konwersacji źródłowej
targetConversationId Yes Identyfikator konwersacji docelowej
limit No Maksymalna liczba komunikatów do skopiowania

PobierzWiadomośćRozmowy

Pobiera określoną wiadomość z konwersacji.

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

Właściwości:

Własność Wymagane Opis
conversationId Yes Identyfikator konwersacji
messageId Yes Identyfikator komunikatu do pobrania
variable Yes Ścieżka do przechowywania pobranego komunikatu

PobierzWiadomościKonwersacji

Pobiera wiele wiadomości z konwersacji.

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

Właściwości:

Własność Wymagane Opis
conversationId Yes Identyfikator konwersacji
limit No Maksymalna liczba komunikatów do pobrania (wartość domyślna: 20)
newestFirst No Zwracanie w kolejności malejącej
after No Kursor do stronicowania
before No Kursor do stronicowania
variable Yes Ścieżka do przechowywania pobranych komunikatów

Szybki przegląd akcji

Action Category C# Python Opis
SetVariable Variable Ustawianie pojedynczej zmiennej
SetMultipleVariables Variable Ustawianie wielu zmiennych
SetTextVariable Variable Ustawianie zmiennej tekstowej
ResetVariable Variable Czyszczenie zmiennej
ClearAllVariables Variable Wyczyść wszystkie zmienne
ParseValue Variable Analizowanie/przekształcanie danych
EditTableV2 Variable Modyfikowanie danych tabeli
If Sterowanie przepływem Rozgałęzianie warunkowe
ConditionGroup Sterowanie przepływem Przełącznik z wieloma gałęziami
Foreach Sterowanie przepływem Iterowanie w kolekcji
BreakLoop Sterowanie przepływem Zakończ bieżącą pętlę
ContinueLoop Sterowanie przepływem Przejdź do następnej iteracji
GotoAction Sterowanie przepływem Przechodzenie do akcji według identyfikatora
SendActivity Wynik Wysyłanie wiadomości do użytkownika
SendMessage Wynik Wysyłanie szablonowej wiadomości tekstowej
InvokeAzureAgent Agent Wywoływanie agenta sztucznej inteligencji platformy Azure
InvokeFunctionTool Narzędzie Wywoływanie funkcji bezpośrednio
InvokeMcpTool Narzędzie Wywoływanie narzędzia serwera MCP
HttpRequestAction HTTP Wywoływanie punktu końcowego HTTP
Question Człowiek w pętli Zadaj użytkownikowi pytanie
RequestExternalInput Człowiek w pętli Żądanie zewnętrznych danych wejściowych
EndWorkflow Kontrolka przepływu pracy Zakończ przepływ pracy
EndConversation Kontrolka przepływu pracy Zakończ konwersację
CreateConversation Kontrolka przepływu pracy Tworzenie nowej konwersacji
AddConversationMessage Rozmowa Dodawanie komunikatu do wątku
CopyConversationMessages Rozmowa Kopiowanie komunikatów
RetrieveConversationMessage Rozmowa Pobierz pojedynczą wiadomość
RetrieveConversationMessages Rozmowa Pobieranie wielu komunikatów

Wzorce zaawansowane

Orkiestracja wielu agentów

Sekwencyjny potok danych agenta

Przejmij pracę przez wielu agentów w sekwencji.

#
# 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

Konfiguracja języka 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");

Routing według warunków agenta

Kierowanie żądań do różnych agentów na podstawie warunków.

#
# 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

Wzorce integracji narzędzi

Wstępne pobieranie danych za pomocą funkcji InvokeFunctionTool

Pobierz dane przed wywołaniem agenta:

#
# 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)'

Integracja narzędzia MCP

Wywołaj serwer zewnętrzny przy użyciu programu 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")

Wymagania wstępne

Zanim zaczniesz, upewnij się, że masz:

  • Python 3.10 — 3.13 (język Python 3.14 nie jest jeszcze obsługiwany ze względu na zgodność z programem PowerFx)
  • Zainstalowany pakiet deklaratywny platformy Agent Framework:
pip install agent-framework-declarative --pre

Ten pakiet automatycznie integruje się z podstawowym agent-framework-core.

Pierwszy deklaratywny przepływ pracy

Utwórzmy prosty przepływ pracy, który wita użytkownika po imieniu.

Krok 1. Tworzenie pliku YAML

Utwórz plik o nazwie 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

Krok 2. Ładowanie i uruchamianie przepływu pracy

Utwórz plik w języku Python, aby wykonać przepływ pracy:

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}")
    for output in result.get_intermediate_outputs():
        print(f"Intermediate: {output}")


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

Oczekiwane dane wyjściowe

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

Podstawowe pojęcia

Przestrzenie nazw zmiennych

Deklaratywne przepływy pracy używają zmiennych przestrzeni nazw do organizowania stanu:

Namespace Opis Example
Local.* Zmienne lokalne w przepływie pracy Local.message
Workflow.Inputs.* Parametry wejściowe Workflow.Inputs.name
Workflow.Outputs.* Wartości wyjściowe Workflow.Outputs.result
System.* Wartości dostarczone przez system System.ConversationId

Język wyrażeń

Wartości poprzedzone prefiksem = są oceniane jako wyrażenia:

# Literal value (no evaluation)
value: Hello

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

Typowe funkcje obejmują:

  • Concat(str1, str2, ...) - Łączenie ciągów
  • If(condition, trueValue, falseValue) - Wyrażenie warunkowe
  • IsBlank(value) — Sprawdzanie, czy wartość jest pusta

Typy akcji

Deklaratywne przepływy pracy obsługują różne typy akcji:

Category Czynności
Zarządzanie zmiennymi SetVariable, SetMultipleVariables, ResetVariable
Sterowanie przepływem If, , ConditionGroup, Foreach, BreakLoop, , ContinueLoopGotoAction
Wynik SendActivity
Wywołanie agenta InvokeAzureAgent
Wywołanie narzędzia InvokeFunctionTool, InvokeMcpTool
HTTP HttpRequestAction
Człowiek w pętli Question, RequestExternalInput
Kontrolka przepływu pracy EndWorkflow, EndConversation, CreateConversation

Referencja Akcji

Akcje to bloki konstrukcyjne deklaratywnych przepływów pracy. Każda akcja wykonuje określoną operację, a akcje są wykonywane sekwencyjnie w kolejności, w której są wyświetlane w pliku YAML.

Struktura akcji

Wszystkie akcje mają wspólne właściwości:

- 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...

Akcje zarządzania zmiennymi

SetVariable

Ustawia zmienną na określoną wartość.

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

Z wyrażeniem:

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

Właściwości:

Własność Wymagane Opis
variable Yes Ścieżka zmiennej (np. Local.name, Workflow.Outputs.result)
value Yes Wartość do ustawienia (literał lub wyrażenie)

Uwaga / Notatka

Python również obsługuje SetValue rodzaj akcji używający path zamiast variable jako właściwości docelowej. Oba SetVariable (z variable) i SetValue (z path) osiągną ten sam wynik. Przykład:

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

SetMultipleVariables

Ustawia wiele zmiennych w jednej akcji.

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

Właściwości:

Własność Wymagane Opis
variables Yes Mapa ścieżek zmiennych do wartości

ResetVariable

Czyści wartość zmiennej.

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

Właściwości:

Własność Wymagane Opis
variable Yes Ścieżka zmiennej do zresetowania

Akcje sterowania przepływem

If

Wykonuje akcje warunkowo w zależności od spełnienia warunku.

- 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!"

Warunki zagnieżdżone:

- 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"

Właściwości:

Własność Wymagane Opis
condition Yes Wyrażenie, które ocenia się jako prawda/fałsz
then Yes Akcje do wykonania, jeśli warunek ma wartość true
else No Akcje do wykonania, jeśli warunek ma wartość false

Grupa warunków

Ocenia wiele warunków, takich jak instrukcja 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

Właściwości:

Własność Wymagane Opis
conditions Yes Lista par warunku/akcji (pierwsze zwycięstwo meczu)
elseActions No Działania, jeśli żaden warunek nie pasuje

Foreach

Iteruje po kolekcji.

- 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)'

Właściwości:

Własność Wymagane Opis
source Yes Wyrażenie zwracające kolekcję
itemName No Nazwa zmiennej dla bieżącego elementu (wartość domyślna: item)
indexName No Nazwa zmiennej dla bieżącego indeksu (wartość domyślna: index)
actions Yes Akcje do wykonania dla każdego elementu

BreakLoop

Natychmiast przerywa bieżącą pętlę.

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

KontynuujLoop

Pomija kolejną iterację pętli.

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

GotoAction

Przechodzi do określonej akcji według identyfikatora.

- 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

Właściwości:

Własność Wymagane Opis
actionId Yes Identyfikator działania, do którego ma przejść

Akcje wyjściowe

SendActivity

Wysyła wiadomość do użytkownika.

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

Z wyrażeniem:

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

Właściwości:

Własność Wymagane Opis
activity Yes Działanie do zrealizowania w celu wysłania
activity.text Yes Tekst wiadomości (literał lub wyrażenie)

Akcje wywoływania agenta

Wywołaj AzureAgent

Wywołuje agenta usługi Azure AI.

Wywołanie podstawowe:

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

Z konfiguracją danych wejściowych i wyjściowych:

- 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

W przypadku pętli zewnętrznej (trwa do momentu spełnienia warunku):

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

Właściwości:

Własność Wymagane Opis
agent.name Yes Nazwa zarejestrowanego agenta
conversationId No Identyfikator kontekstu konwersacji
input.messages No Komunikaty wysyłane do agenta
input.arguments No Dodatkowe argumenty agenta
input.externalLoop.when No Warunek kontynuowania pętli agenta
output.responseObject No Ścieżka do przechowywania odpowiedzi agenta
output.messages No Ścieżka do przechowywania wiadomości
output.autoSend No Automatyczne wysyłanie odpowiedzi do użytkownika

Narzędzia i akcje HTTP

InvokeFunctionTool

Wywołuje zarejestrowaną funkcję języka Python bezpośrednio z przepływu pracy bez przechodzenia przez agenta sztucznej inteligencji.

- 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

Właściwości:

Własność Wymagane Opis
functionName Yes Nazwa zarejestrowanej funkcji do wywołania
arguments No Argumenty przekazywane do funkcji
output.result No Ścieżka do przechowywania wyniku funkcji
output.messages No Ścieżka do przechowywania komunikatów funkcji
output.autoSend No Automatyczne wysyłanie wyniku do użytkownika

Konfiguracja języka Python dla narzędzia InvokeFunctionTool:

Funkcje muszą być zarejestrowane przy użyciu WorkflowFactoryregister_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"})

InvokeMcpTool

Wywołuje narzędzie na serwerze MCP za pomocą skonfigurowanego MCPToolHandlerelementu .

- kind: InvokeMcpTool
  id: search_docs
  serverUrl: https://learn.microsoft.com/api/mcp
  serverLabel: microsoft_docs
  toolName: microsoft_docs_search
  arguments:
    query: =Local.searchQuery
  output:
    result: Local.searchResults
    messages: Local.toolMessage
    autoSend: true

Właściwości:

Własność Wymagane Opis
serverUrl Yes Adres URL serwera MCP
toolName Yes Nazwa narzędzia na serwerze MCP
serverLabel No Etykieta serwera czytelnego dla człowieka
arguments No Argumenty przekazane do narzędzia
headers No Nagłówki żądań; puste wartości są pomijane
connection.name No Nazwa połączenia dla obsługi własnych handlerów
conversationId No Dodaje pomyślne dane wyjściowe narzędzia do konwersacji
requireApproval No Żąda zatwierdzenia przed wywołaniem narzędzia
output.result No Ścieżka do przechowywania analizowanych danych wyjściowych narzędzia
output.messages No Ścieżka do przechowywania komunikatu narzędzia
output.autoSend No Emituje dane wyjściowe narzędzia do wyniku przepływu pracy; wartość domyślna: true

Konfiguracja Python dla InvokeMcpTool:

Przekaż program obsługi narzędzi MCP do WorkflowFactory. Użyj niestandardowej procedury obsługi, gdy potrzebujesz uwierzytelniania, połączeń zarządzanych lub listy dozwolonych adresów URL.

from agent_framework.declarative import DefaultMCPToolHandler, WorkflowFactory

factory = WorkflowFactory(mcp_tool_handler=DefaultMCPToolHandler())
workflow = factory.create_workflow_from_yaml_path("workflow.yaml")

HttpRequestAction

Wysyła żądanie HTTP za pośrednictwem skonfigurowanego HttpRequestHandlerelementu . Pomyślne odpowiedzi JSON są analizowane przed przypisaniem; odpowiedzi inne niż 2xx powodują niepowodzenie akcji.

- kind: HttpRequestAction
  id: fetch_repo_info
  method: GET
  url: =Concat("https://api.github.com/repos/", Local.repoName)
  headers:
    Accept: application/vnd.github+json
    User-Agent: agent-framework
  queryParameters:
    per_page: 10
  response: Local.repoInfo
  responseHeaders: Local.repoHeaders

Właściwości:

Własność Wymagane Opis
url Yes Bezwzględny adres URL żądania
method No Metoda HTTP; wartość domyślna: GET
headers No Nagłówki zapytań
queryParameters No Parametry zapytania dołączone do adresu URL
body No Treść żądania; użyj , kind: jsonrawlubnone
requestTimeoutInMilliseconds No Limit czasu przekroczenia na żądanie
connection.name No Nazwa połączenia dla obsługi własnych handlerów
conversationId No Dodaje treść pomyślnej odpowiedzi do konwersacji
response No Ścieżka do przechowywania przeanalizowanej treści odpowiedzi
responseHeaders No Ścieżka do przechowywania nagłówków odpowiedzi

Konfiguracja Pythona dla HttpRequestAction:

Przekaż procedurę obsługi żądań HTTP do WorkflowFactory. Użyj niestandardowej procedury obsługi, gdy potrzebujesz uwierzytelniania, ponawiania prób lub listy dozwolonych adresów URL.

from agent_framework.declarative import DefaultHttpRequestHandler, WorkflowFactory

factory = WorkflowFactory(http_request_handler=DefaultHttpRequestHandler())
workflow = factory.create_workflow_from_yaml_path("workflow.yaml")

Akcje pętli "człowiek w pętli"

Question

Zadaje użytkownikowi pytanie i przechowuje odpowiedź.

Zestawy SDK języka C# i Python używają różnych nazw pól dla monitu pytania. W tej sekcji jest używane najmniejsze zachowanie udostępnione: poproś o tekst i zapisz odpowiedź w stanie przepływu pracy.

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

Właściwości:

Własność Wymagane Opis
question Yes Pytanie, które należy zadać. Użyj question.text dla formularza zagnieżdżonego lub wartości ciągu dla formularza kompaktowego.
variable Yes Ścieżka do przechowywania odpowiedzi. Użyj property jako alternatywnej nazwy pola najwyższego poziomu, jeśli chcesz dopasować je do nazwy pola docelowego języka C#.
default No Wartość domyślna uwzględniona w metadanych żądania do użycia przez podmiot wywołujący.
choices No Lista opcji dodanych do metadanych żądania. Każdy wybór może być łańcuchem znaków lub obiektem z polem value i opcjonalnym polem label.
allowFreeText No Wskazuje, czy wywołujący może akceptować tekst spoza skonfigurowanego choices. Wartość domyślna to true.

Python akceptuje również alternatywne nazwy pól pod kątem zgodności. Użyj question najwyższego poziomu zamiast text oraz defaultValue zamiast default.

- kind: Question
  id: ask_color
  text: "Choose a color:"
  property: Local.color
  choices:
    - value: red
      label: Red
    - blue
  allowFreeText: false

ŻądanieDanychZewnętrznych

Żąda danych wejściowych z systemu zewnętrznego lub procesu.

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

Właściwości:

Własność Wymagane Opis
prompt.text Yes Opis wymaganych danych wejściowych
variable Yes Ścieżka do przechowywania danych wejściowych
default No Wartość domyślna

Akcje sterowania przepływem pracy

Zakończenie przepływu pracy

Kończy działanie przepływu pracy.

- kind: EndWorkflow
  id: finish
  displayName: End workflow

EndConversation

Kończy bieżącą konwersację.

- kind: EndConversation
  id: end_chat
  displayName: End conversation

UtwórzKonwersację

Tworzy nowy kontekst konwersacji.

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

Właściwości:

Własność Wymagane Opis
conversationId Yes Ścieżka do przechowywania nowego identyfikatora konwersacji

Szybki przegląd akcji

Action Category Opis
SetVariable Variable Ustawianie pojedynczej zmiennej
SetMultipleVariables Variable Ustawianie wielu zmiennych
ResetVariable Variable Czyszczenie zmiennej
If Sterowanie przepływem Rozgałęzianie warunkowe
ConditionGroup Sterowanie przepływem Przełącznik z wieloma gałęziami
Foreach Sterowanie przepływem Iterowanie w kolekcji
BreakLoop Sterowanie przepływem Zakończ bieżącą pętlę
ContinueLoop Sterowanie przepływem Przejdź do następnej iteracji
GotoAction Sterowanie przepływem Przechodzenie do akcji według identyfikatora
SendActivity Wynik Wysyłanie wiadomości do użytkownika
InvokeAzureAgent Agent Wywoływanie agenta sztucznej inteligencji platformy Azure
InvokeFunctionTool Narzędzie Wywoływanie zarejestrowanej funkcji
InvokeMcpTool Narzędzie Wywoływanie narzędzia serwera MCP
HttpRequestAction HTTP Wywoływanie punktu końcowego HTTP
Question Człowiek w pętli Zadaj użytkownikowi pytanie
RequestExternalInput Człowiek w pętli Żądanie zewnętrznych danych wejściowych
EndWorkflow Kontrolka przepływu pracy Zakończ przepływ pracy
EndConversation Kontrolka przepływu pracy Zakończ konwersację
CreateConversation Kontrolka przepływu pracy Tworzenie nowej konwersacji

Składnia wyrażeń

Deklaratywne przepływy pracy używają języka wyrażeń przypominającego PowerFx do zarządzania stanem i obliczania wartości dynamicznych. Wartości poprzedzone prefiksem = są oceniane jako wyrażenia w czasie wykonywania.

Szczegóły przestrzeni nazw zmiennej

Namespace Opis Access
Local.* Zmienne lokalne przepływu pracy Odczyt/zapis
Workflow.Inputs.* Parametry wejściowe przekazywane do przepływu pracy Tylko odczyt
Workflow.Outputs.* Wartości zwrócone z przepływu pracy Odczyt/zapis
System.* Wartości dostarczone przez system Tylko odczyt
Agent.* Wyniki wywołań agenta Tylko odczyt

Zmienne systemowe

Variable Opis
System.ConversationId Bieżący identyfikator konwersacji
System.LastMessage Najnowsza wiadomość
System.Timestamp Bieżący znacznik czasu

Zmienne agenta

Po wywołaniu agenta uzyskaj dostęp do danych odpowiedzi za pośrednictwem zmiennej wyjściowej:

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

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

Wartości literału kontra wartości wyrażeń

# 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

Operacje na ciągach

Concat

Łączenie wielu ciągów:

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

Sprawdź, czy wartość jest pusta lub niezdefiniowana:

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

Wyrażenia warunkowe

Funkcja If

Zwracanie różnych wartości na podstawie warunku:

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"))

Operatory porównania

Operator Opis Example
= Równa się =Workflow.Inputs.status = "active"
<> Nie równa się =Workflow.Inputs.status <> "deleted"
< Mniejsze niż =Workflow.Inputs.age < 18
> Większe niż =Workflow.Inputs.count > 0
<= Mniejsze lub równe =Workflow.Inputs.score <= 100
>= Większe niż lub równe =Workflow.Inputs.quantity >= 1

Funkcje Boole'a

# 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))

Operacje matematyczne

# 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

Przykłady wyrażeń praktycznych

Kategoryzacja użytkownika

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

Warunkowe powitanie

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

Walidacja danych wejściowych

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")

Wzorce zaawansowane

W miarę zwiększania złożoności przepływów pracy potrzebne będą wzorce obsługujące wieloetapowe procesy, koordynację agentów i interaktywne scenariusze.

Orkiestracja wielu agentów

Sekwencyjny potok danych agenta

Przekazywanie pracy przez wielu agentów w sekwencji, gdzie każdy agent opiera się na danych wyjściowych poprzedniego agenta.

Przypadek użycia: linie tworzenia treści, w których różni specjaliści obsługują badania, pisanie i edycję.

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

Konfiguracja języka 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"})

Routing według warunków agenta

Kierowanie żądań do różnych agentów na podstawie wyników wejściowych lub pośrednich.

Przypadek użycia: Systemy pomocy technicznej, które kierują do wyspecjalizowanych agentów na podstawie typu problemu.

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

Agent z pętlą zewnętrzną

Kontynuuj interakcję z agentem do momentu spełnienia warunku, takiego jak rozwiązany problem.

Przypadek użycia: obsługa konwersacji, które będą kontynuowane do momentu rozwiązania problemu użytkownika.

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."

Wzorce sterowania pętlami

Konwersacja z agentem iteracyjnym

Tworzenie dwustronnych rozmów między agentami z użyciem kontrolowanej iteracji.

Przypadek użycia: scenariusze dla uczniów, symulacje debaty lub iteracyjne uściślenie.

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

Pętle oparte na liczniku

Zaimplementuj tradycyjne pętle zliczania przy użyciu zmiennych i 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!"

Wczesne wyjście z funkcją breakLoop

Użyj metody BreakLoop, aby zamknąć iteracji na wczesnym etapie, gdy warunek zostanie spełniony.

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"

Wzorce integracji człowieka w procesach

Interakcyjne badanie

Zbierz wiele informacji od użytkownika.

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

Proces zatwierdzania

Zażądaj zatwierdzenia przed kontynuowaniem akcji.

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: Question
        id: get_approval
        question:
          text: =Concat("Do you approve this ", Workflow.Inputs.requestType, " request for $", Workflow.Inputs.amount, "? (yes/no)")
        variable: Local.approved

      - kind: If
        condition: =Local.approved = "yes"
        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

Złożona orkiestracja

Przepływ zgłoszenia serwisowego

Wszechstronny przykład łączenia wielu wzorców: routing agentów, logika o warunkach i zarządzanie rozmowami.

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.")

Najlepsze praktyki

Konwencje nazewnictwa

Użyj przejrzystych, opisowych nazw akcji i zmiennych:

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

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

Organizowanie dużych przepływów pracy

Podziel złożone przepływy pracy na sekcje logiczne z komentarzami:

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
    # ...

Obsługa błędów

Użyj kontroli warunkowych, aby obsłużyć potencjalne problemy:

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

Strategie testowania

  1. Rozpocznij proste: przetestuj podstawowe przepływy przed dodaniem złożoności
  2. Użyj wartości domyślnych: podaj rozsądne wartości domyślne dla danych wejściowych
  3. Dodawanie rejestrowania: użyj funkcji SendActivity do debugowania podczas programowania
  4. Przypadki brzegowe testów: sprawdź zachowanie z brakującymi lub nieprawidłowymi danymi wejściowymi
# Debug logging example
- kind: SendActivity
  id: debug_log
  activity:
    text: '=Concat("[DEBUG] Current state: counter=", Local.counter, ", status=", Local.status)'

Dalsze kroki

  • Przykłady deklaratywnego przepływu pracy języka C# — zapoznaj się z pełnymi przykładami roboczymi, w tym:
    • StudentTeacher — konwersacja z wieloma agentami z iteracyjnym uczeniem
    • InvokeMcpTool — integracja narzędzi serwera MCP
    • InvokeFunctionTool — wywołanie funkcji bezpośredniej z przepływów pracy
    • FunctionTools — agent z narzędziami funkcji
    • ToolApproval — ręczne zatwierdzenie wykonania narzędzia
    • CustomerSupport — złożony przepływ pracy zgłoszenia pomocy technicznej
    • DeepResearch — przepływ pracy badawczej z wieloma agentami

Uwaga / Notatka

Obsługa tej funkcji w języku Go będzie dostępna wkrótce. Aktualny status znajdziesz w repozytorium Agent Framework dla Go.