에이전트 프레임워크는 표준 API 뒤에 있는 에이전트를 호스팅 하고 OpenAI 호환 엔드포인트에 연결하는 두 가지 모두에 대해 OpenAI 호환 프로토콜 을 지원합니다.
OpenAI 프로토콜이란?
두 개의 OpenAI 프로토콜이 지원됩니다.
- Chat Completions API — 채팅 상호 작용을 위한 표준 상태 비저장 요청/응답 형식
- 응답 API - 대화, 스트리밍 및 장기 실행 에이전트 프로세스를 지원하는 고급 형식
이제 응답 API는 OpenAI의 설명서에 따라 기본적이고 권장되는 방법입니다 . 기본 제공 대화 관리, 스트리밍 기능 및 장기 실행 프로세스 지원을 사용하여 AI 애플리케이션을 빌드하기 위한 보다 포괄적이고 기능이 풍부한 인터페이스를 제공합니다.
다음과 같은 경우 응답 API 를 사용합니다.
- 새 애플리케이션 빌드(권장 기본값)
- 서버 쪽 대화 관리가 필요합니다. 그러나 이는 요구 사항이 아닙니다. 상태 비저장 모드에서 응답 API를 계속 사용할 수 있습니다.
- 영구 대화 기록을 원합니다.
- 장기 실행 에이전트 프로세스를 빌드하고 있습니다.
- 자세한 이벤트 유형이 있는 고급 스트리밍 기능이 필요합니다.
- 개별 응답을 추적하고 관리하려고 합니다(예: ID로 특정 응답을 검색하거나, 상태를 확인하거나, 실행 중인 응답을 취소).
다음과 같은 경우 채팅 완료 API 를 사용합니다.
- 채팅 완료 형식을 사용하는 기존 애플리케이션 마이그레이션
- 간단한 상태 비저장 요청/응답 상호 작용이 필요합니다.
- 상태 관리는 클라이언트에서 전적으로 처리됩니다.
- 채팅 완료만 지원하는 기존 도구와 통합하고 있습니다.
- 레거시 시스템과의 최대 호환성이 필요합니다.
OpenAI 엔드포인트로 에이전트 호스팅(.NET)
Microsoft.Agents.AI.Hosting.OpenAI 라이브러리를 사용하면 OpenAI 호환 HTTP 엔드포인트를 통해 AI 에이전트를 노출하여 채팅 완료 및 응답 API를 모두 지원할 수 있습니다. 이렇게 하면 OpenAI 호환 클라이언트 또는 도구와 에이전트를 통합할 수 있습니다.
NuGet 패키지:
채팅 완료 API
채팅 완료 API는 표준 OpenAI 채팅 형식을 사용하여 프로그램과 상호 작용하기 위한 간단한 무상태 인터페이스를 제공합니다.
ChatCompletions 통합을 사용하여 ASP.NET Core에서 에이전트 설정
다음은 채팅 완료 API를 통해 에이전트를 노출하는 전체 예제입니다.
필수 조건
1. ASP.NET Core Web API 프로젝트 만들기
새 ASP.NET Core Web API 프로젝트를 만들거나 기존 프로젝트를 사용합니다.
2. 필수 종속성 설치
다음 패키지를 설치합니다.
프로젝트 디렉터리에서 다음 명령을 실행하여 필요한 NuGet 패키지를 설치합니다.
# Hosting.A2A.AspNetCore for OpenAI ChatCompletions/Responses protocol(s) integration
dotnet add package Microsoft.Agents.AI.Hosting.OpenAI --prerelease
# Libraries to connect to Azure OpenAI
dotnet add package Azure.AI.OpenAI --prerelease
dotnet add package Azure.Identity
dotnet add package Microsoft.Extensions.AI
dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease
# Swagger to test app
dotnet add package Microsoft.AspNetCore.OpenApi
dotnet add package Swashbuckle.AspNetCore
3. Azure OpenAI 연결 구성
애플리케이션에는 Azure OpenAI 연결이 필요합니다. 또는 환경 변수를 사용하여 dotnet user-secrets 엔드포인트 및 배포 이름을 구성합니다.
일부 데이터를 비밀로 appsettings.json간주할 수 있으므로 단순히 편집할 수도 있지만 프로덕션에 배포된 앱에는 권장되지 않습니다.
dotnet user-secrets set "AZURE_OPENAI_ENDPOINT" "https://<your-openai-resource>.openai.azure.com/"
dotnet user-secrets set "AZURE_OPENAI_DEPLOYMENT_NAME" "gpt-4o-mini"
4. Program.cs 코드를 추가합니다.
Program.cs의 내용을 다음 코드로 바꿉니다.
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI.Hosting;
using Microsoft.Extensions.AI;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
builder.Services.AddSwaggerGen();
string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"]
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
string deploymentName = builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"]
?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set.");
// Register the chat client
IChatClient chatClient = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName)
.AsIChatClient();
builder.Services.AddSingleton(chatClient);
builder.AddOpenAIChatCompletions();
// Register an agent
var pirateAgent = builder.AddAIAgent("pirate", instructions: "You are a pirate. Speak like a pirate.");
var app = builder.Build();
app.MapOpenApi();
app.UseSwagger();
app.UseSwaggerUI();
// Expose the agent via OpenAI ChatCompletions protocol
app.MapOpenAIChatCompletions(pirateAgent);
app.Run();
채팅 완료 엔드포인트 테스트
애플리케이션이 실행되면 OpenAI SDK 또는 HTTP 요청을 사용하여 에이전트를 테스트할 수 있습니다.
HTTP 요청 사용
POST {{baseAddress}}/pirate/v1/chat/completions
Content-Type: application/json
{
"model": "pirate",
"stream": false,
"messages": [
{
"role": "user",
"content": "Hey mate!"
}
]
}
참고: {{baseAddress}}를 본인의 서버 엔드포인트로 교체하십시오.
샘플 응답은 다음과 같습니다.
{
"id": "chatcmpl-nxAZsM6SNI2BRPMbzgjFyvWWULTFr",
"object": "chat.completion",
"created": 1762280028,
"model": "gpt-5",
"choices": [
{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "Ahoy there, matey! How be ye farin' on this fine day?"
}
}
],
"usage": {
"completion_tokens": 18,
"prompt_tokens": 22,
"total_tokens": 40,
"completion_tokens_details": {
"accepted_prediction_tokens": 0,
"audio_tokens": 0,
"reasoning_tokens": 0,
"rejected_prediction_tokens": 0
},
"prompt_tokens_details": {
"audio_tokens": 0,
"cached_tokens": 0
}
},
"service_tier": "default"
}
응답에는 메시지 ID, 콘텐츠 및 사용 통계가 포함됩니다.
채팅 완료 기능은 콘텐츠가 사용 가능해지는 즉시 청크 단위로 출력되는 스트리밍도 지원합니다.
이 기능을 사용하면 출력을 점진적으로 표시할 수 있습니다. 를 지정하여 스트리밍을 사용하도록 설정할 수 있습니다 "stream": true.
출력 형식은 OpenAI 채팅 완료 사양에 정의된 대로 SSE(Server-Sent 이벤트) 청크로 구성됩니다.
POST {{baseAddress}}/pirate/v1/chat/completions
Content-Type: application/json
{
"model": "pirate",
"stream": true,
"messages": [
{
"role": "user",
"content": "Hey mate!"
}
]
}
그리고 결과 출력은 "ChatCompletions" 청크의 집합입니다.
data: {"id":"chatcmpl-xwKgBbFtSEQ3OtMf21ctMS2Q8lo93","choices":[],"object":"chat.completion.chunk","created":0,"model":"gpt-5"}
data: {"id":"chatcmpl-xwKgBbFtSEQ3OtMf21ctMS2Q8lo93","choices":[{"index":0,"finish_reason":"stop","delta":{"content":"","role":"assistant"}}],"object":"chat.completion.chunk","created":0,"model":"gpt-5"}
...
data: {"id":"chatcmpl-xwKgBbFtSEQ3OtMf21ctMS2Q8lo93","choices":[],"object":"chat.completion.chunk","created":0,"model":"gpt-5","usage":{"completion_tokens":34,"prompt_tokens":23,"total_tokens":57,"completion_tokens_details":{"accepted_prediction_tokens":0,"audio_tokens":0,"reasoning_tokens":0,"rejected_prediction_tokens":0},"prompt_tokens_details":{"audio_tokens":0,"cached_tokens":0}}}
스트리밍 응답은 유사한 정보를 포함하지만 Server-Sent 이벤트로 전달됩니다.
응답 API
응답 API는 대화 관리, 스트리밍 및 장기 실행 에이전트 프로세스에 대한 지원을 비롯한 고급 기능을 제공합니다.
ASP.NET Core에서 응답 API 통합을 사용하여 에이전트 설정
다음은 응답 API를 사용하는 전체 예제입니다.
필수 조건
채팅 완료 예제와 동일한 필수 구성 요소를 따릅니다(1-3단계).
4. Program.cs 코드를 추가합니다.
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI.Hosting;
using Microsoft.Extensions.AI;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
builder.Services.AddSwaggerGen();
string endpoint = builder.Configuration["AZURE_OPENAI_ENDPOINT"]
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
string deploymentName = builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"]
?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set.");
// Register the chat client
IChatClient chatClient = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName)
.AsIChatClient();
builder.Services.AddSingleton(chatClient);
builder.AddOpenAIResponses();
builder.AddOpenAIConversations();
// Register an agent
var pirateAgent = builder.AddAIAgent("pirate", instructions: "You are a pirate. Speak like a pirate.");
var app = builder.Build();
app.MapOpenApi();
app.UseSwagger();
app.UseSwaggerUI();
// Expose the agent via OpenAI Responses protocol
app.MapOpenAIResponses(pirateAgent);
app.MapOpenAIConversations();
app.Run();
응답 API 테스트
응답 API는 채팅 완료와 유사하지만 상태 저장이므로 매개 변수를 conversation 전달할 수 있습니다.
채팅 완료와 마찬가지로, stream 매개 변수를 지원하여 단일 JSON 응답 또는 이벤트 스트림의 출력 형식을 제어합니다.
응답 API는 , response.createdresponse.output_item.addedresponse.output_item.done, 등과 같은 response.completed자체 스트리밍 이벤트 형식을 정의합니다.
대화 및 응답 만들기
응답 요청을 직접 보내거나, 먼저 대화 API를 사용하여 대화를 만든 다음, 후속 요청을 해당 대화에 연결할 수 있습니다.
시작하려면 새 대화를 만듭니다.
POST http://localhost:5209/v1/conversations
Content-Type: application/json
{
"items": [
{
"type": "message",
"role": "user",
"content": "Hello!"
}
]
}
응답에는 대화 ID가 포함됩니다.
{
"id": "conv_E9Ma6nQpRzYxRHxRRqoOWWsDjZVyZfKxlHhfCf02Yxyy9N2y",
"object": "conversation",
"created_at": 1762881679,
"metadata": {}
}
다음으로 요청을 보내고 대화 매개 변수를 지정합니다.
(응답을 스트리밍 이벤트로 받으려면 요청에 설정합니다 "stream": true .)
POST http://localhost:5209/pirate/v1/responses
Content-Type: application/json
{
"stream": false,
"conversation": "conv_E9Ma6nQpRzYxRHxRRqoOWWsDjZVyZfKxlHhfCf02Yxyy9N2y",
"input": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "are you a feminist?"
}
]
}
]
}
에이전트는 응답을 반환하고 나중에 검색할 수 있도록 대화 항목을 스토리지에 저장합니다.
{
"id": "resp_FP01K4bnMsyQydQhUpovK6ysJJroZMs1pnYCUvEqCZqGCkac",
"conversation": "conv_E9Ma6nQpRzYxRHxRRqoOWWsDjZVyZfKxlHhfCf02Yxyy9N2y",
"object": "response",
"created_at": 1762881518,
"status": "completed",
"incomplete_details": null,
"output": [
{
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Arrr, matey! As a pirate, I be all about respect for the crew, no matter their gender! We sail these seas together, and every hand on deck be valuable. A true buccaneer knows that fairness and equality be what keeps the ship afloat. So, in me own way, I’d say I be supportin’ all hearty souls who seek what be right! What say ye?"
}
],
"type": "message",
"status": "completed",
"id": "msg_1FAQyZcWgsBdmgJgiXmDyavWimUs8irClHhfCf02Yxyy9N2y"
}
],
"usage": {
"input_tokens": 26,
"input_tokens_details": {
"cached_tokens": 0
},
"output_tokens": 85,
"output_tokens_details": {
"reasoning_tokens": 0
},
"total_tokens": 111
},
"tool_choice": null,
"temperature": 1,
"top_p": 1
}
응답에는 대화 및 메시지 식별자, 콘텐츠 및 사용 통계가 포함됩니다.
대화 항목을 검색하려면 다음 요청을 보냅니다.
GET http://localhost:5209/v1/conversations/conv_E9Ma6nQpRzYxRHxRRqoOWWsDjZVyZfKxlHhfCf02Yxyy9N2y/items?include=string
그러면 입력 및 출력 메시지가 모두 포함된 JSON 응답이 반환됩니다.
{
"object": "list",
"data": [
{
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "Arrr, matey! As a pirate, I be all about respect for the crew, no matter their gender! We sail these seas together, and every hand on deck be valuable. A true buccaneer knows that fairness and equality be what keeps the ship afloat. So, in me own way, I’d say I be supportin’ all hearty souls who seek what be right! What say ye?",
"annotations": [],
"logprobs": []
}
],
"type": "message",
"status": "completed",
"id": "msg_1FAQyZcWgsBdmgJgiXmDyavWimUs8irClHhfCf02Yxyy9N2y"
},
{
"role": "user",
"content": [
{
"type": "input_text",
"text": "are you a feminist?"
}
],
"type": "message",
"status": "completed",
"id": "msg_iLVtSEJL0Nd2b3ayr9sJWeV9VyEASMlilHhfCf02Yxyy9N2y"
}
],
"first_id": "msg_1FAQyZcWgsBdmgJgiXmDyavWimUs8irClHhfCf02Yxyy9N2y",
"last_id": "msg_lUpquo0Hisvo6cLdFXMKdYACqFRWcFDrlHhfCf02Yxyy9N2y",
"has_more": false
}
여러 에이전트 공개
두 프로토콜을 사용하여 동시에 여러 에이전트를 노출할 수 있습니다.
var mathAgent = builder.AddAIAgent("math", instructions: "You are a math expert.");
var scienceAgent = builder.AddAIAgent("science", instructions: "You are a science expert.");
// Add both protocols
builder.AddOpenAIChatCompletions();
builder.AddOpenAIResponses();
var app = builder.Build();
// Expose both agents via Chat Completions
app.MapOpenAIChatCompletions(mathAgent);
app.MapOpenAIChatCompletions(scienceAgent);
// Expose both agents via Responses
app.MapOpenAIResponses(mathAgent);
app.MapOpenAIResponses(scienceAgent);
에이전트는 다음 위치에서 사용할 수 있습니다.
- 채팅 완료:
/math/v1/chat/completions및/science/v1/chat/completions - 응답:
/math/v1/responses및/science/v1/responses
사용자 지정 엔드포인트
엔드포인트 경로를 사용자 지정할 수 있습니다.
// Custom path for Chat Completions
app.MapOpenAIChatCompletions(mathAgent, path: "/api/chat");
// Custom path for Responses
app.MapOpenAIResponses(scienceAgent, responsesPath: "/api/responses");
OpenAI 호환 엔드포인트에 연결하기 (Python)
Python OpenAIChatClient 과 OpenAIResponsesClient 둘 다 매개 변수를 지원 base_url 하므로 자체 호스팅 에이전트, 로컬 유추 서버(Ollama, LM Studio, vLLM) 또는 타사 OpenAI 호환 API를 포함하여 OpenAI 호환 엔드포인트에 연결할 수 있습니다.
pip install agent-framework --pre
채팅 완료 클라이언트
OpenAIChatClient 및 base_url를 사용하여 채팅 완료 기능과 호환되는 서버를 가리킵니다.
import asyncio
from agent_framework import tool
from agent_framework.openai import OpenAIChatClient
@tool(approval_mode="never_require")
def get_weather(location: str) -> str:
"""Get the weather for a location."""
return f"Weather in {location}: sunny, 22°C"
async def main():
# Point to any OpenAI-compatible endpoint
agent = OpenAIChatClient(
base_url="http://localhost:11434/v1/", # e.g. Ollama
api_key="not-needed", # placeholder for local servers
model_id="llama3.2",
).as_agent(
name="WeatherAgent",
instructions="You are a helpful weather assistant.",
tools=get_weather,
)
response = await agent.run("What's the weather in Seattle?")
print(response)
asyncio.run(main())
응답 클라이언트
OpenAIResponsesClient와 base_url을(를) 응답 API를 지원하는 엔드포인트에 사용하세요.
import asyncio
from agent_framework.openai import OpenAIResponsesClient
async def main():
agent = OpenAIResponsesClient(
base_url="https://your-hosted-agent.example.com/v1/",
api_key="your-api-key",
model_id="gpt-4o-mini",
).as_agent(
name="Assistant",
instructions="You are a helpful assistant.",
)
# Non-streaming
response = await agent.run("Hello!")
print(response)
# Streaming
async for chunk in agent.run("Tell me a joke", stream=True):
if chunk.text:
print(chunk.text, end="", flush=True)
asyncio.run(main())
일반 OpenAI-Compatible 서버
이 base_url 방법은 OpenAI 채팅 완료 형식을 노출하는 모든 서버에서 작동합니다.
| 서버 | 기본 URL | 비고 |
|---|---|---|
| 올라마 섬 | http://localhost:11434/v1/ |
로컬 유추, API 키가 필요하지 않음 |
| LM Studio | http://localhost:1234/v1/ |
GUI를 사용하여 로컬 유추 |
| vLLM | http://localhost:8000/v1/ |
처리량이 높은 서비스 |
| Azure AI 파운드리 | 배포 엔드포인트 | Azure 자격 증명 사용 |
| 호스트된 에이전트 프레임워크 에이전트 | 에이전트 엔드포인트 |
MapOpenAIChatCompletions을 통해 노출되는 .NET 에이전트 |
비고
직접 전달하는 OPENAI_BASE_URL 대신 환경 변수를 base_url 설정할 수도 있습니다. 클라이언트는 자동으로 사용합니다.
Azure OpenAI 클라이언트 사용
Azure OpenAI 변형(AzureOpenAIChatClient, AzureOpenAIResponsesClient)은 Azure 자격 증명을 사용하여 Azure OpenAI 엔드포인트에 연결하며, base_url가 필요하지 않습니다.
from agent_framework.azure import AzureOpenAIResponsesClient
agent = AzureOpenAIResponsesClient().as_agent(
name="Assistant",
instructions="You are a helpful assistant.",
)
환경 변수를 사용하여 구성:
export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"
export AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME="gpt-4o-mini"