Opus 4.8에 Dynamic Workflows 탑재 — 세션당 수백 개의 병렬 서브에이전트(subagents) 지원. 프로덕션 적용 전
요약
Anthropic의 Opus 4.8은 수백 개의 병렬 서브에이전트를 실행할 수 있는 Dynamic Workflows를 도입했습니다. 이는 기존의 제한적인 방식이나 복잡한 직접 구현 방식 대신, 단순한 함수 호출만으로 동시성 및 검증을 처리하는 새로운 프로그래밍 모델을 제공합니다.
핵심 포인트
- Dynamic Workflows를 통한 수백 개의 병렬 서브에이전트 지원
- agent, parallel, pipeline 등 직관적인 프로그래밍 프리미티브 제공
- 런타임 수준에서 동시성, 구조화된 출력 검증, 재시도 자동 처리
- 프로덕션 적용 시 설정 고정(pinning)을 통한 비용 관리 권장
Opus 4.8에 Dynamic Workflows 탑재 — 세션당 수백 개의 병렬 서브에이전트(subagents) 지원. 프로덕션 적용 전 필독 사항
5월 28일 Anthropic의 Opus 4.8 발표는 대부분의 분량을 벤치마크(benchmarks)에 할애했습니다. CursorBench 상승, Terminal-Bench 2.1이 GPT-5.5를 능가, OSWorld-Verified 82.3%, Online-Mind2Web 84%를 기록했습니다. 법률 에이전트(legal-agent) 벤치마크는 처음으로 전 항목 통과(all-pass) 10%를 돌파했습니다. 헤드라인 작성자들이 주목한 수치들은 바로 이것들입니다.
하지만 벤치마크 표 아래에는 에이전트(agents)를 배포하는 방식을 실제로 변화시킬 문장이 숨겨져 있습니다:
Dynamic Workflows(동적 워크플로우). 수백 개의 병렬 서브에이전트(subagents)를 실행합니다. 수십만 줄에 달하는 코드베이스 규모의 마이그레이션(migrations)을 처리합니다.
이것은 벤치마크가 아닙니다. 새로운 프로그래밍 모델(programming model)입니다. 그리고 현재 프리뷰(preview) 형태로 출시되었으므로, 현재의 기본 설정(defaults)은 90일 후의 모습과 다를 것입니다. 만약 프로덕션(production) 환경에서 에이전트를 운영 중이라면, 다음 마이너 릴리스(minor release)가 나오기 전에 설정을 고정(pin)하지 않을 경우 청구 금액에 놀라게 될 것입니다.
프리뷰가 실제로 수행하는 작업은 다음과 같습니다. 압도적으로 처리하는 세 가지 작업, 돈을 낭비하게 만드는 한 가지 작업 유형, 그리고 Dynamic Workflows의 기본 설정이 변경되기 전에 반드시 고정해야 할 정확한 설정값입니다.
Dynamic Workflows가 실제로 변화시킨 것
4.8 버전 이전에는 Anthropic 스택에서 병렬 서브에이전트(parallel subagents)를 사용하는 것이 다음 두 가지 중 하나를 의미했습니다. Claude Code 내부에서 Agent 도구를 호출하여 고정된 수의 사이드 태스크(side-task) 서브에이전트를 얻는 방식(보통 동시 실행이 4개 또는 8개 정도로 제한됨)이거나, TypeScript 또는 Python으로 직접 오케스트레이터(orchestrator)를 작성하여 Promise.all로 Messages API를 호출하고 큐잉(queueing)을 직접 처리하는 방식이었습니다.
Agent 방식은 사용하기 편리(ergonomic)했지만 제한적(capped)이었습니다. 직접 만드는(DIY) 방식은 제한이 없었지만, 재시도(retries), 구조화된 출력 검증(structured output validation), 캐시 무효화(cache invalidation) 등 모든 오케스트레이션 문제를 직접 해결해야 했습니다.
4.8 버전의 Dynamic Workflows는 이 두 가지 문제를 모두 해결합니다. 별도의 오케스트레이터 바이너리(orchestrator binary)를 만드는 대신, JavaScript 스크립트를 작성하여 agent(), parallel(), pipeline(), phase()를 기본 단위(primitives)로 호출하기만 하면 됩니다. 런타임(runtime)이 동시성(concurrency), JSON 스키마(JSON Schema)에 따른 구조화된 출력 검증(structured output validation), 검증 실패 시 재시도(retries), 그리고 진행 상황 보고(progress reporting)를 처리합니다. 동시성 제한은 워크플로(workflow)당 min(16, cpu_cores - 2)입니다. 수명 제한(lifetime cap)은 무한 루프(runaway loops)를 방지하기 위한 안전장치로 워크플로당 1,000개의 에이전트(agents)로 설정되어 있습니다.
"수백 개의 병렬 서브에이전트(subagents)"라는 문구는 마케팅용 수사가 아닙니다. pipeline()에 800개의 항목이 담긴 배열을 전달하면 모든 항목이 실행됩니다. 제한 사항은 동시에 실행 중인(in-flight) 작업 수에 적용되는 것이지, 총 파견(dispatched)된 작업 수에 적용되는 것이 아닙니다.
구조를 보여주는 가장 작은 규모의 워크플로는 다음과 같습니다:
export const meta = {
name: 'review-changed-files',
description: 'Review changed files across dimensions, verify each finding',
...
주의 깊게 봐야 할 세 가지 사항이 있습니다. 첫째, pipeline()은 배리어(barrier)가 아닙니다. 즉, bugs 차원(dimension)이 검증(verify) 단계에 있는 동안 perf 차원은 여전히 검토(review) 단계에 머물 수 있습니다. 기본 제어 흐름(control flow)은 폭포수(waterfall) 방식이 아닌 스트리밍(streaming) 방식입니다. 둘째, schema:는 서브에이전트가 StructuredOutput 도구(tool)를 호출하도록 강제합니다. 검증은 자유 형식의 텍스트(free text)를 파싱하는 것이 아니라 도구 호출(tool-call) 레이어에서 발생합니다. 따라서 JSON.parse(try/catch) 블록을 별도로 작성할 필요가 없습니다. 셋째, 예산(budget)은 공유됩니다. 모든 서브에이전트는 budget.spent()에 합산되며, 부모 스크립트는 실행 도중에 이를 읽어 실시간으로 탐색 깊이(depth)를 조절할 수 있습니다.
만약 Messages API를 기반으로 직접 오케스트레이터를 작성해 오셨다면, 이것이 그 역할을 대체할 것입니다. 보완(augments)하는 것이 아니라, 대체(replaces)하는 것입니다.
이것이 중요한 이유: 84%가 아닌 4배라는 정직한 수치
헤드라인을 장식하는 벤치마크(benchmarks)는 실제 수치이지만, Dynamic Workflows를 실질적으로 지탱하는 핵심은 아닙니다. 이 기능을 실제로 사용할 수 있게 만드는 수치는 모델 카드(model card)에 숨겨져 있습니다. Opus 4.8은 4.7 버전보다 코드 결함(code flaws)이 지적되지 않은 채 통과될 확률이 약 4배 더 낮습니다.
그 문장은 fan-out(팬아웃)이 실제로 오류율(error rates)에 어떤 영향을 미치는지 생각하기 전까지는 마케팅 문구처럼 들립니다. 만약 단일 서브에이전트(subagent)의 "이것은 실제 버그입니다"에 대한 오탐률(false-positive rate)이 5%라면, 50개를 병렬로 실행했을 때 생성되는 결과 목록은 대부분 노이즈(noise)가 됩니다. 리뷰어의 오버헤드(reviewer-overhead) 곡선은 매우 가혹합니다. 더 많은 결과물을 얻게 되지만, 각 결과물에 대한 신뢰도는 낮아지고, 분류(triage) 작업은 길어지며, 결국 워크플로우(workflow) 사용을 중단하게 됩니다.
오탐률을 4배 낮추면 곡선은 반전됩니다. 약 1%의 오탐률을 가진 50개의 서브에이전트는 실제로 15분 안에 읽을 수 있는 목록을 생성합니다. 이제 fan-out은 가치가 있습니다. 이것이 워크플로우 기능을 실행 가능하게 만드는 전제 조건입니다. 정직성(honesty)의 개선 없이는 수백 개의 서브에이전트가 그저 결과물의 품질 저하(slop)를 증폭시킬 뿐일 것입니다.
두 번째는 도구 호출(tool-calling) 효율성입니다. Anthropic의 릴리스 노트에 따르면 4.8 버전은 작업당 "의미 있게 더 적은 단계(meaningfully fewer steps)"를 사용합니다. 이것이 중요한 이유는 Dynamic Workflows가 에이전트당, 단계당 비용을 부과하기 때문입니다. 기존에 각 에이전트가 12번의 도구 호출(tool calls)을 수행하던 워크플로우가 200개의 서브에이전트로 fan-out 될 때, 이제 7번의 호출만 수행한다면 이는 단순히 1.7배 저렴해지는 것이 아닙니다. 1.7배 더 저렴해지면서, 1.7배 더 빨라지고, 1.7배 더 낮은 확률로 속도 제한(rate limit)에 걸리게 됩니다. 이러한 복리 효과(compounding)가 이 기능을 경제적으로 만듭니다.
세 번째는 Messages API의 변경 사항입니다. 이제 시스템 엔트리(System entries)를 프롬프트 캐시(prompt cache)를 깨뜨리지 않고 작업 중간에 수용할 수 있습니다. 이 부분을 두 번 읽어보십시오. 4.7 및 이전 버전의 세계에서는 장시간 실행되는 에이전트 실행 중에 새로운 시스템 지침(system instruction)을 주입하면 이전의 모든 턴(turn)에 대한 캐시가 날아갔습니다. 4.8에서는 이것이 가능합니다. 즉, 한 시간 동안 실행되는 워크플로우에서 부모 스크립트가 서브에이전트가 반환한 결과에 따라 새로운 컨텍스트(context)를 주입하더라도, 이전에는 원샷 프롬프트(one-shot prompts)에서만 가능했던 캐시 적중률(cache hit rates)을 유지할 수 있다는 의미입니다. 이 변경 사항 없이는 Dynamic Workflows 기능의 비용 효율성을 확보할 수 없었을 것입니다.
이 세 가지 수치는 복리로 작용합니다. 4배의 정직성 × 1.7배의 효율성 × 작업 중간의 캐시 안정적 주입. 이것이 프리뷰(preview) 버전에서 단지 5개가 아니라 실제로 수백 개의 서브에이전트를 출시할 수 있는 이유입니다.
메커니즘: pipeline()이 parallel()과 다르게 수행하는 것
문서상으로는 이 두 가지 제어 흐름 프리미티브 (control-flow primitives)가 비슷해 보일 수 있습니다. 하지만 그렇지 않습니다. 이 차이를 구분하는 것이 모든 팀이 처음 세 번의 Dynamic Workflows를 구축할 때 저지르는 공통된 실수입니다.
parallel(thunks)는 배리어 (barrier)입니다. 값을 반환하기 전에 모든 thunk가 완료되기를 기다립니다. 만약 10개의 서브에이전트 (subagents)가 있고 그중 하나가 90초가 걸리는 반면 나머지 9개가 10초가 걸린다면, 호출은 90초 후에 반환됩니다. 빠른 9개는 80초 동안 유휴 상태 (idle)로 대기하게 됩니다.
pipeline(items, stage1, stage2, ...)는 배리어가 아닙니다. 각 아이템 (item)은 모든 스테이지 (stage)를 독립적으로 통과합니다. 아이템 A가 스테이지 3에 있는 동안 아이템 B는 여전히 스테이지 1에 있을 수 있습니다. 실제 소요 시간 (wall-clock cost)은 각 스테이지별 최장 시간의 합이 아니라, 가장 느린 단일 아이템 체인의 시간입니다.
'찾기(find) 후 검증(verify)'이라는 2단계 워크플로우 (workflow)의 경우, 계산 방식은 다음과 같이 달라집니다:
- 50개의 찾기를
parallel로 수행한 후, 모든 결과에 대해parallel로 검증할 때: max(find_times) + max(verify_times) - 50개 아이템에 대해 (찾기 후 검증)을
pipeline으로 수행할 때: 단일 아이템에 대한 max(find_time + verify_time)
찾기 시간이 차원(dimension)에 따라 3배까지 차이 나는 리뷰 작업의 경우, pipeline을 사용하면 실제 소요 시간 (wall-clock)이 대략 50~60% 더 빠릅니다. 비용 (cost)은 동일합니다. 에이전트 호출 횟수는 같습니다. 오직 지연 시간 (latency)만 줄어듭니다.
배리어 (barrier) 방식이 정확히 맞는 경우는 딱 세 가지입니다. 첫째, 스테이지 N이 스테이지 N-1의 모든 아이템으로부터 교차 아이템 컨텍스트 (cross-item context)를 필요로 할 때 — 예를 들어, 비용이 많이 드는 후속 작업을 수행하기 전 전체 결과 집합에 대해 중복을 제거 (dedup)해야 하는 경우입니다. 둘째, 전체 집합에 의존하는 조기 종료 (early-exit) 신호가 필요할 때 — "버그가 하나도 발견되지 않았다면 검증을 완전히 건너뛴다"와 같은 경우입니다. 셋째, 스테이지 N의 프롬프트 (prompt)가 비교를 위해 문자 그대로 "다른 결과들"을 참조할 때입니다.
그 외의 모든 것은 pipeline을 사용해야 합니다. Promise.all의 근육 기억 (muscle memory)으로 인해 기본적으로 배리어를 선택하려는 본능은 Dynamic Workflows에서 실제 소요 시간 (wall-clock)을 낭비하게 만드는 가장 큰 원인입니다.
다음은 미래의 독자가 그 형태를 알아볼 수 있도록 작성된 수정된 패턴입니다:
// 잘못된 방식 — 단계 간의 병렬 배리어(parallel barrier)
const found = await parallel(DIMENSIONS.map(d => () => agent(d.prompt, { schema: BUGS })))
const flat = found.filter(Boolean).flatMap(r => r.bugs)
...
반대 의견: "우리는 이미 자체 오케스트레이터(orchestrator)를 가지고 있습니다"
이번 주에만 이 논리를 세 번이나 보았습니다. 그 형태는 다음과 같습니다: "우리는 이미 Promise.all을 통해 Messages API를 호출하는 TypeScript 오케스트레이터를 작성했습니다. 재시도(retries) 로직도 있고, 구조화된 출력(structured output)도 있으며, 진행 상황 보고(progress reporting) 기능도 있습니다. Dynamic Workflows는 우리가 이미 하고 있는 작업의 래퍼(wrapper)일 뿐입니다."
이 말이 틀린 것은 아닙니다. 다만 불완전할 뿐입니다.
이미 오케스트레이터를 구축한 사람들이 놓치고 있는 것은 캐시 공유 모델(cache-sharing model)입니다. 코드에서 Messages API를 호출하는 DIY 오케스트레이터는 호출할 때마다 Anthropic의 API에 새로운 클라이언트로 접속하게 됩니다. 각 호출은 자신만의 프롬프트 캐시(prompt cache) 상태를 가집니다. 반면 워크플로 에이전트(Workflow agents)들은 부모 실행(parent run)의 동시성 제한(concurrency cap), 에이전트 카운터(agent counter), 중단 신호(abort signal), 그리고 — 결정적으로 — 토큰 예산(token budget)을 공유합니다. 이 예산은 메인 루프와 모든 워크플로에 걸쳐 풀(pool)로 관리됩니다. 워크플로 내의 budget.spent()는 메인 에이전트와 동일한 카운터를 읽습니다. 이는 외부에서는 복제할 수 없는 기능입니다.
DIY를 선호하는 사람들이 놓치는 두 번째 사항은 도구 호출(tool-call) 계층에서의 구조화된 출력 검증(structured output validation)입니다. 워크플로 런타임(Workflow runtime)은 서브에이전트(subagent)에 대해 StructuredOutput 도구 호출을 강제합니다. 만약 검증에 실패하면, 모델은 서브에이전트 자체 루프 내부에서 — 여러분의 오케스트레이터로 다시 돌아오는 라운드 트립(round-tripping) 없이 — 자동으로 재시도합니다. 부모의 관점에서는 호출이 검증된 객체를 반환하거나, 아니면 예외(throw)를 발생시킵니다. 별도의 파싱(parsing) 단계가 필요 없습니다. 스키마 불일치(schema-mismatch)에 따른 폴백(fallback)도 필요 없습니다. 여러분은 지난 2년 동안 모든 오케스트레이터에서 동일한 if (parsed?.findings) 방어적 체크 코드를 작성해 왔습니다. 이제 런타임이 그 체크를 대신 처리합니다.
세 번째는 동시성 제한(concurrency cap)입니다. 여러분이 직접 만든 오케스트레이터(DIY orchestrator)는 동일한 세션 내에서 실행되는 다른 워크플로우(workflows)에 대해 알지 못합니다. 워크플로우 런타임(Workflow runtime)은 워크플로우당 min(16, cpu_cores - 2)로 제한을 두지만, 중첩된 워크플로우(nested workflows) 간에도 이를 조정합니다. 즉, 워크플로우 내부에서 호출된 workflow()는 부모의 제한(cap)을 공유합니다. 이것은 여러분이 작성한 것이 아닙니다. 외부에서는 이를 작성할 수 없습니다.
이것은 단순한 래퍼(wrapper)가 아닙니다. 캐시(cache), 예산(budget), 그리고 동시성(concurrency)을 소유하는 런타임입니다. 이 세 가지는 여러분의 DIY 코드가 건드리기는 하지만 소유하고 있지는 않은 것들입니다.
덜 명확하지만 네 번째 요소가 있습니다: 바로 재개(resume)입니다. 워크플로우 런타임은 모든 agent() 호출을 저널링(journaling)합니다. 스크립트가 충돌하거나, 중단 후 수정하여 다시 실행하더라도, 런타임은 캐시에서 변경되지 않은 가장 긴 접두사(prefix)를 재생(replay)하고 수정되었거나 새로운 호출만 실시간으로 실행합니다. 동일한 스크립트에 동일한 인자(args)를 사용하면 100% 캐시 히트(cache hit)가 발생합니다. 솔직히 말씀드리면, 여러분의 DIY 오케스트레이터는 이 기능을 수행하지 못합니다. 파이프라인 전체를 다시 실행하고 비용을 다시 지불해야 합니다. 200개의 에이전트(agent)로 구성된 워크플로우에서 이러한 재지불은 매우 의미 있는 차이를 만듭니다. Opus 비중이 높은 스크립트의 경우, 실패한 실행당 쉽게 40달러의 차이가 발생할 수 있습니다.
Dynamic Workflows에 대한 올바른 해석은 다음과 같습니다: 이것은 여러분이 이미 구축한 오케스트레이터 코드를 60일 이내에 쓸모없게 만듭니다. 여러분의 코드가 나빠서가 아니라, 새로운 런타임이 기질(substrate)을 소유하기 때문입니다. 마이그레이션(migration)을 계획하십시오. 가장 먼저 움직이는 팀은 기존 오케스트레이터를 유지 관리하는 것이 가장 고통스러운 팀들이 될 것입니다. 제 경험상, 6개월 이전에 오케스트레이터를 직접 작성한 모든 팀이 이에 해당합니다.
플레이북: 기본값이 변경되기 전에 이 세 가지 설정을 고정(pin)하세요
Dynamic Workflows는 프리뷰(preview) 단계입니다. 프리뷰는 변경됩니다. 다음 마이너 릴리스(minor release)에서 세 가지 요소가 거의 확실히 변동될 것이며, 만약 이를 고정(pin)해두지 않았다면 동작이 조용히 변하게 될 것입니다.
첫째: 동시성 제한(concurrency cap)을 명시적으로 고정(pin)하세요. 기본값은 min(16, cpu_cores - 2)입니다. 만약 Anthropic이 마이너 릴리스(minor release)에서 워크플로당 상한선을 32로 높인다면 — 문서에 따르면 로드맵에 포함되어 있습니다 — 기존의 워크플로들은 두 배 더 많은 동시 호출(concurrent calls)을 시작하게 될 것입니다. 대부분은 괜찮을 것입니다. 하지만 다운스트림 속도 제한(downstream rate limit)(사용자의 데이터베이스, CI 시스템, 도구에서 호출하는 외부 API 등)에 걸리는 워크플로들은 문제가 될 것입니다.
아직 명시적인 제한 설정을 위한 공개 API가 없으므로, 실질적인 해결책은 작업을 직접 청크(chunk)로 나누는 것입니다. 즉, 전체 리스트를 한 번에 전달하는 대신 pipeline()에 N개 단위의 배치(batch)로 아이템을 전달하세요. 실행 시점에 처리 중인(in flight) 아이템이 N개를 넘지 않으므로, 런타임은 N개 이상의 동시 호출을 발생시키지 않을 것입니다.
둘째: 중요한 모든 agent() 호출에서 모델을 고정(pin)하세요. agent()의 opts.model 파라미터는 선택 사항입니다. 이를 생략하면 서브에이전트(subagent)는 메인 루프 모델을 상속받는데, 이는 세션 모델이며 변경될 수 있습니다. 만약 여러분이 4.8 버전 환경에서 워크플로를 작성했고 4배 향상된 정직성(honesty) 개선 사항에 의존하고 있다면, 모든 적대적 검증(adversarial-verify) 에이전트에 model: 'claude-opus-4-8'을 명시적으로 설정하세요. 세션이 4.7로 폴백(fallback)되는 경우 — 이는 4.8 장애 발생 시 일어날 수 있으며, 지난 30일 동안 두 번 발생했습니다 — 검증 단계의 오탐률(false-positive rate)이 4배 급증합니다. 반드시 고정하세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기