☰
用微软Agent Framework打造智能博客生成系统的那些事儿:TaoToken统一Key接入实践
2026/10/7 9:12:08 网站建设 项目流程

1. 从三个真实痛点说起:为什么需要多智能体博客生成系统

写技术博客这件事,单靠一个通用大模型对话窗口,做久了就会发现三个绕不开的坎。第一个坎是资料收集累成狗:打开十几个标签页,复制粘贴到凌晨,最后发现资料太乱理不清头绪。第二个坎是写作没思路:盯着空白文档三小时,憋出来的开头自己都觉得尴尬。第三个坎是质量没把条:写完了不知道质量如何,发出去被大佬指正错误时社死。

这三个坎本质上不是"模型不够聪明",而是"任务没有分工"。资料收集、内容撰写、质量审校,本来就是三种不同的认知任务,硬塞给一个 Prompt 让它一次干完,结果就是每一样都干得马马虎虎。我试过把这三件事拆成三个独立的 Agent,每个 Agent 只负责一件事,配上明确的职责边界、工具能力和输出约束,整个链路的质量立刻上了一个台阶。

这就是本文要聊的微软 Agent Framework 多智能体协作生成博客方案。它适合谁?适合已经会写 C#、想从"调 API 拼 Prompt"升级到"编排 Agent 工作流"的开发者;适合内容团队想搭一套半自动化的选题、撰写、审校流水线;也适合想理解多智能体协作到底怎么落地、而不是停留在概念层面的技术人。整套系统我把它叫做 BlogAgent,核心就是三个 Agent 加一条工作流,再配一个统一的模型接入通道。

在模型接入这块,多 Agent 系统有个很现实的麻烦:三个 Agent 可能要用不同的模型,Researcher 用便宜的小模型就够,Writer 要用强模型保证质量,Reviewer 又要稳定低温度。如果每个 Agent 都单独配一套 Key 和 Base URL,管理起来非常痛苦。所以本文会用 TaoToken 的统一 Key 通道来收敛这件事,一个 Key、一个 Base URL,通过 Model ID 区分不同 Agent 用哪个模型。下面从环境准备开始,一步步把这条链路搭起来。

2. TaoToken 统一 Key 接入:多 Agent 模型通道的前置准备

在动手写 Agent 代码之前,先把模型通道这件事解决掉。多智能体系统最怕的就是"每个 Agent 一套凭证",配置散落在 appsettings.json、环境变量、代码常量里,改一个模型要翻五个文件。TaoToken 的思路是提供一个 OpenAI 兼容的统一入口,你只需要维护一个 API Key 和一个 Base URL,具体用哪个模型通过请求里的 Model ID 指定。

先明确三个关键信息,后面配置里会反复用到:

项目值说明
Base URLhttps://taotoken.net/apiOpenAI 兼容接口地址,不加 UTM
API Key在控制台创建形如sk-...,只显示一次,务必保存
Model ID按 Agent 分配例如gpt-4o、gpt-4o-mini等

获取 Key 的路径很直接:打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,注册登录后进入控制台,在 API Keys 页面创建一个新 Key。创建时建议按用途命名,比如blogagent-dev,方便后面区分环境和轮换。创建完成后立刻复制保存,页面刷新后就看不到完整 Key 了。

拿到 Key 之后,先别急着写 Agent,用一条 curl 命令验证通道是否通。这一步非常关键,因为后面 Agent Framework 报的错往往是"模型返回格式不对",而根因其实是通道没通或者 Model ID 写错了。先用最原始的方式确认:

curl https://taotoken.net/api/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer sk-你的Key" \ -d '{ "model": "gpt-4o-mini", "messages": [ {"role": "user", "content": "用一句话说明什么是多智能体协作"} ], "temperature": 0.7 }'

如果返回结构里有choices[0].message.content,说明通道正常。如果返回 401,说明 Key 错了或者没带Bearer前缀;如果返回 404,多半是 Base URL 写成了https://taotoken.net/api但路径少了/v1/chat/completions,注意 OpenAI 兼容接口的完整路径是{BaseURL}/v1/chat/completions。这一步确认通过后,再进入 .NET 项目配置。

在 .NET 项目里,我建议把模型配置集中放在appsettings.json的一个节点下,而不是散落在代码里。这样三个 Agent 用哪个模型一目了然,切换模型也不用改代码:

{ "TaoToken": { "BaseUrl": "https://taotoken.net/api", "ApiKey": "sk-你的Key", "Models": { "Researcher": "gpt-4o-mini", "Writer": "gpt-4o", "Reviewer": "gpt-4o-mini" } } }

