目录

  1. 框架概述
  2. 环境搭建与NuGet包
  3. 核心概念与关键接口
  4. Agent 的创建与配置
  5. 运行 Agent(基础用法)
  6. Tool Calling(工具调用)
  7. 结构化输出(Structured Output)
  8. Agent Session 与会话管理
  9. 聊天历史管理(Chat History)
  10. AIContextProvider(LLM调用拦截)
  11. Middleware(中间件)
  12. Workflow(工作流)
  13. 多 Agent 模式
  14. Agent-to-Agent (A2A) 协议
  15. AG-UI(Agent 用户界面)
  16. Hosting 与 .NET Aspire 集成
  17. Azure AI Foundry 集成
  18. 遥测与监控
  19. MCP (Model Context Protocol) 集成
  20. 依赖注入
  21. Agent 输入数据类型
  22. RAG 集成
  23. 框架工具包 (AgentFrameworkToolkit)
  24. 各模式适用场景总结

1. 框架概述

Microsoft Agent Framework (MAF) 是微软推出的新一代 AI Agent 框架,是 Semantic KernelAutoGen 的继任者。它提供了一套统一的抽象层,使开发者能够:

  • 用相同的 API 对接 OpenAIAzure OpenAIGoogle GeminiAnthropic ClaudeMistralOllamaGroqAWS Bedrock 等不同的 LLM 提供商
  • 构建 单 Agent多 Agent 应用
  • 通过 Workflow 编排复杂的 Agent 协作流程
  • 提供 Tool Calling结构化输出会话管理 等企业级特性

关键技术指标

特性支持情况
编程语言C# (主), Python
NuGet 版本v1.8.0 (稳定版), v1.8.0-preview
.NET 版本net10.0 (预览), net9.0, net8.0
开源协议MIT
底层标准Microsoft.Extensions.AI (MEAI)

2. 环境搭建与NuGet包

2.1 核心包

包名用途版本
Microsoft.Agents.AI核心抽象(IAIAgent, AIAgent 等)1.8.0
Microsoft.Agents.AI.OpenAIOpenAI / Azure OpenAI 集成1.8.0
Microsoft.Agents.AI.Workflows工作流引擎1.8.0
Microsoft.Agents.AI.HostingAspire Hosting 支持1.8.0-preview
Microsoft.Agents.AI.DevUI开发 UI1.8.0-preview
Microsoft.Agents.AI.AGUIAG-UI 客户端1.8.0-preview
Microsoft.Agents.AI.Hosting.AGUI.AspNetCoreAG-UI 服务端1.8.0-preview
Microsoft.Agents.AI.A2AAgent-to-Agent 协议1.8.0-preview
Microsoft.Agents.AI.AzureAIAzure AI Foundry 集成1.8.0-preview
Microsoft.Agents.AI.AnthropicAnthropic Claude 集成1.8.0-preview
Microsoft.Agents.AI.FoundryAI Foundry 集成1.8.0-preview
Microsoft.Agents.AI.Hyperlight安全沙箱集成1.8.0-preview
Microsoft.Agents.AI.Hosting.AzureFunctionsAzure Functions 集成1.8.0-preview
AgentFrameworkToolkit.AzureOpenAI第三方简化工具包1.8.0
AgentFrameworkToolkit.AnthropicClaude 简化工具包1.8.0
AgentFrameworkToolkit.GoogleGemini 简化工具包1.8.0

2.2 标准 .csproj 配置

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Azure.AI.OpenAI" />
    <PackageReference Include="Microsoft.Agents.AI.OpenAI" />
  </ItemGroup>
</Project>

2.3 集中包管理 (Directory.Packages.props)

推荐使用中央包管理,在 Directory.Packages.props 中统一版本:

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>
  <ItemGroup>
    <PackageVersion Include="Microsoft.Agents.AI" Version="1.8.0" />
    <PackageVersion Include="Microsoft.Agents.AI.OpenAI" Version="1.8.0" />
  </ItemGroup>
</Project>

3. 核心概念与关键接口

3.1 AIAgent(核心接口)

AIAgent 是整个框架的核心抽象接口,代表一个 AI Agent。所有 Agent 操作都围绕此接口展开。

// AIAgent 核心成员
public interface AIAgent
{
    string Name { get; }
    string Description { get; }
    // 创建会话
    AgentSession CreateSessionAsync();
    // 运行 Agent(非流式)
    AgentResponse RunAsync(...);
    // 运行 Agent(流式)
    IAsyncEnumerable<AgentResponseUpdate> RunStreamingAsync(...);
}

3.2 ChatClientAgent(最常用的 Agent 类型)

ChatClientAgent 是基于 Chat Completion API 的 Agent 实现,通过 AsAIAgent() 扩展方法创建:

// 从 ChatClient 创建 Agent
ChatClientAgent agent = chatClient.AsAIAgent(
    instructions: "你是助手",
    name: "MyAgent",
    tools: [...]
);

3.3 AgentResponse(响应)

所有 Agent 执行的返回类型:

// 普通响应
AgentResponse response = await agent.RunAsync("你好");
string text = response.Text;          // 响应文本
UsageDetails usage = response.Usage;   // Token 用量

// 结构化响应
AgentResponse<WeatherReport> response = await agent.RunAsync<WeatherReport>("巴黎天气");
WeatherReport result = response.Result; // 强类型结果

3.4 AgentResponseUpdate(流式更新)

流式执行时逐帧接收的更新单元:

await foreach (AgentResponseUpdate update in agent.RunStreamingAsync("问题"))
{
    Console.Write(update);
    // update.Text, update.Contents 等
}

3.5 AgentSession(会话)

用于在多轮对话中保持上下文:

AgentSession session = await agent.CreateSessionAsync();
AgentResponse r1 = await agent.RunAsync("我叫张三", session);
AgentResponse r2 = await agent.RunAsync("我叫什么名字?", session); // 记得我叫张三

3.6 AIFunctionFactory(工具工厂)

将 C# 方法转换为 AI 工具的核心工厂类:

// 从静态方法创建工具
AIFunction tool = AIFunctionFactory.Create(GetWeather, "get_weather");

// 从实例方法创建
AIFunction tool2 = AIFunctionFactory.Create(instance.MethodName);

// 带描述的工具
AIFunction tool3 = AIFunctionFactory.Create(
    Tools.GetCurrentTime, 
    "get_current_time",
    "获取当前时间"
);

3.7 关键枚举与常量

类型描述
ChatRole表示消息角色(User, Assistant, System, Tool)
ChatMessage单条聊天消息(来自 Microsoft.Extensions.AI)
AIContent消息内容的抽象基类
TextContent文本内容
DataContent二进制数据内容(图片、PDF等)
FunctionCallContent函数调用内容
FunctionResultContent函数执行结果内容

4. Agent 的创建与配置

4.1 基本创建方式

using Azure.AI.OpenAI;
using Microsoft.Agents.AI;
using OpenAI;
using OpenAI.Chat;
using System.ClientModel;

// 1. 创建 OpenAI Client
AzureOpenAIClient client = new(
    new Uri(endpoint), 
    new ApiKeyCredential(apiKey));

