에이전트가 더 야심 찬 작업을 수행할수록 다음과 같은 어려움에 직면합니다:
- 대규모 작업을 안정적으로 완료하는 것
- 자체 컨텍스트를 관리하는 것
저희는 이러한 문제를 해결하기 위해 동적 하위 에이전트(Dynamic Subagents) 형태로 다양한 실험을 진행해 왔습니다. 즉, 일반적인 도구 호출을 통해 하위 에이전트 작업을 발행하는 대신, 에이전트가 하위 에이전트 실행을 주도하는 짧은 스크립트를 작성하는 방식입니다. 이를 통해 모델은 루프, 분기, 동시성과 같이 작성에 능숙한 코드 패턴을 활용하여 작업에 맞는 오케스트레이션 로직을 구성할 수 있습니다.
동적 하위 에이전트가 필요한 이유는?
Deep Agents는 이미 하위 에이전트(Subagents)를 지원합니다. 하위 에이전트는 컨텍스트를 분리하여 메인 에이전트가 개별 작업 단위를 위임할 수 있게 하고, 중간 결과가 메인 컨텍스트 창에 남지 않도록 합니다. 그렇다면 왜 동적 하위 에이전트가 필요할까요?
일반 하위 에이전트는 메인 모델이 직접 호출하여 한 번에 하나씩 호출됩니다. 소규모에서는 잘 작동하지만, 수백 개의 하위 에이전트를 생성해야 하거나 오케스트레이션 로직이 조건부 또는 다단계인 경우에는 한계가 있습니다.
동적 하위 에이전트는 프로그래매틱 오케스트레이션(Programmatic Orchestration) 으로 이 문제를 해결합니다. 에이전트는 턴바이턴으로 도구 호출을 하는 대신, 하위 에이전트를 오케스트레이션하고 호출하는 짧은 스크립트를 작성하여 가벼운 인터프리터에서 실행합니다.
전형적인 예시: 300페이지 분량 문서의 각 페이지에 대해 하나의 하위 에이전트를 할당하는 경우입니다. 에이전트는 하위 에이전트 도구를 300번 호출하는 대신 루프를 작성합니다:
1const results = await Promise.all(pages.map(page =>2 task({ description: `Summarize page ${page.number}`, subagentType: "summarizer" })3));
이를 통해 도구 호출 기반 오케스트레이션으로는 안정적으로 구현할 수 없는 두 가지 기능을 사용할 수 있습니다:
대규모 환경에서의 결정론적 커버리지. 구조가 없으면 에이전트는 범위에 대한 판단을 내려 500개 중 75개만 검토하고 작업을 완료했다고 간주합니다. 하지만 디스패치 루프는 그렇지 않습니다. 커버리지는 프롬프트 엔지니어링 문제가 아닌 구조적 보장이 됩니다.
안정적인 복잡 오케스트레이션. 오케스트레이션을 코드로 작성하는 것은 모델이 이를 일련의 도구 호출로 재현하도록 하는 것보다 훨씬 안정적입니다. 특히 분산 출력 후 합성(Fan-out + Synthesis), 다단계 파이프라인 또는 조건부 분기의 경우 더욱 그렇습니다.
이는 Claude Code의 워크플로우와 Recursive Language Models (RLMs)의 기본 아이디어와 동일합니다. 즉, 모델이 코드를 작성하고, 그 코드가 더 많은 에이전트를 디스패치하는 방식입니다.
빠른 시작
동적 하위 에이전트를 사용하려면 두 가지가 필요합니다: 작업을 위임할 하위 에이전트와 코드 인터프리터 즉, 모델이 오케스트레이션 코드를 작성하고 실행하는 안전하고 가벼운 런타임이 필요합니다. Deep Agents에는 QuickJS 기반의 옵션 코드 인터프리터가 포함되어 있습니다. 사용하려면 QuickJS 미들웨어 패키지를 설치한 후, create_deep_agent의 middleware 인자를 통해 CodeInterpreterMiddleware를 전달하세요.
1pip install -U "deepagents[quickjs]"
1from deepagents import create_deep_agent2from langchain_quickjs import CodeInterpreterMiddleware34agent = create_deep_agent(5 model="openai:gpt-5.5",6 middleware=[CodeInterpreterMiddleware()],7)
Deep Agents에는 범용 하위 에이전트가 내장되어 있으므로 워크플로우에서 사용할 수 있는 일반 하위 에이전트 프로필이 하나 이미 존재합니다. 특수 워크플로우의 경우, 고유한 이름, 설명 및 시스템 프롬프트를 사용하여 커스텀 하위 에이전트를 구성하세요. 이름과 설명은 에이전트가 어떤 역할을 선택해야 하는지 알게 해줍니다.
동적 하위 에이전트를 트리거하려면 다음과 같이 에이전트에 "workflow"라는 단어로 프롬프트를 입력하세요:
1result = await agent.ainvoke({2 "messages": [{"role": "user", "content": "Run a workflow that reviews every file in src/routes/ and summarizes the top risks."}]3})
코딩 에이전트와 함께 사용하기
동적 하위 에이전트를 가장 빠르게 체험하는 방법은 Deep Agent를 사용하여 구축된 터미널 코딩 에이전트인 dcode를 사용하는 것입니다. dcode에는 코드 인터프리터가 활성화된 상태로 제공되므로 별도로 설정할 필요 없이 동적 하위 에이전트를 즉시 사용할 수 있습니다.
설치
1curl -LsSf https://langch.in/dcode | bash
실행
1dcode
동적 하위 에이전트를 트리거하려면 "workflow"를 요청하기만 하면 됩니다. 에이전트는 작업을 직접 처리하거나 기본 task 도구를 사용하여 하위 에이전트 분산을 관리하는 대신, 내장된 task() 전역 함수를 호출하는 오케스트레이션 스크립트를 작성하여 코드 인터프리터에서 실행합니다. 예를 들어, "src/ 디렉토리의 모든 파일을 SQL 인젝션에 대해 검토하는 workflow를 실행해 줘"와 같이 요청하면 됩니다.
하위 에이전트가 생성됨에 따라 dcode는 동적 하위 에이전트 패널에 디스패치별로 단계별로 그룹화하여 실시간으로 표시합니다.

