비동기 서브에이전트

비동기 서브에이전트 (Async subagents)

슈퍼바이저가 사용자와 계속 상호작용하는 동안 동시에 실행되는 백그라운드 서브에이전트를 실행하세요.

비동기 서브에이전트는 슈퍼바이저 에이전트가 즉시 반환되는 백그라운드 작업을 실행할 수 있게 해줘, 서브에이전트가 동시에 작업하는 동안 슈퍼바이저가 사용자와 계속 상호작용할 수 있습니다. 슈퍼바이저는 언제든 진행 상황을 확인하고, 후속 지침을 보내고, 작업을 취소할 수 있습니다.

이 기능은 완료될 때까지 슈퍼바이저를 차단하는 동기적으로 실행되는 서브에이전트를 기반으로 합니다. 작업이 장기 실행이거나 병렬화 가능하거나 실행 중간 조정이 필요할 때 비동기 서브에이전트를 사용하세요.

출처: 문서

본문

비동기 서브에이전트는 [Agent Protocol](https://github.com/langchain-ai/agent-protocol)을 구현하는 모든 서버와 통신합니다. [LangSmith Deployments](/langsmith/deployment)를 사용하거나 Agent Protocol 호환 서버를 자체 호스팅할 수 있습니다. 각 서브에이전트는 슈퍼바이저와 독립적으로 실행되며, 슈퍼바이저는 SDK를 통해 이를 실행, 확인, 업데이트, 취소합니다.

비동기 서브에이전트를 사용해야 할 때 (When to use async subagents)

차원 동기 서브에이전트 비동기 서브에이전트
실행 모델 슈퍼바이저가 서브에이전트 완료까지 차단 작업 ID 즉시 반환; 슈퍼바이저 계속
동시성 병렬이지만 차단 병렬이고 비차단
작업 중 업데이트 불가능 update_async_task로 후속 지침 전송
취소 불가능 cancel_async_task로 실행 중 작업 취소
상태 유지 무상태 -- 호출 간 영구 상태 없음 상태 유지 -- 자체 스레드에서 상호작용 간 상태 유지
최적의 경우 에이전트가 계속하기 전 결과를 기다려야 하는 작업 채팅에서 대화형으로 관리되는 장기 실행 복잡 작업

비동기 서브에이전트 구성하기 (Configure async subagents)

비동기 서브에이전트를 각각 Agent Protocol 서버를 가리키는 AsyncSubAgent 스펙 목록으로 정의하세요:

import { createDeepAgent, type AsyncSubAgent } from "deepagents";

const asyncSubagents: AsyncSubAgent[] = [
  {
    name: "researcher",
    description: "Research agent for information gathering and synthesis",
    graphId: "researcher",
    // No url → ASGI transport (co-deployed in the same deployment)
  },
  {
    name: "coder",
    description: "Coding agent for code generation and review",
    graphId: "coder",
    // url: "https://coder-deployment.langsmith.dev"  // Optional: HTTP transport for remote
  },
];

const agent = createDeepAgent({
  model: "google-genai:gemini-3.6-flash",
  subagents: [...asyncSubagents],
});
import { createDeepAgent, type AsyncSubAgent } from "deepagents";

const asyncSubagents: AsyncSubAgent[] = [
  {
    name: "researcher",
    description: "Research agent for information gathering and synthesis",
    graphId: "researcher",
    // No url → ASGI transport (co-deployed in the same deployment)
  },
  {
    name: "coder",
    description: "Coding agent for code generation and review",
    graphId: "coder",
    // url: "https://coder-deployment.langsmith.dev"  // Optional: HTTP transport for remote
  },
];

const agent = createDeepAgent({
  model: "openai:gpt-5.5",
  subagents: [...asyncSubagents],
});
import { createDeepAgent, type AsyncSubAgent } from "deepagents";

const asyncSubagents: AsyncSubAgent[] = [
  {
    name: "researcher",
    description: "Research agent for information gathering and synthesis",
    graphId: "researcher",
    // No url → ASGI transport (co-deployed in the same deployment)
  },
  {
    name: "coder",
    description: "Coding agent for code generation and review",
    graphId: "coder",
    // url: "https://coder-deployment.langsmith.dev"  // Optional: HTTP transport for remote
  },
];

const agent = createDeepAgent({
  model: "anthropic:claude-sonnet-5",
  subagents: [...asyncSubagents],
});
import { createDeepAgent, type AsyncSubAgent } from "deepagents";

const asyncSubagents: AsyncSubAgent[] = [
  {
    name: "researcher",
    description: "Research agent for information gathering and synthesis",
    graphId: "researcher",
    // No url → ASGI transport (co-deployed in the same deployment)
  },
  {
    name: "coder",
    description: "Coding agent for code generation and review",
    graphId: "coder",
    // url: "https://coder-deployment.langsmith.dev"  // Optional: HTTP transport for remote
  },
];

const agent = createDeepAgent({
  model: "openrouter:z-ai/glm-5.2",
  subagents: [...asyncSubagents],
});
import { createDeepAgent, type AsyncSubAgent } from "deepagents";

const asyncSubagents: AsyncSubAgent[] = [
  {
    name: "researcher",
    description: "Research agent for information gathering and synthesis",
    graphId: "researcher",
    // No url → ASGI transport (co-deployed in the same deployment)
  },
  {
    name: "coder",
    description: "Coding agent for code generation and review",
    graphId: "coder",
    // url: "https://coder-deployment.langsmith.dev"  // Optional: HTTP transport for remote
  },
];

const agent = createDeepAgent({
  model: "fireworks:accounts/fireworks/models/glm-5p2",
  subagents: [...asyncSubagents],
});
import { createDeepAgent, type AsyncSubAgent } from "deepagents";

const asyncSubagents: AsyncSubAgent[] = [
  {
    name: "researcher",
    description: "Research agent for information gathering and synthesis",
    graphId: "researcher",
    // No url → ASGI transport (co-deployed in the same deployment)
  },
  {
    name: "coder",
    description: "Coding agent for code generation and review",
    graphId: "coder",
    // url: "https://coder-deployment.langsmith.dev"  // Optional: HTTP transport for remote
  },
];

const agent = createDeepAgent({
  model: "baseten:zai-org/GLM-5.2",
  subagents: [...asyncSubagents],
});
import { createDeepAgent, type AsyncSubAgent } from "deepagents";

const asyncSubagents: AsyncSubAgent[] = [
  {
    name: "researcher",
    description: "Research agent for information gathering and synthesis",
    graphId: "researcher",
    // No url → ASGI transport (co-deployed in the same deployment)
  },
  {
    name: "coder",
    description: "Coding agent for code generation and review",
    graphId: "coder",
    // url: "https://coder-deployment.langsmith.dev"  // Optional: HTTP transport for remote
  },
];

const agent = createDeepAgent({
  model: "ollama:north-mini-code-1.0",
  subagents: [...asyncSubagents],
});
필드 유형 설명
name string 필수. 고유 식별자. 슈퍼바이저가 작업 실행 시 사용.
description string 필수. 이 서브에이전트가 하는 일. 슈퍼바이저가 어떤 에이전트에 위임할지 결정하는 데 사용.
graphId string 필수. Agent Protocol 서버의 그래프 ID (또는 어시스턴트 ID). LangGraph 기반 배포의 경우 langgraph.json에 등록된 그래프와 일치해야 함.
url string 선택. 생략하면 ASGI 전송(프로세스 내) 사용. 설정하면 원격 Agent Protocol 서버로 HTTP 전송 사용.
headers Record<string, string> 선택. 원격 서버로의 요청에 대한 추가 헤더. 자체 호스팅 Agent Protocol 서버의 커스텀 인증에 사용.

LangGraph 기반 배포의 경우, 공동 배포 설정을 위해 모든 그래프를 같은 langgraph.json에 등록하세요:

{
  "graphs": {
    "supervisor": "./src/supervisor.py:graph",
    "researcher": "./src/researcher.py:graph",
    "coder": "./src/coder.py:graph"
  }
}

비동기 서브에이전트 도구 사용하기 (Use the async subagent tools)

비동기 서브에이전트가 구성될 때 Deep Agents 스택에 포함되는 AsyncSubAgentMiddleware는 슈퍼바이저에게 다섯 가지 도구를 제공합니다:

도구 목적 반환
start_async_task 새 백그라운드 작업 시작 작업 ID (즉시)
check_async_task 작업의 현재 상태와 결과 가져오기 상태 + 결과 (완료된 경우)
update_async_task 실행 중인 작업에 새 지침 보내기 확인 + 업데이트된 상태
cancel_async_task 실행 중인 작업 중지 확인
list_async_tasks 실시간 상태를 가진 모든 추적 작업 나열 모든 작업 요약

슈퍼바이저의 LLM은 다른 도구처럼 이 도구들을 호출합니다. 미들웨어가 스레드 생성, 실행 관리, 상태 영속성을 자동으로 처리합니다.

수명주기 이해하기 (Understand the lifecycle)

일반적인 상호작용은 다음 순서를 따릅니다:

  • Launch(실행) 은 서버에 새 스레드를 만들고 작업 설명을 입력으로 실행을 시작하며 스레드 ID를 작업 ID로 반환합니다. 슈퍼바이저는 이 ID를 사용자에게 보고하고 완료를 폴링하지 않습니다.
  • Check(확인) 은 현재 실행 상태를 가져옵니다. 실행이 성공하면 스레드 상태를 검색해 서브에이전트의 최종 출력을 추출합니다. 여전히 실행 중이면 그 사실을 사용자에게 보고합니다.
  • Update(업데이트) 은 interrupt 멀티태스크 전략으로 같은 스레드에 새 실행을 만듭니다. 이전 실행이 인터럽트되고, 서브에이전트가 전체 대화 기록에 새 지침을 더해 다시 시작합니다. 작업 ID는 유지됩니다.
  • Cancel(취소) 은 서버에서 runs.cancel()을 호출하고 작업을 "cancelled"로 표시합니다.
  • List(나열) 은 추적된 모든 작업을 순회합니다. 종료되지 않은 작업은 서버에서 실시간 상태를 병렬로 가져옵니다. 종료 상태(success, error, cancelled)는 캐시에서 반환됩니다.

상태 관리 이해하기 (Understand state management)

작업 메타데이터는 메시지 기록과 분리된 슈퍼바이저 그래프의 전용 상태 채널(asyncTasks)에 저장됩니다. 딥 에이전트는 컨텍스트 윈도우가 가득 차면 메시지 기록을 압축(compact)하므로 이는 중요합니다. 작업 ID가 도구 메시지에만 있었다면 압축 중에 유실됩니다. 전용 채널 덕분에 슈퍼바이저는 여러 번의 요약 후에도 list_async_tasks를 통해 항상 자신의 작업을 회상할 수 있습니다.

각 추적 작업은 작업 ID, 에이전트 이름, 스레드 ID, 실행 ID, 상태, 타임스탬프(createdAt, checkedAt, updatedAt)를 기록합니다.

전송 선택하기 (Choose a transport)

ASGI 전송 (공동 배포)

서브에이전트 스펙이 url 필드를 생략하면 LangGraph SDK는 ASGI 전송을 사용합니다 — SDK 호출이 HTTP가 아닌 프로세스 내 함수 호출로 라우팅됩니다. LangGraph 기반 배포의 경우 두 그래프가 모두 같은 langgraph.json에 등록되어야 합니다.

ASGI 전송은 네트워크 지연을 제거하고 추가 인증 구성이 필요 없습니다. 서브에이전트는 여전히 자체 상태를 가진 별도 스레드로 실행됩니다. 이것이 권장 기본값입니다.

HTTP 전송 (원격)

url 필드를 추가해 HTTP 전송으로 전환하면 SDK 호출이 네트워크를 통해 원격 Agent Protocol 서버로 이동합니다:

{
  name: "researcher",
  description: "Research agent",
  graphId: "researcher",
  url: "https://my-research-deployment.langsmith.dev",
}

LangGraph 배포의 경우 인증은 LangGraph SDK가 환경 변수의 LANGSMITH_API_KEY(또는 LANGGRAPH_API_KEY)로 처리합니다. 자체 호스팅 Agent Protocol 서버는 다른 인증 메커니즘을 사용할 수 있습니다.

서브에이전트가 독립적인 스케일링, 다른 리소스 프로필, 또는 다른 팀이 유지 관리할 때 HTTP 전송을 사용하세요.

배포 토폴로지 선택하기 (Choose a deployment topology)

단일 배포

단일 배포는 모든 에이전트가 ASGI 전송으로 같은 서버에 공동 배포된다는 뜻입니다. LangGraph 기반 배포의 경우 모든 그래프를 하나의 langgraph.json에 등록하세요. 이것이 권장 시작점입니다 — 관리할 서버 하나, 에이전트 간 네트워크 지연 제로.

분리 배포

슈퍼바이저는 한 서버에, 서브에이전트는 HTTP 전송으로 다른 서버에. 서브에이전트가 다른 컴퓨트 프로필이나 독립적인 스케일링이 필요할 때 사용하세요.

하이브리드

하이브리드 배포에서는 일부 서브에이전트는 ASGI로 공동 배포되고, 다른 일부는 HTTP로 원격입니다:

import type { AsyncSubAgent } from "deepagents";

const asyncSubagents: AsyncSubAgent[] = [
  {
    name: "researcher",
    description: "Research agent",
    graphId: "researcher",
    // No url → ASGI (co-deployed)
  },
  {
    name: "coder",
    description: "Coding agent",
    graphId: "coder",
    url: "https://coder-deployment.langsmith.dev",
    // url present → HTTP (remote)
  },
];

모범 사례 (Best practices)

로컬 개발용 워커 풀 크기 조정

langgraph dev로 로컬에서 실행할 때 동시 서브에이전트 실행을 수용하도록 워커 풀을 늘리세요. 각 활성 실행은 워커 슬롯을 차지합니다. 3개의 동시 서브에이전트 작업이 있는 슈퍼바이저는 4개 슬롯(슈퍼바이저 1 + 서브에이전트 3)이 필요합니다. 과소 프로비저닝하면 실행이 대기열에 쌓입니다.

langgraph dev --n-jobs-per-worker 10

명확한 서브에이전트 설명 작성

슈퍼바이저는 어떤 서브에이전트를 실행할지 결정하는 데 설명을 사용합니다. 구체적이고 행동 지향적으로 작성하세요:

// Good
{
  name: "researcher",
  description: "Conducts in-depth research using web search. Use for questions requiring multiple searches and synthesis.",
  graphId: "researcher",
}
// Bad
{
  name: "helper",
  description: "helps with stuff",
  graphId: "helper",
}

스레드 ID로 트레이싱

LangGraph 기반 배포를 사용할 때, 모든 비동기 서브에이전트 실행은 표준 LangGraph 실행이며 LangSmith에서 완전히 보입니다. 슈퍼바이저의 트레이스는 launch, check, update, cancel, list의 도구 호출을 보여줍니다. 각 서브에이전트 실행은 스레드 ID로 연결된 별도 트레이스로 나타납니다. 스레드 ID(작업 ID)를 사용해 슈퍼바이저 오케스트레이션 트레이스를 서브에이전트 실행 트레이스와 연관시키세요.

문제 해결 (Troubleshooting)

슈퍼바이저가 실행 직후 폴링

문제: 슈퍼바이저가 실행 직후 루프로 check를 호출해 비동기 실행을 차단으로 바꿉니다.

해결책: 미들웨어가 이 문제를 방지하는 시스템 프롬프트 규칙을 주입합니다. 폴링이 지속되면 슈퍼바이저의 시스템 프롬프트에서 동작을 강화하세요:

import { createDeepAgent } from "deepagents";

const agent = createDeepAgent({
  model: "google_genai:gemini-3.6-flash",
  systemPrompt: `...your instructions...

    After launching an async subagent, ALWAYS return control to the user.
    Never call check_async_task immediately after launch.`,
  subagents: [...asyncSubagents],
});

슈퍼바이저가 오래된 상태 보고

문제: 슈퍼바이저가 새 check 호출 대신 대화 기록 앞부분의 작업 상태를 참조합니다.

해결책: 미들웨어 프롬프트는 모델에게 "대화 기록의 작업 상태는 항상 오래된 것"이라고 지시합니다. 여전히 발생하면 상태를 보고하기 전에 항상 checklist를 호출하라는 명시적 지침을 추가하세요.

작업 ID 조회 실패

문제: 슈퍼바이저가 작업 ID를 잘라내거나 다시 포맷하여 checkcancel이 실패합니다.

해결책: 미들웨어 프롬프트는 모델에게 항상 전체 작업 ID를 사용하도록 지시합니다. 잘림이 지속되면 이는 보통 모델 특정 문제입니다 — 다른 모델을 시도하거나 시스템 프롬프트에 "항상 전체 task_id를 표시하고, 절대 잘라내거나 줄이지 마세요"를 추가하세요.

서브에이전트 실행이 진행되지 않고 대기열에 쌓임

문제: 서브에이전트 실행이 멈추거나 시작하는 데 오래 걸립니다.

해결책: 워커 풀이 소진되었을 가능성이 높습니다. --n-jobs-per-worker로 풀 크기를 늘리세요. 워커 풀 크기 조정을 참고하세요.

참조 구현 (Reference implementation)

async-deep-agents 저장소에는 LangSmith Deployments에 배포되는 Python과 TypeScript의 작동 예시가 포함되어 있습니다. 백그라운드 작업으로 실행되는 researcher와 coder 서브에이전트가 있는 슈퍼바이저를 보여줍니다.

더 알아보기