宣言型ワークフローを使用すると、プログラムによるコードを記述する代わりに、YAML 構成ファイルを使用してワークフロー ロジックを定義できます。 このアプローチにより、ワークフローの読み取り、変更、チーム間での共有が容易になります。
概要
宣言型ワークフローでは、 ワークフローを実装 する 方法 ではなく、何を行う必要があるかを説明します。 フレームワークは基になる実行を処理し、YAML 定義を実行可能なワークフロー グラフに変換します。
主な利点:
- 読み取り可能な形式: 開発者以外の場合でも、YAML 構文が理解しやすい
- 移植可能: コードを変更せずに、ワークフロー定義を共有、バージョン管理、変更できます
- 迅速な反復: 構成ファイルを編集してワークフローの動作を変更する
- 一貫性のある構造: 定義済みのアクションの種類により、ワークフローがベスト プラクティスに従っていることを確認する
宣言型ワークフローとプログラム型ワークフローを使用する場合
| Scenario | 推奨されるアプローチ |
|---|---|
| 標準オーケストレーション パターン | 宣言型 |
| 頻繁に変更されるワークフロー | 宣言型 |
| 開発者以外のユーザーがワークフローを変更する必要がある | 宣言型 |
| 複雑なカスタム ロジック | プログラム的な |
| 最大限の柔軟性と制御 | プログラム的な |
| 既存の Python コードとの統合 | プログラム的な |
基本的な YAML 構造体
YAML 構造は、C# と Python の実装で若干異なります。 詳細については、以下の言語固有のセクションを参照してください。
アクションの種類
宣言型ワークフローでは、さまざまなアクションの種類がサポートされています。 次の表は、言語別の可用性を示しています。
| カテゴリ | アクション | C# | Python |
|---|---|---|---|
| 変数管理 |
SetVariable、 SetMultipleVariables、 ResetVariable |
✅ | ✅ |
| 変数管理 | AppendValue |
❌ | ✅ |
| 変数管理 |
SetTextVariable、 ClearAllVariables、 ParseValue、 EditTableV2 |
✅ | ❌ |
| 制御フロー |
If、 ConditionGroup、 Foreach、 BreakLoop、 ContinueLoop、 GotoAction |
✅ | ✅ |
| 制御フロー | RepeatUntil |
❌ | ✅ |
| アウトプット | SendActivity |
✅ | ✅ |
| アウトプット | EmitEvent |
❌ | ✅ |
| エージェント呼び出し | InvokeAzureAgent |
✅ | ✅ |
| ツールの呼び出し | InvokeFunctionTool |
✅ | ✅ |
| ツールの呼び出し | InvokeMcpTool |
✅ | ❌ |
| 人間関与システム |
Question、RequestExternalInput |
✅ | ✅ |
| 人間関与システム |
Confirmation、WaitForInput |
❌ | ✅ |
| ワークフロー コントロール |
EndWorkflow、 EndConversation、 CreateConversation |
✅ | ✅ |
| 会話 |
AddConversationMessage、 CopyConversationMessages、 RetrieveConversationMessage、 RetrieveConversationMessages |
✅ | ❌ |
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.ConversationId、System.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.name、 Workflow.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)- 値が空かどうかを確認する
アクションの種類
宣言型ワークフローでは、さまざまなアクションの種類がサポートされています。
| カテゴリ | アクション |
|---|---|
| 変数管理 |
SetVariable、 SetMultipleVariables、 AppendValue、 ResetVariable |
| 制御フロー |
If、 ConditionGroup、 Foreach、 RepeatUntil、 BreakLoop、 ContinueLoop、 GotoAction |
| アウトプット |
SendActivity、EmitEvent |
| エージェント呼び出し | InvokeAzureAgent |
| ツールの呼び出し | InvokeFunctionTool |
| 人間関与システム |
Question、 Confirmation、 RequestExternalInput、 WaitForInput |
| ワークフロー コントロール |
EndWorkflow、 EndConversation、 CreateConversation |
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.name、 Workflow.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
テスト戦略
- 単純な開始: 複雑さを追加する前に基本的なフローをテストする
- 既定値を使用する: 入力に適切な既定値を指定する
- ログ記録の追加: 開発中のデバッグに SendActivity を使用する
- エッジケースのテスト: 欠落しているか無効な入力を使用して動作を検証する
# 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 - 複数のエージェントを使用した調査ワークフロー
- Python 宣言型ワークフローサンプル - 完全な作業例を調べる