次の方法で共有


宣言型ワークフロー - 概要

宣言型ワークフローを使用すると、プログラムによるコードを記述する代わりに、YAML 構成ファイルを使用してワークフロー ロジックを定義できます。 このアプローチにより、ワークフローの読み取り、変更、チーム間での共有が容易になります。

概要

宣言型ワークフローでは、 ワークフローを実装 する 方法 ではなく、何を行う必要があるかを説明します。 フレームワークは基になる実行を処理し、YAML 定義を実行可能なワークフロー グラフに変換します。

主な利点:

  • 読み取り可能な形式: 開発者以外の場合でも、YAML 構文が理解しやすい
  • 移植可能: コードを変更せずに、ワークフロー定義を共有、バージョン管理、変更できます
  • 迅速な反復: 構成ファイルを編集してワークフローの動作を変更する
  • 一貫性のある構造: 定義済みのアクションの種類により、ワークフローがベスト プラクティスに従っていることを確認する

宣言型ワークフローとプログラム型ワークフローを使用する場合

Scenario 推奨されるアプローチ
標準オーケストレーション パターン 宣言型
頻繁に変更されるワークフロー 宣言型
開発者以外のユーザーがワークフローを変更する必要がある 宣言型
複雑なカスタム ロジック プログラム的な
最大限の柔軟性と制御 プログラム的な
既存の Python コードとの統合 プログラム的な

基本的な YAML 構造体

YAML 構造は、C# と Python の実装で若干異なります。 詳細については、以下の言語固有のセクションを参照してください。

アクションの種類

宣言型ワークフローでは、さまざまなアクションの種類がサポートされています。 次の表は、言語別の可用性を示しています。

カテゴリ アクション C# Python
変数管理 SetVariableSetMultipleVariablesResetVariable
変数管理 AppendValue
変数管理 SetTextVariableClearAllVariablesParseValueEditTableV2
制御フロー IfConditionGroupForeachBreakLoopContinueLoopGotoAction
制御フロー RepeatUntil
アウトプット SendActivity
アウトプット EmitEvent
エージェント呼び出し InvokeAzureAgent
ツールの呼び出し InvokeFunctionTool
ツールの呼び出し InvokeMcpTool
人間関与システム QuestionRequestExternalInput
人間関与システム ConfirmationWaitForInput
ワークフロー コントロール EndWorkflowEndConversationCreateConversation
会話 AddConversationMessageCopyConversationMessagesRetrieveConversationMessageRetrieveConversationMessages

C# YAML 構造体

C# 宣言型ワークフローでは、トリガーベースの構造が使用されます。

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

要素 構造

要素 必須 Description
kind イエス Workflow にする必要があります。
trigger.kind イエス トリガーの種類 (通常は OnConversationStart)
trigger.id イエス ワークフローの一意識別子
trigger.actions イエス 実行するアクションの一覧

Python YAML 構造体

Python 宣言型ワークフローでは、省略可能な入力を含む名前ベースの構造体が使用されます。

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

要素 構造

要素 必須 Description
name イエス ワークフローの一意識別子
description いいえ 人間が判読できる説明
inputs いいえ ワークフローが受け入れる入力パラメーター
actions イエス 実行するアクションの一覧

[前提条件]

開始する前に、次のことを確認します。

  • .NET 8.0 以降
  • 少なくとも 1 つのエージェントがデプロイされた Microsoft Foundry プロジェクト
  • 次の NuGet パッケージがインストールされています。
dotnet add package Microsoft.Agents.AI.Workflows.Declarative --prerelease
dotnet add package Microsoft.Agents.AI.Workflows.Declarative.AzureAI --prerelease
  • MCP ツール呼び出しアクションをワークフローに追加する場合は、次の NuGet パッケージもインストールします。
dotnet add package Microsoft.Agents.AI.Workflows.Declarative.Mcp --prerelease
  • YAML 構文に関する基本的な知識
  • ワークフローの概念の理解

最初の宣言型ワークフロー

入力に基づいてユーザーにあいさつする簡単なワークフローを作成しましょう。

手順 1: YAML ファイルを作成する

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

手順 2: エージェント プロバイダーを構成する

ワークフローを実行する C# コンソール アプリケーションを作成します。 まず、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());

手順 3: ワークフローをビルドして実行する

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