// 2. 获取 ChatClient
ChatClient chatClient = client.GetChatClient("gpt-4.1");

// 3. 创建 Agent
ChatClientAgent agent = chatClient.AsAIAgent();

4.2 完整配置参数

AIAgent agent = chatClient.AsAIAgent(
    // 系统指令 - 定义 Agent 的行为和个性
    instructions: "你是一名友好的 AI 助手",
    
    // Agent 名称 - 用于标识
    name: "MyAgent",
    
    // 描述 - 部分 Agent 平台使用
    description: "这是一个示例 Agent",
    
    // 可用工具集合
    tools: [AIFunctionFactory.Create(GetWeather)],
    
    // 自定义 ChatClient 工厂
    clientFactory: chatClient => new ConfigureOptionsChatClient(
        chatClient, options => {
            options.RawRepresentationFactory = _ => 
                new ChatCompletionOptions {
                    ReasoningEffortLevel = ChatReasoningEffortLevel.High
                };
        }),
    
    // 日志工厂
    loggerFactory: LoggerFactory.Create(builder => 
        builder.AddConsole()),
    
    // 服务提供者(用于工具中的 DI)
    services: serviceProvider
);

4.3 使用 ChatClientAgentOptions 配置

ChatClientAgent advancedAgent = chatClient.AsAIAgent(
    new ChatClientAgentOptions
    {
        ChatOptions = new ChatOptions
        {
            Instructions = "Speak like a Pirate",
            Temperature = 0.7f,
            MaxOutputTokens = 2000,
        },
        AIContextProviders = [],   // LLM 调用拦截器
        ChatHistoryProvider = null, // 会话历史存储
        Name = "My Agent",
        Description = "Agent 描述",
        Id = "agent-1234",
        UseProvidedChatClientAsIs = false
    },
    clientFactory: chatClient => { ... },
    loggerFactory: LoggerFactory.Create(builder => { ... }),
    services: serviceProvider
);

4.4 使用 Builder 模式(推荐用于高级场景)

AIAgent agent = chatClient
    .AsAIAgent(instructions: "你是一个专业助手", tools: [...])
    .AsBuilder()
    .Use(FunctionCallMiddleware)          // 添加中间件
    .UseOpenTelemetry(sourceName)          // 添加遥测
    .UseAIContextProviders([...])          // 添加上下文提供者
    .Build();

5. 运行 Agent(基础用法)

5.1 非流式执行

AgentResponse response = await agent.RunAsync("法国的首都是什么?");
Console.WriteLine(response);
// 输出: 法国的首都是巴黎。

5.2 流式执行

await foreach (AgentResponseUpdate update in agent.RunStreamingAsync("怎么做汤?"))
{
    Console.Write(update);
}

5.3 带会话的执行

AgentSession session = await agent.CreateSessionAsync();

AgentResponse r1 = await agent.RunAsync("Hello, 我叫张三", session);
AgentResponse r2 = await agent.RunAsync("我叫什么名字?", session); // 知道是张三

// 或使用 ChatMessage 列表手动管理
List<ChatMessage> messages = [
    new ChatMessage(ChatRole.System, "你是一个助手"),
    new ChatMessage(ChatRole.User, "你好")
];
AgentResponse response = await agent.RunAsync(messages);

5.4 背景响应(长任务)

对需要长时间处理的请求,支持异步轮询:

ChatClientAgentRunOptions options = new()
{
    AllowBackgroundResponses = true
};

AgentResponse response = await agent.RunAsync("写一篇2000字的文章", session, options: options);

int counter = 0;
while (response.ContinuationToken is not null)
{
    await Task.Delay(TimeSpan.FromSeconds(2));
    counter++;
    options.ContinuationToken = response.ContinuationToken;
    response = await agent.RunAsync(session, options);
}

Console.WriteLine(response.Text);

6. Tool Calling(工具调用)

6.1 基本工具定义

// 定义工具方法
public static class Tools
{
    public static DateTime CurrentDataAndTime(TimeType type)
    {
        return type switch
        {
            TimeType.Local => DateTime.Now,
            TimeType.Utc => DateTime.UtcNow,
        };
    }

    public static string CurrentTimezone()
    {
        return TimeZoneInfo.Local.DisplayName;
    }

    public enum TimeType { Local, Utc }
}

// 绑定到 Agent
ChatClientAgent agent = chatClient
    .AsAIAgent(
        instructions: "你是时间专家",
        tools: [
            AIFunctionFactory.Create(Tools.CurrentDataAndTime, "current_date_and_time"),
            AIFunctionFactory.Create(Tools.CurrentTimezone, "current_timezone")
        ]
    );

6.2 使用 AIFunctionFactoryOptions

AIFunctionFactory.Create(
    Tools.MyMethod,
    new AIFunctionFactoryOptions
    {
        Name = "my_tool",
        Description = "工具描述"
    }
);

6.3 服务注入工具

工具方法支持 IServiceProvider 注入:

// 静态工具方法 + DI
public static string MyTool(IServiceProvider serviceProvider)
{
    HttpClient httpClient = serviceProvider.GetRequiredService<HttpClient>();
    return httpClient.GetStringAsync("https://api.example.com").Result;
}

// 实例工具方法(推荐)
class ToolService(HttpClient httpClient)
{
    public string DoSomething()
    {
        return httpClient.GetStringAsync("https://api.example.com").Result;
    }
}

// 注册到 Agent
agent = chatClient.AsAIAgent(
    tools: [
        AIFunctionFactory.Create(toolInstance.DoSomething, "do_something"),
    ],
    services: serviceProvider
);

6.4 工具调用中间件

拦截和记录工具调用:

AIAgent agent = chatClient
    .AsAIAgent(name: "MyAgent", instructions: "你是助手", tools: [...])
    .AsBuilder()
    .Use(FunctionCallMiddleware)
    .Build();

async ValueTask<object?> FunctionCallMiddleware(
    AIAgent callingAgent,
    FunctionInvocationContext context,
    Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next,
    CancellationToken cancellationToken)
{
    Console.WriteLine($"工具调用: '{context.Function.Name}'");
    
    if (context.Arguments.Count > 0)
    {
        Console.WriteLine($"参数: {string.Join(",", context.Arguments.Select(x => $"[{x.Key} = {x.Value}]"))}");
    }

    return await next(context, cancellationToken);
}

6.5 流式调用中的工具追踪

await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(message))
{
    if (update.Contents.OfType<FunctionCallContent>().FirstOrDefault() 
        is FunctionCallContent call)
    {
        Console.WriteLine($"调用 '{call.Name}' 参数: {JsonSerializer.Serialize(call.Arguments)}");
    }
}

7. 结构化输出(Structured Output)

7.1 基本用法

使用泛型 RunAsync<T> 获取强类型结果:

public class Movie
{
    public required string Title { get; set; }
    public int YearOfRelease { get; set; }
    public required string Director { get; set; }
    public MovieGenre Genre { get; set; }
    public decimal ImdbScore { get; set; }
}

