Deep Agents 서브에이전트

Deep Agents 서브에이전트 (Subagents)

딥 에이전트는 작업을 위임하기 위해 서브에이전트를 만들 수 있어요. subagents 파라미터로 커스텀 서브에이전트를 지정할 수 있는데, 서브에이전트는 컨텍스트 격리(메인 에이전트의 컨텍스트를 깨끗하게 유지)와 전문화된 지시 제공에 특히 유용해요. 이 페이지는 동기(synchronous) 서브에이전트를 다뤄요. 감독자(supervisor)가 서브에이전트가 끝날 때까지 블로킹하는 방식이에요. 오래 걸리는 작업, 병렬 워크스트림, 중간 조정·취소가 필요하다면 Async subagents 문서를 보세요.

출처: 공식문서

왜 서브에이전트를 쓸까요

서브에이전트는 컨텍스트 비대(bloat) 문제를 해결해요. 큰 출력을 내는 도구(웹 검색, 파일 읽기, DB 쿼리)를 쓸 때 중간 결과로 컨텍스트 윈도우가 금방 차기 마련인데, 서브에이전트는 이 세부 작업을 격리해서 메인 에이전트에게는 수십 개의 툴 호출이 아니라 최종 결과만 전달되게 해요.

서브에이전트를 쓸 때:

  • ✅ 메인 에이전트 컨텍스트를 어지럽힐 다단계 작업
  • ✅ 커스텀 지시·도구가 필요한 전문화 영역
  • ✅ 다른 모델 능력이 필요한 작업
  • ✅ 메인 에이전트를 높은 수준의 조정에 집중시키고 싶을 때

쓰지 않을 때:

  • ❌ 단순한 단일 단계 작업
  • ❌ 중간 컨텍스트를 유지해야 할 때
  • ❌ 오버헤드가 이점보다 클 때

설정 (Configuration)

subagents는 딕셔너리 리스트 또는 CompiledSubAgent 객체 목록이에요. 두 가지 타입이 있어요.

기본 서브에이전트 (Default subagent)

Deep Agents는 그 이름을 가진 동기 서브에이전트를 이미 제공하지 않는 한, 동기 범용(general-purpose) 서브에이전트를 자동으로 추가해요. 범용 서브에이전트는 기본적으로 파일시스템 도구를 갖고 있고, 추가 도구·미들웨어로 커스터마이즈할 수 있어요.

  • 교체하려면 general-purpose라는 이름의 서브에이전트를 직접 넘겨요.
  • 자동 추가 버전을 이름 바꾸거나 리프롬프트하려면 활성 하네스 프로필에서 general_purpose_subagent=GeneralPurposeSubagentProfile(...)을 설정해요.
  • 비활성화하려면 아래 "서브에이전트 없이 실행"을 참고하세요.

서브에이전트 없이 실행 (Running without subagents)

task 도구 없이 에이전트를 실행하려면 두 가지를 해요.

  1. 활성 하네스 프로필에서 general_purpose_subagent=GeneralPurposeSubagentProfile(enabled=False)을 설정.
  2. create_deep_agentsubagents=에 동기 서브에이전트를 넘기지 않기.

Deep Agents는 동기 서브에이전트가 하나라도 있을 때만 SubAgentMiddleware(와 task 도구)를 붙여요. 기본이든 호출자가 넘긴 것이든 아무것도 없으면 위임 없이 실행돼요. 여기서 excluded_middleware를 쓰면 안 돼요 — SubAgentMiddleware는 필수 스캐폴딩이라 나열하면 ValueError가 나요. general_purpose_subagent.enabled = False 노브가 지원되는 경로예요.

커스텀 서브에이전트 (Custom subagents)

subagents 파라미터로 특정 도구를 가진 전문화 서브에이전트를 정의할 수 있어요. 코드 리뷰어, 웹 리서처, 테스트 러너 같은 역할로요. 대부분의 경우 SubAgent 딕셔너리로 정의하고, 복잡한 워크플로에는 CompiledSubAgent를 써요.

