데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      Claude Code Dynamic Workflow 쉽게 이해하기

      한성원 26.08.21
      196 1 0
      DEVOTEE 요약
      Claude Code의 ‘Dynamic Workflow’는 JavaScript 코드로 제어 흐름을 확정하고, 실제 세부 작업만 여러 서브에이전트에 위임하여 실행하는 오케스트레이션 방식입니다. 이 방식은 단일 에이전트의 컨텍스트 초과와 즉흥적인 판단 한계를 해결하여, 대규모 작업을 병렬로 신속하게 처리하고 적대적 교차 검증을 통해 높은 정확도와 재현성을 확보합니다. `pipeline`, `parallel` 등의 API와 유연한 토큰 예산 관리를 지원하므로, 전수 코드 감사나 대규모 마이그레이션처럼 신뢰성과 확장성이 필요한 복잡한 작업에 매우 효과적입니다.
      DEVOTEE 추천 블로그

      나의 에이전트가 순서대로 일하는 대신,

      JavaScript 스크립트가 여러 서브에이전트를 지휘하는 방식. 반복·분기·병렬 같은 제어 흐름을 코드로 확정해 두고, 실제 작업만 에이전트에게 맡깁니다.

      Claude Code의 Dynamic Workflow 기능이 이 방식을 실행합니다.

      아래에 나오는 agent()·pipeline() 같은 함수는 그 스크립트 안에서 쓰는 API이고, Claude Code가 이를 읽어 서브에이전트를 띄웁니다.

      스크린샷 2026-08-21 오전 11.18.25.png

      1. 왜 Dynamic Workflow인가

      큰 작업을 에이전트 하나에게 통째로 맡기면 두 가지 한계가 생깁니다.

      컨텍스트가 넘치고(한 머리에 다 안 들어감), 흐름이 모델의 즉흥 판단에 좌우됩니다(매번 다르게 행동).

      Dynamic Workflow는 이 문제를 "흐름은 코드로 고정, 작업은 에이전트에 위임" 으로 풉니다. 네 가지를 동시에 얻습니다:



      🔭 빠짐없이 (Comprehensive)

      작업을 쪼개 병렬로 커버. 50개 파일도 한 번에 훑습니다.

      확신 있게 (Confident)

      독립적인 관점으로 교차 검증하고, 적대적으로 반박한 뒤 확정합니다.

      📦 큰 규모로 (Scale)

      한 컨텍스트에 안 담기는 마이그레이션·감사·전수 작업을 처리합니다.

      🎯 결정적으로 (Deterministic)

      반복·분기·팬아웃이 코드로 확정됩니다. 모델의 즉흥 판단이 아닙니다.


      2. 핵심 개념: 코드가 흐름을, 에이전트가 작업을

      무엇이 달라지는지부터 보겠습니다.


      일반 에이전트 호출

      Dynamic Workflow

      흐름을 정하는 주체

      에이전트가 "다음에 뭘 할지" 매번 스스로 판단

      루프·조건·팬아웃을 스크립트가 확정

      재현성

      모델 판단에 달려 있어 매번 다르게 동작

      같은 스크립트면 같은 흐름

      중간 결과

      전부 Claude의 컨텍스트에 쌓임

      스크립트 변수에 남고, 컨텍스트에는 최종 결과만

      에이전트의 역할

      계획과 실행을 함께 떠맡음

      "이 한 가지 작업"만 하고 결과 반환 — 조립은 코드가

      구현은 단순합니다. 워크플로우는 meta 블록으로 시작하는 평범한 JavaScript 스크립트이고, 본문에서 agent()를 호출하면 서브에이전트가 떠서 작업하고 그 결과를 다시 JS 코드로 다룹니다.

      export const meta = {
        name: 'review-changes',
        description: '변경된 파일을 차원별로 리뷰하고 각 발견을 검증',
        phases: [{ title: 'Review' }, { title: 'Verify' }],
      }
      // ↑ meta는 반드시 순수 리터럴 (변수·함수 호출 금지)
      // ↓ 여기서부터 스크립트 본문 — await를 바로 쓸 수 있음
      
      phase('Review')
      const result = await agent('이 디렉토리에서 버그를 찾아라', { schema: BUGS_SCHEMA })
      // schema를 주면 검증된 객체를 반환 — 파싱 불필요

      기억할 점: 서브에이전트에게는 "너의 마지막 텍스트가 곧 반환값"이라고 전달됩니다. 사람에게 보내는 메시지가 아니라 데이터를 반환합니다. schema를 주면 검증까지 자동입니다.

      위 코드는 뼈대만 보여주는 조각입니다. 스키마 정의부터 결과 반환까지 그대로 돌아가는 전체 스크립트는 6장에 있습니다.


      3. 기본 구성 요소 4가지

      함수

      역할

      핵심

      agent(prompt, opts?)

      서브에이전트 하나를 띄움

      schema 있으면 검증된 객체, 없으면 텍스트 반환. 죽으면 null

      pipeline(items, ...stages)

      각 항목을 여러 단계에 독립적으로 통과시킴

      단계 사이에 장벽 없음 — A가 3단계일 때 B는 1단계 가능. 기본 선택

      parallel(thunks)

      여러 작업을 동시에 실행

      장벽(barrier) — 전부 끝날 때까지 대기. 모든 결과가 한꺼번에 필요할 때만

      phase(title) / log(msg)

      진행 단계 구분 / 진행 메시지 출력

      사용자에게 보이는 진행 트리를 구성

      그 외에 budget (토큰 예산), args (외부 입력), workflow() (다른 워크플로우를 하위 단계로 실행) 등이 있습니다.

      런타임이 걸어두는 상한은 두 개입니다.

      동시에 도는 에이전트는 최대 16개이고(CPU 코어가 적은 머신에서는 그보다 적게), 한 번의 실행에서 띄울 수 있는 에이전트는 총 1,000개입니다.

      그래서 항목을 100개 넘겨도 슬롯이 비는 대로 순서대로 전부 처리됩니다.


      4. pipeline vs parallel — 가장 중요한 선택

      이 둘의 차이가 워크플로우 설계의 핵심입니다. 기본은 항상 pipeline이고, parallel은 "정말로 모든 결과를 한꺼번에 모아야 할 때"만 씁니다.

      pipeline — 장벽 없음 (기본)

      pipeline.png

      그림 1. 항목 A와 항목 B가 각각 리뷰·검증 단계를 독립적으로 통과하는 흐름도


      A가 검증 중일 때 B는 아직 리뷰 중일 수 있습니다. 빠른 항목이 느린 항목을 기다리지 않으므로, 전체 시간은 가장 느린 한 체인이 결정합니다.

      parallel — 장벽 있음

      parallel.png

      그림 2. finder 3개가 장벽에서 전부 완료를 기다린 뒤 결과 병합으로 이어지는 흐름도


      이전 단계의 결과가 전부 모여야 다음 단계로 갈 수 있습니다. 전체 결과에서 중복을 제거한 뒤 검증하거나, 0건이면 조기 종료하는 경우가 여기 해당합니다.

      판별 기준: "다음 단계가 이전 단계의 모든 항목을 교차 참조하는가?"

      — 예(중복 제거/병합/조기 종료)면 parallel, 아니면 pipeline. "그냥 flatten/map/filter가 필요해서"는 장벽의 이유가 되지 못합니다.

      변환은 pipeline 단계 안에서 하세요.

      // 표준 패턴 — 리뷰가 끝나는 즉시 그 차원만 검증 시작 (pipeline)
      const results = await pipeline(
        DIMENSIONS,
        d => agent(d.prompt, { phase: 'Review', schema: FINDINGS }),
        review => parallel(review.findings.map(f => () =>
          agent(`적대적으로 검증: ${f.title}`, { phase: 'Verify', schema: VERDICT })
            .then(v => ({ ...f, verdict: v }))
        ))
      )
      const confirmed = results.flat().filter(Boolean).filter(f => f.verdict?.isReal)


      5. 대표 패턴

      아래는 자주 쓰는 형태들입니다. 작업 성격에 맞게 조합하면 됩니다.

      🛡️ 적대적 검증 (Adversarial verify)

      발견마다 독립적인 회의론자 N명이 반박을 시도. 과반이 반박하면 폐기. 그럴듯하지만 틀린 결과를 걸러냄.

      🧭 관점 다양화 검증

      같은 검증자 N명 대신 각자 다른 렌즈(정확성·보안·성능·재현성)를 줌. 중복으로는 못 잡는 실패 모드를 포착.

      ⚖️ 심사위원단 (Judge panel)

      서로 다른 각도로 N개 시도를 생성 → 병렬 심사로 채점 → 우승안 기반으로 종합. 해법 공간이 넓을 때 강력.

      🔁 마를 때까지 반복 (Loop-until-dry)

      크기를 모르는 발견 작업(버그·엣지케이스)에서, K번 연속 새 결과가 없을 때까지 finder를 계속 투입. 꼬리를 놓치지 않음.

      🔀 멀티모달 스윕

      컨테이너별·내용별·엔티티별·시간별 등 서로 다른 방식으로 동시 검색. 한 가지 각도로는 다 못 찾을 때.

      🔍 완전성 비평가 (Completeness critic)

      마지막에 "빠진 게 뭐냐 — 안 돌린 방식, 미검증 주장, 안 읽은 출처?"를 묻는 에이전트. 답이 다음 라운드 작업이 됨.


      6. 전체 예제 — 처음부터 끝까지

      지금까지 나온 조각을 하나로 합친 완결된 스크립트입니다.

      모듈별로 버그를 찾고, 찾은 즉시 각 발견을 적대적으로 검증해 확정된 것만 반환합니다.

      MODULES 경로만 자기 저장소에 맞게 바꾸면 그대로 돌아갑니다.

      export const meta = {
        name: 'audit-modules',
        description: '모듈별로 버그를 찾고 각 발견을 적대적으로 검증',
        phases: [
          { title: 'Find', detail: '모듈별 병렬 탐색' },
          { title: 'Verify', detail: '발견마다 반박 시도' },
        ],
      }
      
      // 스키마 — agent()가 이 형태로 검증된 객체를 돌려준다. 파싱·재시도 불필요.
      const FINDINGS = {
        type: 'object',
        properties: {
          findings: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                title: { type: 'string' },
                file: { type: 'string' },
                detail: { type: 'string' },
              },
              required: ['title', 'file', 'detail'],
            },
          },
        },
        required: ['findings'],
      }
      
      const VERDICT = {
        type: 'object',
        properties: {
          isReal: { type: 'boolean' },
          reason: { type: 'string' },
        },
        required: ['isReal', 'reason'],
      }
      
      // 대상 목록 — 외부에서 args로 넘기거나 기본값 사용
      const MODULES = args?.modules ?? ['src/auth', 'src/billing', 'src/api']
      
      log(`${MODULES.length}개 모듈 감사 시작`)
      
      const results = await pipeline(
        MODULES,
      
        // 1단계: 모듈마다 버그 탐색
        (mod) =>
          agent(`${mod} 디렉토리에서 실제로 터질 수 있는 버그를 찾아라.`, {
            label: `find:${mod}`,
            phase: 'Find',        // pipeline 안에서는 phase()가 아니라 opts.phase를 쓴다
            schema: FINDINGS,
          }),
      
        // 2단계: 그 모듈의 발견만 즉시 검증 — 다른 모듈을 기다리지 않는다
        (found, mod) => {
          if (!found?.findings.length) return []   // agent가 죽으면 null이 온다
          return parallel(
            found.findings.map((f) => () =>
              agent(
                `다음 주장을 반박해 보라: "${f.title}" (${f.file})\n${f.detail}\n` +
                  `확신이 없으면 isReal=false로 판단하라.`,
                { label: `verify:${mod}`, phase: 'Verify', schema: VERDICT },
              ).then((v) => ({ ...f, verdict: v })),
            ),
          )
        },
      )
      
      const confirmed = results
        .flat()
        .filter(Boolean)                      // 죽은 에이전트는 null로 떨어진다
        .filter((f) => f.verdict?.isReal)
      
      log(`확정 ${confirmed.length}건`)
      return { confirmed }

      읽을 때 짚어볼 지점 네 곳입니다.

      • 2단계의 두 번째 인자 modpipeline의 각 단계는 (이전 결과, 원본 항목, 인덱스)를 받습니다. 그래서 1단계 반환값에 모듈명을 끼워 넣어 나르지 않아도 됩니다.

      • pipeline 안의 parallel — 겉은 장벽 없이 흐르고, 안에서 한 모듈의 발견들만 동시에 검증합니다. 4장의 판별 기준이 그대로 적용된 형태입니다.

      • phase() 대신 opts.phasepipeline·parallel 안에서는 전역 phase() 상태가 경쟁할 수 있어 옵션으로 직접 지정합니다.

      • 필터가 두 번 — 단계 자체가 실패한 항목은 null로 떨어지므로 filter(Boolean)이 걸러내고, 검증 에이전트가 죽어 verdictnull인 항목은 뒤의 verdict?.isReal이 걸러냅니다. 에이전트는 죽을 수 있다고 전제하고 씁니다.


      7. 언제 쓰고, 언제 쓰지 않나

      ✅ 적합

      ✋ 부적합

      전수 감사·리뷰·리서치 (병렬 팬아웃)

      대화형 한 턴짜리 응답

      대규모 마이그레이션 (사이트 발견 → 변환 → 검증)

      사소한 기계적 편집

      독립 관점의 교차/적대적 검증이 필요한 작업

      흐름이 단순해 단일 에이전트로 충분한 일

      한 컨텍스트에 안 담기는 규모

      사용자가 명시적으로 요청하지 않은 대규모 팬아웃

      중요한 전제: Dynamic Workflow는 한 번에 수십에서 수백 개의 에이전트를 띄우고 그만큼 토큰을 씁니다. 그래서 기본값은 직접 요청했을 때만 실행되는 쪽입니다

      — 프롬프트에 ultracode 키워드를 넣거나 "워크플로우로 처리해줘"처럼 말하거나, 저장해 둔 워크플로우를 /이름으로 부르는 방식입니다.

      반대로 /effort ultracode를 켜 두면 매 작업마다 Claude가 알아서 판단해 워크플로우를 씁니다.

      예산으로 깊이를 조절한다

      비용이 문제라면 깊이를 예산에 맡길 수 있습니다.

      스크립트 안에서 budget으로 남은 토큰을 조회할 수 있어서, 몇 개를 돌릴지 미리 정하는 대신 예산이 마를 때까지 돌리는 식으로 쓸 수 있습니다.

      const bugs = []
      // budget.total이 없으면 remaining()은 Infinity → 가드 필수
      while (budget.total && budget.remaining() > 50_000) {
        const r = await agent('이 코드베이스에서 버그를 찾아라', { schema: BUGS })
        bugs.push(...r.bugs)
        log(`${bugs.length}개 발견, ${Math.round(budget.remaining()/1000)}k 남음`)
      }

      루프 대신 고정 규모를 정하는 방식도 같은 요령입니다. budget.total을 나눠 finder 수를 계산하면, 예산이 클수록 더 많이 투입됩니다.

      실전에서는 하이브리드

      먼저 인라인으로 정찰(파일 나열, 범위 파악)해 작업 목록을 발견한 뒤, 그 목록을 워크플로우로 파이프라인 처리하는 형태가 많습니다.

      작업 전에 모든 걸 알 필요는 없고, 오케스트레이션 단계 전에만 알면 됩니다.


      직접 해보기: 가장 빠른 길은 기본 내장 워크플로우입니다.

      /deep-research <질문>을 실행하면 여러 에이전트가 출처를 교차검증해 리포트를 만들어내는 과정을 그대로 볼 수 있습니다.

      내 작업에 쓰려면 프롬프트에 ultracode를 넣거나 "워크플로우로 처리해줘"라고 요청하면 됩니다.

      진행 상황은 /workflows에서 실시간으로 볼 수 있고, 마음에 든 실행은 그 화면에서 s 키로 내 명령어로 저장할 수 있습니다.


      Claude Code v2.1.154 이상, 유료 플랜에서 동작합니다(Pro는 /config의 Dynamic workflows를 켜야 합니다).

      Anthropic API, Amazon Bedrock, Google Cloud Agent Platform, Microsoft Foundry에서도 지원됩니다.



      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      한성원 님의 최신 블로그

      더보기

      DEVOTEE 추천 블로그

      동영상 기고하기