这里的分工逻辑是:Researcher 做资料整理和结构化摘要,任务相对机械,用便宜的小模型足够;Writer 要产出 4000 字以上的成稿,对语言质量和连贯性要求高,用强模型;Reviewer 做打分和挑错,需要稳定一致,用低温度的小模型即可。这样一套组合下来,单篇博客的模型成本能压到很低,而质量主要由 Writer 那一步保证。

注意:API Key 不要硬编码进代码提交到仓库。本地开发用appsettings.Development.json或环境变量TAOTOKEN__APIKEY覆盖,生产环境走密钥管理服务。.NET 的配置系统支持用双下划线表示层级,环境变量TAOTOKEN__APIKEY会自动映射到TaoToken:ApiKey。

配置就绪后,在Program.cs里注册一个统一的IChatClient,让三个 Agent 共享同一个客户端实例,只是调用时传不同的 Model ID。这样既复用了连接池,又保持了模型选择的灵活性。具体注册代码在下一节和 Agent 定义一起给出。

3. 可复制的 Agent 配置:三类 Agent 的编排与 settings 片段

这一节是全文的核心,把 Researcher、Writer、Reviewer 三个 Agent 的定义和工作流编排完整写出来。先看项目依赖,在.csproj里加上这几个包:

<PackageReference Include="Microsoft.Agents.AI" Version="1.0.0-preview" /> <PackageReference Include="Microsoft.Extensions.AI" Version="9.10.1-preview" /> <PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.10.1-preview" />

然后在Program.cs里注册统一客户端。注意这里用OpenAIClient指向 TaoToken 的 Base URL,再包一层IChatClient:

using Microsoft.Extensions.AI; using OpenAI; var builder = WebApplication.CreateBuilder(args); var baseUrl = builder.Configuration["TaoToken:BaseUrl"]!; var apiKey = builder.Configuration["TaoToken:ApiKey"]!; // 统一客户端,指向 TaoToken 兼容入口 var openAiClient = new OpenAIClient( new System.ClientModel.ApiKeyCredential(apiKey), new OpenAIClientOptions { Endpoint = new Uri(baseUrl) }); builder.Services.AddSingleton<IChatClient>(sp => openAiClient.GetChatClient("gpt-4o-mini").AsIChatClient()); builder.Services.AddSingleton<AgentFactory>();

AgentFactory负责按 Agent 类型创建带不同 Model ID 的 Agent 实例。这里的关键是每个 Agent 的Instructions、Tools、ResponseFormat和Temperature都要明确:

public class AgentFactory { private readonly IChatClient _chatClient; private readonly IConfiguration _config; public AgentFactory(IChatClient chatClient, IConfiguration config) { _chatClient = chatClient; _config = config; } public ChatClientAgent CreateResearcher() { var model = _config["TaoToken:Models:Researcher"]!; return new ChatClientAgent( _chatClient, name: "ResearcherAgent", instructions: """ 你是一位专业的技术资料收集专家。 任务:提取关键信息、整理代码示例、生成结构化摘要。 输出:严格的 JSON 格式,字段包括 topic_analysis、key_points、code_examples。 不要输出任何 JSON 之外的文字。 """, modelId: model); } public ChatClientAgent CreateWriter() { var model = _config["TaoToken:Models:Writer"]!; return new ChatClientAgent( _chatClient, name: "WriterAgent", instructions: """ 你是一位资深技术博客作家,擅长把技术内容转化为通俗易懂的文章。 文章结构必须包含:标题、引言、背景介绍、核心概念、实战应用、最佳实践、总结。 代码示例使用 ``` 代码块并标注语言类型。 避免空洞的套话,逻辑流畅,前后呼应。 """, modelId: model); } public ChatClientAgent CreateReviewer() { var model = _config["TaoToken:Models:Reviewer"]!; return new ChatClientAgent( _chatClient, name: "ReviewerAgent", instructions: """ 你是一位严格的技术审稿人。 评分维度:准确性 40%、逻辑性 30%、原创性 20%、规范性 10%。 输出 JSON:overall_score、accuracy、logic、recommendation。 """, modelId: model); } }

三个 Agent 定义好之后,用AgentWorkflowBuilder把它们串成顺序工作流。这一步是整个系统"编排"的体现,状态管理和数据传递都由框架接管:

public async Task<WorkflowResult> ExecuteFullWorkflowAsync(string topic, string referenceContent) { var researcher = _factory.CreateResearcher(); var writer = _factory.CreateWriter(); var reviewer = _factory.CreateReviewer(); var workflow = AgentWorkflowBuilder.BuildSequential( "BlogGenerationWorkflow", researcher, writer, reviewer); var input = $""" 主题:{topic} 参考资料:{referenceContent} 撰写要求:字数不少于 2000 字,风格偏实战教程。 """; var messages = new List<ChatMessage> { new(ChatRole.User, input) }; await using var run = await InProcessExecution.StreamAsync(workflow, messages); await run.TrySendMessageAsync(new TurnToken(emitEvents: true)); string finalOutput = ""; await foreach (var evt in run.WatchStreamAsync()) { if (evt is AgentRunUpdateEvent update && !string.IsNullOrEmpty(update.Update.Text)) { finalOutput += update.Update.Text; } else if (evt is WorkflowOutputEvent output) { finalOutput = output.ToString(); break; } } return new WorkflowResult { Content = finalOutput }; }

