본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 06. 19:57

.NET 에이전트 생태계에는 진정한 아키텍처적 선택지가 필요합니다. 워크플로 중심(Workflow-driven) 방식이 정답의 전부는 아닙니다.

요약

.NET 에이전트 AI 생태계에서 주류인 워크플로 중심 오케스트레이션 방식의 장점과 한계를 분석합니다. 사전 정의된 단계가 유용한 경우도 있지만, 모델의 자율적 추론이 필요한 복잡한 상황에서는 기존 방식이 한계를 보임을 지적합니다.

핵심 포인트

  • 워크플로 중심 방식은 가시성과 제어력이 높음
  • 문서 처리 및 데이터 추출 등 정형화된 작업에 적합
  • 예기치 못한 실패 상황에서 LLM의 추론 능력을 활용하기 어려움
  • 사전 정의된 플로우차트로 표현 불가능한 동적 작업에는 부적합

.NET 에이전트 AI (agentic AI) 생태계에서 무언가가 빠르게 일어나고 있습니다. 프레임워크들이 등장하고, 패턴들이 확립되고 있으며, 개발자들은 나중에 되돌리기 어려운 아키텍처적 결정을 내리고 있습니다. 이러한 결정의 대부분은 동일한 패턴으로 수렴하고 있습니다. 바로 주요 단계에 LLM (Large Language Model)을 결합한 워크플로 중심 오케스트레이션 (workflow-driven orchestration) 방식입니다.

이 패턴은 실질적인 장점이 있습니다. 하지만 실질적인 한계도 존재합니다. 현재 .NET 개발자들에게는 진정한 대안이 제시되지 않고 있습니다.

워크플로 중심(Workflow-driven) 방식의 실제 의미

워크플로 중심 에이전트 프레임워크는 오케스트레이션 (orchestration) 사고방식에서 그 형태를 물려받습니다. 당신이 단계를 정의합니다. 당신이 전이 (transitions)를 정의합니다. LLM은 당신이 설정한 경계 내에서, 당신이 결정한 시점에 호출됩니다. 개발자가 실행의 설계자(architect)가 됩니다. LLM은 당신이 이미 설계한 프로세스 내에서 유능한 참여자가 됩니다.

당신은 코드를 보고 정확히 어떤 일이 일어날지 이해할 수 있습니다. 무언가 실패했을 때, 어디서 왜 발생했는지 알 수 있습니다. 그러한 가시성 (visibility)은 아키텍처에 내장되어 있습니다.

워크플로 중심 방식이 제 역할을 하는 경우

실행이 시작되기 전에 작업의 형태를 알 수 있는 경우, 워크플로 중심 방식은 올바른 아키텍처적 선택입니다. 단계는 명시적이고, 전이는 정의되어 있으며, 실행 경로는 설계에 의해 미리 결정됩니다. 문서 처리 (document processing), 분류 (classification), 구조화된 데이터 추출 (structured data extraction), 그리고 보고서 생성 (report generation)은 모두 사전 정의된 워크플로 패턴에 잘 부합합니다. 왜냐하면 이들은 동일한 특성을 공유하기 때문입니다. 즉, 코드를 작성하기 전에 플로우차트 (flowchart)를 그릴 수 있다는 점입니다.

그 플로우차트가 당신이 원하는 바로 그것일 때, 워크플로 중심 방식은 올바른 선택입니다. 가치가 에이전트가 정밀하고 반복 가능한 시퀀스 (sequence)를 따르는 데 있고, 개발자가 실행 형태를 의도적으로 소유할 때 그러합니다. LLM과 도구들은 당신이 설계한 구조 내에서 제한된 역할을 수행합니다. 그것은 제약이 아니라 의도입니다.

한계점

작업이 사전 정의된 형태에 맞지 않을 때 한계가 나타납니다.

사용자가 에이전트에게 특정 주제를 조사하고, 여러 소스로부터 얻은 결과물을 종합하며, 공백(gap)을 식별하고, 더 깊이 파고들지 아니면 현재 확보한 내용을 바탕으로 유용한 결과물을 만들어낼지 결정하라고 요청한다고 가정해 봅시다. 이러한 흐름을 미리 플로우차트(flowchart)로 그려낼 수는 없습니다. 어떤 소스를 추적할 가치가 있는지, 언제 충분한 정보가 모였는지, 무엇을 공백으로 간주할지에 대한 결정은 개발자가 아닌 모델(model)의 판단 영역입니다.

