본문으로 건너뛰기

© 2026 Molayo

Zenn헤드라인2026. 06. 08. 12:45

Microsoft Agent Framework의 A2A 프리뷰로 시도하는 멀티 에이전트

요약

Microsoft Agent Framework의 A2A 프리뷰 기능을 활용하여 부모 에이전트와 여러 자식 에이전트가 협업하는 멀티 에이전트 시스템을 구현합니다. Agents as Tools 방식을 통해 각 에이전트가 관광, 소지품, 교통, 예산 등 특정 역할에 특화된 도구를 수행하도록 구성합니다.

핵심 포인트

  • A2A 프리뷰를 통한 부모-자식 에이전트 간 역할 분담 구현
  • Agents as Tools 방식을 활용한 멀티 에이전트 워크플로우 설계
  • 각 자식 에이전트가 전용 시스템 프롬프트와 내부 도구를 보유
  • .NET 10 및 Gemma 모델 환경에서의 구현 사례 제시

서론

Microsoft Agent Framework의 A2A 기능 프리뷰 버전을 사용하여, 여러 개의 자식 에이전트(Child Agent)를 조합한 멀티 에이전트(Multi-agent) 구성을 시도해 봅니다.

  • 자식 에이전트
  • 관광 플랜 담당 A2A 에이전트
  • 소지품 정리 담당 A2A 에이전트
  • 교통 안내 담당 A2A 에이전트
  • 예산 정리 담당 A2A 에이전트

이 기사에서는 Agents as Tools를 통해 멀티 에이전트를 시도합니다.

부모 에이전트(Parent Agent)는 여행 코디네이터로서 A2A 도구를 선택합니다.

각 자식 에이전트는 역할별 시스템 프롬프트(System Prompt)와 내부 도구를 가진 FunctionInvokingChatClient를 통해 LLM에 질의합니다. 그 결과를 A2A 응답으로 반환합니다.

시나리오

시나리오는 다음 3가지입니다.

시나리오 케이스목적기대하는 도구
family_rainy_sightseeing우천 시 아이 동반 아사쿠사 관광consult_sightseeing_agent, consult_packing_agent
transport_and_budget_only도쿄역에서 아사쿠사로의 이동과 비용 정보만 필요consult_transport_agent, consult_budget_agent
full_trip_plan관광·소지품·교통·예산을 모두 정리4개의 도구 모두

기대하는 도구와 담당의 대응은 다음과 같습니다.

부모가 선택하는 A2A 도구대응하는 자식 에이전트자식이 사용하는 내부 도구이후 설명할 부분
consult_sightseeing_agent관광 플랜 담당 A2A 에이전트lookup_sightseeing_grounding관광 플랜 담당 A2A 에이전트
consult_packing_agent소지품 정리 담당 A2A 에이전트lookup_packing_grounding소지품 정리 담당 A2A 에이전트
consult_transport_agent교통 안내 담당 A2A 에이전트lookup_transport_grounding교통 안내 담당 A2A 에이전트
consult_budget_agent예산 정리 담당 A2A 에이전트lookup_budget_grounding예산 정리 담당 A2A 에이전트

전체 모습은 다음 그림과 같습니다.

부모는 A2A 배분을 담당합니다. 자식은 전문적인 답변을 반환하며, 내부 도구는 참조 정보를 공급합니다.

환경 정보

이번에 확인한 주요 환경 정보는 다음과 같습니다.

항목버전 / 값
Target Framework.NET 10
...A2A 1.0.0-preview2 / A2A.AspNetCore 1.0.0-preview2
LM Studio modelgoogle/gemma-4-26b-a4b
컨텍스트 길이 (Context Length)15000
자식 에이전트 측 최대 출력 토큰 수600

전체 시퀀스 (Sequence)

1회의 시나리오 실행에서는 부모가 도구를 선택합니다.

선택된 자식 A2A 에이전트는 내부 도구를 거치며 LLM에 질의합니다.

전문적인 답변은 자식 에이전트에게 맡기는 역할 분담을 하고 있습니다.

역할 분담

consult_sightseeing_agent

관광 플랜 담당 A2A 에이전트 (관광 플랜 담당은 우천 및 아이 동반을 전제로 한 시스템 프롬프트를 가집니다. 이동량을 억제하는 조건으로 답변합니다.)

lookup_sightseeing_grounding으로 참조 정보를 가져온 후, 반나절 관광 플랜만을 반환합니다.

이 내부 도구는 후보 지역 / 기본 플랜 / 우천 시 전환 대상 / 걷는 방식의 방침을 반환합니다.

