AI Agent开发(2) - 深入解析 A2A 协议与 Go 实战指南

目录

  • 介绍
    • [1. 什么是A2A?](#1. 什么是A2A?)
    • [2. 为什么需要A2A?](#2. 为什么需要A2A?)
  • 核心概念
    • [1. 核心角色](#1. 核心角色)
    • [2. 数据结构](#2. 数据结构)
  • 框架集成

介绍

  • 在人工智能飞速发展的今天,我们见证了无数强大的AI Agent(智能体)的诞生。然而,当我们需要解决复杂问题的时候,往往发现这些Agent就像一个个孤岛,被禁锢在各自的框架和生态中,无法协同工作。接下来我们主要探讨下一个旨在打破这些壁垒的开放标准,A2A(Agent2Agent)协议。

1. 什么是A2A?

  • A2A协议是一个开放标准,旨在实现AI Agent之间的无缝通信与协作。它提供了一种通用的语言,让基于不同框架,如LangChain,CrewAI Google ADK等由不同供应商开发的Agent能够互相理解并协同工作,A2A的核心愿景是让Agent回归其本质 - 作为问题解决者,独立的在其环境中行动,跨越组织和技术的边界进行联合。

2. 为什么需要A2A?

  • 在A2A出现之前,要实现Agent之间的协作面临着诸多挑战

痛点:Agent被"降级为"工具

  • 当前的普遍做法是将Agent包装成"工具(Tools)"暴露给其他Agent(类似于MCP协议中的工具)。这种做法存在显著缺陷:
  1. 效率低下:Agent本应具备协商和推理能力,将其视为无状态的工具限制了其潜能
  2. 集成噩梦:每一次集成都需要定制化的点对点解决方案,工程量巨大
  3. 创新受阻:各自为政的开发模式导致系统难以扩展,且缺乏统一的安全标准

核心概念

1. 核心角色

  • 用户(User):一切的起点,可能是人类,也可能是自动化服务,它是提出需求的一方。
  • A2A客户端(Client Agent):用户的"代理人",它代表用户发起请求,负责与远端Agent进行沟通,相当于用户的私人助理。
  • A2A服务端(Remote Agent):提供服务的"专家"。它是一个实现了A2A协议HTTP接口的AI Agent。对于客户端来说,服务端是不透明(Opaque)的黑盒,客户端只知道它能做什么(能力),但不知道它怎么做(内部逻辑、模型、记忆),这最大程度保护了隐私和知识产权。

2. 数据结构

  • A2A设计了一套标准化的数据结构,确保不同"语言的Agent能够顺畅交流"
  1. Agent Card(名片):包含身份、能力、API地址、认证方式的json文档。通信的时候会和给对端agent交换名片,对端通过它来判断该Agent是否适合当前任务,以及如何建立安全连接。skills是Agent向外界声明其具体能力的元数据结构,可以理解为Agent的技能清单或者功能模块。
  2. Task(任务):一个有状态的工作单元,拥有唯一ID和生命周期,管理复杂工作,不仅仅是一问一答,而是支持多轮对话、长时运行操作的完整流程管理。
  3. Message(消息):客户端和Agent之间的一轮对话,包含角色(用户/Agent)和内容。
  4. Part(内容块):消息和产物中的基本内容容器(如文本块、文件块、数据块)。也提供了多模态支持,让Agent可以灵活的交换文本、文件、JSON数据等多种格式内容。
  5. Artifact(产物):Agent工作产生的具体、有形的成果(如生成的文档、图片、结构化数据)。与普通消息不同,它是任务的最终交付物,可被结构化存储和检索。
  • 在A2A响应中,对于简单的任务,Agent可以直接返回Message(立即回复);如果任务复杂,Agent会创建一个Task,返回任务ID,客户端随后通过该ID追踪进度或接收流式更新。

其他概念:

  1. Context(上下文):通过contextId将多个相关的任务逻辑上分组,确保多轮交互中的记忆连贯性
  2. Transport(传输层):基于HTTP(S)协议,使用JSON-RPC 2.0作为载荷格式,确保与现有Web基础设施的完美兼容
  3. Security(安全):企业级标准。认证信息(如Token)通过HTTP Header传递,与业务消息分离,确保安全且不侵入协议本身

框架集成

  • 一般我们会需要把a2a与现有框架集成,例如go-restful框架,下面重点讲解下如何实现这个效果

首先我们选择https://github.com/trpc-group/trpc-a2a-go?tab=readme-ov-file作为a2a协议的框架,下面创建了一个a2aserver实例

go 复制代码
package agents

import (
	"fmt"

	"trpc.group/trpc-go/trpc-a2a-go/server"
	"trpc.group/trpc-go/trpc-a2a-go/taskmanager"
)

/**
 * @Author clarenceLiu
 * Data 2026/1/7 18:01
 **/

func NewA2AServer(a *MainAgent) (*server.A2AServer, error) {
	mtm, err := taskmanager.NewMemoryTaskManager(a)
	if err != nil {
		return nil, err
	}
	
	card := newAgentCard()
	
	return server.NewA2AServer(card, mtm)
}

func stringPtr(s string) *string {
	return &s
}

func boolPtr(b bool) *bool  {
	return &b
}

func newAgentCard() server.AgentCard {
	// 企业级智能客服系统
	agentCard := server.AgentCard{
		Name:        "智能客服助手-Pro",
		Description: "基于大语言模型的企业级智能客服系统,支持多轮对话、工单自动处理、客户意图识别和情感分析,7×24小时为客户提供专业服务",
		URL:         "https://api.enterprise.com/v2/agent/customer-service",
		Version:     "2.1.4",

		Provider: &server.AgentProvider{
			Organization: "腾讯云智能",
			URL:         stringPtr("https://cloud.tencent.com/product/ti-platform"),
		},

		IconURL:         stringPtr("https://cdn.enterprise.com/icons/customer-service-bot.png"),
		DocumentationURL: stringPtr("https://docs.enterprise.com/agents/customer-service"),

		Capabilities: server.AgentCapabilities{
			Streaming:              boolPtr(true),
			PushNotifications:      boolPtr(true),
			StateTransitionHistory: boolPtr(true),
			Extensions: []server.AgentExtension{
				{
					URI:         "https://schemas.enterprise.com/extensions/crm-integration",
					Required:    boolPtr(true),
					Description: stringPtr("CRM系统集成扩展"),
					Params: map[string]interface{}{
						"supported_crm": []string{"Salesforce", "HubSpot", "Zendesk"},
						"sync_interval": 300,
					},
				},
				{
					URI:         "https://schemas.enterprise.com/extensions/sentiment-analysis",
					Required:    boolPtr(false),
					Description: stringPtr("情感分析扩展"),
					Params: map[string]interface{}{
						"languages": []string{"zh-CN", "en-US", "ja-JP"},
						"accuracy":  0.92,
					},
				},
			},
		},

		Skills: []server.AgentSkill{
			{
				ID:          "ticket-classification",
				Name:        "工单智能分类",
				Description: stringPtr("自动识别客户问题类型,分类到相应的处理队列"),
				Tags:        []string{"classification", "automation"},
				Examples: []string{
					"我的订单什么时候发货?",
					"如何申请退换货?",
					"支付失败了怎么办?",
				},
				InputModes:  []string{"text", "voice"},
				OutputModes: []string{"text", "json"},
			},
			{
				ID:          "order-inquiry",
				Name:        "订单查询助手",
				Description: stringPtr("帮助客户查询订单状态、物流信息等"),
				Tags:        []string{"order", "tracking", "logistics"},
				Examples: []string{
					"查询订单TF2024123456的状态",
					"我的包裹到哪里了?",
					"什么时候能收到货?",
				},
				InputModes:  []string{"text", "voice", "image"},
				OutputModes: []string{"text", "rich-message"},
			},
			{
				ID:          "complaint-handling",
				Name:        "投诉处理专员",
				Description: stringPtr("专业处理客户投诉,提供解决方案和补偿建议"),
				Tags:        []string{"complaint", "escalation", "compensation"},
				Examples: []string{
					"我对你们的服务很不满意",
					"产品质量有问题,要求退款",
					"客服态度太差了",
				},
				InputModes:  []string{"text", "voice"},
				OutputModes: []string{"text", "escalation-form"},
			},
			{
				ID:          "technical-support",
				Name:        "技术支持专家",
				Description: stringPtr("提供产品使用指导和技术问题解答"),
				Tags:        []string{"technical", "troubleshooting", "guidance"},
				Examples: []string{
					"如何设置账户?",
					"APP闪退了怎么办?",
					"这个功能怎么用?",
				},
				InputModes:  []string{"text", "voice", "screenshot"},
				OutputModes: []string{"text", "step-by-step", "video-guide"},
			},
		},

		DefaultInputModes:  []string{"text", "voice"},
		DefaultOutputModes: []string{"text", "rich-message"},

		SecuritySchemes: map[string]server.SecurityScheme{
			"api_key": {
				Type:        server.SecuritySchemeTypeAPIKey,
				Description: stringPtr("API密钥认证"),
				Name:        stringPtr("X-API-Key"),
				In:          server.SecuritySchemeInHeader.Ptr(),
			},
			"bearer_token": {
				Type:        server.SecuritySchemeTypeHTTP,
				Description: stringPtr("JWT Bearer令牌认证"),
				Scheme:      stringPtr("bearer"),
				BearerFormat: stringPtr("JWT"),
			},
			"oauth2": {
				Type:        server.SecuritySchemeTypeOAuth2,
				Description: stringPtr("OAuth2认证"),
				Flows: &server.OAuthFlows{
					ClientCredentials: &server.OAuthFlow{
						TokenURL: "https://auth.enterprise.com/oauth/token",
						Scopes: map[string]string{
							"read":  "读取权限",
							"write": "写入权限",
							"admin": "管理权限",
						},
					},
				},
			},
		},

		Security: []map[string][]string{
			{"api_key": []string{}},
			{"bearer_token": []string{"read", "write"}},
			{"oauth2": []string{"read", "write", "admin"}},
		},

		PreferredTransport: stringPtr("http2"),
		ProtocolVersion:    stringPtr(server.ProtocolVersion),

		AdditionalInterfaces: []server.AgentInterface{
			{
				URL:       "wss://ws.enterprise.com/v2/agent/customer-service",
				Transport: "websocket",
			},
			{
				URL:       "grpc://grpc.enterprise.com:50051",
				Transport: "grpc",
			},
		},

		SupportsAuthenticatedExtendedCard: boolPtr(true),

		Signatures: []server.AgentCardSignature{
			{
				Protected: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImsyNTYifQ",
				Signature: "signature-base64-encoded",
			},
		},
	}
	
	return agentCard
}
  • 类似下面这样,使用server实例提供一个对外服务
go 复制代码
type agentResource struct {
	MainAgent *agents.MainAgent `inject:""`
	A2AServer *server.A2AServer `inject:""`
}

func (a *agentResource) A2A(req *restful.Request, resp *restful.Response) {
	a.A2AServer.Handler().ServeHTTP(resp.ResponseWriter, req.Request)
}

func (a *agentResource) A2AStream(req *restful.Request, resp *restful.Response) {
	a.A2AServer.Handler().ServeHTTP(resp.ResponseWriter, req.Request)
}
  • 流传输核心代码如下所示(基于eino框架)
go 复制代码
func (a *JoyAgent) runWithStream(ctx context.Context, input *adk.AgentInput, options ...adk.AgentRunOption) *adk.AsyncIterator[*adk.AgentEvent] {
	iterator, generator := adk.NewAsyncIteratorPair[*adk.AgentEvent]()
	go func() {
		var err error
		defer func() {
			var panicError error
			utilruntime.RecoverFromPanic(&panicError)
			if panicError != nil {
				generator.Send(&adk.AgentEvent{
					Err: panicError,
				})
			} else if err != nil {
				generator.Send(&adk.AgentEvent{
					Err: err,
				})
			}
			generator.Close()
		}()
		a2aMessage := protocol.Message{
			Role: protocol.MessageRoleUser,
		}

		ln := len(input.Messages)
		for i := ln - 1; i >= 0; i-- {
			message := input.Messages[i]
			if message.Role != schema.User {
				continue
			}
			a2aMessage.Parts = append(a2aMessage.Parts, protocol.NewTextPart(message.Content))
			break
		}
		if len(a2aMessage.Parts) == 0 {
			log.Logger.Error(fmt.Errorf("no messages provided"), "JoyAgent input has no messages",
				"input", gconv.String(input))
		}
		events, err := a.a2aStreamClient.StreamMessage(ctx, protocol.SendMessageParams{
			Message:  a2aMessage,
			Metadata: a.metadata(ctx),
		})
		if err != nil {
			log.Logger.Error(err, "[JoyAgent] failed to stream message")
			return
		}

		reader, writer := schema.Pipe[*schema.Message](5)
		defer writer.Close()
		generator.Send(&adk.AgentEvent{
			AgentName: a.Name(ctx),
			Output: &adk.AgentOutput{
				MessageOutput: &adk.MessageVariant{
					IsStreaming:   true,
					Role:          schema.Assistant,
					MessageStream: reader,
				},
			},
		})
		for event := range events {
			task, ok := event.Result.(*protocol.Task)
			if !ok {
				log.Logger.Error(fmt.Errorf("type: %T", event.Result), "JoyAgent event is not task")
				continue
			}
			for _, artifact := range task.Artifacts {
				for _, part := range artifact.Parts {
					switch v := part.(type) {
					case *protocol.TextPart:
						writer.Send(&schema.Message{
							Role:    schema.Assistant,
							Content: v.Text,
						}, nil)
					default:
						log.Logger.Error(fmt.Errorf("type: %T", part), "JoyAgent event is not TextPart")
						continue
					}
				}
			}
		}
		log.Logger.Info("[JoyAgent]", "finished", len(events))
	}()

	return iterator
}
相关推荐
综合热讯2 小时前
AUS GLOBAL 荣耀赞助 2026 LIL TOUR 高尔夫嘉年华
人工智能
业精于勤_荒于稀2 小时前
异常梳理aaaa
开发语言·qt
黎雁·泠崖2 小时前
Java面向对象:对象内存图+成员与局部变量
java·开发语言
sunfove2 小时前
实战篇:用 Python 徒手实现模拟退火算法解决 TSP 问题
开发语言·python·模拟退火算法
jiunian_cn2 小时前
【C++】IO流
开发语言·c++
小饼干超人2 小时前
详解向量数据库中的PQ算法(Product Quantization)
人工智能·算法·机器学习
砚边数影3 小时前
AI数学基础(一):线性代数核心,向量/矩阵运算的Java实现
java·数据库·人工智能·线性代数·矩阵·ai编程·金仓数据库
froginwe113 小时前
C 语言输入与输出详解
开发语言