
Microsoft Agent Framework 워크플로: 언제 사용하고 언제 C#에 머물러야 하는가
요약
Microsoft Agent Framework의 워크플로 엔진 활용 시점과 일반 C# 코드 기반 오케스트레이션의 차이점을 분석합니다. 프로세스의 명시성, 관찰 가능성, 재개 가능성이 필요한 복잡한 시나리오에서 워크플로 엔진의 효용성을 설명합니다.
핵심 포인트
- 워크플로 엔진은 그래프 기반의 명시적 오케스트레이션을 제공함
- 장기 실행 프로세스 및 체크포인팅이 필요한 경우 워크플로가 유리함
- 단순한 에이전트 라우팅은 일반 C# 코드가 더 효율적일 수 있음
- 시스템의 복잡도를 낮추기 위해 가장 작은 추상화를 선택하는 것이 중요함
이 글은 Microsoft Agent Framework에 관한 제 시리즈의 12번째 파트입니다. 원문 게시물은 lukaswalter.dev에서 읽으실 수 있습니다.
이전 기사에서 우리는 에이전트(agents)를 도구로서 살펴보았습니다.
코디네이터 에이전트(coordinator agent)는 모든 저수준 도구(low-level tool)를 직접 노출하지 않고도 집중된 전문가 에이전트(specialist agents)에게 작업을 위임할 수 있습니다.
그 전에는 수동 멀티 에이전트 라우팅 (manual multi-agent routing)을 살펴보았습니다.
작은 의도 에이전트(intent agent)가 구조화된 출력(structured output)을 반환하면, 일반적인 C# 코드가 어떤 전문가 에이전트를 실행할지 결정하는 방식이었습니다.
두 패턴 모두 오케스트레이션(orchestration)을 애플리케이션에 가깝게 유지하기 때문에 유용합니다.
하지만 Microsoft Agent Framework에는 실제 워크플로 엔진(workflow engine)도 포함되어 있습니다.
이 엔진은 실행기(executors), 엣지(edges), 그래프 기반 오케스트레이션(graph-based orchestration), 스트리밍 이벤트(streaming events), 핸드오프(handoffs), 체크포인팅(checkpointing), 그리고 인간 참여형(human-in-the-loop) 시나리오를 갖추고 있습니다.
이것은 강력합니다.
하지만 공짜는 아닙니다.
프레임워크가 워크플로 엔진을 제공한다고 해서 모든 멀티 에이전트 상호작용이 워크플로 그래프(workflow graph)가 되어야 한다는 의미는 아닙니다.
프로덕션 시스템(production systems)에서 가장 좋은 아키텍처는 종종 시스템을 이해 가능하고 신뢰할 수 있게 만드는 가장 작은 추상화(abstraction)입니다.
저의 규칙은 간단합니다:
Microsoft Agent Framework 워크플로는 프로세스 자체가 명시적(explicit)이고, 관찰 가능(observable)하며, 재개 가능(resumable)하고, 장기 실행(long-running)되어야 할 때 유용합니다.
단순한 오케스트레이션의 경우, 일반적인 C# 코드가 종종 더 나은 선택입니다.
워크플로가 존재하는 이유
워크플로는 오케스트레이션을 명시적으로 만듭니다.
프로세스를 임시적인(ad-hoc) 메서드 호출 내부에 숨기는 대신, 프로세스가 하나의 모델(model)이 됩니다.
이 모델은 그래프(graph)입니다.
그래프는 작업 단위(units of work)와 그들 사이의 연결을 포함합니다.
해당 그래프는 다음과 같은 것들을 나타낼 수 있습니다:
- 순차적 실행 (sequential execution)
- 분기 (branching)
- 병렬 실행 (parallel execution)
- 팬아웃 및 팬인 (fan-out and fan-in)
- 에이전트 간의 핸드오프 (handoffs between agents)
- 인간의 입력 (human input)
- 장기 실행 프로세스 (long-running processes)
- 프로세스 실행 중 발생하는 이벤트 (events emitted while the process runs)
- 체크포인팅 및 재개 (checkpointing and resumption)
이것은 단일 에이전트 호출 (single agent call)과는 다른 추상화입니다.
에이전트 (Agent)는 자신의 지침 (instructions), 도구 (tools), 그리고 대화 문맥 (conversation context)을 기반으로 무엇을 할지 동적으로 결정합니다.
워크플로 (Workflow)는 모델 외부에서 프로세스를 정의합니다.
에이전트는 해당 프로세스 내부의 단계 (steps)가 될 수 있지만, 프로세스 자체는 워크플로에 의해 제어됩니다.
이러한 차이는 중요합니다.
문서 검토 흐름 (document review flow), 지원 에스컬레이션 흐름 (support escalation flow), 또는 나중에 일시 중지 및 재개될 수 있는 승인 프로세스 (approval process)를 구축하고 있다면, 워크플로는 단순한 배관 (plumbing) 작업이 아닙니다.
그것은 시스템의 일부입니다.
워크플로를 검사하고, 영속화 (persist)하고, 테스트하고, 버전 관리하고, 다른 사람들에게 설명해야 할 수도 있습니다.
그 지점에서 워크플로 엔진 (workflow engine)이 유용해집니다.
하지만 비용이 따릅니다.
워크플로 그래프 (workflow graph)는 더 많은 설정 코드 (setup code), 더 많은 타입 (types), 더 많은 이벤트 처리 (event handling), 그리고 애플리케이션 코드와 실제로 발생하는 일 사이의 또 다른 계층을 도입합니다.
복잡한 시스템의 경우, 그 비용을 지불할 가치가 있습니다.
작은 흐름의 경우, 시스템을 읽기 더 어렵게 만들 수 있습니다.
실행기 (Executors) 및 엣지 (Edges)
두 가지 기본 구성 요소는 실행기 (executors)와 엣지 (edges)입니다.
실행기는 작업 단위 (unit of work)입니다.
입력을 받고, 로직을 실행하며, 출력 또는 이벤트 (events)를 생성합니다.
실행기는 다음과 같은 것들을 감쌀 수 있습니다:
- 결정론적 (deterministic) C# 코드
- 에이전트 호출 (agent call)
- 도구 호출 (tool call)
- 검증 로직 (validation logic)
- 변환 단계 (transformation step)
- 사람의 승인 요청 (human approval request)
- 또 다른 프로세스 로직 조각
에이전트 중심 워크플로 (agentic workflows)에서 많은 실행기는 에이전트이거나 에이전트 주도 단계 (agent-driven steps)입니다.
예를 들어, 한 실행기는 문서 요약 에이전트 (document summarizer agent)를 호출할 수 있습니다.
다른 실행기는 생성된 요약을 검증할 수 있습니다.
또 다른 실행기는 사람 검토자 (human reviewer)를 기다릴 수 있습니다.
엣지는 실행기 사이에서 데이터가 어떻게 이동하는지를 정의합니다.
그것들은 그래프 내의 연결 (connections)입니다.
엣지는 다음과 같은 것을 나타낼 수 있습니다:
- 한 단계에서 다음 단계로의 직접적인 연결 (direct connection)
- 조건부 라우팅 (conditional routing)
- 스위치(switch)와 같은 분기 (switch-like branching)
- 여러 단계로의 팬아웃 (fan-out)
- 집계 단계로의 팬인 (fan-in)
이 지점이 워크플로 엔진 (workflow engine)이 가치를 더하는 부분입니다.
제어 흐름 (control flow)이 워크플로 정의 내에서 가시화됩니다.
그래프를 통해 어떤 단계가 발생할 수 있고 어떤 전이 (transitions)가 허용되는지 확인할 수 있습니다.
실행자 (Executors)와 엣지 (edges)가 강력한 이유는 오케스트레이션 (orchestration)을 하나의 모델로 바꾸기 때문입니다.
하지만 오케스트레이션이 모델이 되면, 그 모델을 유지 관리해야 하는 비용도 발생합니다.
네 가지 워크플로 관련 패턴
실제 애플리케이션에서는 여러 가지 워크플로 관련 패턴이 빠르게 나타납니다.
어떤 것들은 오케스트레이션 패턴 (orchestration patterns)입니다.
Human-in-the-loop와 같은 다른 것들은 프로세스 역량 (process capabilities)입니다.
중요한 것은 라벨이 아닙니다.
중요한 것은 프로세스가 명시적으로 모델링됨으로써 이득을 얻느냐 하는 것입니다.
예시들은 의도적으로 단순화되었습니다.
핵심은 정확한 API 표면 (API surface)이 아니라 오케스트레이션의 형태입니다.
순차적 워크플로 (Sequential Workflows)
순차적 워크플로는 한 단계의 출력을 다음 단계로 전달합니다.
예를 들어:
- 한 에이전트가 법률 문서를 요약합니다.
- 다른 에이전트가 요약된 내용을 프랑스어로 번역합니다.
- 마지막 단계에서 사용자를 위해 결과를 포맷팅합니다.
워크플로로서 이것은 파이프라인 (pipeline)입니다.
각 단계는 이전 단계에 의존합니다.
단순한 파이프라인에서는 한 실행자의 결과가 다음 실행자의 입력이 될 수 있습니다. Agent Framework의 순차적 에이전트 오케스트레이션 (sequential agent orchestration)에서는 오케스트레이션이 어떻게 구성되었느냐에 따라 다음 에이전트가 대화 컨텍스트 (conversation context)를 받을 수도 있습니다.
이것은 유효한 워크플로 형태입니다.
하지만 결정론적인 (deterministic) 단계가 두세 개뿐이라면, 일반적인 C#이 더 명확할 수 있습니다:
AgentResponse summary = await summarizerAgent.RunAsync(
documentText,
cancellationToken: cancellationToken);
...
이 방식에는 아무런 문제가 없습니다.
위에서 아래로 읽기 쉽습니다.
테스트하기 쉽습니다.
디버깅하기 쉽습니다.
워크플로 (Workflow) 버전은 시퀀스(sequence) 자체가 운영상 중요해질 때 이점을 발휘하기 시작합니다:
- 각 단계별로 진행 상황을 보여줘야 할 때
- 나중 단계부터 재시도(retry)하거나 재개(resume)해야 할 때
- 어떤 단계가 어떤 출력을 생성했는지 감사(audit)해야 할 때
- 파이프라인 (pipeline)이 확장될 것으로 예상될 때
- 단계 사이에 복잡한 분기 (branches)가 나타날 때
병렬 워크플로 (Concurrent Workflows)
병렬 워크플로는 동일한 입력을 여러 에이전트(agent)나 단계에 동시에 보냅니다.
예를 들어, 법률 문서는 세 명의 에이전트에 의해 처리될 수 있습니다:
- 한 명은 법적 리스크를 확인합니다.
- 한 명은 철자와 문법을 확인합니다.
- 한 명은 주요 의무 사항을 추출합니다.
작업이 병렬로 수행되기 때문에 지연 시간 (latency)을 줄일 수 있습니다.
또한 각 분기가 고유한 상태 (state), 이벤트 (events), 재시도 동작 (retry behavior) 또는 결과 타입 (result type)을 가질 때 유용한 구조를 만들어 줍니다.
하지만 다시 말하지만, C#에는 이미 훌륭한 동시성 기본 요소 (concurrency primitive)가 있습니다:
Task<AgentResponse> riskTask = legalRiskAgent.RunAsync(
documentText,
cancellationToken: cancellationToken);
...
단순한 병렬 오케스트레이션 (orchestration)의 경우, Task.WhenAll이 워크플로 그래프 (workflow graph)보다 읽고 테스트하기 더 쉬운 경우가 많습니다.
어떤 방식이든 운영상의 고려 사항은 동일합니다:
- 병렬 에이전트 호출은 토큰 (token) 사용량을 배가시킵니다.
- 제공업체의 속도 제한 (rate limits)에 더 빨리 도달할 수 있습니다.
- 비용을 증가시킵니다.
- 부분적 실패 (partial failure) 처리를 더 중요하게 만듭니다.
- 동시성은 제한되어야 하며 의도적이어야 합니다.
워크플로 엔진이 이러한 문제들을 사라지게 만들지는 않습니다.
워크플로 엔진은 그러한 구조가 중요할 때, 병렬 분기를 모델링하고 관찰할 수 있는 구조화된 방법을 제공합니다.
핸드오프 워크플로 (Handoff Workflows)
핸드오프 (handoff) 워크플로는 하나의 에이전트나 단계가 어떤 다른 에이전트가 작업을 계속해야 할지 결정할 수 있게 합니다.
예를 들어:
- 의도 에이전트 (intent agent)가 사용자 요청을 받습니다.
- 해당 작업이 영화 전문가, 음악 전문가, 법률 전문가 또는 지원 에이전트(support agent) 중 누구에게 속하는지 결정합니다.
- 워크플로 (workflow)는 어떤 핸드오프 (handoff)가 허용되는지 제어합니다.
- 선택된 에이전트가 프로세스를 계속 진행합니다.
이는 경로가 여러 단계에 걸쳐 계속될 수 있고, 허용된 전환 (transitions)이 중요할 때 유용합니다.
워크플로를 통해 법률 전문가가 컴플라이언스 (compliance) 팀에는 핸드오프할 수 있지만, 결제 (billing) 팀으로 직접 핸드오프할 수는 없다는 점을 명확히 할 수 있습니다.
또는 지원 팀이 특정 정보를 수집한 후에만 엔지니어링 (engineering) 팀으로 에스컬레이션 (escalate)할 수 있도록 설정할 수도 있습니다.
단순한 라우팅 (routing)의 경우, 저는 보통 여기서 시작하지 않을 것입니다.
수동 라우팅 (manual routing) 기사에서 다룬 패턴만으로도 충분한 경우가 많습니다:
AgentResponse<IntentResult> intentResponse =
await intentAgent.RunAsync<IntentResult>(
$"""
...
이렇게 하면 라우팅이 애플리케이션 코드 내에서 명시적으로 유지됩니다.
분류기 (classifier)는 구조화된 출력 (structured output)을 반환합니다.
애플리케이션이 이를 검증합니다.
스위치 식 (switch expression)이 경로를 소유합니다.
이것은 가장 좋은 의미에서 지루한 방식입니다.
핸드오프 워크플로는 라우팅이 더 이상 단일 스위치에 그치지 않을 때 도움이 됩니다:
- 허용된 전환 (transitions)이 도메인의 일부인 경우
- 에이전트들이 반복적으로 핸드오프를 수행해야 하는 경우
- 경로를 나중에 검사해야 하는 경우
- 핸드오프 사이에 중간 상태 (intermediate state)가 유지되어야 하는 경우
- 핸드오프에 이벤트 (events), 체크포인트 (checkpoints) 또는 사람의 승인이 필요한 경우
Human-in-the-Loop 워크플로
Human-in-the-loop (인간 참여형)는 라우팅보다는 프로세스 상태 (process state)에 더 가깝습니다.
시스템이 일시 중지하고 사람의 입력을 기다릴 수 있게 합니다.
예를 들어:
- 에이전트가 답변 초안을 작성합니다.
- 워크플로가 사람의 승인을 위해 일시 중지합니다.
- 사람이 답변을 수정하거나 승인합니다.
- 워크플로가 결과를 게시하거나 전송하며 계속 진행됩니다.
이것이 워크플로 엔진 (workflow engine)을 사용해야 하는 가장 강력한 이유 중 하나입니다.
일시 중지는 UI의 세부 사항이 아닙니다.
그것은 프로세스의 일부입니다.
그럼에도 불구하고, 모든 사용자 상호작용에 워크플로가 필요한 것은 아닙니다.
로컬 채팅 UI의 경우, 다음 정도로 충분할 수 있습니다:
AgentResponse draft = await agent.RunAsync(
userMessage,
cancellationToken: cancellationToken);
...
그것은 간단합니다.
사용자가 존재합니다.
상호작용이 즉각적입니다.
상태(State)가 자연스럽게 UI 또는 컨트롤러 흐름에 속합니다.
워크플로(Workflows)는 인간의 상호작용이 장기 실행되는 비즈니스 프로세스의 일부일 때 유용해집니다:
- 승인 체인 (approval chains)
- 컴플라이언스 체크 (compliance checks)
- 티켓 에스컬레이션 (ticket escalation)
- 지연된 검토 (delayed review)
- 다일(multi-day) 프로세스
- 지속되는 상태 (persisted state)
- 감사 요구사항 (audit requirements)
만약 프로세스가 오늘 일시 중지되었다가 내일 재개될 수 있다면, 모든 것이 여전히 하나의 요청 핸들러(request handler) 내에 머물러 있는 것처럼 가장하는 것보다 워크플로 엔진(workflow engine)을 사용하는 것이 훨씬 더 적합합니다.
기타 주문 예시
트레이드오프(trade-off)를 구체화해 보겠습니다.
한 고객이 온라인 악기점에서 기타를 주문합니다.
시스템은 다음을 수행해야 합니다:
- 고객의 기타 주문을 파싱 (parse)
- 재고 확인
- 기타를 예약할 수 있는지 여부 결정
- 확인, 대안 추천, 또는 사람의 검토 요청 중 하나를 반환
에이전트(Agents)는 어려운 부분이 아닙니다.
설계 결정의 핵심은 오케스트레이션(orchestration)이 어디에 위치해야 하는가입니다.
워크플로 중심 버전 (The Workflow-Heavy Version)
워크플로 중심 설계에서는 프로세스를 다음과 같이 모델링할 수 있습니다:
GuitarOrderParserExecutorInventoryCheckExecutorReserveInventoryExecutorAlternativeRecommendationExecutorHumanReviewExecutorOrderConfirmationExecutor- 파싱에서 재고 확인으로 이어지는 엣지 (edge)
- 재고 확인에서 대안 추천으로 이어지는 조건부 엣지 (conditional edge)
- 재고 확인에서 예약으로 이어지는 조건부 엣지
- 예약에서 사람의 검토로 이어지는 조건부 엣지
- 예약에서 확인으로 이어지는 조건부 엣지
- 승인된 사람의 검토에서 확인으로 이어지는 엣지
- 파싱, 재고 확인, 예약, 검토 및 최종 결정이 완료될 때 방출되는 이벤트 (events)
개념적으로 그래프는 다음과 같습니다:
이것은 좋은 설계가 될 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