public enum MovieGenre
{
    ScienceFiction, Drama, Comedy, Horror, LoveStory, Other
}

// Agent 定义
AIAgent agent = chatClient.GetChatClient("gpt-4.1").AsAIAgent(
    "你是 IMDB 榜单专家");

// 结构化执行
AgentResponse<List<Movie>> response = await agent.RunAsync<List<Movie>>(
    "IMDB 评分最高的10部电影有哪些?");

List<Movie> movies = response.Result;
foreach (var movie in movies)
{
    Console.WriteLine($"{movie.Title} ({movie.YearOfRelease}) - {movie.ImdbScore}");
}

7.2 使用 Description 属性控制字段

public class WeatherResponse
{
    [Description("城市(含国家)")]
    public required string City { get; set; }
    
    public required string Condition { get; set; }
    public required int DegreesFahrenheit { get; set; }
    public required int DegreesCelsius { get; set; }
}

AgentResponse<WeatherResponse> response = await agent.RunAsync<WeatherResponse>(
    "巴黎天气怎么样?");

7.3 使用 JSON Schema 控制输出格式

AgentResponse response = await agent.RunAsync("巴黎天气",
    options: new ChatClientAgentRunOptions()
    {
        ChatOptions = new ChatOptions
        {
            ResponseFormat = ChatResponseFormat.ForJsonSchema<WeatherReport>(jsonOptions)
        }
    }
);

WeatherReport weather = JsonSerializer.Deserialize<WeatherReport>(
    response.Text, jsonOptions)!;

8. Agent Session 与会话管理

8.1 内置 Session

// 创建新会话
AgentSession session = await agent.CreateSessionAsync();

// 使用会话
AgentResponse r1 = await agent.RunAsync("你好,我叫张三", session);
AgentResponse r2 = await agent.RunAsync("我叫什么名字?", session); // 张三

// 重新开始新会话
session = await agent.CreateSessionAsync();
AgentResponse r3 = await agent.RunAsync("我叫什么名字?", session); // 不知道

8.2 手动管理对话历史

List<ChatMessage> messages = [
    new ChatMessage(ChatRole.System, "你是一名友好助手"),
    new ChatMessage(ChatRole.User, "法国的首都是什么?")
];

AgentResponse response = await agent.RunAsync(messages);
messages.AddRange(response.Messages); // 追加 AI 回复到历史
messages.Add(new ChatMessage(ChatRole.User, "德国的首都呢?"));

8.3 会话历史提供者

ChatClientAgent agent = chatClient.AsAIAgent(
    new ChatClientAgentOptions
    {
        ChatOptions = new() { Instructions = "你是一个友好的 AI" },
        ChatHistoryProvider = new InMemoryChatHistoryProvider(
            new InMemoryChatHistoryProviderOptions
            {
                ChatReducer = new SummarizingChatReducer(
                    chatClient.AsIChatClient(), 
                    targetCount: 1, 
                    threshold: 4
                )
            }
        )
    }
);

9. 聊天历史管理(Chat History)

9.1 IChatReducer(历史缩减器)

控制聊天历史长度以避免 Token 超限:

// 1. 按消息计数缩减
IChatReducer countReducer = new MessageCountingChatReducer(targetCount: 4);

// 2. 按摘要缩减(超过阈值后自动摘要)
IChatReducer summaryReducer = new SummarizingChatReducer(
    chatClient.AsIChatClient(), // 用于生成摘要的 ChatClient
    targetCount: 1,             // 缩减后的目标消息数
    threshold: 4                // 触发缩减的阈值
);

9.2 自定义 ChatHistoryProvider

public class CustomChatHistoryStore : IChatHistoryProvider
{
    public IChatReducer? Reducer { get; set; }

    public List<ChatMessage> GetMessages(AgentSession session)
    {
        // 从自定义存储加载消息
    }

    public void AddMessage(AgentSession session, ChatMessage message)
    {
        // 保存消息到自定义存储
    }

    public void DeleteMessages(AgentSession session)
    {
        // 清空会话消息
    }
}

9.3 检查历史状态

InMemoryChatHistoryProvider? provider = agent.GetService<InMemoryChatHistoryProvider>();
List<ChatMessage> messagesInSession = provider?.GetMessages(session) ?? [];
Console.WriteLine($"会话中的消息数: {messagesInSession.Count}");
foreach (var msg in messagesInSession)
{
    Console.WriteLine($"-- {msg.Role}: {msg.Text}");
}

10. AIContextProvider(LLM调用拦截)

10.1 AIContextProvider 概述

AIContextProvider 允许在每个 LLM 调用前后执行自定义逻辑,生命周期如下:

RunAsync 执行流程:
  ┌─ InvokingCoreAsync (核心 - 合并各 Provider 的上下文)
  ├─ ProvideAIContextAsync (丰富 - 注入指令/工具/消息)
  ├─ LLM 调用
  ├─ InvokedCoreAsync (核心 - 处理异常)
  └─ StoreAIContextAsync (后处理 - 提取响应信息/存储记忆)

10.2 实现自定义 Provider

class MyAIContextProvider : AIContextProvider
{
    // LLM 调用前:注入指令和工具(供本次调用使用,不入历史)
    protected override ValueTask<AIContext> ProvideAIContextAsync(
        InvokingContext context, 
        CancellationToken cancellationToken = default)
    {
        // 查看当前消息
        foreach (var message in context.AIContext.Messages ?? [])
        {
            Console.WriteLine($"-- {message.Role}: {message.Text}");
        }

        return ValueTask.FromResult(new AIContext
        {
            Instructions = "用海盗语气说话",   // 本次调用的额外指令
            Tools = [...],                      // 本次调用的额外工具
        });
    }

    // LLM 调用后:提取信息、存储记忆
    protected override async ValueTask StoreAIContextAsync(
        InvokedContext context, 
        CancellationToken cancellationToken = default)
    {
        if (context.InvokeException != null)
        {
            Console.WriteLine($"LLM 调用异常: {context.InvokeException}");
        }

        foreach (var msg in context.ResponseMessages ?? [])
        {
            Console.WriteLine($"-- {msg.Role}: {msg.Text}");
        }

        // 提取并存储记忆...
        await Task.CompletedTask;
    }
}

10.3 MessageAIContextProvider(消息级 Provider)

专注于在调用前注入额外消息:

class MyMessageProvider : MessageAIContextProvider
{
    protected override ValueTask<IEnumerable<ChatMessage>> ProvideMessagesAsync(
        InvokingContext context, 
        CancellationToken cancellationToken = default)
    {
        // 注入额外的消息
        IList<ChatMessage> injected = [
            new ChatMessage(ChatRole.User, "请全部用大写字母回复")
        ];
        return ValueTask.FromResult<IEnumerable<ChatMessage>>(injected);
    }
}

10.4 注册 AIContextProvider

两种注册方式:

// 方式1:通过 Options(作为 Provider)
AIAgent agent = chatClient.AsAIAgent(new ChatClientAgentOptions
{
    AIContextProviders = [
        new MyAIContextProvider(),
        new MyMessageAIContextProvider()
    ]
});

