Skip to content

SubAgents

Danny edited this page Apr 11, 2026 · 1 revision

SubAgents

이 페이지는 SubAgent 가 언제 생성되고, 어떻게 식별되고, 어떻게 정리되는지 를 구현 레벨에서 다룬다. README 의 현재 SubAgent 역할SubAgent 는 언제 실제로 뜨나 섹션의 뒷면이다.

1. 기본 등록된 10개 역할

모든 역할은 src/coding_agent/async_subagent_manager.py:32-160DEFAULT_ASYNC_SUBAGENTS dict 에 하드코딩되어 있다. 각 역할은 자기 system prompt, 책임 범위, 기본 모델을 가진다.

역할 책임
planner PRD 생성, atomic task breakdown, acceptance criteria 정의
architect System design, 모듈 경계, API/data flow
frontend Web UI/UX 구현
mobile Mobile UX/flow
backend DB/API/domain logic
coder 일반 코드 구현
reviewer 코드/산출물 리뷰, 회귀 탐지, 누락 테스트 지적
debugger 버그 재현, root cause 분석
researcher 외부 정보 탐색, 배경 지식 정리
remember 장기 메모리 후보 파일 선별 + 파일별 계층 추천 + 저장 노트 초안

로딩 경로

load_async_subagents() (async_subagent_manager.py:235) 가 먼저 ~/.deepagents/config.toml[async_subagents] 섹션을 시도하고, 없으면 위 DEFAULT_ASYNC_SUBAGENTS 를 그대로 사용한다. config 파일은 자동 생성되지 않는다 — 커스터마이즈하고 싶을 때만 사람이 만든다.

LocalAsyncSubagentManager.__init__() (async_subagent_manager.py:337-348) 에서 위 스펙에 host, port, model, transport 를 확장하고, build_async_subagents() 가 DeepAgents 에 넘길 최종 spec 목록을 만든다.

2. Lazy spawn: "필요한 순간에만 프로세스가 뜬다"

split topology 의 핵심은 앱 시작 시 SubAgent 를 전부 띄우지 않는다는 점이다. 구현은 src/coding_agent/middleware/lazy_async_subagents.pyLazyAsyncSubagentsMiddleware 에 있다.

동작

  1. Main Agent 가 tool call 을 발행
  2. LazyAsyncSubagentsMiddleware.wrap_tool_call() / awrap_tool_call() (lazy_async_subagents.py:74-90) 가 모든 tool call 을 가로챔
  3. tool_call.get("name") == "start_async_task" 이면 (lazy_async_subagents.py:26), 타겟 subagent 이름을 추출
  4. self._runtime.ensure_started(subagent_type) 호출 (lazy_async_subagents.py:53)
  5. LocalAsyncSubagentManager 가 해당 역할의 SubAgent 서버 프로세스를 spawn → health check 통과까지 대기
  6. 그 후 원래 tool call 이 실행되어 task 가 그 SubAgent 로 들어감

왜 Lazy 인가

  • 10개 역할을 미리 띄우면 포트 10개 + 프로세스 10개 + 모델 로딩 10번 → 대부분은 안 쓰임
  • 질의 하나는 평균 2-3개 역할만 사용
  • MAX_SUBAGENTS (기본 30) 한도 안에서 "지금 이 순간 실제로 쓰이는" 프로세스만 살아있도록 관리

3. Per-SubAgent 프로세스 내부

실제 프로세스는 src/coding_agent/async_subagent_server.py:243-253 에서 create_deep_agent(...) 로 조립된다. 차이점:

항목 Main Agent SubAgent
조립 함수 finalize_coding_agent() (agent.py:298) async_subagent_server.py:243-253
Middleware 6개 (fallback, LTM, async-only, lazy, lifecycle, completion) 2개 (fallback, LTM)
System prompt build_system_prompt(...) 역할별 prompt (DEFAULT_ASYNC_SUBAGENTS)
Shell backend LocalShellBackend(root_dir=<query_workdir>) 같은 query_workdir 공유
Partial output 직접 streaming 파일로 덤프 → WebUI polling

즉, SubAgent 는 "단독으로 create_deep_agent 로 만든, middleware 가 얇은 에이전트" 이지 Main Agent 의 일부가 아니다. 이 설계가 process isolationcrash containment 를 만들어낸다.

4. SubAgent 수명주기 상태

SubAgentLifecycleMiddleware 가 다음 상태 전이를 추적한다 (src/coding_agent/middleware/subagent_lifecycle.py):

created → assigned → running → completed
                   └→ blocked → (alternate role 재시도)
                   └→ failed
                   └→ cancelled
→ destroyed

각 전이는 DurableStateStore (state/store.py) 의 subagent_records / subagent_events 테이블에 기록되며, WebUI 는 이 이벤트 스트림을 polling 해서 실시간 timeline 을 그린다.

메타데이터 (WebUI 에 노출):

  • agent_id + role ordinal (예: architect agent #1)
  • task_id, run_id
  • endpoint, pid, port, model
  • lifecycle event summary

5. 실패 대응

Resilience and Models 페이지에서 자세히 다루지만, SubAgent 관련 policy 두 개를 미리 언급한다:

  • subagent_failure (resilience.py:43) — SubAgent 가 blocked 혹은 failed 상태가 되면 다른 role 로 alternate 재시도 를 시도한다. 예: architect 가 막히면 planner 로 우회.
  • safe_stop (resilience.py:59) — 증거가 부족하거나 위험한 작업 요청이 들어오면 즉시 정지.

6. 커스텀 역할 추가하는 법

  1. ~/.deepagents/config.toml 을 만들고 [async_subagents] 섹션에 새 역할 정의
  2. 역할 이름, system prompt, 기본 모델, 필요 시 tools 를 명시
  3. LocalAsyncSubagentManager 가 재시작 시 이 파일을 읽음 (async_subagent_manager.py:235)
  4. Main Agent 가 start_async_task(subagent_type="<new_role>") 를 호출하면 lazy spawn 됨

주의: config.toml 에 정의한 역할 이름과 Main Agent prompt 안의 역할 이름이 일치해야 한다. src/coding_agent/async_subagent_manager.pyDEFAULT_ASYNC_SUBAGENTS 를 템플릿으로 참고하자.

7. 동시 실행 한도

  • 하드 리밋: max_subagents = 100 (agent.py 의 loop 설정)
  • 실사용 리밋: 환경변수 MAX_SUBAGENTS, 기본 30 (.env.example, docker-compose.yml 모두 30)
  • 이 한도를 넘기면 Main Agent 의 추가 start_async_task 는 대기하거나 거절된다

Clone this wiki locally