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-v4-flash",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 updatein 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.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— неверный или отозванный ключ: проверьте значение и что ключ активен в кабинете.402— нужна оплата: пуст баланс, исчерпана месячная квота, модель не входит в тариф, либо сработал лимит самого ключа (список моделей, потолок расхода, срок действия). Пополните баланс, смените тариф либо проверьте настройки ключа.429— превышен лимит запросов в минуту: снизьте темп и повторите с экспоненциальной паузой.5xx— сбой апстрима: шлюз сам повторяет запрос, резервные провайдеры модели подставляет апстрим, но свой retry с экспоненциальной паузой в проде не помешает.
using System.ClientModel;try{ChatCompletion completion = client.CompleteChat("Привет!");}catch (ClientResultException ex){// ex.Status == 429 → превышен RPM: подождать и повторитьConsole.WriteLine($"{ex.Status}: {ex.Message}");}Какую модель выбрать
Частые вопросы
Какую версию пакета 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 и ключ.