더 심각한 문제는 실패 상황에서 나타납니다. 워크플로 중심(workflow-driven) 에이전트가 도구(tool)의 실패, API의 비정상적인 응답, 또는 예상보다 복잡한 작업과 같은 예기치 못한 상황에 직면하면, 프레임워크는 개발자가 작성한 에러 핸들링(error handling) 로직으로 경로를 지정합니다. catch 블록, 재시도(retry), 폴백(fallback) 단계 같은 것들 말입니다. 이는 실패가 발생하기 전에, 어떤 실패를 예상해야 할지 추측해야 했던 개발자에 의해 미리 작성된 코드입니다.

정작 호출되지 않는 것은 LLM(Large Language Model) 그 자체입니다. 이것은 매우 중요한 문제인데, 왜냐하면 LLM은 이전에 본 적 없는 실패에 대해서도 추론(reasoning)할 수 있기 때문입니다. LLM은 사용자의 의도를 이해합니다. 어떤 대안이 존재하는지 알고 있습니다. 다른 도구를 시도할지, 사용자에게 명확한 질문을 던질지, 아니면 유용한 부분적 결과물을 생성하고 그 이유를 설명할지를 스스로 결정할 수 있습니다. catch 블록을 작성하는 개발자는 이러한 폭넓은 추론 능력을 미리 인코딩(encode)할 수 없습니다. LLM은 런타임(runtime) 시점에 모든 실패 상황에 대해 이러한 능력을 무료로 제공합니다. 단, 아키텍처(architecture)가 그럴 기회를 제공할 때에만 말입니다.

모델 중심(model-driven) 방식의 의미

모델 중심(model-driven) 프레임워크에서는 개발자와 LLM 사이의 관계가 역전됩니다.

당신은 에이전트에게 모델, 시스템 프롬프트(system prompt), 그리고 일련의 도구들을 제공합니다. 모델은 스스로의 이벤트 루프(event loop)를 구동합니다. 모델은 어떤 도구를 어떤 순서로 호출할지, 도구가 예상치 못한 결과를 반환했을 때 무엇을 할지, 그리고 응답하기에 충분한 정보가 모였을 때를 스스로 결정합니다. 당신은 오케스트레이션(orchestration)을 작성하지 않습니다. 모델이 이를 소유합니다.

개발자의 역할은 실행 경로(execution paths)를 정의하는 것에서 도구 표면(tool surface)을 정의하는 것으로 전환됩니다. 즉, 에이전트가 어떤 기능에 접근할 수 있는지, 그리고 시스템 프롬프트(system prompt)를 통해 자신에 대해 무엇을 알고 있는지를 정의하는 것입니다. 시스템 프롬프트는 아키텍처 문서(architectural document)가 됩니다. 실패 모드(failure modes)는 다르게 처리됩니다. 모델이 작성되지 않은 코드의 처리되지 않은 분기(unhandled branch)에 부딪히는 대신, 이를 추론할 수 있는 완전한 컨텍스트(context)를 갖기 때문입니다.

복구(recovery) 시나리오는 별도로 다룰 가치가 있습니다. 에이전트가 작업 중간에 실패할 때 어떤 일이 발생하는지, 그리고 왜 아키텍처적 선택이 모델과 개발자 중 누가 이를 처리할지를 결정하는지는 이 시리즈의 다음 포스트에서 다룰 주제입니다.

오늘날 .NET 생태계가 제공하고 있는 것

.NET 생태계는 워크플로 중심(workflow-driven) 방식을 기본값으로 수렴하고 있습니다. 누군가가 이를 위해 의도적인 아키텍처적 논거를 제시했기 때문이 아닙니다. 그것이 먼저 도착했고, 기존의 .NET 사고 모델(mental models)에 자연스럽게 부합하며, 점차 영향력을 얻고 있는 프레임워크들에 내장되고 있기 때문입니다.