// 方式2:通过 Builder(作为 Middleware)
AIAgent agent = chatClient.AsAIAgent()
    .AsBuilder()
    .UseAIContextProviders([new MyMessageAIContextProvider()])
    .Build();

注意AIContextProvider 在 Provider 模式下会参与 AIContext 合并,而 MessageAIContextProvider 在 Middleware 模式下只注入消息,不参与上下文合并。


11. Middleware(中间件)

中间件是构建 Agent 处理管道的核心机制,使用 Builder 模式链式注册:

AIAgent agent = chatClient
    .AsAIAgent(instructions: "你是助手", tools: [...])
    .AsBuilder()
    .Use(FunctionCallMiddleware)       // 自定义中间件
    .UseOpenTelemetry(sourceName)      // OpenTelemetry 遥测
    .UseAIContextProviders([...])      // 上下文提供者
    .Build();

中间件签名

// 函数调用中间件
async ValueTask<object?> MyMiddleware(
    AIAgent callingAgent,
    FunctionInvocationContext context,
    Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next,
    CancellationToken cancellationToken)
{
    // 前置处理
    Console.WriteLine($"调用工具: {context.Function.Name}");
    
    // 执行下一个中间件
    object? result = await next(context, cancellationToken);
    
    // 后置处理
    Console.WriteLine($"结果: {result}");
    
    return result;
}

12. Workflow(工作流)

工作流引擎允许编排多个 Agent,实现复杂的任务处理流水线。

12.1 顺序工作流(Sequential)

多个 Agent 按顺序依次处理,前一个输出作为后一个输入:

ChatClientAgent summaryAgent = chatClient.AsAIAgent(
    name: "SummaryAgent",
    instructions: "将文本总结到最多20个词");

ChatClientAgent translationAgent = chatClient.AsAIAgent(
    name: "TranslationAgent",
    instructions: "将文本翻译成法语");

Workflow workflow = AgentWorkflowBuilder.BuildSequential(
    summaryAgent, translationAgent);

// 执行
List<ChatMessage> messages = [new ChatMessage(ChatRole.User, legalText)];
StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, messages);
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));

List<ChatMessage> result = [];
await foreach (WorkflowEvent evt in run.WatchStreamAsync())
{
    if (evt is WorkflowOutputEvent output)
    {
        result = output.As<List<ChatMessage>>()!;
    }
}

12.2 并发工作流(Concurrent)

多个 Agent 同时处理同一个输入:

ChatClientAgent legalAgent = chatClient.AsAIAgent(
    name: "LegalAgent",
    instructions: "评估文本是否合法");

ChatClientAgent spellAgent = chatClient.AsAIAgent(
    name: "SpellingAgent",
    instructions: "检查拼写错误");

Workflow workflow = AgentWorkflowBuilder.BuildConcurrent([
    legalAgent, spellAgent
]);

12.3 移交工作流(Handoff)

Agent 之间根据意图进行任务移交:

ChatClientAgent intentAgent = chatClient.AsAIAgent(
    name: "IntentAgent",
    instructions: "确定问题类型,不要自己回答");

ChatClientAgent movieNerd = chatClient.AsAIAgent(
    name: "MovieNerd", 
    instructions: "你是电影专家");

ChatClientAgent musicNerd = chatClient.AsAIAgent(
    name: "MusicNerd",
    instructions: "你是音乐专家");

Workflow workflow = AgentWorkflowBuilder.CreateHandoffBuilderWith(intentAgent)
    .WithHandoffs(intentAgent, [movieNerd, musicNerd])
    .WithHandoffs([movieNerd, musicNerd], intentAgent)
    .Build();

// 执行 - 先由 intentAgent 判断意图,然后移交给对应专家

12.4 AI 辅助工作流(AI-Assisted)

结合自定义 Executor 和条件分支:

// 定义自定义 Executor
[YieldsOutput(typeof(PizzaOrder))]
class PizzaOrderParserExecutor(ChatClientAgent agent) 
    : Executor<PizzaOrder>("OrderParser")
{
    public override async ValueTask HandleAsync(
        PizzaOrder message,
        IWorkflowContext context,
        CancellationToken ct = default)
    {
        // 使用 Agent 解析订单
        AgentResponse<PizzaOrder> response = await agent
            .RunAsync<PizzaOrder>(message.OrderText, cancellationToken: ct);
        
        await context.YieldOutputAsync(response.Result, ct);
    }
}

// 构建工作流(带条件分支)
WorkflowBuilder builder = new(orderParser);
builder.AddEdge(orderParser, stockChecker);
builder.AddSwitch(stockChecker, switchBuilder =>
{
    switchBuilder.AddCase<PizzaOrder>(
        x => x!.Warnings.Count == 0, endSuccess);
    switchBuilder.AddCase<PizzaOrder>(
        x => x!.Warnings.Count != 0, endWarning);
});

Workflow workflow = builder.Build();

12.5 人工介入工作流(Human-in-the-Loop)

通过 RequestPort 实现与用户的交互:

RequestPort requestPort = RequestPort.Create<FeedbackToUser, string>("GuessAnimal");
EvaluateAndHintExecutor evaluator = new(agent, animalToGuess);

Workflow workflow = new WorkflowBuilder(requestPort)
    .AddEdge(requestPort, evaluator)
    .AddEdge(evaluator, requestPort)
    .WithOutputFrom(evaluator)
    .Build();

// 执行并处理人工交互
await foreach (WorkflowEvent evt in handle.WatchStreamAsync())
{
    if (evt is RequestInfoEvent requestEvt)
    {
        ExternalRequest externalRequest = requestEvt.Request;
        if (externalRequest.IsDataOfType<FeedbackToUser>())
        {
            // 向用户展示信息并等待输入
            string? input = Console.ReadLine();
            ExternalResponse externalResponse = externalRequest.CreateResponse(input);
            await handle.SendResponseAsync(externalResponse);
        }
    }
    else if (evt is WorkflowOutputEvent outputEvt)
    {
        Console.WriteLine(outputEvt.Data);
        return;
    }
}

12.6 Workflow 事件处理

await foreach (WorkflowEvent evt in run.WatchStreamAsync())
{
    switch (evt)
    {
        case AgentResponseUpdateEvent e:
            // Agent 流式响应更新
            Console.Write(e.Update.Text);
            // 追踪切换的 Agent
            if (e.ExecutorId != lastExecutorId)
            {
                Console.WriteLine($"\n[Agent: {e.ExecutorId}]");
                lastExecutorId = e.ExecutorId;
            }
            break;

        case WorkflowOutputEvent output:
            // 工作流最终输出
            List<ChatMessage> result = output.As<List<ChatMessage>>()!;
            break;

        case ExecutorCompletedEvent completed:
            // Executor 执行完成
            Console.WriteLine($"{completed.ExecutorId} 完成");
            break;

        case ExecutorFailedEvent failed:
            // Executor 执行失败
            Console.WriteLine($"Agent {failedEvent.ExecutorId} 出错: {failedEvent.Data}");
            break;
    }
}

12.7 Workflow 执行入口

