多模型协同与智能体(Agent)架构

多模型协同与智能体(Agent)架构

多个 AI 角色的协作 :一个规划者拆解任务,一个研究员搜索信息,一个执行者调用工具,一个审核者检查结果。这种 多智能体(Multi-Agent) 架构,正是迈向真正自主 AI 系统的关键一步。

将深入探讨 Semantic Kernel 如何支持多模型协同。将学习 群聊模式 ,让多个 Agent 像人类团队一样对话;掌握 规划器(Planner) ,使 AI 能够自动编写和执行 C# 代码;最后,我们将实现 流式输出,通过 Server-Sent Events(SSE)让 Web 应用获得实时响应体验。

1 基于 Semantic Kernel 的群聊模式(Group Chat)

1.1 什么是群聊模式?

在群聊模式中,每个 Agent 都是一个独立的 Kernel 实例,拥有自己的系统提示词、插件和模型配置。它们通过一个 协调器 进行通信,模拟人类团队的协作流程。例如,一个"软件架构师"Agent 负责拆解需求,一个"代码生成器"Agent 负责编写代码,一个"代码审查者"Agent 负责检查质量。

1.2 Semantic Kernel 中的 Agent 抽象

SK 在 Microsoft.SemanticKernel.Agents 包中提供了官方的 Agent 抽象,包括:

  • ChatCompletionAgent:基于聊天模型的 Agent,支持多轮对话。
  • CodeAgent:专门用于生成和执行代码的 Agent。
  • GroupChat:管理多个 Agent 的对话和转轮逻辑。

安装

bash 复制代码
dotnet add package Microsoft.SemanticKernel.Agents
1.3 构建多 Agent 团队

构建一个简单的三 Agent 团队,用于解决技术问题:

csharp 复制代码
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.ChatCompletion;

// 创建 Kernel 和 Agent
var kernel = Kernel.CreateBuilder()
    .AddAzureOpenAIChatCompletion(...)
    .Build();

var architect = new ChatCompletionAgent
{
    Name = "Architect",
    Instructions = """
        You are a software architect. Analyze the user's request and break it down
        into clear, actionable tasks. Output the tasks as a numbered list.
        Do not write code.
        """,
    Kernel = kernel
};

var coder = new ChatCompletionAgent
{
    Name = "Coder",
    Instructions = """
        You are a senior developer. Based on the tasks provided by the Architect,
        write clean, efficient C# code. Include comments and error handling.
        Output only the code, no extra text.
        """,
    Kernel = kernel
};

var reviewer = new ChatCompletionAgent
{
    Name = "Reviewer",
    Instructions = """
        You are a code reviewer. Analyze the code written by the Coder.
        Point out potential bugs, performance issues, or style problems.
        Suggest improvements. If the code is perfect, say "Approved".
        """,
    Kernel = kernel
};
1.4 群聊协调器:GroupChat

SK 的 GroupChat 提供了一个简单的协调器,可以管理 Agent 之间的对话。但它默认是顺序发言的,需要我们自己实现转轮逻辑。我们可以手动控制对话流程,更灵活。

手动控制流程示例

csharp 复制代码
public class AgentOrchestrator
{
    private readonly ChatCompletionAgent _architect;
    private readonly ChatCompletionAgent _coder;
    private readonly ChatCompletionAgent _reviewer;

    public async Task<string> ProcessAsync(string userRequest)
    {
        var chat = new ChatHistory();
        chat.AddUserMessage(userRequest);

        // 1. 架构师拆解任务
        var architectResponse = await _architect.GetResponseAsync(chat);
        chat.AddAssistantMessage(architectResponse.Content);
        var tasks = architectResponse.Content;

        // 2. 编码员根据任务编写代码
        var coderResponse = await _coder.GetResponseAsync(chat);
        chat.AddAssistantMessage(coderResponse.Content);
        var code = coderResponse.Content;

        // 3. 审查员审查代码
        var reviewerResponse = await _reviewer.GetResponseAsync(chat);
        chat.AddAssistantMessage(reviewerResponse.Content);
        var review = reviewerResponse.Content;

        // 判断是否需要迭代
        if (review.Contains("Approved"))
        {
            return $"**Code:**\n```csharp\n{code}\n```\n\n**Review:** {review}";
        }
        else
        {
            // 可以迭代:将审查意见加入对话,让 Coder 修改
            var revisedCoderResponse = await _coder.GetResponseAsync(chat);
            return revisedCoderResponse.Content;
        }
    }
}
1.5 高级群聊模式:动态角色与投票

对于更复杂的场景,可以引入 动态角色选择投票机制。例如,多个专家 Agent 分别提出方案,由一个"裁判"Agent 投票决定最佳方案。SK 的 Agent 包支持为每个 Agent 指定不同的模型和参数,实现"混合专家"架构。

实现投票模式

csharp 复制代码
var agents = new List<ChatCompletionAgent> { expertA, expertB, expertC };
var chat = new ChatHistory();
chat.AddUserMessage("How to implement a distributed lock in Redis?");

var suggestions = new List<string>();
foreach (var agent in agents)
{
    var response = await agent.GetResponseAsync(chat);
    suggestions.Add(response.Content);
}

