爱在零柒陆玖 發表於 2025-10-14 10:34:00

多智能体微服务实战(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-&gt;&gt;PM: 需要验证预算
    PM-&gt;&gt;MCP: 初始化MCP客户端
    MCP-&gt;&gt;Finance: GET /finance/mcp (Handshake)
    Finance--&gt;&gt;MCP: Server Info + Protocol Version
   
    MCP-&gt;&gt;Finance: ListTools()
    Finance--&gt;&gt;MCP:
   
    MCP-&gt;&gt;Finance: CallTool("ValidateBudget", {&lt;br/&gt;amount: 200,&lt;br/&gt;projectType: "ERP"&lt;br/&gt;})
    Finance-&gt;&gt;Tool: ValidateBudget(200, "ERP")
    Tool-&gt;&gt;Tool: 业务逻辑处理
    Tool--&gt;&gt;Finance: {IsValid: false, Message: "预算偏低,建议至少300万"}
    Finance--&gt;&gt;MCP: CallToolResult
    MCP--&gt;&gt;PM: 工具调用结果
    PM-&gt;&gt;AI: 提供验证结果给AI
    AI--&gt;&gt;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
{
    /// &lt;summary&gt;
    /// 验证预算是否在可用范围内
    /// &lt;/summary&gt;
   
    public Task&lt;CallToolResult&gt; ValidateBudget(
      decimal amount,
      string category,
      string costCenter)
    {
      // 业务逻辑:检查预算
      var isValid = amount &gt; 0 &amp;&amp; amount &lt; 1000000;
      var availableBudget = 500000m;
      
      var result = new
      {
            IsValid = isValid &amp;&amp; amount &lt;= availableBudget,
            RequestedAmount = amount,
            AvailableBudget = availableBudget,
            Category = category,
            CostCenter = costCenter,
            Message = isValid &amp;&amp; amount &lt;= 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)
            }]
      });
    }

    /// &lt;summary&gt;
    /// 查询历史项目成本数据
    /// &lt;/summary&gt;
   
    public Task&lt;CallToolResult&gt; 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)
            }]
      });
    }

    /// &lt;summary&gt;
    /// 计算投资回报率(ROI)
    /// &lt;/summary&gt;
   
    public Task&lt;CallToolResult&gt; CalculateROI(
      decimal investment,
      string expectedReturnsJson)
    {
      var expectedReturns = System.Text.Json.JsonSerializer
            .Deserialize&lt;decimal[]&gt;(expectedReturnsJson) ?? [];
      var totalReturn = expectedReturns.Sum();
      var roi = investment &gt; 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 &gt; 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&lt;FinanceTools&gt;()         // 注册工具
    .WithResources&lt;BudgetResources&gt;();   // 注册资源(可选)

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
{
    /// &lt;summary&gt;
    /// 获取标准预算分配模板
    /// &lt;/summary&gt;
   
    public Task&lt;ReadResourceResult&gt; 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-&gt;&gt;HTTP: 创建A2ACardResolver
    HTTP-&gt;&gt;Card: GET https://localhost:7063/.well-known/agent-card.json
    Card--&gt;&gt;HTTP: AgentCard JSON&lt;br/&gt;{name, description, capabilities}
    HTTP--&gt;&gt;PM: AgentCard对象
   
    Note over PM: 解析AgentCard&lt;br/&gt;- 验证协议版本&lt;br/&gt;- 检查capabilities&lt;br/&gt;- 获取endpoint URL
   
    Note over PM,Tech: 阶段2: Agent初始化
   
    PM-&gt;&gt;HTTP: GetAIAgentAsync(AgentCard)
    HTTP-&gt;&gt;Tech: 建立连接到/tech/requirement-analyst/run
    Tech--&gt;&gt;HTTP: 连接确认
    HTTP--&gt;&gt;PM: AIAgent客户端实例
   
    Note over PM,Tech: 阶段3: 消息传递
   
    PM-&gt;&gt;HTTP: agent.InvokeAsync(messages)
    HTTP-&gt;&gt;Tech: POST /tech/requirement-analyst/run&lt;br/&gt;{messages: [{role: "user", content: "..."}]}
    Tech-&gt;&gt;Agent: 处理用户消息
    Agent-&gt;&gt;Agent: 执行业务逻辑
    Agent--&gt;&gt;Tech: 生成响应
    Tech--&gt;&gt;HTTP: AgentRunResponse&lt;br/&gt;{messages: [{role: "assistant", content: "..."}]}
    HTTP--&gt;&gt;PM: 解析响应
    PM-&gt;&gt;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&lt;AgentCard&gt; 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;
   
    /// &lt;summary&gt;
    /// 使用A2ACardResolver初始化单个agent
    /// &lt;/summary&gt;
    private async Task&lt;AIAgent&gt; 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;
    }
   
    /// &lt;summary&gt;
    /// 调用A2A Agent
    /// &lt;/summary&gt;
    private async Task&lt;AgentRunResponse&gt; CallA2AAgentAsync(
      string agentName,
      AIAgent agent,
      string userInput,
      CancellationToken ct)
    {
      _logger.LogInformation("Calling {AgentName} agent via A2A...", agentName);
      
      // 创建标准消息
      var messages = new List&lt;ChatMessage&gt;
      {
            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;
    }

    /// &lt;summary&gt;
    /// 处理收到的A2A消息
    /// &lt;/summary&gt;
    private async Task&lt;A2AResponse&gt; ProcessMessageAsync(
      MessageSendParams messageSendParams,
      CancellationToken cancellationToken)
    {
      // 提取消息文本
      var messageText = messageSendParams.Message.Parts
            .OfType&lt;TextPart&gt;()
            .FirstOrDefault()?.Text ?? "";

      // 构造提示词
      var messages = new List&lt;ChatMessage&gt;
      {
            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&lt;br/&gt;(Web)
    participant Tech as Tech Agent&lt;br/&gt;(Service)
   
    PM-&gt;&gt;Tech: 1. GET /.well-known/agent-card.json
    Tech--&gt;&gt;PM: 2. AgentCard Response&lt;br/&gt;{name, description, capabilities}
   
    PM-&gt;&gt;Tech: 3. POST /tech/requirement-analyst&lt;br/&gt;MessageSendParams
   
    Note over Tech: 处理消息&lt;br/&gt;执行业务逻辑
   
    Tech--&gt;&gt;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&lt;A2AResponse&gt; ProcessMessageAsync(
      MessageSendParams messageSendParams,
      CancellationToken cancellationToken)
    {
      // 直接调用IChatClient,返回结果
      var messages = new List&lt;ChatMessage&gt;
      {
            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([用户输入:请评估项目风险]) --&gt; RiskIdentifier
   
    subgraph Stage1 [阶段1: 风险识别]
      RiskIdentifier
      RiskIdentifier --&gt; Output1[输出:风险列表&lt;br/&gt;例如:技术风险、成本风险、进度风险]
    end
   
    Output1 --&gt; ImpactAnalyzer
   
    subgraph Stage2 [阶段2: 影响分析]
      ImpactAnalyzer
      ImpactAnalyzer --&gt; Output2[输出:优先级矩阵&lt;br/&gt;例如:技术风险 - 高概率高影响]
    end
   
    Output2 --&gt; MitigationPlanner
   
    subgraph Stage3 [阶段3: 缓解策略]
      MitigationPlanner
      MitigationPlanner --&gt; Output3[输出:应对措施&lt;br/&gt;例如:技术预研、技术顾问、原型验证]
    end
   
    Output3 --&gt; MonitoringPlanner
   
    subgraph Stage4 [阶段4: 监控计划]
      MonitoringPlanner
      MonitoringPlanner --&gt; Output4[输出:监控计划&lt;br/&gt;例如:每周风险审查、KPI跟踪]
    end
   
    Output4 --&gt; 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([用户输入:评估项目风险]) --&gt; RiskId
    RiskId --&gt; |识别的风险列表| Impact
    Impact --&gt; |优先级矩阵| Mitigation
    Mitigation --&gt; |应对措施| Monitoring
    Monitoring --&gt; 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&lt;A2AResponse&gt; ProcessMessageAsync(
    MessageSendParams messageSendParams,
    CancellationToken cancellationToken)
{
    var messageText = messageSendParams.Message.Parts
      .OfType&lt;TextPart&gt;()
      .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&lt;ExecutorEvent&gt; 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&lt;AgentRunResponse&gt;();
   
    // 使用 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 =&gt; ctx.SomeFlag)
    .AddEdge(agent1, agent3, condition: ctx =&gt; !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 --&gt; Scheduling
    end
   
    subgraph CommLayer [通信层 - A2A Protocol]
      Discovery[智能体发现 AgentCard]
      Messaging[标准化消息传递]
      Context[上下文管理]
      Discovery --&gt; Messaging --&gt; Context
    end
   
    subgraph ToolLayer [工具层 - MCP Protocol]
      ToolExpose[工具暴露和发现]
      ParamValidation[参数验证和调用]
      ResourceAccess[资源访问]
      ToolExpose --&gt; ParamValidation --&gt; ResourceAccess
    end
   
    AppLayer --&gt; |使用| CommLayer
    CommLayer --&gt; |调用| 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系统&lt;br/&gt;预算300万] --&gt; PM
   
    PM --&gt; Stage1{Stage 1: 并行分析}
   
    Stage1 --&gt; |A2A调用| Tech
    Stage1 --&gt; |A2A调用| HR
    Stage1 --&gt; |A2A调用| Finance
    Stage1 --&gt; |A2A调用| QA
   
    Finance --&gt; |MCP调用| ValidateBudget
    Finance --&gt; |MCP调用| GetHistoricalCosts
   
    Tech --&gt; |返回分析| Gather1
    HR --&gt; |返回分析| Gather1
    Finance --&gt; |返回分析| Gather1
    QA --&gt; |返回分析| Gather1
   
    Gather1 --&gt; Stage2
   
    Stage2 --&gt; |任务分解&lt;br/&gt;里程碑| Stage3
   
    Stage3 --&gt; Output[综合项目计划&lt;br/&gt;返回给用户]
   
    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&lt;CallToolResult&gt; 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&lt;A2AResponse&gt; ProcessMessageAsync(
      MessageSendParams messageSendParams,
      CancellationToken cancellationToken)
    {
      var messageText = messageSendParams.Message.Parts
            .OfType&lt;TextPart&gt;()
            .FirstOrDefault()?.Text ?? "";

      var messages = new List&lt;ChatMessage&gt;
      {
            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&lt;AgentCard&gt; 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&lt;LegalTools&gt;();

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&lt;Projects.Legal&gt;("legal")
    .WithEnvironment("OpenAI__ApiKey", openAiApiKey)
    .WithEnvironment("OpenAI__DeploymentName", openAiDeployment);

builder.AddProject&lt;Projects.AgentFrameworkAspire_Web&gt;("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&lt;string, AIAgent&gt; _agentCache = new();

private async Task&lt;AIAgent&gt; 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]
查看完整版本: 多智能体微服务实战(2/4):三大开放协议让智能体互联互通