// 标准执行
StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, messages);
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));

// 带初始数据的执行
await using StreamingRun handle = await InProcessExecution.RunStreamingAsync(
    workflow, initialFeedback);

13. 多 Agent 模式

13.1 Agent As Tool(Agent 作为工具)

将一个 Agent 封装为另一个 Agent 的工具:

// 创建子 Agent
AIAgent stringAgent = chatClient
    .AsAIAgent(name: "StringAgent", 
        instructions: "你是一个字符串操作专家",
        tools: [AIFunctionFactory.Create(StringTools.Reverse), ...])
    .AsBuilder()
    .Use(FunctionCallMiddleware)
    .Build();

AIAgent numberAgent = chatClient
    .AsAIAgent(name: "NumberAgent",
        instructions: "你是一个数字专家",
        tools: [AIFunctionFactory.Create(NumberTools.RandomNumber), ...])
    .AsBuilder()
    .Use(FunctionCallMiddleware)
    .Build();

// 创建委托 Agent(将子 Agent 作为工具)
AIAgent delegationAgent = chatClient
    .AsAIAgent(name: "DelegateAgent",
        instructions: "你是字符串和数字任务的调度者,不要自己做",
        tools: [
            stringAgent.AsAIFunction(new AIFunctionFactoryOptions 
            { 
                Name = "StringAgentAsTool" 
            }),
            numberAgent.AsAIFunction(new AIFunctionFactoryOptions 
            { 
                Name = "NumberAgentAsTool" 
            })
        ])
    .AsBuilder()
    .Use(FunctionCallMiddleware)
    .Build();

AgentResponse response = await delegationAgent.RunAsync("把 'Hello World' 变成大写");

13.2 手动多 Agent(结构化输出路由)

通过结构化输出来判断由哪个 Agent 处理:

public enum Intent { MusicQuestion, MovieQuestion, Other }

public class IntentResult
{
    [Description("问题类型")]
    public required Intent Intent { get; set; }
}

// 意图判断 Agent
ChatClientAgent intentAgent = chatClientMini.AsAIAgent(
    name: "IntentAgent", 
    instructions: "确定问题类型,不要自己回答");

AgentResponse<IntentResult> result = await intentAgent.RunAsync<IntentResult>(question);

switch (result.Result.Intent)
{
    case Intent.MusicQuestion:
        var musicAgent = chatClient.AsAIAgent(name: "MusicNerd", 
            instructions: "你是音乐专家");
        var musicResponse = await musicAgent.RunAsync(question);
        break;
    case Intent.MovieQuestion:
        var movieAgent = chatClient.AsAIAgent(name: "MovieNerd", 
            instructions: "你是电影专家");
        var movieResponse = await movieAgent.RunAsync(question);
        break;
}

13.3 多模型混合

使用不同模型处理不同任务:

// 小模型做路由/意图识别
ChatClient intentClient = client.GetChatClient("gpt-4.1-mini");
// 大模型做复杂处理
ChatClient chatClient = client.GetChatClient("gpt-4.1");

ChatClientAgent intentAgent = intentClient.AsAIAgent(instructions: "判断意图");
ChatClientAgent mainAgent = chatClient.AsAIAgent(instructions: "你是专家");

14. Agent-to-Agent (A2A) 协议

A2A 协议允许不同进程/机器上的 Agent 互相通信。

14.1 A2A 服务端

// 创建 Agent
AIAgent agent = client
    .GetChatClient("gpt-4.1-mini")
    .AsAIAgent(name: "FileAgent", 
        instructions: "你是文件专家", 
        tools: listOfTools)
    .AsBuilder()
    .Use(FunctionCallMiddleware)
    .Build();

// 构建 A2A Server
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.AddA2AServer(agent);

WebApplication app = builder.Build();

// 配置 Agent Card(名片)
AgentCard agentCard = new()
{
    Name = "FilesAgent",
    Description = "处理文件相关请求",
    Version = "1.0.0",
    DefaultInputModes = ["text"],
    DefaultOutputModes = ["text"],
    Capabilities = new AgentCapabilities()
    {
        Streaming = false,
        PushNotifications = false,
    },
    Skills = [
        new AgentSkill()
        {
            Id = "my_files_agent",
            Name = "File Expert",
            Description = "处理硬盘上的文件操作",
            Tags = ["files", "folders"],
            Examples = ["显示 Demo1 文件夹中的文件"],
        }
    ],
    SupportedInterfaces = [
        new AgentInterface
        {
            Url = "http://localhost:5000",
            ProtocolBinding = ProtocolBindingNames.JsonRpc,
            ProtocolVersion = "1.0"
        }
    ]
};

// 注册端点
app.MapA2AJsonRpc(agent, path: "/");
app.MapWellKnownAgentCard(agentCard);

await app.RunAsync();

14.2 A2A 客户端

// 解析远程 Agent
A2ACardResolver resolver = new A2ACardResolver(new Uri("http://localhost:5000"));
AIAgent remoteAgent = await resolver.GetAIAgentAsync();

// 将远程 Agent 作为本地 Agent 的工具
ChatClientAgent agent = client
    .GetChatClient("gpt-4.1")
    .AsAIAgent(
        name: "ClientAgent",
        instructions: "你擅长处理用户查询并使用工具提供答案",
        tools: [remoteAgent.AsAIFunction()]);

// 正常使用
AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync("帮我列出 C 盘的文件", session);

15. AG-UI(Agent 用户界面)

AG-UI 提供可嵌入的 Web 聊天界面,支持与 Agent 交互。

15.1 服务端配置

// 创建 Agent
ChatClientAgent agent = chatClient
    .AsAIAgent(tools: [AIFunctionFactory.Create(GetWeather, "get_weather")]);

// 配置 AG-UI
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddAGUI();

WebApplication app = builder.Build();
app.MapAGUI("/", agent);

app.Run();

// 服务端工具
static string GetWeather(string city)
{
    return "晴 19度";
}

15.2 客户端调用 AG-UI

// 连接 AG-UI 服务端
AGUIChatClient chatClient = new AGUIChatClient(httpClient, "http://localhost:5000");
AIAgent agent = chatClient.AsAIAgent(tools: [AIFunctionFactory.Create(MyTool)]);

// 调用(注意:AG-UI 不支持 Instructions 和 Sessions,需手动管理)
List<ChatMessage> messages = [new ChatMessage(ChatRole.System, "你是一个助手")];

messages.Add(new ChatMessage(ChatRole.User, "你好"));
List<AgentResponseUpdate> updates = [];
await foreach (AgentResponseUpdate update in agent.RunStreamingAsync(messages))
{
    updates.Add(update);
    foreach (AIContent content in update.Contents)
    {
        if (content is TextContent text)
            Console.Write(text.Text);
        else if (content is FunctionCallContent call)
            Console.WriteLine($"[工具调用: {call.Name}]");
    }
}

AgentResponse fullResponse = updates.ToAgentResponse();
messages.AddRange(fullResponse.Messages);

15.3 高级 AG-UI(多 Agent、结构化输出)

