멀티 에이전트 하네스에서 컨텍스트 구성하기
요약
멀티 에이전트 시스템에서 컨텍스트 구성 방식에 대한 내용을 다루며, 서브에이전트를 활용한 작업 위임의 중요성을 설명합니다. 기존의 격리된(Isolated) 방식 외에 슈퍼바이저의 대화 기록을 상속받는 포크드(Forked) 서브에이전트 방식을 도입하여 효율성과 비용 절감을 제안합니다.
핵심 포인트
- 서브에이전트는 컨텍스트 격리를 통해 작업 위임 시 오염을 막습니다.
- 포크드 서브에이전트는 슈퍼바이저의 대화 내용을 상속받아 재사용성을 높입니다.
- 포킹은 프롬프트 캐싱 활용으로 속도와 비용 효율성이 뛰어납니다.
- Deep Agents에서 컨텍스트 모드를 명시적으로 지정할 수 있습니다.
요약 (TL;DR)
대부분의 하네스는 슈퍼바이저 에이전트(supervisor agent)가 새로운 작업을 생성하도록 하는 서브에이전트(subagents) 기능을 지원합니다. 서브에이전트는 병렬 추론과 컨텍스트 격리(context isolation)를 가능하게 하여, 슈퍼바이저 에이전트가 컨텍스트 창을 오염시키지 않고도 작업을 위임할 수 있게 합니다.
슈퍼바이저 에이전트가 작업을 지정하면, 서브에이전트는 일반적으로 새로운 컨텍스트 창에서 작업을 완료합니다. 이 방식은 낭비로 이어질 수 있습니다. 예를 들어, 서브에이전트가 슈퍼바이저가 이미 수행한 파일 읽기(file reads)와 같은 컨텍스트 수집 작업을 반복할 수 있기 때문입니다.
서브에이전트가 슈퍼바이저 에이전트의 컨텍스트로부터 이점을 얻을 수 있는 경우, 저희는 포크드 서브에이전트(forked subagents)를 구축했습니다. 포크드 서브에이전트는 처음부터 시작하는 대신 슈퍼바이저의 전체 대화 내용을 상속받습니다. 포킹은 슈퍼바이저의 대화를 재사용하여 프롬프트 캐싱(prompt caching)을 활용하고 반복 작업을 줄이기 때문에, 격리된 서브에이전트보다 더 빠르고 저렴할 수 있습니다.
서브에이전트를 사용하는 하네스
작업을 서브에이전트에 위임하는 것은 에이전트가 자체 컨텍스트를 관리하는 효과적인 방법 중 하나입니다. 서브에이전트는 컨텍스트 격리를 제공하여, 개별 작업의 세부 사항이 슈퍼바이저 에이전트의 컨텍스트 창에서 제외되도록 합니다. 더 자세히 알고 싶으시다면, 저희가 다양한 멀티 에이전트 아키텍처에 대해 길게 작성한 글을 참고해 주세요!
슈퍼바이저는 가장 일반화 가능한 패턴 중 하나이며, 대부분의 코딩 하네스가 이를 채택했습니다. 여기에서 슈퍼바이저는 계획을 유지하고 전문화된 서브에이전트에게 작업을 위임합니다. 예를 들어,
- 워커(Workers): 특정 범위가 명확한 구현 문제를 다룹니다.
- 리뷰어(Reviewers): 이미 수행된 작업에 대한 독립적인 판단을 내립니다.
슈퍼바이저 에이전트는 일반적으로 서브에이전트로부터 작업의 결과만 받으며, 그들의 중간 추론 과정은 컨텍스트 창에서 제외됩니다. 하지만 서브에이전트가 슈퍼바이저로부터 어떤 컨텍스트를 받아야 하는지는 해당 서브에이전트가 무엇을 위해 사용되는지에 따라 달라집니다.
서브에이전트를 위한 컨텍스트 모드
이를 명시적으로 지정하는 데 도움을 주기 위해, 저희는 deepagents의 최신 버전에서 컨텍스트 모드를 도입했습니다. 컨텍스트 모드는 서브에이전트가 슈퍼바이저로부터 받을 수 있는 컨텍스트를 지정합니다. 지원되는 값은 `
그리고 "fork"
격리된 서브에이전트 (Isolated subagents)
이는 Deep Agents에서 서브에이전트의 기본적이고 기존의 동작 방식입니다. 서브에이전트는 새로운 컨텍스트 창을 가지고 시작하며, 슈퍼바이저가 지정한 작업 설명만을 받습니다.

포크된 서브에이전트 (Forked subagents)
"mode": "fork"를 설정하면, 슈퍼바이저의 현재 상태가 비어 있는 상태로 시작하는 대신 서브에이전트에 전파됩니다. 이는 본질적으로 현재 스레드의 포크된 연속(forked continuation)이며—슈퍼바이저가 작성한 추가 지시사항을 포함합니다—최종적으로 단일 도구 결과로 풀려서 슈퍼바이저에 의해 읽힙니다.

구체적으로는 다음과 같습니다:
- 슈퍼바이저 에이전트가 작업 설명을 담아 서브에이전트를 호출하는 도구 호출(tool call)을 생성합니다.
- 서브에이전트는 대화 기록을 포함하여 전체 슈퍼바이저 에이전트의 상태를 받습니다. 뒤따르는 도구 호출은 제거되고, 그 작업 설명은 역할 명확화를 위한 고정된 서문과 함께 사용자 메시지(user message)로 형식화됩니다.
- 서브에이전트가 완료되면, 슈퍼바이저는 최초 도구 호출에 대한 응답으로 최종 메시지를 받습니다.
포크된 서브에이전트는 격리된 서브에이전트보다 더 많은 컨텍스트를 가지고 시작하지만, 프롬프트 캐싱(prompt caching)은 설계상 존중됩니다. 만약 서브에이전트가 작업을 올바르게 수행하기 위해 상세한 컨텍스트가 필요한 경우, 포킹(forking)은 반복적인 도구 호출과 컨텍스트 수집을 절약할 수 있습니다.
컨텍스트 모드 선택하기 (Choosing a context mode)
적절한 컨텍스트 모드의 선택은 서브에이전트가 작업과 어떤 관계를 맺는지에 따라 달라집니다. 이를 생각하는 유용한 방법은 두 가지 일반적인 패턴을 이용하는 것입니다: 슈퍼바이저의 작업을 이어가는 워커(workers)와 그것을 독립적으로 평가하는 검증기(verifiers)입니다.
워커 에이전트 (Worker Agent): 진행 중인 작업을 계속하기 위해 수행합니다.
워커는 슈퍼바이저가 이미 컨텍스트를 수집했거나 결정을 내린 후에 특정 작업을 수행합니다. 예를 들어, 슈퍼바이저는 오류를 검사하고, 그것을 특정 함수로 추적한 다음, 수정 사항의 구현 및 테스트를 위임할 수 있습니다.
워커를 격리된 상태에서 시작하면 증거(evidence)를 재발견하도록 강요됩니다. fork
, 이는 감독자(supervisor)의 기록을 받아들여 조사하던 지점부터 작업을 재개할 수 있습니다. 감독자는 어떤 작업이 수행되어야 할 때 이를 호출하지만, 결론에 도달하는 과정에서 거치는 중간 단계까지는 반드시 신경 쓰지 않습니다.
const fixerSubagent: SubAgent = {
mode: "fork",
name: "fixer",
...
감독자는 다음과 같은 작업으로 이를 호출할 수 있습니다:
우리가 식별한 타임아웃 문제에 기반하여 재시도 로직을 업데이트하고, 회귀 테스트(regression test)를 추가하세요.
검증자 에이전트 (Verifier agent): 작업을 독립적으로 평가합니다.
검증자는 다른 에이전트의 작업물을 특정 기준에 따라 검토합니다. 예를 들어, diff가 정확성, 하위 호환성(backwards compatibility), 테스트 커버리지 측면에서 적절한지 확인하는 것입니다.
이 경우, 감독자의 추론을 상속받는 것은 역효과일 수 있습니다. 검증자는 감독자의 진단이나 기대치에 얽매이기보다는 작업 자체를 평가해야 합니다. isolated 모드는 이전 대화 없이 작업과 관련 검토 자료만을 제공합니다.
const reviewerSubagent: SubAgent = {
mode: "isolated",
name: "reviewer",
...
감독자는 다음과 같이 이를 호출할 수 있습니다:
이 diff를 완전성, 하위 호환성, 적절한 테스트 커버리지 측면에서 검토해 주세요.
저희는 독립적인 검증자를 사용하는 또 다른 사례인 RubricMiddleware에 대해 이전에 작성한 적이 있습니다!
서브 에이전트 전문화 (Specializing subagents)
도구(tools)나 미들웨어(middleware)와 더불어, 컨텍스트 모드(context modes)는 서브 에이전트를 특정 작업에 맞게 전문화하는 데 사용할 수 있는 레버리지 중 하나입니다. 저희가 전문화되었다고 간주하는 몇 가지 서브 에이전트와 컨텍스트 모드의 관계를 살펴보겠습니다:
연구원 에이전트 (Researcher agent): 질문을 조사합니다.
연구원은 질문을 조사하고 감독자에게 요약된 답변을 반환합니다. 예를 들어, 감독자는 생소한 라이브러리, 경쟁사 또는 기술적 결정의 역사에 대한 개별적인 질문들을 위임할 수 있습니다.
질문이 독립적으로 설 수 있는 경우, 연구원은 감독자의 대화가 필요하지 않습니다. isolated 모드를 사용하면
현재의 질문에 컨텍스트를 집중적으로 유지합니다. 이는 여러 연구원이 병렬로 실행될 때 특히 유용합니다. 각 연구원은 할당된 질문만 필요함에도 불구하고 감독자의 기록이 중복되는 것을 방지할 수 있기 때문입니다.
isolated 모드를 사용하면
const researcherSubagent: SubAgent = {
mode: 'isolated',
name: 'researcher',
...
감독자는 다음과 같이 이를 호출할 수 있습니다:
버전 1.2와 1.3 사이에 API가 변경되었는지 판단하고 관련 릴리스 노트에 연결하세요.
우리는 서브 에이전트에게 자체적인 기능(예: search_engine 도구)을 부여하여 작업을 완료하는 데 도움을 줄 수 있습니다.
Memory agent: 대화에서 정보를 보존합니다
메모리 에이전트는 나중에 사용 가능해야 하는 상호작용으로부터 정보를 식별합니다. 예를 들어, 사용자 선호도, 아키텍처 결정 또는 대화 중에 설정된 제약 조건 등이 있습니다.
여기서 대화가 에이전트가 분석해야 할 자료입니다. fork를 사용하면 메모리 에이전트는 전체 상호작용을 받고 감독자가 작업에서 이를 다시 언급할 필요 없이 보존할 가치가 있는 것이 무엇인지 결정할 수 있습니다.
const memorizerSubagent: SubAgent = {
mode: "fork",
name: "memorizer",
...
감독자는 다음과 같이 이를 호출할 수 있습니다:
이 대화에서 설정된 결정과 선호도를 메모리화하세요.
메모라이저 에이전트가 편집할 수 있는 내용을 정확히 제한하고 싶기 때문에, 작업하는 동안 어떤 파일을 편집할 수 있는지에 대한 제한을 설정하여 서브 에이전트를 전문화할 수 있습니다.
직접 사용해 보기
deepagents는 저희가 수천 개의 다른 팀과 함께 에이전트를 배포하면서 얻은 교훈을 담아 구축하고 있는 프레임워크입니다. 다음 명령어를 설치하여 서브 에이전트 컨텍스트 모드(여기 문서를 참조하세요) 및 훨씬 더 많은 기능을 사용해 볼 수 있습니다:
# Python
uv add deepagents
# Typescript
...
GitHub 이슈, 포럼 또는 X / LinkedIn에서 의견을 알려주세요!
AI 자동 생성 콘텐츠
본 콘텐츠는 LangChain Blog의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기