SubAgent (딕셔너리 기반)

SubAgent 스펙에 맞는 딕셔너리로 정의하며, 필드는 다음과 같아요.

필드 타입 설명
name str 필수. 서브에이전트의 고유 식별자. 메인 에이전트가 task() 도구를 호출할 때 이 이름을 사용해요. 서브에이전트 이름은 AIMessage와 스트리밍의 메타데이터가 되어 에이전트를 구분하는 데 도움돼요.
description str 필수. 무엇을 하는지에 대한 설명. 구체적이고 행동 지향적으로 작성해요. 메인 에이전트가 언제 위임할지 결정할 때 쓰여요.
system_prompt str mode: "isolated"(기본값)에서 필수. 서브에이전트 지시. 커스텀 isolated 서브에이전트는 반드시 자신의 것을 정의해야 해요. 도구 사용 안내와 출력 형식 요구사항을 포함하세요. 메인 에이전트에서 상속하지 않아요. mode: "fork"라면 fork 전용 부가문이 아니라면 생략해요.
mode "isolated" | "fork" 선택. 컨텍스트 모드. 기본은 "isolated"로, 서브에이전트는 위임된 작업만 봐요. "fork"로 설정하면 부모의 대화·시스템 프롬프트를 상속해요.
tools list[Callable] 선택. 서브에이전트가 쓸 도구. 최소한으로 유지하고 필요한 것만 넣어요. 기본은 메인 에이전트에서 상속. 지정하면 상속된 도구를 전부 덮어써요.
model str | BaseChatModel 선택. 메인 에이전트의 모델을 덮어씀. 생략하면 메인 에이전트 모델 사용. 'openai:gpt-5.5' 같은 'provider:model' 형식 문자열이나 LangChain 채팅 모델 객체(init_chat_model("gpt-5.5"), ChatOpenAI(model="gpt-5.5"))를 넘길 수 있어요.
middleware list[Middleware] 선택. 커스텀 동작·로깅·레이트 리밋용 추가 미들웨어. 메인 에이전트에서 상속하지 않아요.
interrupt_on dict[str, bool | InterruptOnConfig] 선택. 특정 도구에 대한 human-in-the-loop 설정. True, False, 또는 allowed_decisions가 있는 InterruptOnConfig. checkpointer 필요. 기본은 메인 에이전트에서 상속.
skills list[str] 선택. 스킬 소스 경로. 지정하면 그 디렉터리에서 스킬을 로드해요. 메인 에이전트에서 상속하지 않아요. 범용 서브에이전트만 메인 에이전트 스킬을 상속해요.
response_format ResponseFormat 선택. 서브에이전트의 구조화된 출력 스키마. 설정하면 부모는 자유 형식 텍스트 대신 JSON으로 결과를 받아요.
permissions list[FilesystemPermission] 선택. 서브에이전트의 파일시스템 권한 규칙. 설정하면 부모 에이전트의 권한을 전부 대체해요. 기본은 메인 에이전트에서 상속.

CompiledSubAgent

복잡한 워크플로에는 사전 구축된 LangGraph 그래프를 CompiledSubAgent로 쓰면 돼요.

필드 타입 설명
name str 필수. 고유 식별자. name은 AIMessage·스트리밍 메타데이터가 되어 에이전트를 구분하는 데 도움돼요.
description str 필수. 무엇을 하는지.
runnable Runnable 필수. 컴파일된 LangGraph 그래프(먼저 .compile() 호출 필수).
mode "isolated" | "fork" 선택. 기본 "isolated". "fork"면 부모의 메시지 히스토리를 상속. 컴파일된 그래프는 어느 쪽이든 자신의 시스템 프롬프트를 유지해요.

SubAgent 사용하기

internet_search 도구를 가진 리서치 서브에이전트를 만들고 subagents=research_subagent로 연결하는 예시예요.

