이 세션에서는 앞서 개발한 프론트엔드 웹 UI앱과 백엔드 에이전트 앱을 Aspire를 이용해 오케스트레이션합니다.
- Aspire를 이용해서 프론트엔드 웹 UI와 백엔드 에이전트 및 LLM 커넥션을 오케스트레이션할 수 있습니다.
- Aspire를 통해 Observability(관측용이성) 및 Traceability(추적용이성) 등 클라우드네이티브 관련 기능을 설정할 수 있습니다.
- 전체 애플리케이션을 Azure 클라우드로 배포할 수 있습니다.
이 세션이 끝나고 나면 아래와 같은 시스템이 만들어집니다.
이전 00: 개발 환경 설정에서 개발 환경을 모두 설정한 상태라고 가정합니다.
-
아래 명령어를 실행시켜
$REPOSITORY_ROOT환경 변수를 설정합니다.# zsh/bash REPOSITORY_ROOT=$(git rev-parse --show-toplevel)
# PowerShell $REPOSITORY_ROOT = git rev-parse --show-toplevel
이 워크샵을 위해 필요한 시작 프로젝트를 준비해 뒀습니다. 시작 프로젝트의 프로젝트 구조는 아래와 같습니다.
save-points/
└── step-04/
└── start/
├── MafWorkshop.sln
├── MafWorkshop.Agent/
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── Program.cs
│ ├── appsettings.json
│ └── MafWorkshop.Agent.csproj
├── MafWorkshop.WebUI/
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── Components/
│ │ └── < Razor component files >
│ ├── wwwroot/
│ │ └── < HTML/CSS/JS files >
│ ├── Program.cs
│ ├── appsettings.json
│ └── MafWorkshop.WebUI.csproj
├── MafWorkshop.AppHost/
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── Program.cs
│ ├── appsettings.json
│ └── MafWorkshop.AppHost.csproj
└── MafWorkshop.ServiceDefaults/
├── Extension.cs
└── MafWorkshop.ServiceDefaults.csproj
프로젝트 소개:
MafWorkshop.Agent: 백엔드 에이전트 애플리케이션 프로젝트MafWorkshop.WebUI: 프론트엔드 웹 UI 애플리케이션 프로젝트MafWorkshop.AppHost: Aspire 오케스트레이션 프로젝트MafWorkshop.ServiceDefaults: Aspire Observability 및 Traceability 확장 프로젝트
-
앞서 실습한
workshop디렉토리가 있다면 삭제하거나 다른 이름으로 바꿔주세요. 예)workshop-step-03 -
터미널을 열고 아래 명령어를 차례로 실행시켜 실습 디렉토리를 만들고 시작 프로젝트를 복사합니다.
# zsh/bash rm -rf $REPOSITORY_ROOT/workshop && \ mkdir -p $REPOSITORY_ROOT/workshop && \ cp -a $REPOSITORY_ROOT/save-points/step-04/start/. $REPOSITORY_ROOT/workshop/
# PowerShell Remove-Item -Path $REPOSITORY_ROOT/workshop -Recurse -Force && ` New-Item -Type Directory -Path $REPOSITORY_ROOT/workshop -Force && ` Copy-Item -Path $REPOSITORY_ROOT/save-points/step-04/start/* -Destination $REPOSITORY_ROOT/workshop -Recurse -Force
-
워크샵 디렉토리에 있는지 다시 한 번 확인합니다.
cd $REPOSITORY_ROOT/workshop
-
전체 프로젝트를 빌드합니다.
dotnet restore && dotnet build -
백엔드 에이전트 애플리케이션을 실행합니다.
dotnet run --project ./MafWorkshop.Agent
-
다른 터미널을 열고 프론트엔드 UI 애플리케이션을 실행합니다. 새 터미널에서는
$REPOSITORY_ROOT값을 인식하지 못하므로 리포지토리 루트 설정 섹션을 다시 다시 실행시켜야 합니다.cd $REPOSITORY_ROOT/workshop dotnet watch run --project ./MafWorkshop.WebUI
-
자동으로 웹 브라우저가 열리면서 아래와 같은 챗 UI 페이지가 나타나는지 확인합니다.
아무 문장이나 입력한 후 결과를 확인합니다.
-
두 터미널에서 각각
CTRL+C키를 눌러 모든 애플리케이션 실행을 종료합니다.
-
워크샵 디렉토리에 있는지 다시 한 번 확인합니다.
cd $REPOSITORY_ROOT/workshop
-
아래 명령어를 실행시켜 Observability 및 Traceability 도구를 추가합니다.
dotnet add ./MafWorkshop.Agent reference ./MafWorkshop.ServiceDefaults
-
./MafWorkshop.Agent/Program.cs파일을 열고// Observability 및 Traceability를 위한 Service Defaults 추가하기주석을 찾아 아래 내용을 추가합니다. 이를 통해 다양한 Observability 및 Traceability 기능 관련 인스턴스를 의존성 개체로 등록합니다.// Observability 및 Traceability를 위한 Service Defaults 추가하기 builder.AddServiceDefaults();
-
같은 파일에서
// Observability 및 Traceability를 위한 미들웨어 설정하기주석을 찾아 아래와 같이 입력합니다. 서비스의 가용성 확인을 위한 헬스체크 엔드포인트를 추가하는 미들웨어입니다.// Observability 및 Traceability를 위한 미들웨어 설정하기 app.MapDefaultEndpoints();
-
워크샵 디렉토리에 있는지 다시 한 번 확인합니다.
cd $REPOSITORY_ROOT/workshop
-
아래 명령어를 실행시켜 Observability 및 Traceability 도구를 추가합니다.
dotnet add ./MafWorkshop.WebUI reference ./MafWorkshop.ServiceDefaults
-
./MafWorkshop.WebUI/Program.cs파일을 열고// Observability 및 Traceability를 위한 Service Defaults 추가하기주석을 찾아 아래 내용을 추가합니다. 백엔드 에이전트 앱과 마찬가지로 이를 통해 다양한 Observability 및 Traceability 기능 관련 인스턴스를 의존성 개체로 등록합니다.// Observability 및 Traceability를 위한 Service Defaults 추가하기 builder.AddServiceDefaults();
-
같은 파일에서
// Observability 및 Traceability를 위한 미들웨어 설정하기주석을 찾아 아래와 같이 입력합니다. 백엔드 에이전트 앱과 마찬가지로 서비스의 가용성 확인을 위한 헬스체크 엔드포인트를 추가하는 미들웨어입니다.// Observability 및 Traceability를 위한 미들웨어 설정하기 app.MapDefaultEndpoints();
-
워크샵 디렉토리에 있는지 다시 한 번 확인합니다.
cd $REPOSITORY_ROOT/workshop
-
아래 명령어를 실행시켜 오케스트레이션을 위한 백엔드 및 프론트엔드 애플리케이션을 추가합니다.
dotnet add ./MafWorkshop.AppHost reference ./MafWorkshop.Agent dotnet add ./MafWorkshop.AppHost reference ./MafWorkshop.WebUI
-
아래 명령어를 실행시켜 Aspire 오케스트레이션을 위한 호스트 패키지를 설치합니다.
dotnet add ./MafWorkshop.AppHost package Aspire.Hosting.GitHub.Models dotnet add ./MafWorkshop.AppHost package Aspire.Hosting.OpenAI
-
./MafWorkshop.AppHost/AppHost.cs파일을 열고// LlmResourceFactory 클래스 추가하기주석을 찾아 아래 내용을 추가합니다. 백엔드 에이전트 앱에서 구현했던ChatClientFactory클래스와 비슷한 형태라고 볼 수 있습니다. 다만,ChatClientFactory클래스에서는IChatClient인스턴스를 직접 생성하지만,LlmResourceFactory클래스는 리소스 레퍼런스를 생성한다는 차이가 있습니다.// LlmResourceFactory 클래스 추가하기 public static class LlmResourceFactory { public static IResourceBuilder<ProjectResource> WithLlmReference(this IResourceBuilder<ProjectResource> source, IConfiguration config, IEnumerable<string> args) { var provider = config["LlmProvider"]; // 커맨드라인 파라미터 확인 로직 추가하기 if (string.IsNullOrWhiteSpace(provider)) { throw new InvalidOperationException("Missing configuration: LlmProvider"); } source = provider switch { "GitHubModels" => source.AddGitHubModelsResource(config, provider), "AzureOpenAI" => source.AddAzureOpenAIResource(config, provider), _ => throw new NotSupportedException($"The specified LLM provider '{provider}' is not supported.") }; return source; } // AddGitHubModelsResource 메서드 추가하기 // AddAzureOpenAIResource 메서드 추가하기 }
-
같은 파일에서
// 커맨드라인 파라미터 확인 로직 추가하기주석을 찾아 아래 내용을 추가합니다. 커맨드라인 파라미터의--provider값을 확인해서 기존appsettings.json파일의 값보다 우선적으로 적용할 수 있도록 합니다.// 커맨드라인 파라미터 확인 로직 추가하기 foreach (var arg in args) { var index = args.ToList().IndexOf(arg); switch (arg) { case "--provider": provider = args.ToList()[index + 1]; break; } }
-
같은 파일에서
// AddGitHubModelsResource 메서드 추가하기주석을 찾아 아래와 같이 입력합니다. GitHub Models 연결 정보를 통해 LLM 리소스를 연결합니다.// AddGitHubModelsResource 메서드 추가하기 private static IResourceBuilder<ProjectResource> AddGitHubModelsResource(this IResourceBuilder<ProjectResource> source, IConfiguration config, string provider) { var github = config.GetSection("GitHub"); var endpoint = github["Endpoint"] ?? throw new InvalidOperationException("Missing configuration: GitHub:Endpoint"); var token = github["Token"] ?? throw new InvalidOperationException("Missing configuration: GitHub:Token"); var model = github["Model"] ?? throw new InvalidOperationException("Missing configuration: GitHub:Model"); Console.WriteLine(); Console.WriteLine($"\tUsing {provider}: {model}"); Console.WriteLine(); var apiKey = source.ApplicationBuilder .AddParameter(name: "apiKey", value: token, secret: true); var chat = source.ApplicationBuilder .AddGitHubModel(name: "chat", model: model) .WithApiKey(apiKey); return source.WithReference(chat) .WaitFor(chat); }
-
같은 파일에서
// AddAzureOpenAIResource 메서드 추가하기주석을 찾아 아래와 같이 입력합니다. Azure OpenAI 연결 정보를 통해 LLM 리소스를 연결합니다.// AddAzureOpenAIResource 메서드 추가하기 private static IResourceBuilder<ProjectResource> AddAzureOpenAIResource(this IResourceBuilder<ProjectResource> source, IConfiguration config, string provider) { var azure = config.GetSection("Azure:OpenAI"); var endpoint = azure["Endpoint"] ?? throw new InvalidOperationException("Missing configuration: Azure:OpenAI:Endpoint"); var accessKey = azure["ApiKey"] ?? throw new InvalidOperationException("Missing configuration: Azure:OpenAI:ApiKey"); var deploymentName = azure["DeploymentName"] ?? throw new InvalidOperationException("Missing configuration: Azure:OpenAI:DeploymentName"); Console.WriteLine(); Console.WriteLine($"\tUsing {provider}: {deploymentName}"); Console.WriteLine(); var apiKey = source.ApplicationBuilder .AddParameter(name: "apiKey", value: accessKey, secret: true); var chat = source.ApplicationBuilder .AddOpenAI("openai") .WithEndpoint($"{endpoint.TrimEnd('/')}/openai/v1/") .WithApiKey(apiKey) .AddModel(name: "chat", model: deploymentName); return source.WithReference(chat) .WaitFor(chat); }
-
같은 파일에서
// 백엔드 에이전트 프로젝트 추가하기주석을 찾아 아래와 같이 입력합니다. 백엔드 에이전트 앱을agent라는 리소스로 선언하고 여기에 앞서 작성한WithLlmReference메소드를 통해 LLM 리소스를 연결합니다.// 백엔드 에이전트 프로젝트 추가하기 var agent = builder.AddProject<Projects.MafWorkshop_Agent>("agent") .WithLlmReference(builder.Configuration, args);
-
같은 파일에서
// 프론트엔드 웹 UI 프로젝트 추가하기주석을 찾아 아래와 같이 입력합니다. 프론트엔드 웹 UI 앱을webUI라는 리소스로 선언하고 거기에 방금 작성한agent리소스를 연결합니다.// 프론트엔드 웹 UI 프로젝트 추가하기 var webUI = builder.AddProject<Projects.MafWorkshop_WebUI>("webui") .WithExternalHttpEndpoints() .WithReference(agent) .WaitFor(agent);
-
워크샵 디렉토리에 있는지 다시 한 번 확인합니다.
cd $REPOSITORY_ROOT/workshop
-
아래 명령어를 실행시켜 Aspire 오케스트레이션을 위한 클라이언트 패키지를 백엔드 에이전트 애플리케이션에 설치합니다.
dotnet add ./MafWorkshop.Agent package Aspire.OpenAI --prerelease
-
./MafWorkshop.Agent/appsettings.json파일을 열고LlmProvider,Azure,GitHub항목을 모두 삭제합니다. Aspire의AppHost프로젝트에서 대신 해결해 주기 때문에 더이상 이 로직이 필요없습니다. -
./MafWorkshop.Agent/Program.cs파일을 열고// IChatClient 인스턴스 생성하기주석을 찾아 바로 아래에 있는 코드를 삭제합니다. 마찬가지로 Aspire의AppHost프로젝트에서 대신 해결해 주기 때문에 더이상 이 로직이 필요없습니다.삭제전:
// IChatClient 인스턴스 생성하기 IChatClient? chatClient = ChatClientFactory.CreateChatClient(builder.Configuration);
삭제후: 주석만 남아있습니다.
// IChatClient 인스턴스 생성하기 -
같은 파일에서
// IChatClient 인스턴스 등록하기주석을 찾아 아래와 같이 변경합니다. Aspire에서 넘어오는IChatClient인스턴스를 직접 의존성 개체로 등록합니다.변경전:
// IChatClient 인스턴스 등록하기 builder.Services.AddChatClient(chatClient);
변경후:
// IChatClient 인스턴스 등록하기 builder.AddOpenAIClient("chat") .AddChatClient();
-
워크샵 디렉토리에 있는지 다시 한 번 확인합니다.
cd $REPOSITORY_ROOT/workshop
-
./MafWorkshop.WebUI/appsettings.json파일을 열고AgentEndpoints항목을 삭제합니다. Aspire의AppHost프로젝트에서 대신 해결해 주기 때문에 더이상 이 로직이 필요없습니다. -
./MafWorkshop.WebUI/Program.cs파일을 열고// HttpClientFactory 등록하기주석을 찾아 아래와 같이 변경합니다. 마찬가지로 Aspire의AppHost프로젝트에서 대신 해결해 주기 때문에 Aspire에서 전달 받은IHttpClientFactory인스턴스를 의존성 개체로 등록합니다.변경전:
// HttpClientFactory 등록하기 builder.Services.AddHttpClient("agent", client => { var endpoint = builder.Environment.IsDevelopment() == true ? builder.Configuration["AgentEndpoints:Http"] : builder.Configuration["AgentEndpoints:Https"]; client.BaseAddress = new Uri(endpoint!); });
변경후:
// HttpClientFactory 등록하기 builder.Services.AddHttpClient("agent", client => { client.BaseAddress = new Uri("https+http://agent"); });
-
워크샵 디렉토리에 있는지 다시 한 번 확인합니다.
cd $REPOSITORY_ROOT/workshop
-
전체 프로젝트를 빌드합니다.
dotnet restore && dotnet build -
Aspire 오케스트레이션 애플리케이션을 실행합니다.
dotnet watch run --project ./MafWorkshop.AppHost
-
자동으로 웹 브라우저가 열리면서 아래와 같은 Aspire 대시보드 페이지가 나타나는지 확인합니다.
NOTE: 만약 대시보드 페이지가 보이지 않고 에러가 난다면 터미널에서 아래와 비슷한 URL을 클릭해서 대시보드를 열어보세요.
https://awesome-workshop-45397.app.github.dev/login?t=12345678abcdefgh90123456ijklmnop -
터미널에서
CTRL+C키를 눌러 애플리케이션 실행을 종료합니다. -
./MafWorkshop.AppHost/appsettings.json파일을 열고LlmProvider값을AzureOpenAI로 변경합니다.또는 커맨드라인 파라미터를 통해
LlmProvider값을AzureOpenAI로 변경해 보세요.dotnet watch run --project ./MafWorkshop.AppHost -- --provider AzureOpenAI
-
다시 Aspire 오케스트레이션 앱을 실행시켜 아래와 같은 Aspire 대시보드 페이지가 나타나는지 확인합니다.
-
백엔드 에이전트 앱 링크를 클릭해서 Dev UI 화면이 잘 보이는지 확인합니다. 그리고, Publish 워크플로우를 선택해서 잘 동작하는지 확인합니다.
-
프론트엔드 웹 UI 앱 링크를 클릭해서 챗 UI 화면이 잘 보이는지 확인합니다. 그리고, 메시지를 입력해서 결과를 잘 출력하는지 확인합니다.
-
Aspire 대시보드에서 Traces 탭으로 이동합니다. 그리고
agent리소스를 선택한 후 전체 데이터 흐름을 살펴봅니다.프론트엔드 웹 UI 화면부터 백엔드 에이전트를 거쳐 LLM 서비스까지 데이터가 오고간 과정을 확인합니다.
-
터미널에서
CTRL+C키를 눌러 애플리케이션 실행을 종료합니다.
NOTE: Azure 구독을 제공 받았을 경우 진행하세요. 워크샵에 따라 Azure 구독을 제공하지 않을 수도 있습니다.
-
워크샵 디렉토리에 있는지 다시 한 번 확인합니다.
cd $REPOSITORY_ROOT/workshop
-
./MafWorkshop.AppHost/appsettings.json파일을 열고LlmProvider값이GitHubModels인지AzureOpenAI인지 확인합니다. -
아래 명령어를 실행시켜 전체 애플리케이션을 배포하세요.
azd up
아래와 같은 질문이 나오면 적당하게 입력합니다.
? Enter a unique environment name:👉 환경 이름 (예:mafworkshop-2026)? Enter a value for the 'apiKey' infrastructure secured parameter:👉 API 키 값 입력 -LlmProvider값이GitHubModels이면 GitHub PAT 값을,AzureOpenAI이면 Azure OpenAI 인스턴스의 API 키 값을 입력합니다.
잠시 기다리면 프론트엔드 웹 UI 및 백엔드 에이전트를 배포한 Azure Container Apps 인스턴스가 각각 만들어진 것을 확인할 수 있습니다.
-
위 스크린샷의
webui링크를 클릭해서 웹 UI 화면이 나오면 메시지를 입력해서 결과를 잘 출력하는지 확인합니다. -
아래 명령어를 실행시켜 방금 배포한 애플리케이션을 모두 삭제합니다.
azd down --purge --force
이 세션의 완성본은 $REPOSITORY_ROOT/save-points/step-04/complete에서 확인할 수 있습니다.
-
앞서 실습한
workshop디렉토리가 있다면 삭제하거나 다른 이름으로 바꿔주세요. 예)workshop-step-04 -
터미널을 열고 아래 명령어를 차례로 실행시켜 실습 디렉토리를 만들고 시작 프로젝트를 복사합니다.
# zsh/bash rm -rf $REPOSITORY_ROOT/workshop && \ mkdir -p $REPOSITORY_ROOT/workshop && \ cp -a $REPOSITORY_ROOT/save-points/step-04/complete/. $REPOSITORY_ROOT/workshop/
# PowerShell Remove-Item -Path $REPOSITORY_ROOT/workshop -Recurse -Force && ` New-Item -Type Directory -Path $REPOSITORY_ROOT/workshop -Force && ` Copy-Item -Path $REPOSITORY_ROOT/save-points/step-04/complete/* -Destination $REPOSITORY_ROOT/workshop -Recurse -Force
-
워크샵 디렉토리로 이동합니다.
cd $REPOSITORY_ROOT/workshop
-
애플리케이션 빌드 및 실행 섹션을 따라합니다.
-
애플리케이션 배포 및 실행 섹션을 따라합니다.
축하합니다! Aspire로 프론트엔드 웹 UI와 백엔드 에이전트 앱 그리고 다양한 LLM을 모두 오케스트레이션했습니다. 이제 다음 단계로 이동하세요!
👈 03: Microsoft Agent Framework 사용해서 다중 에이전트 개발하기 | 05: MCP 서버 개발하기 👉









{ "LlmProvider": "AzureOpenAI" }