이 기능은 dcode로 가장 빠르게 체험할 수 있지만, ACP를 통해 원하는 도구 (예: Zed)에서도 사용할 수 있습니다.
작동 방식
에이전트에는 eval 도구가 제공됩니다. 에이전트는 인터프리터 내부에서 안전하게 실행되는 JavaScript를 작성합니다. 하위 에이전트가 구성되면, 인터프리터는 코드에서 하위 에이전트를 디스패치하는 내장 task() 전역 함수를 노출합니다. 당면한 작업에 따라 모델은 루프, 분기, Promise.all 등 다양한 코드를 작성하고 인터프리터는 이를 결정론적으로 실행합니다.

task()는 description, subagentType 및 선택적 responseSchema를 받습니다. responseSchema가 제공되면 결과는 이미 타입이 지정된 객체가 되어 다음 단계로 필터링하거나 전달할 준비가 됩니다.
1const result = await task({2 description: "Review src/auth/login.ts for security issues.",3 subagentType: "reviewer",4 responseSchema: {5 type: "object",6 properties: {7 severity: { type: "string", enum: ["high", "medium", "low"] },8 issues: { type: "array", items: { type: "string" } },9 },10 },11});1213const critical = result.severity === "high" ? result.issues : [];14critical; // model sees the last line
자세한 내용은 문서의 프로그래매틱 하위 에이전트 및 인터프리터를 참조하세요.
일반적인 오케스트레이션 패턴
Anthropic의 동적 워크플로우는 병렬 에이전트 작업을 위한 일련의 오케스트레이션 패턴을 대중화했습니다. 이들은 단순히 켜고 끄는 기능이 아닙니다. 작업의 성격에 따라 자연스럽게 나타나는 형태이며, 작업이 변경됨에 따라 에이전트는 다른 패턴으로 전환됩니다. 아래 표는 각 형태가 어떤 종류의 작업에 적합한지 보여줍니다.

