ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用 .NET + Microsoft Agent Framework 搭一个 AI 美女聊天群组(一):Aspire 编排与 TaoToken 配置起步

用 .NET + Microsoft Agent Framework 搭一个 AI 美女聊天群组(一):Aspire 编排与 TaoToken 配置起步 1. 为什么 .NET 开发者需要一个「群聊骨架」来上手 Agent Framework如果你写过 Semantic Kernel 的单 Agent 应用再回头看 Microsoft Agent Framework第一反应大概率是多智能体协作的代码量并没有想象中那么夸张真正让人卡住的是「怎么把多个 Agent 跑起来、怎么让它们互相说话、模型 Key 从哪来」。我这次的目标很具体用 .NET 搭一个 AI 美女聊天群组让几个性格不同的角色在同一个会话里轮流发言而第一步不是写 Prompt而是先把 Aspire 编排和模型通道跑通。Microsoft Agent Framework 是微软在多智能体方向上的新一代框架它把 Handoff、GroupChat、Sequential、Concurrent 这些协作模式做成了内置工作流同时支持 .NET 和 Python。对 .NET 开发者来说它最大的价值是你不需要自己手写消息路由和状态机框架会帮你把「谁该说话、说完传给谁」这件事管起来。适合谁适合已经会 C#、写过 Web API、想从单 Agent 过渡到多 Agent 协作的开发者。这一篇是系列的第一篇只做一件事把 Aspire AppHost 和 Agent 注册的最小骨架搭起来再通过 TaoToken 统一 Key/API 通道完成一次真实的模型调用。跑通之后你会看到群聊消息在多个 Agent 之间流转而不是只有一个机器人在自说自话。后面几篇再逐步加角色人设、路由策略和持久化。2. TaoToken 前置统一 Key 与 API 通道在写 Agent 代码之前先把模型通道确定下来。多 Agent 群聊会频繁调用模型如果每个 Agent 各配一套 Key管理成本会很高。TaoToken 的思路是提供一个统一的 API 入口你只需要一个 Key就能在同一个通道里切换不同模型Agent 侧只认一个 BaseUrl 和一个 ApiKey。你需要先拿到两样东西一个可用的 API Key以及确认调用地址。控制台入口在这里控制台与 Key 管理https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite创建 Key 的页面API Keyshttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite调用时使用的 API 根地址是https://taotoken.net/api注意这个地址不带任何查询参数直接作为 OpenAI 兼容的 BaseUrl 使用。也就是说在 .NET 里你可以继续用OpenAI的 SDK只把Endpoint指向 TaoToken 即可代码几乎不用改。这里有个容易踩的坑很多人会把控制台地址和 API 地址搞混。控制台是给人看的网页API 地址是给程序调用的。你在appsettings.json里填的必须是https://taotoken.net/api而不是控制台那个带一堆参数的链接。另外Key 不要硬编码进代码放进用户机密或环境变量后面配置章节会给具体做法。如果你只是想先验证模型通不通不想马上写代码可以用模型对话页面直接试模型对话https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite3. 可复制配置Aspire AppHost 与 Agent 注册骨架3.1 项目结构与 Aspire 编排先建一个 Aspire 解决方案包含三个项目AgentGroupChat.AppHost编排入口、AgentGroupChat.AgentHost后端 API 与 Agent 逻辑、AgentGroupChat.Web前端本篇可以先不细做。AppHost 的Program.cs是整个本地编排的起点var builder DistributedApplication.CreateBuilder(args); // 后端 Agent 服务 var agentHost builder.AddProjectProjects.AgentGroupChat_AgentHost(agenthost) .WithEnvironment(TAOTOKEN_API_KEY, builder.Configuration[TAOTOKEN_API_KEY]) .WithEnvironment(TAOTOKEN_BASE_URL, https://taotoken.net/api); // 前端引用后端等待后端就绪 builder.AddProjectProjects.AgentGroupChat_Web(webfrontend) .WithExternalHttpEndpoints() .WithReference(agentHost) .WaitFor(agentHost); builder.Build().Run();这段代码做了三件事注册后端服务、把 TaoToken 的 Key 和 BaseUrl 作为环境变量注入、让前端等待后端启动完成。Aspire 会自动做服务发现前端不需要硬编码后端端口。3.2 Agent 注册与模型客户端在AgentHost里先注册一个共享的ChatClient所有 Agent 复用它。这里用 OpenAI 兼容的写法把地址指向 TaoTokenvar builder WebApplication.CreateBuilder(args); var apiKey builder.Configuration[TAOTOKEN_API_KEY] ?? throw new InvalidOperationException(缺少 TAOTOKEN_API_KEY); var baseUrl builder.Configuration[TAOTOKEN_BASE_URL] ?? https://taotoken.net/api; builder.Services.AddSingleton(sp { var options new OpenAIClientOptions { Endpoint new Uri(baseUrl) }; return new ChatClient( model: gpt-4o-mini, credential: new ApiKeyCredential(apiKey), options: options); }); builder.Services.AddSingletonAgentRegistry();AgentRegistry负责把角色定义转成框架里的 Agent 实例。先定义角色模型public record AgentProfile( string Id, string Name, string Avatar, string SystemPrompt, string Description); public class AgentRegistry { private readonly ChatClient _chatClient; private readonly ListAgentProfile _profiles new() { new(elena, 艾莲, EL, 你是艾莲一位专注哲学与文学的研究者说话理性、喜欢引经据典。, 哲学与文学), new(rina, 莉娜, RI, 你是莉娜来自东京的元气少女热爱动漫和游戏说话活泼带感叹号。, 动漫与游戏), new(chloe, 克洛伊, CH, 你是克洛伊纽约科技博主擅长用通俗语言解释编程和 AI。, 科技与编程) }; public AgentRegistry(ChatClient chatClient) _chatClient chatClient; public IReadOnlyListAgentProfile Profiles _profiles; public ChatClientAgent CreateAgent(AgentProfile profile) new(_chatClient, profile.SystemPrompt, profile.Id, profile.Description); }3.3 settings.json 关键字段后端appsettings.json只放非敏感配置Key 走用户机密或环境变量{ TAOTOKEN_BASE_URL: https://taotoken.net/api, DefaultModel: gpt-4o-mini, AgentGroup: { TriageAgentId: triage, MaxTurns: 6 } }本地开发时用dotnet user-secrets存 Keycd AgentGroupChat.AgentHost dotnet user-secrets init dotnet user-secrets set TAOTOKEN_API_KEY 你的Key如果你更习惯用config.toml管理比如配合某些 CLI 工具对应字段可以这样写注意它只是配置载体程序读取逻辑要自己接[taotoken] base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY default_model gpt-4o-mini4. 验证请求群聊消息如何流转4.1 最小工作流构建先用 Handoff 模式搭一个最小群聊一个 Triage Agent 负责路由三个角色 Agent 负责回复。构建逻辑放在WorkflowManager里public class WorkflowManager { private readonly AgentRegistry _registry; private readonly ChatClient _chatClient; public WorkflowManager(AgentRegistry registry, ChatClient chatClient) { _registry registry; _chatClient chatClient; } public Workflow Build() { var triage new ChatClientAgent( _chatClient, 你是路由系统只负责把用户消息转给最合适的角色不要自己回答。, triage, 消息路由); var specialists _registry.Profiles .Select(p _registry.CreateAgent(p)) .ToList(); var builder AgentWorkflowBuilder .CreateHandoffBuilderWith(triage) .WithHandoffs(triage, specialists) .WithHandoffs(specialists, triage); return builder.Build(); } }4.2 发送一条消息并观察事件流在 API 端点里触发一次群聊监听事件流把非 Triage 的输出收集起来app.MapPost(/api/chat, async (ChatRequest req, WorkflowManager wm) { var workflow wm.Build(); var messages new ListAIChatMessage { new(ChatRole.User, req.Message) }; var results new Listobject(); await using var run await InProcessExecution.StreamAsync(workflow, messages); await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); await foreach (var evt in run.WatchStreamAsync()) { if (evt is AgentRunUpdateEvent update) { var id update.ExecutorId.Split(_)[0]; if (id.Equals(triage, StringComparison.OrdinalIgnoreCase)) continue; var text update.Update.Contents .OfTypeTextContent() .FirstOrDefault()?.Text; if (!string.IsNullOrWhiteSpace(text)) results.Add(new { agent id, content text }); } } return Results.Ok(results); });4.3 启动与预期结果用 Aspire 一键启动dotnet run --project AgentGroupChat.AppHostAspire Dashboard 会自动打开你能看到agenthost和webfrontend两个服务都变成 Running。用 curl 打一条消息curl -X POST https://localhost:7390/api/chat \ -H Content-Type: application/json \ -d {message:最近有什么好看的动漫推荐吗}预期结果是Triage Agent 识别出「动漫」关键词把消息路由到莉娜返回的 JSON 里agent字段是rinacontent是莉娜风格的回复。如果你看到agent是triage或者内容为空说明路由没生效往下看排查章节。5. 本篇常见错排查5.1 401 或鉴权失败最常见的原因是 Key 没注入成功。先确认环境变量是否真的传进去了在 Aspire Dashboard 里点开agenthost看 Environment 里有没有TAOTOKEN_API_KEY。如果为空检查 AppHost 里builder.Configuration[TAOTOKEN_API_KEY]是否读到了值——AppHost 自己也需要能读到这个配置可以在 AppHost 项目里也执行一次dotnet user-secrets set。另一个原因是 BaseUrl 写成了控制台地址。记住 API 根地址是https://taotoken.net/api不要带/chat或查询参数SDK 会自己拼/v1/chat/completions这类路径。5.2 模型返回 404 或 model not found这通常是模型名写错了。TaoToken 通道里可用的模型名以控制台展示为准不要凭记忆写。如果你在ChatClient里写的是gpt-4o-mini但通道里实际叫别的名字就会 404。建议先在模型对话页面确认模型名再填进代码。5.3 群聊只有 Triage 回复如果返回结果里agent一直是triage说明 Handoff 没触发。检查两点一是 Triage 的 SystemPrompt 里是否明确要求「不要自己回答只做路由」二是WithHandoffs是否把 specialists 正确传进去了。我试过把 Triage 的 Prompt 写得太宽松它会直接自己回答导致路由失效。5.4 Aspire 启动后前端连不上后端Aspire 的服务发现依赖WithReference。如果前端报连接被拒绝检查 AppHost 里是否给前端加了.WithReference(agentHost)。另外.WaitFor(agentHost)能避免前端比后端先启动导致的偶发失败建议保留。5.5 事件流里文本被截断多 Agent 流式输出时AgentRunUpdateEvent会分多次推送文本片段。如果你只取第一次的TextContent就会丢内容。正确做法是按ExecutorId累积同一个 Agent 的片段拼起来再输出。上面的示例为了简洁只取了首个片段生产代码里要改成累积逻辑。6. 下一步把骨架跑顺再谈人设到这里Aspire 编排、TaoToken 通道、Agent 注册、群聊消息流转这四件事已经串起来了。你现在拥有的不是一个完整的聊天产品而是一个可运行的最小骨架——它的价值在于后面加角色、换路由策略、接持久化都是在这个骨架上做增量而不是推倒重来。如果你在验证模型阶段想快速试不同 Prompt 的效果可以直接用模型对话页面调不用每次都改代码重启模型对话https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite接入文档里有 OpenAI 兼容调用的完整字段说明遇到参数不确定时对照着看接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite如果你打算把这个群聊继续做成长期跑的编码助手或 Agent 应用Key 和额度管理会变成日常问题可以了解下 Coding PlanCoding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite下一篇会在这个骨架上加角色人设和 GroupChat 轮询策略让多个 Agent 真正「聊起来」而不是一问一答。
返回列表