news 2025/12/26 15:15:59

从开发一个AI美女聊天群组开始

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从开发一个AI美女聊天群组开始

ramework。很多开发者可能会有疑问:为什么微软要推出这么多框架?它们之间有什么区别?本文将通过一个实际的AI美女聊天群组项目,带你深入理解Microsoft Agent Framework,掌握多智能体开发的核心概念。

本文的示例代码已开源:agent-framework-tutorial-code/agent-groupchat

效果截图

视频演示

为什么微软要推出Microsoft Agent Framework?

AutoGen vs Semantic Kernel vs Agent Framework

在讲解新框架之前,我们先理解一下微软AI框架的演进路径:

AutoGen(研究导向)

最早期的多智能体研究框架

侧重学术研究和实验性功能

Python为主,生态相对独立

Semantic Kernel(应用导向)

面向生产环境的AI应用开发框架

强大的插件系统和内存管理

多语言支持(C#、Python、Java)

适合单一智能体应用

Microsoft Agent Framework(企业导向)

专为多智能体协作设计

内置工作流编排能力(Sequential、Concurrent、Handoff、GroupChat)

支持Handoff转移模式和GroupChat管理模式

与Azure AI Foundry深度集成

同时支持.NET和Python

Agent Framework的核心优势

原生多智能体支持:无需手动管理智能体间的通信,框架自动处理消息路由

声明式工作流:通过AgentWorkflowBuilder构建复杂协作场景

内置编排模式:

Handoff模式:智能体通过function calling实现控制权转移

GroupChat模式:通过GroupChatManager选择下一个发言智能体(支持RoundRobin、Prompt-based等策略)

状态管理:支持checkpoint存储,可恢复中断的工作流

大模型基础知识科普

在使用框架之前,我们需要理解大模型的工作原理。很多开发者对大模型有神秘感,其实它本质上就是一个HTTP API调用。

LLM API的本质

让我们用curl演示一个最简单的OpenAI API调用:

curl https://api.openai.com/v1/chat/completions \

-H "Content-Type: application/json" \

-H "Authorization: Bearer YOUR_API_KEY" \

-d '{

"model": "gpt-4o-mini",

"messages": [

{

"role": "user",

"content": "你好,请介绍一下自己"

}

]

}'

响应结果:

{

"id": "chatcmpl-abc123",

"object": "chat.completion",

"created": 1677652288,

"model": "gpt-4o-mini",

"choices": [{

"index": 0,

"message": {

"role": "assistant",

"content": "你好!我是一个AI助手,可以回答问题、提供建议..."

},

"finish_reason": "stop"

}]

}

关键点:

LLM就是一个普通的HTTP接口

输入:对话历史(messages数组)

输出:AI生成的回复(content字段)

所有复杂的Agent功能都是框架基于这个简单API构建的

函数调用(Function Calling)

函数调用是让LLM能够操作外部工具的关键机制。

工作流程:

开发者定义可用的函数(工具)

LLM根据用户意图决定调用哪个函数

框架执行函数并获取结果

将结果返回给LLM继续对话

示例 - 定义天气查询函数:

{

"name": "get_weather",

"description": "查询指定城市的天气信息",

"parameters": {

"type": "object",

"properties": {

"city": {

"type": "string",

"description": "城市名称,例如:北京"

}

},

"required": ["city"]

}

}

LLM的调用响应:

{

"role": "assistant",

"content": null,

"function_call": {

"name": "get_weather",

"arguments": "{\"city\": \"北京\"}"

}

}

重点理解:

LLM不会直接执行函数,只是"建议"调用

框架负责解析并执行函数

执行结果需要再次发送给LLM才能生成最终回复

MCP(Model Context Protocol)

MCP是新兴的标准化协议,用于LLM与外部工具的通信。

MCP的优势:

标准化接口:不同工具遵循统一协议

动态工具发现:运行时加载工具

安全隔离:工具在独立进程运行

在我们的示例项目中,使用MCP集成了阿里云通义万相图片生成能力。

agent-groupchat项目解析

项目架构

项目采用.NET Aspire编排,前后端分离架构:

agent-groupchat/

├── AgentGroupChat.AppHost/ # Aspire编排入口

│ └── Program.cs # 服务编排配置

├── AgentGroupChat.AgentHost/ # 后端API服务(.NET 9)

│ ├── Services/

│ │ ├── AgentChatService.cs # 核心聊天服务

│ │ ├── WorkflowManager.cs # 工作流管理

│ │ ├── AgentRepository.cs # 智能体配置管理

│ │ └── AgentGroupRepository.cs # 群组管理

│ ├── Models/

│ │ ├── AgentProfile.cs # 智能体模型

│ │ └── AgentGroup.cs # 群组模型

│ └── Program.cs # API端点

├── AgentGroupChat.Web/ # Blazor WebAssembly前端

│ ├── Components/

│ │ ├── Pages/

│ │ │ ├── Home.razor # 聊天主页面

│ │ │ └── Admin.razor # 管理后台

