多智能体微服务实战(2/4):三大开放协议让智能体互联互通
<h1 id="三大协议让智能体说同一种语言---mcpa2a与agent-framework深度解析">三大协议让智能体"说同一种语言" - MCP、A2A与Agent Framework深度解析</h1><h2 id="引言">引言</h2>
<p>在上一篇文章中,我们介绍了为什么企业需要多智能体协作系统。但一个关键问题还没有解答:</p>
<p><strong>这么多智能体,它们之间怎么通信?如何确保不同团队开发的智能体能够互操作?</strong></p>
<p>想象一下,如果没有HTTP协议,Web就不可能存在;如果没有TCP/IP协议,互联网就无从谈起。同样,要构建企业级的多智能体系统,我们需要<strong>标准化的通信协议</strong>。</p>
<p>在AgentFrameworkAspire项目中,我们使用了三大开放协议:</p>
<ol>
<li><strong>MCP (Model Context Protocol)</strong> - 工具暴露标准</li>
<li><strong>A2A (Agent-to-Agent Protocol)</strong> - 智能体通信协议</li>
<li><strong>Agent Framework</strong> - 工作流编排框架</li>
</ol>
<p>这三个协议各司其职,又相互配合,共同构建了一个强大而灵活的多智能体生态系统。</p>
<p>本文将深入这三大协议的技术细节,带你理解它们的设计理念和实际应用。</p>
<hr>
<h2 id="一mcp协议让ai模型发现和调用工具">一、MCP协议:让AI模型发现和调用工具</h2>
<h3 id="11-为什么需要mcp">1.1 为什么需要MCP?</h3>
<p>在MCP出现之前,如果你想让AI模型调用你的业务系统功能,通常有两种做法:</p>
<p><strong>方式1:Function Calling(函数调用)</strong></p>
<pre><code class="language-json">{
"name": "validate_budget",
"description": "验证预算是否在可用范围内",
"parameters": {
"type": "object",
"properties": {
"amount": {"type": "number"},
"category": {"type": "string"}
}
}
}
</code></pre>
<p>问题:</p>
<ul>
<li>每个AI提供商的格式略有不同</li>
<li>需要手工编写JSON描述</li>
<li>工具和实现代码分离,容易不一致</li>
</ul>
<p><strong>方式2:自然语言提示</strong></p>
<pre><code>你有以下工具可用:
- validate_budget: 验证预算,参数amount和category
请根据用户问题调用工具...
</code></pre>
<p>问题:</p>
<ul>
<li>格式不标准,AI容易理解错误</li>
<li>参数类型不明确</li>
<li>无法自动发现工具</li>
</ul>
<p><strong>MCP的解决方案</strong>:</p>
<p>MCP (Model Context Protocol) 是一个开放标准,定义了:</p>
<ul>
<li>工具如何描述自己(Tool Metadata)</li>
<li>工具如何被调用(Tool Invocation)</li>
<li>资源如何被访问(Resources)</li>
<li>提示词如何被复用(Prompts)</li>
</ul>
<p>更重要的是,MCP提供了<strong>自动发现机制</strong>。AI模型可以:</p>
<ol>
<li>查询服务有哪些工具(List Tools)</li>
<li>获取工具的详细描述</li>
<li>调用工具并获得结果</li>
</ol>
<h3 id="13-mcp调用流程图解">1.3 MCP调用流程图解</h3>
<p>下面用序列图展示完整的MCP工具调用流程:</p>
<div class="mermaid">sequenceDiagram
participant AI as AI Model (GPT-4)
participant PM as ProjectManager
participant MCP as MCP Client
participant Finance as Finance MCP Server
participant Tool as ValidateBudget Tool
Note over AI,PM: 用户询问:200万预算是否合理?
AI->>PM: 需要验证预算
PM->>MCP: 初始化MCP客户端
MCP->>Finance: GET /finance/mcp (Handshake)
Finance-->>MCP: Server Info + Protocol Version
MCP->>Finance: ListTools()
Finance-->>MCP:
MCP->>Finance: CallTool("ValidateBudget", {<br/>amount: 200,<br/>projectType: "ERP"<br/>})
Finance->>Tool: ValidateBudget(200, "ERP")
Tool->>Tool: 业务逻辑处理
Tool-->>Finance: {IsValid: false, Message: "预算偏低,建议至少300万"}
Finance-->>MCP: CallToolResult
MCP-->>PM: 工具调用结果
PM->>AI: 提供验证结果给AI
AI-->>AI: 生成最终响应
</div><p><strong>关键步骤解析</strong>:</p>
<ol>
<li><strong>Handshake(握手)</strong>:客户端连接到MCP服务器,协商协议版本</li>
<li><strong>ListTools(列出工具)</strong>:客户端查询服务器有哪些可用工具</li>
<li><strong>CallTool(调用工具)</strong>:客户端调用具体工具,传递参数</li>
<li><strong>工具执行</strong>:服务器执行业务逻辑</li>
<li><strong>返回结果</strong>:服务器返回标准化的<code>CallToolResult</code></li>
</ol>
<h3 id="14-mcp在agentframeworkaspire中的实现">1.4 MCP在AgentFrameworkAspire中的实现</h3>
<p>让我们看一个实际的例子:Finance服务的MCP工具。</p>
<h4 id="工具定义">工具定义</h4>
<pre><code class="language-csharp">// Finance/Program.cs
using ModelContextProtocol.Server;
using ModelContextProtocol.Protocol;
public class FinanceTools
{
/// <summary>
/// 验证预算是否在可用范围内
/// </summary>
public Task<CallToolResult> ValidateBudget(
decimal amount,
string category,
string costCenter)
{
// 业务逻辑:检查预算
var isValid = amount > 0 && amount < 1000000;
var availableBudget = 500000m;
var result = new
{
IsValid = isValid && amount <= availableBudget,
RequestedAmount = amount,
AvailableBudget = availableBudget,
Category = category,
CostCenter = costCenter,
Message = isValid && amount <= availableBudget
? "Budget validation passed"
: $"Budget validation failed: requested {amount} " +
$"exceeds available {availableBudget}"
};
return Task.FromResult(new CallToolResult
{
Content = [new TextContentBlock {
Text = System.Text.Json.JsonSerializer.Serialize(result)
}]
});
}
/// <summary>
/// 查询历史项目成本数据
/// </summary>
public Task<CallToolResult> GetHistoricalCosts(
string projectType,
string department)
{
// 模拟从数据库查询历史数据
var historicalData = new
{
ProjectType = projectType,
Department = department,
AverageCost = 250000m,
MinCost = 150000m,
MaxCost = 450000m,
ProjectCount = 15,
TimeframeMonths = 12
};
return Task.FromResult(new CallToolResult
{
Content = [new TextContentBlock {
Text = System.Text.Json.JsonSerializer.Serialize(historicalData)
}]
});
}
/// <summary>
/// 计算投资回报率(ROI)
/// </summary>
public Task<CallToolResult> CalculateROI(
decimal investment,
string expectedReturnsJson)
{
var expectedReturns = System.Text.Json.JsonSerializer
.Deserialize<decimal[]>(expectedReturnsJson) ?? [];
var totalReturn = expectedReturns.Sum();
var roi = investment > 0 ? ((totalReturn - investment) / investment) * 100 : 0;
var result = new
{
Investment = investment,
TotalReturn = totalReturn,
NetProfit = totalReturn - investment,
ROI_Percentage = Math.Round(roi, 2),
PaybackPeriod = expectedReturns.Length > 0 ? "Estimated 18 months" : "N/A"
};
return Task.FromResult(new CallToolResult
{
Content = [new TextContentBlock {
Text = System.Text.Json.JsonSerializer.Serialize(result)
}]
});
}
}
</code></pre>
<p><strong>关键点解析</strong>:</p>
<ol>
<li><strong><code></code> 特性</strong>:标记这个类包含MCP工具</li>
<li><strong><code></code> 特性</strong>:标记每个公开的工具方法</li>
<li><strong>强类型参数</strong>:<code>decimal amount</code>, <code>string category</code> - MCP会自动生成类型描述</li>
<li><strong>返回 <code>CallToolResult</code></strong>:标准化的返回格式,包含文本内容</li>
</ol>
<h4 id="注册mcp服务">注册MCP服务</h4>
<pre><code class="language-csharp">// Finance/Program.cs
var builder = WebApplication.CreateBuilder(args);
// 注册MCP Server,支持HTTP传输
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithTools<FinanceTools>() // 注册工具
.WithResources<BudgetResources>(); // 注册资源(可选)
var app = builder.Build();
// 暴露MCP端点
app.MapMcp("/finance/mcp");
app.Run();
</code></pre>
<h4 id="工具发现流程">工具发现流程</h4>
<p>当AI模型或其他智能体想要使用Finance的工具时:</p>
<p><strong>步骤1:发现工具</strong></p>
<pre><code class="language-http">POST /finance/mcp
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}
</code></pre>
<p><strong>MCP服务器响应</strong>:</p>
<pre><code class="language-json">{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "ValidateBudget",
"description": "验证预算是否在可用范围内",
"inputSchema": {
"type": "object",
"properties": {
"amount": {"type": "number"},
"category": {"type": "string"},
"costCenter": {"type": "string"}
},
"required": ["amount", "category", "costCenter"]
}
},
{
"name": "GetHistoricalCosts",
"description": "查询历史项目成本数据",
"inputSchema": {
"type": "object",
"properties": {
"projectType": {"type": "string"},
"department": {"type": "string"}
}
}
},
{
"name": "CalculateROI",
"description": "计算投资回报率(ROI)",
"inputSchema": {
"type": "object",
"properties": {
"investment": {"type": "number"},
"expectedReturnsJson": {"type": "string"}
}
}
}
]
}
}
</code></pre>
<p><strong>步骤2:调用工具</strong></p>
<pre><code class="language-http">POST /finance/mcp
Content-Type: application/json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "ValidateBudget",
"arguments": {
"amount": 300000,
"category": "Development",
"costCenter": "IT-001"
}
}
}
</code></pre>
<p><strong>MCP服务器响应</strong>:</p>
<pre><code class="language-json">{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "{\"IsValid\":true,\"RequestedAmount\":300000,\"AvailableBudget\":500000,...}"
}
]
}
}
</code></pre>
<h3 id="13-mcp-resources不止于工具">1.3 MCP Resources:不止于工具</h3>
<p>除了工具,MCP还支持<strong>Resources(资源)</strong>,用于暴露静态或动态的数据源。</p>
<pre><code class="language-csharp">// Finance/Program.cs
public class BudgetResources
{
/// <summary>
/// 获取标准预算分配模板
/// </summary>
public Task<ReadResourceResult> GetBudgetTemplate()
{
var template = new
{
Category = "General",
StandardAllocations = new
{
Personnel = "60%",
Infrastructure = "20%",
Operations = "15%",
Contingency = "5%"
}
};
return Task.FromResult(new ReadResourceResult
{
Contents = [new TextResourceContents
{
Uri = "budget://templates/general",
MimeType = "application/json",
Text = System.Text.Json.JsonSerializer.Serialize(template)
}]
});
}
}
</code></pre>
<p><strong>使用场景</strong>:</p>
<ul>
<li>暴露配置文件、模板、规范文档</li>
<li>提供数据集、历史记录</li>
<li>分享知识库、FAQ</li>
</ul>
<h3 id="14-mcp的价值">1.4 MCP的价值</h3>
<p>对比传统的REST API:</p>
<table>
<thead>
<tr>
<th>特性</th>
<th>REST API</th>
<th>MCP</th>
</tr>
</thead>
<tbody>
<tr>
<td>自动发现</td>
<td>❌ 需要文档</td>
<td>✅ 内置List API</td>
</tr>
<tr>
<td>类型安全</td>
<td>⚠️ OpenAPI可选</td>
<td>✅ 强制类型定义</td>
</tr>
<tr>
<td>AI友好</td>
<td>❌ 需要额外转换</td>
<td>✅ 原生设计</td>
</tr>
<tr>
<td>统一标准</td>
<td>❌ 各家不同</td>
<td>✅ 开放标准</td>
</tr>
<tr>
<td>工具和代码一致性</td>
<td>⚠️ 容易不同步</td>
<td>✅ 代码即文档</td>
</tr>
</tbody>
</table>
<hr>
<h2 id="二a2a协议智能体之间的标准对讲机">二、A2A协议:智能体之间的"标准对讲机"</h2>
<h3 id="21-智能体通信的挑战">2.1 智能体通信的挑战</h3>
<p>假设Tech团队和Finance团队各自开发了自己的智能体,现在PMO团队想要调用它们。没有标准协议的情况下:</p>
<p><strong>Tech团队的接口</strong>:</p>
<pre><code class="language-json">{
"query": "评估技术可行性",
"response_format": "json"
}
</code></pre>
<p><strong>Finance团队的接口</strong>:</p>
<pre><code class="language-json">{
"question": "评估技术可行性",
"output_type": "structured"
}
</code></pre>
<p><strong>问题</strong>:</p>
<ul>
<li>参数名不一样(<code>query</code> vs <code>question</code>)</li>
<li>格式不一样(<code>response_format</code> vs <code>output_type</code>)</li>
<li>如何知道智能体能做什么?</li>
<li>如何处理流式响应?</li>
<li>如何传递上下文?</li>
</ul>
<p><strong>A2A协议的解决方案</strong>:</p>
<p>A2A (Agent-to-Agent Protocol) 是由 Google Cloud 主导的智能体间通信标准,它定义了:</p>
<ol>
<li><strong>AgentCard</strong>:智能体的"名片",描述自己的能力</li>
<li><strong>标准消息格式</strong>:<code>MessageSendParams</code> 和 <code>AgentMessage</code></li>
<li><strong>发现机制</strong>:<code>.well-known/agent-card.json</code> 约定</li>
<li><strong>能力声明</strong>:支持的输入输出模式、是否支持流式等</li>
</ol>
<h3 id="22-a2a握手流程图解">2.2 A2A握手流程图解</h3>
<p>下面展示ProjectManager如何通过A2A协议连接并调用Tech Agent:</p>
<div class="mermaid">sequenceDiagram
participant PM as ProjectManager Agent
participant HTTP as HTTP Client
participant Tech as Tech Agent Server
participant Card as AgentCard Endpoint
participant Agent as RequirementAnalyst
Note over PM,Tech: 阶段1: 服务发现
PM->>HTTP: 创建A2ACardResolver
HTTP->>Card: GET https://localhost:7063/.well-known/agent-card.json
Card-->>HTTP: AgentCard JSON<br/>{name, description, capabilities}
HTTP-->>PM: AgentCard对象
Note over PM: 解析AgentCard<br/>- 验证协议版本<br/>- 检查capabilities<br/>- 获取endpoint URL
Note over PM,Tech: 阶段2: Agent初始化
PM->>HTTP: GetAIAgentAsync(AgentCard)
HTTP->>Tech: 建立连接到/tech/requirement-analyst/run
Tech-->>HTTP: 连接确认
HTTP-->>PM: AIAgent客户端实例
Note over PM,Tech: 阶段3: 消息传递
PM->>HTTP: agent.InvokeAsync(messages)
HTTP->>Tech: POST /tech/requirement-analyst/run<br/>{messages: [{role: "user", content: "..."}]}
Tech->>Agent: 处理用户消息
Agent->>Agent: 执行业务逻辑
Agent-->>Tech: 生成响应
Tech-->>HTTP: AgentRunResponse<br/>{messages: [{role: "assistant", content: "..."}]}
HTTP-->>PM: 解析响应
PM->>PM: 处理Tech Agent返回的结果
</div><p><strong>三阶段详解</strong>:</p>
<ol>
<li><strong>服务发现阶段</strong>:通过标准化的<code>.well-known/agent-card.json</code>端点获取Agent元数据</li>
<li><strong>初始化阶段</strong>:使用AgentCard中的信息创建可复用的AIAgent客户端</li>
<li><strong>消息传递阶段</strong>:使用标准化的消息格式进行双向通信</li>
</ol>
<h3 id="23-agentcard智能体的自我介绍">2.3 AgentCard:智能体的自我介绍</h3>
<p>每个A2A智能体都需要暴露一个AgentCard,描述自己:</p>
<pre><code class="language-csharp">// Tech/Program.cs
public class TechAnalystAgent
{
// ... (其他代码)
private Task<AgentCard> GetAgentCardAsync(
string agentUrl,
CancellationToken cancellationToken)
{
return Task.FromResult(new AgentCard
{
Name = "Technical Requirements Analyst",
Description = "Technical analyst agent specializing in " +
"requirements analysis, architecture design, " +
"and technology stack validation",
Url = agentUrl,
Version = "1.0.0",
DefaultInputModes = ["text"], // 支持文本输入
DefaultOutputModes = ["text"], // 输出文本
Capabilities = new AgentCapabilities
{
Streaming = false, // 不支持流式
PushNotifications = false // 不支持推送
},
Skills = [] // 技能列表(可选)
});
}
}
</code></pre>
<p><strong>AgentCard会自动暴露在标准端点</strong>:</p>
<pre><code>https://localhost:7063/.well-known/agent-card.json
</code></pre>
<p>任何智能体或客户端都可以访问这个端点,了解Tech Agent的能力。</p>
<h3 id="23-消息发送和接收">2.3 消息发送和接收</h3>
<h4 id="发送方web前端的projectmanageragent">发送方(Web前端的ProjectManagerAgent)</h4>
<pre><code class="language-csharp">// AgentFrameworkAspire.Web/Services/ProjectManagerAgent.cs
public class ProjectManagerAgent
{
private AIAgent? _techAgent;
/// <summary>
/// 使用A2ACardResolver初始化单个agent
/// </summary>
private async Task<AIAgent> InitializeAgentAsync(
string agentName,
string agentUrl,
CancellationToken ct)
{
_logger.LogInformation(
"Initializing {AgentName} agent from {Url}",
agentName, agentUrl);
// A2ACardResolver会自动在URL后追加 /.well-known/agent-card.json
// 例如: https://localhost:7063/.well-known/agent-card.json
var url = new Uri(agentUrl);
var agentCardResolver = new A2ACardResolver(url, _httpClient);
// 获取AgentCard并创建AIAgent客户端
var agent = await agentCardResolver.GetAIAgentAsync(
httpClient: _httpClient,
cancellationToken: ct);
_logger.LogInformation("{AgentName} agent initialized successfully", agentName);
return agent;
}
/// <summary>
/// 调用A2A Agent
/// </summary>
private async Task<AgentRunResponse> CallA2AAgentAsync(
string agentName,
AIAgent agent,
string userInput,
CancellationToken ct)
{
_logger.LogInformation("Calling {AgentName} agent via A2A...", agentName);
// 创建标准消息
var messages = new List<ChatMessage>
{
new(ChatRole.User, userInput)
};
// 调用远程智能体
var response = await agent.InvokeAsync(
messages,
cancellationToken: ct);
_logger.LogInformation(
"{AgentName} agent responded with {MessageCount} messages",
agentName,
response.Messages.Count);
return response;
}
}
</code></pre>
<p><strong>关键步骤</strong>:</p>
<ol>
<li><strong>A2ACardResolver</strong>:从URL解析AgentCard</li>
<li><strong>GetAIAgentAsync</strong>:创建AIAgent客户端代理</li>
<li><strong>InvokeAsync</strong>:调用远程智能体,发送消息并获取响应</li>
</ol>
<h4 id="接收方tech服务的techanalystagent">接收方(Tech服务的TechAnalystAgent)</h4>
<pre><code class="language-csharp">// Tech/Program.cs
public class TechAnalystAgent
{
private readonly IChatClient _chatClient;
public void Attach(ITaskManager taskManager)
{
// 注册消息处理器
taskManager.OnMessageReceived = ProcessMessageAsync;
// 注册AgentCard查询处理器
taskManager.OnAgentCardQuery = GetAgentCardAsync;
}
/// <summary>
/// 处理收到的A2A消息
/// </summary>
private async Task<A2AResponse> ProcessMessageAsync(
MessageSendParams messageSendParams,
CancellationToken cancellationToken)
{
// 提取消息文本
var messageText = messageSendParams.Message.Parts
.OfType<TextPart>()
.FirstOrDefault()?.Text ?? "";
// 构造提示词
var messages = new List<ChatMessage>
{
new(ChatRole.System,
"You are a technical requirements analyst specializing in " +
"software architecture and technical feasibility. You help " +
"analyze technical requirements, assess complexity, and " +
"recommend technology stacks."),
new(ChatRole.User, messageText)
};
// 调用底层的IChatClient(连接到OpenAI等)
var completion = await _chatClient.GetResponseAsync(
messages,
cancellationToken: cancellationToken);
// 返回标准的A2A响应
return new AgentMessage
{
Role = MessageRole.Agent,
MessageId = Guid.NewGuid().ToString(),
ContextId = messageSendParams.Message.ContextId,
Parts =
};
}
}
</code></pre>
<p><strong>关键点</strong>:</p>
<ul>
<li><strong>ITaskManager</strong>:A2A协议的任务管理器</li>
<li><strong>MessageSendParams</strong>:标准消息参数(包含消息ID、上下文ID、消息内容)</li>
<li><strong>AgentMessage</strong>:标准响应格式</li>
</ul>
<h4 id="暴露a2a端点">暴露A2A端点</h4>
<pre><code class="language-csharp">// Tech/Program.cs
var app = builder.Build();
// 创建TechAnalystAgent实例
var requirementAnalyst = new TechAnalystAgent(
AgentHelpers.CreateChatClient(app.Configuration)
);
// 创建TaskManager并绑定Agent
var techTaskManager = new TaskManager();
requirementAnalyst.Attach(techTaskManager);
// 暴露A2A端点
app.MapA2A(techTaskManager, "/tech/requirement-analyst");
// 暴露AgentCard端点
app.MapWellKnownAgentCard(techTaskManager, "/tech/requirement-analyst");
app.Run();
</code></pre>
<h3 id="24-完整的a2a通信流程">2.4 完整的A2A通信流程</h3>
<p>让我们追踪一次完整的A2A调用:</p>
<div class="mermaid">sequenceDiagram
participant PM as ProjectManager Agent<br/>(Web)
participant Tech as Tech Agent<br/>(Service)
PM->>Tech: 1. GET /.well-known/agent-card.json
Tech-->>PM: 2. AgentCard Response<br/>{name, description, capabilities}
PM->>Tech: 3. POST /tech/requirement-analyst<br/>MessageSendParams
Note over Tech: 处理消息<br/>执行业务逻辑
Tech-->>PM: 4. AgentMessage Response
</div><h3 id="25-a2a-vs-rest为什么需要专门的协议">2.5 A2A vs REST:为什么需要专门的协议?</h3>
<p>你可能会问:A2A和普通的REST API有什么区别?</p>
<table>
<thead>
<tr>
<th>特性</th>
<th>REST API</th>
<th>A2A</th>
</tr>
</thead>
<tbody>
<tr>
<td>目标</td>
<td>数据交换</td>
<td>智能体协作</td>
</tr>
<tr>
<td>消息格式</td>
<td>自定义JSON</td>
<td>标准化MessageSendParams</td>
</tr>
<tr>
<td>能力描述</td>
<td>OpenAPI(可选)</td>
<td>AgentCard(强制)</td>
</tr>
<tr>
<td>上下文传递</td>
<td>❌ 需要自己设计</td>
<td>✅ 内置ContextId</td>
</tr>
<tr>
<td>流式支持</td>
<td>⚠️ SSE或WebSocket</td>
<td>✅ 标准流式协议</td>
</tr>
<tr>
<td>AI原生</td>
<td>❌ 为人类设计</td>
<td>✅ 为AI设计</td>
</tr>
</tbody>
</table>
<p><strong>核心差异</strong>:A2A协议是<strong>AI原生</strong>的,考虑了智能体协作的特殊需求。</p>
<hr>
<h2 id="三agent-framework编排复杂的多阶段工作流">三、Agent Framework:编排复杂的多阶段工作流</h2>
<h3 id="31-为什么需要工作流编排">3.1 为什么需要工作流编排?</h3>
<p>前面介绍的MCP和A2A解决了"单点调用"的问题。但在实际场景中,我们常常需要:</p>
<ul>
<li><strong>串行执行</strong>:先做A,再做B,最后做C</li>
<li><strong>并行执行</strong>:同时做A、B、C、D</li>
<li><strong>条件分支</strong>:如果X成立,做A;否则做B</li>
<li><strong>状态传递</strong>:前一步的输出是后一步的输入</li>
</ul>
<p>这就需要<strong>工作流编排(Workflow Orchestration)</strong>。</p>
<h3 id="32-两种agentsimple-agent-vs-workflow-agent">3.2 两种Agent:Simple Agent vs Workflow Agent</h3>
<p>在AgentFrameworkAspire中,我们使用了两种类型的智能体:</p>
<h4 id="simple-agent简单智能体">Simple Agent(简单智能体)</h4>
<p>适用于单次调用、无状态的场景:</p>
<pre><code class="language-csharp">// Finance/Program.cs - Simple Agent
public class FinanceAgent
{
private readonly IChatClient _chatClient;
private async Task<A2AResponse> ProcessMessageAsync(
MessageSendParams messageSendParams,
CancellationToken cancellationToken)
{
// 直接调用IChatClient,返回结果
var messages = new List<ChatMessage>
{
new(ChatRole.System, "You are a financial analyst..."),
new(ChatRole.User, messageText)
};
var completion = await _chatClient.GetResponseAsync(
messages,
cancellationToken: cancellationToken);
return new AgentMessage { ... };
}
}
</code></pre>
<p><strong>特点</strong>:</p>
<ul>
<li>单次输入输出</li>
<li>无内部状态</li>
<li>快速响应</li>
</ul>
<h4 id="workflow-agent工作流智能体">Workflow Agent(工作流智能体)</h4>
<p>适用于多阶段、有状态的复杂场景。以QA团队的RiskManagementExpert为例,展示典型的4阶段串行工作流:</p>
<div class="mermaid">graph LR
Start([用户输入:请评估项目风险]) --> RiskIdentifier
subgraph Stage1 [阶段1: 风险识别]
RiskIdentifier
RiskIdentifier --> Output1[输出:风险列表<br/>例如:技术风险、成本风险、进度风险]
end
Output1 --> ImpactAnalyzer
subgraph Stage2 [阶段2: 影响分析]
ImpactAnalyzer
ImpactAnalyzer --> Output2[输出:优先级矩阵<br/>例如:技术风险 - 高概率高影响]
end
Output2 --> MitigationPlanner
subgraph Stage3 [阶段3: 缓解策略]
MitigationPlanner
MitigationPlanner --> Output3[输出:应对措施<br/>例如:技术预研、技术顾问、原型验证]
end
Output3 --> MonitoringPlanner
subgraph Stage4 [阶段4: 监控计划]
MonitoringPlanner
MonitoringPlanner --> Output4[输出:监控计划<br/>例如:每周风险审查、KPI跟踪]
end
Output4 --> End([最终输出:完整风险管理报告])
style Start fill:#3273dc,stroke:#333,color:#fff
style End fill:#3273dc,stroke:#333,color:#fff
style RiskIdentifier fill:#9b59b6,stroke:#333,color:#fff
style ImpactAnalyzer fill:#9b59b6,stroke:#333,color:#fff
style MitigationPlanner fill:#9b59b6,stroke:#333,color:#fff
style MonitoringPlanner fill:#9b59b6,stroke:#333,color:#fff
style Output1 fill:#ffe082,stroke:#333
style Output2 fill:#ffe082,stroke:#333
style Output3 fill:#ffe082,stroke:#333
style Output4 fill:#ffe082,stroke:#333
style Stage1 fill:#f0f0f0,stroke:#999,stroke-width:2px
style Stage2 fill:#f0f0f0,stroke:#999,stroke-width:2px
style Stage3 fill:#f0f0f0,stroke:#999,stroke-width:2px
style Stage4 fill:#f0f0f0,stroke:#999,stroke-width:2px
</div><p><strong>Workflow Agent实现代码</strong>:</p>
<pre><code class="language-csharp">// QA/Program.cs - Workflow Agent
public class RiskManagementExpertAgent
{
private readonly Workflow _riskAnalysisWorkflow;
private readonly IChatClient _chatClient;
public RiskManagementExpertAgent(IChatClient chatClient)
{
_chatClient = chatClient;
// 定义4个阶段的Agent
var riskIdentifier = new ChatClientAgent(chatClient, new ChatClientAgentOptions
{
Instructions = "你是项目风险识别专家。请用简洁的中文列出项目的主要风险...",
Name = "Risk Identifier"
});
var impactAnalyzer = new ChatClientAgent(chatClient, new ChatClientAgentOptions
{
Instructions = "你是风险影响分析专家。请用中文分析每个风险的影响和概率...",
Name = "Impact Analyzer"
});
var mitigationPlanner = new ChatClientAgent(chatClient, new ChatClientAgentOptions
{
Instructions = "你是风险缓解策略专家。请为每个高优先级风险制定具体的缓解措施...",
Name = "Mitigation Planner"
});
var monitoringPlanner = new ChatClientAgent(chatClient, new ChatClientAgentOptions
{
Instructions = "你是风险监控计划专家。请制定风险监控和控制计划...",
Name = "Monitoring Planner"
});
// 使用WorkflowBuilder构建工作流
_riskAnalysisWorkflow = new WorkflowBuilder(riskIdentifier)
.AddEdge(riskIdentifier, impactAnalyzer)
.AddEdge(impactAnalyzer, mitigationPlanner)
.AddEdge(mitigationPlanner, monitoringPlanner)
.WithOutputFrom(monitoringPlanner)
.Build();
}
}
</code></pre>
<p><strong>工作流关键特性</strong>:</p>
<ol>
<li><strong>串行执行</strong>:每个阶段按顺序执行,前一阶段输出作为后一阶段输入</li>
<li><strong>状态传递</strong>:通过<code>AddEdge()</code>定义数据流向</li>
<li><strong>专业分工</strong>:每个Agent有明确的专业角色和职责</li>
<li><strong>最终输出</strong>:<code>WithOutputFrom()</code>指定最终输出来源</li>
</ol>
<h3 id="33-执行工作流并流式返回">3.3 执行工作流并流式返回</h3>
<div class="mermaid">graph LR
Input([用户输入:评估项目风险]) --> RiskId
RiskId --> |识别的风险列表| Impact
Impact --> |优先级矩阵| Mitigation
Mitigation --> |应对措施| Monitoring
Monitoring --> Output([最终输出:完整风险管理计划])
style Input fill:#3273dc,stroke:#333,color:#fff
style Output fill:#3273dc,stroke:#333,color:#fff
style RiskId fill:#9b59b6,stroke:#333,color:#fff
style Impact fill:#9b59b6,stroke:#333,color:#fff
style Mitigation fill:#9b59b6,stroke:#333,color:#fff
style Monitoring fill:#9b59b6,stroke:#333,color:#fff
</div><p><strong>执行工作流的代码实现</strong>:</p>
<pre><code class="language-csharp">// QA/Program.cs
private async Task<A2AResponse> ProcessMessageAsync(
MessageSendParams messageSendParams,
CancellationToken cancellationToken)
{
var messageText = messageSendParams.Message.Parts
.OfType<TextPart>()
.FirstOrDefault()?.Text ?? "";
_logger.LogInformation("=== QA Risk Management Expert - Message Received ===");
_logger.LogInformation("Input Message: {MessageText}", messageText);
// 使用workflow处理风险分析 - 使用StreamingRun
var env = InProcessExecution.Default;
var run = await env.StreamAsync(_riskAnalysisWorkflow, messageText);
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
var responseBuilder = new StringBuilder();
// 监听工作流的流式事件
await foreach (var evt in run.WatchStreamAsync().WithCancellation(cancellationToken))
{
if (evt is AgentRunUpdateEvent update)
{
var response = update.AsResponse();
foreach (var message in response.Messages)
{
foreach (var content in message.Contents)
{
if (content is TextContent textContent)
{
responseBuilder.Append(textContent.Text);
}
}
}
}
}
return new AgentMessage
{
Role = MessageRole.Agent,
MessageId = Guid.NewGuid().ToString(),
ContextId = messageSendParams.Message.ContextId,
Parts =
};
}
</code></pre>
<p><strong>关键API</strong>:</p>
<ul>
<li><strong>InProcessExecution.Default</strong>:本地执行环境</li>
<li><strong>StreamAsync</strong>:启动流式工作流</li>
<li><strong>WatchStreamAsync</strong>:监听工作流事件</li>
<li><strong>AgentRunUpdateEvent</strong>:每个阶段的输出事件</li>
</ul>
<h3 id="34-web前端的3阶段工作流编排">3.4 Web前端的3阶段工作流编排</h3>
<p>ProjectManagerAgent实现了一个更复杂的工作流:</p>
<pre><code class="language-csharp">// AgentFrameworkAspire.Web/Services/ProjectManagerAgent.cs
public async IAsyncEnumerable<ExecutorEvent> ExecuteWorkflowStreamAsync(
string userInput,
CancellationToken ct = default)
{
// 确保agents已初始化
await InitializeAgentsAsync(ct);
// ==================== Stage 1: 并行分析 ====================
yield return new WorkflowStageStartEvent("pm-workflow")
{
StageName = "并行分析阶段",
InvolvedAgents = ["Tech", "HR", "Finance", "QA"]
};
// 并行调用4个specialist agents (使用A2A)
var parallelTasks = new[]
{
CallA2AAgentAsync("Tech", _techAgent!, userInput, ct),
CallA2AAgentAsync("HR", _hrAgent!, userInput, ct),
CallA2AAgentAsync("Finance", _financeAgent!, userInput, ct),
CallA2AAgentAsync("QA", _qaAgent!, userInput, ct)
};
var analysisResults = new List<AgentRunResponse>();
// 使用 Task.WhenEach 实现真正的并行 + 流式返回
await foreach (var task in Task.WhenEach(parallelTasks))
{
var response = await task;
analysisResults.Add(response);
// 流式输出每个specialist的响应
foreach (var message in response.Messages)
{
var update = new AgentRunResponseUpdate
{
Role = message.Role,
Contents = message.Contents,
AgentId = response.AgentId,
CreatedAt = DateTimeOffset.Now,
MessageId = message.MessageId
};
yield return new AgentRunUpdateEvent("pm-workflow", update);
}
}
yield return new WorkflowStageCompleteEvent("pm-workflow")
{
StageName = "并行分析阶段"
};
// ==================== Stage 2: PMO规划 ====================
yield return new WorkflowStageStartEvent("pm-workflow")
{
StageName = "PMO规划阶段",
InvolvedAgents = ["PMO"]
};
// 整合Stage 1的结果
var consolidatedAnalysis = ConsolidateAnalysisResults(analysisResults);
// 调用PMO Agent
var pmoResponse = await CallA2AAgentAsync(
"PMO",
_pmoAgent!,
$"基于以下分析结果生成详细项目计划:\n\n{consolidatedAnalysis}",
ct);
foreach (var message in pmoResponse.Messages)
{
var update = new AgentRunResponseUpdate
{
Role = message.Role,
Contents = message.Contents,
AgentId = "PMO",
CreatedAt = DateTimeOffset.Now,
MessageId = message.MessageId
};
yield return new AgentRunUpdateEvent("pm-workflow", update);
}
yield return new WorkflowStageCompleteEvent("pm-workflow")
{
StageName = "PMO规划阶段"
};
// ==================== Stage 3: PM整合决策 ====================
yield return new WorkflowStageStartEvent("pm-workflow")
{
StageName = "整合决策阶段",
InvolvedAgents = ["ProjectManager"]
};
// PM使用IChatClient进行最终整合
var chatClient = AgentHelpers.CreateChatClient(_configuration);
var finalPrompt = BuildFinalIntegrationPrompt(analysisResults, pmoResponse);
var finalResponse = await chatClient.GetResponseAsync(
,
null,
ct);
var finalUpdate = new AgentRunResponseUpdate
{
Role = ChatRole.Assistant,
Contents = ,
AgentId = "ProjectManager",
CreatedAt = DateTimeOffset.Now
};
yield return new AgentRunUpdateEvent("pm-workflow", finalUpdate);
yield return new WorkflowStageCompleteEvent("pm-workflow")
{
StageName = "整合决策阶段"
};
// 工作流完成
yield return new WorkflowOutputEvent("pm-workflow");
}
</code></pre>
<p><strong>工作流特点</strong>:</p>
<ul>
<li><strong>Stage 1并行</strong>:Tech、HR、Finance、QA同时执行,大幅缩短时间</li>
<li><strong>Stage 2依赖Stage 1</strong>:PMO基于前4个团队的分析结果进行规划</li>
<li><strong>Stage 3汇总</strong>:PM整合所有信息,生成最终报告</li>
<li><strong>流式返回</strong>:使用<code>IAsyncEnumerable</code>,每个Agent完成后立即返回,无需等待全部完成</li>
</ul>
<h3 id="35-workflowbuilder-api详解">3.5 WorkflowBuilder API详解</h3>
<p>Agent Framework提供了流畅的API来构建工作流:</p>
<pre><code class="language-csharp">// 线性工作流(Sequential)
var workflow = new WorkflowBuilder(agent1)
.AddEdge(agent1, agent2)
.AddEdge(agent2, agent3)
.WithOutputFrom(agent3)
.Build();
// 并行工作流(Parallel)
var workflow = new WorkflowBuilder(agent1)
.AddEdge(agent1, agent2)
.AddEdge(agent1, agent3)// agent2和agent3并行执行
.AddEdge(agent1, agent4)
.WithOutputFrom()// 收集所有输出
.Build();
// 条件分支(Conditional)
var workflow = new WorkflowBuilder(agent1)
.AddEdge(agent1, agent2, condition: ctx => ctx.SomeFlag)
.AddEdge(agent1, agent3, condition: ctx => !ctx.SomeFlag)
.Build();
</code></pre>
<hr>
<h2 id="四三大协议如何协同工作">四、三大协议如何协同工作?</h2>
<p>现在我们理解了每个协议的作用,让我们看看它们如何配合:</p>
<h3 id="41-分层架构">4.1 分层架构</h3>
<div class="mermaid">graph TB
subgraph AppLayer [应用层 - Agent Framework]
Workflow
Scheduling[并行/串行调度]
Workflow --> Scheduling
end
subgraph CommLayer [通信层 - A2A Protocol]
Discovery[智能体发现 AgentCard]
Messaging[标准化消息传递]
Context[上下文管理]
Discovery --> Messaging --> Context
end
subgraph ToolLayer [工具层 - MCP Protocol]
ToolExpose[工具暴露和发现]
ParamValidation[参数验证和调用]
ResourceAccess[资源访问]
ToolExpose --> ParamValidation --> ResourceAccess
end
AppLayer --> |使用| CommLayer
CommLayer --> |调用| ToolLayer
style AppLayer fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
style CommLayer fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
style ToolLayer fill:#fff3e0,stroke:#ff9800,stroke-width:2px
style Workflow fill:#3273dc,stroke:#333,color:#fff
style Scheduling fill:#3273dc,stroke:#333,color:#fff
style Discovery fill:#48c774,stroke:#333,color:#fff
style Messaging fill:#48c774,stroke:#333,color:#fff
style Context fill:#48c774,stroke:#333,color:#fff
style ToolExpose fill:#9b59b6,stroke:#333,color:#fff
style ParamValidation fill:#9b59b6,stroke:#333,color:#fff
style ResourceAccess fill:#9b59b6,stroke:#333,color:#fff
</div><h3 id="42-完整的调用链路">4.2 完整的调用链路</h3>
<p>让我们追踪一次完整的用户提问:</p>
<div class="mermaid">graph TD
User[用户:开发一个ERP系统<br/>预算300万] --> PM
PM --> Stage1{Stage 1: 并行分析}
Stage1 --> |A2A调用| Tech
Stage1 --> |A2A调用| HR
Stage1 --> |A2A调用| Finance
Stage1 --> |A2A调用| QA
Finance --> |MCP调用| ValidateBudget
Finance --> |MCP调用| GetHistoricalCosts
Tech --> |返回分析| Gather1
HR --> |返回分析| Gather1
Finance --> |返回分析| Gather1
QA --> |返回分析| Gather1
Gather1 --> Stage2
Stage2 --> |任务分解<br/>里程碑| Stage3
Stage3 --> Output[综合项目计划<br/>返回给用户]
style User fill:#3273dc,stroke:#333,color:#fff
style PM fill:#9b59b6,stroke:#333,color:#fff
style Stage1 fill:#ffe082,stroke:#333
style Stage2 fill:#ffe082,stroke:#333
style Stage3 fill:#ffe082,stroke:#333
style Tech fill:#48c774,stroke:#333,color:#fff
style HR fill:#48c774,stroke:#333,color:#fff
style Finance fill:#48c774,stroke:#333,color:#fff
style QA fill:#48c774,stroke:#333,color:#fff
style ValidateBudget fill:#e3f2fd,stroke:#2196f3
style GetHistoricalCosts fill:#e3f2fd,stroke:#2196f3
style Gather1 fill:#f0f0f0,stroke:#999
style Output fill:#3273dc,stroke:#333,color:#fff
</div><p><strong>调用链路详解</strong>:</p>
<ol>
<li><strong>用户提问</strong> → PM Agent接收并启动Agent Framework工作流</li>
<li><strong>Stage 1(并行)</strong>:PM通过A2A协议同时调用4个专家Agent</li>
<li><strong>MCP工具调用</strong>:Finance Agent调用MCP工具验证预算和查询历史数据</li>
<li><strong>结果汇总</strong>:4个Agent的分析结果收集到一起</li>
<li><strong>Stage 2(串行)</strong>:PMO Agent基于前4个结果进行项目规划</li>
<li><strong>Stage 3(整合)</strong>:PM Agent整合所有信息生成最终报告</li>
<li><strong>返回用户</strong>:完整的项目计划呈现给用户</li>
</ol>
<p><strong>关键点</strong>:</p>
<ol>
<li><strong>Workflow编排</strong>:PM Agent决定调用哪些Agent、什么时候调用</li>
<li><strong>A2A通信</strong>:所有Agent间的调用使用标准A2A协议</li>
<li><strong>MCP工具</strong>:Agent在处理请求时,可以调用自己的MCP工具获取数据</li>
</ol>
<hr>
<h2 id="五代码实践如何实现一个新的智能体">五、代码实践:如何实现一个新的智能体?</h2>
<p>理论讲完了,让我们动手实践。假设你要添加一个"Legal(法务)"智能体。</p>
<h3 id="步骤1创建aspnet-core项目">步骤1:创建ASP.NET Core项目</h3>
<pre><code class="language-powershell">dotnet new webapi -n Legal
cd Legal
dotnet add package A2A.AspNetCore
dotnet add package ModelContextProtocol.Server
dotnet add package Microsoft.Extensions.AI.OpenAI
</code></pre>
<h3 id="步骤2定义mcp工具">步骤2:定义MCP工具</h3>
<pre><code class="language-csharp">// Legal/Program.cs
using ModelContextProtocol.Server;
using ModelContextProtocol.Protocol;
public class LegalTools
{
public Task<CallToolResult> CheckCompliance(string projectType, string region)
{
// 模拟合规检查
var result = new
{
ProjectType = projectType,
Region = region,
ComplianceStatus = "Compliant",
RequiredLicenses = new[] { "Business License", "Data Processing Agreement" },
Risks = new[] { "GDPR compliance required for EU customers" }
};
return Task.FromResult(new CallToolResult
{
Content = [new TextContentBlock {
Text = System.Text.Json.JsonSerializer.Serialize(result)
}]
});
}
}
</code></pre>
<h3 id="步骤3实现a2a-agent">步骤3:实现A2A Agent</h3>
<pre><code class="language-csharp">// Legal/Program.cs
using A2A;
using A2A.AspNetCore;
using Microsoft.Extensions.AI;
public class LegalAgent
{
private readonly IChatClient _chatClient;
public LegalAgent(IChatClient chatClient)
{
_chatClient = chatClient;
}
public void Attach(ITaskManager taskManager)
{
taskManager.OnMessageReceived = ProcessMessageAsync;
taskManager.OnAgentCardQuery = GetAgentCardAsync;
}
private async Task<A2AResponse> ProcessMessageAsync(
MessageSendParams messageSendParams,
CancellationToken cancellationToken)
{
var messageText = messageSendParams.Message.Parts
.OfType<TextPart>()
.FirstOrDefault()?.Text ?? "";
var messages = new List<ChatMessage>
{
new(ChatRole.System,
"You are a legal compliance expert. Analyze legal and compliance requirements."),
new(ChatRole.User, messageText)
};
var completion = await _chatClient.GetResponseAsync(
messages,
cancellationToken: cancellationToken);
return new AgentMessage
{
Role = MessageRole.Agent,
MessageId = Guid.NewGuid().ToString(),
ContextId = messageSendParams.Message.ContextId,
Parts =
};
}
private Task<AgentCard> GetAgentCardAsync(
string agentUrl,
CancellationToken cancellationToken)
{
return Task.FromResult(new AgentCard
{
Name = "Legal Compliance Expert",
Description = "Legal expert for compliance analysis and risk assessment",
Url = agentUrl,
Version = "1.0.0",
DefaultInputModes = ["text"],
DefaultOutputModes = ["text"],
Capabilities = new AgentCapabilities
{
Streaming = false,
PushNotifications = false
},
Skills = []
});
}
}
</code></pre>
<h3 id="步骤4启动服务">步骤4:启动服务</h3>
<pre><code class="language-csharp">// Legal/Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
// 注册MCP Server
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithTools<LegalTools>();
var app = builder.Build();
app.MapDefaultEndpoints();
// 暴露MCP端点
app.MapMcp("/legal/mcp");
// 暴露A2A端点
var legalAgent = new LegalAgent(
AgentHelpers.CreateChatClient(app.Configuration)
);
var legalTaskManager = new TaskManager();
legalAgent.Attach(legalTaskManager);
app.MapA2A(legalTaskManager, "/legal/compliance-expert");
app.MapWellKnownAgentCard(legalTaskManager, "/legal/compliance-expert");
app.Run();
</code></pre>
<h3 id="步骤5在aspire中注册">步骤5:在Aspire中注册</h3>
<pre><code class="language-csharp">// AgentFrameworkAspire.AppHost/Program.cs
var legalService = builder.AddProject<Projects.Legal>("legal")
.WithEnvironment("OpenAI__ApiKey", openAiApiKey)
.WithEnvironment("OpenAI__DeploymentName", openAiDeployment);
builder.AddProject<Projects.AgentFrameworkAspire_Web>("webfrontend")
// ... 其他引用
.WithReference(legalService)
.WaitFor(legalService);
</code></pre>
<p><strong>完成!</strong> 现在你有了一个完整的Legal智能体,支持MCP工具和A2A通信。</p>
<hr>
<h2 id="六最佳实践与注意事项">六、最佳实践与注意事项</h2>
<h3 id="61-mcp工具设计">6.1 MCP工具设计</h3>
<p><strong>✅ DO</strong>:</p>
<ul>
<li>工具职责单一,每个工具只做一件事</li>
<li>参数类型明确,避免使用<code>object</code></li>
<li>返回结构化数据,便于AI理解</li>
<li>添加详细的XML注释,会自动生成工具描述</li>
</ul>
<p><strong>❌ DON'T</strong>:</p>
<ul>
<li>工具不要有副作用(如修改数据库)</li>
<li>避免长时间运行的操作(超过10秒)</li>
<li>不要返回大量数据(超过10KB)</li>
</ul>
<h3 id="62-a2a-agent实现">6.2 A2A Agent实现</h3>
<p><strong>✅ DO</strong>:</p>
<ul>
<li>AgentCard要准确描述能力</li>
<li>正确处理ContextId,支持多轮对话</li>
<li>使用结构化日志,便于调试</li>
<li>返回有意义的错误消息</li>
</ul>
<p><strong>❌ DON'T</strong>:</p>
<ul>
<li>不要在ProcessMessageAsync中做耗时操作</li>
<li>不要忽略CancellationToken</li>
<li>避免在Agent中保存状态(应该是无状态的)</li>
</ul>
<h3 id="63-workflow设计">6.3 Workflow设计</h3>
<p><strong>✅ DO</strong>:</p>
<ul>
<li>合理划分阶段,每个阶段职责清晰</li>
<li>并行任务要真正独立,没有依赖</li>
<li>使用<code>IAsyncEnumerable</code>实现流式返回</li>
<li>记录每个阶段的耗时,便于性能优化</li>
</ul>
<p><strong>❌ DON'T</strong>:</p>
<ul>
<li>避免过深的嵌套(超过5层)</li>
<li>不要在循环中调用Agent(可能导致成本爆炸)</li>
<li>避免没有超时控制的等待</li>
</ul>
<hr>
<h2 id="七性能与成本优化">七、性能与成本优化</h2>
<h3 id="71-并行加速">7.1 并行加速</h3>
<pre><code class="language-csharp">// ❌ 串行执行(慢)
var techResult = await CallA2AAgentAsync("Tech", _techAgent, input, ct);
var hrResult = await CallA2AAgentAsync("HR", _hrAgent, input, ct);
var financeResult = await CallA2AAgentAsync("Finance", _financeAgent, input, ct);
// 总时间 = T_tech + T_hr + T_finance
// ✅ 并行执行(快)
var tasks = new[]
{
CallA2AAgentAsync("Tech", _techAgent, input, ct),
CallA2AAgentAsync("HR", _hrAgent, input, ct),
CallA2AAgentAsync("Finance", _financeAgent, input, ct)
};
var results = await Task.WhenAll(tasks);
// 总时间 = max(T_tech, T_hr, T_finance)
</code></pre>
<h3 id="72-缓存agentcard">7.2 缓存AgentCard</h3>
<pre><code class="language-csharp">private static readonly ConcurrentDictionary<string, AIAgent> _agentCache = new();
private async Task<AIAgent> GetOrCreateAgentAsync(string url)
{
if (_agentCache.TryGetValue(url, out var cachedAgent))
{
return cachedAgent;
}
var agent = await InitializeAgentAsync(url);
_agentCache.TryAdd(url, agent);
return agent;
}
</code></pre>
<h3 id="73-控制ai调用成本">7.3 控制AI调用成本</h3>
<pre><code class="language-csharp">// 使用更便宜的模型进行初步分析
var cheapClient = AgentHelpers.CreateChatClient(config, "gpt-4o-mini");
// 只在关键决策时使用高级模型
var premiumClient = AgentHelpers.CreateChatClient(config, "gpt-4");
</code></pre>
<hr>
<h2 id="八常见问题faq">八、常见问题(FAQ)</h2>
<h3 id="q1-为什么不直接用httprest">Q1: 为什么不直接用HTTP/REST?</h3>
<p><strong>A</strong>: A2A和MCP是<strong>AI原生</strong>的协议,专门为智能体协作设计:</p>
<ul>
<li>AgentCard:AI可以自动理解智能体的能力</li>
<li>标准化消息格式:减少适配工作</li>
<li>上下文管理:内置支持多轮对话</li>
<li>社区生态:未来会有更多工具支持</li>
</ul>
<h3 id="q2-这些协议成熟吗会不会频繁变化">Q2: 这些协议成熟吗?会不会频繁变化?</h3>
<p><strong>A</strong>:</p>
<ul>
<li>MCP:由 Anthropic 主导,已有不少项目使用</li>
<li>A2A:由 Google Cloud 主导推出的开放标准,Microsoft 提供了 .NET SDK 实现</li>
<li>都是开放标准,社区驱动</li>
<li>建议:代码做好抽象层,协议变化时影响面小</li>
</ul>
<h3 id="q3-性能够吗http调用会不会太慢">Q3: 性能够吗?HTTP调用会不会太慢?</h3>
<p><strong>A</strong>:</p>
<ul>
<li>并行执行可以大幅减少总时间(3-4倍加速)</li>
<li>对于AI应用,瓶颈通常是LLM响应(5-15秒),而非网络(100-300ms)</li>
<li>可以使用gRPC替代HTTP(更快,但生态较小)</li>
</ul>
<h3 id="q4-如何调试分布式的agent系统">Q4: 如何调试分布式的Agent系统?</h3>
<p><strong>A</strong>:</p>
<ul>
<li>使用Aspire Dashboard查看所有服务日志</li>
<li>分布式追踪(OpenTelemetry)追踪请求链路</li>
<li>结构化日志记录每个Agent的输入输出</li>
<li>单独启动服务进行单元测试</li>
</ul>
<hr>
<h2 id="九结语">九、结语</h2>
<p>三大协议——MCP、A2A、Agent Framework——共同构建了一个强大的多智能体协作生态:</p>
<ul>
<li><strong>MCP</strong>:让每个团队暴露专业工具,AI可以自动发现和调用</li>
<li><strong>A2A</strong>:让智能体之间"说同一种语言",标准化通信</li>
<li><strong>Agent Framework</strong>:编排复杂工作流,实现真正的智能协作</li>
</ul>
<p><strong>关键优势</strong>:</p>
<ol>
<li><strong>互操作性</strong>:基于开放标准,不同团队开发的Agent可以无缝协作</li>
<li><strong>灵活性</strong>:可以单独使用MCP/A2A,也可以组合使用</li>
<li><strong>可扩展性</strong>:添加新Agent只需几行代码</li>
<li><strong>面向未来</strong>:这些协议会成为企业AI的基础设施</li>
</ol>
<p><strong>下一步</strong>:</p>
<ul>
<li>克隆项目,运行Demo</li>
<li>尝试添加你自己的智能体</li>
<li>探索更复杂的工作流场景</li>
</ul>
<p>在下一篇文章中,我们将深入 <strong>.NET Aspire</strong>,看看如何用它简化多智能体系统的开发和调试。</p>
<hr>
<h2 id="参考资料">参考资料</h2>
<ul>
<li>MCP规范:https://modelcontextprotocol.io/</li>
<li>MCP C# SDK:https://github.com/microsoft/mcp-dotnet</li>
<li>A2A协议(Google Cloud):https://cloud.google.com/agentspace/docs/agent-to-agent</li>
<li>A2A .NET SDK(社区实现):https://github.com/microsoft/a2a-dotnet</li>
<li>Agent Framework:https://github.com/microsoft/agents</li>
<li>本项目地址:https://github.com/MadLongTom/A2AMicroserviceSample</li>
</ul>
</div>
<div id="MySignature" role="contentinfo">
<p>本文来自博客园,作者:MadLongTom,转载请注明原文链接:https://www.cnblogs.com/madtom/p/19140161</p><br><br>
来源:https://www.cnblogs.com/madtom/p/19140161
頁:
[1]