// 多个 Agent 注册到不同端点
app.MapAGUI("/clientToolAgent", clientToolAgent);
app.MapAGUI("/weatherAgent", weatherAgent);
app.MapAGUI("/weatherAgentWithStructuredContent", 
    new AgUiStructuredToolsOutputAgent(weatherAgentStructured, "get_weather"));
app.MapAGUI("/movieAgent", 
    new AgUiStructuredOutputAgent<MovieResult>(movieStructuredOutputAgent));

15.4 DevUI(开发调试 UI)

// 注册服务
builder.Services.AddChatClient(azureOpenAIClient.GetChatClient("gpt-4.1").AsIChatClient());
builder.Services.AddOpenAIResponses();
builder.Services.AddOpenAIConversations();

// 注册 Agent
builder.AddAIAgent("Comic Book Guy", "你是辛普森一家中的漫画店老板")
    .WithAITool(AIFunctionFactory.Create(GetWeather));

// 注册工作流
builder.AddWorkflow("translation-workflow-sequential", (sp, key) => { ... })
    .AddAsAIAgent();

// 映射端点(仅开发环境)
app.MapOpenAIResponses();
app.MapOpenAIConversations();
app.MapDevUI();

16. Hosting 与 .NET Aspire 集成

16.1 Agent Hosting

// 注册 Agent 到 Hosting 系统
IHostedAgentBuilder agentBuilder = builder.AddAIAgent(
    "MyAgent", 
    "你是一个友好的 AI 机器人")
    .WithAITool(AIFunctionFactory.Create(GetWeather));

16.2 Workflow Hosting

IHostedAgentBuilder frenchTranslator = builder.AddAIAgent(
    "french-translator", "将文本翻译成法语");
IHostedAgentBuilder germanTranslator = builder.AddAIAgent(
    "german-translator", "将文本翻译成德语");

// 注册为 Workflow
builder.AddWorkflow("translation-workflow-sequential", (sp, key) =>
{
    var agents = new[] { frenchTranslator, germanTranslator }
        .Select(ab => sp.GetRequiredKeyedService<AIAgent>(ab.Name));
    return AgentWorkflowBuilder.BuildSequential(workflowName: key, agents: agents);
}).AddAsAIAgent();

16.3 Aspire 编排

IDistributedApplicationBuilder builder = DistributedApplication.CreateBuilder(args);
builder.AddProject<Projects.MyBlazorApp>("blazor-app");
builder.Build().Run();

17. Azure AI Foundry 集成

17.1 使用 Foundry Agent(云端托管 Agent)

using Azure.AI.Agents.Persistent;
using Azure.Identity;

PersistentAgentsClient client = new(
    endpoint, 
    new AzureCliCredential());

// 创建托管 Agent
Response<PersistentAgent> foundryAgent = await client.Administration
    .CreateAgentAsync(model, "MyAgent", "描述", "指令");

// 转换为本地 Agent
ChatClientAgent agent = await client.GetAIAgentAsync(foundryAgent.Value.Id);

AgentResponse response = await agent.RunAsync("你好");

17.2 Foundry Agent + 工具(Code Interpreter, Web Search, MCP)

// 创建 Agent 版本(包含平台工具)
await client.Agents.CreateAgentVersionAsync(
    agentName: myAgentName,
    options: new AgentVersionCreationOptions(
        new PromptAgentDefinition(model)
        {
            Tools = {
                new CodeInterpreterTool(new CodeInterpreterToolContainer(
                    new AutomaticCodeInterpreterToolContainerConfiguration())),
                new WebSearchTool(),
                localTool.AsOpenAIResponseTool(),
                new McpTool("TrelloDotNet", new Uri("mcp-url"))
                {
                    ToolCallApprovalPolicy = new McpToolCallApprovalPolicy(
                        new GlobalMcpToolCallApprovalPolicy("never"))
                },
            },
            Instructions = "Speak like a pirate",
            ReasoningOptions = new ResponseReasoningOptions {
                ReasoningEffortLevel = ResponseReasoningEffortLevel.Low
            }
        }
    )
);

// 使用 Agent
FoundryAgent agentByName = client.AsAIAgent(myAgentName, tools: [localTool]);
AgentResponse response = await agentByName.RunAsync("查询最新新闻");

17.3 获取 Code Interpreter 生成的文件

foreach (ChatMessage message in agentResponse.Messages)
{
    foreach (AIContent content in message.Contents)
    {
        foreach (AIAnnotation annotation in content.Annotations ?? [])
        {
            if (annotation.RawRepresentation is ContainerFileCitationMessageAnnotation fileCitation)
            {
                ContainerClient containerClient = aiProjectClient.OpenAI.GetContainerClient();
                ClientResult<BinaryData> fileContent = await containerClient
                    .DownloadContainerFileAsync(fileCitation.ContainerId, fileCitation.FileId);
                string path = Path.Combine(Path.GetTempPath(), fileCitation.Filename);
                await File.WriteAllBytesAsync(path, fileContent.Value.ToArray());
            }
        }
    }
}

18. 遥测与监控

18.1 OpenTelemetry 集成

// 配置 OpenTelemetry
string sourceName = "AiSource";
using TracerProvider tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddSource(sourceName)
    .AddConsoleExporter()
    .AddAzureMonitorTraceExporter(options => 
        options.ConnectionString = connectionString)
    .Build();

// 将遥测附加到 Agent
AIAgent agent = chatClient
    .AsAIAgent(name: "MyObservedAgent", instructions: "你是一个友好的 AI")
    .AsBuilder()
    .UseOpenTelemetry(sourceName, options =>
    {
        options.EnableSensitiveData = true; // 是否记录实际消息内容
    })
    .Build();

18.2 Token 用量追踪

AgentResponse response = await agent.RunAsync("问题");
Console.WriteLine($"输入 Token: {response.Usage.InputTokens}");
Console.WriteLine($"输出 Token: {response.Usage.OutputTokens}");
Console.WriteLine($"总 Token: {response.Usage.TotalTokens}");
response.Usage.OutputAsInformation(); // 格式化输出

18.3 原始 HTTP 请求/响应监控

class RawCallHttpHandler : HttpClientHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        string requestBody = await request.Content?.ReadAsStringAsync(cancellationToken)!;
        Console.WriteLine($"[请求] {request.RequestUri}");
        Console.WriteLine(MakePretty(requestBody));

        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
        
        string responseBody = await response.Content.ReadAsStringAsync(cancellationToken);
        Console.WriteLine("[响应]");
        Console.WriteLine(MakePretty(responseBody));
        
        return response;
    }
}

// 使用自定义 Handler
HttpClient httpClient = new(new RawCallHttpHandler());
AzureOpenAIClient client = new(endpoint, credential, new AzureOpenAIClientOptions
{
    Transport = new HttpClientPipelineTransport(httpClient)
});

19. MCP (Model Context Protocol) 集成

19.1 将 Agent 暴露为 MCP 服务

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

builder.Services.AddMcpServer()
    .WithHttpTransport()
    .WithToolsFromAssembly(); // 自动注册所有公共方法为工具