如果你更希望用配置文件而不是代码来定义 Agent,Agent Framework 也支持声明式配置。下面是一个 YAML 片段,把三个 Agent 的角色和模型绑定写清楚,适合团队协作时统一管理:

agents: - name: ResearcherAgent model: gpt-4o-mini temperature: 0.5 instructions: "提取关键信息,输出结构化 JSON 摘要" - name: WriterAgent model: gpt-4o temperature: 0.8 maxTokens: 6000 instructions: "撰写 2000 字以上技术博客,结构完整" - name: ReviewerAgent model: gpt-4o-mini temperature: 0.3 instructions: "按四维度打分,输出 JSON 评审结果" workflow: type: sequential order: [ResearcherAgent, WriterAgent, ReviewerAgent]

这里有个容易踩的坑:Writer 的maxTokens一定要显式调大。默认值往往只有 4000,写长博客时输出会被截断,表现为文章写到一半突然没了。把maxTokens设到 6000 以上,长文输出才稳定。另外 Reviewer 的temperature要压低到 0.3 左右,审校工作需要一致性,不能今天说好明天说不好。

4. 端到端验证:一次完整生成请求与成功结果确认

配置写完了,必须做一次端到端验证,确认多 Agent 链路真的能稳定产出成稿,而不是"看起来能跑"。验证分三步:先单独测每个 Agent,再测完整工作流,最后检查输出结构。

第一步,单独调用 Researcher,确认它能返回合法 JSON。这一步能提前暴露通道问题和结构化输出问题:

var researcher = factory.CreateResearcher(); var thread = researcher.GetNewThread(); var result = await researcher.RunAsync( "主题:微软 Agent Framework 多智能体协作", thread); Console.WriteLine(result.Text);

期望输出是一段纯 JSON,形如:

{ "topic_analysis": "本文讨论 Agent Framework 的多智能体协作机制", "key_points": [ { "importance": 3, "content": "声明式工作流编排" }, { "importance": 2, "content": "结构化输出约束" } ], "code_examples": [ { "language": "csharp", "code": "AgentWorkflowBuilder.BuildSequential(...)" } ] }

如果返回里混了"好的,我来生成 JSON:"这类前缀,说明模型没有严格遵守结构化输出约束。解决办法是在 Instructions 里加一句"不要输出任何 JSON 之外的文字",并在解析时做容错,提取第一个{到最后一个}之间的内容再反序列化。

第二步,跑完整工作流。调用ExecuteFullWorkflowAsync,观察事件流。正常情况下你会依次看到 ResearcherAgent、WriterAgent、ReviewerAgent 的执行事件,每个 Agent 的输出会累积到finalOutput。实测下来,一次完整生成(gpt-4o 系列模型)的耗时分布大致是:资料收集 8 到 12 秒,博客撰写 25 到 40 秒,质量审查 10 到 15 秒,总计 45 到 70 秒。这个时间对批量生产来说完全可以接受。

第三步,检查最终输出。一个成功的端到端结果应该满足:文章有完整标题和章节结构、代码块标注了语言、字数达到要求、Reviewer 返回了带overall_score的 JSON。如果 Reviewer 的评分低于 70,说明 Writer 的输出质量不达标,这时候可以触发重写分支,而不是直接发布。

为了确认链路稳定,建议连续跑三次同样的主题,观察输出是否结构一致。如果三次里有一次 Reviewer 返回的不是 JSON,那多半是温度太高或者 Instructions 不够严格。把 Reviewer 的temperature降到 0.2 再试,通常就稳定了。验证通过后,这套链路就可以接到前端,用 Blazor Server 做实时进度展示,用户点一下按钮就能看到三个 Agent 依次工作的过程。

5. 本篇常见错误排查:401、local proxy failed 与 reading choices

多 Agent 系统跑不起来,八成问题出在模型通道和输出解析上。这一节把最常见的几类报错和排查路径列清楚,对照着查能省很多时间。

401 Unauthorized。这是最高频的错误,几乎都是 Key 的问题。先确认三件事:Key 有没有带Bearer前缀(注意有个空格);Key 是不是复制时多了换行或空格;Key 有没有被禁用或额度耗尽。在 .NET 里,如果用的是ApiKeyCredential,框架会自动加Bearer,这时候你传的 Key 就不能再手动带前缀,否则会变成Bearer Bearer sk-...。排查时把实际请求的 Header 打出来看一眼最直接。