// 裁判 Agent 综合评估
var judge = new ChatCompletionAgent
{
    Name = "Judge",
    Instructions = "You are a judge. Evaluate the following suggestions and pick the best one, explaining why.",
    Kernel = kernel
};

var judgeChat = new ChatHistory();
judgeChat.AddUserMessage($"Suggestions:\n{string.Join("\n---\n", suggestions)}");
var finalVerdict = await judge.GetResponseAsync(judgeChat);
1.6 群聊模式的挑战与最佳实践
  • 状态管理:多轮对话会产生大量历史记录,容易超出上下文窗口。建议定期压缩或总结历史。
  • 模型选择:不同 Agent 可以用不同模型,例如规划者用 GPT-4,代码生成用专门的 Codex 模型。
  • 错误处理:Agent 可能输出不符合预期格式的内容,需要解析和重试机制。
  • 可观测性:为每个 Agent 的调用添加 OpenTelemetry 追踪,记录耗时、输入输出,便于调试。

2 规划器(Planner):让 AI 自动编写 C# 代码执行任务

规划器是 Semantic Kernel 最强大的功能之一。它允许 LLM 根据用户意图,自动生成一个包含多个函数调用的 执行计划 ,甚至可以 生成 C# 代码并动态执行。这为实现"AI 编程"铺平了道路。

2.1 规划器的工作原理

规划器本质上是一个特殊的提示词,它引导 LLM 分析可用插件,生成一个步骤列表。SK 提供了两种规划器:

  • FunctionCallingStepPlanner:基于函数调用,将计划表示为一连串的函数调用。
  • HandlebarsPlanner:使用 Handlebars 模板语法生成包含逻辑分支的计划。
2.2 使用 FunctionCallingStepPlanner

安装

bash 复制代码
dotnet add package Microsoft.SemanticKernel.Planners

基础用法

csharp 复制代码
using Microsoft.SemanticKernel.Planning;

var planner = new FunctionCallingStepPlanner(kernel);
var plan = await planner.CreatePlanAsync("What's the weather in London and send an email summary to john@example.com");

// 执行计划
var result = await plan.InvokeAsync(kernel);
Console.WriteLine(result);

这个计划会自动分解为两步:

  1. 调用 WeatherPlugin.GetWeather("London")
  2. 调用 EmailPlugin.SendEmailAsync("john@example.com", "Weather Update", result_from_step1)
2.3 自定义规划器:代码生成与动态编译

当内置插件无法满足需求时,规划器可以生成 C# 代码,然后动态编译执行。这需要谨慎启用,因为它涉及代码执行的安全风险。

启用代码生成规划器 (需安装 Microsoft.SemanticKernel.Planning.CodeGeneration):

csharp 复制代码
using Microsoft.SemanticKernel.Planning.CodeGeneration;

var codePlanner = new CodeGenPlanner(kernel);
var plan = await codePlanner.CreatePlanAsync("Calculate Fibonacci(10) and write result to a file.");

SK 会生成类似以下的 C# 代码,然后使用 Microsoft.CodeAnalysis 动态编译并执行。这在数据转换、复杂计算等场景非常有用。

安全考虑

  • 在生产环境中,应限制代码生成能力,仅允许受信任的模型和用户。
  • 使用沙箱环境执行生成的代码,例如在隔离的 AppDomain 或容器中。
  • 设置执行超时和资源限制。
2.4 规划器的最佳实践
  • 插件描述至关重要 :清晰的插件描述能显著提升规划器的准确性。务必为每个函数和参数添加详细的 [Description]
  • 限制函数数量 :提供给规划器的函数越多,选择越困难。可以通过 Kernel.Plugins.Filter 动态过滤,只暴露与当前任务相关的插件。
  • 计划验证与重试:生成计划后,可以检查其是否合理,如出现循环调用或缺失必要参数时,重新生成计划。
  • 人工介入:对于高风险操作(如删除数据),规划器应请求用户确认后再执行。

3 流式输出与 Server-Sent Events(SSE)在 ASP.NET Core 中的实现

在聊天应用中,用户期望实时看到 AI 的回复,而不是等待完整响应。流式输出(Streaming)正是为此而生。Semantic Kernel 原生支持流式调用,而 ASP.NET Core 可以通过 Server-Sent Events(SSE)WebSockets 将这些增量数据推送到前端。

3.1 Semantic Kernel 中的流式调用

SK 提供了 InvokePromptStreamingAsync 方法,用于获取流式响应。

csharp 复制代码
var streamingResult = kernel.InvokePromptStreamingAsync("Write a poem about AI");

await foreach (var update in streamingResult)
{
    Console.Write(update); // 逐块输出
}

对于函数调用,同样支持流式输出:

csharp 复制代码
var streamingResult = kernel.InvokeStreamingAsync<MyFunctionResult>(...);
3.2 ASP.NET Core 中的 SSE 实现

SSE 是一种轻量级的推送技术,基于 HTTP,适合单向实时数据流。在 .NET 中,通过 IResult 扩展方法 Results.Stream 可以轻松实现。

控制器/端点示例