予期される出力

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

核となる概念

変数の名前空間

C# の宣言型ワークフローでは、名前空間付き変数を使用して状態を整理します。

Namespace Description
Local.* ワークフローにローカルな変数 Local.message
System.* システム指定の値 System.ConversationIdSystem.LastMessage

C# 宣言型ワークフローでは、 Workflow.Inputs または Workflow.Outputs 名前空間は使用されません。 入力は System.LastMessage を介して受信され、出力は SendActivity アクションを介して送信されます。

システム変数

Variable Description
System.ConversationId 現在の会話識別子
System.LastMessage 最新のユーザー メッセージ
System.LastMessage.Text 最後のメッセージのテキスト コンテンツ

式言語

=プレフィックスが付いた値は、PowerFx 式言語を使用して式として評価されます。

# Literal value (no evaluation)
value: Hello

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

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

一般的な関数は次のとおりです。

  • Concat(str1, str2, ...) - 文字列を連結する
  • If(condition, trueValue, falseValue) - 条件式
  • IsBlank(value) - 値が空かどうかを確認する
  • Upper(text) / Lower(text) - 大文字と小文字の変換
  • Find(searchText, withinText) - 文字列内のテキストを検索する
  • MessageText(message) - メッセージ オブジェクトからテキストを抽出する
  • UserMessage(text) - テキストからユーザー メッセージを作成する
  • AgentMessage(text) - テキストからエージェント メッセージを作成する

構成オプション

DeclarativeWorkflowOptions クラスは、ワークフロー実行の構成を提供します。

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

エージェント プロバイダーのセットアップ

AzureAgentProviderは、ワークフローを 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,
};

ワークフローの実行

InProcessExecutionを使用してワークフローを実行し、イベントを処理します。

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

チェックポイントからの再開

障害耐性のために、チェックポイントからワークフローを再開することができます。

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

Actions リファレンス

アクションは、宣言型ワークフローの構成要素です。 各アクションは特定の操作を実行し、アクションは YAML ファイルに表示される順序で順番に実行されます。

アクション構造

すべてのアクションは、共通のプロパティを共有します。

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

変数管理アクション

SetVariable

変数を指定した値に設定します。

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

式を使用する場合:

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

プロパティ:

プロパティ 必須 Description
variable イエス 変数パス (例: Local.nameWorkflow.Outputs.result)
value イエス 設定する値 (リテラルまたは式)

SetMultipleVariables

1 つのアクションで複数の変数を設定します。

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

プロパティ:

プロパティ 必須 Description
variables イエス 変数パスを値にマップする