local proxy failed / connection refused。这个报错通常和网络环境有关,表现为客户端连不上 Base URL。先确认BaseUrl写的是https://taotoken.net/api,没有多余路径;再确认本机 DNS 能解析、能访问外网。如果是在容器里跑,检查容器网络是否放行了出站 HTTPS。还有一种情况是配置里 Base URL 末尾多了斜杠,导致拼出来的路径变成//v1/chat/completions,某些网关会拒绝,统一去掉末尾斜杠即可。

reading choices 相关报错。典型信息是Cannot read properties of undefined (reading 'choices')或者反序列化时找不到choices字段。这说明返回体结构和预期不符。可能原因有三个:一是请求路径不对,打到了非兼容接口;二是 Model ID 写错了,服务端返回了错误对象而不是正常响应;三是流式和非流式模式混用,代码按流式解析但请求发的是非流式。排查方法是在 curl 里复现同样的请求,看原始返回体长什么样,再对照代码里的解析逻辑。

OAuth / 认证方式不匹配。如果你在 MCP 配置里用了 HTTP 传输并开启了requiresAuth,但没配oauthClientId,就会报认证失败。MCP 的 HTTP 模式需要走 OAuth 流程,配置片段要写全:

{ "name": "RemoteToolService", "transportType": "http", "serverUrl": "https://your-mcp-host/mcp", "requiresAuth": true, "oauthClientId": "your_client_id" }

结构化输出解析失败。即使设了ChatResponseFormat.ForJsonSchema,部分模型仍可能返回带废词的 JSON。稳妥做法是加一层容错解析:先尝试直接反序列化,失败则截取第一个{到最后一个}再解析。这个兜底逻辑在多 Agent 系统里几乎是必备的,因为任何一个 Agent 的输出格式抖动都会让整条链路断掉。

MCP 工具加载超时。Stdio 模式的 MCP 要启动 Node 进程,冷启动可能 3 到 5 秒。如果同步等待,Agent 创建会被卡住。解决办法是加超时保护,用WaitAsync(TimeSpan.FromSeconds(15)),超时就跳过 MCP 工具继续执行,不要让整个 Agent 创建失败。

排查时记住一个原则:先隔离,再定位。先用 curl 确认通道,再单独跑每个 Agent,最后跑完整工作流。哪一层出问题就在哪一层解决,不要一上来就怀疑框架。

6. 把链路接到实际项目:Coding Plan 与后续扩展

三个 Agent 跑通之后,下一步就是把它接到真实项目里,让它真正产生价值。这里有两个方向值得展开:一是把模型调用成本控制住,二是把工作流扩展到更多场景。

成本控制方面,多 Agent 系统最容易失控的地方是重复调用。Researcher 收集的资料,如果 Writer 每次重写都要重新收集一遍,Token 消耗会翻好几倍。解决办法是加缓存:把 Researcher 的输出按 taskId 缓存起来,Writer 重写时直接复用。同时按 Agent 分配模型,Researcher 和 Reviewer 用便宜的小模型,只有 Writer 用强模型,单篇成本能压到很低。如果内容生产是长期、批量的需求,可以考虑用 Coding Plan 这类面向持续调用的方案来统一管理额度,避免每次都要单独充值。

扩展方向方面,这套"收集、撰写、审校"的三段式结构可以直接迁移到很多场景。新闻稿生成、产品文档、技术白皮书,本质都是"资料整理加内容产出加质量把关"。代码生成场景可以改成"需求分析、代码实现、代码审查"。数据分析场景可以改成"数据收集、分析报告、可视化建议"。只要你的业务能拆成多个步骤,就能用 Agent 工作流来实现。

如果要继续深入,建议从这几个点入手:给工作流加条件路由,Reviewer 评分低于阈值时自动触发重写;接入向量数据库做 RAG,让 Researcher 能引用历史博客保持风格一致;用 OpenTelemetry 做可观测性,追踪每个 Agent 的耗时和 Token 消耗。这些扩展都能在现有结构上平滑叠加,不需要推倒重来。

最后说个实操建议:先把最小链路跑通,也就是三个 Agent 加顺序工作流,确认能稳定产出一篇成稿,再去加 MCP 工具、RAG、条件路由这些高级特性。很多项目失败不是因为架构不够先进,而是因为一开始就堆了太多东西,结果哪一环都没调通。先把主干跑顺,再长枝叶。

需要创建 Key 或查看接入文档的话,可以从这里进:API Keys 页面 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite ,接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。想先验证模型效果,可以直接在模型对话页试 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=chat&utm_campaign=rewrite 。长期做内容生产或 Agent 开发的话,Coding Plan 会更划算 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询