│ │ └── Layout/

│ │ └── MainLayout.razor # 主布局

│ ├── Services/

│ │ └── AgentHostClient.cs # API客户端

│ └── Program.cs # 前端入口

└── AgentGroupChat.ServiceDefaults/ # 共享服务配置

└── Extensions.cs # OpenTelemetry/健康检查

Aspire编排说明

什么是.NET Aspire?

.NET Aspire是微软推出的云原生应用编排框架,简化分布式应用的开发和部署:

服务发现:自动解析服务地址,前端无需硬编码API地址

统一启动:一个命令启动所有服务

可观测性:内置OpenTelemetry遥测数据收集

Dashboard:实时查看服务状态、日志、指标

AppHost配置(AgentGroupChat.AppHost/Program.cs):

var builder = DistributedApplication.CreateBuilder(args);

// 添加后端API服务

var agentHost = builder.AddProject<Projects.AgentGroupChat_AgentHost>("agenthost");

// 添加Blazor前端,引用后端服务

builder.AddProject<Projects.AgentGroupChat_Web>("webfrontend")

.WithExternalHttpEndpoints() // 暴露外部访问端口

.WithReference(agentHost) // 注入agenthost服务发现信息

.WaitFor(agentHost); // 等待后端启动完成

builder.Build().Run();

服务发现原理:

前端通过Aspire自动获取后端地址(Program.cs):

// Web项目的Program.cs

var agentHostUrl = builder.Configuration["AgentHostUrl"] ?? "https://localhost:7390";

builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(agentHostUrl) });

Aspire会自动将agenthost服务的实际地址注入到配置中。

智能体定义

项目创建了6个性格各异的AI美女角色,组成"AI世界公馆":

艾莲 (Elena)

new PersistedAgentProfile

{

Id = "elena",

Name = "艾莲",

Avatar = "🧠",

SystemPrompt = "你是艾莲,一位来自巴黎的人文学者,专注于哲学、艺术和文学研究...",

Description = "巴黎研究员,擅长哲学、艺术与思辨分析",

Personality = "理性、深邃,喜欢引经据典,用哲学视角看世界"

}

莉子 (Rina)

new PersistedAgentProfile

{

Id = "rina",

Name = "莉子",

Avatar = "🎮",

SystemPrompt = "你是莉子,来自东京的元气少女,热爱动漫、游戏和可爱的事物...",

Description = "东京元气少女,热爱动漫、游戏和可爱事物",

Personality = "活泼、热情,说话带感叹号,喜欢用可爱的emoji"

}

其他角色:

克洛伊 (Chloe):纽约科技极客

安妮 (Annie):洛杉矶时尚博主

苏菲 (Sophie):伦敦哲学诗人

智能路由实现

这是项目的核心亮点 - Triage Agent自动将用户消息路由到最合适的AI角色。

Triage Agent配置:

var triageSystemPrompt = @"你是AI世界公馆的智能路由系统。

【核心规则】

1. 永远不要生成文本回复 - 你对用户完全透明

2. 立即调用handoff函数,不需要解释

3. 不要确认、问候或回应 - 只默默路由

【路由策略】

1. **直接提及**:用户用 @ 提到角色名,立即路由到该角色

2. **话题匹配**:

- 哲学/艺术/文学 → 艾莲

- 动漫/游戏/萌文化 → 莉子

- 科技/编程/AI → 克洛伊

- 时尚/美妆/生活 → 安妮

- 诗歌/文学/情感 → 苏菲

3. **语气风格**:活泼→莉子,理性→艾莲,冷静→克洛伊

4. **上下文连贯**:查看对话历史,如果上一条是某专家回复且话题相关,继续路由到该专家

示例:

- ""@莉子 推荐动漫"" → handoff_to_rina

- ""如何学习机器学习?"" → handoff_to_chloe

- ""最新的时尚趋势是什么?"" → handoff_to_annie

";

Handoff实现:

// 创建Handoff工作流

var workflow = _workflowManager.GetOrCreateWorkflow(groupId);

// 运行工作流

await using StreamingRun run = await InProcessExecution.StreamAsync(workflow, messages);

await run.TrySendMessageAsync(new TurnToken(emitEvents: true));

// 监听事件流

await foreach (WorkflowEvent evt in run.WatchStreamAsync())

{

if (evt is AgentRunUpdateEvent agentUpdate)

{

// 检测到specialist agent执行

if (agentUpdate.ExecutorId != "triage")

{

var profile = _agentRepository.Get(agentUpdate.ExecutorId);

// 提取LLM生成的文本

var textContent = agentUpdate.Update.Contents

.OfType<TextContent>()

.FirstOrDefault();

// 构建响应

summaries.Add(new ChatMessageSummary

{

AgentId = agentUpdate.ExecutorId,

AgentName = profile?.Name,

AgentAvatar = profile?.Avatar,

Content = textContent?.Text,

IsUser = false

});

}

}

}

关键技术点

1. 动态智能体加载