consult_packing_agent

소지품 정리 담당 A2A 에이전트 (소지품 담당은 우천 대비와 아이용 필수품으로 책임을 좁힙니다.)

lookup_packing_grounding으로 참조 정보를 가져온 후 반환합니다.

이 내부 도구는 우천 대비를 위한 준비물 / 아이용 추가 용품 / 짐을 너무 늘리지 않기 위한 정리 방침을 반환합니다.

consult_transport_agent

)

교통 안내 담당 A2A 에이전트 (교통 담당은 이동 수단과 소요 시간의 예상치로 범위를 제한합니다.)

lookup_transport_grounding으로 경로 후보를 가져온 후, 가족 단위 여행객이라면 환승 횟수를 줄이는 관점을 우선합니다.

이 내부 도구는 경로 후보 / 소요 시간 / 가족 단위 여행객을 위한 이동 방침을 반환합니다.

consult_budget_agent

)

예산 정리 담당 A2A 에이전트 (예산 담당은 총액 지정이 있으면 lookup_budget_grounding으로 배분의 기초 자료를 만듭니다.)

그 후 예산 배분을 반환합니다. 내역으로는 교통비, 식비, 예비비를 나타냅니다.

이 내부 도구는 총액 대비 교통비 / 식비 / 간식비 / 예비비의 예상치를 반환합니다.

부모 에이전트 (Parent Agent)

부모 에이전트에게는 어느 담당에게 업무를 넘길지 판단하는 역할을 부여했습니다.

4개의 자식 에이전트 (Child Agent) 결과를 통합하여 최종 답변으로 정리합니다.

주로 사용한 메서드와 타입

메서드 / 타입역할이번 사용 사례
AddA2AAgent<T>()A2A 서버에 IAgentHandler 구현을 등록4개의 담당 에이전트를 등록
MapA2A()A2A 엔드포인트 (Endpoint)를 공개/sightseeing-agent, /packing-agent, /transport-agent, /budget-agent를 공개
MapWellKnownAgentCard()에이전트 카드 디스커버리 엔드포인트 (Agent card discovery endpoint)를 공개자식 에이전트의 .well-known/agent-card.json을 공개
A2ACardResolver.GetAgentCardAsync()A2A 에이전트의 에이전트 카드 (Agent card)를 가져옴부모 에이전트 측에서 4개의 자식 에이전트 분량의 에이전트 카드를 가져옴
AgentCard.AsAIAgent()A2A 에이전트를 AIAgent로 취급도구화(Tooling)하기 전 단계에서 사용
AIFunctionFactory.Create()임의의 처리를 도구화함A2A 자식 에이전트 호출을 도구로 변환
IChatClient.GetResponseAsync()LLM에 질의함각 자식 에이전트 내부에서 전문적인 답변을 생성
FunctionInvokingChatClient도구 요청을 자동 실행하여 다시 LLM으로 돌려줌자식 에이전트 내부의 2단계 도구 호출을 구현
ChatClientAgentOptions부모 에이전트 설정4개의 도구와 일본어 지침 (Instructions)을 설정
FunctionCallContent어떤 도구 (Tool)가 호출되었는지 확인시나리오별 실제 선택 결과 확인
FunctionResultContent도구의 결과를 읽음각 자식 에이전트가 무엇을 반환했는지 확인

로컬 A2A 에이전트 호스팅

자식 에이전트를 공개하기 위해 A2A.AspNetCore의 이지 패스 호스팅 (Easy-path hosting)을 사용하고 있습니다.

이번에는 호스트 측에서 ChildAgentLlmRuntime을 싱글톤 (Singleton)으로 등록하고, IAgentHandler에 생성자를 통해 주입합니다.

파일: A2AMultiAgentSample/LocalA2AHost.cs

AgentCard agentCard = createAgentCard(baseUrl, endpointPath);
builder.Services.AddSingleton(new ChildAgentLlmRuntime(settings));
builder.Services.AddA2AAgent<TAgent>(agentCard);
...

자식 에이전트 내부에서도 내부 도구를 호출

고정된 BuildXxx() 메서드를 사용하는 대신, 각 자식 에이전트는 시스템 프롬프트 (System Prompt)와 내부 도구 프로필을 가집니다. 공통의 ChildAgentLlmRuntime을 통해 LLM을 호출합니다.

내부 도구 (Internal Tool)의 역할은 다음과 같습니다.

