共用方式為


OpenAI-Compatible 端點

代理框架支援 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.createdresponse.output_item.addedresponse.output_item.doneresponse.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

聊天完成客戶端

使用 OpenAIChatClientbase_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())

回應客戶端

使用OpenAIResponsesClientbase_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 變體(AzureOpenAIChatClientAzureOpenAIResponsesClient)使用 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"

另請參閱

後續步驟