Claude Platform Docs
Managed Agents고급 오케스트레이션

멀티에이전트 오케스트레이션

단일 세션 내에서 여러 에이전트를 조율합니다.

"Multiagent orchestration"(멀티에이전트 오케스트레이션)을 사용하면 하나의 에이전트가 다른 에이전트들과 협력하여 복잡한 작업을 완료할 수 있습니다. 에이전트들은 각자 격리된 컨텍스트를 가지고 병렬로 동작할 수 있으며, 이는 출력 품질을 향상시키는 데 도움이 되고 완료 시간도 단축할 수 있습니다.

멀티에이전트 구성이 여러분의 문제에 적합한지 확신이 서지 않으시나요? 멀티에이전트 시스템을 사용해야 할 때(그리고 사용하지 말아야 할 때)를 참조하세요.

작동 방식

모든 에이전트는 동일한 샌드박스, 파일시스템, vault 자격 증명을 공유하지만, 각 에이전트는 자체 session thread(세션 스레드), 즉 자체 대화 기록을 가진 컨텍스트 격리 이벤트 스트림에서 실행됩니다. 코디네이터는 primary thread(기본 스레드)에서 활동을 보고하며(이는 세션 수준 이벤트 스트림과 동일합니다), 코디네이터가 작업을 위임할 때 런타임에 추가 스레드가 생성됩니다.

스레드는 영속적입니다. 코디네이터는 이전에 호출했던 에이전트에게 후속 메시지를 보낼 수 있으며, 해당 에이전트는 이전 턴의 모든 내용을 유지합니다.

각 에이전트는 자체 구성(모델, 시스템 프롬프트, 도구, MCP 서버, 스킬)을 사용합니다. 세션 수준 에이전트 구성 재정의는 예외이며, 이는 코디네이터와 그 self 복사본에 적용됩니다. 도구, MCP 서버, 컨텍스트는 공유되지 않습니다.

무엇을 위임할 것인가

멀티에이전트 조율은 다양한 영역에 걸친 작업이 필요하거나, 범위가 잘 정의된 여러 작업이 전체 목표에 기여하는 복잡한 작업에 가장 적합합니다.

잘 작동하는 패턴:

  • 병렬화: 독립적인 하위 작업(여러 소스 검색, 개별 파일 분석)을 동시에 분산 실행하고 코디네이터가 결과를 종합하도록 합니다.
  • 전문화: 단일 에이전트에 모든 기능을 탑재하는 대신, 보안 에이전트나 문서화 에이전트처럼 도메인에 특화된 시스템 프롬프트와 도구를 가진 에이전트로 라우팅합니다.
  • 에스컬레이션: 복잡한 하위 작업의 일부에 대해 더 유능한 에이전트나 모델에 자문을 구합니다.

코디네이터 구성

에이전트를 정의할 때, multiagent를 설정하여 코디네이터가 위임할 수 있는 에이전트 명단(roster)을 선언합니다:

ant beta:agents create < coordinator.agent.yaml
coordinator.agent.yaml
name: Engineering Lead
model: claude-opus-5
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 # replace before running command
    - type: agent
      id: $TEST_WRITER_AGENT_ID # replace before running command

multiagent.agents는 다음 중 어느 것이든 받을 수 있습니다:

  • {"type": "agent", "id": agent.id}는 이전에 생성된 agent를 ID로 참조합니다. version이 지정되지 않으면, 참조는 코디네이터가 생성되는 시점의 해당 에이전트 최신 버전으로 고정됩니다.
  • {"type": "agent", "id": agent.id, "version": agent.version}은 특정 에이전트 버전을 고정합니다.
  • {"type": "self"}는 코디네이터가 자기 자신의 복사본을 생성할 수 있게 합니다. 세션이 에이전트 구성 재정의와 함께 생성된 경우, 해당 재정의는 이 복사본에도 적용됩니다. ID로 참조된 명단 항목은 영향을 받지 않습니다.
  • {"type": "advisor", "model": "<model id>"}는 세션의 기본 스레드에 턴 도중 자문을 구할 수 있는 어드바이저를 제공합니다. 명단당 최대 하나의 어드바이저 항목만 허용됩니다. 세션에 어드바이저 제공하기를 참조하세요.

multiagent.agents 명단을 포함한 코디네이터의 구성은 코디네이터가 생성되거나 업데이트될 때 스냅샷으로 저장됩니다. 참조된 에이전트는 그 시점에 확정된 버전으로 고정된 상태를 유지하며, 이후 정의가 업데이트되어도 자동으로 반영되지 않습니다. 참조된 에이전트의 더 새로운 버전에 위임하려면, 명단이 해당 버전을 참조하도록 코디네이터를 업데이트하세요.

코디네이터는 한 단계의 에이전트에게만 위임할 수 있습니다. 자체 multiagent.agents 명단을 가진 에이전트를 참조하면 생성 또는 업데이트 요청이 유효성 검사 오류로 실패합니다. multiagent.agents에는 최대 20개의 고유 에이전트를 나열할 수 있지만, 코디네이터는 각 에이전트의 복사본을 여러 개 호출할 수 있습니다.

