使用 Google Agent Development Kit 和 A2A 构建跨语言多智能体团队
英文标题:Build Cross-Language Multi-Agent Team with Google’s Agent Development Kit and A2A
本文演示如何用 Python 提取智能体与 Go 合规验证智能体,通过 Agent2Agent (A2A) 协议和 Google Agent Development Kit (ADK) 协同完成合同合规检查。核心架构包括跨语言智能体协作、RemoteA2aAgent 抽象以及流水线编排,展示生产环境中不同技术栈智能体无缝集成的模式。文中提供完整代码与开源应用,为开发者提供了构建稳健、可审计的分布式 AI 系统的方法。
357.9 KB
241.1 KB
403.4 KB
116.0 KB
851.7 KB
64.8 KB
12.8 KB
496.8 KB
112.2 KB
中文

一个 Python 智能体和一个 Go 智能体如何通过 Agent2Agent 协议在合同合规性上协作
你的合同合规管道有个难题。数据科学团队用 Python 写了一个出色的提取智能体,它利用 Gemini 解析法律合同并拉取每一项关键条款。安全工程团队用纯确定性逻辑、不依赖任何 LLM 构建了一个超快的合规验证器。两者在各自孤立的环境中都能完美运行。但现在你需要让它们作为一个协调管道一起工作,而两个团队都不愿意用另一种语言重写自己的服务。
这便是生产环境 AI 系统的现实:不同的团队、不同的语言、不同的部署目标。关键不在于你是否会面对这个问题,而在于你将如何解决它。
在本文中,我们将构建一个合同合规多智能体管道,其中 Python 智能体使用 Gemini 提取合同条款,Go 智能体则根据公司政策进行验证。这两个服务通过 Agent2Agent (A2A) 协议连接,并由 Google 的 Agent Development Kit (ADK) 进行编排。
在此过程中,你将学到三种将生产级多智能体系统与单语言演示区分开来的架构模式:
- 使用 A2A 协议进行跨语言智能体协作,使团队能够用最适合工作的语言构建智能体,而无需重写代码。
- ADK 的 RemoteA2aAgent 抽象,它只需几行代码就能将任何远程 A2A 兼容服务变成一个本地子智能体。
- 多智能体管道编排,由职责单一的专门智能体取代试图完成所有任务的大一统提示。
完整源代码可在 GitHub 上获取。
当一个智能体不够用的时候
大多数 AI 项目都以同样的方式开始:一个大智能体、一条巨大的提示、所有工具都塞在一个上下文窗口里。这种演示还行。但在生产环境中会因三个关键原因而崩溃:
- 上下文退化: 当工具数量超过 10-15 个时,模型开始遗漏指令,调用错误的工具,或产生幻觉参数。每增加一个工具都会稀释模型在更大范围上的注意力。一个同时处理翻译、摘要和邮件起草的合同提取智能体最终会搞不清在何时调用哪个工具。
- 影响范围: 一个次要功能中未处理的异常就能让整个智能体回合崩溃。翻译 API 上的速率限制不应让你的整个工作流瘫痪。但在单体智能体中,每个故障都是全局故障。
- 无法测试: 你无法干净地对一个包含 50 个纠缠职责的系统进行单元测试。当每条提示的改动都可能影响所有下游行为时,评估回归就成了猜谜游戏。
解决办法和十年前改变后端工程的那种模式一样:将单体分解为专门化的微服务。每个智能体只负责一项工作、一条聚焦的提示和最小的工具集。
A2A 协议:智能体如何发现并相互通信
Agent-to-Agent (A2A) 协议是一个开放标准,能使任何语言或框架构建的智能体进行互操作。可以将其视为智能体世界的 HTTP:一种共享契约,让任意两个智能体无论内部如何构建都可以通信。
A2A 解决了三个根本问题:
- 发现: 智能体通过 Agent Card(在 /.well-known/agent.json 中提供的 JSON 元数据)来发布其能力。与 REST API 的 OpenAPI 规范类似,该卡片声明了智能体的名称、URL、版本、技能以及支持的输入/输出格式。调用方会首先获取卡片来了解远程智能体能做什么。
- 通信: 所有数据交换都通过 JSON-RPC 2.0 进行,路由到单一端点。智能体通信的核心方法是 message/send(在我们的实现中用于提交合同数据并同步接收结果),其他协议方法还有 tasks/send 和 tasks/get 等用于任务提交和检索。数据在带类型的 Message Part 中传输:自然语言用 TextParts,结构化 JSON 用 DataParts。
- 任务生命周期: 每个交互都被包裹在一个 Task 中,该任务会经历明确定义的状态:submitted(已提交)、working(处理中)、completed(已完成)或 failed(已失败)。这种状态机意味着智能体可以用同一套协议处理同步工作流(立即检查这份合同)和异步工作流(在 48 小时内验证这份文档)。
这种做法的美妙之处在于,任何一方都无需了解另一方的实现细节。Python 智能体不导入 Go 包。Go 智能体不运行 Python 代码。它们只是通过 HTTP 说一种共享协议。
Agent Card 实际长什么样
以下是 Go 合规服务在 /.well-known/agent.json 上暴露的 Agent Card:
// go-compliance-agent/internal/agentcard/card.go
func GetCard() AgentCard {
agentURL := os.Getenv("AGENT_URL")
if agentURL == "" {
agentURL = "http://localhost:8888"
}
return AgentCard{
Name: "Security Compliance Validator",
Description: "基于 Go 的验证引擎,根据公司合规政策规则检查供应商合同。",
Version: "1.0.0",
SupportedInterfaces: []AgentInterface{
{
URL: agentURL,
ProtocolBinding: "JSONRPC",
ProtocolVersion: "1.0",
},
},
Capabilities: Capabilities{
ExtendedAgentCard: false,
},
DefaultInputModes: []string{"application/json"},
DefaultOutputModes: []string{"application/json"},
Skills: []Skill{
{
ID: "contract_compliance_check",
Name: "合同合规检查",
Description: "根据公司政策规则验证提取的合同字段。",
Tags: []string{"合规", "合同", "验证"},
Examples: []string{
"检查此合同是否存在合规违规",
"根据政策验证供应商协议条款",
},
},
},
}
}
Go
URL 是从环境变量读取的,因此同一段代码既可以在本机(‘localhost:8888’)运行,也可以在容器(‘go-compliance-agent:8888’)中运行。Skills 数组意味着单个智能体可以发布多种能力。
代码实现详解
下面展示了如何使用 Python 中的 ADK 和 Go 中的一个标准 HTTP 服务器轻松组装这个跨语言团队。
共享状态:智能体之间的数据总线
在深入各个智能体之前,理解它们如何通信很重要。ADK 的 ToolContext.state 提供了一个共享字典,管道中所有子智能体都可以读写。与通过函数参数或返回值在智能体之间传递数据不同,智能体通过共享的会话状态进行通信。
我们合规管道中的每一步都映射到一个特定的检查点:
class ComplianceStep(str, Enum):
INGESTED = "INGESTED" # 合同已上传,等待提取
EXTRACTED = "EXTRACTED" # 字段已被 Gemini 解析
COMPLIANCE_PENDING = "COMPLIANCE_PENDING" # 已发送至 Go 智能体,等待结果
COMPLIANCE_COMPLETE = "COMPLIANCE_COMPLETE"# Go 智能体返回判定结果
MANUAL_REVIEW = "MANUAL_REVIEW" # 超时或错误,路由至人工处理
REVIEW_READY = "REVIEW_READY" # 报告已生成,发现违规项
APPROVED = "APPROVED" # 所有检查通过
Python
MANUAL_REVIEW 状态值得强调。如果 Go 合规智能体因服务器崩溃、网络超时、容器未启动等原因不可达,管道不会直接失败,而是转移到 MANUAL_REVIEW 状态,将案例分发给人类法律审核员。这种故障安全模式对于下游服务可能间歇性不可用的生产系统至关重要。
1. 完整的多智能体管道:用 Python 包装 Go 智能体
使用 ADK,你可以通过 RemoteA2aAgent 在本地定义一个远程 A2A 兼容的智能体。SDK 会自动在后台处理 Agent Card 握手、参数序列化和 JSON-RPC 网络请求。
# python-extraction-agent/app/agent.py
from google.adk.agents import Agent, SequentialAgent
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
from google.adk.models import Gemini
# 子智能体 1: 使用 LLM 推理进行接收和提取详情
extractor_agent = Agent(
name="extractor_agent",
model=Gemini(model="gemini-3.5-flash"),
instruction="你是一个法律数据提取智能体。提取合同字段:金额、承包商、日期、保险……",
tools=[read_contract_text, save_extracted_fields, classify_risk_level]
)
# 子智能体 2: 包装为本地智能体的 Go A2A 合规服务
compliance_agent = RemoteA2aAgent(
name="compliance_agent",
agent_card=GO_AGENT_CARD_URL,
description="根据公司政策验证提取的合同字段。"
)
# 子智能体 3: 生成最终的审计摘要报告
report_agent = Agent(
name="report_agent",
model=Gemini(model="gemini-3.5-flash"),
instruction="生成最终的合规报告和 Markdown 摘要。",
tools=[generate_summary_report]
)
# 协调器: 按顺序将它们串联
root_agent = SequentialAgent(
name="contract_compliance_coordinator",
description="按顺序编排合同解析、A2A 合规验证和最终报告生成。",
sub_agents=[extractor_agent, compliance_agent, report_agent],
)
Python
2. Go 合规端点
在 Go 端,合规智能体是一个实现了 A2A 协议的标准 HTTP 服务器。它暴露一个 Agent Card 用于发现,以及一个单一的 JSON-RPC 端点,接收 message/send 请求,对提取的合同字段运行确定性策略检查,并返回通过/未通过的判定。无需任何 AI 框架或 SDK——仅使用 Go 标准库。
以下是简化的流程(完整实现 在仓库中):
// 简化伪代码——完整实现见 GitHub 仓库
func HandleJSONRPC(w http.ResponseWriter, r *http.Request) {
var req JSONRPCRequest
json.NewDecoder(r.Body).Decode(&req)
// 从 A2A 消息中提取合同详情
var details compliance.ContractDetails
extractContractFromMessage(req.Params, &details)
// 运行确定性策略检查
result := compliance.CheckCompliance(details, policy)
// 以 JSON-RPC 响应的形式返回判定结果
writeJSONRPCResult(w, req.ID, result)
}
Go
开源应用:合同合规引擎
完整管道作为开源应用发布,你可以部署和扩展。仓库 包含一个由 FastAPI 服务提供的全功能操作驾驶舱。
- 三栏操作驾驶舱: 左侧面板允许操作员选择或上传合同。中间面板显示实时结果:合格合同的合规证书和未通过合同的违规报告。右侧面板是开发者控制台,包含策略控制、网络模拟以及两个智能体间数据传输的实时视图。
- 网络故障模拟: 一个开关可将 Go 智能体在 Normal(正常)、Delayed(延迟)和 Crashed(崩溃)状态之间切换。将其设为 Crashed 状态即可展示故障安全机制:Python 智能体检测到中断,暂停管道,并将合同路由到人工审核,而不是默默失败。
- 实时智能体握手查看器: 右侧面板显示从 Python 发往 Go 的确切请求以及返回的响应,这样你就可以实时看到跨越语言边界的结构化合同数据。
ADK 与 A2A 方案的优势
- 技术自由:你的数据科学团队可以用 Python 编写复杂的认知智能体,你的系统团队可以用 Go、Rust 或 C++ 编写高性能、安全的合规验证器。
- 简化集成:Python 编排器与 Go 智能体通信,就像它是一个本地类一样。你无需编写自定义 HTTP 客户端或处理手动的 JSON-RPC 负载包装。
- 弹性:因为智能体是解耦的,你可以配置细粒度的超时和重试逻辑。如果 Go 验证器宕机,Python 智能体会保存当前状态检查点并等待人工审批。
- 隔离审计:Go 合规验证器是完全确定性的。出于审计目的,你可以传入相同的输入并验证它们产生相同的策略判定,从而绕过 LLM 的非确定性。
结论
多智能体编排不仅仅是把提示连接起来;它关乎构建稳健的、跨语言的分布式系统。
利用 Google ADK 和开放的 A2A 协议,在 Python 的 AI 生态和 Go 的运行时可靠性之间架起桥梁,你就能兼得两者的长处:在存在模糊性的地方进行认知推理,在存在政策的地方进行确定性执行。
准备自己运行这个项目吗?
English / 原文