import os
from typing import Literal

from deepagents import create_deep_agent
from tavily import TavilyClient

tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])

def internet_search(
    query: str,
    max_results: int = 5,
    topic: Literal["general", "news", "finance"] = "general",
    include_raw_content: bool = False,
):
    """Run a web search"""
    return tavily_client.search(
        query,
        max_results=max_results,
        include_raw_content=include_raw_content,
        topic=topic,
    )

research_subagent = {
    "name": "research-agent",
    "description": "Used to research more in depth questions",
    "system_prompt": "You are a great researcher",
    "tools": [internet_search],
    "model": "openai:gpt-5.5",  # Optional override, defaults to main agent model
}
subagents = [research_subagent]

agent = create_deep_agent(
    model="google_genai:gemini-3.6-flash",
    subagents=subagents,
)

CompiledSubAgent 사용하기

더 복잡한 경우에는 커스텀 서브에이전트를 CompiledSubAgent로 제공할 수 있어요. LangChain의 create_agent로 만들거나, 그래프 API로 커스텀 LangGraph 그래프를 만들면 돼요. 커스텀 LangGraph 그래프를 만든다면 그래프에 "messages"라는 상태 키가 있어야 해요.

from deepagents import CompiledSubAgent, create_deep_agent
from langchain.agents import create_agent

def internet_search(query: str) -> str:
    """Run a web search."""
    return f"search results for {query}"

research_instructions = "You are a research coordinator."
your_model = "openai:gpt-5.5"
specialized_tools: list = []

# Create a custom agent graph
custom_graph = create_agent(
    model=your_model,
    tools=specialized_tools,
    system_prompt="You are a specialized agent for data analysis...",
)

# Use it as a custom subagent
custom_subagent = CompiledSubAgent(
    name="data-analyzer",
    description="Specialized agent for complex data analysis tasks",
    runnable=custom_graph,
)

subagents = [custom_subagent]

agent = create_deep_agent(
    model="google_genai:gemini-3.6-flash",
    tools=[internet_search],
    system_prompt=research_instructions,
    subagents=subagents,
)

문제 해결 (Troubleshooting)

서브에이전트가 호출되지 않을 때

문제: 메인 에이전트가 위임하지 않고 스스로 작업을 처리하려 해요. 해결책:

  • description을 더 구체적으로: "Conducts in-depth research on specific topics using web search. Use when you need detailed information that requires multiple searches."처럼 행동 지향적으로 작성해요. "helps with stuff" 같은 모호한 설명은 피하세요.
  • 메인 에이전트에게 위임을 지시: 시스템 프롬프트에 "IMPORTANT: For complex tasks, delegate to your subagents using the task() tool. This keeps your context clean and improves results." 같은 문장을 넣어요.

컨텍스트가 계속 비대해질 때

문제: 서브에이전트를 쓰는데도 컨텍스트가 가득 차요. 해결책:

  • 서브에이전트에게 간결하게 요약해서 돌려보내라고 지시: "IMPORTANT: Return only the essential summary. Do NOT include raw data, intermediate search results, or detailed tool outputs. Your response should be under 500 words."
  • 큰 데이터는 파일시스템 활용: 원시 데이터를 /data/raw_results.txt에 저장하고 분석 요약만 반환하도록 지시.

잘못된 서브에이전트가 선택될 때

문제: 메인 에이전트가 작업에 맞지 않는 서브에이전트를 호출해요. 해결책: 서브에이전트들을 description으로 명확히 구분. 예를 들어 quick-researcher(간단·빠른 질문, 1-2회 검색)와 deep-researcher(복잡·심층, 통합·분석 필요)처럼 용도를 구별해요.

더 알아보기 (Learn more)

  • Async subagents — 병렬 워크스트림과 비동기 서브에이전트
  • 미들웨어 재정의(Override a default middleware instance)와 파일시스템 도구 제한
  • Deep Agents 개요의 위임(Delegation) 섹션