에이전트가 추론 지역(에이전트 정의model.inference_geo)을 고정하는 경우, 코디네이터의 고정값과 모든 명단 구성원의 고정값은 모두 동일한 값으로 설정되거나 모두 설정되지 않아야 합니다. 일치하지 않는 명단은 에이전트가 저장될 때와 세션 생성 재정의가 고정값 중 하나라도 변경할 때 모두 400 유효성 검사 오류로 거부됩니다.

세션에 어드바이저 제공하기

multiagent.agents의 어드바이저 항목은 세션의 기본 스레드에 advisor(어드바이저)를 제공합니다. 이는 접근 방식 계획, 막힌 상황 해결, 완료 전 작업 검토와 같은 전략적 지침을 얻기 위해 턴 도중 자문을 구할 수 있는 모델입니다. 이 항목에는 정확히 두 개의 필드, typemodel이 있습니다:

cURL
curl -fsS https://api.anthropic.com/v1/agents \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: managed-agents-2026-04-01" \
  -H "content-type: application/json" \
  -d '{
    "name": "Backend engineer",
    "model": "claude-sonnet-5",
    "system": "You implement backend features end to end. Consult the advisor before major backend design decisions.",
    "multiagent": {
      "type": "coordinator",
      "agents": [
        {"type": "advisor", "model": "claude-opus-5"}
      ]
    }
  }'

명단에는 다른 명단 형식들과 함께 최대 하나의 어드바이저 항목만 포함될 수 있습니다. 이 항목은 예약된 명단 이름 anthropic.advisor를 차지합니다. 어드바이저 항목과 문자 그대로 anthropic.advisor라는 이름의 구성원을 모두 나열한 명단은 400 유효성 검사 오류로 거부됩니다. 응답에서 어드바이저 항목은 제출된 위치와 관계없이 명단의 마지막에 반환됩니다.

어드바이저 모델은 최소 역량 기준을 충족해야 하며, 에이전트 자체의 모델이 어드바이저보다 더 유능해서는 안 됩니다. 동일한 역량의 모델끼리는 짝을 이룰 수 있습니다. 유효하지 않은 조합은 에이전트가 저장될 때 400 유효성 검사 오류로 거부됩니다. 유효한 조합은 어드바이저 도구의 모델 호환성 표를 따릅니다.

어드바이저는 Messages API의 서버 도구로도 제공됩니다. Managed Agents 환경은 구성과 전달 방식에서 차이가 있습니다. 명단 항목에는 max_uses, max_tokens, caching 필드가 없으며, 조언은 advisor_tool_result 블록이 아닌 스레드 이벤트를 통해 도착합니다.

자문이 작동하는 방식

각 자문은 anthropic.advisor라는 이름의 플랫폼 생성 스레드로 실행되며, 자문이 완료되면 스스로 종료됩니다. 조언은 agent.thread_message_received 이벤트로 기본 스레드에 전달됩니다. 자문은 예약된 이름 anthropic.advisor로 식별되는 표준 스레드 이벤트를 발생시키며(스레드 수명 주기 이벤트는 이를 agent_name으로, 조언 전달은 from_agent_name으로 전달합니다), 일반적으로 다음 순서를 따릅니다:

  1. session.thread_created
  2. session.thread_status_running
  3. agent.thread_message_received (조언)
  4. session.thread_status_idle (stop_reason: end_turn)
  5. session.thread_status_terminated

자문 입력은 에이전트가 보내는 것이 아니라 플랫폼이 구성하기 때문에, 자문에 대해서는 agent.tool_use 이벤트가 발생하지 않으며 세션의 이벤트 스트림에 agent.thread_message_sent 이벤트도 나타나지 않습니다. 어드바이저 스레드 자체의 이벤트를 나열하면, 조언은 그곳에도 agent.thread_message_sent 이벤트로 나타납니다. 조언 전달(이벤트 3)이 어드바이저 스레드의 idle 및 terminated 이벤트보다 먼저 도착한다는 보장은 없으므로, 이들 이벤트를 조언이 이미 전달되었다는 신호로 취급하지 마세요.

클라이언트가 조언을 읽을 수 있는지 여부는 어드바이저 모델의 정책에 따르며, 이는 Messages API 어드바이저 도구의 결과 변형 구분을 그대로 반영합니다. 그곳에서 평문 결과를 반환하는 어드바이저 모델은 여기서도 읽을 수 있는 텍스트 콘텐츠로 조언을 전달합니다. 그곳에서 편집된(redacted) 결과를 반환하는 어드바이저 모델은 모든 클라이언트 환경에서 메시지 콘텐츠로 [{"type": "redacted"}] 플레이스홀더를 전달하며, 에이전트 자체는 여전히 서버 측에서 전체 조언을 읽습니다. 앞의 예시에서 Claude Opus 5는 편집된 결과를 반환하는 어드바이저이므로, 에이전트는 전체 조언을 읽지만 클라이언트에는 플레이스홀더가 표시됩니다. 이벤트 스트림에서 조언을 읽을 수 있기를 원한다면 대신 Claude Opus 4.8을 어드바이저로 선택하세요. 어드바이저의 사고(thinking)는 절대 노출되지 않습니다. 클라이언트는 redacted 블록을 직접 보낼 수 없으며, 이를 포함한 이벤트는 400 유효성 검사 오류로 거부됩니다.

