mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
e224f06e60
* Update models used in dotnet samples to gpt-5.4-mini * Fix additional missed sample
99 lines
4.4 KiB
C#
99 lines
4.4 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using Azure.AI.OpenAI;
|
|
using Azure.Identity;
|
|
using Microsoft.Agents.AI;
|
|
using Microsoft.Agents.AI.Workflows;
|
|
using Microsoft.Extensions.AI;
|
|
|
|
namespace WorkflowAsAnAgentSample;
|
|
|
|
/// <summary>
|
|
/// This sample introduces the concept of workflows as agents, where a workflow can be
|
|
/// treated as an <see cref="AIAgent"/>. This allows you to interact with a workflow
|
|
/// as if it were a single agent.
|
|
///
|
|
/// In this example, we create a workflow that uses two language agents to process
|
|
/// input concurrently, one that responds in French and another that responds in English.
|
|
///
|
|
/// You will interact with the workflow in an interactive loop, sending messages and receiving
|
|
/// streaming responses from the workflow as if it were an agent who responds in both languages.
|
|
///
|
|
/// This sample also demonstrates <see cref="IResettableExecutor"/>, which is required
|
|
/// for stateful executors that are shared across multiple workflow runs. Each iteration
|
|
/// of the interactive loop triggers a new workflow run against the same workflow instance.
|
|
/// Between runs, the framework automatically calls <see cref="IResettableExecutor.ResetAsync"/>
|
|
/// on shared executors so that accumulated state (e.g., collected messages) is cleared
|
|
/// before the next run begins. See <c>WorkflowFactory.ConcurrentAggregationExecutor</c>
|
|
/// for the implementation.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Pre-requisites:
|
|
/// - Foundational samples should be completed first.
|
|
/// - This sample uses concurrent processing.
|
|
/// - An Azure OpenAI endpoint and deployment name.
|
|
/// </remarks>
|
|
public static class Program
|
|
{
|
|
private static async Task Main()
|
|
{
|
|
// Set up the Azure OpenAI client
|
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
|
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-5.4-mini";
|
|
var chatClient = new AzureOpenAIClient(new Uri(endpoint), new AzureCliCredential()).GetChatClient(deploymentName).AsIChatClient();
|
|
|
|
// Create the workflow and turn it into an agent
|
|
var workflow = WorkflowFactory.BuildWorkflow(chatClient);
|
|
var agent = workflow.AsAIAgent("workflow-agent", "Workflow Agent");
|
|
var session = await agent.CreateSessionAsync();
|
|
|
|
// Start an interactive loop to interact with the workflow as if it were an agent.
|
|
// Each iteration runs the workflow again on the same workflow instance. Between runs,
|
|
// the framework calls IResettableExecutor.ResetAsync() on shared stateful executors
|
|
// (like ConcurrentAggregationExecutor) to clear accumulated state from the previous run.
|
|
while (true)
|
|
{
|
|
Console.WriteLine();
|
|
Console.Write("User (or 'exit' to quit): ");
|
|
string? input = Console.ReadLine();
|
|
if (string.IsNullOrWhiteSpace(input) || input.Equals("exit", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
break;
|
|
}
|
|
|
|
await ProcessInputAsync(agent, session, input);
|
|
}
|
|
|
|
// Helper method to process user input and display streaming responses. To display
|
|
// multiple interleaved responses correctly, we buffer updates by message ID and
|
|
// re-render all messages on each update.
|
|
static async Task ProcessInputAsync(AIAgent agent, AgentSession? session, string input)
|
|
{
|
|
Dictionary<string, List<AgentResponseUpdate>> buffer = [];
|
|
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(input, session))
|
|
{
|
|
if (update.MessageId is null || string.IsNullOrEmpty(update.Text))
|
|
{
|
|
// skip updates that don't have a message ID or text
|
|
continue;
|
|
}
|
|
Console.Clear();
|
|
|
|
if (!buffer.TryGetValue(update.MessageId, out List<AgentResponseUpdate>? value))
|
|
{
|
|
value = [];
|
|
buffer[update.MessageId] = value;
|
|
}
|
|
value.Add(update);
|
|
|
|
foreach (var (messageId, segments) in buffer)
|
|
{
|
|
string combinedText = string.Concat(segments);
|
|
Console.WriteLine($"{segments[0].AuthorName}: {combinedText}");
|
|
Console.WriteLine();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|