Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Декларативные рабочие процессы позволяют определять логику рабочего процесса с помощью файлов конфигурации YAML вместо написания программного кода. Такой подход упрощает чтение, изменение и совместное использование рабочих процессов между командами.
Обзор
С декларативными рабочими процессами вы описываете , что должен делать рабочий процесс, а не как его реализовать. Платформа обрабатывает базовое выполнение, преобразуя определения YAML в исполняемые графики рабочих процессов.
Ключевые преимущества:
- Доступный для чтения формат: синтаксис YAML легко понять, даже для разработчиков, не являющихся разработчиками
- Переносимая: определения рабочих процессов могут быть разделяемыми, версионируемыми и изменены без изменения кода
- Быстрая итерация: изменение поведения рабочего процесса путем редактирования файлов конфигурации
- Согласованная структура: предопределенные типы действий гарантируют, что рабочие процессы соответствуют рекомендациям
Когда использовать декларативные или программируемые рабочие процессы
| Сценарий | Рекомендуемый подход |
|---|---|
| Стандартные шаблоны оркестрации | Декларативный |
| Рабочие процессы, которые часто изменяются | Декларативный |
| Людям, не являющимся разработчиками, нужно изменять рабочие процессы | Декларативный |
| Сложная настраиваемая логика | Programmatic |
| Максимальная гибкость и контроль | Programmatic |
| Интеграция с существующим кодом Python | Programmatic |
Базовая структура YAML
Структура YAML немного отличается от реализаций C# и Python. Дополнительные сведения см. в разделах, посвященных языку.
Типы действий
Декларативные рабочие процессы поддерживают широкий спектр действий, охватывающих управление переменными, контроль потоков, вызов агента и инструмента, интеграцию HTTP и MCP, управление взаимодействием с человеком в процессе и управление беседами. Полный справочник по языку отображается в каждой зоне ниже; Сведения о матрице доступности на обоих языках см. в разделе "Краткий справочник по действиям " в нижней части этой статьи.
Структура YAML C#
Декларативные рабочие процессы 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 |
Да | Список действий для выполнения |
Структура YAML Python
Декларативные рабочие процессы 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 или более поздней версии
- Проект 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,
// HTTP request handler for HttpRequestAction actions (optional)
HttpRequestHandler = new DefaultHttpRequestHandler(),
// PowerFx expression limits (optional)
MaximumCallDepth = 50,
MaximumExpressionLength = 10000,
// Telemetry configuration (optional)
ConfigureTelemetry = opts => { /* configure telemetry */ },
TelemetryActivitySource = activitySource,
};
Настройка поставщика агента
Процесс рабочего 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...
}
Контрольные точки AOT и Trim-Aggressive
При публикации с Native AOT (dotnet publish -p:PublishAot=true) или при ином отключении резервного механизма на основе рефлексии у System.Text.Json (<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>) стандартный вызов CheckpointManager.CreateJson(store) завершается сбоем при фиксации контрольной точки или восстановлении состояния.
Пакет declarative-workflow поставляется с экземпляром JsonSerializerOptions, сгенерированным из исходного кода, DeclarativeWorkflowJsonOptions.Default, который охватывает все типы declarative-package, проходящие через конвейер контрольных точек. Передайте его как второй аргумент в CheckpointManager.CreateJson:
using Microsoft.Agents.AI.Workflows.Checkpointing;
using Microsoft.Agents.AI.Workflows.Declarative;
// AOT-safe: type info is resolved via the source-generated JsonSerializerContext,
// so no runtime reflection is required.
CheckpointManager checkpointManager = CheckpointManager.CreateJson(
store,
DeclarativeWorkflowJsonOptions.Default);
Замечание
Передача DeclarativeWorkflowJsonOptions.Defaultтакже безопасна для использования в средах, отличных от AOT . Это обновление с прямой заменой для CheckpointManager.CreateJson(store) — приложения, использующие рефлексию, не заметят никаких изменений в поведении. Используйте это безоговорочно, чтобы тот же код продолжал работать, если позже вы выполните публикацию с AOT или триммингом.
DeclarativeWorkflowJsonOptions отмечен как [Experimental("MAAI001")]. Отключите диагностику на сайте вызова или в файле проекта:
<PropertyGroup>
<NoWarn>$(NoWarn);MAAI001</NoWarn>
</PropertyGroup>
Регистрация определяемых пользователем типов
Если входные данные рабочего процесса, настраиваемые полезные нагрузки ActionExecutorResult.Result или аргументы запроса на утверждение непримитивных типов являются типами, определяемыми пользователем, клонируйте Default и добавьте собственный резолвер, сгенерированный исходным кодом:
// Compose: declarative-package types + your app's source-gen context.
JsonSerializerOptions options = new(DeclarativeWorkflowJsonOptions.Default);
options.TypeInfoResolverChain.Add(MyAppJsonContext.Default);
options.MakeReadOnly();
CheckpointManager checkpointManager = CheckpointManager.CreateJson(store, options);
Где MyAppJsonContext — это JsonSerializerContext, который вы определяете для типов вашего приложения:
[JsonSourceGenerationOptions(JsonSerializerDefaults.Web)]
[JsonSerializable(typeof(MyWorkflowInput))]
[JsonSerializable(typeof(MyCustomResult))]
internal sealed partial class MyAppJsonContext : JsonSerializerContext;
Совет
Полный рабочий пример, который можно запустить, включая YAML-процесс, агент на базе AzureCliCredential и наблюдаемый режим «удалите параметры, чтобы увидеть сбой», см. AotCheckpointing пример в dotnet/samples/03-workflows/Declarative/AotCheckpointing. В примере .csproj задаётся JsonSerializerIsReflectionEnabledByDefault=false, чтобы воспроизвести режим сбоя AOT без необходимости выполнять полную AOT-публикацию.
Справочник по действиям
Действия — это стандартные блоки декларативных рабочих процессов. Каждое действие выполняет определенную операцию, и действия выполняются последовательно в том порядке, в который они отображаются в 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...
Действия по управлению переменными
УстановитьПеременную
Задает переменную заданному значению.
- 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
Задает несколько переменных в одном действии.
- 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
Задает текстовую переменную указанным строковым значением.
- kind: SetTextVariable
id: set_text
displayName: Set text content
variable: Local.description
value: This is a text description
Свойства:
| Недвижимость | Обязательно | Description |
|---|---|---|
variable |
Да | Путь переменной для текстового значения |
value |
Да | Текстовое значение для установки |
ResetVariable
Очищает значение переменной.
- kind: ResetVariable
id: clear_counter
variable: Local.counter
Свойства:
| Недвижимость | Обязательно | Description |
|---|---|---|
variable |
Да | Переменный путь для сброса |
Очистить все переменные
Сбрасывает все переменные в текущем контексте.
- kind: ClearAllVariables
id: clear_all
displayName: Clear all workflow variables
ParseValue
Извлекает или преобразует данные в доступный формат.
- kind: ParseValue
id: parse_json
displayName: Parse JSON response
source: =Local.rawResponse
variable: Local.parsedData
Свойства:
| Недвижимость | Обязательно | Description |
|---|---|---|
source |
Да | Выражение, возвращающее значение для синтаксического анализа |
variable |
Да | Переменный путь для хранения выходных данных парсинга |
EditTableV2
Изменяет данные в структурированном формате таблицы.
- 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 |
Да | Данные строк для операции |
Действия потока управления
If
Выполняет действия условно на основе условия.
- 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 |
Да | Выражение, которое оценивается как истина/ложь |
then |
Да | Действия, выполняемые, если условие истинно |
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 |
нет | Действия, если ни одно условие не выполняется |
Foreach
Выполняет итерацию по коллекции.
- 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
Переход к определенному действию по идентификатору.
- 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 |
Да | Идентификатор действия для перехода к определенному месту |
Выходные действия
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 |
нет | Автоматическая отправка ответа пользователю |
Действия инструмента и HTTP
InvokeFunctionTool
Вызывает средство-функцию непосредственно из рабочего процесса без прохождения агента ИИ.
- 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 |
нет | Автоматическая отправка результата пользователю |
Настройка C# для InvokeFunctionTool:
Функции должны быть зарегистрированы с помощью 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 |
Да | URL-адрес сервера MCP |
serverLabel |
нет | Читаемая человеком метка для сервера |
toolName |
Да | Имя вызываемого средства |
conversationId |
нет | Идентификатор контекста беседы |
requireApproval |
нет | Требуется ли утверждение пользователя |
arguments |
нет | Аргументы для передачи средству |
headers |
нет | Пользовательские заголовки HTTP для запроса |
connection.name |
нет | Именованное подключение для размещенных сценариев (подключается к ProjectConnectionId в Foundry; пока полностью не поддерживается) |
output.result |
нет | Путь к хранилищу результатов инструмента |
output.messages |
нет | Путь к хранилищу сообщений результатов |
output.autoSend |
нет | Автоматическая отправка результата пользователю |
Настройка C# для InvokeMcpTool:
Настройте 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
};
HttpRequestAction
Отправляет HTTP-запрос через настроенный IHttpRequestHandler. Успешные ответы JSON анализируются перед назначением; ответы, отличные от 2xx, приводят к сбою действия.
- kind: HttpRequestAction
id: fetch_repo_info
method: GET
url: "https://api.github.com/repos/Microsoft/agent-framework"
headers:
Accept: application/vnd.github+json
User-Agent: agent-framework
queryParameters:
per_page: 10
response: Local.RepoInfo
responseHeaders: Local.RepoHeaders
Свойства:
| Недвижимость | Обязательно | Description |
|---|---|---|
url |
Да | Абсолютный URL-адрес запроса |
method |
нет | Метод HTTP; значение по умолчанию GET |
headers |
нет | Заголовки запросов |
queryParameters |
нет | Параметры запроса, добавленные к URL-адресу |
body |
нет | Текст запроса; используйте kind: json, raw или none |
requestTimeoutInMilliseconds |
нет | Время ожидания на каждый запрос |
conversationId |
нет | Добавляет текст успешного ответа в беседу |
response |
нет | Путь для хранения разобранного содержимого ответа |
responseHeaders |
нет | Путь к хранилищу заголовков ответов |
Настройка C# для HttpRequestAction:
Задает HttpRequestHandler при создании рабочего процесса. Используйте пользовательский обработчик, если вам нужны повторные попытки или внесение URL-адресов в белый список.
DeclarativeWorkflowOptions options = new(agentProvider)
{
HttpRequestHandler = new DefaultHttpRequestHandler(),
};
Workflow workflow = DeclarativeWorkflowBuilder.Build<string>("workflow.yaml", options);
Действия человека в цикле
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
ЗавершитьРазговор
Заканчивает текущую беседу.
- kind: EndConversation
id: end_chat
displayName: End conversation
СоздатьРазговор
Создает новый контекст беседы.
- kind: CreateConversation
id: create_new_conv
displayName: Create new conversation
conversationId: Local.NewConversationId
Свойства:
| Недвижимость | Обязательно | Description |
|---|---|---|
conversationId |
Да | Путь для хранения нового идентификатора беседы |
Действия беседы (только для 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# | Питон | Description |
|---|---|---|---|---|
SetVariable |
Variable | ✅ | ✅ | Установка одной переменной |
SetMultipleVariables |
Variable | ✅ | ✅ | Задание нескольких переменных |
SetTextVariable |
Variable | ✅ | ✅ | Установка текстовой переменной |
ResetVariable |
Variable | ✅ | ✅ | Очистка переменной |
ClearAllVariables |
Variable | ✅ | ✅ | Очистка всех переменных |
ParseValue |
Variable | ✅ | ✅ | Анализ и преобразование данных |
EditTableV2 |
Variable | ✅ | ✅ | Изменение данных таблицы |
If |
Управление потоком | ✅ | ✅ | Условное ветвление |
ConditionGroup |
Управление потоком | ✅ | ✅ | Коммутатор с несколькими ответвлениями |
Foreach |
Управление потоком | ✅ | ✅ | Выполнить итерацию по коллекции |
BreakLoop |
Управление потоком | ✅ | ✅ | Выход из текущего цикла |
ContinueLoop |
Управление потоком | ✅ | ✅ | Переход к следующей итерации |
GotoAction |
Управление потоком | ✅ | ✅ | Переход к действию по идентификатору |
SendActivity |
Выходные данные | ✅ | ✅ | Отправка сообщения пользователю |
InvokeAzureAgent |
Агент | ✅ | ✅ | Вызовите агента ИИ Azure |
InvokeFunctionTool |
Инструмент | ✅ | ✅ | Вызов функции напрямую |
InvokeMcpTool |
Инструмент | ✅ | ✅ | Вызов средства сервера MCP |
HttpRequestAction |
HTTP | ✅ | ✅ | Вызов конечной точки HTTP |
Question |
Человек в контуре | ✅ | ✅ | Задать пользователю вопрос |
RequestExternalInput |
Человек в контуре | ✅ | ✅ | Запрос внешних входных данных |
EndWorkflow |
Управление рабочим процессом | ✅ | ✅ | Завершение рабочего процесса |
EndConversation |
Управление рабочим процессом | ✅ | ✅ | Завершение беседы |
CreateConversation |
Управление рабочим процессом | ✅ | ✅ | Создать новую беседу |
AddConversationMessage |
Беседа | ✅ | ❌ | Добавление сообщения в тему |
CopyConversationMessages |
Беседа | ✅ | ❌ | Копирование сообщений |
RetrieveConversationMessage |
Беседа | ✅ | ❌ | Получение одного сообщения |
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 (Python 3.14 еще не поддерживается из-за совместимости PowerFx)
- Установленный декларативный пакет 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}")
for output in result.get_intermediate_outputs():
print(f"Intermediate: {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, SetMultipleVariablesResetVariable |
| Управление потоком |
If, , ConditionGroupBreakLoopForeachContinueLoop,GotoAction |
| Выходные данные | SendActivity |
| Вызов агента | InvokeAzureAgent |
| Вызов инструмента |
InvokeFunctionTool, InvokeMcpTool |
| HTTP | HttpRequestAction |
| Человек в контуре |
Question, RequestExternalInput |
| Управление рабочим процессом |
EndWorkflow, EndConversationCreateConversation |
Справочник по действиям
Действия — это стандартные блоки декларативных рабочих процессов. Каждое действие выполняет определенную операцию, и действия выполняются последовательно в том порядке, в который они отображаются в 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...
Действия по управлению переменными
УстановитьПеременную
Задает переменную заданному значению.
- 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
Задает несколько переменных в одном действии.
- 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 |
Да | Сопоставление путей переменных со значениями |
ResetVariable
Очищает значение переменной.
- kind: ResetVariable
id: clear_counter
variable: Local.counter
Свойства:
| Недвижимость | Обязательно | Description |
|---|---|---|
variable |
Да | Переменный путь для сброса |
Действия потока управления
If
Выполняет действия условно на основе условия.
- 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 |
Да | Выражение, которое оценивается как истина/ложь |
then |
Да | Действия, выполняемые, если условие истинно |
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 |
нет | Действия, если ни одно условие не выполняется |
Foreach
Выполняет итерацию по коллекции.
- 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 |
Да | Действия для каждого элемента |
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
Переход к определенному действию по идентификатору.
- 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 |
Да | Идентификатор действия для перехода к определенному месту |
Выходные действия
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 |
Да | Текст сообщения (литерал или выражение) |
Действия вызова агента
InvokeAzureAgent
Вызывает агента ИИ Azure.
Базовый вызов:
- 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 |
нет | Автоматическая отправка ответа пользователю |
Действия инструмента и HTTP
InvokeFunctionTool
Вызывает зарегистрированную функцию 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 |
нет | Автоматическая отправка результата пользователю |
Настройка Python для InvokeFunctionTool:
Функции должны быть зарегистрированы с 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"})
InvokeMcpTool
Вызывает средство на сервере MCP с помощью настроенного MCPToolHandler.
- kind: InvokeMcpTool
id: search_docs
serverUrl: https://learn.microsoft.com/api/mcp
serverLabel: microsoft_docs
toolName: microsoft_docs_search
arguments:
query: =Local.searchQuery
output:
result: Local.searchResults
messages: Local.toolMessage
autoSend: true
Свойства:
| Недвижимость | Обязательно | Description |
|---|---|---|
serverUrl |
Да | URL-адрес сервера MCP |
toolName |
Да | Название инструмента на сервере MCP |
serverLabel |
нет | Метка сервера, понятная человеку |
arguments |
нет | Аргументы, переданные средству |
headers |
нет | Заголовки запросов; Пустые значения пропускаются |
connection.name |
нет | Именованное соединение для пользовательских обработчиков |
conversationId |
нет | Добавляет результаты выполнения средства в беседу |
requireApproval |
нет | Запрашивает утверждение перед вызовом инструмента |
output.result |
нет | Путь к хранилищу выходных данных средства синтаксического анализа |
output.messages |
нет | Путь для сохранения сообщения инструмента |
output.autoSend |
нет | Выводит результаты инструмента в результат рабочего процесса; значение по умолчанию true |
Python настройка для InvokeMcpTool:
Передайте обработчик инструмента MCP для WorkflowFactory. Используйте пользовательский обработчик, если требуется проверка подлинности, управляемые соединения или список разрешенных URL-адресов.
from agent_framework.declarative import DefaultMCPToolHandler, WorkflowFactory
factory = WorkflowFactory(mcp_tool_handler=DefaultMCPToolHandler())
workflow = factory.create_workflow_from_yaml_path("workflow.yaml")
HttpRequestAction
Отправляет HTTP-запрос через настроенный HttpRequestHandler. Успешные ответы JSON анализируются перед назначением; ответы, отличные от 2xx, приводят к сбою действия.
- kind: HttpRequestAction
id: fetch_repo_info
method: GET
url: =Concat("https://api.github.com/repos/", Local.repoName)
headers:
Accept: application/vnd.github+json
User-Agent: agent-framework
queryParameters:
per_page: 10
response: Local.repoInfo
responseHeaders: Local.repoHeaders
Свойства:
| Недвижимость | Обязательно | Description |
|---|---|---|
url |
Да | Абсолютный URL-адрес запроса |
method |
нет | Метод HTTP; значение по умолчанию GET |
headers |
нет | Заголовки запросов |
queryParameters |
нет | Параметры запроса, добавленные к URL-адресу |
body |
нет | Текст запроса; используйте kind: json, raw или none |
requestTimeoutInMilliseconds |
нет | Время ожидания на каждый запрос |
connection.name |
нет | Именованное соединение для пользовательских обработчиков |
conversationId |
нет | Добавляет текст успешного ответа в беседу |
response |
нет | Путь для хранения разобранного содержимого ответа |
responseHeaders |
нет | Путь к хранилищу заголовков ответов |
** Настройка Python для HttpRequestAction:
Передайте обработчик HTTP-запроса в WorkflowFactory. Используйте пользовательский обработчик, если требуется проверка подлинности, повторные попытки или список разрешений URL-адресов.
from agent_framework.declarative import DefaultHttpRequestHandler, WorkflowFactory
factory = WorkflowFactory(http_request_handler=DefaultHttpRequestHandler())
workflow = factory.create_workflow_from_yaml_path("workflow.yaml")
Действия человека в цикле
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
ЗавершитьРазговор
Заканчивает текущую беседу.
- kind: EndConversation
id: end_chat
displayName: End conversation
СоздатьРазговор
Создает новый контекст беседы.
- kind: CreateConversation
id: create_new_conv
displayName: Create new conversation
conversationId: Local.NewConversationId
Свойства:
| Недвижимость | Обязательно | Description |
|---|---|---|
conversationId |
Да | Путь для хранения нового идентификатора беседы |
Краткий справочник по действиям
| Действие | Категория | Description |
|---|---|---|
SetVariable |
Variable | Установка одной переменной |
SetMultipleVariables |
Variable | Задание нескольких переменных |
ResetVariable |
Variable | Очистка переменной |
If |
Управление потоком | Условное ветвление |
ConditionGroup |
Управление потоком | Коммутатор с несколькими ответвлениями |
Foreach |
Управление потоком | Выполнить итерацию по коллекции |
BreakLoop |
Управление потоком | Выход из текущего цикла |
ContinueLoop |
Управление потоком | Переход к следующей итерации |
GotoAction |
Управление потоком | Переход к действию по идентификатору |
SendActivity |
Выходные данные | Отправка сообщения пользователю |
InvokeAzureAgent |
Агент | Вызовите агента ИИ Azure |
InvokeFunctionTool |
Инструмент | Вызов зарегистрированной функции |
InvokeMcpTool |
Инструмент | Вызов средства сервера MCP |
HttpRequestAction |
HTTP | Вызов конечной точки HTTP |
Question |
Человек в контуре | Задать пользователю вопрос |
RequestExternalInput |
Человек в контуре | Запрос внешних входных данных |
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
Условные выражения
Если функция
Возвращает разные значения на основе условия:
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
циклы Counter-Based
Реализуйте традиционные циклы подсчета с помощью переменных и 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: Question
id: get_approval
question:
text: =Concat("Do you approve this ", Workflow.Inputs.requestType, " request for $", Workflow.Inputs.amount, "? (yes/no)")
variable: Local.approved
- kind: If
condition: =Local.approved = "yes"
then:
- kind: SendActivity
activity:
text: "Request approved. Processing..."
- kind: SetVariable
variable: Workflow.Outputs.status
value: approved
else:
- kind: SendActivity
activity:
text: "Request denied."
- kind: SetVariable
variable: Workflow.Outputs.status
value: denied
else:
- kind: SendActivity
activity:
text: "Request auto-approved (under threshold)."
- kind: SetVariable
variable: Workflow.Outputs.status
value: auto_approved
Сложная оркестрация
Рабочий процесс запроса в службу поддержки
Полный пример объединения нескольких шаблонов: маршрутизация агентов, условная логика и управление беседами.
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 . Изучение полных рабочих примеров
Замечание
Поддержка Go для этой функции скоро появится. Сведения о последнем состоянии см. в репозитории Agent Framework Go .