아래에서는 각 패턴이 Deep Agents에서 어떻게 작동하는지 실제 트레이스와 함께 자세히 설명합니다. 또한 이 여섯 가지 패턴을 설명하는 동영상을 준비했으니 여기에서 확인하실 수 있습니다.
분류 및 실행 (Classify and act)
항목을 먼저 분류한 다음, 각 항목을 분류에 따라 specialized 하위 에이전트가 처리합니다. 이를 통해 서로 다른 항목에 다른 전문 지식이 필요한 혼합 입력을 처리할 수 있습니다.

사용 사례: 지원 티켓 분류, 오류 로그 분석, 사용자 피드백 처리, 또는 유형에 따라 다른 처리가 필요한 모든 항목 배치 처리.
예시: 지원 티켓 백로그 분류. 에이전트가 티켓을 읽고 각각을 버그, 기능 요청, 질문으로 분류합니다. 버그는 버그 조사관에게, 기능 요청은 기능 분석가에게, 질문은 지원 응답자에게 할당합니다. 결과는 카테고리별로 그룹화된 요약입니다.
트레이스는 여기에서 확인하세요.
분산 출력 및 합성 (Fanout and synthesize)
에이전트가 여러 항목에 걸쳐 동일한 유형의 작업을 병렬로 분산시킨 후, 결과를 결합합니다.

사용 사례: 디렉토리 전체에 대한 코드 리뷰, 문서 배치 분석, 로그 파일 처리, 여러 서비스에 동일한 검사 실행.
예시: 소스 트리 전체에 대한 파일별 보안 검토. 에이전트가 src/ 디렉토리 아래의 모든 TypeScript 파일을 찾고 각 파일에 대해 하나의 security-reviewer 하위 에이전트를 병렬로 디스패치합니다. 그런 다음 결과를 단일 우선순위 보고서로 병합하여 심각도 등급과 변경해야 할 라인을 함께 제공합니다.
트레이스는 여기에서 확인하세요.
적대적 검증 (Adversarial verification)
2-패스 방식입니다. 첫 번째 패스에서 결과를 도출합니다. 두 번째 패스에서는 각 결과를 독립적인 검증자에게 보내고, 합의가 이루어진 결과만 유지됩니다. 이는 속도보다 정확도가 중요할 때 거짓 양성(False Positive)을 줄여줍니다.

사용 사례: 거짓 양성 비용이 큰 보안 감사, 규정 준수 점검, 결과에 높은 신뢰도가 필요한 모든 검토.
예시: 거짓 양성이 허용되지 않는 보안 감사. 감사자가 잠재적 취약점을 광범위하게 찾아내고, 각 결과는 코드를 새롭게 읽고 CONFIRMED 또는 REFUTED 판정을 반환하는 독립적인 검증자에게 전달됩니다. 최종 보고서에는 확인된 결과만 포함됩니다.
트레이스는 여기에서 확인하세요.
생성 및 필터링 (Generate and filter)
여러 하위 에이전트가 동일한 문제에 대한 독립적인 솔루션을 생성합니다. 에이전트는 코드 내에서 결과를 비교, 점수화 및 필터링하여 최상의 결과만 유지합니다.