How a Python agent and a Go agent collaborate on contract compliance using the Agent2Agent protocol
Your contract compliance pipeline has a problem. The data science team wrote a brilliant extraction agent in Python. It uses Gemini to parse legal contracts and pull out every key term. The security engineering team built a blazing-fast compliance validator in Go, using all deterministic logic and no LLM. Both work perfectly in isolation. But now you need them to work together, as a single coordinated pipeline, and neither team is willing to rewrite their service in another language.
This is the reality of production AI systems: different teams, different languages, different deployment targets. The question isn't whether you'll face this; it's how you'll solve it.
In this post, we'll build a Contract Compliance Multi-Agent Pipeline where a Python agent extracts contract terms using Gemini and a Go agent validates them against corporate policy. The two services are connected by the Agent2Agent (A2A) protocol and orchestrated by Google's Agent Development Kit (ADK).
Along the way, you'll learn three architectural patterns that separate production multi-agent systems from single-language demos:
- Cross-language agent collaboration using the A2A protocol so teams can build agents in the best language for the job without rewriting code.
- ADK's RemoteA2aAgent abstraction that turns any remote A2A-compliant service into a local sub-agent with a few lines of code
- Multi-agent pipeline orchestration where specialized agents with narrow responsibilities replace monolithic prompts that try to do everything
The complete source code is available on GitHub.
When one agent isn't enough
Most AI projects start the same way: one big agent, one massive prompt, every tool crammed into a single context window. It works for demos. It falls apart in production for three key reasons:
- Context degradation: As tools multiply beyond 10-15, the model starts missing instructions, calling wrong tools, or hallucinating parameters. Each additional tool dilutes the model's attention across a wider surface area. A contract extraction agent that also handles translation, summarization, and email drafting will eventually get confused about which tool to call when.
- Blast radius : One unhandled exception in a minor feature crashes the entire agent turn. A rate limit on a translation API shouldn't bring down your entire workflow. But in a monolithic agent, every failure is a total failure.
- Untestable : You can't cleanly unit test a system with 50 entangled responsibilities. When every prompt change potentially affects every downstream behavior, evaluating regressions becomes guesswork.
The fix is the same pattern that transformed backend engineering a decade ago: decompose the monolith into specialized microservices. Each agent gets one job, a focused prompt, and a minimal toolset.
The A2A protocol: how agents discover and talk to each other
The Agent-to-Agent (A2A) protocol is an open standard that enables agents built in any language or framework to interoperate. Think of it as the HTTP of the agent world: a shared contract that lets any two agents communicate regardless of how they're built internally.
A2A solves three fundamental problems:
- Discovery: Agents advertise their capabilities through Agent Cards, JSON metadata served at /.well-known/agent.json. Similar to OpenAPI specs for REST APIs, the card declares the agent's name, URL, version, skills, and supported input/output formats. A calling agent fetches the card first to understand what the remote agent can do.
- Communication: All data exchange happens over JSON-RPC 2.0, routed through a single endpoint. The core method for agent communication is message/send (used by our implementation to submit contract data and receive results synchronously), alongside other protocol methods like tasks/send and tasks/get for task submission and retrieval. Data travels inside typed Message Parts: TextParts for natural language and DataParts for structured JSON.
- Task lifecycle: Every interaction is wrapped in a Task that transitions through well-defined states: submitted, working, completed, or failed. This state machine means agents can handle both synchronous workflows (check this contract now) and asynchronous ones (verify this document over 48 hours) with the same protocol.
The beauty of this approach is that neither agent needs to know anything about the other's implementation. The Python agent doesn't import Go packages. The Go agent doesn't run Python code. They just speak a shared protocol over HTTP.
What an Agent Card Actually looks like
Here is the Agent Card the Go compliance service exposes at ‘/.well-known/agent.json’:
// go-compliance-agent/internal/agentcard/card.go
func GetCard() AgentCard {
agentURL := os.Getenv("AGENT_URL")
if agentURL == "" {
agentURL = "http://localhost:8888"
}
return AgentCard{
Name: "Security Compliance Validator",
Description: "Go-based validation engine that checks vendor contracts against corporate compliance policy rules.",
Version: "1.0.0",
SupportedInterfaces: []AgentInterface{
{
URL: agentURL,
ProtocolBinding: "JSONRPC",
ProtocolVersion: "1.0",
},
},
Capabilities: Capabilities{
ExtendedAgentCard: false,
},
DefaultInputModes: []string{"application/json"},
DefaultOutputModes: []string{"application/json"},
Skills: []Skill{
{
ID: "contract_compliance_check",
Name: "Contract Compliance Check",
Description: "Validates extracted contract fields against corporate policy rules.",
Tags: []string{"compliance", "contract", "validation"},
Examples: []string{
"Check this contract for compliance violations",
"Validate vendor agreement terms against policy",
},
},
},
}
}
Go
The URL is read from an environment variable so the same code works locally (‘localhost:8888’) and in containers (‘go-compliance-agent:8888’). The Skills array means a single agent can advertise multiple capabilities.
Code Implementation Walkthrough
Here is how easily this cross-language team is assembled using the ADK in Python and a standard HTTP server in Go.
Shared state: the data bus between agents
Before diving into individual agents, it's important to understand how they communicate. ADK's ToolContext.state provides a shared dictionary that all sub-agents in a pipeline read and write to. Rather than passing data between agents through function arguments or return values, agents communicate through a shared session state.
Each step in our compliance pipeline maps to a specific checkpoint:
class ComplianceStep(str, Enum):
INGESTED = "INGESTED" # Contract uploaded, awaiting extraction
EXTRACTED = "EXTRACTED" # Fields parsed by Gemini
COMPLIANCE_PENDING = "COMPLIANCE_PENDING" # Sent to Go agent, awaiting result
COMPLIANCE_COMPLETE = "COMPLIANCE_COMPLETE"# Go agent returned verdict
MANUAL_REVIEW = "MANUAL_REVIEW" # Timeout or error, routed to human
REVIEW_READY = "REVIEW_READY" # Report generated, violations found
APPROVED = "APPROVED" # All checks passed
Python
The MANUAL_REVIEW state is worth highlighting. If the Go compliance agent is unreachable for reasons like server crash, network timeout, container not started - the pipeline doesn't just fail. It transitions to MANUAL_REVIEW, routing the case to a human legal reviewer. This fail-safe pattern is essential for production systems where downstream services may be intermittently unavailable.
1. Full Multi-Agent Pipeline: Wrapping the Go Agent in Python
Using the ADK, you can define a remote A2A-compliant agent locally using RemoteA2aAgent. The SDK automatically handles the Agent Card handshake, parameter serialization, and JSON-RPC network requests behind the scenes.
# python-extraction-agent/app/agent.py
from google.adk.agents import Agent, SequentialAgent
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
from google.adk.models import Gemini
# Sub-Agent 1: Ingests & extracts details using LLM reasoning
extractor_agent = Agent(
name="extractor_agent",
model=Gemini(model="gemini-3.5-flash"),
instruction="You are a Legal Data Extraction Agent. Extract contract fields: value, contractor, dates, insurance...",
tools=[read_contract_text, save_extracted_fields, classify_risk_level]
)
# Sub-Agent 2: Go A2A Compliance Service wrapped as a local agent
compliance_agent = RemoteA2aAgent(
name="compliance_agent",
agent_card=GO_AGENT_CARD_URL,
description="Validates extracted contract fields against corporate policies."
)
# Sub-Agent 3: Generates the final audit summary report
report_agent = Agent(
name="report_agent",
model=Gemini(model="gemini-3.5-flash"),
instruction="Generate the final compliance report and Markdown summary.",
tools=[generate_summary_report]
)
# Coordinator: Chains them together sequentially
root_agent = SequentialAgent(
name="contract_compliance_coordinator",
description="Orchestrates contract parsing, A2A compliance validation, and final reporting in sequence.",
sub_agents=[extractor_agent, compliance_agent, report_agent],
)
Python
2. The Go Compliance Endpoint
On the Go side, the compliance agent is a standard HTTP server that implements the A2A protocol. It exposes an Agent Card for discovery and a single JSON-RPC endpoint that accepts message/send requests, runs deterministic policy checks against the extracted contract fields, and returns a pass/fail verdict. No AI frameworks or SDKs needed — just the Go standard library.
Here's the simplified flow (the full implementation is in the repository):
// Simplified pseudo-code — see GitHub repository for full implementation
func HandleJSONRPC(w http.ResponseWriter, r *http.Request) {
var req JSONRPCRequest
json.NewDecoder(r.Body).Decode(&req)
// Extract contract details from the A2A message
var details compliance.ContractDetails
extractContractFromMessage(req.Params, &details)
// Run deterministic policy checks
result := compliance.CheckCompliance(details, policy)
// Return verdict as a JSON-RPC response
writeJSONRPCResult(w, req.ID, result)
}
Go
Open source App: Contract Compliance Engine
The complete pipeline ships as an open source application you can deploy and extend. The repository includes a full-featured operations cockpit served by the FastAPI service.
- Three-panel operations cockpit: The left panel lets operators select or upload contracts. The center panel shows live results: compliance certificates for passing contracts and violation reports for failures. The right panel is a developer console with policy controls, network simulation, and a real-time view of the data flowing between the two agents.
- Network fault simulation: A toggle lets you switch the Go agent between Normal, Delayed, and Crashed states. Setting it to Crashed shows the fail-safe in action: the Python agent detects the outage, halts the pipeline, and routes the contract for manual human review instead of silently failing.
- Live agent handoff inspector: The right panel displays the exact request sent from Python to Go and the response coming back, so you can see the structured contract data crossing the language boundary in real time.
Benefits of the ADK and A2A Approach
- Freedom of Technology : Your data science team can write complex cognitive agents in Python, and your systems team can write high-performance, secure compliance validators in Go, Rust, or C++.
- Simplified Integration : The Python orchestrator communicates with the Go agent as if it were a local class. You do not have to write custom HTTP clients or handle manual JSON-RPC payload wrapping.
- Resilience : Because the agents are decoupled, you can configure granular timeouts and retry logic. If the Go validator is down, the Python agent saves the current state checkpoint and waits for manual approval.
- Isolated Auditing : The Go compliance validator is completely deterministic. For audit purposes, you can pass the same inputs and verify they produce identical policy verdicts, bypassing LLM non-determinism.
Conclusion
Multi-agent orchestration isn't just about chaining prompts; it's about building robust, cross-language distributed systems.
By bridging Python's AI ecosystem and Go's runtime reliability using Google ADK and the open A2A protocol, you get the best of both worlds: cognitive reasoning where there is ambiguity, and deterministic enforcement where there is policy.
Ready to run this yourself?