
들어가며
코드로 AI 에이전트를 개발한다고 하면 복잡한 프로젝트 구조, Dockerfile, 컨테이너 레지스트리와 CI/CD 파이프라인부터 떠올리기 쉽습니다. 하지만 .NET 10부터 새롭게 도입된 파일 기반 앱 (File-based App) 기능을 사용하면 Visual Studio나 .csproj 없이, 선호하는 코드 에디터와 .NET CLI만으로 Python 스크립트를 작성하듯 C# 파일 만으로 에이전트를 작성하고 Microsoft Foundry에 배포하여 실행하도록 만들 수 있습니다.
이 글은 C#과 Azure에 익숙하지만 Hosted Agent를 처음 접하는 개발자를 대상으로 합니다. 최소한의 코드로 에이전트를 실행하는 방법뿐 아니라 Linux용 게시, Foundry 배포, 버전 활성화와 실제 호출 검증까지 이어지는 전체 흐름을 다룹니다. 기존 .NET 코드나 사내 시스템을 AI 에이전트로 확장하려는 개발자와 아키텍트에게도 출발점이 될 수 있습니다.
이 글의 모든 내용은 Linux, macOS, 그리고 Windows에서 동일한 흐름으로 실행해볼 수 있으며, 전체 예제는 아래 GitHub Gist에서 확인할 수 있습니다.
https://gist.github.com/rkttu/5a258b2f52e122d4893e1b89951d20a8
Microsoft Foundry Hosted Agent란?
Microsoft Foundry는 프롬프트와 도구 설정만으로 구성하는 Prompt Agent와 개발자가 작성한 코드를 직접 실행하는 Hosted Agent를 지원합니다.
Prompt Agent는 빠르게 에이전트를 구성하고 운영 부담을 줄이고 싶을 때 적합합니다. 반면 Hosted Agent는 다음과 같이 코드 수준의 제어가 필요한 경우에 적합합니다.
- 사내 API나 데이터베이스를 호출해야 하는 경우
- 복잡한 조건 분기와 업무 규칙을 구현해야 하는 경우
- 기존 .NET 코드와 Azure SDK를 재사용해야 하는 경우
- 자체적인 도구 호출 및 에이전트 오케스트레이션이 필요한 경우
- 비동기 작업이나 멀티 에이전트 구조가 필요한 경우
Hosted Agent에서는 개발자가 에이전트의 로직을 작성하고, Foundry가 실행 환경을 관리합니다. 여기에는 관리형 엔드포인트, 자동 확장, 에이전트 전용 ID, 세션 관리와 관측성이 포함됩니다. Microsoft Learn은 Hosted Agent를 개발자가 에이전트 로직을 직접 제어하면서 호스팅, 확장, ID 관리는 Foundry에 맡기는 방식으로 설명합니다.
역할을 구분하면 다음과 같습니다.
| 구성 요소 | 역할 |
|---|---|
| AI 모델 | 자연어 이해, 추론, 요약, 응답 생성 |
| C# 에이전트 코드 | 업무 규칙, 도구 호출, 입력 검증, 시스템 연동 |
| Microsoft Foundry | 호스팅, 확장, 엔드포인트, ID, 세션, 관측성 |
Hosted Agent의 핵심은 모델에 모든 권한을 주는 것이 아닙니다. 모델이 판단과 제안을 담당하고, 검증된 C# 코드가 실제 업무를 수행하도록 역할을 나누는 데 있습니다.
개발 환경 준비하기
이 예제는 .NET 10의 파일 기반 앱을 사용합니다. 따라서 .NET 런타임이 아닌 .NET SDK를 설치해야 합니다.
노트
현재 사용하는 컴퓨터가 Mac이거나 Linux PC라면 이 노트를 건너뛰고 다음 단계로 넘어가도 됩니다. Windows PC를 사용하고 있다면 잠시 읽어 주세요.
Windows에는 이미 .NET이 설치되어 있으니 별도로 준비할 것이 없다고 생각하기 쉽습니다. 대부분의 Windows PC에 기본 설치된 것은 .NET Framework 4.8입니다. 이름의 숫자만 놓고 보면 이 글에서 사용하는 .NET 10보다 무려 여섯 버전이나 낮은 장기 지원 제품입니다. 이 글의 실습을 진행하려면 기존 .NET Framework와 별도로 .NET 10 이상의 SDK를 설치해야 합니다.
최신 .NET 10 SDK는 dot.net에서 Windows, macOS, Linux용으로 내려받을 수 있습니다. 다운로드 페이지에서 운영체제와 CPU 아키텍처에 맞는 최신 SDK를 선택하면 됩니다. .NET 10은 장기 지원 버전입니다. .NET 공식 다운로드 페이지는 .NET 10을 장기 지원 버전으로 안내하고 최신 SDK 설치 파일을 제공합니다.
설치 후 다음 명령으로 SDK가 정상적으로 인식되는지 확인합니다.
dotnet --info
dotnet --list-sdks
그 밖에 다음 항목이 필요합니다.
- Azure CLI 2.80 이상
- 모델이 하나 이상 배포된 Microsoft Foundry 프로젝트
- 프로젝트 범위의 Foundry Project Manager 역할
- Foundry 프로젝트의 데이터 플레인 엔드포인트
Azure CLI에 로그인한 후에는 Foundry 데이터 플레인 토큰을 실제로 발급받을 수 있는지 확인합니다.
az login
az account get-access-token --scope https://ai.azure.com/.default
az account show는 로컬에 저장된 계정 정보를 읽기 때문에 인증 토큰이 만료된 상태에서도 성공할 수 있습니다. 실제 배포 가능 여부를 확인하려면 get-access-token 명령을 실행하는 편이 정확합니다.
예제의 파일 구성
예제는 세 파일로 구성됩니다.
| 파일 | 역할 |
|---|---|
agent.cs | Foundry 모델을 호출하고 /responses API를 제공하는 에이전트 서버 |
deploy.cs | 게시, 버전 생성, 활성화 대기, 트래픽 연결과 호출 검증을 수행하는 배포 스크립트 |
.env.example | 에이전트를 로컬에서 실행할 때 사용하는 환경 변수 템플릿 |
agent.cs와 deploy.cs는 실행되는 위치가 다릅니다.
deploy.cs는 개발자 PC에서 실행됩니다.agent.cs는 배포 후 Foundry의 컨테이너에서 실행됩니다.- 개발 중에는
agent.cs를 로컬에서도 실행할 수 있습니다.
따라서 배포 스크립트가 사용하는 환경 변수와 에이전트가 사용하는 환경 변수를 구분해야 합니다.
C# 프로젝트 없이 AI 에이전트 만들기
.NET 10 파일 기반 앱에서는 C# 파일 상단에 SDK, NuGet 패키지와 빌드 속성을 직접 선언할 수 있습니다. 예전에는 별도의 XML 문법을 쓰는 프로젝트를 만들어야 했던 것을 이렇게 간소화할 수 있습니다.
#!/usr/bin/env dotnet
#:sdk Microsoft.NET.Sdk.Web
#:package Microsoft.Agents.AI.Foundry.Hosting@1.15.0-preview.260722.1
#:package Azure.AI.Projects@2.1.0-beta.4
#:package Azure.AI.AgentServer.Responses@1.0.0-beta.8
#:package Azure.Identity@*
#:package DotNetEnv@*
#:property PublishAot=false
여기서 하나 더 눈여겨 보실 것이 있습니다. 제일 위의 Shebang Line을 통해 현재 사용자가 쓰는 셸에 dotnet 명령어가 있고, 이 C# 소스 파일에 실행 권한을 부여했다면 dotnet 명령어 없이도 이 스크립트를 셸 스크립트처럼 바로 실행해볼 수 있습니다. Shebang Line도 .NET 10에 포함된 C# 14에서는 문법 오류가 아닌 투과 문법으로 인정되어 자연스럽게 리눅스, 유닉스 시스템 환경에 통합됩니다.
웹 SDK가 필요한 이유
기본적으로 파일 기반 앱은 콘솔 애플리케이션 형태로 빌드됩니다. 하지만 Hosted Agent는 HTTP 요청을 수신하는 서버이므로 ASP.NET Core 호스팅 기능이 필요합니다.
이를 위해 다음 지시문을 사용합니다.
#:sdk Microsoft.NET.Sdk.Web
이 선언이 빠지면 에이전트가 컨테이너의 HTTP 포트에 정상적으로 바인딩되지 않을 수 있습니다.
NativeAOT를 끄는 이유
.NET 10의 파일 기반 앱은 게시와 NativeAOT를 지원합니다. Microsoft Learn은 .NET 10 SDK에서 파일 기반 앱의 게시 기능과 NativeAOT 지원이 강화됐다고 설명합니다.
하지만 이 예제에서 Foundry가 사용하는 진입점은 다음과 같은 형태입니다.
dotnet <어셈블리 이름>.dll
NativeAOT로 게시하면 DLL 대신 닷넷에 종속성이 없는 완전한 네이티브 실행 파일이 만들어지게 되며 dotnet CLI는 이렇게 만들어진 네이티브 실행 파일을 실행해 줄 수 없습니다.
위의 코드에서 #property PublishAot=false로 지정한 부분은 빌드 과정에서 다음과 같은 인자를 지정한 것과 동일한 효과를 내며, NativeAOT를 끄게 됩니다.
-p:PublishAot=false
이를 통해 관리형 DLL과 runtimeconfig.json 파일이 생성되도록 보장합니다.
Foundry 모델을 Agent Framework에 연결하기
먼저 .env 파일이나 프로세스 환경 변수에서 Foundry 프로젝트 엔드포인트와 모델 배포 이름을 읽습니다.
using Azure.AI.Projects;
using Azure.Identity;
using DotNetEnv;
using Microsoft.Agents.AI.Foundry.Hosting;
Env.NoClobber().TraversePath().Load();
var projectEndpoint = new Uri(
Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT")
?? throw new InvalidOperationException(
"FOUNDRY_PROJECT_ENDPOINT 환경 변수가 설정되지 않았습니다."));
var deployment = Environment.GetEnvironmentVariable(
"AZURE_AI_MODEL_DEPLOYMENT_NAME")
?? throw new InvalidOperationException(
"AZURE_AI_MODEL_DEPLOYMENT_NAME 환경 변수가 설정되지 않았습니다.");
그다음 AIProjectClient를 만들고 Foundry에 배포된 모델을 Agent Framework 에이전트로 변환합니다.
var agent = new AIProjectClient(
projectEndpoint,
new DefaultAzureCredential())
.AsAIAgent(
model: deployment,
instructions: "사용자의 질문에 간결하고 정확하게 답변하세요.",
name: "hello-world",
description: "Agent Framework로 만든 기본 에이전트");
AsAIAgent()를 사용하면 Agent Framework가 모델 호출, 응답 처리와 대화 이력 구성을 담당합니다. 개발자는 시스템 지침, 도구 연결과 업무 흐름 구현에 집중할 수 있습니다.
/responses API 제공하기
생성한 에이전트를 AgentHost에 등록합니다.
var builder = AgentHost.CreateBuilder(args);
builder.Services.AddFoundryResponses(agent);
builder.RegisterProtocol(
"responses",
endpoints => endpoints.MapFoundryResponses());
var app = builder.Build();
app.Run();
이 구성으로 다음 기능이 준비됩니다.
- OpenAI 호환
/responsesAPI PORT환경 변수를 이용한 HTTP 포트 바인딩GET /readiness준비 상태 확인 API- 스트리밍 응답 처리
- OpenTelemetry 기반 추적과 메트릭
/responses는 챗봇, 사내 업무 도우미, 문서 질의 시스템처럼 대화형 애플리케이션에 적합합니다.
대화가 아닌 정형화된 업무 요청이나 웹훅을 처리해야 한다면 /invocations 프로토콜을 고려할 수 있습니다. /responses는 OpenAI 호환 형식을 사용하지만, /invocations는 애플리케이션이 필요한 JSON 형식을 직접 정의할 수 있습니다. Microsoft Learn은 /responses를 OpenAI 호환 대화형 규약으로, /invocations를 개발자가 요청 및 응답 구조를 직접 정의하는 규약으로 구분합니다.
로컬에서 실행하기
먼저 .env.example 파일을 .env로 복사합니다.
cp .env.example .env
다음 값을 실제 환경에 맞게 입력합니다.
FOUNDRY_PROJECT_ENDPOINT=https://<계정>.services.ai.azure.com/api/projects/<프로젝트>
AZURE_AI_MODEL_DEPLOYMENT_NAME=<모델-배포-이름>
AZURE_AI_MODEL_DEPLOYMENT_NAME에는 모델 제품명이 아니라 Foundry 프로젝트에서 생성한 실제 배포 이름을 입력해야 합니다.
에이전트를 실행합니다.
dotnet run agent.cs
기본 포트는 8088입니다. 필요하면 PORT 환경 변수로 변경할 수 있습니다.
준비 상태는 다음과 같이 확인합니다.
curl http://localhost:8088/readiness
에이전트에는 다음과 같이 질문할 수 있습니다.
curl -sS -X POST http://localhost:8088/responses \
-H "Content-Type: application/json" \
-d '{
"input": "Microsoft Foundry Hosted Agent의 특징을 설명해 주세요.",
"stream": false
}'
첫 번째 응답의 id를 previous_response_id로 전달하면 대화 맥락을 이어갈 수 있습니다.
curl -sS -X POST http://localhost:8088/responses \
-H "Content-Type: application/json" \
-d '{
"input": "방금 설명한 내용을 세 문장으로 요약해 주세요.",
"previous_response_id": "<이전-응답-ID>",
"stream": false
}'
로컬에서는 대화 상태가 프로세스 안에 저장되므로 애플리케이션을 다시 시작하면 사라집니다. Foundry에 배포된 에이전트는 플랫폼에서 세션 상태를 관리합니다.
Microsoft Foundry에 배포하기
배포 스크립트는 다음 환경 변수를 사용합니다.
$env:FOUNDRY_PROJECT_ENDPOINT = `
'https://<계정>.services.ai.azure.com/api/projects/<프로젝트>'
$env:FOUNDRY_MODEL_NAME = '<모델-배포-이름>'
FOUNDRY_MODEL_NAME에도 Foundry 프로젝트에 생성된 실제 모델 배포 이름을 입력해야 합니다.
다음 명령으로 배포합니다. 에이전트 이름을 생략해도 배포가 되며, 이 때는 소스 파일 이름을 바탕으로 자동 생성됩니다.
dotnet run deploy.cs -- agent.cs
여기서 중요한 점은 로컬 PC에서 컨테이너 이미지를 만들지 않는다는 것입니다. deploy.cs가 에이전트를 Linux용으로 게시한 뒤, Foundry SDK가 게시 폴더를 압축해 업로드합니다.
실제 컨테이너 실행 환경은 Microsoft Foundry가 준비하므로 Dockerfile, Docker Desktop과 로컬 Docker 데몬이 필요하지 않습니다. 컨테이너를 사용하지 않는 것이 아니라, 컨테이너를 직접 빌드하고 운영하는 부담을 Foundry에 맡기는 방식입니다.
배포 명령을 실행할 때 기본 이름 대신 원하는 에이전트 이름을 직접 지정할 수도 있습니다. 이름은 소문자 영문자 또는 숫자로 시작하고 끝나야 하며, 중간에 하이픈을 사용할 수 있습니다.
dotnet run deploy.cs -- agent.cs my-agent
배포 스크립트가 하는 일
deploy.cs는 단순히 파일을 업로드하는 데 그치지 않고 다음 작업을 차례로 수행합니다.
1. Linux용으로 게시
Foundry의 실행 환경에 맞춰 linux-x64 대상으로 게시합니다.
dotnet publish agent.cs \
-c Release \
-r linux-x64 \
--self-contained false \
-p:PublishAot=false \
-p:PublishTrimmed=false \
-p:PublishSingleFile=false
게시 결과는 임시 디렉터리에 생성됩니다. 배포에 성공하면 디렉터리를 삭제하고, 실패하면 문제를 분석할 수 있도록 그대로 남깁니다.
2. 실제 진입점 확인
파일 기반 앱 코드를 빌드하면 어셈블리 이름은 파일 이름에서 파생되지만, 이름을 정규화하는 과정이 개입할 수 있습니다.
따라서 배포 스크립트는 DLL 이름을 추측하지 않고 게시 결과의 *.runtimeconfig.json 파일을 찾아 실제 어셈블리 이름을 확인합니다.
이를 통해 잘못된 진입점 때문에 첫 번째 호출에서 424 session_not_ready 오류가 발생하는 상황을 줄일 수 있습니다.
3. 인증 상태 사전 점검
Foundry API를 호출하기 전에 https://ai.azure.com/.default 범위의 토큰을 요청합니다. 인증이나 권한 문제가 있다면 파일을 모두 게시하고 업로드한 뒤가 아니라 배포 초기에 오류를 확인할 수 있습니다.
로컬 배포에서는 기본적으로 AzureCliCredential을 사용합니다. 개발자 PC에 남아 있는 서비스 주체 환경 변수 때문에 DefaultAzureCredential이 의도하지 않은 계정으로 인증을 시도하는 문제를 피하기 위해서입니다.
4. 에이전트 버전 생성
게시 결과가 있는 폴더를 Foundry SDK에 전달해 새 에이전트 버전을 생성합니다. .NET SDK는 폴더를 직접 압축한 뒤 업로드하므로 별도 ZIP 생성 코드가 필요하지 않습니다. Microsoft Learn에 따르면 .NET SDK를 이용한 소스 배포에서는 게시 폴더의 경로를 전달하면 SDK가 압축과 업로드를 처리합니다.
현재 .NET의 소스 코드 배포 API는 시험 공개 단계의 패키지에서 제공됩니다. 따라서 운영 환경에서는 패키지 버전을 고정하고 업그레이드 전에 호환성 테스트를 수행하는 것이 좋습니다. Microsoft Learn은 .NET용 소스 코드 배포 API가 아직 정식 안정 버전에 포함되지 않았다고 안내합니다.
5. 활성화와 트래픽 연결
에이전트 버전이 활성 상태가 될 때까지 주기적으로 확인한 뒤 새 버전이 모든 요청을 처리하도록 연결합니다.
6. 실제 호출 검증
컨테이너는 첫 요청이 들어왔을 때 세션 단위로 시작될 수 있습니다. 따라서 버전 생성과 활성화가 성공했더라도 진입점이나 준비 상태 문제가 첫 요청에서 발견될 수 있습니다.
배포 스크립트는 마지막에 실제 요청을 전송해 다음 항목을 함께 확인합니다.
- 컨테이너가 정상적으로 시작되는가
- DLL 진입점이 올바른가
- HTTP 포트가 정상적으로 열리는가
- 준비 상태 확인이 성공하는가
- 모델이 실제 응답을 반환하는가
기업에서 활용할 수 있는 시나리오
Hosted Agent는 단순 질의응답보다 모델의 판단을 실제 업무 과정과 연결할 때 장점이 큽니다.
개발자와 IT 운영 지원
- 장애 로그와 모니터링 데이터 요약
- 배포 실패 원인 분석
- 운영 문서와 아키텍처 문서 검색
- 장애 티켓 초안 생성
- Azure 리소스 상태 조회
고객 상담과 CRM 업무
- 상담 내용 요약과 분류
- 담당 부서 및 우선순위 추천
- CRM 활동 기록 초안 작성
- 후속 안내문 작성
- 긴급 고객 이슈 식별
영업과 제안서 작성
- 제안 요청서에서 요구 사항 추출
- 제품 및 보안 문서 검색
- 고객별 제안서 초안 작성
- 기술 검토 항목 정리
- 계약서 변경 사항 비교
문서 중심의 심사 업무
- 보험 청구 서류의 누락 항목 확인
- 품질 보고서와 작업 기록 분석
- 내부 정책과 새 규정 비교
- 공급망 관련 문서와 재고 현황 요약
이러한 시나리오에서 모델은 자연어 이해, 요약, 분류와 초안 작성을 맡습니다. CRM 수정, 티켓 상태 변경, 주문 처리처럼 외부 시스템을 바꾸는 작업은 C# 코드가 입력과 권한을 검증한 뒤 수행해야 합니다.
이후 확장 방향
현재 예제는 하나의 모델과 /responses API만 사용하는 가장 작은 형태입니다. 실제 서비스에서는 다음과 같이 확장할 수 있습니다.
- 사내 문서 검색과 검색 증강 생성 연결
- CRM, ERP, 티켓 시스템과 데이터베이스 연동
- 업무 실행 전 사람의 승인 단계 추가
- 대량 문서 처리와 장기 실행 작업 지원
- 업무 영역별 전문 에이전트를 둔 멀티 에이전트 구성
Microsoft Agent Framework를 사용한다면 Foundry Toolbox를 통해 도구와 지식 소스를 연결할 수 있습니다. .NET 애플리케이션에서는 AddFoundryToolboxes를 사용해 Foundry의 도구 체계와 통합할 수 있습니다. Microsoft Learn은 Agent Framework 기반의 .NET 에이전트에서 Foundry Toolbox를 연결할 때 AddFoundryToolboxes를 사용하도록 안내합니다.
운영 환경에서 고려할 사항
Foundry는 Hosted Agent를 배포할 때 에이전트별 Microsoft Entra ID와 전용 엔드포인트를 만듭니다. Microsoft Learn에 따르면 각 Hosted Agent에는 전용 Microsoft Entra ID와 전용 호출 엔드포인트가 자동으로 생성됩니다.
이 구조를 활용해 다음 원칙을 적용해야 합니다.
- 에이전트가 필요한 시스템에만 최소 권한을 부여합니다.
- 개발, 테스트와 운영 환경의 에이전트 ID를 분리합니다.
- 모델의 출력만으로 외부 시스템을 변경하지 않습니다.
- 쓰기 작업에는 입력 검증, 정책 검사와 승인 절차를 둡니다.
- 사용자 요청, 모델 응답, 도구 호출과 오류를 추적합니다.
- 지연 시간, 비용, 응답 품질과 실패율을 지속적으로 평가합니다.
- 중요한 업무 데이터는 대화 세션에만 저장하지 않습니다.
마무리
.NET 10 파일 기반 앱을 사용하면 .csproj와 Dockerfile 없이도 C#으로 Microsoft Foundry Hosted Agent를 만들 수 있습니다.
agent.cs에서는 Foundry 모델을 Agent Framework에 연결하고 /responses API를 제공합니다. deploy.cs에서는 Linux용 게시, 진입점 확인, 인증 검증, 버전 생성, 활성화와 실제 호출 테스트를 자동화합니다.
작은 파일 기반 예제로 시작하더라도 이후 사내 문서 검색, 업무 시스템 연동, 승인 절차, 비동기 작업과 멀티 에이전트 구조를 단계적으로 추가할 수 있습니다.
가장 중요한 원칙은 모델과 코드의 역할을 명확히 나누는 것입니다. 모델은 사용자의 의도를 해석하고 판단과 제안을 담당합니다. C# 코드는 권한 검사, 데이터 검증, 외부 시스템 연동과 감사 기록처럼 신뢰가 필요한 업무를 담당합니다.
Microsoft Foundry Hosted Agent는 이러한 역할 분담을 유지하면서 기존 .NET 기술 자산을 기업용 AI 에이전트로 확장할 수 있는 실용적인 출발점입니다.