智能体配置存储在LiteDB中,支持运行时动态更新:

public class AgentRepository

{

public List<PersistedAgentProfile> GetAllEnabled()

{

return _collection

.Find(a => a.Enabled)

.ToList();

}

public void Upsert(PersistedAgentProfile agent)

{

_collection.Upsert(agent);

}

}

2. 工作流管理

每个智能体组有独立的工作流实例:

public class WorkflowManager

{

private readonly Dictionary<string, Workflow> _workflows = new();

public Workflow GetOrCreateWorkflow(string groupId)

{

if (!_workflows.TryGetValue(groupId, out var workflow))

{

var group = _groupRepository.Get(groupId);

workflow = BuildHandoffWorkflow(group);

_workflows[groupId] = workflow;

}

return workflow;

}

}

3. 消息持久化

使用LiteDB存储会话历史:

public class PersistedSessionService

{

public void AddMessage(string sessionId, ChatMessageSummary message)

{

var doc = new BsonDocument

{

["SessionId"] = sessionId,

["AgentId"] = message.AgentId,

["Content"] = message.Content,

["Timestamp"] = message.Timestamp,

["IsUser"] = message.IsUser

};

_messagesCollection.Insert(doc);

}

}

国内用户运行指南

方式一:使用阿里云百炼平台

img

获取API密钥

访问 阿里云百炼,创建应用并获取API Key。

配置appsettings.json

{

"DefaultModelProvider": "OpenAI",

"OpenAI": {

"BaseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",

"ModelName": "qwen-plus",

"ApiKey": "sk-your-api-key"

}

}

配置MCP生图

需要开通MCP生图服务

使用的key也是和百炼的模型key一致

img

{

"McpServers": {

"Servers": [

{

"Id": "dashscope-text-to-image",

"Name": "DashScope Text-to-Image",

"Endpoint": "https://dashscope.aliyuncs.com/api/v1/mcps/TextToImage/sse",

"AuthType": "Bearer",

"BearerToken": "",

"TransportMode": "Sse",

"Enabled": true,

"Description": "阿里云 DashScope 文生图服务,用于生成图像"

}

]

}

}

运行项目

方式A:使用Aspire一键启动(推荐)

cd agent-groupchat

dotnet run --project AgentGroupChat.AppHost

Aspire Dashboard会自动打开(http://localhost:15220),显示:

agenthost:后端API服务

webfrontend:Blazor前端

直接点击webfrontend的URL即可访问应用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/21 23:18:05

最小二乘问题详解6:梯度下降法

4. 实例从上述求解过程可以看到&#xff0c;梯度下降法其实比之前文章中介绍的Gauss-Newton方法要简单很多&#xff0c;那么这里还是给出一个只使用Eigen实现梯度下降法求解非线性最小二乘问题的例子。例子中模型函数为f(x;θ)aebx&#xff1a;#include <Eigen/Dense>#in…

作者头像 李华
网站建设 2025/12/21 23:13:24

Kamailio转发机制

目录 一&#xff0e;Kamailio转发机制 1.有状态的请求转发 2.无状态的请求转发 3.有状态的响应转发 4.无状态的响应转发 二&#xff0e;示例 1.有状态的请求转发 2.无状态的请求转发 一&#xff0e;Kamailio转发机制 基于路由规则和SIP消息头&#xff08;可以是Request…

作者头像 李华
网站建设 2025/12/21 22:56:44

Thinkphp和Laravelpython桂平旅游管理系统vue

目录具体实现截图项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理具体实现截图 本系统&#xff08;程序源码数据库调试部署讲解&#xff09;带文档1万字以上 同行可拿货,招校园代理 Thinkphp和Laravelpython桂平旅游管理系统vue 项目开发技…

作者头像 李华
网站建设 2025/12/21 22:56:04

Linux设备树基础

Linux设备树基础笔记学习整理基于野火鲁班猫教程并且添加自己学习后理解的内容然后还有ai的一些总结。如果有说的不好或者不对的地方希望大家指正&#xff01;&#xff01;&#xff01;这是设备树的简略图&#xff0c;设备树的根节点扩张了许多子节点。有关设备树&#xff0c;D…

作者头像 李华
网站建设 2025/12/21 22:50:32

基于Thinkphp和Laravel框架的竞赛管理系统vue

目录具体实现截图项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理具体实现截图 本系统&#xff08;程序源码数据库调试部署讲解&#xff09;带文档1万字以上 同行可拿货,招校园代理 基于Thinkphp和Laravel框架的竞赛管理系统vue 项目开发技…

作者头像 李华
网站建设 2025/12/24 8:47:43

one-hot编码

我来详细介绍一下 one-hot 编码&#xff08;独热编码&#xff09;。什么是 One-Hot 编码&#xff1f;One-Hot 编码是一种将分类变量转换为二进制向量的技术&#xff0c;其中每个类别都表示为一个二进制向量&#xff0c;只有一个元素为1&#xff08;"热"&#xff09;&…

作者头像 李华