레슨 2: 워크플로의 구성 요소: 단계, 상태, 분기, 루프
학습 목표:
- 워크플로의 네 가지 핵심 구성 요소 익히기
- 단계 사이의 의존 관계와 데이터 전달 이해하기
- 워크플로의 실행 흐름도 설계하기
전제: 레슨 1: 대화에서 워크플로로 | 다음: 레슨 3 >>
워크플로는 마법이 아니라 조합이다
지난 레슨에서 워크플로가 수십 개의 에이전트를 조율해 복잡한 작업을 끝낼 수 있다는 것을 봤습니다. 그런데 워크플로 스크립트를 열어 보면 그저 평범한 코드일 뿐입니다. 함수, 루프, 조건문.
워크플로의 힘은 네 가지 단순한 구성 요소의 조합에서 나옵니다.
- 단계 — 작업의 기본 단위
- 상태 — 단계 사이에 공유되는 데이터
- 분기 — 조건에 따라 경로를 고르는 것
- 루프 — 비슷한 조작을 반복하는 것
이 네 가지 구성 요소를 이해하면 어떤 복잡도의 워크플로도 설계할 수 있습니다.1
구성 요소 1: 단계
단계는 워크플로의 원자적 조작입니다. 각 단계는 에이전트 호출이거나 결정론적 함수입니다.2
에이전트 단계 vs 함수 단계
에이전트 단계를 쓸 때:
- 모호한 입력(자연어, 비정형 데이터)을 이해해야 할 때
- 창의적인 결과물(문서, 코드, 설명)을 생성해야 할 때
- 판단을 내려야 할 때(이 코드에 보안 문제가 있는가?)
함수 단계를 쓸 때:
- 데이터 변환(필터링, 정렬, 형식 맞추기)
- 계산(통계, 집계)
- 조건 검사(if-else 로직)
- 파일 조작(읽기, 쓰기, 이동)
모범 사례: 에이전트 단계는 추론하고, 함수 단계는 계산합니다. 단순한 배열 필터링이나 숫자 더하기를 LLM에게 시키지 마세요. 느리고, 비싸고, 믿을 수 없습니다.2
단계의 입출력 계약
모든 단계에는 명확한 입출력 계약이 있어야 합니다.
계약이 명확하면 워크플로를 이해하고 디버그하기 쉬워집니다. 5단계가 깨졌을 때, 4단계의 출력 형식이 잘못됐기 때문임을 곧바로 알 수 있습니다.3
구성 요소 2: 상태
상태는 단계 사이에 공유되는 데이터입니다. 워크플로의 기억과 같아서, 중간 결과와 실행 진행 상황을 담고 있습니다.4
두 가지 상태
워크플로 상태(Workflow State):
- 현재 작업에 관한 모든 정보. 어느 단계에 있는지, 각 단계의 결과가 무엇인지, 다음 단계에 무엇이 필요한지
- 스크립트 변수나 외부 데이터베이스에 저장된다
- 단계 사이로 전달되지만, 세션을 넘어가지는 않는다
세션 상태(Session State):
- 사용자의 대화 이력과 선호 설정
- 에이전트가 알아서 관리하며, 워크플로가 신경 쓸 필요가 없다4
상태 관리 패턴
패턴 1: 스크립트 변수(짧은 워크플로에 적합)
패턴 2: 상태 객체(중간 복잡도에 적합)
패턴 3: 외부 저장소(오래 도는 워크플로에 적합)
체크포인팅: 핵심 단계를 지난 뒤에 상태를 저장해 두면, 워크플로가 처음부터 다시 시작하는 대신 실패한 지점부터 재개할 수 있습니다.5
구성 요소 3: 분기
분기는 조건에 따라 다른 실행 경로를 고릅니다.6
단순 분기
에이전트의 판단에 따른 분기
에러 처리 분기
구성 요소 4: 루프
루프는 비슷한 대상 여러 개에 같은 조작을 실행하게 해 줍니다. 워크플로가 가진 힘의 핵심 원천입니다.6
순차 루프
병렬 루프
여기서 limit = 5가 동시 실행 상한입니다. Promise.all로 100개를 한꺼번에 쏘아 올려 연결이나 파일 핸들을 너무 많이 여는 대신, 한 번에 최대 5개씩만 돌립니다.
누적이 있는 루프
조건부 종료가 있는 루프
구성 요소 조합하기: 완전한 워크플로
이 네 가지 구성 요소를 조합해 "마이크로서비스 헬스 체크" 워크플로를 설계해 봅시다.
여기에 대응하는 스크립트입니다.
이 워크플로는 네 가지 구성 요소를 모두 씁니다.
- 단계:
listServices, checkServiceHealth, agent() 호출들
- 상태: 전체 개수와 정상/비정상 목록을 담은
state 객체
- 분기: 서비스 개수에 따른 병렬 대 순차, 그리고 건강 상태에 따른 보고서 종류
- 루프:
map 병렬 루프, for 순차 루프
워크플로 설계를 생각하는 방법
끝점에서 거꾸로 올라가기:
- 최종 출력이 무엇인가?(보고서, 배포된 서비스, 정리된 코드)
- 마지막 단계에 어떤 입력이 필요한가?(취합된 데이터, 검증된 결과)
- 그 입력은 어디서 오는가?(앞 단계의 출력)
- 시작점(사용자 입력이나 파일 시스템)에 닿을 때까지 반복
병렬화할 기회 찾기:
- 여러 단계가 서로 의존하지 않는다면 병렬로 돌릴 수 있다
- "각각의 X에 대해 Y를 한다"는 대개 병렬화할 수 있다
- 병렬화하면 5분짜리 작업 10개가 50분에서 5분으로 줄어든다
의존 관계를 드러내기:
다음: 레슨 3: 복잡한 작업을 워크플로로 분해하기 — 복잡한 작업을 워크플로 단계로 체계적으로 쪼개는 전략