SetTextVariable (C# のみ)

テキスト変数を指定した文字列値に設定します。

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

プロパティ:

プロパティ 必須 Description
variable イエス テキスト値の変数パス
value イエス 設定するテキスト値

変数をリセット

変数の値をクリアします。

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

プロパティ:

プロパティ 必須 Description
variable イエス リセットする変数パス

ClearAllVariables (C# のみ)

現在のコンテキスト内のすべての変数をリセットします。

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

ParseValue (C# のみ)

データを抽出または使用可能な形式に変換します。

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

プロパティ:

プロパティ 必須 Description
source イエス 解析する値を返す式
variable イエス 解析された結果を格納するための変数パス

EditTableV2 (C# のみ)

構造化テーブル形式でデータを変更します。

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

プロパティ:

プロパティ 必須 Description
table イエス テーブルへの変数パス
operation イエス 操作の種類 (追加、更新、削除)
row イエス 操作用の行データ

制御フローアクション

もし

条件に基づいて条件付きでアクションを実行します。

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

プロパティ:

プロパティ 必須 Description
condition イエス true/false に評価される式
then イエス 条件が true の場合に実行するアクション
else いいえ 条件が false の場合に実行するアクション

条件グループ (ConditionGroup)

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

プロパティ:

プロパティ 必須 Description
conditions イエス 条件とアクションのペアの一覧 (最初に一致したものが優先されます)
elseActions いいえ 条件が一致しない場合のアクション

フォーイーチ

コレクションを反復処理します。

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

プロパティ:

プロパティ 必須 Description
source イエス コレクションを返す式
itemName いいえ 現在の項目の変数名 (既定値: item)
indexName いいえ 現在のインデックスの変数名 (既定値: index)
actions イエス 各項目に対して実行するアクション

BreakLoop

現在のループを直ちに終了します。

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

ContinueLoop

ループの次のイテレーションにスキップします。

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

GotoAction

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

プロパティ:

プロパティ 必須 Description
actionId イエス ジャンプ先のアクションのID

出力アクション

SendActivity

ユーザーにメッセージを送信します。

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

式を使用する場合:

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

プロパティ:

プロパティ 必須 Description
activity イエス 送信するためのアクティビティ
activity.text イエス メッセージ テキスト (リテラルまたは式)

エージェント呼び出しアクション

InvokeAzureAgent

Foundry エージェントを呼び出します。

基本的な呼び出し:

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

入力と出力の構成を使用する場合:

- 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

外部ループ (条件が満たされるまで続行):

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

プロパティ:

プロパティ 必須 Description
agent.name イエス 登録済みエージェントの名前
conversationId いいえ 会話コンテキスト識別子
input.messages いいえ エージェントに送信するメッセージ
input.arguments いいえ エージェントに対する追加の引数
input.externalLoop.when いいえ エージェント ループを続行する条件
output.responseObject いいえ エージェントの応答を格納するパス
output.messages いいえ 会話メッセージを格納するパス
output.autoSend いいえ ユーザーに応答を自動的に送信する

ツール呼び出しアクション (C# のみ)

InvokeFunctionTool

AI エージェントを経由せずに、ワークフローから関数ツールを直接呼び出します。

- 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

プロパティ:

プロパティ 必須 Description
functionName イエス 呼び出す関数の名前
conversationId いいえ 会話コンテキスト識別子
requireApproval いいえ 実行前にユーザーの承認を要求するかどうか
arguments いいえ 関数に渡す引数
output.result いいえ 関数の結果を格納するパス
output.messages いいえ 関数メッセージを格納するパス
output.autoSend いいえ ユーザーに結果を自動的に送信する

InvokeFunctionTool の C# セットアップ:

関数は、 WorkflowRunner に登録するか、外部入力を使用して処理する必要があります。

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

MCP (モデル コンテキスト プロトコル) サーバーでツールを呼び出します。

- 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

ホスティングされるシナリオの接続名:

- 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

プロパティ:

プロパティ 必須 Description
serverUrl イエス MCP サーバーの URL
serverLabel いいえ サーバーの人間が判読できるラベル
toolName イエス 呼び出すツールの名前
conversationId いいえ 会話コンテキスト識別子
requireApproval いいえ ユーザーの承認を要求するかどうか
arguments いいえ ツールに渡す引数
headers いいえ 要求のカスタム HTTP ヘッダー
connection.name いいえ ホストされるシナリオの名前付き接続 (Foundry の ProjectConnectionId に接続します。まだ完全にはサポートされていません)
output.result いいえ ツールの結果を格納するパス
output.messages いいえ 結果メッセージを格納するパス
output.autoSend いいえ ユーザーに結果を自動的に送信する

InvokeMcpTool の C# セットアップ:

ワークフロー ファクトリで McpToolHandler を構成します。

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

Human-in-the-Loop アクション

Question

ユーザーに質問し、応答を格納します。

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

プロパティ:

プロパティ 必須 Description
question.text イエス 尋ねるべき質問
variable イエス 応答を格納するパス
default いいえ 応答がない場合の既定値

外部入力を要求

外部システムまたはプロセスからの入力を要求します。

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

プロパティ:

プロパティ 必須 Description
prompt.text イエス 必要な入力の説明
variable イエス 入力を格納するパス
default いいえ 既定値

ワークフロー コントロール アクション

EndWorkflow

ワークフローの実行を終了します。

- kind: EndWorkflow
  id: finish
  displayName: End workflow

EndConversation

現在の会話を終了します。

- kind: EndConversation
  id: end_chat
  displayName: End conversation

会話を作成

新しい会話コンテキストを作成します。

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

プロパティ:

プロパティ 必須 Description
conversationId イエス 新しい会話 ID を格納するパス

会話アクション (C# のみ)

会話メッセージを追加

メッセージ交換スレッドにメッセージを追加します。

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

プロパティ:

プロパティ 必須 Description
conversationId イエス ターゲット会話識別子
message イエス 追加するメッセージ
message.role イエス メッセージ ロール (システム、ユーザー、アシスタント)
message.content イエス メッセージ コンテンツ

会話メッセージをコピーする

ある会話から別の会話にメッセージをコピーします。

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

プロパティ:

プロパティ 必須 Description
sourceConversationId イエス ソース会話識別子
targetConversationId イエス ターゲット会話識別子
limit いいえ コピーするメッセージの最大数

会話メッセージを取得する

会話から特定のメッセージを取得します。

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

プロパティ:

プロパティ 必須 Description
conversationId イエス 会話識別子
messageId イエス 取得するメッセージ識別子
variable イエス 取得したメッセージを格納するパス

会話メッセージを取得する

会話から複数のメッセージを取得します。

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

プロパティ:

プロパティ 必須 Description
conversationId イエス 会話識別子
limit いいえ 取得する最大メッセージ数 (既定値: 20)
newestFirst いいえ 降順で返す
after いいえ ページネーションのカーソル
before いいえ ページネーションのカーソル
variable イエス 取得したメッセージを格納するパス

アクションのクイック リファレンス

アクション カテゴリ C# Python Description
SetVariable Variable 1 つの変数を設定する
SetMultipleVariables Variable 複数の変数を設定する
SetTextVariable Variable テキスト変数を設定する
AppendValue Variable リスト/文字列に追加
ResetVariable Variable 変数をクリアする
ClearAllVariables Variable すべての変数をクリアする
ParseValue Variable データの解析/変換
EditTableV2 Variable テーブル データの変更
If 制御フロー 条件分岐
ConditionGroup 制御フロー マルチ分岐スイッチ
Foreach 制御フロー コレクションを反復処理する
RepeatUntil 制御フロー 条件が満たされるまでループ
BreakLoop 制御フロー 現在のループを終了する
ContinueLoop 制御フロー 次のイテレーションにスキップする
GotoAction 制御フロー ID でアクションにジャンプする
SendActivity アウトプット ユーザーにメッセージを送信する
EmitEvent アウトプット カスタム イベントを出力する
InvokeAzureAgent Agent Azure AI エージェントを呼び出す
InvokeFunctionTool Tool 関数を直接呼び出す
InvokeMcpTool Tool MCP サーバー ツールを呼び出す
Question 人間関与システム ユーザーに質問する
Confirmation 人間関与システム はい/いいえの確認
RequestExternalInput 人間関与システム 外部入力を要求する
WaitForInput 人間関与システム 入力を待つ
EndWorkflow ワークフロー コントロール ワークフローの終了
EndConversation ワークフロー コントロール 会話を終了する
CreateConversation ワークフロー コントロール 新しい会話を作成する
AddConversationMessage 会話 スレッドにメッセージを追加する
CopyConversationMessages 会話 メッセージをコピーする
RetrieveConversationMessage 会話 1 つのメッセージを取得する
RetrieveConversationMessages 会話 複数のメッセージを取得する

高度なパターン

マルチエージェント オーケストレーション

シーケンシャル エージェント パイプライン

複数のエージェントに順番に作業を渡します。

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

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

条件付きエージェント のルーティング

条件に基づいて異なるエージェントに要求をルーティングします。

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

ツール統合パターン

InvokeFunctionTool を使用したデータのプリフェッチ

エージェントを呼び出す前にデータを取得する。

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

MCP ツールの統合

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

[前提条件]

開始する前に、次のことを確認します。

  • Python 3.10 - 3.13 (PowerFx の互換性のため、Python 3.14 はまだサポートされていません)
  • Agent Framework 宣言パッケージがインストールされています。
pip install agent-framework-declarative --pre

このパッケージは、基になるagent-framework-coreを自動的に取り込みます。

  • YAML 構文に関する基本的な知識
  • ワークフローの概念の理解

最初の宣言型ワークフロー

名前でユーザーを迎える簡単なワークフローを作成しましょう。

手順 1: YAML ファイルを作成する

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

手順 2: ワークフローを読み込んで実行する

ワークフローを実行する Python ファイルを作成します。

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

予期される出力

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

核となる概念

変数の名前空間

宣言型ワークフローでは、名前空間付き変数を使用して状態を整理します。

Namespace Description
Local.* ワークフローにローカルな変数 Local.message
Workflow.Inputs.* 入力パラメーター Workflow.Inputs.name
Workflow.Outputs.* 出力値 Workflow.Outputs.result
System.* システム指定の値 System.ConversationId

式言語

=プレフィックスが付いた値は、式として評価されます。

# Literal value (no evaluation)
value: Hello

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

一般的な関数は次のとおりです。

  • Concat(str1, str2, ...) - 文字列を連結する
  • If(condition, trueValue, falseValue) - 条件式
  • IsBlank(value) - 値が空かどうかを確認する

アクションの種類

宣言型ワークフローでは、さまざまなアクションの種類がサポートされています。

カテゴリ アクション
変数管理 SetVariableSetMultipleVariablesAppendValueResetVariable
制御フロー IfConditionGroupForeachRepeatUntilBreakLoopContinueLoopGotoAction
アウトプット SendActivityEmitEvent
エージェント呼び出し InvokeAzureAgent
ツールの呼び出し InvokeFunctionTool
人間関与システム QuestionConfirmationRequestExternalInputWaitForInput
ワークフロー コントロール EndWorkflowEndConversationCreateConversation

Actions リファレンス

アクションは、宣言型ワークフローの構成要素です。 各アクションは特定の操作を実行し、アクションは YAML ファイルに表示される順序で順番に実行されます。

アクション構造

すべてのアクションは、共通のプロパティを共有します。

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

変数管理アクション

SetVariable

変数を指定した値に設定します。

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

式を使用する場合:

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

プロパティ:

プロパティ 必須 Description
variable イエス 変数パス (例: Local.nameWorkflow.Outputs.result)
value イエス 設定する値 (リテラルまたは式)

Python では、ターゲット プロパティのSetValueではなくpathを使用するvariable アクションの種類もサポートされています。 SetVariable (variable) とSetValue (path) の両方で同じ結果が得られます。 例えば次が挙げられます。

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

SetMultipleVariables

1 つのアクションで複数の変数を設定します。

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

プロパティ:

プロパティ 必須 Description
variables イエス 変数パスを値にマップする

AppendValue(値を追加)

リストに値を追加するか、文字列に連結します。

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

プロパティ:

プロパティ 必須 Description
variable イエス 追加する変数パス
value イエス 追加する値

変数をリセット

変数の値をクリアします。

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

プロパティ:

プロパティ 必須 Description
variable イエス リセットする変数パス

制御フローアクション

もし

条件に基づいて条件付きでアクションを実行します。

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

入れ子になった条件:

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

プロパティ:

プロパティ 必須 Description
condition イエス true/false に評価される式
then イエス 条件が true の場合に実行するアクション
else いいえ 条件が false の場合に実行するアクション

条件グループ (ConditionGroup)

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

プロパティ:

プロパティ 必須 Description
conditions イエス 条件とアクションのペアの一覧 (最初に一致したものが優先されます)
elseActions いいえ 条件が一致しない場合のアクション

フォーイーチ

コレクションを反復処理します。

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

プロパティ:

プロパティ 必須 Description
source イエス コレクションを返す式
itemName いいえ 現在の項目の変数名 (既定値: item)
indexName いいえ 現在のインデックスの変数名 (既定値: index)
actions イエス 各項目に対して実行するアクション

反復〜まで

条件が true になるまでアクションを繰り返します。

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

プロパティ:

プロパティ 必須 Description
condition イエス ループは、これが true になるまで続行されます
actions イエス 繰り返し実行するアクション

BreakLoop

現在のループを直ちに終了します。

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

ContinueLoop

ループの次のイテレーションにスキップします。

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

GotoAction

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

プロパティ:

プロパティ 必須 Description
actionId イエス ジャンプ先のアクションのID

出力アクション

SendActivity

ユーザーにメッセージを送信します。

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

式を使用する場合:

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

プロパティ:

プロパティ 必須 Description
activity イエス 送信するためのアクティビティ
activity.text イエス メッセージ テキスト (リテラルまたは式)

EmitEvent

カスタム イベントを出力します。

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

プロパティ:

プロパティ 必須 Description
eventType イエス イベントの型識別子
data いいえ イベント ペイロード データ

エージェント呼び出しアクション

InvokeAzureAgent

Azure AI エージェントを呼び出します。

基本的な呼び出し:

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

入力と出力の構成を使用する場合:

- 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

外部ループ (条件が満たされるまで続行):

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

プロパティ:

プロパティ 必須 Description
agent.name イエス 登録済みエージェントの名前
conversationId いいえ 会話コンテキスト識別子
input.messages いいえ エージェントに送信するメッセージ
input.arguments いいえ エージェントに対する追加の引数
input.externalLoop.when いいえ エージェント ループを続行する条件
output.responseObject いいえ エージェントの応答を格納するパス
output.messages いいえ 会話メッセージを格納するパス
output.autoSend いいえ ユーザーに応答を自動的に送信する

ツール呼び出しアクション

InvokeFunctionTool

AI エージェントを経由せずに、登録済みの Python 関数をワークフローから直接呼び出します。

- 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

プロパティ:

プロパティ 必須 Description
functionName イエス 呼び出す登録済み関数の名前
arguments いいえ 関数に渡す引数
output.result いいえ 関数の結果を格納するパス
output.messages いいえ 関数メッセージを格納するパス
output.autoSend いいえ ユーザーに結果を自動的に送信する

InvokeFunctionTool の Python セットアップ:

関数は、WorkflowFactoryを使用して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"})

Human-in-the-Loop アクション

Question

ユーザーに質問し、応答を格納します。

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

プロパティ:

プロパティ 必須 Description
question.text イエス 尋ねるべき質問
variable イエス 応答を格納するパス
default いいえ 応答がない場合の既定値

確認

ユーザーに [はい] または [いいえ] の確認を求めます。

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

プロパティ:

プロパティ 必須 Description
question.text イエス 確認の質問
variable イエス ブール値の結果を格納するパス

外部入力を要求

外部システムまたはプロセスからの入力を要求します。

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

プロパティ:

プロパティ 必須 Description
prompt.text イエス 必要な入力の説明
variable イエス 入力を格納するパス
default いいえ 既定値

入力待ち (WaitForInput)

ワークフローを一時停止し、外部入力を待機します。

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

プロパティ:

プロパティ 必須 Description
variable イエス 受信時に入力を格納するパス

ワークフロー コントロール アクション

EndWorkflow

ワークフローの実行を終了します。

- kind: EndWorkflow
  id: finish
  displayName: End workflow

EndConversation

現在の会話を終了します。

- kind: EndConversation
  id: end_chat
  displayName: End conversation

会話を作成

新しい会話コンテキストを作成します。

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

プロパティ:

プロパティ 必須 Description
conversationId イエス 新しい会話 ID を格納するパス

アクションのクイック リファレンス

アクション カテゴリ Description
SetVariable Variable 1 つの変数を設定する
SetMultipleVariables Variable 複数の変数を設定する
AppendValue Variable リスト/文字列に追加
ResetVariable Variable 変数をクリアする
If 制御フロー 条件分岐
ConditionGroup 制御フロー マルチ分岐スイッチ
Foreach 制御フロー コレクションを反復処理する
RepeatUntil 制御フロー 条件が満たされるまでループ
BreakLoop 制御フロー 現在のループを終了する
ContinueLoop 制御フロー 次のイテレーションにスキップする
GotoAction 制御フロー ID でアクションにジャンプする
SendActivity アウトプット ユーザーにメッセージを送信する
EmitEvent アウトプット カスタム イベントを出力する
InvokeAzureAgent Agent Azure AI エージェントを呼び出す
InvokeFunctionTool Tool 登録済み関数を呼び出す
Question 人間関与システム ユーザーに質問する
Confirmation 人間関与システム はい/いいえの確認
RequestExternalInput 人間関与システム 外部入力を要求する
WaitForInput 人間関与システム 入力を待つ
EndWorkflow ワークフロー コントロール ワークフローの終了
EndConversation ワークフロー コントロール 会話を終了する
CreateConversation ワークフロー コントロール 新しい会話を作成する

式の構文

宣言型ワークフローでは、PowerFx に似た式言語を使用して状態を管理し、動的な値を計算します。 =プレフィックスが付いた値は、実行時に式として評価されます。

変数名前空間の詳細

Namespace Description アクセス
Local.* ワークフローローカル変数 読み取り/書き込み
Workflow.Inputs.* ワークフローに渡される入力パラメーター 読み取り専用
Workflow.Outputs.* ワークフローから返される値 読み取り/書き込み
System.* システム指定の値 読み取り専用
Agent.* エージェント呼び出しの結果 読み取り専用

システム変数

Variable Description
System.ConversationId 現在の会話識別子
System.LastMessage 最新のメッセージ
System.Timestamp 現在のタイムスタンプ

エージェント変数

エージェントを呼び出した後、出力変数を使用して応答データにアクセスします。

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

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

リテラル値と式の値

# 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

文字列操作

Concat

複数の文字列を連結する:

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

値が空か未定義か確認します。

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

条件式

If 関数

条件に基づいて異なる値を返します。

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

比較演算子

Operator Description
= 等しい =Workflow.Inputs.status = "active"
<> 等しくない =Workflow.Inputs.status <> "deleted"
< より小さい =Workflow.Inputs.age < 18
> より大きい =Workflow.Inputs.count > 0
<= 以下 =Workflow.Inputs.score <= 100
>= 大なりまたは等しい =Workflow.Inputs.quantity >= 1

ブール関数

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

数学演算

# 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

実際の式の例

ユーザーの分類

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

条件付き挨拶

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

入力の検証

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

高度なパターン

ワークフローが複雑になるにつれて、マルチステップ プロセス、エージェントの調整、対話型のシナリオを処理するパターンが必要になります。

マルチエージェント オーケストレーション

シーケンシャル エージェント パイプライン

複数のエージェントを順番に処理を渡します。各エージェントは、前のエージェントの出力に基づいて構築されます。

ユース ケース: さまざまな専門家が調査、作成、編集を処理するコンテンツ作成パイプライン。

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

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

条件付きエージェント のルーティング

入力または中間結果に基づいて異なるエージェントに要求をルーティングします。

ユース ケース: 問題の種類に基づいて特殊なエージェントにルーティングするサポート システム。

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

外部ループを含むエージェント

解決中の問題など、条件が満たされるまでエージェントの対話を続行します。

ユース ケース: ユーザーの問題が解決されるまで続く会話をサポートします。

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

ループ コントロール パターン

エージェントのイテレーティブ対話

制御されたイテレーションを使用して、エージェント間でやり取りする会話を作成します。

ユース ケース: 学生と教師のシナリオ、ディベート シミュレーション、または反復的な絞り込み。

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

カウンターに基づくループ

変数と 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!"

BreakLoop を使用した早期終了

BreakLoop を使用して、条件が満たされたときにイテレーションを早期に終了します。

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"

人間を介在させた手法パターン

対話型アンケート

ユーザーから複数の情報を収集します。

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

承認ワークフロー

アクションを続行する前に承認を要求します。

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

複雑なオーケストレーション

サポート チケットのワークフロー

エージェント ルーティング、条件付きロジック、会話管理など、複数のパターンを組み合わせた包括的な例。

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

ベスト プラクティス

命名規則

アクションと変数には、わかりやすいわかりやすい名前を使用します。

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

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

大規模なワークフローの整理

複雑なワークフローをコメント付きの論理セクションに分割します。

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

エラー処理

条件付きチェックを使用して、潜在的な問題を処理します。

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

テスト戦略

  1. 単純な開始: 複雑さを追加する前に基本的なフローをテストする
  2. 既定値を使用する: 入力に適切な既定値を指定する
  3. ログ記録の追加: 開発中のデバッグに SendActivity を使用する
  4. エッジケースのテスト: 欠落しているか無効な入力を使用して動作を検証する
# Debug logging example
- kind: SendActivity
  id: debug_log
  activity:
    text: =Concat("[DEBUG] Current state: counter=", Local.counter, ", status=", Local.status)

次のステップ

  • C# 宣言型ワークフロー のサンプル - 以下を含む完全な作業例を確認します。
    • StudentTeacher - 反復学習を使用したマルチエージェント会話
    • InvokeMcpTool - MCP サーバー ツールの統合
    • InvokeFunctionTool - ワークフローからの直接関数呼び出し
    • FunctionTools - 関数ツールを使用したエージェント
    • ToolApproval - ツールの実行に対する人間の承認
    • CustomerSupport - 複雑なサポート チケット ワークフロー
    • DeepResearch - 複数のエージェントを使用した調査ワークフロー