단일 에이전트 루프를 넘어: Octo에서 멀티 에이전트 오케스트레이션(Multi-Agent Orchestration)을 구축한 방법
요약
단일 에이전트의 반복적인 루프 엔지니어링을 넘어, 복잡한 조직 업무를 수행하기 위한 멀티 에이전트 오케스트레이션의 필요성을 다룹니다. Octo 플랫폼 구축 경험을 바탕으로 컨텍스트 관리와 상태 공유를 위한 네트워크 수준의 조정 방식을 제안합니다.
핵심 포인트
- 단일 프롬프트 튜닝보다 모델 중심의 반복적 루프 시스템 구축이 효율적임
- 단일 에이전트 루프는 복잡한 조직적 업무 프로세스를 처리하기에 한계가 있음
- 멀티 에이전트 환경에서는 루프 간 상태 공유와 상호 트리거링이 필수적임
- 채팅 기반 인터페이스는 컨텍스트 윈도우 제한으로 인해 장기 업무 추적에 부적합함
몇 주 전, Claude Code 개발을 이끄는 Boris Cherny는 Acquired Unplugged 강연에서 더 이상 Claude를 위한 프롬프트(prompt)를 직접 작성하지 않는다고 언급했습니다. 대신 그는 작업이 실제로 완료될 때까지 Claude에게 계속해서 프롬프트를 제공하는 루프(loop)를 작성합니다. 이 영상 클립은 X(구 트위터)에서 바이럴되며 24시간도 채 되지 않아 약 70만 회의 조회수를 기록했고, 루프 엔지니어링(Loop Engineering)은 AI 개발 커뮤니티에서 최신 유행어가 되었습니다.
핵심 아이디어는 충분히 직관적입니다. 첫 번째 시도에서 완벽한 출력을 얻기 위해 단일 프롬프트를 집요하게 튜닝하는 대신, 모델을 중심으로 반복적인 시스템을 구축하는 것입니다. 모델에 명확한 목표를 부여하고, 적절한 컨텍스트(context)를 제공하며, 사용할 도구(tools)를 주고, 생성된 결과물을 평가하며, 언제 멈출지에 대한 조건을 정의합니다. 이러한 요소들을 서로 연결하면, 에이전트는 단발성 호출(one-shot call)에 그치지 않고, 출력이 실제로 사용자의 기준을 충족할 때까지 반복하고, 스스로 수정하며, 계속해서 작동하는 존재가 됩니다. 프롬프트 튜닝(prompt-tuning) 대비 효율성 향상은 실질적이며, 이것이 바로 이 개념이 빠르게 공감을 얻은 이유입니다.
우리가 자체 플랫폼인 Octo를 위한 루프 시스템(loop system)을 구축하고 출시하면서 느낀 점은, 현재 루프 엔지니어링(Loop Engineering)에 관한 거의 모든 논의가 단일 에이전트(single-agent) 수준에 머물러 있다는 사실입니다. 하나의 모델, 정교하게 설계된 하나의 루프, 하나의 샌드박스(sandbox)를 가지고, 에이전트가 설정된 모든 검증 과정을 통과할 때까지 반복적으로 작업을 수행합니다. 이는 한 사람이 AI를 활용해 더 빠르게 일하는 방법이라는 실질적인 문제를 해결해 줍니다. 하지만 실제 업무, 특히 조직 내부의 업무는 단일 에이전트 루프 안에 깔끔하게 들어맞는 경우가 드뭅니다. 아이디어에서 출시된 코드에 이르는 제품 기능 개발에는 요구사항을 정의하는 사람, 접근 방식을 설계하는 사람, 구현을 작성하는 사람, 품질을 검증하는 사람, 그리고 결과를 피드백하는 사람이 필요합니다. 이것들은 동일한 루프의 서로 다른 반복이 아닙니다. 이들은 서로 컨텍스트(context)와 출력값(outputs)을 전달해야 하는 상호 연결된 루프들입니다. 루프들이 상태(state)를 공유하고, 서로를 트리거(trigger)하며, 조직의 경계를 존중해야 할 때, 단일 에이전트 루프 설계는 더 이상 충분하지 않습니다. 네트워크 수준의 오케스트레이션(orchestration)이 필요합니다.
이 포스트는 루프 엔지니어링을 단일 에이전트 반복을 넘어 멀티 에이전트 협업(multi-agent collaboration)과 조직 규모의 조정(organizational-scale coordination)으로 확장하며 배운 점에 관한 것입니다.
IM은 대화에는 훌륭합니다. 하지만 장기적인 업무를 추적하는 데는 최악입니다.
Octo는 AI 네이티브 인스턴트 메시징(instant messaging) 플랫폼으로 시작되었습니다. 스레드(thread)에서 에이전트를 @로 호출하면, 에이전트가 작업을 가져와 대화창에 결과를 다시 게시합니다. 이 모델은 짧은 질의응답(Q&A)이나 빠른 작업에는 깔끔하게 작동합니다. 하지만 에이전트를 실제 프로덕션급(production-grade) 업무에 사용하기 시작하면 빠르게 무너집니다.
가장 먼저 컨텍스트 윈도우(Context window) 제한에 부딪힙니다. 채팅 인터페이스의 모든 스레드(thread)는 고정된 컨텍스트 예산을 가진 격리된 세션입니다. 작업이 여러 차례의 도구 호출(tool calls), 코드 수정, 에러 로그, 그리고 피드백 사이클을 포함하게 되면, 불과 십여 차례의 대화만으로도 컨텍스트가 가득 차게 되며, 이후 라운드에서 초기 지침을 준수하는 모델의 능력이 눈에 띄게 저하됩니다. 우리는 에이전트가 주의(attention)를 집중할 수 있도록 주제를 스레드로 격리하는 방법을 시도했고, 이는 미미하게나마 도움이 되었지만, 장기 실행 작업(long-running tasks)은 채팅 스트림 내에 존재해서는 안 된다는 근본적인 문제는 해결하지 못했습니다.
작업을 완료하는 데 30분 또는 몇 시간이 걸릴 때, 채팅창에서 답변을 기다리는 것은 실제적인 불안감을 유발합니다. 에이전트가 5분 동안 응답하지 않으면, 여전히 작업 중인지, 연결이 끊겼는지, 지시를 오해했는지, 아니면 어떤 엣지 케이스(edge case)에서 무한 루프에 빠졌는지 알 수 없습니다. 진행 상황을 확인하기 위해 동일한 스레드에 다른 메시지를 보내는 것은 에이전트가 하고 있는 작업을 방해할 위험이 있습니다. 이러한 불확실성 때문에 에이전트가 장기 작업에 대해 방치된 상태로 실행되도록 맡기는 것이 진정으로 어렵습니다. 90분 분량의 팟캐스트 스크립트를 구조화된 연구 요약본(research brief)으로 처리하거나, 프론트엔드와 백엔드 전체에 걸쳐 기능을 구현하는 것과 같이 실제로 중요한 작업들은 지속적인 실행 시간이 필요합니다.
여러 에이전트를 병렬로 실행하면 또 다른 문제가 발생합니다. 우리 팀원들은 Octo 내부에서 작동하는 에이전트와 함께 별도의 터미널에서 여러 개의 코딩 에이전트를 동시에 실행하는 일을 일상적으로 수행합니다. 이때 여러 로그 스트림(log streams)이 동시에 스크롤되면, 어떤 작업에 주의를 기울여야 하는지, 어떤 작업이 차단(blocked)되었는지, 그리고 어떤 작업이 검토를 기다리며 실제로 완료되었는지를 추적하는 능력이 급격히 떨어집니다. 터미널 창으로 가득 찬 Peter Steinberger의 데스크톱 스크린샷은 이제 익숙한 모습이지만, 이는 이상 현상이 아닙니다. 여러 에이전트를 동시에 실행할 때 터미널 자체가 충분히 훌륭한 작업 관리 인터페이스(task management surface)가 아니라는 증거입니다.
또한 우리는 회사 전반의 팀들로부터 일관된 요청을 계속해서 듣고 있었습니다. 사람들은 부서 수준의 공유 가능한 에이전트(shared, department-level agents)를 원했습니다. 도메인 전문가가 특정 워크플로(workflow)에 적합한 시스템 프롬프트(system prompt)와 기술 세트(skill set)로 에이전트를 구성하면, 팀원 모두가 각자 자신만의 버전을 구축하고 유지 관리할 필요 없이 이를 호출할 수 있는 방식입니다. 컴퓨팅 자원 할당(compute allocation) 측면의 영향도 있습니다. 아무도 팀 간 협업 작업 때문에 자신의 개인 에이전트 할당량(quota)이 소모되는 것을 원하지 않기 때문입니다.
우리가 도달한 해결책은 메시징 인터페이스(messaging interface) 위에 전용 작업 실행 레이어(task execution layer)를 구축하는 것이었습니다. 우리는 이 레이어를 루프(Loop)라고 부릅니다. 메시징은 대화가 이루어지고 의도(intent)가 명확해지는 곳으로 남겨두고, 루프(Loop)는 작업이 배정(dispatch), 실행, 추적 및 검토되는 곳입니다. 실행 기능을 채팅 스트림(chat stream) 자체에 억지로 밀어 넣으려 하기보다, 비동기 알림 레이어(async notification layer)를 통해 두 영역을 연결했습니다.
어시스턴트(Assistants)와 스페셜리스트(Specialists)는 근본적으로 다른 역할입니다.
우리가 결정하는 데 가장 오랜 시간이 걸린 설계 결정 중 하나는 플랫폼에서 실행되는 다양한 종류의 에이전트를 어떻게 분류할 것인가였습니다. 우리는 두 가지 역할, 즉 어시스턴트(Assistants)와 스페셜리스트(Specialists) 사이의 명확한 구분에 합의했습니다.
어시스턴트(Assistant)는 개인에게 속합니다. 어시스턴트는 당신이 어떻게 일하는지, 무엇을 선호하는지, 어떻게 판단을 내리는지, 그리고 당신의 프로젝트 전반에서 어떤 맥락(context)이 중요한지에 대한 장기 기억(long-term memory)을 보유합니다. 어시스턴트는 메시징 인터페이스 내에 존재하며, 그 역할은 관리적(managerial)입니다. 즉, 당신의 의도를 이해하고, 적절한 맥락을 가진 작업을 생성하며, 진행 상황을 모니터링하고, 적절한 결정 시점에 결과를 당신에게 제시합니다. 당신이 어시스턴트를 훈련시키면, 어시스턴트는 실제 작업을 수행하는 에이전트들을 관리합니다.
Specialist(전문가)는 작업자입니다. 이들에게는 장기 기억(long-term memory)이 없습니다. 각 작업은 깨끗한 컨텍스트(context)와 함께 시작됩니다. Specialist는 명시적인 시스템 프롬프트(system prompt), 제한된 기술 세트(set of skills), 그리고 작업 디렉토리(working directory)를 갖춘 지정된 런타임(runtime)에서 실행됩니다. 이러한 깨끗한 컨텍스트는 제약 사항이 아니라, 오히려 핵심적인 목적입니다. 우리가 관찰한 가장 흔한 실패 사례 중 하나는, 코딩 에이전트를 공유 그룹 채팅에 배치했을 때 여러 사람이 몇 주 동안 사용한 후 에이전트의 출력이 눈에 띄게 저하되는 현상이었습니다. 메모리 파일에 상충하는 선호도가 축적되고 서로 다른 사람들로부터 파편화된 컨텍스트가 쌓이면서, 시스템 프롬프트의 영향력이 약해지고 에이전트가 혼란에 빠지게 된 것입니다. Specialist는 프롬프트, 기술 구성, 그리고 런타임에 의해 동작이 완전히 결정되므로 이러한 문제를 완전히 방지하며, 예측 가능하고 재현 가능한(reproducible) 동작을 보장합니다. 여러 Specialist는 하나의 Squad(분대)로 구성되어, 리드 에이전트(lead agent) 아래에서 서로 다른 역량들이 협력해야 하는 교차 도메인(cross-domain) 작업을 수행할 수 있습니다.
소유권 측면에서, Assistant는 사용자에게 비공개로 유지됩니다. 반면 Specialist와 Squad는 가시성 범위(visibility ranges)를 설정할 수 있어, 개인에게 비공개로 유지하거나 워크스페이스 전체에 공유하거나, 또는 특정 그룹으로 제한할 수 있습니다. 이는 부서 단위의 에이전트 공유 사용 사례를 직접적으로 지원합니다.
루프(Loop)를 통한 작업 흐름
실행 흐름은 다음과 같이 작동합니다. 사용자는 메시징 인터페이스(messaging interface)를 통해 Assistant에게 말을 걸고 필요한 사항을 명확히 합니다. Assistant는 대화 문맥(context)으로부터 배경, 목표, 수락 기준(acceptance criteria)을 포함하는 구조화된 작업 브리프(task brief)를 생성합니다. 이후 Loop 내에 작업을 생성하고 이를 적절한 Specialist 또는 Squad에 할당합니다. Specialist는 작업을 가져와 실행을 시작하며, 필요에 따라 Loop 내부에서 멀티 에이전트 협업(multi-agent collaboration)이 이루어집니다. 결과는 웹훅(webhook)을 통해 메시징 인터페이스로 전달됩니다. Assistant는 핵심 사항을 추출하기 위해 1차 검토를 수행한 후 요약본을 사용자에게 전달합니다. 사용자는 주요 결정 지점에서 이를 검토하고 수락하거나, 피드백과 함께 반려하거나, 요구 사항을 추가할 수 있습니다. 모든 수락 및 반려 사항은 선호도 학습(preference learning)을 위한 자료로 기록됩니다.
이 흐름에서 몇 가지 공학적 선택 사항은 명시적으로 언급할 가치가 있습니다.
작업 브리프는 사람이 직접 작성하는 것이 아니라 Assistant에 의해 생성됩니다. 사람은 대화 형식으로 요구 사항을 설명하며 수락 기준이나 예외 케이스(edge cases)를 누락하곤 합니다. 반면 대화 전체에 참여한 Assistant는 더 완전하고 구조화된 브리프를 생성합니다. 실제로 브리프의 품질은 실행 성공률을 예측하는 가장 강력한 단일 지표입니다. 모호한 브리프는 Specialist가 잘못된 방향으로 시간과 토큰(tokens)을 낭비하게 만듭니다.
Specialist는 좁은 전문성 원칙(narrow-expertise principle)을 따릅니다. 단일 Specialist에 연결된 기술(skills)의 수를 10개 미만으로 제한하고, 역할을 명확히 정의하는 엄격하게 범위가 지정된 시스템 프롬프트(system prompt)를 부여합니다. 하나의 Specialist가 제품 사고(product thinking), 코드 구현(code implementation), 디자인 리뷰(design review)를 모두 잘하도록 만들려고 시도하면, 실행 중에 충돌하는 역할 정의가 모델을 서로 다른 방향으로 끌어당기기 때문에 전반적으로 평범한 결과물만 나오게 됩니다. 도메인을 넘나드는 작업은 단일 에이전트에 과부하를 주는 방식이 아니라, Squad를 구성함으로써 처리됩니다.
워크플로(Workflows)는 드래그 앤 드롭 방식의 노드 에디터가 아닌 프롬프트(prompts) 내에서 정의됩니다. 지난 1년 동안 많은 AI 워크플로 제품들이 시각적 노드 그래프(visual node graphs)를 사용해 왔지만, 고정된 그래프는 취약합니다. 만약 하나의 노드가 예상치 못한 출력을 생성하면, 스스로 수정할 수 있는 능력 없이 전체 흐름이 깨져버리기 때문입니다. 우리는 전문가(Specialist) 시스템 프롬프트 내에 워크플로를 정의합니다. 즉, 단계(phases), 단계별 목표(phase objectives), 전환 조건(transition conditions), 그리고 루프를 다시 돌리거나 인간의 개입을 요청해야 하는 규칙을 지정합니다. 이를 통해 워크플로에 탄력성(elasticity)을 부여하여, 전문가가 표준 절차를 위한 규율 있는 단계별 관문(stage gates)을 유지하면서도 실제 실행 상태에 적응할 수 있도록 합니다.
저희 엔지니어링 팀은 이미 한동안 기능 개발에 이 흐름을 사용해 왔습니다. 어시스턴트(Assistant)가 요구사항 대화로부터 브리프(brief)를 작성하고 구현 전문가(implementing Specialist)를 할당합니다. 전문가는 요구사항을 명확히 하고 아키텍처 제안서(architecture proposal)를 작성하며, 이는 다른 전문가 또는 사람에 의한 리뷰를 트리거합니다. 접근 방식이 승인되면 전문가는 브랜치(branch)를 생성하고, 코드를 작성하고, 테스트를 실행하고, 커밋(commit)한 뒤 PR(Pull Request)을 생성합니다. 만약 CI 리뷰에서 문제가 발견되면 전문가는 자동으로 리뷰 코멘트를 가져와 수정하고, 통과할 때까지 다시 제출합니다. 인간은 제안서 리뷰와 최종 승인 시점에만 개입합니다. 프론트엔드와 백엔드를 모두 건드리는 중간 규모의 기능을 개발할 때, 인간의 투입 시간은 방향성을 확인하는 약 10분 정도입니다.
비동기 알림(Async notifications)은 실행과 대화 사이의 간극을 메웁니다
긴 작업들은 메시징 인터페이스를 차단하지 않고 루프(Loop) 내에서 실행됩니다. 웹훅(Webhooks)은 상태 전환을 감시합니다. '대기 중(queued)'에서 '진행 중(in-progress)'으로, '진행 중'에서 '리뷰 대기 중(awaiting-review)'으로, '리뷰 대기 중'에서 '완료(done)' 또는 '반려(sent-back)'로의 전환을 감지하여 관련 스레드에 푸시 알림을 보내고, 관련 담당자나 어시스턴트를 @멘션합니다. 웹훅을 프로젝트 수준에서 설정하므로, 프로젝트 아래의 모든 작업이 일관되게 상태를 보고하게 됩니다.
각 채팅 스레드에는 Assistant가 다양한 상태에 따른 알림을 처리하는 방법을 알려주는 GROUP.md 설정 파일이 있습니다. 실행 중의 진행 상황 업데이트는 억제되며, 검토 준비(review-ready) 및 완료(completed) 상태는 푸시된 요약(pushed summary)을 트리거하고, 차단(blocked) 상태는 차단 사유와 함께 알림을 생성합니다. 설정을 마친 후 Assistant는 사용자와 Loop 사이에서 노이즈 필터(noise filter) 역할을 수행하며, 가공되지 않은 로그(raw logs)를 스트리밍하는 대신 의사 결정 시점에 정보를 표면화합니다.
실제로 이는 예약된 작업이나 장시간 실행되는 작업에 효과적입니다. 저희는 정해진 시간에 트리거되도록 설정된 반복적인 콘텐츠 분석 작업을 운영하고 있습니다. Squad는 몇 시간 동안 실행되며 소스 자료를 수집하고, 트랜스크립트(transcripts)를 처리하며, 구조화된 보고서를 생성합니다. 다음 날 아침이면 Assistant는 이미 스레드에 주요 결과와 전체 결과물로 연결되는 링크를 게시해 둡니다. 실행 도중 무언가 실패하면 Assistant가 차단 알림을 포착하여 이를 표시합니다.
런타임(Runtimes)과 스킬(Skills)은 전문가(Specialists)에게 실제 실행 능력을 부여합니다
전문가(Specialists)는 실제 컴퓨팅 자원 위에서 실행되어야 합니다. 런타임 관리 계층(runtime management layer)은 터미널 명령을 통한 개인용 컴퓨터 연결, 내부 클라우드 VM, 또는 제3자 서버 연결을 지원하며, 전문가(Specialists)는 특정 런타임에 바인딩(bound)됩니다. 현재 macOS와 Linux를 지원하며, Windows는 아직 테스트 중입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기