csharp 复制代码
[ApiController]
[Route("api/chat")]
public class ChatController : ControllerBase
{
    private readonly Kernel _kernel;

    [HttpGet("stream")]
    public async IAsyncEnumerable<string> StreamChat([FromQuery] string message)
    {
        var prompt = "You are a helpful assistant. " + message;
        var streamingResult = _kernel.InvokePromptStreamingAsync(prompt);
        
        await foreach (var chunk in streamingResult)
        {
            // 发送每个块
            yield return chunk;
        }
    }
}

在 Program.cs 中配置

csharp 复制代码
app.MapGet("/api/chat/stream", async (string message, Kernel kernel) =>
{
    var streaming = kernel.InvokePromptStreamingAsync($"You are a helpful assistant. {message}");
    return Results.Stream(async (stream) =>
    {
        var writer = new StreamWriter(stream);
        await foreach (var chunk in streaming)
        {
            await writer.WriteAsync(chunk);
            await writer.FlushAsync();
        }
    }, "text/plain");
});
3.3 使用 SignalR 实现双向流式通信

对于需要双向通信的场景(如多轮对话),SignalR 是更合适的选择。它可以建立持久连接,支持从服务器推送流式数据,也允许客户端随时发送消息。

SignalR Hub 示例

csharp 复制代码
public class ChatHub : Hub
{
    private readonly Kernel _kernel;

    public ChatHub(Kernel kernel) => _kernel = kernel;

    public async IAsyncEnumerable<string> StreamMessage(string userMessage)
    {
        var prompt = "You are a helpful assistant. " + userMessage;
        var streaming = _kernel.InvokePromptStreamingAsync(prompt);
        await foreach (var chunk in streaming)
        {
            yield return chunk;
        }
    }
}

前端调用(JavaScript)

javascript 复制代码
const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chatHub")
    .build();

await connection.start();

// 调用流式方法
const stream = connection.stream("StreamMessage", "What is AI?");
stream.subscribe({
    next: (chunk) => {
        document.getElementById("response").innerHTML += chunk;
    },
    complete: () => console.log("Done")
});
3.4 流式输出的错误处理与取消
  • 取消令牌 :在流式方法中,支持 CancellationToken,允许客户端取消长时间运行的生成。
  • 错误恢复:流可能因网络中断而中止,需要在客户端实现重连和续传机制。
  • 超时:设置合理的超时,避免连接被防火墙或代理关闭。
csharp 复制代码
public async IAsyncEnumerable<string> StreamMessage(
    string userMessage,
    CancellationToken cancellationToken)
{
    var streaming = _kernel.InvokePromptStreamingAsync(
        prompt: $"You are a helpful assistant. {userMessage}",
        cancellationToken: cancellationToken);
    
    await foreach (var chunk in streaming.WithCancellation(cancellationToken))
    {
        yield return chunk;
    }
}
3.5 流式输出的最佳实践
  • 前端渲染:使用 Markdown 实时渲染库(如 marked.js)在收到每个块后增量渲染。
  • 心跳机制 :SSE 可能被负载均衡器超时断开,定期发送注释行(: heartbeat)维持连接。
  • 压缩:对于大量文本,可考虑在传输层启用 gzip 压缩。
  • 观测性:在服务端记录流式请求的开始、结束和中断事件,便于监控和计费。

总结

探索了多模型协同与智能体架构的核心技术:

  • 群聊模式:通过多个 Agent 协作,模拟人类团队,解决复杂问题。
  • 规划器(Planner):让 AI 自动生成执行计划,甚至编写 C# 代码,实现动态任务编排。
  • 流式输出:通过 SSE 或 SignalR 提供实时交互体验,提升应用响应性。

掌握了这些能力,你就可以构建真正自主、协作的 AI 系统。

相关推荐
三更两点2 小时前
[特殊字符] 智能代理AI架构(生产就绪系统)
人工智能·架构
无忧智库2 小时前
从“数据孤岛”到“数智飞轮”:解码浙江移动“5141”企业级数据治理体系的顶层架构与实战逻辑(PPT)
架构
eF06U766F2 小时前
Ubuntu Linux 上 固定P/E 核混合架构CPU频率
linux·ubuntu·架构
heimeiyingwang2 小时前
【架构实战】数据湖架构设计与实践
架构
tianbaolc2 小时前
Claude Code 技能系统深度解析:核心架构
ai·架构·claude code
电磁脑机2 小时前
基于分布式电磁场的双体闭环脑机接口体系与场域认知底层理论
分布式·目标跟踪·重构·架构·交互
电磁脑机2 小时前
人类分布式大脑架构与文明、技术、安全的底层逻辑——原创大脑架构理论研究
网络·分布式·神经网络·安全·架构
蒸汽求职3 小时前
低延迟系统优化:针对金融 IT 与高频交易,如何从 CPU 缓存行(Cache Line)对齐展现硬核工程底蕴?
sql·算法·缓存·面试·职场和发展·金融·架构
fe7tQnVan3 小时前
.NET 11 预览版 1 中的新兴架构演进:RISC-V 与 LoongArch 支持的深度技术解析与生态展望
架构·.net·risc-v