Поделиться через


Конечные точки, совместимые с OpenAI

Agent Framework поддерживает протоколы, совместимые с OpenAI, как для размещения агентов через стандартные API, так и для подключения к любой конечной точке, совместимой с OpenAI.

Что такое протоколы OpenAI?

Поддерживаются два протокола OpenAI:

  • API завершения чата — стандартный формат запроса и ответа без отслеживания состояния для взаимодействия чата
  • API ответов — расширенный формат, поддерживающий беседы, потоковое вещание и долговременные процессы агентов

API ответов теперь является стандартным и рекомендуемым подходом в соответствии с документацией OpenAI. Он предоставляет более комплексный и функциональный интерфейс для создания приложений ИИ со встроенным управлением беседами, возможностями потоковой передачи и поддержкой длительных процессов.

Используйте API ответов , когда:

  • Создание новых приложений (рекомендуется по умолчанию)
  • Вам потребуется управление беседами на стороне сервера. Однако это не обязательно: вы можете использовать API для ответов в режиме без сохранения состояния.
  • Вы хотите постоянную историю бесед
  • Вы создаете долговременные процессы агента
  • Вам нужны расширенные возможности потоковой передачи с подробными типами событий
  • Вы хотите отслеживать отдельные ответы и управлять ими (например, получать определенный ответ по идентификатору, проверять его состояние или отменять выполняемый ответ).

Используйте API завершения чата , когда:

  • Перенос существующих приложений, использующих формат завершения чата
  • Вам нужны простые, без отслеживания состояния взаимодействия запросов и ответа
  • Управление состоянием полностью осуществляется вашим клиентом
  • Вы интегрируете с существующими инструментами, поддерживающими только завершение чата
  • Вам нужна максимальная совместимость с устаревшими системами

Агенты хостинга в качестве конечных точек OpenAI (.NET)

Библиотека Microsoft.Agents.AI.Hosting.OpenAI позволяет предоставлять агентов ИИ через интерфейсы HTTP, совместимые с OpenAI, поддерживая API завершения чат-диалогов и ответов. Это позволяет интегрировать агентов с любым клиентом или инструментом, совместимым с OpenAI.

Пакет NuGet:

API завершения чата

API завершения чата предоставляет простой интерфейс без отслеживания состояния для взаимодействия с агентами с помощью стандартного формата чата OpenAI.

Настройка агента в ASP.NET Core с интеграцией ChatCompletions

Вот полный пример демонстрации агента через API завершения чата:

Предпосылки

1. Создание проекта веб-API ASP.NET Core

Создайте проект веб-API ASP.NET Core или используйте существующий.

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();

Тестирование конечной точки завершения чата

После запуска приложения можно протестировать агент с помощью пакета SDK OpenAI или 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"
}

Ответ содержит идентификатор сообщения, содержимое и статистику использования.

Завершение чата также поддерживает потоковую передачу, где выходные данные возвращаются в блоках, как только содержимое доступно. Эта возможность позволяет постепенно отображать выходные данные. Вы можете включить потоковую передачу, указав "stream": true. Формат выходных данных состоит из блоков Server-Sent Events (SSE), как определено в спецификации завершений чатов OpenAI.

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.created, , response.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": "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, позволяя подключаться к любой конечной точке, совместимой с OpenAI, включая самостоятельно размещенные агенты, локальные серверы вывода (Ollama, LM Studio, vLLM) или сторонние интерфейсы 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

Подход base_url работает с любым сервером, предоставляющим формат завершения чата OpenAI:

Сервер Базовый URL-адрес Примечания.
Ollama http://localhost:11434/v1/ Локальная инференция, ключ API не требуется
LM Studio http://localhost:1234/v1/ Локальный инференс с графическим интерфейсом
vLLM http://localhost:8000/v1/ Обслуживание с высокой пропускной способностью
Azure AI Foundry Конечная точка развертывания Использование учетных данных Azure
Агенты платформы Hosted Agent Framework Конечная точка агента Агенты .NET, доступные через MapOpenAIChatCompletions

Замечание

Можно также задать OPENAI_BASE_URL переменную среды вместо передачи base_url напрямую. Клиент будет использовать его автоматически.

Использование клиентов Azure OpenAI

Варианты Azure OpenAI (AzureOpenAIChatClient, AzureOpenAIResponsesClient) подключаются к конечным точкам Azure OpenAI с помощью учетных данных Azure — 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"

См. также

Дальнейшие шаги