Figma 퍼블리싱 파이프라인 03. 병렬화 시도와 토큰 폭발 악몽
V02의 스킬 시스템을 프로덕션에 투입했다. 처음엔 괜찮았다. 하지만 복잡한 페이지를 처리하다가 갑자기 토큰 게이지가 폭주했다. 원인을 추적해보니 서브에이전트가 66개나 동시에 실행되고 있었다.
병렬화 아이디어: 순차에서 병렬로
V02에서 기본 구조는 잘 작동했다. 하지만 성능이 문제였다. 섹션 5개를 처리하는 데 순차로 5배 시간이 걸린다. 병렬로 처리할 수 있으면 가장 느린 1개 섹션만큼만 걸린다.
Figma MCP의 get_design_context는 한 번에 반환할 수 있는 데이터량에 한계가 있다. 큰 프레임을 통째로 조회하면 하위 레이어가 조용히 잘린다.
get_metadata를 먼저 호출하면 전체 노드 트리를 XML 형태로 받을 수 있다. 이 트리를 보고 기능 단위로 분리한 뒤, 각 영역을 개별 get_design_context로 조회하면 누락이 거의 없어진다.
실제 노드 트리 예시
병렬 퍼블리싱 구조
각 서브에이전트는 자기 파일만 생성하고, 최종 조립은 메인 세션이 순차적으로 한다.
기존 방식과 비교
| 항목 | 기존 (순차) | 병렬 |
|---|---|---|
| 디자인 조회 | 1회 통째로 → 잘림 발생 | 영역별 개별 조회 → 누락 없음 |
| 구현 속도 | 순차 합산 시간 | 가장 느린 1개 시간 (2~3배 빠름) |
| 누락 대응 | 완성 후 발견 → 재작업 | 사전에 노드 트리로 전수 확인 |
| 컨텍스트 소모 | 메인 세션에 모든 코드 누적 | 서브에이전트가 분산 처리 |
악몽: 66개 에이전트 폭발
평소처럼 Figma 시안 퍼블리싱을 맡기고 자리를 비웠다가 돌아오니 토큰 게이지가 37%를 가리키고 있었다. 페이지 하나 퍼블리싱하는 동안 거의 1분에 3%씩 오르고 있었다.
원인을 추적해보니 백그라운드에서 claude -p 프로세스가 66개 동시에 돌고 있었다.
아키텍처 이해
PHASE 0~1.5는 Python + Figma API만 사용해 LLM 토큰이 0이다. 모든 토큰 소비는 PHASE 2에서 발생한다.
근본 원인: 섹션 분할 로직의 절벽
figma_publish.py의 split_sections() 함수를 보니 이런 로직이 있었다.
MAX_SECTION_TOKENS = 8000 # child JSON 토큰 예산
if n <= 3:
return [단일 에이전트]
elif n <= 7:
return [2개 그룹]
else:
return [n개 개별 에이전트] # ← 문제절벽 현상: 섹션이 7개면 에이전트 2개, 8개면 에이전트 8개. 복잡한 페이지는 필연적으로 n >= 8에 걸려 섹션 수만큼 에이전트가 생성된다.
이 페이지는 MAX_SECTION_TOKENS = 8000 기준으로 분할하니 66개 섹션이 나왔고, 결국 66개 에이전트가 실행됐다.
토큰 낭비 구조 분석
서브에이전트 1개가 실제로 받는 컨텍스트를 측정했다.
시스템 프롬프트 ~8K 토큰
스킬 프롬프트 ~4K 토큰
빌드 프롬프트 ~2K 토큰
shared.json ~25K 토큰
section 파일 ~36K 토큰
└─ specCache 포함 ~30K 토큰 ← 전체 section 파일의 83%
└─ 실제 노드 데이터 ~6K 토큰
────────────────────────────────
에이전트당 총 입력 ~75K 토큰Claude Sonnet의 컨텍스트 창은 200K인데, 에이전트가 75K만 쓰고 125K를 비워두고 있었다.
더 심각한 문제는 specCache(~30K 토큰)가 66개 섹션 파일 전부에 중복 복사되고 있었다는 점이다.
실제 Figma 노드 데이터: 6K × 66 = 396K
specCache 중복: 30K × 66 = 1,980K ← 낭비해결책 1: MAX_SECTION_TOKENS 상향 + 병합 패스
MAX_SECTION_TOKENS를 8K에서 30K로 올리고, 분할 후 인접 섹션을 다시 묶는 merge_by_budget() 함수를 추가했다.
결과: 66개 → 4개 에이전트
그룹 1: frame-1261172071 (6개 섹션, 49K 토큰)
그룹 2: dropdown (11개 섹션, 59K 토큰)
그룹 3: frame-1437265828 (10개 섹션, 55K 토큰)
그룹 4: table_cpa (7개 섹션, 42K 토큰)해결책 2~6: specCache 중복 제거, 토큰 슬리밍, 모델 교체, QA 수동화, 스킬 통합
specCache 중복 제거
specCache를 각 섹션 파일에서 제거하고 shared.json으로 이동.
tokenIndex 슬리밍 전체 토큰이 아니라 이 페이지에서 실제 참조하는 토큰만 필터링.
PHASE 2 모델 교체 서브에이전트에서 Haiku 사용 (비용 절감).
자동 QA 파이프라인 전면 수동화 필요한 것만 선택해서 실행.
스킬 통합 (4개 → 2개) chakra/tailwind 변형을 단일 스킬로 통합, 프레임워크 자동감지.
최종 결과
| 항목 | Before | After | 절감 |
|---|---|---|---|
| PHASE 2 입력 | 4,950K | 484K | -90% |
| PHASE 2 출력 | 528K | 170K | -68% |
| QA 파이프라인 | 230K | 75K | -67% |
| 총계 | 5,748K | 769K | -87% |
처음 ████████████████████████████████████░░░░░░░░░░░░░░░░░░░░░░░ 37%
지금 ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 5%핵심 교훈
-
절벽 로직을 주의하라:
n <= 7 → 2개,n >= 8 → n개같은 분기는 입력 크기에 따라 비용이 선형이 아닌 계단식으로 폭발한다. -
공유 데이터는 1회만: 여러 에이전트가 읽는 공통 데이터는 반드시 공유 파일에 1번만 두고 참조하게 해야 한다.
-
컨텍스트 창 활용률을 측정하라: 200K 창에 75K만 쓰고 있다면, 에이전트를 더 줄일 수 있다는 신호다.
-
분할과 병합을 분리하라: 분할은 트리 구조를 보존하며 분해하고, 병합이 토큰 예산 내에서 재조립한다.
-
API truncation과 LLM context는 다른 문제다: API 응답 크기 제한과 LLM 컨텍스트 관리는 다른 파라미터로 풀어야 한다.
이 버전에서 배운 것
-
병렬화는 속도는 올리지만 복잡도도 올린다 — 순차 실행이 간단하다. 병렬화하기 전에 정말 필요한지 검토해야 한다.
-
토큰 낭비는 구조 문제다 — 모델을 바꾸는 것보다 설계를 바꾸는 게 훨씬 효과적이다.
-
절벽은 예측 불가능성을 만든다 — 선형이 아닌 계단식 증가는 입력 크기를 조금만 늘려도 폭발한다.
-
병렬 실행의 기숨은 안전성 — 66개 에이전트가 동시에 실행되면 뭔가 하나라도 실패하면 전체 실패한다.
다음 버전에서는 이 경험을 바탕으로 구조를 완전히 재설계했다. 덜 하게 만들기로 방향을 꺾었다.