WebApplication app = builder.Build();
app.MapMcp("/mcp");
app.Run();

19.2 在 Agent 中使用 MCP 工具

(通过 Foundry Agent 集成,见第 17.2 节)


20. 依赖注入

20.1 注册 Agent 到 DI 容器

// 注册 OpenAI Client
builder.Services.AddSingleton(azureOpenAiClient);

// 注册 ChatClient
ChatClient chatClient = client.GetChatClient("gpt-4.1");
builder.Services.AddKeyedSingleton("gpt-4.1", chatClient);

// 注册 Agent
ChatClientAgent agent = chatClient.AsAIAgent();
builder.Services.AddKeyedSingleton("gpt-4.1", agent);

20.2 在 ASP.NET Core 中使用

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

// 注册 Agent 需要的服务
builder.Services.AddSingleton(azureOpenAiClient);
builder.Services.AddSingleton(chatClient);
builder.Services.AddSingleton(agent);

// 在 Blazor Component 中注入
// @inject ChatClientAgent MyAgent

21. Agent 输入数据类型

Agent 支持多种输入类型:

21.1 文本

AgentResponse response = await agent.RunAsync("法国的首都是什么?");

21.2 图片(URL / Base64 / Memory)

// URL 模式
ChatMessage msg = new ChatMessage(ChatRole.User, [
    new TextContent("这张图片里有什么?"),
    new UriContent("https://example.com/image.jpg", "image/jpeg")
]);

// Base64 模式
string base64Image = Convert.ToBase64String(File.ReadAllBytes(path));
string dataUri = $"data:image/jpeg;base64,{base64Image}";
msg = new ChatMessage(ChatRole.User, [
    new TextContent("这张图片里有什么?"),
    new DataContent(dataUri, "image/jpeg")
]);

// Memory 模式
ReadOnlyMemory<byte> data = File.ReadAllBytes(path).AsMemory();
msg = new ChatMessage(ChatRole.User, [
    new TextContent("这张图片里有什么?"),
    new DataContent(data, "image/jpeg")
]);

21.3 PDF(仅 OpenAI,不支持 Azure OpenAI)

// Base64 模式(PDF)
string base64Pdf = Convert.ToBase64String(File.ReadAllBytes(pdfPath));
string dataUri = $"data:application/pdf;base64,{base64Pdf}";
ChatMessage msg = new ChatMessage(ChatRole.User, [
    new TextContent("PDF 中的获胜条件是什么?"),
    new DataContent(dataUri, "application/pdf")
]);

// Memory 模式(PDF)
ReadOnlyMemory<byte> data = File.ReadAllBytes(pdfPath).AsMemory();
msg = new ChatMessage(ChatRole.User, [
    new TextContent("PDF 中的获胜条件是什么?"),
    new DataContent(data, "application/pdf")
]);

21.4 多模态混合

ChatMessage msg = new ChatMessage(ChatRole.User, [
    new TextContent("图片显示什么?PDF 中的获胜条件是什么?"),
    new DataContent(pdfDataUri, "application/pdf"),
    new DataContent(imageDataUri, "image/jpeg")
]);

22. RAG 集成

22.1 向量搜索集成

// 创建嵌入生成器
IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator = client
    .GetEmbeddingClient("text-embedding-3-small")
    .AsIEmbeddingGenerator();

// 创建向量存储(支持 InMemory/Azure AI Search/SQL Server/CosmosDB)
InMemoryVectorStore vectorStore = new(new InMemoryVectorStoreOptions
{
    EmbeddingGenerator = embeddingGenerator
});

InMemoryCollection<Guid, MovieVectorStoreRecord> collection = 
    vectorStore.GetCollection<Guid, MovieVectorStoreRecord>("movies");
await collection.EnsureCollectionExistsAsync();

// 写入向量数据
await collection.UpsertAsync(new MovieVectorStoreRecord
{
    Id = Guid.NewGuid(),
    Title = movie.Title,
    Plot = movie.Plot,
    Rating = movie.Rating
});

// 查询相似内容
await foreach (VectorSearchResult<MovieVectorStoreRecord> result in 
    collection.SearchAsync(question.Text, 10))
{
    MovieVectorStoreRecord record = result.Record;
    Console.WriteLine(record.Title);
}

22.2 三种 RAG 实现方式

方式1:预加载所有数据

List<ChatMessage> messages = [
    new ChatMessage(ChatRole.Assistant, "这是所有电影数据"),
];
foreach (var movie in allMovies) {
    messages.Add(new ChatMessage(ChatRole.Assistant, movie.GetDetails()));
}
messages.Add(new ChatMessage(ChatRole.User, question));
AgentResponse response = await agent.RunAsync(messages);

方式2:RAG + 预加载(向量搜索后注入)

List<ChatMessage> messages = [
    new ChatMessage(ChatRole.Assistant, "这是最相关的电影")
];
await foreach (var result in collection.SearchAsync(question.Text, 10))
{
    messages.Add(new ChatMessage(ChatRole.Assistant, result.Record.GetDetails()));
}
messages.Add(new ChatMessage(ChatRole.User, question));
AgentResponse response = await agent.RunAsync(messages);

方式3:RAG via Tool Call(按需搜索)

class SearchTool(InMemoryCollection<Guid, MovieVectorStoreRecord> collection)
{
    public async Task<List<string>> SearchVectorStore(string question)
    {
        List<string> result = [];
        await foreach (var searchResult in collection.SearchAsync(question, 10))
        {
            result.Add(searchResult.Record.GetDetails());
        }
        return result;
    }
}

AIAgent agent = chatClient.AsAIAgent(
    instructions: "根据提供的数据回答问题",
    tools: [AIFunctionFactory.Create(searchTool.SearchVectorStore)]
).AsBuilder().Use(FunctionCallMiddleware).Build();

22.3 支持的向量存储

存储
InMemoryMicrosoft.SemanticKernel.Connectors.InMemory
Azure AI SearchMicrosoft.SemanticKernel.Connectors.AzureAISearch
SQL Server 2025Microsoft.SemanticKernel.Connectors.SqlServer
CosmosDB NoSQLMicrosoft.SemanticKernel.Connectors.CosmosNoSql

23. 框架工具包 (AgentFrameworkToolkit)

第三方社区工具包 AgentFrameworkToolkit 提供了更简洁的 API:

23.1 简化 Agent 创建

// Before(原生 MAF)
AzureOpenAIClient client = ClientHelper.GetAzureOpenAIClient();
AIAgent agent = client.GetChatClient("gpt-5-mini")
    .AsAIAgent(options: new ChatClientAgentOptions { ... })
    .AsBuilder()
    .Use(FunctionCallMiddleware)
    .Build();

// After(使用 AgentFrameworkToolkit)
AzureOpenAIAgentFactory factory = new(endpoint, apiKey);
AzureOpenAIAgent agent = factory.CreateAgent(new AgentOptions
{
    Model = OpenAIChatModels.Gpt5Mini,
    ReasoningEffort = OpenAIReasoningEffort.Low,
    Tools = [AIFunctionFactory.Create(WeatherTool.GetWeather)],
    RawToolCallDetails = details => Console.WriteLine(details.ToString())
});

