상태 머신과 워크플로 그래프 설계
분류: Layer 12 - AI 시스템 & LLM 애플리케이션 | 선수지식: L10-20 (트리·그래프), L9-10 (설계 원칙), L12-60 (Agent)
상태 머신과 워크플로 그래프 설계 — FSM, Statecharts, XState, LangGraph
섹션 제목: “상태 머신과 워크플로 그래프 설계 — FSM, Statecharts, XState, LangGraph”1. 한 줄 정의
섹션 제목: “1. 한 줄 정의”상태 머신과 워크플로 그래프는 시스템을 **상태(state), 이벤트(event), 전이(transition), side effect(action)**로 분해해 복잡한 흐름을 명시적으로 제어하는 설계 방식이다.
2. 왜 중요한가
섹션 제목: “2. 왜 중요한가”- agent를 무한 루프에서 꺼낸다: “다음에 무엇을 할지”를 모델에만 맡기지 않고 가능한 경로를 제한한다.
- 디버깅 가능성: 현재 상태와 직전 이벤트를 보면 실패 위치를 추적할 수 있다.
- 테스트 가능성: 모든 상태·전이 조합을 표로 만들고 누락 전이를 검증할 수 있다.
- Human-in-the-loop와 잘 맞음: 승인 대기, 수정 요청, 재시도 같은 block 상태를 모델링하기 쉽다.
- Durable execution의 기반: 재시작 시 복원할 최소 단위가 “현재 상태 + context”로 정리된다.
2.5 선행 기술의 한계 — if/else Workflow가 무너지는 지점
섹션 제목: “2.5 선행 기술의 한계 — if/else Workflow가 무너지는 지점”초기 LLM workflow는 보통 다음과 같은 코드로 시작한다.
if (needsSearch) { const docs = await search(query); if (docs.length === 0) retry();}if (needsTool) { const result = await callTool(args);}처음에는 읽기 쉽지만, 검색 실패, 도구 권한 부족, 사람 승인 대기, 재시도 초과, 부분 성공, 취소가 붙으면 분기 수가 곱셈으로 늘어난다. 상태는 지역 변수와 DB row, queue message, frontend UI에 흩어지고 “지금 이 작업이 정확히 어디에 멈췄는가”가 사라진다.
상태 머신은 이 한계를 불가능한 상태를 표현하지 않는 모델로 푼다. XState는 finite state machine과 statechart를 핵심 추상화로 제공하고, LangGraph는 agent 실행을 graph node와 edge로 표현한다. 출처: XState API, LangGraph durable execution.
3. 핵심 개념
섹션 제목: “3. 핵심 개념”3.0 State Machine과 Stateful System의 차이
섹션 제목: “3.0 State Machine과 Stateful System의 차이”상태 머신은 가능한 상태와 전이를 정의하는 모델이고, stateful system은 그 모델을 실제 운영 환경에서 저장·복원·관측·마이그레이션까지 책임지는 시스템이다.
| 관점 | State machine | Stateful system |
|---|---|---|
| 관심사 | 어떤 상태에서 어떤 이벤트 허용 | 상태를 어디에 저장하고 어떻게 복구할지 |
| 산출물 | 상태도, transition table | DB schema, checkpoint, replay log, migration |
| 실패 처리 | invalid transition 거부 | worker crash, 중복 이벤트, 버전 불일치 복구 |
| 테스트 | 상태·이벤트 조합 테스트 | 재시작, 재처리, 오래된 run replay 테스트 |
예를 들어 waiting_for_human -> approved -> acting 전이를 정의하는 것은 state machine 설계다. 승인 대기 중 서버가 재시작되어도 같은 run을 복원하고, 승인 이벤트가 두 번 와도 한 번만 처리하며, workflow 코드 v2 배포 후 v1 run을 깨뜨리지 않는 것은 stateful system 설계다.
3.1 FSM 기본
섹션 제목: “3.1 FSM 기본”State: idle | planning | acting | waiting_for_human | done | failedEvent: START | TOOL_OK | TOOL_ERROR | APPROVE | REJECT | RETRY | CANCELTransition: (state, event) -> next_stateFSM의 장점은 “현재 상태에서 받을 수 없는 이벤트”를 명확히 거부할 수 있다는 점이다.
작은 승인 workflow라면 transition table을 먼저 적어보면 누락 전이가 보인다.
| 현재 상태 | 이벤트 | 다음 상태 | 비고 |
|---|---|---|---|
planning | START | acting | plan이 유효할 때만 허용 |
acting | TOOL_ERROR | failed_transient | attempt < max_attempts |
waiting_for_human | APPROVE | acting | 승인 이벤트는 idempotent 처리 |
waiting_for_human | CANCEL | failed | 사용자 취소 |
done | APPROVE | 거부 | 완료된 run은 다시 진행 금지 |
전이 테스트는 최소한 done + APPROVE 같은 invalid transition 거부, TOOL_ERROR 반복 후 fallback 진입, APPROVE 중복 수신 시 상태가 한 번만 바뀌는지를 확인한다.
3.2 Statechart
섹션 제목: “3.2 Statechart”statechart는 FSM에 계층·병렬·history 개념을 더한다.
- Hierarchical state:
running.searching,running.calling_tool - Parallel state:
drafting과compliance_check를 동시에 진행 - History state: 승인 후 중단 전 상태로 복귀
- Guard:
if confidence >= 0.8일 때만 자동 진행
LLM workflow에서는 human review 후 어디로 돌아갈지 history state가 특히 중요하다.
3.3 Workflow Graph
섹션 제목: “3.3 Workflow Graph”Graph는 node와 edge로 흐름을 표현한다.
START -> classify -> retrieve -> draft -> judge -> [pass] final -> [fail] revise -> judgeFSM이 “상태 중심”이라면 graph는 “실행 step 중심”이다. LangGraph 같은 agent framework는 state를 공유 객체로 두고 node가 state를 갱신한다.
3.4 Guard, Action, Effect 분리
섹션 제목: “3.4 Guard, Action, Effect 분리”| 요소 | 역할 | 예시 |
|---|---|---|
| Guard | 전이 가능 여부 판단 | risk < threshold |
| Action | 내부 state 갱신 | attempt += 1 |
| Effect | 외부 side effect | 이메일 발송, DB 업데이트 |
Durable execution에서는 effect를 재실행하면 안 되므로 action/effect 분리가 필수다.
3.5 LLM Node 설계
섹션 제목: “3.5 LLM Node 설계”LLM을 graph node로 넣을 때 출력 계약이 필요하다.
{ "decision": "call_tool | ask_human | final", "confidence": 0.74, "reason": "...", "tool_args": {}}자유 텍스트 답변을 바로 edge condition에 쓰면 parsing 실패가 workflow 실패로 번진다.
LLM node가 참고할 입력은 L12-100 Context Engineering의 context bundle로 관리하고, graph state에는 “다음 전이를 결정하는 데 필요한 최소 상태”만 남기는 편이 안전하다. 검색 결과 원문이나 긴 tool 로그를 graph state에 계속 누적하면 persistence 비용과 replay 노이즈가 함께 커진다.
3.6 Retry와 Compensation
섹션 제목: “3.6 Retry와 Compensation”재시도는 edge가 아니라 상태로 모델링하는 편이 안전하다.
acting -> failed_transient -> retry_wait -> acting -> failed_permanent외부 side effect가 이미 일어났다면 L9 Saga처럼 보상 action을 별도 node로 둔다.
3.7 Checkpoint, Persistence, Replay
섹션 제목: “3.7 Checkpoint, Persistence, Replay”운영 가능한 workflow graph는 “현재 node가 어디인가”만 저장하지 않는다.
| 항목 | 저장 내용 | 운영 목적 |
|---|---|---|
| Checkpoint | 현재 state, context summary, attempts, timers | crash 후 마지막 안전 지점에서 재개 |
| Persistence | checkpoint를 durable store에 기록 | worker 교체·배포·장기 대기에도 상태 보존 |
| Replay | event log나 history로 같은 결정을 재현 | 사고 분석, regression test, human approval 재개 |
| Versioning | state schema와 transition graph 버전 | 진행 중 run을 새 코드 배포와 분리 |
checkpoint는 snapshot이고 replay는 history다. snapshot만 있으면 “왜 이 상태가 되었는가”가 약하고, history만 있으면 긴 workflow 재구성이 비싸다. production에서는 보통 event history와 최신 checkpoint를 함께 둔다.
LLM workflow에서는 다음 값을 특히 조심해서 저장한다.
- LLM 입력 원문: 재현성에는 좋지만 PII·secret·비용 문제가 있으므로 redaction과 reference 저장을 우선한다.
- Tool side effect 결과: 외부 시스템에 이미 반영된 작업은 idempotency key와 함께 저장한다.
- Context summary: 다음 step 판단에 필요한 사실만 구조화하고, 원문 근거는 문서 ID·span ID로 참조한다.
- Graph version:
v1run이 진행 중일 때v2transition을 강제로 적용하면 불가능한 상태가 생길 수 있다.
작은 persistence schema는 다음 정도만 있어도 crash 복구와 중복 이벤트 방어를 시작할 수 있다.
{ "run_id": "run_20260522_001", "graph_version": "support-agent-v1", "state_schema_version": 2, "checkpoint_id": "chk_0007", "current_node": "waiting_for_human", "state": { "attempt": 1, "approval_status": "pending", "context_summary_ref": "ctxsum_42" }, "last_event_id": "evt_103", "idempotency_key": "approve:ticket_77:reviewer_12", "updated_at": "2026-05-22T09:30:00Z"}예를 들어 support-agent-v1의 waiting_for_human run이 남아 있는 상태에서 v2가 needs_legal_review node를 추가한다면, 진행 중 run은 그대로 v1 graph로 재개하거나 migration job에서 state_schema_version: 2 -> 3 변환과 새 checkpoint 생성을 명시적으로 수행한다. 이때 기존 approval signal은 같은 idempotency_key로 dedupe해야 승인 메일 발송 같은 effect가 두 번 실행되지 않는다.
L12-120 Temporal Durable Execution은 이 운영 관점을 workflow history, activity result, signal, replay 규칙으로 더 엄격하게 구현한 사례다.
3.8 Agent Graph 안티패턴
섹션 제목: “3.8 Agent Graph 안티패턴”| 안티패턴 | 문제 | 대안 |
|---|---|---|
| everything node | 한 node가 분류·검색·도구·응답을 모두 수행 | node를 결정 단위로 분리 |
| hidden state | 상태가 prompt 문자열 안에만 존재 | typed state schema |
| unbounded loop | judge 실패 시 무한 revise | max_attempts guard |
| side effect in guard | 조건 판단 중 외부 API 호출 | guard는 순수 함수 유지 |
| UI state와 실행 state 혼합 | 화면 표시 변경이 workflow 의미를 바꿈 | UI projection 분리 |
| unversioned transition | 배포 후 진행 중 run이 새 graph와 충돌 | graph/schema version 고정 |
4. 실무에서 어디에 쓰이나
섹션 제목: “4. 실무에서 어디에 쓰이나”- 상담 봇의
draft → review → send승인 플로우 - 코드 agent의
plan → edit → test → fix → summarize루프 - RAG pipeline의
retrieve → rerank → answer → judge → fallback - 결제/주문처럼 보상이 필요한 AI-assisted workflow
- batch 평가 시스템의 queue 상태 관리
5. 현재 내 업무와 연결점
섹션 제목: “5. 현재 내 업무와 연결점”프론트엔드에서 복잡한 모달·폼 상태를 boolean 여러 개로 관리하면 isOpen && isSubmitting && hasError 같은 불가능한 조합이 생긴다. FSM은 이런 상태를 editing | submitting | failed | submitted로 제한한다. AI workflow도 동일하다. LLM이 더 똑똑해져도 실행 상태는 명시적으로 모델링해야 운영이 된다.
6. 자주 헷갈리는 개념 비교
섹션 제목: “6. 자주 헷갈리는 개념 비교”| 개념 A | 개념 B | 차이점 |
|---|---|---|
| FSM | Statechart | FSM은 평면 상태, statechart는 계층·병렬·history 지원 |
| DAG | State machine | DAG는 보통 일회성 비순환 작업, state machine은 loop와 이벤트 처리 가능 |
| Workflow | Agent | workflow는 경로가 코드에 명시, agent는 일부 결정을 LLM이 수행 |
| Guard | Judge | guard는 deterministic 조건, judge는 모델 기반 품질 판단 |
| State | Context | state는 실행 위치, context는 결정을 위한 데이터 |
| Checkpoint | Replay | checkpoint는 현재 snapshot, replay는 이벤트 history로 결정 재현 |
7. 체크리스트
섹션 제목: “7. 체크리스트”- workflow를 state/event/transition으로 표현할 수 있다.
- state machine 모델과 stateful system 운영 책임을 구분할 수 있다.
- LLM decision node의 structured output schema를 설계할 수 있다.
- retry, timeout, cancel, human approval을 상태로 모델링할 수 있다.
- guard와 side effect를 분리해야 하는 이유를 설명할 수 있다.
- checkpoint, persistence, replay, versioning을 workflow 설계에 반영할 수 있다.
- unbounded loop를 max attempt와 fallback state로 제어할 수 있다.
8. 추가 학습 키워드
섹션 제목: “8. 추가 학습 키워드”finite state machine, statechart, stateful system, XState, LangGraph StateGraph, workflow graph, checkpoint, persistence, replay, workflow versioning, guard condition, actor model, Saga compensation, deterministic workflow
9. 내가 직접 확인해볼 것
섹션 제목: “9. 내가 직접 확인해볼 것”- 간단한 고객 문의 agent를 상태도 6개 이하로 그려보기
-
judge → revise루프에 max attempt guard를 넣고 실패 시 fallback 설계 - 진행 중인 workflow에
graph_version과 checkpoint schema를 추가해 migration 시나리오 써보기 - XState로
idle/editing/submitting/success/failure폼 머신 구현 - LangGraph에서 node별 state update와 trace를 확인
10. 5줄 요약
섹션 제목: “10. 5줄 요약”- 상태 머신은 복잡한 workflow를 상태·이벤트·전이로 제한해 불가능한 상태를 줄인다.
- state machine은 모델이고 stateful system은 저장·복원·replay·versioning까지 포함한 운영 책임이다.
- LLM agent도 실행 경로는 명시적 graph로 두는 편이 디버깅과 운영에 유리하다.
- guard, action, effect를 분리해야 재시도와 durable execution이 안전해진다.
- graph 설계의 핵심은 모델의 자율성을 없애는 것이 아니라 위험한 경로를 좁히는 것이다.
11. 출처
섹션 제목: “11. 출처”최종 수정: 2026-05-21