실패하거나 중단된 자문은 결코 에이전트의 턴을 실패시키지 않습니다. 에이전트는 자문이 실패했다는 일반적인 알림 후 계속 진행합니다. 자문 중 세션 수준 user.interrupt는 조언이 전달되지 않은 채 어드바이저 스레드를 종료합니다. 어드바이저 스레드의 session_thread_id를 지정한 user.interrupt는 해당 자문만 중단합니다.

어드바이저 스레드

어드바이저는 명단 에이전트가 아닙니다. 코디네이터의 list_agents 도구에 보이지 않으며, send_to_agent로 메시지를 보낼 수 없고, 세션의 기본 스레드만 자문을 구할 수 있습니다. 명단 에이전트는 자문을 구할 수 없습니다.

어드바이저 스레드는 동시 스레드 제한에서 제외됩니다. 이들은 세션의 스레드 목록agent가 구성된 그대로의 어드바이저 형식({"type": "advisor", "model": ...})으로, parent_thread_id가 기본 스레드로 설정되어 나타납니다.

어드바이저 측의 프롬프트 캐싱은 자동으로 이루어지며, 구성할 것이 없습니다. 자문은 어드바이저 모델의 요금으로 청구되며, 해당 토큰은 어드바이저 스레드의 사용량과 세션의 사용량 합계에 나타납니다.

어드바이저 제거하기

어드바이저를 제거하려면, 어드바이저 항목을 더 이상 포함하지 않는 명단으로 에이전트를 업데이트하세요. 어드바이저가 명단의 유일한 항목이라면, "multiagent": null을 설정하여 명단을 완전히 비우세요.

세션 생성

코디네이터를 참조하는 세션을 생성합니다. 코디네이터는 필요에 따라 명단의 에이전트에게 위임합니다.

session = client.beta.sessions.create(
    agent=coordinator.id,
    environment_id=environment.id,
)

에이전트를 MCP 서버에 연결하기

MCP 서버는 에이전트 범위이고(각 에이전트 정의가 자체 서버와 도구를 선언합니다), vault 자격 증명은 세션 범위입니다(세션 생성 시 전달된 vault_ids는 모든 스레드에 적용됩니다). 통합 시 두 가지 의미가 있습니다:

  • MCP 서버를 인증하려면, 모든 에이전트에 걸쳐 사용되는 모든 MCP 서버에 대한 vault 자격 증명을 포함하세요.
  • 에이전트의 접근을 제한하려면, 에이전트 정의에 필요한 서버만 선언하세요.

세션 생성 시의 에이전트 구성 재정의는 코디네이터와 그 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-5",
    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)

이 예시에서는 researcher만 GitHub MCP 서버를 선언하므로, 코디네이터는 접근 권한이 없습니다. 세션의 vault_ids가 researcher의 스레드에 GitHub 자격 증명을 제공합니다.

스레드

세션 수준 이벤트 스트림(/v1/sessions/{session_id}/events/stream)은 기본 스레드로 간주되며, 모든 스레드에 걸친 모든 활동의 요약된 뷰를 포함합니다. 서브에이전트의 전체 활동은 볼 수 없지만, 작업의 시작과 끝, 그리고 도구 권한 요청과 같은 차단 이벤트는 볼 수 있습니다.

세션 스레드는 특정 에이전트의 활동을 자세히 살펴보는 곳입니다.

세션 status는 모든 에이전트 활동의 집계입니다. 하나 이상의 스레드가 running이면 전체 세션 상태도 running입니다.

세션 예산은 세션의 모든 스레드에 걸친 단일 공유 한도입니다. 한도에 도달하면 스레드는 독립적으로 일시 중지되며, 각 스레드의 비용은 해당 스레드에서 실제로 제공된 모델 기준으로 책정됩니다.

세션과 연결된 모든 스레드를 다음과 같이 나열합니다:

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_idagent_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를 포함합니다.

어드바이저 자문은 예약된 이름 anthropic.advisor로 동일한 스레드 이벤트를 발생시킵니다(스레드 수명 주기 이벤트에서는 agent_name으로, 조언 전달에서는 from_agent_name으로). 순서는 세션에 어드바이저 제공하기를 참조하세요.

세션 스레드 이벤트

중요한 이벤트는 기본 스레드로 프록시됩니다. 그러나 특정 에이전트의 추론과 도구 호출을 조사하고 싶을 수도 있습니다. 그렇게 하려면 연결된 세션 스레드의 이벤트를 스트리밍하거나 나열하세요.

각 세션 스레드는 /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": ["sevt_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?