사용 사례: 아키텍처 제안, 리팩토링 전략, 콘텐츠 변형, 최종 결정 전에 여러 옵션을 탐색하는 것이 더 나은 결과를 가져오는 모든 작업.
예시: 경쟁하는 Rate Limiter 재설계안의 순위 매기기. 에이전트는 아키텍트 하위 에이전트를 사용하여 rate-limiter.ts에 대한 여러 독립적인 재설계안을 생성하며, 각각은 서로 다른 파일에 저장되어 덮어쓰지 않도록 합니다. 그런 다음 버스트 상황에서의 정확성, 다중 인스턴스 지원, 복잡성 등을 기준으로 점수를 매깁니다. 가장 강력한 설계안이 선정되며, 그 이유에 대한 설명이 함께 제공됩니다.
트레이스는 여기에서 확인하세요.
토너먼트 (Tournament)
변형들을 심사 하위 에이전트가 1:1로 비교하고, 승자는 토너먼트 방식으로 다음 라운드에 진출합니다.

사용 사례: 주관적 기준에 따른 최적화, 스타일 선택, 경쟁 구현체 간 선택.
예시: 복잡한 createOrder 핸들러 리팩토링에 대한 페어와이즈 브라켓. 여러 작성자가 각기 다른 우선순위로 리팩토링 후보를 생성합니다. 그런 다음 심사 하위 에이전트가 이를 1:1로 비교하여 라운드별로 승자를 선정하고, 최종적으로 하나의 챔피언이 결정됩니다. 심사의 판단 근거와 함께 결과가 반환됩니다.
트레이스는 여기에서 확인하세요.
완료될 때까지 반복 (Loop until done)
에이전트가 발견 루프를 실행하여 이미 찾은 내용과 중복을 제거하고, 새로운 결과가 더 이상 나오지 않을 때까지 반복합니다. 작업 범위를 사전에 알 수 없을 때 유용합니다.

사용 사례: 완전 탐색, 데드 코드 감지, 의존성 감사, 고정된 결과 수보다 완전성을 원하는 모든 분석 작업.
예시: 패스 기반 보안 분석. 에이전트가 스캔 패스를 실행하고, 코드에서 찾은 내용을 검사한 후, 이전 패스에서 새로운 문제가 발견된 경우에만 다음 패스를 시작합니다. 패스에서 새로운 내용이 전혀 발견되지 않으면 중단됩니다. 통합된 결과와 몇 번의 패스가 필요했는지를 보고합니다.
트레이스는 여기에서 확인하세요.
결론
동적 하위 에이전트는 에이전트에게 더 큰 자율성과 향상된 안정성을 부여하는 방법입니다. 코드가 커버리지와 중간 컨텍스트를 처리하고, 모델은 여전히 판단이 많이 필요한 작업을 수행합니다. 위에서 설명한 패턴들은 시작점에 불과합니다. 실제로 에이전트는 작업 요구사항에 따라 이러한 패턴들을 조합하고 혼합하여 사용합니다.
이는 Recursive Language Model 아이디어의 가장 단순한 형태입니다. 코드를 작성하는 에이전트, 그리고 그 코드가 더 많은 에이전트를 디스패치하는 구조입니다. 이는 스스로를 재귀적으로 호출하는 에이전트이며, 컨텍스트 창에 의해 제한되거나 고정된 워크플로우에 갇히지 않습니다. 에이전트는 문제를 필요한 만큼 세분화하여 분해하고, 상황에 맞는 형태로 조각들을 재조립할 수 있습니다. 위에서 강조된 오케스트레이션 패턴은 가능성의 초기 모습에 불과하며, 모델이 코드를 더 잘 작성하게 됨에 따라 그 한계는 계속해서 높아질 것입니다.
Dynamic Subagents는 Deep Agents가 오늘 여러분께 이 기능을 제공하는 방식입니다. 지금 바로 에이전트에 코드 인터프리터를 추가하여 시작하거나, 동적 하위 에이전트가 기본적으로 활성화된 dcode를 사용해보세요.
감사의 말
공동 작성: @colifran_님과 @huntlovell님. @hwchase17님, @masondrxy님, @chester_curme님의 세심한 검토에 감사드립니다.