내부 도구담당 자식 에이전트반환되는 참조 정보
lookup_sightseeing_grounding관광 플랜 담당후보 지역, 기본 플랜, 우천 시 전환 대상, 휴식을 포함한 진행 방식
lookup_packing_grounding소지품 정리 담당우천 대비 소지품, 어린이용 추가 물품, 짐 압축 방침
lookup_transport_grounding교통 안내 담당경로 후보, 소요 시간, 가족 단위 이동 방침
lookup_budget_grounding예산 정리 담당총액, 교통비, 식비, 간식비, 예비비 기준

파일: A2AMultiAgentSample/SubAgents.cs

internal sealed class TransportAdvisorAgent : IAgentHandler
{
private const string AgentLabel = "교통 안내 담당 A2A 에이전트";
...

ChildAgentLlmRuntime에서는 FunctionInvokingChatClient를 사용합니다.

도구 요청 (Tool Request)을 자동으로 실행하고, 그 후에 최종 답변까지 루프를 돕니다.

파일: A2AMultiAgentSample/SubAgents.cs

internal sealed class ChildAgentLlmRuntime
{
private readonly IChatClient _chatClient;
...

내부 도구는 현재 사용자의 입력을 캡처한 인자 없는 클로저 함수 (Closure Function)로 생성합니다.

이를 통해 모델이 인자 JSON을 제대로 구성하지 못하더라도 실패할 확률을 낮출 수 있습니다.

파일: A2AMultiAgentSample/SubAgents.cs

internal static class ChildToolCatalog
{
public static IReadOnlyList<AIFunction> CreateTools(ChildToolProfile profile, string request)
...

Agents as Tools 구성이므로, 부모 에이전트 입장에서는 일반적인 도구 호출 (Tool Calling) 도구로 취급됩니다.

A2A 에이전트를 도구로 변환하기

부모 에이전트는 A2A 엔드포인트를 직접 호출하는 대신, AgentCard로부터 AIAgent를 생성합니다. 그 후 이를 도구로 감쌉니다.

파일: A2AMultiAgentSample/Program.cs

A2ACardResolver cardResolver = new(new Uri(baseUrl));
AgentCard agentCard = await cardResolver.GetAgentCardAsync();
A2AClientOptions clientOptions = new()
...

그 후, AIFunctionFactory.Create()를 통해 도구로 만듭니다.

파일: A2AMultiAgentSample/Program.cs

return AIFunctionFactory.Create(InvokeAsync, options);
async Task<string> InvokeAsync(string input, CancellationToken cancellationToken)
{
...

부모 에이전트 생성

파일: A2AMultiAgentSample/Program.cs

AIAgent coordinator = chatClient.AsAIAgent(new ChatClientAgentOptions
{
Name = "여행 코디네이터",
...

도구 호출 결과 추출

AgentResponse.Messages에서 FunctionCallContentFunctionResultContent를 추출하여, 부모 에이전트가 실제로 어떤 도구를 선택했는지 확인합니다.

동시에 자식 에이전트가 무엇을 반환했는지도 확인합니다.

파일: A2AMultiAgentSample/Program.cs

List<FunctionCallContent> calls = response.Messages
.SelectMany(message => message.Contents)
.OfType<FunctionCallContent>()
...

이번에는 3가지 시나리오분의 calledTools를 수집하여, 마지막에 비교표로 나타내고 있습니다.

실제 실행 결과

google/gemma-4-26b-a4b / 컨텍스트 길이 (Context Length) 15000 / 자식 에이전트 측의 최대 출력 토큰 수 (Max Output Tokens) 600으로 실행했습니다.

실행 결과에서는 부모의 A2A 도구 선택뿐만 아니라 자식의 내부 도구 호출(Internal Tool Call)도 확인할 수 있었습니다.

시나리오부모가 선택한 A2A 도구자식이 내부에서 호출한 내부 도구
family_rainy_sightseeingconsult_sightseeing_agent, consult_packing_agentlookup_sightseeing_grounding, lookup_packing_grounding
transport_and_budget_onlyconsult_transport_agent, consult_budget_agentlookup_transport_grounding, lookup_budget_grounding
full_trip_planconsult_sightseeing_agent, consult_packing_agent, consult_transport_agent, consult_budget_agent4종류 모두

full_trip_plan의 실행 순서는 다음과 같습니다.

부모가 4개의 A2A 도구를 차례로 호출하고, 각각의 자식 에이전트가 내부 도구를 1회씩 호출했습니다.

마지막으로 부모가 4개의 결과를 통합하여 최종 답변을 반환합니다.

기동 직후의 배너를 통해서도 자식 에이전트 측이 호출되고 있음을 알 수 있습니다.

=== A2A-like Multi-Agent Sample ===
lm_studio=http://localhost:1234/v1
model=google/gemma-4-26b-a4b
...

부모에게 전달된 A2A 도구는 다음 4개입니다.

[A2A Tools]
tool=consult_sightseeing_agent agent=관광 플랜 담당 A2A 에이전트 skill=반일 관광 플랜 제안
tool=consult_packing_agent agent=소지품 정리 담당 A2A 에이전트 skill=소지품 제안
...

자식 에이전트 측에서는 다음과 같은 [Child Tool Summary]가 출력됩니다.

[Child Tool Summary] agent=관광 플랜 담당 A2A 에이전트
call[0] lookup_sightseeing_grounding
result[0] 후보 지역=아사쿠사; 기본 플랜=센소지와 나카미세 거리를 짧은 시간 내에 둘러봄; 우천 시 전환=아사쿠사 문화 관광 센터 주변 카스미다 수족관 방면의 실내 시설로 전환; 진행 방식=도보 구간을 줄이고 휴식을 1회 이상 포함
...

예를 들어 full_trip_plan에서는 부모 에이전트가 4개의 A2A 도구를 모두 호출했습니다.

[Tool Call Summary]
call[0] consult_sightseeing_agent: input=아이를 동반하여 아사쿠사 주변을 반일 동안 관광합니다. 오후에는 비 예보가 있습니다.
call[1] consult_packing_agent: input=아이를 동반한 외출이며, 오후에는 비 예보가 있습니다. 필요한 소지품을 제안해 주세요.
...

최종 답변에는 관광 플랜, 교통수단, 소지품, 예산 배분이 통합되었습니다.

예산 배분은 교통비 약 2000엔, 식비 약 3520엔, 간식비 약 1040엔, 예비비 약 1440엔이라는 내역이었습니다.

full_trip_plan의 최종 답변은 다음과 같았습니다.

full_trip_plan의 Coordinator Response

아이를 동반한 아사쿠사 반나절 관광 플랜을 제안합니다. 오후의 비 예보를 고려하여, 이동을 최소화한 쾌적한 플랜입니다.
### 관광 플랜
우천 시에도 안심할 수 있도록, 이동을 최소화한 플랜입니다.
...

부모(Parent) 측의 비교 로그는 다음과 같습니다.

[Scenario Comparison]
scenario=family_rainy_sightseeing
consult_sightseeing_agent=used
...

적어도 이번 3가지 시나리오에서는, 부모 에이전트(Parent Agent)가 4개의 후보 중에서 필요한 A2A 도구(Tool)만을 선택할 수 있었습니다.

각 자식 에이전트(Sub-agent)는 내부 도구(Internal Tool)를 통해 참조 정보를 가져온 후 LLM의 답변을 반환할 수 있었습니다.

실행 방법

LM Studio 측에서 google/gemma-4-26b-a4b를 로드한 상태에서 다음을 실행합니다.

$env:OPENAI_BASE_URL="http://localhost:1234/v1"
$env:OPENAI_API_KEY="sk-dummy"
$env:OPENAI_MODEL="google/gemma-4-26b-a4b"
...

요약

이번에는 A2A 프리뷰(Preview)를 사용하여, 4개의 자식 에이전트를 가진 멀티 에이전트(Multi-agent) 구성을 확인했습니다.

확인된 포인트는 다음과 같습니다.

  • A2A 자식 에이전트를 4개로 늘려도, 부모 에이전트의 도구로서 일관된 형태로 다룰 수 있음
  • IAgentHandler 내부에서 FunctionInvokingChatClient를 사용하면, 자식 에이전트도 역할별 시스템 프롬프트(System Prompt)와 내부 도구를 조합하여 응답할 수 있음
  • google/gemma-4-26b-a4b에서도 일본어 지시사항(Instructions)을 명시하면, 프롬프트에 따라 필요한 A2A 도구와 내부 도구를 구분하여 선택할 수 있음

A2A의 다양한 기능을 테스트해 보았으나, 본격적으로 활용하기 위해서는 에이전트 간의 그래프(Graph)나 그룹화(Grouping) 등의 멀티 에이전트 구성을 학습하고, 이를 주입할 수 있는 지점을 찾아낼 필요가 있다고 느꼈습니다.

소스

Program.cs

using System.ClientModel;
using System.Text;
using A2A;
...

LocalA2AHost.cs

using A2A;
using A2A.AspNetCore;
using Microsoft.Extensions.DependencyInjection;
...

SubAgents.cs

using System.ClientModel;
using System.Text.RegularExpressions;
using A2A;
...

Discussion

AI 자동 생성 콘텐츠

본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0