AI-модели в C# и .NET через AI Gateway — официальный NuGet-пакет OpenAI
AI Gateway совместим с официальным .NET-SDK OpenAI (v2): задаются только Endpoint и ключ, весь остальной код — как в документации OpenAI. Один клиент даёт доступ ко всем моделям каталога — Claude, GPT, Gemini, DeepSeek — сменой имени модели у ChatClient.
Установка
dotnet add package OpenAIПервый запрос
using System.ClientModel;
using OpenAI;
using OpenAI.Chat;
var options = new OpenAIClientOptions
{
Endpoint = new Uri("https://ai-gatewey.ru/v1"),
};
var credential = new ApiKeyCredential("sk-aigate-ваш_ключ");
ChatClient client = new(
model: "deepseek/deepseek-chat",
credential: credential,
options: options);
ChatCompletion completion = client.CompleteChat("Привет!");
Console.WriteLine(completion.Content[0].Text);Environment.GetEnvironmentVariable("AIGATE_API_KEY")) или в user-secrets, а не в коде — так его не утащат из репозитория.Стриминг
Ответ частями через Server-Sent Events — метод CompleteChatStreamingAsync возвращает асинхронный поток обновлений, который перебирают через await foreach:
await foreach (StreamingChatCompletionUpdate update
in client.CompleteChatStreamingAsync("Расскажи о токенах"))
{
foreach (ChatMessageContentPart part in update.ContentUpdate)
{
Console.Write(part.Text);
}
}Function calling
Вызов инструментов работает прозрачно — выбирайте модель с поддержкой function calling (бейдж «инструменты» в каталоге). Инструмент описывается через ChatTool.CreateFunctionTool, а модель возвращает ToolCalls:
ChatClient toolClient = new(
model: "anthropic/claude-sonnet-5",
credential: credential,
options: options);
ChatTool weatherTool = ChatTool.CreateFunctionTool(
functionName: "get_weather",
functionDescription: "Погода в городе",
functionParameters: BinaryData.FromString("""
{
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
"""));
ChatCompletion completion = toolClient.CompleteChat(
new[] { new UserChatMessage("Какая погода в Москве?") },
new ChatCompletionOptions { Tools = { weatherTool } });
foreach (ChatToolCall call in completion.ToolCalls)
{
Console.WriteLine($"{call.FunctionName}: {call.FunctionArguments}");
}Обработка ошибок
401— неверный или отозванный ключ: проверьте значение и что ключ активен в кабинете.403— модель сверх тарифа при пустом балансе: пополните баланс или выберите модель тарифа.429— исчерпана квота или RPM-лимит ключа: дождитесь окна, поднимите лимит или тариф.5xx— сбой апстрима: шлюз сам ретраит и переключает провайдера, но свой retry с экспоненциальной паузой в проде не помешает.
using System.ClientModel;
try
{
ChatCompletion completion = client.CompleteChat("Привет!");
}
catch (ClientResultException ex)
{
// ex.Status == 429 → квота/RPM: подождать и повторить
Console.WriteLine($"{ex.Status}: {ex.Message}");
}Какую модель выбрать
| Модель | Ввод, ₽/1М | Вывод, ₽/1М | Контекст |
|---|---|---|---|
| DeepSeek: DeepSeek V3 | 31 | 125 | 128K |
| Anthropic: Claude Sonnet 5 | 314 | 1 568 | 1M |
| OpenAI: GPT-5.4 Mini | 118 | 705 | 400K |
Частые вопросы
Какую версию пакета OpenAI использовать?
Официальный NuGet-пакет OpenAI версии 2.x — в нём появились ChatClient и OpenAIClientOptions.Endpoint, через которые AI Gateway и подключается. На пакетах 1.x синтаксис другой.
Работает ли Semantic Kernel и Azure-обёртки?
Semantic Kernel умеет принимать кастомный endpoint и ключ, поэтому подключается к AI Gateway. Специализированный AzureOpenAIClient рассчитан на Azure и для AI Gateway не нужен — берите базовый ChatClient.
Можно ли переключать модели без нового клиента?
Модель задаётся при создании ChatClient, поэтому под каждую модель удобно держать свой экземпляр — все они используют один Endpoint и ключ.
.NET-приложение с AI — за пять минут
Получить ключ