구글 ADK와 A2A 프로토콜로 크로스-언어 멀티 에이전트 팀 구축하기
요약
구글 ADK와 오픈소스 A2A 프로토콜을 사용해서 파이썬(Python)과 Go 언어로 만들어진 에이전트들이 서로 협력하며 계약 준수 검증을 수행하는 크로스-언어 멀티 에이전트 파이프라인을 구축하는 방법을 배워볼 수 있어요.
인사이트
- A2A(Agent2Agent) 프로토콜을 통해 서로 다른 언어로 개발된 에이전트들이 유연하게 협력할 수 있어, 각 팀이 최적의 언어로 개발을 진행할 수 있어요.
- ADK의 `RemoteA2aAgent` 추상화를 활용하면 원격 A2A 호환 서비스를 몇 줄의 코드로 로컬 서브 에이전트처럼 쉽게 통합할 수 있어요.
- 모놀리식 프롬프트 대신 특화된 책임과 역할(single responsibility)을 가진 에이전트들을 활용하여 멀티 에이전트 파이프라인을 구축하면, 시스템의 확장성, 견고성, 테스트 용이성을 크게 향상시킬 수 있어요.
왜 중요한가
현실 세계의 AI 시스템은 다양한 팀, 언어, 배포 환경에서 작동해야 하는 복잡한 문제를 가지고 있어요. 이 글은 이러한 문제를 구글 ADK와 A2A 프로토콜로 어떻게 우아하게 해결하는지 보여줘요. 파이썬의 AI 생태계 강점과 Go 언어의 안정적인 런타임 성능을 결합하여, 유연하고 견고하며 테스트하기 쉬운 프로덕션급 멀티 에이전트 시스템을 구축할 수 있게 도와줍니다.
2026년 6월 22일
에릭 동, 개발자 관계 엔지니어
파이썬 에이전트와 Go 에이전트가 Agent2Agent 프로토콜을 사용해서 계약 준수 작업을 협업하는 방법
계약 준수 파이프라인에 문제가 생겼다고 해봐요. 데이터 사이언스 팀이 파이썬으로 기가 막힌 추출 에이전트를 만들었어요. 이 에이전트는 제미나이를 써서 법률 계약서를 파싱하고 모든 핵심 용어를 뽑아내죠. 한편, 보안 엔지니어링 팀은 Go 언어로 엄청나게 빠른 준수 검증 도구를 만들었는데, 이건 LLM 없이 순수하게 결정론적인 로직만 사용했어요. 둘 다 따로 쓸 때는 완벽하게 작동해요. 그런데 이제 이걸 같이 묶어서 하나의 유기적인 파이프라인처럼 작동하게 해야 하는데, 두 팀 모두 자기 서비스를 다른 언어로 다시 만들 생각은 없어요.
이게 바로 프로덕션 AI 시스템의 현실이에요. 팀도 다르고, 언어도 다르고, 배포 대상도 다르죠. 이런 문제에 직면할지 안 할지가 아니라, 어떻게 해결할지가 중요해요.
이번 포스팅에서는 파이썬 에이전트가 제미나이를 사용해서 계약 조건을 추출하고, Go 에이전트가 이를 회사 정책과 비교해서 검증하는 계약 준수 멀티 에이전트 파이프라인을 구축해 볼 거예요. 두 서비스는 Agent2Agent (A2A) 프로토콜로 연결되고, 구글의 Agent Development Kit (ADK)가 이들을 조율하죠.
이 과정에서 프로덕션 환경의 멀티 에이전트 시스템을 단일 언어 데모와 구분 짓는 세 가지 아키텍처 패턴을 배울 수 있어요.
- A2A 프로토콜을 이용한 크로스-언어 에이전트 협업: 팀이 코드를 다시 작성할 필요 없이 해당 작업에 가장 적합한 언어로 에이전트를 구축할 수 있게 해줘요.
- ADK의
RemoteA2aAgent추상화: 어떤 원격 A2A 호환 서비스든 몇 줄의 코드로 로컬 서브 에이전트처럼 사용할 수 있게 해줘요. - 멀티 에이전트 파이프라인 오케스트레이션: 모든 것을 처리하려는 모놀리식 프롬프트 대신, 각자 좁은 책임을 가진 전문 에이전트들을 활용하는 방식이에요.
전체 소스 코드는 GitHub에서 확인할 수 있어요.
에이전트 하나로는 부족할 때
대부분의 AI 프로젝트는 비슷한 방식으로 시작해요. 하나의 거대한 에이전트, 하나의 방대한 프롬프트, 그리고 모든 도구가 단일 컨텍스트 윈도우에 꽉 채워져 있죠. 데모에서는 잘 작동할 거예요. 하지만 프로덕션 환경에서는 세 가지 주요 이유 때문에 무너져 내릴 수 있어요.
- 컨텍스트 저하: 도구가 10~15개 이상으로 늘어나면, 모델이 지시를 놓치거나, 엉뚱한 도구를 호출하거나, 심지어 환각(Hallucination) 현상을 일으키기 시작해요. 도구가 추가될 때마다 모델의 어텐션이 더 넓은 영역으로 분산되거든요. 번역, 요약, 이메일 작성까지 모두 처리하는 계약 추출 에이전트는 결국 언제 어떤 도구를 호출해야 할지 헷갈리게 될 거예요.
- 영향 범위(Blast radius): 사소한 기능에서 예외가 한 번 발생하면 전체 에이전트 턴이 멈춰버릴 수 있어요. 번역 API의 속도 제한이 전체 워크플로우를 마비시켜서는 안 되죠. 하지만 모놀리식 에이전트에서는 모든 실패가 곧 전체 실패를 의미해요.
- 테스트 불가: 50개의 뒤얽힌 책임을 가진 시스템을 깔끔하게 단위 테스트하는 건 불가능해요. 프롬프트 변경 하나가 모든 하위 동작에 잠재적으로 영향을 미칠 수 있다면, 회귀(regression) 평가도 추측에 불과하게 돼요.
해결책은 10년 전 백엔드 엔지니어링을 혁신했던 방식과 같아요. 바로 모놀리식 시스템을 전문화된 마이크로서비스로 쪼개는 거죠. 각 에이전트는 하나의 작업, 집중된 프롬프트, 그리고 최소한의 도구 세트를 갖게 되는 거예요.
A2A 프로토콜: 에이전트들이 서로를 발견하고 대화하는 방법
Agent-to-Agent (A2A) 프로토콜은 어떤 언어나 프레임워크로 구축된 에이전트든 상호 운용될 수 있도록 하는 오픈 표준이에요. 에이전트 세상의 HTTP라고 생각하면 편할 거예요. 내부적으로 어떻게 구축되었는지 상관없이 두 에이전트가 통신할 수 있도록 해주는 공유 계약인 거죠.
A2A는 세 가지 근본적인 문제를 해결해 줘요.
- 발견(Discovery): 에이전트는
/well-known/agent.json경로에서 제공되는 JSON 메타데이터인 에이전트 카드(Agent Card)를 통해 자신의 기능을 외부에 알릴 수 있어요. REST API의 OpenAPI 스펙과 비슷하게, 이 카드에는 에이전트의 이름, URL, 버전, 스킬, 지원되는 입출력 형식이 선언되어 있죠. 호출하는 에이전트는 원격 에이전트가 무엇을 할 수 있는지 파악하기 위해 먼저 이 카드를 가져와요. - 통신(Communication): 모든 데이터 교환은 단일 엔드포인트를 통해 JSON-RPC 2.0으로 이루어져요. 에이전트 통신의 핵심 메서드는
message/send(저희 구현에서는 계약 데이터를 제출하고 결과를 동기적으로 받는 데 사용해요)이며, 태스크 제출 및 검색을 위한tasks/send,tasks/get과 같은 다른 프로토콜 메서드도 있어요. 데이터는 타입이 지정된 메시지 파트(Message Parts) 내에서 이동하는데, 자연어를 위한TextParts와 구조화된 JSON을 위한DataParts가 있죠. - 태스크 라이프사이클: 모든 상호작용은
submitted,working,completed,failed와 같이 잘 정의된 상태를 거치는 태스크(Task)로 감싸져 있어요. 이 상태 머신(state machine) 덕분에 에이전트들은 동기식 워크플로우(지금 이 계약을 확인해 줘)와 비동기식 워크플로우(48시간 이내에 이 문서를 검증해 줘)를 동일한 프로토콜로 처리할 수 있어요.
이 접근 방식의 장점은 두 에이전트 모두 상대방의 구현 방식에 대해 아무것도 몰라도 된다는 점이에요. 파이썬 에이전트가 Go 패키지를 임포트할 필요도 없고, Go 에이전트가 파이썬 코드를 실행할 필요도 없죠. 그저 HTTP를 통해 공유된 프로토콜로 대화할 뿐이에요.
에이전트 카드는 실제로 어떻게 생겼을까요?
여기에 Go 준수 서비스가 /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
Copied
URL은 환경 변수에서 읽어오기 때문에 동일한 코드가 로컬(localhost:8888)과 컨테이너(go-compliance-agent:8888)에서 모두 작동해요. Skills 배열은 하나의 에이전트가 여러 기능을 외부에 알릴 수 있다는 것을 의미하죠.
코드 구현 둘러보기
ADK를 파이썬에서, 그리고 표준 HTTP 서버를 Go에서 사용해서 이 크로스-언어 팀을 얼마나 쉽게 구성할 수 있는지 보여드릴게요.
공유 상태: 에이전트 간의 데이터 버스
개별 에이전트에 대해 자세히 알아보기 전에, 에이전트들이 어떻게 통신하는지 이해하는 게 중요해요. ADK의 ToolContext.state는 파이프라인의 모든 서브 에이전트가 읽고 쓸 수 있는 공유 딕셔너리를 제공해요. 함수 인자나 반환 값을 통해 데이터를 주고받기보다는, 에이전트들은 공유 세션 상태를 통해 통신하는 거죠.
저희 준수 파이프라인의 각 단계는 특정 체크포인트에 매핑돼요.
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
Copied
MANUAL_REVIEW 상태는 중요해서 좀 더 자세히 설명할게요. Go 준수 에이전트에 서버 크래시, 네트워크 타임아웃, 컨테이너 미시작 등의 이유로 접근할 수 없게 되면, 파이프라인이 그냥 실패해 버리는 게 아니에요. MANUAL_REVIEW로 전환되면서 해당 케이스는 법률 검토자에게 전달되어 사람이 직접 검토하게 되죠. 이런 페일 세이프(fail-safe) 패턴은 다운스트림 서비스가 간헐적으로 사용 불가능할 수 있는 프로덕션 시스템에서 정말 필수적이에요.
1. 전체 멀티 에이전트 파이프라인: Go 에이전트를 파이썬으로 래핑하기
ADK를 사용하면 RemoteA2aAgent를 이용해 원격 A2A 호환 에이전트를 로컬에서 정의할 수 있어요. SDK가 에이전트 카드 핸드셰이크, 파라미터 직렬화, 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
# 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
Copied
2. Go 준수 엔드포인트
Go 측에서 준수 에이전트는 A2A 프로토콜을 구현하는 표준 HTTP 서버예요. 이 서버는 발견을 위한 에이전트 카드와 message/send 요청을 받아들이는 단일 JSON-RPC 엔드포인트를 노출해요. 이 엔드포인트는 추출된 계약 필드에 대해 결정론적 정책 검사를 실행하고, 통과/실패 판정을 반환하죠. AI 프레임워크나 SDK는 필요 없어요. 그저 Go 표준 라이브러리만 있으면 돼요.
여기 간소화된 흐름이 있어요 (전체 구현 코드는 저장소에서 확인할 수 있어요).
// 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
Copied
오픈소스 앱: 계약 준수 엔진
전체 파이프라인은 배포 및 확장이 가능한 오픈소스 애플리케이션으로 제공돼요. 저장소에는 FastAPI 서비스로 제공되는 모든 기능을 갖춘 운영 대시보드가 포함되어 있어요.
- 세 개의 패널로 구성된 운영 대시보드: 왼쪽 패널에서는 운영자가 계약을 선택하거나 업로드할 수 있어요. 중앙 패널은 실시간 결과를 보여주는데, 통과된 계약에는 준수 증명서를, 실패한 계약에는 위반 보고서를 표시하죠. 오른쪽 패널은 정책 제어, 네트워크 시뮬레이션, 그리고 두 에이전트 사이를 오가는 데이터의 실시간 보기를 제공하는 개발자 콘솔이에요.
- 네트워크 오류 시뮬레이션: 토글을 사용해서 Go 에이전트를 '정상(Normal)', '지연(Delayed)', '충돌(Crashed)' 상태로 전환할 수 있어요. '충돌'로 설정하면 페일 세이프가 작동하는 것을 볼 수 있는데, 파이썬 에이전트가 중단을 감지하고 파이프라인을 중단하며, 자동으로 실패하는 대신 계약을 수동 검토를 위해 라우팅해요.
- 실시간 에이전트 핸드오프 검사기: 오른쪽 패널은 파이썬에서 Go로 전송된 정확한 요청과 그 응답을 표시해서, 구조화된 계약 데이터가 언어 경계를 실시간으로 넘나드는 것을 볼 수 있게 해줘요.
ADK 및 A2A 접근 방식의 장점
- 기술 선택의 자유: 데이터 사이언스 팀은 파이썬으로 복잡한 인지 에이전트를 작성하고, 시스템 팀은 Go, Rust 또는 C++로 고성능의 안전한 준수 검증 도구를 작성할 수 있어요.
- 간소화된 통합: 파이썬 오케스트레이터는 Go 에이전트와 마치 로컬 클래스인 것처럼 통신해요. 사용자 지정 HTTP 클라이언트를 작성하거나 수동으로 JSON-RPC 페이로드를 래핑하는 작업을 처리할 필요가 없어요.
- 복원력(Resilience): 에이전트들이 서로 분리되어 있기 때문에, 세밀한 타임아웃과 재시도 로직을 구성할 수 있어요. 만약 Go 검증 도구가 다운되면, 파이썬 에이전트는 현재 상태 체크포인트를 저장하고 수동 승인을 기다려요.
- 분리된 감사: Go 준수 검증 도구는 완전히 결정론적이에요. 감사를 위해 동일한 입력을 전달하고 LLM의 비결정론적 특성을 우회하여 동일한 정책 판정을 생성하는지 확인할 수 있어요.
결론
멀티 에이전트 오케스트레이션은 단순히 프롬프트를 연결하는 것 이상이에요. 견고하고 크로스-언어로 분산된 시스템을 구축하는 것에 가깝죠.
구글 ADK와 오픈소스 A2A 프로토콜을 사용해서 파이썬의 AI 생태계와 Go의 런타임 안정성을 연결하면, 두 가지 장점을 모두 얻을 수 있어요. 즉, 모호함이 있는 곳에서는 인지적 추론을, 정책이 있는 곳에서는 결정론적 강제력을 활용할 수 있는 거죠.
이것을 직접 실행해 볼 준비가 되셨나요?
- contract-compliance-engine을 클론해서 라이브 데모를 직접 실행해 보세요.
- ADK 문서에서 세션 관리, 멀티 에이전트 패턴, 평가 프레임워크 등을 살펴보세요.
- Agent2Agent 프로토콜 문서에서 더 자세한 내용을 확인해 보세요.
다음