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 도구 없이 에이전트를 실행하려면 두 가지를 해요.
- 활성 하네스 프로필에서
general_purpose_subagent=GeneralPurposeSubagentProfile(enabled=False)을 설정. create_deep_agent의subagents=에 동기 서브에이전트를 넘기지 않기.
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) 섹션