모델 중심(model-driven) 경로는 .NET 개발자들에게 네이티브하게 존재하지 않았습니다. 그것이 바로 간극(gap)입니다. 다른 생태계에 이미 존재하는 것과 같은 네이티브하고, 모델 중심적이며, 제로 리플렉션(zero-reflection) 방식의 .NET 구현체가 .NET을 위해 구축되지 않고 있었습니다.

그것이 바로 Jacquard.NET입니다. 제가 만든 이 프레임워크는 Strands Agents의 설계 원칙에서 영감을 받아 C# 13을 기반으로 밑바닥부터 구축되었으며, .NET 개발자들에게 그들이 이미 작업하고 있는 플랫폼에 적합한 진정으로 네이티브하고, 모델 중심적이며, 런타임 리플렉션이 없는(zero runtime reflection) 경로를 제공합니다.

C# 13에서의 모델 중심 루프(model-driven loop)

using Jacquard.Core;
using Jacquard.Models.Bedrock;
using MyApp;
...

모델은 어떤 도구를 어떤 순서로 호출할지 결정합니다. 당신은 웹 검색 후 요약을 수행하는 단계를 작성하지 않았습니다. 모델은 작업이 요구하는 사항에 따라 그 경로를 선택했습니다. 도구를 추가하거나 제거하면, 루프(loop)가 그에 맞춰 적응합니다.

도구는 런타임 리플렉션 없이 Roslyn 소스 생성기(source generators)를 통해 컴파일 타임에 정의됩니다:

using Jacquard.Core;

namespace MyApp;
...

그것이 프레임워크 전반에 걸쳐 적용되는 패턴입니다. 모델이 주도하고, 도구(Tools)는 보조합니다. 개발자는 단계(Steps)가 아닌 인터페이스(Surface)를 정의합니다.

Jacquard.NET의 현재 위치

Jacquard.NET은 네 가지 모델 제공자(Model providers)를 네이티브로 지원합니다: Converse 및 ConverseStream API를 통한 Amazon Bedrock은 Anthropic, Amazon Nova, Mistral, Meta 등을 포함한 100개 이상의 모델에 대한 접근을 제공하며, Anthropic 직접 API, OpenAI를 포함하여 Ollama 및 Google Gemini를 포함한 모든 OpenAI 호환 엔드포인트(OpenAI-compatible endpoint)를 지원합니다. 단 한 줄의 코드만으로 모델을 변경할 수 있으며, 그 외의 모든 것은 동일하게 유지됩니다.

프레임워크에 내장된 에이전트 설계 패턴(Agentic design patterns)은 .NET 개발자가 단일 에이전트에서 프로덕션급 멀티 에이전트 시스템(Multi-agent system)으로 나아가는 데 필요한 모든 범위를 다룹니다. 순차적 파이프라인(Sequential pipelines), 병렬 팬아웃(Parallel fan-out), 조건부 그래프 라우팅(Conditional graph routing), 그리고 도구로서의 에이전트 계층적 구성(Agent-as-tool hierarchical composition)은 모두 작동 가능한 샘플이 포함된 퍼스트 클래스 패턴(First-class patterns)입니다. MCP는 에이전트를 모든 외부 도구 서버에 연결합니다. A2A는 HTTP를 통해 프레임워크 간, 언어 간 에이전트 통신을 가능하게 하여, Jacquard.NET 에이전트가 Strands Python 에이전트를 호출하거나 그 반대의 동작을 수행할 수 있도록 합니다.

AWS에서 구축하는 팀을 위해, 이 프레임워크는 Amazon Bedrock AgentCore 전체 영역에 걸쳐 네이티브 통합(native integration)을 제공합니다. AgentCore RuntimeMapAgentCoreEndpoints() 호출 한 번으로 세션 격리(session isolation) 및 확장된 실행 시간(extended execution windows)을 갖춘 안전한 서버리스(serverless) 환경에 모든 에이전트를 배포합니다. AgentCore Memory는 관리해야 할 인프라 없이도 상호작용 전반에 걸쳐 에이전트에게 단기 및 장기 메모리를 제공합니다. AgentCore Gateway는 기존 API, Lambda 함수 및 MCP 서버를 대규모의 에이전트용 도구(agent-ready tools)로 변환합니다. AgentCore Code Interpreter는 에이전트 루프(agent loop) 내에서 Python, JavaScript 및 TypeScript를 실행할 수 있는 안전한 샌드박스(sandbox)를 제공합니다. AgentCore Browser는 웹 상호작용 및 자동화를 위해 에이전트에게 관리형 클라우드 브라우저 세션을 제공합니다.

