.NET을 사용하여 Microsoft Foundry Agent Service로 첫 번째 에이전트 구축하기
요약
C#과 .NET을 사용하여 Microsoft Foundry Agent Service에서 에이전트를 구축하는 실전 가이드를 제공합니다. 공식 문서의 Python 중심 설명과 명칭 변경(Azure AI Foundry → Microsoft Foundry)으로 인한 혼란을 해결하기 위한 리소스 프로비저닝 및 RBAC 설정 방법을 다룹니다.
핵심 포인트
- C# SDK를 활용한 Microsoft Foundry Agent Service 구축 방법 안내
- Azure AI Foundry에서 Microsoft Foundry로의 명칭 및 RBAC 역할 변경 사항 설명
- 에이전트 구축에 필요한 4가지 필수 Azure 리소스 정의
- 안정적인 배포를 위한 역할 정의 GUID 사용 및 지역(East US 2) 권장
이번 포스트에서는 C#을 사용하여 Microsoft Foundry Agent Service에서 저의 첫 번째 에이전트를 구축하는 과정에 어떻게 접근했는지 공유하고자 합니다. 실제로 필요한 모든 리소스, 이를 프로비저닝하는 모든 CLI 명령, 그리고 가정이 아닌 설명이 포함된 SDK 코드를 제공합니다. 만약 더 깔끔한 설정 방법을 찾으셨거나, 제가 여기서 언급한 트레이드오프(trade-offs) 중 동의하지 않는 부분이 있다면 진심으로 의견을 듣고 싶습니다.
제가 이 글을 쓰는 이유는 공식 퀵스타트(quickstart)가 Python 중심이며, azd 스캐폴딩(scaffolding) 뒤에 Azure 설정을 숨겨두었기 때문입니다. 공식 문서에서는 실제로 어떤 리소스가 필요한지, RBAC 역할 할당(role assignments)은 무엇인지, 왜 SDK가 이제 4개의 NuGet 패키지를 제공하며 그중 어떤 것이 빌드를 조용히 깨뜨릴 수 있는지 알려주지 않습니다. C# SDK는 2026년 중반에 2.0.0 버전으로 안정화되었고, 같은 시기에 제품명이 Azure AI Foundry에서 변경되었으며, RBAC 역할 이름도 변경되었습니다. 문서를 처음 접하면 세 가지 별개의 사항이 동시에 고장 난 것처럼 보일 것입니다. 하지만 실제로는 그렇지 않습니다.
첫째, 명칭 상황
이 서비스는 Azure AI Foundry라고 불렸습니다. 현재는 Microsoft Foundry라고 불립니다. RBAC 역할(roles)도 함께 변경되었습니다. 개발자에게 프로젝트 액세스 권한을 부여하기 위해 할당하는 역할은 이제 Foundry User(이전에는 Azure AI User)입니다. 역할 ID(GUID)는 변경되지 않았으며, 이는 할당을 스크립트로 작성할 때 중요합니다. 포털 화면, 오류 메시지, 그리고 많은 기존 튜토리얼들은 여전히 이전 이름을 사용하고 있습니다. 여러분이 혼란스러운 것이 아니라, 배포(rollout)가 아직 완료되지 않은 것뿐입니다.
Azure에서 필요한 사항
네 가지입니다:
- Foundry 리소스 (최상위 Azure 리소스, kind
AIServices) - 해당 리소스 내의 프로젝트
- 배포된 모델
- 사용자의 ID가 API를 호출할 수 있도록 하는 역할 할당(role assignment)
그게 전부입니다. 기본적인 프롬프트-에이전트(prompt-agent) 경로를 위해서는 스토리지 계정(Storage account)도, 검색 인덱스(Search index)도, 그 외 다른 것도 필요하지 않습니다. 여기 설정 스크립트가 있습니다:
#!/usr/bin/env bash
# setup.sh — Foundry Agent Service 예제에 필요한 모든 Azure 리소스를 프로비저닝합니다.
# 어느 디렉토리에서든 실행 가능합니다. Azure CLI (az)가 설치되어 있고 로그인된 상태여야 합니다.
...
주의해야 할 몇 가지 사항이 있습니다. --custom-domain 값은 프로젝트 엔드포인트 (endpoint) URL의 일부가 되며 전역적으로 고유해야 하므로, 단순히 foundry-agent-demo가 아닌 귀사의 조직에 특화된 이름을 선택하십시오. --allow-project-management 플래그는 리소스 생성 후 변경할 수 없으므로 생략하지 마십시오.
할당 시 표시 이름 (display name) 대신 역할 정의 (role definition) GUID를 사용하십시오. 표시 이름은 최근에 이름이 변경되었으며, 테넌트 (tenant)에 따라 배포 기간 동안 잘못 해석될 수 있습니다. GUID는 안정적입니다.
선택할 수 있다면 East US 2 지역에 배포하십시오. 모델 라우터 (model router)와 모든 표준 내장 도구 (built-in tool)를 사용할 수 있습니다. 일부 지역에는 도구가 누락되어 있으므로, 코드 인터프리터 (code interpreter)나 파일 검색 (file search)을 사용할 계획이라면 확정하기 전에 도구 가용성 매트릭스 (tool availability matrix)를 확인하는 것이 좋습니다.
코드에서 사용할 프로젝트 엔드포인트는 https://<resource-name>.services.ai.azure.com/api/projects/<project-name>와 같은 형태입니다. 프로비저닝이 완료되면 Foundry 포털에서 복사하거나, 스크립트에서 사용한 이름을 바탕으로 직접 구성하십시오.
프롬프트 에이전트 (Prompt agents)인가요, 호스팅된 에이전트 (hosted agents)인가요?
코드를 작성하기 전에 실제로 무엇을 구축하고 있는지 명확히 하는 것이 중요합니다. Foundry Agent Service에는 의미론적으로 다른 두 가지 모드가 있습니다.
**프롬프트 에이전트 (Prompt agents)**는 모델 (model), 지침 (instructions), 도구 (tools)를 선언적으로 정의합니다. Foundry가 이를 대신 실행해 줍니다. 유지 관리할 애플리케이션 코드가 없으며, 지불해야 할 컴퓨팅 (compute) 비용도 없습니다. Responses API로 요청을 보내면 답변을 받게 됩니다. 내부 도구, 질의응답 (question-answering), 커스텀 오케스트레이션 (orchestration) 로직이 없는 파이프라인의 경우 이 방식부터 시작하는 것을 권장합니다.
**호스팅된 에이전트 (Hosted agents)**는 직접 작성한 코드(Agent Framework, LangGraph, OpenAI Agents SDK 또는 기타)를 컨테이너 (container)로 패키징하여 Foundry가 관리하는 컴퓨팅에서 실행하는 방식입니다. 관리형 엔드포인트, 오토스케일링 (autoscaling), 전용 Entra ID를 제공받습니다. 또한 추론 (inference) 비용 외에 컨테이너 컴퓨팅 비용을 추가로 지불하게 됩니다. 단순히 설정만 필요한 것이 아니라 에이전트에 내장된 커스텀 비즈니스 로직이 필요한 경우 이 방식이 적절한 선택입니다.
이 글에서는 프롬프트 에이전트 (prompt agents)를 다룹니다. .NET에서 호스팅되는 에이전트 (Hosted agents)는 Microsoft Agent Framework (별도의 오픈 소스 프로젝트)를 사용하며, 별도로 다룰 만큼 충분히 차이가 있습니다. 이 시리즈의 다음 포스트에서 해당 내용을 다루겠습니다.
패키지 — 그리고 피해야 할 패키지
Foundry를 위한 C# SDK는 네 가지 패키지가 필요합니다:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
...
Azure.AI.Projects는 Foundry 프로젝트 API에 대한 얇은 클라이언트 (thin client)입니다. Azure.AI.Projects.Agents는 에이전트 관리 인터페이스(에이전트 정의 생성, 버전 관리 및 삭제)를 추가합니다. Azure.AI.Extensions.OpenAI는 에이전트를 호출할 때 사용하는 것으로, 프로젝트 엔드포인트의 Responses API를 호출하는 ProjectResponsesClient를 제공합니다. Azure.Identity는 자격 증명 (credentials)을 담당합니다.
피해야 할 것은 Azure.AI.Projects.OpenAI입니다. 이는 다른 네임스페이스 (namespace)에 동일한 타입을 정의하는 프리뷰 (preview) 패키지입니다. 이를 Azure.AI.Extensions.OpenAI와 함께 설치하면, 원인을 찾아내는 데 시간이 걸리는 모호한 참조 컴파일 오류 (ambiguous reference compile errors)가 발생합니다. 프로젝트 파일의 주석에도 동일한 내용이 명시되어 있습니다. 그냥 추가하지 마세요.
첫 번째 에이전트 생성하기
다음은 완전한 콘솔 애플리케이션 예시입니다. 프롬프트 에이전트를 생성하고, 질문을 던진 다음, 모델이 첫 번째 답변을 기억해야만 의미가 있는 후속 질문을 던집니다:
using Azure.AI.Extensions.OpenAI;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
...
몇 가지 살펴볼 사항이 있습니다.
AIProjectClient는 프로젝트 엔드포인트 URI와 TokenCredential을 인자로 받습니다. 로컬 환경에서는 DefaultAzureCredential이 az login을 통해 해결됩니다. 프로덕션 환경에서는 코드 변경 없이 관리 ID (managed identity)를 가져옵니다.
ClientResult<T>는 서비스로부터 무언가를 반환하는 모든 메서드에 나타납니다. 이는 System.ClientModel 패키지에 포함되어 있으며 전이적으로 (transitively) 불러와지지만, 파일에 using System.ClientModel;을 여전히 추가해야 합니다. 실제 객체를 얻으려면 .Value를 호출하세요.
DeclarativeAgentDefinition은 모델 선택과 시스템 지침 (system instructions)이 정의되는 곳입니다. 이는 Foundry에 버전 관리된 정의를 등록하는 CreateAgentVersion으로 전달됩니다. 각 호출은 새로운 불변 (immutable) 버전을 생성합니다. 이 메서드는 ClientResult<ProjectsAgentVersion>을 반환하며, .Value를 호출하여 호출 시점에 참조하게 될 안정적인 이름과 버전 문자열을 포함하는 ProjectsAgentVersion을 얻을 수 있습니다.
ProjectConversation은 턴 (turn) 간의 히스토리를 전달하는 역할을 합니다. GetProjectResponsesClientForAgent에 new AgentReference(agentVersion.Name)와 함께 대화 ID (conversation ID)를 전달하면, 해당 클라이언트의 각 CreateResponse 호출 시 이전 컨텍스트 (context)가 자동으로 포함됩니다. 한 가지 세부 사항은, CreateResponse는 null을 전달하더라도 항상 previousResponseId 인자를 요구한다는 점입니다. 예제에 나오는 두 번째 질문이 "그 도시"가 무엇을 가리키는지 알 수 있는 이유는 대화 바인딩 (conversation binding) 덕분이지, 사용자가 직접 히스토리를 이어 붙였기 때문이 아닙니다. 솔직히 이 부분이 저를 가장 놀라게 했습니다. 예상보다 작업량이 적습니다.
웹 검색 (web search) 추가하기
웹 검색 도구는 에이전트의 응답을 실시간 공개 웹 데이터에 기반하도록 합니다 (grounding). 내부적으로는 Bing Search를 실행합니다. 이를 활성화하기 전에 알아두어야 할 두 가지 사항이 있습니다. 쿼리당 추가 비용이 발생하며, Microsoft 데이터 보호 부속서 (Data Protection Addendum)가 Bing으로 전송되는 데이터에는 적용되지 않는다는 점입니다. 규제 환경에 있다면 먼저 Bing을 이용한 그라운딩 (Grounding with Bing) 약관을 확인하십시오. 내부 도구나 프로토타입 용도로는 괜찮습니다.
에이전트 정의의 변경 사항은 작습니다:
using Azure.AI.Extensions.OpenAI;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
...
호출 방식은 기본 예제와 동일합니다. CreateResponse는 ClientResult<ResponseResult>를 반환하며, 텍스트를 얻으려면 .Value.GetOutputText()를 호출하면 됩니다. 차이점은 해당 응답에 무엇이 첨부되어 있는가에서 나타납니다. 출력 항목에는 모델이 인용한 출처에 대한 UriCitationMessageAnnotation 항목이 포함되어 있습니다.
이 코드를 복사할 때 주의해야 할 두 가지 사항이 있습니다. 첫째, 올바른 팩토리(factory)는 CreateWebSearchTool이 아니라 ResponseTool.CreateWebSearchPreviewTool입니다. OpenAI 2.9.x 버전에는 두 가지가 모두 존재합니다. CreateWebSearchTool은 `
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기