Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Los flujos de trabajo declarativos permiten definir la lógica de flujo de trabajo mediante archivos de configuración de YAML en lugar de escribir código mediante programación. Este enfoque facilita la lectura, modificación y uso compartido de flujos de trabajo entre equipos.
Información general
Con los flujos de trabajo declarativos, se describe lo que debe hacer el flujo de trabajo en lugar de cómo implementarlo. El marco controla la ejecución subyacente, convirtiendo las definiciones de YAML en gráficos de flujo de trabajo ejecutables.
Ventajas clave:
- Formato legible: la sintaxis de YAML es fácil de entender, incluso para los no desarrolladores
- Portable: las definiciones de flujo de trabajo se pueden compartir, modificar y modificar sin cambios de código.
- Iteración rápida: modificar el comportamiento del flujo de trabajo mediante la edición de archivos de configuración
- Estructura coherente: los tipos de acción predefinidos garantizan que los flujos de trabajo siguen los procedimientos recomendados
Cuándo usar flujos de trabajo declarativos frente a flujos de trabajo mediante programación
| Escenario | Enfoque recomendado |
|---|---|
| Patrones de orquestación estándar | Declarativo |
| Flujos de trabajo que cambian con frecuencia | Declarativo |
| Los no desarrolladores necesitan modificar flujos de trabajo | Declarativo |
| Lógica personalizada compleja | Mediante programación |
| Máxima flexibilidad y control | Mediante programación |
| Integración con código de Python existente | Mediante programación |
Estructura básica de YAML
La estructura YAML difiere ligeramente entre las implementaciones de C# y Python. Consulte las secciones específicas del idioma a continuación para obtener más información.
Tipos de acción
Los flujos de trabajo declarativos admiten varios tipos de acción. En la tabla siguiente se muestra la disponibilidad por idioma:
| Categoría | Acciones | C# | Pitón |
|---|---|---|---|
| Administración de variables |
SetVariable, , SetMultipleVariables, ResetVariable |
✅ | ✅ |
| Administración de variables | AppendValue |
❌ | ✅ |
| Administración de variables |
SetTextVariable, ClearAllVariables, , ParseValue, EditTableV2 |
✅ | ❌ |
| Flujo de control |
If, ConditionGroup, Foreach, BreakLoop, , ContinueLoop, GotoAction |
✅ | ✅ |
| Flujo de control | RepeatUntil |
❌ | ✅ |
| Salida | SendActivity |
✅ | ✅ |
| Salida | EmitEvent |
❌ | ✅ |
| Invocación de agente | InvokeAzureAgent |
✅ | ✅ |
| Invocación de herramientas | InvokeFunctionTool |
✅ | ✅ |
| Invocación de herramientas | InvokeMcpTool |
✅ | ❌ |
| Humano en el Bucle |
Question, RequestExternalInput |
✅ | ✅ |
| Humano en el Bucle |
Confirmation, WaitForInput |
❌ | ✅ |
| Control de flujo de trabajo |
EndWorkflow, , EndConversation, CreateConversation |
✅ | ✅ |
| Conversación |
AddConversationMessage, CopyConversationMessages, , RetrieveConversationMessage, RetrieveConversationMessages |
✅ | ❌ |
Estructura YAML de C#
Los flujos de trabajo declarativos de C# usan una estructura basada en desencadenadores:
#
# Workflow description as a comment
#
kind: Workflow
trigger:
kind: OnConversationStart
id: my_workflow
actions:
- kind: ActionType
id: unique_action_id
displayName: Human readable name
# Action-specific properties
Elementos de estructura
| Elemento | Obligatorio | Description |
|---|---|---|
kind |
Sí | Debe ser Workflow |
trigger.kind |
Sí | Tipo de desencadenador (normalmente OnConversationStart) |
trigger.id |
Sí | Identificador único del flujo de trabajo |
trigger.actions |
Sí | Lista de acciones que se van a ejecutar |
Estructura YAML de Python
Los flujos de trabajo declarativos de Python usan una estructura basada en nombres con entradas opcionales:
name: my-workflow
description: A brief description of what this workflow does
inputs:
parameterName:
type: string
description: Description of the parameter
actions:
- kind: ActionType
id: unique_action_id
displayName: Human readable name
# Action-specific properties
Elementos de estructura
| Elemento | Obligatorio | Description |
|---|---|---|
name |
Sí | Identificador único del flujo de trabajo |
description |
No | Descripción legible para humanos |
inputs |
No | Parámetros de entrada que acepta el flujo de trabajo |
actions |
Sí | Lista de acciones que se van a ejecutar |
Prerrequisitos
Antes de comenzar, asegúrese de que tiene:
- .NET 8.0 o posterior
- Un proyecto de Microsoft Foundry con al menos un agente implementado
- Los siguientes paquetes NuGet instalados:
dotnet add package Microsoft.Agents.AI.Workflows.Declarative --prerelease
dotnet add package Microsoft.Agents.AI.Workflows.Declarative.AzureAI --prerelease
- Si tiene previsto agregar la acción de invocación de la herramienta MCP al flujo de trabajo, instale también el siguiente paquete NuGet:
dotnet add package Microsoft.Agents.AI.Workflows.Declarative.Mcp --prerelease
- Conocimientos básicos de la sintaxis de YAML
- Descripción de los conceptos de flujo de trabajo
Tu Primer Flujo de Trabajo Declarativo
Vamos a crear un flujo de trabajo sencillo que salude a un usuario en función de su entrada.
Paso 1: Crear el archivo YAML
Cree un archivo denominado 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
Paso 2: Configurar el proveedor del agente
Cree una aplicación de consola de C# para ejecutar el flujo de trabajo. En primer lugar, configure el proveedor del agente que se conecta a 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());
Paso 3: Compilar y ejecutar el flujo de trabajo
// 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!");
Salida esperada
Loaded workflow from: C:\path\to\greeting-workflow.yaml
----------------------------------------
Activity: Hello, Alice!
Workflow completed!
Conceptos básicos
Espacios de nombres para variables
Los flujos de trabajo declarativos en C# usan variables con espacio de nombres para organizar el estado:
| Namespace | Description | Example |
|---|---|---|
Local.* |
Variables locales para el flujo de trabajo | Local.message |
System.* |
Valores proporcionados por el sistema |
System.ConversationId, System.LastMessage |
Nota:
Los flujos de trabajo declarativos de C# no usan ni Workflow.Inputs ni Workflow.Outputs espacios de nombres. La entrada se recibe a través de System.LastMessage y la salida se envía mediante SendActivity acciones.
Variables del sistema
| Variable | Description |
|---|---|
System.ConversationId |
Identificador de conversación actual |
System.LastMessage |
Mensaje de usuario más reciente |
System.LastMessage.Text |
Contenido de texto del último mensaje |
Lenguaje de expresiones
Los valores con = prefijo se evalúan como expresiones mediante el lenguaje de expresiones de PowerFx:
# Literal value (no evaluation)
value: Hello
# Expression (evaluated at runtime)
value: =Concat("Hello, ", Local.userName)
# Access last message text
value: =System.LastMessage.Text
Entre las funciones comunes se incluyen las siguientes:
-
Concat(str1, str2, ...)- Concatenar cadenas -
If(condition, trueValue, falseValue)- Expresión condicional -
IsBlank(value)- Comprobar si el valor está vacío -
Upper(text)/Lower(text)- Conversión de mayúsculas y minúsculas -
Find(searchText, withinText)- Buscar texto dentro de la cadena -
MessageText(message)- Extracción de texto de un objeto de mensaje -
UserMessage(text)- Creación de un mensaje de usuario a partir de texto -
AgentMessage(text)- Creación de un mensaje de agente a partir de texto
Opciones de configuración
La DeclarativeWorkflowOptions clase proporciona configuración para la ejecución del flujo de trabajo:
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,
};
Configuración del agente proveedor
AzureAgentProvider conecta el flujo de trabajo a los agentes de 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,
};
Ejecución del flujo de trabajo
Use InProcessExecution para ejecutar flujos de trabajo y controlar eventos:
using Microsoft.Agents.AI.Workflows;
using Microsoft.Agents.AI.Workflows.Checkpointing;
// Create checkpoint manager (choose in-memory or file-based)
CheckpointManager checkpointManager = CheckpointManager.CreateInMemory();
// Or persist to disk:
// var checkpointFolder = Directory.CreateDirectory("./checkpoints");
// var checkpointManager = CheckpointManager.CreateJson(
// new FileSystemJsonCheckpointStore(checkpointFolder));
// Start workflow execution
StreamingRun run = await InProcessExecution.RunStreamingAsync(
workflow,
input,
checkpointManager);
// Process events as they occur
await foreach (WorkflowEvent workflowEvent in run.WatchStreamAsync())
{
switch (workflowEvent)
{
case MessageActivityEvent activity:
Console.WriteLine($"Message: {activity.Message}");
break;
case AgentResponseUpdateEvent streamEvent:
Console.Write(streamEvent.Update.Text); // Streaming text
break;
case AgentResponseEvent response:
Console.WriteLine($"Agent: {response.Response.Text}");
break;
case RequestInfoEvent request:
// Handle external input requests (human-in-the-loop)
var userInput = await GetUserInputAsync(request);
await run.SendResponseAsync(request.Request.CreateResponse(userInput));
break;
case SuperStepCompletedEvent checkpoint:
// Checkpoint created - can resume from here if needed
var checkpointInfo = checkpoint.CompletionInfo?.Checkpoint;
break;
case WorkflowErrorEvent error:
Console.WriteLine($"Error: {error.Data}");
break;
}
}
Reanudación desde puntos de control
Los flujos de trabajo se pueden reanudar desde puntos de control para la tolerancia a errores:
// 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...
}
Referencia de Acciones
Las acciones son los bloques de construcción de flujos de trabajo declarativos. Cada acción realiza una operación específica y las acciones se ejecutan secuencialmente en el orden en que aparecen en el archivo YAML.
Estructura de acciones
Todas las acciones comparten propiedades comunes:
- 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...
Acciones de administración de variables
EstablecerVariable
Establece una variable en un valor especificado.
- kind: SetVariable
id: set_greeting
displayName: Set greeting message
variable: Local.greeting
value: Hello World
Con una expresión:
- kind: SetVariable
variable: Local.fullName
value: =Concat(Local.firstName, " ", Local.lastName)
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
variable |
Sí | Ruta variable de acceso (por ejemplo, Local.name, Workflow.Outputs.result) |
value |
Sí | Valor que se va a establecer (literal o expresión) |
SetMultipleVariables
Establece varias variables en una sola acción.
- kind: SetMultipleVariables
id: initialize_vars
displayName: Initialize variables
variables:
Local.counter: 0
Local.status: pending
Local.message: =Concat("Processing order ", Local.orderId)
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
variables |
Sí | Mapa de caminos de variables a valores |
SetTextVariable (solo C#)
Establece una variable de texto en un valor de cadena especificado.
- kind: SetTextVariable
id: set_text
displayName: Set text content
variable: Local.description
value: This is a text description
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
variable |
Sí | Ruta variable para el valor de texto |
value |
Sí | Valor de texto a establecer |
ResetVariable
Borra el valor de una variable.
- kind: ResetVariable
id: clear_counter
variable: Local.counter
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
variable |
Sí | Ruta de acceso de la variable para reiniciar |
ClearAllVariables (solo C#)
Restablece todas las variables en el contexto actual.
- kind: ClearAllVariables
id: clear_all
displayName: Clear all workflow variables
ParseValue (solo C#)
Extrae o convierte datos en un formato utilizable.
- kind: ParseValue
id: parse_json
displayName: Parse JSON response
source: =Local.rawResponse
variable: Local.parsedData
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
source |
Sí | Expresión que devuelve el valor para analizar |
variable |
Sí | Ruta variable para almacenar el resultado parseado |
EditTableV2 (solo C#)
Modifica los datos en un formato de tabla estructurado.
- kind: EditTableV2
id: update_table
displayName: Update configuration table
table: Local.configTable
operation: update
row:
key: =Local.settingName
value: =Local.settingValue
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
table |
Sí | Ruta variable a la tabla |
operation |
Sí | Tipo de operación (agregar, actualizar, eliminar) |
row |
Sí | Datos de fila para la operación |
Acciones de flujo de control
Si
Ejecuta acciones condicionalmente basadas en una condición.
- 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!"
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
condition |
Sí | Expresión que se evalúa como verdadero/falso |
then |
Sí | Acciones que se van a ejecutar si la condición es true |
else |
No | Acciones para ejecutar si la condición es false |
ConditionGroup
Evalúa varias condiciones como una sentencia 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
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
conditions |
Sí | Lista de pares de condición/acciones (gana la primera coincidencia) |
elseActions |
No | Acciones si no coincide ninguna condición |
Foreach
Recorre en iteración una colección.
- 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)
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
source |
Sí | Expresión que devuelve una colección |
itemName |
No | Nombre de variable para el elemento actual (valor predeterminado: item) |
indexName |
No | Nombre de variable para el índice actual (valor predeterminado: index) |
actions |
Sí | Acciones que se van a ejecutar para cada elemento |
BreakLoop
Sale del bucle actual inmediatamente.
- kind: Foreach
source: =Local.items
actions:
- kind: If
condition: =item = "stop"
then:
- kind: BreakLoop
- kind: SendActivity
activity:
text: =item
ContinueLoop
Omite la siguiente iteración del bucle.
- kind: Foreach
source: =Local.numbers
actions:
- kind: If
condition: =item < 0
then:
- kind: ContinueLoop
- kind: SendActivity
activity:
text: =Concat("Positive number: ", item)
GotoAction
Salta a una acción específica por identificador.
- 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
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
actionId |
Sí | Identificador de la acción a la que se desea saltar |
Acciones de salida
SendActivity
Envía un mensaje al usuario.
- kind: SendActivity
id: send_welcome
displayName: Send welcome message
activity:
text: "Welcome to our service!"
Con una expresión:
- kind: SendActivity
activity:
text: =Concat("Hello, ", Local.userName, "! How can I help you today?")
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
activity |
Sí | La actividad que se va a enviar |
activity.text |
Sí | Texto del mensaje (literal o expresión) |
Acciones de invocación del agente
InvokeAzureAgent
Invoca un agente de Foundry.
Invocación básica:
- kind: InvokeAzureAgent
id: call_assistant
displayName: Call assistant agent
agent:
name: AssistantAgent
conversationId: =System.ConversationId
Con la configuración de entrada y salida:
- 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
Usando el bucle externo (continúa hasta que se cumpla la condición):
- kind: InvokeAzureAgent
id: support_agent
agent:
name: SupportAgent
input:
externalLoop:
when: =Not(Local.IsResolved)
output:
responseObject: Local.SupportResult
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
agent.name |
Sí | Nombre del agente registrado |
conversationId |
No | Identificador de contexto de conversación |
input.messages |
No | Mensajes que se van a enviar al agente |
input.arguments |
No | Argumentos adicionales para el agente |
input.externalLoop.when |
No | Condición para continuar con el bucle del agente |
output.responseObject |
No | Ruta de acceso para almacenar la respuesta del agente |
output.messages |
No | Ruta de acceso para almacenar mensajes de conversación |
output.autoSend |
No | Enviar automáticamente respuesta al usuario |
Acciones de invocación de herramientas (solo C#)
InvokeFunctionTool
Invoca una herramienta de función directamente desde el flujo de trabajo sin pasar por un agente de IA.
- kind: InvokeFunctionTool
id: invoke_get_data
displayName: Get data from function
functionName: GetUserData
conversationId: =System.ConversationId
requireApproval: true
arguments:
userId: =Local.userId
output:
autoSend: true
result: Local.UserData
messages: Local.FunctionMessages
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
functionName |
Sí | Nombre de la función que se va a invocar |
conversationId |
No | Identificador de contexto de conversación |
requireApproval |
No | Si se debe requerir la aprobación del usuario antes de la ejecución |
arguments |
No | Argumentos que se van a pasar a la función |
output.result |
No | Ruta de acceso para almacenar el resultado de la función |
output.messages |
No | Ruta de acceso para almacenar mensajes de función |
output.autoSend |
No | Enviar automáticamente el resultado al usuario |
Programa de instalación de C# para InvokeFunctionTool:
Las funciones deben registrarse con WorkflowRunner o controlarse a través de una entrada externa.
// Define functions that can be invoked
AIFunction[] functions = [
AIFunctionFactory.Create(myPlugin.GetUserData),
AIFunctionFactory.Create(myPlugin.ProcessOrder),
];
// Create workflow runner with functions
WorkflowRunner runner = new(functions) { UseJsonCheckpoints = true };
await runner.ExecuteAsync(workflowFactory.CreateWorkflow, input);
InvokeMcpTool
Invoca una herramienta en un servidor MCP (Modelo de Protocolo de Contexto).
- 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
Con el nombre de conexión para escenarios hospedados:
- kind: InvokeMcpTool
id: invoke_hosted_mcp
serverUrl: https://mcp.ai.azure.com
toolName: my_tool
# Connection name is used in hosted scenarios to connect to a ProjectConnectionId in Foundry.
# Note: This feature is not fully supported yet.
connection:
name: my-foundry-connection
output:
result: Local.ToolResult
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
serverUrl |
Sí | Dirección URL del servidor MCP |
serverLabel |
No | Etiqueta legible por humanos para el servidor |
toolName |
Sí | Nombre de la herramienta que se va a invocar |
conversationId |
No | Identificador de contexto de conversación |
requireApproval |
No | Si se necesita la aprobación del usuario |
arguments |
No | Argumentos que se van a pasar a la herramienta |
headers |
No | Encabezados HTTP personalizados para la solicitud |
connection.name |
No | Conexión con nombre para escenarios hospedados (se conecta a ProjectConnectionId en Foundry; aún no se admite completamente) |
output.result |
No | Ruta de almacenamiento del resultado de la herramienta |
output.messages |
No | Ruta de acceso para almacenar mensajes de resultado |
output.autoSend |
No | Enviar automáticamente el resultado al usuario |
Programa de instalación de C# para InvokeMcpTool:
Configura el McpToolHandler en tu fábrica de flujos de trabajo.
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
};
Acciones humanas en el bucle
Pregunta
Formula una pregunta al usuario y almacena la respuesta.
- kind: Question
id: ask_name
displayName: Ask for user name
question:
text: "What is your name?"
variable: Local.userName
default: "Guest"
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
question.text |
Sí | La pregunta que se va a formular |
variable |
Sí | Ruta de acceso para almacenar la respuesta |
default |
No | Valor predeterminado si no hay respuesta |
RequestExternalInput
Solicita la entrada de un sistema externo o un proceso.
- kind: RequestExternalInput
id: request_approval
displayName: Request manager approval
prompt:
text: "Please provide approval for this request."
variable: Local.approvalResult
default: "pending"
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
prompt.text |
Sí | Descripción de la entrada necesaria |
variable |
Sí | Ruta de acceso para almacenar la entrada |
default |
No | Valor predeterminado |
Acciones de control de flujo de trabajo
EndWorkflow
Finaliza la ejecución del flujo de trabajo.
- kind: EndWorkflow
id: finish
displayName: End workflow
EndConversation
Finaliza la conversación actual.
- kind: EndConversation
id: end_chat
displayName: End conversation
CrearConversación
Crea un nuevo contexto de conversación.
- kind: CreateConversation
id: create_new_conv
displayName: Create new conversation
conversationId: Local.NewConversationId
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
conversationId |
Sí | Ruta de almacenamiento del nuevo ID de conversación |
Acciones de conversación (solo C#)
AddConversationMessage
Agrega un mensaje a un hilo de conversación.
- kind: AddConversationMessage
id: add_system_message
displayName: Add system context
conversationId: =System.ConversationId
message:
role: system
content: =Local.contextInfo
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
conversationId |
Sí | Identificador de conversación de destino |
message |
Sí | Mensaje que se va a agregar |
message.role |
Sí | Rol de mensaje (sistema, usuario, asistente) |
message.content |
Sí | Contenido del mensaje |
CopiarMensajesDeConversación
Copia mensajes de una conversación a otra.
- kind: CopyConversationMessages
id: copy_context
displayName: Copy conversation context
sourceConversationId: =Local.SourceConversation
targetConversationId: =System.ConversationId
limit: 10
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
sourceConversationId |
Sí | Identificador de conversación de origen |
targetConversationId |
Sí | Identificador de conversación de destino |
limit |
No | Número máximo de mensajes que se van a copiar |
ObtenerMensajeDeConversación
Recupera un mensaje específico de una conversación.
- kind: RetrieveConversationMessage
id: get_message
displayName: Get specific message
conversationId: =System.ConversationId
messageId: =Local.targetMessageId
variable: Local.retrievedMessage
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
conversationId |
Sí | Identificador de conversación |
messageId |
Sí | Identificador de mensaje que se va a recuperar |
variable |
Sí | Ruta de acceso para almacenar el mensaje recuperado |
RecuperarMensajesDeConversación
Recupera varios mensajes de una conversación.
- kind: RetrieveConversationMessages
id: get_history
displayName: Get conversation history
conversationId: =System.ConversationId
limit: 20
newestFirst: true
variable: Local.conversationHistory
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
conversationId |
Sí | Identificador de conversación |
limit |
No | Número máximo de mensajes que se van a recuperar (valor predeterminado: 20) |
newestFirst |
No | Retornar en orden descendente |
after |
No | Cursor para paginación |
before |
No | Cursor para paginación |
variable |
Sí | Ruta de acceso para almacenar mensajes recuperados |
Referencia rápida de acciones
| Acción | Categoría | C# | Pitón | Description |
|---|---|---|---|---|
SetVariable |
Variable | ✅ | ✅ | Establecimiento de una sola variable |
SetMultipleVariables |
Variable | ✅ | ✅ | Establecimiento de varias variables |
SetTextVariable |
Variable | ✅ | ❌ | Establecer una variable de texto |
AppendValue |
Variable | ❌ | ✅ | Anexar a lista/cadena |
ResetVariable |
Variable | ✅ | ✅ | Borrar una variable |
ClearAllVariables |
Variable | ✅ | ❌ | Borrar todas las variables |
ParseValue |
Variable | ✅ | ❌ | Análisis y transformación de datos |
EditTableV2 |
Variable | ✅ | ❌ | Modificación de datos de tabla |
If |
Flujo de control | ✅ | ✅ | Ramificación condicional. |
ConditionGroup |
Flujo de control | ✅ | ✅ | Conmutador de varias ramas |
Foreach |
Flujo de control | ✅ | ✅ | Iteración de la colección |
RepeatUntil |
Flujo de control | ❌ | ✅ | Repetir el bucle hasta que se cumpla la condición |
BreakLoop |
Flujo de control | ✅ | ✅ | Salir del bucle actual |
ContinueLoop |
Flujo de control | ✅ | ✅ | Saltar a la siguiente iteración |
GotoAction |
Flujo de control | ✅ | ✅ | Saltar a la acción por identificador |
SendActivity |
Salida | ✅ | ✅ | Enviar mensaje al usuario |
EmitEvent |
Salida | ❌ | ✅ | Emisión de eventos personalizados |
InvokeAzureAgent |
Agente | ✅ | ✅ | Llamada al agente de Azure AI |
InvokeFunctionTool |
Herramienta | ✅ | ✅ | Invocar la función directamente |
InvokeMcpTool |
Herramienta | ✅ | ❌ | Invocar herramienta de servidor MCP |
Question |
Humano en el Bucle | ✅ | ✅ | Formular una pregunta al usuario |
Confirmation |
Humano en el Bucle | ❌ | ✅ | Sí/no confirmación |
RequestExternalInput |
Humano en el Bucle | ✅ | ✅ | Solicitud de entrada externa |
WaitForInput |
Humano en el Bucle | ❌ | ✅ | Esperar entrada |
EndWorkflow |
Control de flujo de trabajo | ✅ | ✅ | Finalizar flujo de trabajo |
EndConversation |
Control de flujo de trabajo | ✅ | ✅ | Finalizar conversación |
CreateConversation |
Control de flujo de trabajo | ✅ | ✅ | Creación de una nueva conversación |
AddConversationMessage |
Conversación | ✅ | ❌ | Añadir mensaje al hilo |
CopyConversationMessages |
Conversación | ✅ | ❌ | Copiar mensajes |
RetrieveConversationMessage |
Conversación | ✅ | ❌ | Obtener mensaje único |
RetrieveConversationMessages |
Conversación | ✅ | ❌ | Recibir varios mensajes |
Patrones avanzados
Orquestación multiagente
Canalización del agente secuencial
Pase el trabajo a través de varios agentes en secuencia.
#
# 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
Configuración de 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");
Enrutamiento condicional de agentes
Enrutar solicitudes a diferentes agentes en función de las condiciones.
#
# 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
Patrones de integración de herramientas
Captura previa de datos con InvokeFunctionTool
Capturar datos antes de llamar a un agente:
#
# Pre-fetch menu data before agent interaction
#
kind: Workflow
trigger:
kind: OnConversationStart
id: menu_workflow
actions:
# Pre-fetch today's specials
- kind: InvokeFunctionTool
id: get_specials
functionName: GetSpecials
requireApproval: true
output:
autoSend: true
result: Local.Specials
# Agent uses pre-fetched data
- kind: InvokeAzureAgent
id: menu_agent
conversationId: =System.ConversationId
agent:
name: MenuAgent
input:
messages: =UserMessage("Describe today's specials: " & Local.Specials)
Integración de herramientas de MCP
Llame al servidor externo mediante 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")
Prerrequisitos
Antes de comenzar, asegúrese de que tiene:
- Python 3.10: 3.13 (Python 3.14 aún no se admite debido a la compatibilidad de PowerFx)
- El paquete declarativo de Agent Framework instalado:
pip install agent-framework-declarative --pre
Este paquete extrae automáticamente el subyacente agent-framework-core .
- Conocimientos básicos de la sintaxis de YAML
- Descripción de los conceptos de flujo de trabajo
Tu Primer Flujo de Trabajo Declarativo
Vamos a crear un flujo de trabajo sencillo que salude a un usuario por nombre.
Paso 1: Crear el archivo YAML
Cree un archivo denominado 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
Paso 2: Cargar y ejecutar el flujo de trabajo
Cree un archivo de Python para ejecutar el flujo de trabajo:
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())
Salida esperada
Loaded workflow: greeting-workflow
----------------------------------------
Output: Hello, Alice!
Conceptos básicos
Espacios de nombres para variables
Los flujos de trabajo declarativos usan variables con espacio de nombres para organizar el estado:
| Namespace | Description | Example |
|---|---|---|
Local.* |
Variables locales para el flujo de trabajo | Local.message |
Workflow.Inputs.* |
Parámetros de entrada | Workflow.Inputs.name |
Workflow.Outputs.* |
Valores de salida | Workflow.Outputs.result |
System.* |
Valores proporcionados por el sistema | System.ConversationId |
Lenguaje de expresiones
Los valores con = prefijo se evalúan como expresiones:
# Literal value (no evaluation)
value: Hello
# Expression (evaluated at runtime)
value: =Concat("Hello, ", Workflow.Inputs.name)
Entre las funciones comunes se incluyen las siguientes:
-
Concat(str1, str2, ...)- Concatenar cadenas -
If(condition, trueValue, falseValue)- Expresión condicional -
IsBlank(value)- Comprobar si el valor está vacío
Tipos de acción
Los flujos de trabajo declarativos admiten varios tipos de acciones:
| Categoría | Acciones |
|---|---|
| Administración de variables |
SetVariable, SetMultipleVariables, , AppendValue, ResetVariable |
| Flujo de control |
If, ConditionGroup, Foreach, RepeatUntil, BreakLoop, , ContinueLoopGotoAction |
| Salida |
SendActivity, EmitEvent |
| Invocación de agente | InvokeAzureAgent |
| Invocación de herramientas | InvokeFunctionTool |
| Humano en el Bucle |
Question, Confirmation, , RequestExternalInput, WaitForInput |
| Control de flujo de trabajo |
EndWorkflow, , EndConversation, CreateConversation |
Referencia de Acciones
Las acciones son los bloques de construcción de flujos de trabajo declarativos. Cada acción realiza una operación específica y las acciones se ejecutan secuencialmente en el orden en que aparecen en el archivo YAML.
Estructura de acciones
Todas las acciones comparten propiedades comunes:
- 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...
Acciones de administración de variables
EstablecerVariable
Establece una variable en un valor especificado.
- kind: SetVariable
id: set_greeting
displayName: Set greeting message
variable: Local.greeting
value: Hello World
Con una expresión:
- kind: SetVariable
variable: Local.fullName
value: =Concat(Workflow.Inputs.firstName, " ", Workflow.Inputs.lastName)
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
variable |
Sí | Ruta variable de acceso (por ejemplo, Local.name, Workflow.Outputs.result) |
value |
Sí | Valor que se va a establecer (literal o expresión) |
Nota:
Python también admite el SetValue tipo de acción, que usa path en lugar de variable para la propiedad de destino. Tanto SetVariable (con variable) como SetValue (con path) logran el mismo resultado. Por ejemplo:
- kind: SetValue
id: set_greeting
path: Local.greeting
value: Hello World
SetMultipleVariables
Establece varias variables en una sola acción.
- kind: SetMultipleVariables
id: initialize_vars
displayName: Initialize variables
variables:
Local.counter: 0
Local.status: pending
Local.message: =Concat("Processing order ", Workflow.Inputs.orderId)
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
variables |
Sí | Mapa de caminos de variables a valores |
AppendValue
Anexa un valor a una lista o concatena a una cadena.
- kind: AppendValue
id: add_item
variable: Local.items
value: =Workflow.Inputs.newItem
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
variable |
Sí | Ruta de acceso de la variable para anexar |
value |
Sí | Valor para adjuntar |
ResetVariable
Borra el valor de una variable.
- kind: ResetVariable
id: clear_counter
variable: Local.counter
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
variable |
Sí | Ruta de acceso de la variable para reiniciar |
Acciones de flujo de control
Si
Ejecuta acciones condicionalmente basadas en una condición.
- 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!"
Condiciones anidadas:
- 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"
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
condition |
Sí | Expresión que se evalúa como verdadero/falso |
then |
Sí | Acciones que se van a ejecutar si la condición es true |
else |
No | Acciones para ejecutar si la condición es false |
ConditionGroup
Evalúa varias condiciones como una sentencia 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
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
conditions |
Sí | Lista de pares de condición/acciones (gana la primera coincidencia) |
elseActions |
No | Acciones si no coincide ninguna condición |
Foreach
Recorre en iteración una colección.
- 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)
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
source |
Sí | Expresión que devuelve una colección |
itemName |
No | Nombre de variable para el elemento actual (valor predeterminado: item) |
indexName |
No | Nombre de variable para el índice actual (valor predeterminado: index) |
actions |
Sí | Acciones que se van a ejecutar para cada elemento |
RepetirHasta
Repite las acciones hasta que una condición se vuelve verdadera.
- 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)
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
condition |
Sí | El bucle continúa hasta que sea verdadero |
actions |
Sí | Acciones que se van a repetir |
BreakLoop
Sale del bucle actual inmediatamente.
- kind: Foreach
source: =Workflow.Inputs.items
actions:
- kind: If
condition: =item = "stop"
then:
- kind: BreakLoop
- kind: SendActivity
activity:
text: =item
ContinueLoop
Omite la siguiente iteración del bucle.
- kind: Foreach
source: =Workflow.Inputs.numbers
actions:
- kind: If
condition: =item < 0
then:
- kind: ContinueLoop
- kind: SendActivity
activity:
text: =Concat("Positive number: ", item)
GotoAction
Salta a una acción específica por identificador.
- 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
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
actionId |
Sí | Identificador de la acción a la que se desea saltar |
Acciones de salida
SendActivity
Envía un mensaje al usuario.
- kind: SendActivity
id: send_welcome
displayName: Send welcome message
activity:
text: "Welcome to our service!"
Con una expresión:
- kind: SendActivity
activity:
text: =Concat("Hello, ", Workflow.Inputs.name, "! How can I help you today?")
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
activity |
Sí | La actividad que se va a enviar |
activity.text |
Sí | Texto del mensaje (literal o expresión) |
EmitirEvento
Emite un evento personalizado.
- kind: EmitEvent
id: emit_status
displayName: Emit status event
eventType: order_status_changed
data:
orderId: =Workflow.Inputs.orderId
status: =Local.newStatus
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
eventType |
Sí | Identificador de tipo para el evento |
data |
No | Datos de carga de eventos |
Acciones de invocación del agente
InvokeAzureAgent
Invoca un agente de Azure AI.
Invocación básica:
- kind: InvokeAzureAgent
id: call_assistant
displayName: Call assistant agent
agent:
name: AssistantAgent
conversationId: =System.ConversationId
Con la configuración de entrada y salida:
- 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
Usando el bucle externo (continúa hasta que se cumpla la condición):
- kind: InvokeAzureAgent
id: support_agent
agent:
name: SupportAgent
input:
externalLoop:
when: =Not(Local.IsResolved)
output:
responseObject: Local.SupportResult
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
agent.name |
Sí | Nombre del agente registrado |
conversationId |
No | Identificador de contexto de conversación |
input.messages |
No | Mensajes que se van a enviar al agente |
input.arguments |
No | Argumentos adicionales para el agente |
input.externalLoop.when |
No | Condición para continuar con el bucle del agente |
output.responseObject |
No | Ruta de acceso para almacenar la respuesta del agente |
output.messages |
No | Ruta de acceso para almacenar mensajes de conversación |
output.autoSend |
No | Enviar automáticamente respuesta al usuario |
Acciones de invocación de herramientas
InvokeFunctionTool
Invoca una función de Python registrada directamente desde el flujo de trabajo sin pasar por un agente de IA.
- kind: InvokeFunctionTool
id: invoke_weather
displayName: Get weather data
functionName: get_weather
arguments:
location: =Local.location
unit: =Local.unit
output:
result: Local.weatherInfo
messages: Local.weatherToolCallItems
autoSend: true
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
functionName |
Sí | Nombre de la función registrada que se va a invocar |
arguments |
No | Argumentos que se van a pasar a la función |
output.result |
No | Ruta de acceso para almacenar el resultado de la función |
output.messages |
No | Ruta de acceso para almacenar mensajes de función |
output.autoSend |
No | Enviar automáticamente el resultado al usuario |
Configuración de Python para InvokeFunctionTool:
Las funciones deben registrarse en WorkflowFactory usando register_tool:
from agent_framework.declarative import WorkflowFactory
# Define your functions
def get_weather(location: str, unit: str = "F") -> dict:
"""Get weather information for a location."""
# Your implementation here
return {"location": location, "temp": 72, "unit": unit}
def format_message(template: str, data: dict) -> str:
"""Format a message template with data."""
return template.format(**data)
# Register functions with the factory
factory = (
WorkflowFactory()
.register_tool("get_weather", get_weather)
.register_tool("format_message", format_message)
)
# Load and run the workflow
workflow = factory.create_workflow_from_yaml_path("workflow.yaml")
result = await workflow.run({"location": "Seattle", "unit": "F"})
Acciones humanas en el bucle
Pregunta
Formula una pregunta al usuario y almacena la respuesta.
- kind: Question
id: ask_name
displayName: Ask for user name
question:
text: "What is your name?"
variable: Local.userName
default: "Guest"
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
question.text |
Sí | La pregunta que se va a formular |
variable |
Sí | Ruta de acceso para almacenar la respuesta |
default |
No | Valor predeterminado si no hay respuesta |
Confirmación
Pide al usuario una confirmación sí/no.
- kind: Confirmation
id: confirm_delete
displayName: Confirm deletion
question:
text: "Are you sure you want to delete this item?"
variable: Local.confirmed
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
question.text |
Sí | Pregunta de confirmación |
variable |
Sí | Ruta para almacenar el resultado booleano |
RequestExternalInput
Solicita la entrada de un sistema externo o un proceso.
- kind: RequestExternalInput
id: request_approval
displayName: Request manager approval
prompt:
text: "Please provide approval for this request."
variable: Local.approvalResult
default: "pending"
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
prompt.text |
Sí | Descripción de la entrada necesaria |
variable |
Sí | Ruta de acceso para almacenar la entrada |
default |
No | Valor predeterminado |
WaitForInput
Pausa el flujo de trabajo y espera la entrada externa.
- kind: WaitForInput
id: wait_for_response
variable: Local.externalResponse
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
variable |
Sí | Ruta de acceso para almacenar la entrada cuando se recibe |
Acciones de control de flujo de trabajo
EndWorkflow
Finaliza la ejecución del flujo de trabajo.
- kind: EndWorkflow
id: finish
displayName: End workflow
EndConversation
Finaliza la conversación actual.
- kind: EndConversation
id: end_chat
displayName: End conversation
CrearConversación
Crea un nuevo contexto de conversación.
- kind: CreateConversation
id: create_new_conv
displayName: Create new conversation
conversationId: Local.NewConversationId
Propiedades:
| Propiedad | Obligatorio | Description |
|---|---|---|
conversationId |
Sí | Ruta de almacenamiento del nuevo ID de conversación |
Referencia rápida de acciones
| Acción | Categoría | Description |
|---|---|---|
SetVariable |
Variable | Establecimiento de una sola variable |
SetMultipleVariables |
Variable | Establecimiento de varias variables |
AppendValue |
Variable | Anexar a lista/cadena |
ResetVariable |
Variable | Borrar una variable |
If |
Flujo de control | Ramificación condicional. |
ConditionGroup |
Flujo de control | Conmutador de varias ramas |
Foreach |
Flujo de control | Iteración de la colección |
RepeatUntil |
Flujo de control | Repetir el bucle hasta que se cumpla la condición |
BreakLoop |
Flujo de control | Salir del bucle actual |
ContinueLoop |
Flujo de control | Saltar a la siguiente iteración |
GotoAction |
Flujo de control | Saltar a la acción por identificador |
SendActivity |
Salida | Enviar mensaje al usuario |
EmitEvent |
Salida | Emisión de eventos personalizados |
InvokeAzureAgent |
Agente | Llamada al agente de Azure AI |
InvokeFunctionTool |
Herramienta | Invocar función registrada |
Question |
Humano en el Bucle | Formular una pregunta al usuario |
Confirmation |
Humano en el Bucle | Sí/no confirmación |
RequestExternalInput |
Humano en el Bucle | Solicitud de entrada externa |
WaitForInput |
Humano en el Bucle | Esperar entrada |
EndWorkflow |
Control de flujo de trabajo | Finalizar flujo de trabajo |
EndConversation |
Control de flujo de trabajo | Finalizar conversación |
CreateConversation |
Control de flujo de trabajo | Creación de una nueva conversación |
Sintaxis de expresión
Los flujos de trabajo declarativos usan un lenguaje de expresiones similar a PowerFx para administrar valores dinámicos de estado y proceso. Los valores con = prefijo se evalúan como expresiones en tiempo de ejecución.
Detalles del espacio de nombres de variables
| Namespace | Description | Acceso |
|---|---|---|
Local.* |
Variables locales de flujo de trabajo | Lectura y escritura |
Workflow.Inputs.* |
Parámetros de entrada pasados al flujo de trabajo | Solo lectura |
Workflow.Outputs.* |
Valores devueltos desde el flujo de trabajo | Lectura y escritura |
System.* |
Valores proporcionados por el sistema | Solo lectura |
Agent.* |
Resultados de invocaciones del agente | Solo lectura |
Variables del sistema
| Variable | Description |
|---|---|
System.ConversationId |
Identificador de conversación actual |
System.LastMessage |
El mensaje más reciente |
System.Timestamp |
Marca de tiempo actual |
Variables del agente
Después de invocar un agente, acceda a los datos de respuesta a través de la variable de salida:
actions:
- kind: InvokeAzureAgent
id: call_assistant
agent:
name: MyAgent
output:
responseObject: Local.AgentResult
# Access agent response
- kind: SendActivity
activity:
text: =Local.AgentResult.text
Valores literales frente a valores de expresión
# 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
Operaciones con cadenas
Concat
Concatenar varias cadenas:
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
Compruebe si un valor está vacío o no definido:
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
Expresiones condicionales
If (función)
Devuelve valores diferentes en función de una condición:
value: =If(Workflow.Inputs.age < 18, "minor", "adult")
value: =If(Local.count > 0, "Items found", "No items")
# Nested conditions
value: =If(Workflow.Inputs.role = "admin", "Full access", If(Workflow.Inputs.role = "user", "Limited access", "No access"))
Operadores de comparación
| Operador | Description | Example |
|---|---|---|
= |
Igual a | =Workflow.Inputs.status = "active" |
<> |
No es igual a | =Workflow.Inputs.status <> "deleted" |
< |
Menor que | =Workflow.Inputs.age < 18 |
> |
Mayor que | =Workflow.Inputs.count > 0 |
<= |
Menor o igual que | =Workflow.Inputs.score <= 100 |
>= |
Mayor o igual que | =Workflow.Inputs.quantity >= 1 |
Funciones booleanas
# 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))
Operaciones matemáticas
# Addition
value: =Workflow.Inputs.price + Workflow.Inputs.tax
# Subtraction
value: =Workflow.Inputs.total - Workflow.Inputs.discount
# Multiplication
value: =Workflow.Inputs.quantity * Workflow.Inputs.unitPrice
# Division
value: =Workflow.Inputs.total / Workflow.Inputs.count
Ejemplos prácticos de expresiones
Categorización de usuarios
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
Saludo condicional
name: smart-greeting
inputs:
name:
type: string
description: User's name (optional)
timeOfDay:
type: string
description: morning, afternoon, or evening
actions:
# Set the greeting based on time of day
- kind: SetVariable
variable: Local.timeGreeting
value: =If(Workflow.Inputs.timeOfDay = "morning", "Good morning", If(Workflow.Inputs.timeOfDay = "afternoon", "Good afternoon", "Good evening"))
# Handle optional name
- kind: SetVariable
variable: Local.userName
value: =If(IsBlank(Workflow.Inputs.name), "friend", Workflow.Inputs.name)
# Build the full greeting
- kind: SetVariable
variable: Local.fullGreeting
value: =Concat(Local.timeGreeting, ", ", Local.userName, "!")
- kind: SendActivity
activity:
text: =Local.fullGreeting
Validación de entrada
name: validate-order
inputs:
quantity:
type: integer
description: Number of items to order
email:
type: string
description: Customer email
actions:
# Check if inputs are valid
- kind: SetVariable
variable: Local.isValidQuantity
value: =And(Workflow.Inputs.quantity > 0, Workflow.Inputs.quantity <= 100)
- kind: SetVariable
variable: Local.hasEmail
value: =Not(IsBlank(Workflow.Inputs.email))
- kind: SetVariable
variable: Local.isValid
value: =And(Local.isValidQuantity, Local.hasEmail)
- kind: If
condition: =Local.isValid
then:
- kind: SendActivity
activity:
text: "Order validated successfully!"
else:
- kind: SendActivity
activity:
text: =If(Not(Local.isValidQuantity), "Invalid quantity (must be 1-100)", "Email is required")
Patrones avanzados
A medida que tus flujos de trabajo crecen en complejidad, necesitarás patrones que manejen los procesos de varios pasos, la coordinación de agentes y los escenarios interactivos.
Orquestación multiagente
Canalización del agente secuencial
Pase el trabajo por múltiples agentes en secuencia, donde cada agente se basa en el resultado del agente anterior.
Caso de uso: canalizaciones de creación de contenido en las que diferentes especialistas controlan la investigación, la escritura y la edición.
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
Configuración de 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"})
Enrutamiento condicional de agentes
Enrutar solicitudes a diferentes agentes en función de los resultados de entrada o intermedios.
Caso de uso: Soporte a sistemas que enrutan a agentes especializados según el tipo de problema.
name: support-router
description: Route to specialized support agents
inputs:
category:
type: string
description: Support category (billing, technical, general)
actions:
- kind: ConditionGroup
id: route_request
displayName: Route to appropriate agent
conditions:
- condition: =Workflow.Inputs.category = "billing"
id: billing_route
actions:
- kind: InvokeAzureAgent
id: billing_agent
agent:
name: BillingAgent
conversationId: =System.ConversationId
- condition: =Workflow.Inputs.category = "technical"
id: technical_route
actions:
- kind: InvokeAzureAgent
id: technical_agent
agent:
name: TechnicalAgent
conversationId: =System.ConversationId
elseActions:
- kind: InvokeAzureAgent
id: general_agent
agent:
name: GeneralAgent
conversationId: =System.ConversationId
Agente con bucle externo
Continúe la interacción del agente hasta que se cumpla una condición, como el problema que se va a resolver.
Caso de uso: admita conversaciones que continúen hasta que se resuelva el problema del usuario.
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."
Patrones de control de bucle
Conversación del agente iterador
Cree conversaciones de ida y vuelta entre agentes con iteración controlada.
Caso de uso: escenarios de alumno-profesor, simulaciones de debate o refinamiento iterativo.
name: student-teacher
description: Iterative learning conversation between student and teacher
kind: Workflow
trigger:
kind: OnConversationStart
id: learning_session
actions:
# Initialize turn counter
- kind: SetVariable
id: init_counter
variable: Local.TurnCount
value: 0
- kind: SendActivity
id: start_message
activity:
text: =Concat("Starting session for: ", Workflow.Inputs.problem)
# Student attempts solution (loop entry point)
- kind: SendActivity
id: student_label
activity:
text: "\n[Student]:"
- kind: InvokeAzureAgent
id: student_attempt
conversationId: =System.ConversationId
agent:
name: StudentAgent
# Teacher reviews
- kind: SendActivity
id: teacher_label
activity:
text: "\n[Teacher]:"
- kind: InvokeAzureAgent
id: teacher_review
conversationId: =System.ConversationId
agent:
name: TeacherAgent
output:
messages: Local.TeacherResponse
# Increment counter
- kind: SetVariable
id: increment
variable: Local.TurnCount
value: =Local.TurnCount + 1
# Check completion conditions
- kind: ConditionGroup
id: check_completion
conditions:
# Success: Teacher congratulated student
- condition: =Not(IsBlank(Find("congratulations", Local.TeacherResponse)))
id: success_check
actions:
- kind: SendActivity
activity:
text: "Session complete - student succeeded!"
- kind: SetVariable
variable: Workflow.Outputs.result
value: success
# Continue: Under turn limit
- condition: =Local.TurnCount < 4
id: continue_check
actions:
- kind: GotoAction
actionId: student_label
elseActions:
# Timeout: Reached turn limit
- kind: SendActivity
activity:
text: "Session ended - turn limit reached."
- kind: SetVariable
variable: Workflow.Outputs.result
value: timeout
Bucles Basados en Contador
Implemente bucles de recuento tradicionales mediante variables y 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!"
Salida anticipada con BreakLoop
Usar BreakLoop para salir de las iteraciones antes cuando se cumple una condición.
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"
Patrones de bucle humano en el bucle
Encuesta interactiva
Recopile varios fragmentos de información del usuario.
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
Flujo de trabajo de aprobación
Solicitar aprobación antes de continuar con una acción.
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
Orquestación compleja
Flujo de trabajo de tickets de soporte
Un ejemplo completo que combina varios patrones: enrutamiento de agentes, lógica condicional y administración de conversaciones.
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.")
Procedimientos recomendados
Convenciones de nomenclatura
Use nombres claros y descriptivos para acciones y variables:
# Good
- kind: SetVariable
id: calculate_total_price
variable: Local.orderTotal
# Avoid
- kind: SetVariable
id: sv1
variable: Local.x
Organización de flujos de trabajo grandes
Dividir flujos de trabajo complejos en secciones lógicas con comentarios:
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
# ...
Tratamiento de errores
Use comprobaciones condicionales para controlar posibles problemas:
actions:
- kind: SetVariable
variable: Local.hasError
value: false
- kind: InvokeAzureAgent
id: call_agent
agent:
name: ProcessingAgent
output:
responseObject: Local.AgentResult
- kind: If
condition: =IsBlank(Local.AgentResult)
then:
- kind: SetVariable
variable: Local.hasError
value: true
- kind: SendActivity
activity:
text: "An error occurred during processing."
else:
- kind: SendActivity
activity:
text: =Local.AgentResult.message
Estrategias de prueba
- Iniciar sencillo: Probar los flujos básicos antes de agregar complejidad
- Usar valores predeterminados: proporcione valores predeterminados razonables para las entradas.
- Agregar registro: Usar SendActivity para la depuración durante el desarrollo
- Casos perimetrales de prueba: comprobación del comportamiento con entradas que faltan o no son válidas
# Debug logging example
- kind: SendActivity
id: debug_log
activity:
text: =Concat("[DEBUG] Current state: counter=", Local.counter, ", status=", Local.status)
Pasos siguientes
-
Ejemplos de flujo de trabajo declarativos de C# : explore ejemplos de trabajo completos, entre los que se incluyen:
- StudentTeacher : conversación multiagente con aprendizaje iterativo
- InvokeMcpTool : integración de herramientas de servidor MCP
- InvokeFunctionTool : invocación directa de funciones desde flujos de trabajo
- FunctionTools : agente con herramientas de función
- ToolApproval : aprobación humana para la ejecución de herramientas
- CustomerSupport : flujo de trabajo de incidencias de soporte técnico complejo
- DeepResearch : flujo de trabajo de investigación con varios agentes
- Ejemplos de flujo de trabajo declarativos de Python : exploración de ejemplos de trabajo completos