Jacquard.NET은 런타임 의존성이 없는 자가 포함(self-contained) Linux ARM64 바이너리로 NativeAOT에 게시되므로, .NET이 실행되는 곳이라면 어디에서나 실행됩니다. 여기에는 평균 89.6ms의 콜드 스타트(cold start)를 기록하는 AWS Lambda가 포함됩니다. 또한 Linux를 실행하는 Raspberry Pi 및 ARM 기반 IoT 엣지(edge) 장치도 포함됩니다. NativeAOT 바이너리는 JIT 워밍업(warmup)이나 설치된 런타임이 필요하지 않으며, 제로 리플렉션(zero-reflection) 설계의 최소한의 메모리 점유율(memory footprint)을 유지합니다. 소형 로컬 모델을 실행하는 Ollama와 결합하면, Jacquard.NET 에이전트는 클라우드 의존성 없이, 외부 API로 인한 지연 시간(latency) 없이, 그리고 데이터가 로컬 네트워크를 벗어나지 않고 완전히 온디바이스(on-device)로 작동할 수 있습니다. 서버리스 클라우드 환경에서 실행되는 것과 동일한 프레임워크가 단돈 £35의 비용과 5와트의 전력을 소비하는 장치에서도 실행됩니다.

해당 리포지토리에는 CLI 에이전트, ASP.NET API, Blazor, Step Functions 내구성 (durability), Lambda NativeAOT, 그리고 전체 AgentCore 통합 인터페이스를 다루는 20개의 작동 가능한 샘플이 포함되어 있습니다.

생태계에 필요한 아키텍처적 선택지

워크플로 중심 (Workflow-driven) 방식은 그 자리를 확고히 했습니다. 이 방식이 정답인 워크로드 (workloads)가 존재하며, 앞으로도 그럴 것입니다. 여기서의 논점은 이 방식에 반대하는 것이 아닙니다. .NET 개발자에게 실질적으로 제공되는 유일한 선택지가 이 방식뿐이라는 점에 반대하는 것입니다.

문서 처리 파이프라인을 구축하는 개발자는 워크플로 중심 방식을 선택하여 충분한 지원을 받아야 합니다. 반면, 연구 에이전트, 장기 실행되는 자율 작업, 또는 모호함 속에서 진정한 모델의 판단이 필요한 무언가를 구축하는 개발자는 모델 중심 (model-driven) 방식을 선택하여 네이티브 .NET 환경에서 동일하게 충분한 지원을 받아야 합니다.

생태계에는 아직 그러한 선택지가 마땅히 있어야 할 수준으로 존재하지 않습니다. Jacquard.NET은 그 시작입니다.

만약 .NET을 위한 에이전트 프레임워크 (agentic frameworks)를 평가하고 있다면, 비교해야 할 가치가 있는 것은 단순한 기능 커버리지가 아닙니다. 바로 아키텍처적 적합성 (architectural fit)입니다. 당신의 작업은 어떤 형태를 띠고 있습니까? 실행 결정은 누가 내려야 합니까? 작업 중간에 아무도 미리 정의하지 않은 문제가 발생했을 때 복구 (recovery)는 어떤 모습이어야 합니까?

이러한 질문들은 네이티브 .NET 방식의 답변을 요구합니다.

이 내용에 공감하신다면, 여기서 시작하세요: github.com/apncodes/Jacquard.NET

README를 통해 첫 번째 에이전트를 구축하는 과정을 안내받을 수 있습니다. 샘플은 CLI부터 Blazor, Lambda에 이르기까지 전체 범위를 다룹니다. 실제 워크로드를 가져와서 그것으로 무언가를 직접 구축해 보고, 무엇이 부족한지 Discussions를 통해 알려주세요.

이것은 커뮤니티 SDK입니다. 더 많은 개발자가 이를 가져가서 실제 무언가를 구축하려고 시도할수록, .NET 에이전트 생태계가 실제로 필요로 하는 모습으로 더 빠르게 진화할 것입니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0