AgentResponse<WeatherReport> response = await agent.RunAsync<WeatherReport>("巴黎天气");

23.2 Google Gemini 简化

GoogleAgentFactory factory = new(new GoogleConnection { ApiKey = apiKey });
GoogleAgent agent = factory.CreateAgent(new GoogleAgentOptions
{
    Name = "MyGeminiAgent",
    Model = "gemini-2.5-flash"
});

23.3 Anthropic Claude 简化

AnthropicAgentFactory factory = new(new AnthropicConnection { ApiKey = apiKey });
AnthropicAgent agent = factory.CreateAgent(new AnthropicAgentOptions
{
    Name = "MyClaudeAgent",
    Model = AnthropicChatModels.ClaudeHaiku45,
    MaxOutputTokens = 1000
});

24. 各模式适用场景总结

24.1 场景决策树

需要构建 AI Agent 应用?
├── 单一对话式 Agent
│   └── 最简单的 Agent → 使用 ChatClientAgent + AsAIAgent()
│
├── 需要工具调用
│   ├── 基本工具 → AIFunctionFactory + tools 参数
│   ├── 需要日志/监控 → 添加 FunctionCallMiddleware
│   └── 需要 DI → services 参数注入 IServiceProvider
│
├── 需要结构化输出
│   └── RunAsync<T>() + Data Annotation
│
├── 需要多轮对话
│   ├── 基础 → AgentSession
│   ├── 长会话 → IChatReducer (MessageCountingChatReducer / SummarizingChatReducer)
│   └── 持久化 → 自定义 ChatHistoryProvider
│
├── 需要多 Agent 协作
│   ├── 顺序处理 → AgentWorkflowBuilder.BuildSequential()
│   ├── 并发处理 → AgentWorkflowBuilder.BuildConcurrent()
│   ├── 任务移交 → Handoff Workflow
│   ├── 条件分支 → AI-Assisted Workflow (自定义 Executor + Switch)
│   ├── Agent 作为工具 → agent.AsAIFunction()
│   └── 手动路由 → 结构化输出 + 路由逻辑
│
├── 需要人工介入
│   └── Human-in-the-Loop Workflow (RequestPort)
│
├── 需要跨进程通信
│   └── A2A 协议 (Agent2Agent.Server + Agent2Agent.Client)
│
├── 需要 Web 界面
│   ├── 快速集成 → AG-UI (MapAGUI)
│   └── 完整开发体验 → DevUI (MapDevUI)
│
├── 需要生产级部署
│   ├── Aspire Hosting → builder.AddAIAgent()
│   ├── Azure Functions → Microsoft.Agents.AI.Hosting.AzureFunctions
│   └── 独立服务 → ASP.NET Core + MapAGUI
│
├── 需要监控/遥测
│   └── OpenTelemetry → UseOpenTelemetry()
│
├── 需要 LLM 调用拦截
│   ├── 注入临时指令/工具 → AIContextProvider.ProvideAIContextAsync
│   ├── 存储记忆/知识提取 → AIContextProvider.StoreAIContextAsync
│   └── 注入消息 → MessageAIContextProvider
│
├── 需要外挂知识
│   └── RAG (向量搜索 + Tool Call 或预加载)
│
├── 长任务处理
│   └── AllowBackgroundResponses + ContinuationToken
│
├── 多模型混合
│   ├── 意图路由用小模型 + 处理用大模型
│   └── 各 Agent 使用不同模型
│
├── 需要多模态输入
│   └── TextContent / UriContent / DataContent
│
├── 需要 MCP 集成
│   └── MCP Server (WithToolsFromAssembly) 或 Foundry McpTool
│
└── 需要 Azure AI Foundry 平台工具
    └── Foundry Agent + CodeInterpreter / WebSearch / MCP

24.2 模式推荐表

模式推荐场景关键 API
ChatClientAgent标准对话 AgentchatClient.AsAIAgent()
Streaming实时响应体验RunStreamingAsync()
Session多轮对话CreateSessionAsync(), RunAsync(msg, session)
Tool CallingAgent 调用外部功能AIFunctionFactory.Create(), tools: [...]
Structured Output需要确定性返回格式RunAsync<T>()
Sequential Workflow处理流水线(A→B→C)AgentWorkflowBuilder.BuildSequential()
Concurrent Workflow并行分析/评估AgentWorkflowBuilder.BuildConcurrent()
Handoff Workflow专家路由(智能分发)CreateHandoffBuilderWith().WithHandoffs()
AI-Assisted Workflow复杂业务流程编排自定义 Executor<T> + WorkflowBuilder
Human-in-the-Loop需要用户确认/输入RequestPort, ExternalRequest
Agent as ToolAgent 嵌套/组合agent.AsAIFunction()
A2A跨服务 Agent 通信A2ACardResolver, MapA2AJsonRpc()
AG-UI快速 Web 聊天界面AddAGUI(), MapAGUI()
DevUI开发调试 UIAddDevUI(), MapDevUI()
RAG外挂知识库向量搜索 + 预加载/Tool Call
Telemetry生产监控UseOpenTelemetry()
AIContextProvider记忆/拦截/增强实现 AIContextProvider
Chat History Reducer长对话 Token 控制MessageCountingChatReducer, SummarizingChatReducer
Background Response长时间处理任务AllowBackgroundResponses = true
Foundry Agent使用 Azure 平台工具PersistentAgentsClient, AsAIAgent()
MCPAgent 功能暴露为标准协议WithToolsFromAssembly(), MapMcp()

24.3 架构建议

  • 小型应用:单一 ChatClientAgent + Tool Calling + Structured Output
  • 中型应用:Workflow(Sequential/Concurrent/Handoff)+ Session + Chat History Reducer
  • 大型应用:Aspire Hosting + 多 Workflow + A2A + AG-UI + Telemetry + DI
  • 企业级应用:Foundry Agent + Code Interpreter + Web Search + MCP + Human-in-the-Loop

附录:快速参考

最小化示例(15 行)

using Azure.AI.OpenAI;
using Microsoft.Agents.AI;
using OpenAI.Chat;
using System.ClientModel;

AzureOpenAIClient client = new(
    new Uri("https://xxx.openai.azure.com/"), 
    new ApiKeyCredential("your-key"));

ChatClientAgent agent = client
    .GetChatClient("gpt-4.1")
    .AsAIAgent();

AgentResponse response = await agent.RunAsync("法国的首都是什么?");
Console.WriteLine(response);

NuGet 包速查

场景必需包
基础 AgentMicrosoft.Agents.AI, Microsoft.Agents.AI.OpenAI
工作流Microsoft.Agents.AI.Workflows
托管Microsoft.Agents.AI.Hosting
Web UIMicrosoft.Agents.AI.Hosting.AGUI.AspNetCore
A2AMicrosoft.Agents.AI.A2A
遥测OpenTelemetry, Azure.Monitor.OpenTelemetry.Exporter
RAGMicrosoft.SemanticKernel.Connectors.InMemory (或对应存储包)
Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