멀티에이전트 오케스트레이션을 사용하면 하나의 에이전트가 다른 에이전트들과 조율하여 복잡한 작업을 완료할 수 있습니다. 에이전트는 각자 격리된 컨텍스트를 가지고 병렬로 작동할 수 있으며, 이는 출력 품질을 개선하는 데 도움이 되고 완료 시간도 단축할 수 있습니다.
멀티에이전트 구성이 여러분의 문제에 적합한지 확신이 서지 않으신가요? 멀티에이전트 시스템을 사용해야 할 때(그리고 사용하지 말아야 할 때)를 참조하세요.
Managed Agents API 요청에는 managed-agents-2026-04-01 베타 헤더가 필요하지만, 메모리 스토어 엔드포인트는 예외로 agent-memory-2026-07-22를 대신 사용합니다. SDK는 올바른 베타 헤더를 자동으로 설정합니다. 베타 헤더를 참조하세요.
모든 에이전트는 동일한 샌드박스, 파일시스템, 볼트 자격 증명을 공유하지만, 각 에이전트는 자체 대화 기록을 가진 컨텍스트 격리 이벤트 스트림인 세션 스레드에서 실행됩니다. 코디네이터는 기본 스레드(세션 수준 이벤트 스트림과 동일)에서 활동을 보고하며, 코디네이터가 작업을 위임할 때 런타임에 추가 스레드가 생성됩니다.
스레드는 영속적입니다. 코디네이터는 이전에 호출했던 에이전트에게 후속 메시지를 보낼 수 있으며, 해당 에이전트는 이전 턴의 모든 내용을 유지합니다.
각 에이전트는 모델, 시스템 프롬프트, 도구, MCP 서버, 스킬 등 자체 구성을 사용합니다. 세션 수준 에이전트 구성 재정의는 예외로, 코디네이터와 그 self 복사본에 적용됩니다. 도구, MCP 서버, 컨텍스트는 공유되지 않습니다.
멀티에이전트 조율은 다양한 영역에 걸친 작업이 필요하거나, 범위가 명확한 여러 작업이 전체 목표에 기여하는 복잡한 작업에 가장 적합합니다.
잘 작동하는 패턴:
에이전트를 정의할 때 multiagent를 설정하여 코디네이터가 위임할 수 있는 에이전트 목록을 선언합니다:
ant beta:agents create <<YAML
name: Engineering Lead
model: claude-opus-4-8
system: You coordinate engineering work. Delegate code review to the reviewer agent and test writing to the test agent.
tools:
- type: agent_toolset_20260401
multiagent:
type: coordinator
agents:
- type: agent
id: $REVIEWER_AGENT_ID
- type: agent
id: $TEST_WRITER_AGENT_ID
YAMLmultiagent.agents는 다음 중 어느 것이든 받을 수 있습니다:
{"type": "agent", "id": agent.id}는 이전에 생성된 agent를 ID로 참조합니다. version이 지정되지 않으면, 코디네이터가 생성되는 시점의 해당 에이전트 최신 버전에 참조가 고정됩니다.{"type": "agent", "id": agent.id, "version": agent.version}은 특정 에이전트 버전을 고정합니다.{"type": "self"}는 코디네이터가 자기 자신의 복사본을 생성할 수 있게 합니다. 세션이 에이전트 구성 재정의와 함께 생성된 경우, 해당 재정의는 이러한 복사본에도 적용됩니다. ID로 참조된 목록 항목은 영향을 받지 않습니다.코디네이터의 구성은 multiagent.agents 목록을 포함하여 코디네이터가 생성되거나 업데이트될 때 스냅샷으로 저장됩니다. 참조된 에이전트는 그 시점에 확인된 버전에 고정된 상태로 유지되며, 이후 정의가 업데이트되어도 자동으로 반영되지 않습니다. 참조된 에이전트의 최신 버전에 위임하려면, 목록이 해당 버전을 참조하도록 코디네이터를 업데이트하세요.
코디네이터는 한 단계의 에이전트에만 위임할 수 있습니다. 자체 multiagent.agents 목록을 가진 에이전트를 참조하면 생성 또는 업데이트 요청이 유효성 검사 오류로 실패합니다. multiagent.agents에는 최대 20개의 고유한 에이전트를 나열할 수 있지만, 코디네이터는 각 에이전트의 여러 복사본을 호출할 수 있습니다.
코디네이터를 참조하는 세션을 생성합니다. 코디네이터는 필요에 따라 목록에 있는 에이전트에게 위임합니다.
session = client.beta.sessions.create(
agent=coordinator.id,
environment_id=environment.id,
)MCP 서버는 에이전트 범위(각 에이전트 정의가 자체 서버와 도구를 선언)인 반면, 볼트 자격 증명은 세션 범위(세션 생성 시 전달된 vault_ids가 모든 스레드에 적용)입니다. 통합 시 고려해야 할 두 가지 사항:
세션 생성 시 에이전트 구성 재정의를 통해 코디네이터와 그 self 복사본의 MCP 서버를 교체할 수 있습니다.
research_agent = client.beta.agents.create(
name="researcher",
model="claude-haiku-4-5",
mcp_servers=[
{"type": "url", "name": "github", "url": "https://api.githubcopilot.com/mcp/"},
],
tools=[{"type": "mcp_toolset", "mcp_server_name": "github"}],
)
coordinator = client.beta.agents.create(
name="coordinator",
model="claude-opus-4-8",
tools=[{"type": "agent_toolset_20260401"}],
multiagent={
"type": "coordinator",
"agents": [{"type": "agent", "id": research_agent.id}],
},
)
session = client.beta.sessions.create(
agent=coordinator.id,
environment_id=environment.id,
vault_ids=[vault.id],
)
print(session.id)이 예시에서는 리서처만 GitHub MCP 서버를 선언하므로 코디네이터는 접근 권한이 없습니다. 세션의 vault_ids가 리서처의 스레드에 GitHub 자격 증명을 제공합니다.
서버를 선언한 후에도 에이전트의 MCP 호출 인증이 실패한다면, 자격 증명의 mcp_server_url이 에이전트의 mcp_servers[].url과 동일한 서버를 가리키는지 확인하세요. 두 URL은 매칭 전에 정규화되므로(스킴과 호스트 소문자화, 기본 포트 및 후행 슬래시 제거), 호스트 대소문자, 기본 포트, 후행 슬래시의 차이는 매칭을 방해하지 않습니다. 그러나 경로, 서브도메인, 비기본 포트가 다르면 매칭되지 않습니다.
세션 수준 이벤트 스트림(/v1/sessions/{session_id}/events/stream)은 기본 스레드로 간주되며, 모든 스레드에 걸친 모든 활동의 요약된 뷰를 포함합니다. 서브에이전트의 전체 활동은 볼 수 없지만, 작업의 시작과 끝, 그리고 도구 권한 요청과 같은 차단 이벤트는 볼 수 있습니다.
세션 스레드는 특정 에이전트의 활동을 자세히 살펴보는 곳입니다.
세션 status는 모든 에이전트 활동의 집계입니다. 하나 이상의 스레드가 running이면 전체 세션 상태도 running입니다.
최대 25개의 동시 스레드가 지원됩니다. 코디네이터는 목록에 있는 단일 에이전트의 여러 복사본을 호출할 수 있으며, 이 경우 하나의 agent에 연결된 여러 스레드가 생성됩니다.
다음과 같이 세션에 연결된 모든 스레드를 나열합니다:
for thread in client.beta.sessions.threads.list(session.id):
print(f"[{thread.agent.name}] {thread.status}")전체 목록에는 기본 스레드가 포함됩니다. 기본 스레드의 parent_thread_id는 null입니다.
이러한 이벤트는 /v1/sessions/{session_id}/events/stream의 기본 스레드에서 멀티에이전트 활동을 표시합니다. 메시지 방향 이벤트는 해당 이벤트가 나타나는 스트림의 스레드를 기준으로 명명됩니다. agent.thread_message_received는 다른 스레드에서 이 스레드로 메시지가 도착했음을 의미하고, agent.thread_message_sent는 이 스레드가 메시지를 보냈음을 의미합니다. 예를 들어, 코디네이터가 위임한 작업은 자식 스레드 자체의 스트림에 agent.thread_message_received 이벤트로 도착합니다.
| 유형 | 설명 |
|---|---|
session.thread_created | 스레드가 생성되었습니다. session_thread_id와 agent_name을 포함합니다. |
session.thread_status_running | 스레드가 활동을 시작했습니다. |
session.thread_status_idle | 스레드에 연결된 에이전트가 입력을 기다리고 있습니다. 에이전트가 중지된 이유를 나타내는 stop_reason을 포함합니다. |
session.thread_status_terminated | 스레드가 보관되었거나 치명적인 오류가 발생했습니다. |
agent.thread_message_received | 기본 스레드에서, 에이전트가 코디네이터에게 보고 또는 질문을 보냈습니다. from_session_thread_id, from_agent_name, content를 포함합니다. |
agent.thread_message_sent | 기본 스레드에서, 코디네이터가 다른 에이전트에게 작업 또는 후속 메시지를 보냈습니다. to_session_thread_id, to_agent_name, content를 포함합니다. |
중요한 이벤트는 기본 스레드로 프록시됩니다. 그러나 특정 에이전트의 추론과 도구 호출을 조사하고 싶을 수 있습니다. 이를 위해 연결된 세션 스레드의 이벤트를 스트리밍하거나 나열하세요.
각 세션 스레드는 /v1/sessions/{session_id}/threads/{thread_id}/stream에 자체 이벤트 스트림을 가지며, 세션 수준 스트림과 동일한 event_deltas[] 매개변수를 받으므로 모델이 생성하는 동안 서브에이전트의 텍스트를 미리 볼 수 있습니다. 연결은 읽고 있는 스레드만 미리 보여줍니다. 자식 스레드의 미리보기는 세션 수준 스트림에 절대 나타나지 않으므로, 서브에이전트를 실시간으로 보려면 해당 스레드의 자체 스트림을 여세요. 미리보기 활성화, 누적, 조정에 대해서는 세션 스레드 이벤트 미리보기를 참조하세요.
with client.beta.sessions.threads.events.stream(
thread.id,
session_id=session.id,
) as stream:
for event in stream:
match event.type:
case "agent.message":
for block in event.content:
if block.type == "text":
print(block.text, end="")
case "session.thread_status_idle":
break서브에이전트가 always_ask 도구 실행 권한이나 커스텀 도구의 결과와 같이 클라이언트로부터 무언가를 필요로 하는 경우, 해당 이벤트는 발생한 세션 스레드를 식별하는 session_thread_id와 함께 기본 스레드에 교차 게시됩니다.
{
"type": "session.thread_status_idle",
"id": "sevt_01ABC...",
"session_thread_id": "sth_01DEF...",
"agent_name": "code-reviewer",
"stop_reason": {
"type": "requires_action",
"event_ids": ["toolu_01XYZ..."]
}
}user.tool_confirmation(tool_use_id 포함) 또는 user.custom_tool_result(custom_tool_use_id 포함)를 게시하면, 서버가 응답을 올바른 스레드로 자동 라우팅합니다.
다음 예시는 도구 확인 핸들러를 확장하여 응답을 라우팅합니다. 동일한 패턴이 user.custom_tool_result에도 적용됩니다.
for event_id in stop.event_ids:
client.beta.sessions.events.send(
session.id,
events=[
{
"type": "user.tool_confirmation",
"tool_use_id": event_id,
"result": "allow",
}
],
)Was this page helpful?