代理框架支援 OpenAI 相容的協議,無論是將代理託管在符合標準 API 的環境中,還是連接到任何相容 OpenAI 的網路端點。
什麼是 OpenAI 協議?
支援兩種 OpenAI 協定:
- 聊天完成 API — 用於聊天互動的標準無狀態請求/回應格式
- 回應 API — 支援對話、串流及長期代理程序的進階格式
根據 OpenAI 的文件,回應 API 現已成為預設且推薦的做法。 它提供更全面且功能豐富的介面,用於建置 AI 應用程式,內建對話管理、串流功能,並支援長期執行的流程。
以下情況下使用 回應 API :
- 建立新應用程式(建議預設)
- 你需要伺服器端的對話管理。 不過這並非必須:你仍然可以在無狀態模式下使用 Responses API。
- 你需要持續的對話紀錄
- 你正在建立長時間運行的代理程序
- 你需要具備詳細事件類型的進階串流功能
- 你想要追蹤和管理個別回應(例如,透過 ID 檢索特定回應、檢查狀態,或取消正在進行的回應)
以下情況下使用 聊天完成 API :
- 遷移依賴對話完成格式的現有應用程式
- 你需要簡單、無狀態的請求/回應互動
- 狀態管理完全由您的客戶負責
- 你正在融合只支援聊天完成功能的現有工具
- 你需要與舊系統的最大相容性
以 OpenAI 端點作為主機代理(.NET)
該 Microsoft.Agents.AI.Hosting.OpenAI 函式庫讓你能透過相容 OpenAI 的 HTTP 端點暴露 AI 代理,並支援聊天完成與回應 API。 這讓你能將代理人整合到任何相容 OpenAI 的客戶端或工具中。
NuGet 套件:
Chat Completions API(對話完成 API)
聊天完成 API 提供一個簡單且無狀態的介面,用於使用標準 OpenAI 聊天格式與代理互動。
在 ASP.NET Core 中建立 ChatCompletions 整合的代理
這裡有一個完整的範例,透過聊天完成 API 揭露代理:
先決條件
1. 建立 ASP.NET 核心網頁API專案
建立一個新的 ASP.NET 核心網頁 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 connection
該應用程式需要 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 聊天完成規範中定義的 Server-Sent 事件(SSE)區塊組成。
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。
以下是使用 Responses 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.created、 response.output_item.added、 response.output_item.done、 response.completed及其他。
創造對話與回應
你可以直接發送回應請求,或者先用對話 API 建立對話,然後將後續請求連結到該對話。
首先,建立一個新的對話:
POST http://localhost:5209/v1/conversations
Content-Type: application/json
{
"items": [
{
"type": "message",
"role": "user",
"content": "Hello!"
}
]
}
回應中包含對話識別碼:
{
"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
此回應包含輸入與輸出訊息:
{
"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-Compatible 端點(Python)
Python 與OpenAIChatClientOpenAIResponsesClient兩者皆支援參數base_url,讓你能連接任何相容 OpenAI 的端點——包括自架代理、本地推論伺服器(Ollama、LM Studio、vLLM)或第三方 OpenAI 相容 API。
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於支援 Responses 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 | 註釋 |
|---|---|---|
| Ollama | http://localhost:11434/v1/ |
本地推論,不需要 API 金鑰 |
| LM 工作室 | http://localhost:1234/v1/ |
用圖形介面進行局部推論 |
| vLLM | http://localhost:8000/v1/ |
高吞吐量服務 |
| Azure AI Foundry | 你的部署端點 | 使用 Azure 憑證 |
| 託管代理框架的代理 | 您的代理端點 | .NET 代理程式通過 MapOpenAIChatCompletions 公開 |
備註
你也可以設定 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"