X Article · Wayne @waynoir · 2026-08-12 · 조회 4.9만

제로에서 그래프 아키텍트까지: Claude 그래프 엔지니어링 14단계 로드맵

선형 체인으로 굳어진 멀티에이전트 파이프라인을 "무엇이 무엇에 의존하는가"의 그래프로 재설계하고, Claude Code dynamic workflows로 실제 구동하는 14단계.

읽기 전에
멀티에이전트 파이프라인을 "다음에 뭐 하지"의 일직선이 아니라, "무엇이 무엇에 실제로 의존하는가"의 그래프로 재설계하려면 어떻게 해야 하는가?

파이프라인 = 그래프. 노드 = 경계 있는 작업 1개(에이전트 1·입력 1·출력 1), 엣지 = "and then"이 아니라 데이터 소비 사실 — 다음 노드가 앞 노드의 출력을 실제로 읽을 때만 존재. 대부분의 체인은 데이터를 나르지 않는 가짜 화살표 2~3개를 품고 있고, 그것을 지우는 순간 병렬성이 공짜로 나온다. Claude Code의 dynamic workflows(agent() + JSON 스키마 계약, parallel())가 이 그래프를 실제로 구동하는 런타임.

권장 읽기 순서

  • §1→§2 먼저 — "엣지 = 데이터 소비 사실"이라는 정의 하나가 글 전체의 축. 이거 없이 뒤를 읽으면 코드 나열로 보임.
  • §5(parallel 팬아웃) → §7(다이아몬드 패턴) — 실전 골격. 이력서 300건 스크리닝 예제가 여기서 완성됨.
  • §9(클린 슬레이트 검증자) — 속도가 아니라 신뢰성을 만드는 단 하나의 장치. 가장 재사용 가치 높은 통찰.
  • §13(배리어 vs 스트리밍) + §14(Claude가 그래프를 직접 작성) — 비용 최적화와 자동화의 끝단. 나머지(§3·4·6·8·10·11·12)는 위 골격의 세부 규율이라 필요할 때 참조해도 충분.
  • 마지막 두 절(Where this roadmap doesn't apply / The actual shift)은 짧지만 적용 한계를 긋는 부분이라 건너뛰지 말 것.

모르면 막히는 선행 개념

  • Claude Code 서브에이전트 개념 (독립 컨텍스트에서 도는 하위 에이전트)
  • JSON Schema 기초 (agent()의 출력 계약 강제에 사용)
  • DAG·팬아웃/팬인·배리어 같은 그래프 실행 용어 감각

예상 소요 — 요약만: 3분 / 완독: 12분

  1. "파싱하고 나서 날씨를 확인한다"에 엣지가 없는 이유는? 내 파이프라인에서 데이터를 나르지 않는 "and then"은 어디인가?
  2. 검증자 에이전트에게 워커의 대화 컨텍스트를 보여주면 안 되는 이유는 무엇이며, 대신 무엇만 주어야 하는가?
  3. parallel() 배리어가 비용을 정당화하는 경우 3가지는? "코드가 깔끔해서"가 이유가 안 되는 근거는?

Executive Summary

대부분의 멀티에이전트 파이프라인은 "이거 하고, 저거 하고"식 선형 체인으로 짜이지만, 그 순서의 절반은 실제 의존성이 아니라 그냥 타이핑된 순서일 뿐이라는 게 이 글의 출발점이다. 저자는 파이프라인을 그래프로 재설계하는 14단계 로드맵을 제시한다 — 독립 작업은 동시에 돌리고, 결과는 집계 전에 검증하며, 한 대화가 머리에 담을 수 있는 규모를 넘어 확장하라는 것. 각 개념은 Claude Code의 내장 실행 메커니즘인 dynamic workflows(agent(), parallel(), JSON schema)와 짝지어지며, 전 단계를 관통하는 running example은 이력서 스크리닝 파이프라인이다.

저자 Wayne (@waynoir) · 게시 2026-08-12 00:26 KST · 형식 X 장문 아티클 · 조회 4.9만 (리포스트 102 · 좋아요 177) · running example = 이력서 스크리닝 파이프라인 · 실행 기반 = Claude Code dynamic workflows

① 그래프 개념 재정의 (§1–2)

노드 = 경계 지어진 작업 1개(에이전트 1·입력 1·출력 1), 엣지 = "and then"이 아니라 데이터 소비 사실 — 다음 노드가 앞 노드의 출력을 실제로 읽을 때만 엣지가 존재한다("이력서 파싱 후 날씨 확인"엔 엣지가 없다). 선형 체인도 기술적으론 그래프지만 나쁜 그래프: 노드마다 in/out 엣지 1개뿐이라 C가 멈추면 D는 영영 안 돌고 상류 결과는 완성된 채 방치된다. 첫 번째 실전 기술 = 체인의 화살표마다 "데이터를 나르나?"를 물어 다시 그리기 — 대부분의 체인엔 데이터 없이 순서만 남은 화살표가 2–3개 있다.

② 계약 (§3–4)

고립 상태로 추론 불가능한 노드는 병렬화 불가능한 노드 — 해법은 계약: 정의된 입력·출력·단일 임무, 공유 대화에서 암묵적으로 끌어오는 것 없음. Claude Code에선 agent()에 JSON schema를 넘겨 강제하며(예: VERDICT = eligible/fit_score/reasoning), 스키마 불일치 시 Claude가 자동 재시도해 자유 텍스트 수동 파싱을 없앤다. 엣지도 데이터 계약이다: "A가 이 정확한 shape을 생산하고 B가 그것을 소비한다"는 약속 — 엣지를 순서가 아니라 데이터로 명명하면 shape이 유지되는 한 어느 쪽 노드든 교체 가능하다.

③ 병렬 실행 (§5–7)

독립 작업 N개(이력서 300장, 파일 40개 감사)는 체인 금지 — parallel()이 thunk 배열을 받아 thunk당 서브에이전트 1개를 띄운다. 디테일 2개: parallel()배리어(전부 끝나야 다음 스테이지)이며, 실패한 에이전트 1개는 배치를 죽이지 않고 null로 해석되므로 .filter(Boolean)을 항상 직후에 붙인다. fan-in은 전체 집합이 진짜 필요할 때만(중복 제거·랭킹·빈 결과 조기 종료) — 리스트 평탄화는 배리어의 이유가 아니라 그냥 평범한 코드다. fan-out+fan-in = 다이아몬드(분할→병렬 작업→병합): 데이터와 프롬프트만 바꾸면 이력서 스크린·보안 감사·리서치 리포트를 같은 골격이 커버한다.

④ 제어 흐름 (§8, §11)

런타임 분기는 프롬프트가 아니라 코드의 if: 분류는 Claude(서브에이전트)가 해도 되지만 분기 자체는 코드에 있어야 어느 케이스가 어느 경로로 갔는지 모호함이 없다(borderline 이력서 → 패널 리뷰, 명백한 reject → 빠른 체크). 크기를 미리 알 수 없는 작업(미지수의 auth 버그, 미지수의 borderline 지원자)엔 사이클을 허용하되 수렴을 강제 — loop-until-dry: 연속 n라운드 신규 발견 0이면 종료. 실제로 작동하게 하는 디테일 = 확정 결과가 아니라 이제껏 본 모든 것에 대해 dedupe(안 그러면 기각된 발견이 매 라운드 재등장해 루프가 마르지 않는다).

⑤ 신뢰성 (§9–10)

그래프를 빠를 뿐 아니라 신뢰 가능하게 만드는 단일 최대 요소 = clean-slate 검증자: 작업자의 추론을 본 적 없는 체커. 같은 대화를 읽은 검증자는 이미 답에 앵커링돼 "검증으로 분장한 동의"만 내놓는다 — 진짜 검증자는 원자료(이력서+JD)만 받고 독립적으로 결론에 도달해야 한다. 격리: 실패 전파는 thunk→null이 대부분 처리하지만, 병렬 노드들이 같은 파일에 쓰면 실제 충돌이 난다 — Claude Code의 답은 worktree 격리(에이전트별 git checkout 샌드박스, 끝에 clean merge). 단, 병렬 쓰기가 실제로 있을 때만 — 매 실행에 내는 세금이 아니다.

⑥ 성능·운영 (§12–14)

모델 티어링: 서브에이전트는 기본적으로 세션 모델을 상속하지만, 반복적·경계 지어진 노드(빠른 자격 체크)는 agent()의 model 옵션으로 싼 모델로 라우팅 — 그래프 모양은 안 건드린다. 기본값은 배리어가 아니라 스트리밍: 배리어는 가장 느린 항목을 전원이 기다리게 하고, 스트리밍은 이력서 #4가 검증 단계에 있는 동안 #180이 아직 파싱 중일 수 있다 — 배리어는 cross-batch dedupe·랭킹·빈 총합 조기 종료처럼 전체 집합이 필요할 때만("코드가 깔끔해서"는 이유가 아님, 배리어 지연은 실측 가능한 비용). 그래프 작성 자체를 Claude에게: 프롬프트에 "workflow"라 말하거나 ultracode 설정을 켜면 Claude가 fan-out·스키마·검증·병합을 태스크 맞춤으로 직접 설계; /workflows로 라이브 관찰, s~/.claude/workflows/에 저장·재실행. 상한 = 동시 16 에이전트 / 런당 1,000 (폭주 방지 하드 실링); Max·Team·Enterprise 기본 on, Pro는 /config 토글.

⑦ 적용 제외 + 핵심 전환

쓰지 말아야 할 곳 3가지: (1) 단일 이력서·일회성 버그픽스처럼 조정 비용보다 단독 에이전트가 빠른 소규모 작업, (2) 단계들이 진짜로 순차 의존이라 착취할 독립성이 없는 경우(쪼개면 오버헤드만 추가), (3) 모든 중간 결과를 사람이 직접 읽고 승인할 계획일 때 — 그래프의 장점(감시 없이 넓게 돌리기)이 목표와 충돌한다. 핵심 전환: 물을 질문은 "다음에 뭘 해야 하나"(→ 더 긴 체인만 낳는다)가 아니라 "무엇이 실제로 무엇에 의존하고, 무엇은 아닌가" — 그 답이 나오면 일은 더 긴 프롬프트 쓰기가 아니라 작업이 흐르는 모양(shape)을 결정하는 것이 되고, 그 모양이 결과가 빠르고 신뢰할 만한지, 아니면 몇 개를 하나씩 처리하는 비싼 방법인지를 가른다.

팩트체크
A- 핵심 기능 서술(프리미티브·상한·플랜 정책·모델 라우팅)은 Anthropic 공식 문서와 거의 완전 일치 — 어긋나는 곳은 키워드 명칭·저장 위치·워크트리 자동 머지 등 소수 세부의 단순화뿐이다.
Claude Code에 agent()/parallel() 프리미티브로 오케스트레이션 스크립트를 돌리는 "dynamic workflows"가 실재한다 — 공식 문서가 "A dynamic workflow is a JavaScript script that orchestrates subagents at scale"로 정의하고, Agent SDK 레퍼런스가 스크립트 본문의 프리미티브를 agent(), parallel(), pipeline(), phase() 4종으로 명시한다 (v2.1.154+, 2026-05-28 Opus 4.8과 함께 출시). code.claude.com — Dynamic workflows · Agent SDK reference — Workflow tool
agent()에 JSON 스키마를 넘기면 구조화 출력이 강제되고, 불일치 시 자동 재시도한다 — 공식 문서의 저장 스크립트 예시가 agent(…, { schema: {…} }) 형태를 그대로 보여주고, 구조화 출력 문서가 "the SDK validates the output against it, re-prompting on mismatch"라고 확인. 단 재시도는 무한이 아니라 한도 초과 시 에러(error_max_structured_output_retries)로 끝난다. Dynamic workflows — 스크립트 예시 · Structured outputs — 재시도 규칙
🟡 parallel()은 배리어이고, thunk가 throw하면 크래시 대신 null로 해석된다 — 그래서 filter(Boolean) — null + .filter(Boolean) 패턴 자체는 공식 문서가 확인하지만, 공식 표현은 "An agent() call resolves to null if you stop it mid-run or it hits an unrecoverable API error"(중단·복구불가 API 에러 기준, pipeline 예시). "thrown thunk → null"과 parallel()의 배리어 성격은 서드파티 심층 분석("It is a barrier… A thunk that throws resolves to null")으로만 교차 확인된다. Dynamic workflows — null/filter(Boolean) · alexop.dev — parallel() 배리어 분석
🟡 파일을 쓰는 병렬 에이전트에는 워크트리 격리 옵션이 있다 — 격리 자체는 사실: 서브에이전트 frontmatter isolation: worktree와 Agent 툴의 isolation?: "worktree" 필드가 공식 문서에 있고, 워크플로우 예시도 "each file in its own isolated copy"를 권한다. 다만 기사에서 "끝에 깨끗이 머지된다(merges cleanly at the end)"는 서술은 문서 근거가 없다 — 문서상 변경 없는 워크트리는 자동 삭제, 변경 있는 워크트리는 디스크에 남아 주기적 청소 대상이며 자동 머지는 명시되지 않는다. code.claude.com — Isolate subagents with worktrees
agent() 호출별 model 옵션으로 특정 노드만 싼 모델로 라우팅할 수 있고, 기본값은 세션 모델 상속 — 공식 문서: "Every agent in a workflow uses your session's model unless the script routes a stage to a different one"; Agent 툴 스키마에도 model?: "sonnet" | "opus" | "haiku" | … 필드가 있다. Dynamic workflows — Cost/모델 라우팅 · Agent SDK reference — Agent tool
🟡 배리어 대신 스트리밍 파이프라인 대안이 있고, 기본값으로 스트리밍이 권장된다pipeline()의 존재는 공식 확인(문서의 저장 스크립트 예시가 pipeline을 사용, "pipeline() runs one per item in a list"). 그러나 "기본으로 pipeline을 쓰라"는 권고는 공식 문서에 없고, 서드파티 분석("Default to pipeline(). Reach for a parallel() barrier… only when a stage needs all prior results")과 일치하는 베스트프랙티스 수준이다. Dynamic workflows — pipeline() 예시 · alexop.dev — pipeline 우선 권고
🟡 프롬프트에 "workflow"라고 말하거나 ultracode를 켜면 Claude가 그래프를 대신 짜고, /workflows로 실황을 보며, s로 ~/.claude/workflows/에 저장한다 — 큰 줄기는 사실: 자연어 요청("use a workflow")과 /effort ultracode 트리거, /workflows 실황 뷰(phase별 에이전트 수·토큰·경과시간), s 저장 모두 공식 문서와 일치. 세부 2곳이 부정확 — 리터럴 트리거 키워드는 v2.1.160부터 workflowultracode로 변경됐고, 저장 위치는 ~/.claude/workflows/(개인)와 프로젝트 .claude/workflows/(공유) 중 선택인데 기사는 전자만 언급한다. Dynamic workflows — 트리거·/workflows·저장
상한: 동시 16 에이전트, 런당 총 1,000 에이전트 — 공식 제한 표 그대로: "Up to 16 concurrent agents, fewer when Claude Code has fewer CPUs available", "1,000 agents total per run — prevents runaway loops". (CPU가 적으면 16보다 줄어드는 뉘앙스만 기사에서 생략.) Dynamic workflows — Behavior and limits
Max/Team/Enterprise는 기본 활성, Pro는 /config에서 토글 — 공식 문서: "available on all paid plans… On Pro, turn them on from the Dynamic workflows row in /config"; Anthropic 공식 블로그도 "on by default for Max, Team, and Enterprise plans"를 확인. Dynamic workflows — 플랜 정책 · Anthropic 블로그 — Introducing dynamic workflows
🟡 [저자 주장/베스트프랙티스] 검증자는 작업자의 대화를 못 본 깨끗한 컨텍스트여야 하고, 루프는 "지금까지 본 전부"에 대해 dedupe해야 마른다 — 공식 문서가 같은 방향을 지지한다: 워크플로우의 강점으로 "independent agents adversarially review each other's findings"를 들고, 번들 /deep-research도 독립 교차검증 구조이며, 예시 프롬프트에 "stop once two rounds in a row find nothing new"(loop-until-dry)가 그대로 등장한다. 다만 "기각된 발견까지 포함해 dedupe"라는 구체 규칙은 문서에 없는 저자의 엔지니어링 판단이다. Dynamic workflows — 검증 패턴·예시 프롬프트

원본 (완역)
From Zero to Graph Architect 커버 이미지
커버 — From Zero to Graph Architect: Claude와 함께하는 그래프 엔지니어링 14단계 로드맵

멀티에이전트 파이프라인을 만드는 사람 대부분은 결국 일직선으로 끝난다. 이걸 하고, 그다음 이걸 하고, 그다음 이걸 하고 — 그러면서 왜 모든 단계가 앞 단계를 기다리고 있는지는 한 번도 의심하지 않는다. 그 순서의 절반은 실체가 없다. 그냥 누군가 단계를 입력한 순서일 뿐이다.

이 글은 그것을 알아차리고 더 나은 것을 만드는 로드맵이다. 바로 그래프다. 독립적인 작업은 동시에 돌고, 결과는 인정되기 전에 검증되며, 전체는 하나의 대화가 머릿속에 담을 수 있는 규모를 넘어서 확장된다. Claude Code에는 이것을 실제로 실행하는 내장 방법이 있는데, dynamic workflows라고 부른다. 그래서 이 로드맵은 각 아이디어마다 실제로 구현하는 방법을 짝지어 설명하며, 이력서 스크리닝 파이프라인을 관통 예제로 사용한다.

본론에 들어가기 전에, 이런 아티클을 더 보고 싶다면 X에서 나를 팔로우하라.
X - https://x.com/waynoir

1. 노드는 작업이고, 엣지는 사실이다

노드(node)는 경계가 정해진 하나의 작업 단위다. 에이전트 하나, 입력 하나, 출력 하나. 엣지(edge)는 "그다음에"가 아니다. 엣지는 한 노드의 출력이 다른 노드에 의해 실제로 소비될 때만 존재한다. "이력서를 파싱하고, 그다음에 날씨를 확인한다"에는 엣지가 없다. 날씨 확인은 이력서를 읽지 않기 때문이다. 그렇게 사슬로 묶인 두 노드는 아무 이유 없이 큐 하나를 공유하고 있을 뿐이다.

기를 만한 습관은 이것이다. 파이프라인의 모든 "그다음에"마다, 다음 단계가 앞 단계의 산출물을 읽는지 물어라. 읽지 않는다면 엣지는 없는 것이고, 하나가 다른 하나를 기다릴 이유도 없다.

노드와 엣지의 관계를 보여주는 다이어그램
노드는 작업, 엣지는 데이터가 실제로 흐를 때만 존재하는 사실

2. 당신의 일직선 에이전트는 이미 그래프다, 다만 나쁜 그래프일 뿐

"A를 하고, B를 하고, C를 하고, D를 한다"도 엄밀히 말하면 그래프다. 모든 노드가 정확히 들어오는 엣지 하나와 나가는 엣지 하나를 가지는 사슬(chain)이다. 작동은 하지만 취약하다. C가 멈추면 D는 영영 실행되지 않고, 그 상류에 있는 모든 것은 완료된 채로 쓸모없이 그냥 앉아 있게 된다.

사슬을 다시 그리는 것이 여기서 첫 번째 진짜 기술이다. 화살표 하나하나를 붙잡고 1단계의 질문을 던져라. 대부분의 사슬에는 데이터를 실어 나른 적이 한 번도 없는 화살표가 두세 개 있다. 그저 남겨진 순서일 뿐이다.

3. 모든 노드에 계약을 부여하라

고립된 상태로 추론할 수 없는 노드는 병렬화할 수 없는 노드다. 해법은 계약(contract)이다. 정의된 입력, 정의된 출력, 하나의 작업, 공유된 대화에서 암묵적으로 끌어오는 것은 아무것도 없어야 한다.

Claude Code의 dynamic workflow에서 이 계약은 agent()에 전달하는 JSON schema로 강제된다. 서브에이전트는 검증된 구조화 데이터를 반환하도록 강제된다. schema와 맞지 않으면, 손으로 파싱해야 할 자유 텍스트를 넘겨주는 대신 Claude가 자동으로 재시도한다.

const VERDICT = {
  type: 'object',
  additionalProperties: false,
  properties: {
    eligible: { type: 'boolean' },
    fit_score: { type: 'number' },
    reasoning: { type: 'string' },
  },
  required: ['eligible', 'fit_score', 'reasoning'],
};

const result = await agent(`Screen this resume against the JD:\n${resume}`, {
  label: `screen:${resume.id}`,
  schema: VERDICT,
});

4. 엣지를 순서가 아니라 데이터 계약으로 취급하라

엣지는 약속이다. 노드 A는 정확히 이 형태를 생산하고, 노드 B는 그것을 소비하도록 만들어져 있다. 엣지를 순서가 아니라 데이터로 명명하면, 형태만 유지되는 한 어느 쪽 노드든 더 나은 것으로 교체해도 다른 어떤 것도 깨지지 않는다.

5. parallel()로 팬아웃하라

이것이 로드맵의 나머지 전부를 값어치 있게 만드는 한 수다. N개의 독립적인 작업이 주어졌을 때 — 예컨대 스크리닝할 이력서 300건이나 감사할 파일 40개 — 그것들을 사슬로 묶지 마라. parallel()은 썽크(thunk) 배열을 받아, 썽크당 서브에이전트 하나를 띄우고, 전부를 기다린다.

phase('Screen');
const raw = await parallel(
  APPLICANTS.map((a) => () => agent(a.prompt, { schema: VERDICT, label: `screen:${a.id}` }))
);
const collected = raw.filter(Boolean); // a thrown thunk resolves to null, not a crash

여기서 두 가지 디테일이 중요하다. parallel()은 배리어(barrier)다. 모든 썽크가 resolve되기 전까지는 그 뒤의 어떤 것도 실행되지 않으므로, 다음 스테이지는 완전한 집합을 보게 된다. 그리고 실패한 에이전트 하나는 배치 전체를 무너뜨리는 대신 null로 resolve된다. 그래서 .filter(Boolean)이 항상 그 바로 뒤에 붙어야 하는 것이다.

6. 팬인은 스테이지가 진짜로 전체 집합을 필요로 할 때만

팬인(fan-in)은 결과가 수렴하는 곳이다. 중복 제거, 순위 매기기, 아무것도 돌아오지 않았을 때의 조기 종료. 배리어가 그 비용값을 하는 유일한 지점인데, 어떤 결정들 — 이를테면 이 300건 중 어떤 것들이 실제로 서로의 중복인가 — 은 전원을 한꺼번에 보지 않고는 내릴 수 없기 때문이다.

합치는 작업이 정말로 리스트를 평탄화하는 것뿐이라면, 그건 배리어를 둘 이유가 아니다. 그냥 평범한 코드다.

const flat = collected.filter((c) => c.eligible).sort((a, b) => b.fit_score - a.fit_score);

7. 다이아몬드: 쪼개고, 일하고, 짜내고, 결정한다

팬아웃과 팬인을 합치면 거의 모든 진지한 파이프라인 뒤에 있는 형태가 나온다. 노드 하나가 작업을 쪼개고, 여러 노드가 병렬로 일하고, 노드 하나가 병합한다. 소스 데이터와 프롬프트만 바꾸면, 같은 뼈대가 이력서 스크리닝도, 보안 감사도, 리서치 리포트도 커버한다.

다이아몬드 패턴 다이어그램: 분기-병렬 작업-병합
다이아몬드 패턴 — 하나가 쪼개고, 여럿이 일하고, 하나가 병합한다

8. 런타임 라우팅은 프롬프트가 아니라 조건문으로

때로는 다음 단계가 노드가 발견한 것에 따라 달라진다. 애매한(borderline) 이력서는 더 자세히 들여다보고, 명백한 탈락은 그러지 않는다. 그 라우팅 판단 자체는 Claude가 담당할 수 있지만(서브에이전트가 분류한다), 분기 자체는 코드로 쓰인 평범한 if다.

const { severity } = await agent(`Classify this application:\n${a}`, { schema: TIER });
let review = severity === 'borderline'
  ? await parallel(PANEL.map((p) => () => agent(`Review as ${p}: ${a}`)))
  : await agent(`Quick check: ${a}`);

라우팅이 코드에 살고 있기 때문에, 어떤 케이스가 어떤 경로를 탔는지에 대한 모호함이 없다. 같은 분류에 대해서는 매번 같다.

조건부 라우팅 다이어그램
분류는 에이전트가, 분기는 코드의 if가 담당하는 런타임 라우팅

9. 엣지에 검증자를 두되, 백지 상태를 주어라

그래프를 그저 빠른 것이 아니라 신뢰할 수 있는 것으로 만드는 단 하나의 가장 큰 요소: 첫 번째 에이전트의 추론을 본 적이 없는 검사자다. 작업자가 쓴 것과 같은 대화를 읽는 검증자는 아무것도 검증하고 있지 않다. 이미 하나의 답에 정박(anchoring)되어 있고, 그 같은 컨텍스트 안에서 재고를 요청해 봐야 대부분 검증으로 분장한 동의만 나온다.

독립 검증자 다이어그램
검증자는 작업자의 대화가 아니라 원자료만 받아야 한다

진짜 검증자는 원자료만 받는다. 이력서와 직무 기술서(JD), 그 외에는 아무것도 받지 않고, 독립적으로 스스로의 결론에 도달해야 한다.

10. 하나의 실패나 하나의 쓰기 충돌이 번지지 않도록 노드를 격리하라

parallel() 안에서 throw된 썽크는 배치를 크래시시키는 대신 이미 null로 resolve되므로, 실패 봉쇄의 대부분은 그것으로 처리된다. 더 미묘한 위험은 같은 파일에 쓰는 노드들이다. 여러 에이전트가 겹치는 파일을 병렬로 건드리면, 정말로 충돌할 수 있다.

Claude Code의 답은 worktree 격리다. 각 병렬 에이전트가 자기만의 git 체크아웃을 받아, 샌드박스 안에서 작업하고, 마지막에 깔끔하게 병합한다. 노드들이 실제로 병렬로 쓰기를 할 때만 꺼내 드는 것이지, 모든 실행마다 치러야 하는 세금이 아니다.

11. 사이클을 추가하되, 수렴을 강제하라

어떤 작업은 시작 시점에 크기를 알 수 없다. 개수를 모르는 인증 누락(missing-auth) 버그라든지, 개수를 모르는 재검토가 필요한 애매한 지원서라든지. 그럴 때 필요한 것이 사이클이다. 앞선 노드로 되돌아가는 통제된 엣지.

loop-until-dry 사이클 다이어그램
사이클은 loop-until-dry — 연속 N라운드 동안 새것이 없으면 멈춘다

사이클이 영원히 돌지 않게 하는 패턴은 loop-until-dry다. 연속된 몇 라운드 동안 새로운 것이 아무것도 나오지 않을 때까지 계속하고, 그러면 멈춘다. 이것이 실제로 작동하게 만드는 디테일은, 확정된 결과만이 아니라 지금까지 본 모든 것에 대해 중복 제거를 하는 것이다. 그러지 않으면 기각된 발견이 매 라운드 다시 나타나서 루프가 영영 마르지 않는다.

12. 노드별로 모델을 티어링하라

모든 노드에 최고 모델이 필요한 것은 아니다. 이력서의 빠른 자격 요건 체크는 범위가 한정되고 반복적이다. 최종 쇼트리스트를 종합하고 그 뒤의 근거를 작성하는 일이야말로 판단력이 실제로 사는 곳이다. 기본적으로 workflow가 띄우는 모든 서브에이전트는 세션의 모델을 상속받는다. 개별 agent() 호출의 model 옵션이야말로, 그래프의 형태는 건드리지 않은 채 특정 노드만 더 저렴한 곳으로 라우팅하게 해주는 수단이다.

13. 배리어가 아니라 스트리밍을 기본값으로

조용히 가장 많은 실제 소요 시간(wall-clock time)을 잡아먹는 선택은 parallel() 대 스트리밍 파이프라인이다. parallel() 배리어는 다음 스테이지가 시작되기 전에 모든 항목이 가장 느린 하나를 기다리게 만든다. 스트리밍은 빠른 항목들이 스스로 모든 스테이지를 통과해 나아가게 한다. 이력서 #180이 아직 파싱 중일 때 이력서 #4는 이미 검증 스테이지에 가 있을 수 있다.

배리어 대 스트리밍 파이프라인 비교 다이어그램
배리어는 가장 느린 항목을 전원이 기다리게 하고, 스트리밍은 각자 나아가게 한다

배리어는 한 스테이지가 진짜로 전체 집합을 한꺼번에 필요로 할 때만 꺼내라. 배치 간 중복 제거, 점수 기준 순위 매기기, 총합이 비었을 때의 조기 종료. "코드가 더 깔끔해서"는 이유가 아니다. 배리어 지연은 실재하며 측정 가능하다.

14. 그래프를 Claude가 대신 그리게 하라

마지막 한 수는, 사전에 완전히 계획할 수 없는 작업에 대해서는 그래프를 손으로 그리는 것을 그만두는 것이다. Claude Code 프롬프트에 "workflow"라는 단어를 말하거나 ultracode effort 설정을 켜면, Claude가 오케스트레이션 스크립트 자체를 작성한다. 팬아웃, schema, 검증 패스, 병합까지, 고정된 템플릿이 아니라 실제로 기술된 작업에 맞춰서 결정한다. /workflows는 실행을 라이브로 보여준다 — 지금 어느 페이즈인지, 에이전트가 몇 개나 끝났는지 — 그동안 세션은 다른 작업을 위해 자유롭게 남는다. 좋은 실행은 s로 저장할 수 있고, ~/.claude/workflows/에 이름 붙은 스크립트로 남아 나중에 다시 실행할 준비가 된다.

Claude가 workflow를 자동 생성하는 화면
"workflow" 한 단어로 Claude가 오케스트레이션 스크립트를 직접 작성한다

Dynamic workflows는 동시 실행 에이전트 16개, 실행당 1,000개가 상한이다. 코드베이스 전체 마이그레이션이 아닌 이상 거의 무엇이든 담을 만큼 넓고, 스코프가 잘못 잡힌 실행이 무한정 에이전트를 띄우는 것을 막는 확실한 천장이기도 하다. Max, Team, Enterprise 플랜에서는 기본으로 켜져 있고, Pro에서는 /config의 토글이다.

이 로드맵이 적용되지 않는 곳

이력서 한 건, 일회성 버그 픽스, 혹은 조율 체계를 만드는 시간보다 에이전트 하나가 끝내는 게 더 빠를 만큼 작은 일에는 이 중 어떤 것도 세팅할 가치가 없다. 단계들이 정말로 순차적으로 서로 의존하는 곳에서도 잘못된 도구다. 착취할 독립성이 없으니, 쪼개 봐야 오버헤드만 늘어난다. 그리고 모든 중간 결과를 직접 읽고 승인할 계획이라면, 그래프의 핵심 이점 — 아무도 각 단계를 지켜보지 않은 채 넓게 돌리는 것 — 이 오히려 그 목표에 반해서 작동한다.

진짜 전환

물을 가치가 있는 질문은 애초에 "다음에 무엇이 일어나야 하는가"가 아니었다. 그 질문은 더 긴 사슬만 만들어낼 뿐이다. 파이프라인을 만드는 방식을 바꾸는 질문은 "무엇이 실제로 무엇에 의존하고, 무엇은 의존하지 않는가"다. 그 질문에 답하고 나면, 할 일은 더 이상 더 긴 프롬프트를 쓰는 것이 아니다. 작업이 흘러가는 형태를 결정하는 것이고, 그 형태가 결과물이 빠르고 신뢰할 수 있는 것이 될지, 아니면 그저 몇 가지 일을 하나씩 처리하는 비싼 방법이 될지를 결정한다.

AI에서 일어나는 모든 것을 계속 따라잡고 싶다면.
X에서 나를 팔로우하라 : https://x.com/waynoir


원본 링크·인용

기타

2026-08-14 · 원문 게시 2026-08-12 · 팩트체크 기준일 2026-08-14 · dosi.dev