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


Расширение ИИ Azure с помощью средств и выполнение локальной функции с помощью .NET

Приступая к работе с семантического ядра, создав простое консольное приложение чата .NET 8. Приложение будет выполняться локально и использовать модель OpenAI gpt-35-turbo , развернутую в учетной записи Azure OpenAI, однако с помощью средства для расширения возможностей модели она вызовет локальную функцию. Выполните следующие действия, чтобы подготовить Azure OpenAI и узнать, как использовать семантические ядра.

Приступая к работе с пакетом SDK для .NET Azure OpenAI, создав простое консольное приложение чата .NET 8. Приложение будет выполняться локально и использовать модель OpenAI gpt-35-turbo , развернутую в учетной записи Azure OpenAI, однако с помощью средства для расширения возможностей модели она вызовет локальную функцию. Выполните следующие действия, чтобы подготовить Azure OpenAI и узнать, как использовать пакет SDK для .NET Azure OpenAI.

Необходимые компоненты

Развертывание ресурсов Azure

Убедитесь, что вы следуйте предварительным требованиям, чтобы иметь доступ к Службе Azure OpenAI, а также интерфейс командной строки разработчика Azure, а затем следуйте приведенному ниже руководству, чтобы настроить начало работы с примером приложения.

  1. Клонирование репозитория: dotnet/ai-samples

  2. В терминале или командной строке перейдите в каталог кратких руководств.

  3. Это подготавливает ресурсы Azure OpenAI. Для создания службы Azure OpenAI и развертывания модели может потребоваться несколько минут.

    azd up
    

Примечание.

Если у вас уже есть доступная служба Azure OpenAI, можно пропустить развертывание и использовать это значение в Program.cs, предпочтительно из IConfiguration.

Устранение неполадок

В Windows после выполнения azd upмогут появиться следующие сообщения об ошибках:

postprovision.ps1 не имеет цифровой подписи. Сценарий не будет выполняться в системе

Скрипт postprovision.ps1 выполняется для задания секретов пользователей .NET, используемых в приложении. Чтобы избежать этой ошибки, выполните следующую команду PowerShell:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

Затем повторно запустите azd up команду.

Еще одна возможная ошибка:

Pwsh не распознается как внутренняя или внешняя команда, операблирование программы или пакетного файла. ПРЕДУПРЕЖДЕНИЕ: сбой перехватчика postprovision с кодом выхода: "1", путь: ".\infra\post-script\postprovision.ps1". : код выхода: 1 Выполнение будет продолжаться, так как Параметр ContinueOnError имеет значение true.

Скрипт postprovision.ps1 выполняется для задания секретов пользователей .NET, используемых в приложении. Чтобы избежать этой ошибки, вручную запустите скрипт с помощью следующей команды PowerShell:

.\infra\post-script\postprovision.ps1

Теперь приложения .NET AI настроены для пользовательских секретов и их можно протестировать.

Пример Приложения HikerAI Pro

  1. В терминале или командной строке перейдите semantic-kernel\04-HikerAIPro в каталог.
  1. В терминале или командной строке перейдите azure-openai-sdk\04-HikerAIPro в каталог.
  1. Теперь пора попробовать консольное приложение. Введите следующее, чтобы запустить приложение:

    dotnet run
    

    Если появится сообщение об ошибке, возможно, не завершено развертывание ресурсов Azure OpenAI. Подождите пару минут и повторите попытку.

Изучение кода

В нашем приложении используется Microsoft.SemanticKernel пакет, который доступен в NuGet, для отправки и получения запросов в службу Azure OpenAI, развернутую в Azure.

Все приложение содержится в файле Program.cs . Первые несколько строк кода загружают секреты и значения конфигурации, заданные для dotnet user-secrets вас во время подготовки приложения.

var config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
string endpoint = config["AZURE_OPENAI_ENDPOINT"];
string deployment = config["AZURE_OPENAI_GPT_NAME"];
string key = config["AZURE_OPENAI_KEY"];

Класс Kernel упрощает запросы и ответы с помощью AddAzureOpenAIChatCompletion службы.

// Create a Kernel containing the Azure OpenAI Chat Completion Service
IKernelBuilder b = Kernel.CreateBuilder();

Kernel kernel = b
    .AddAzureOpenAIChatCompletion(deployment, endpoint, key)
    .Build();

Функция используется CreateFromMethod для определения локальной функцииImportPluginFromFunctions, которая будет вызываться моделью.

// Add a new plugin with a local .NET function that should be available to the AI model
// For convenience and clarity of into the code, this standalone local method handles tool call responses. It will fake a call to a weather API and return the current weather for the specified location.
kernel.ImportPluginFromFunctions("WeatherPlugin",
[
    KernelFunctionFactory.CreateFromMethod(([Description("The city, e.g. Montreal, Sidney")] string location, string unit = null) =>
    {
        // Here you would call a weather API to get the weather for the location
        return "Periods of rain or drizzle, 15 C";
    }, "get_current_weather", "Get the current weather in a given location")
]);

kernel После создания клиента мы предоставляем больше контекста модели, добавив системный запрос. Это указывает модели, как она будет действовать во время беседы. Обратите внимание, как погода подчеркивается в системном запросе.

ChatHistory chatHistory = new("""
    You are a hiking enthusiast who helps people discover fun hikes in their area. You are upbeat and friendly.
    A good weather is important for a good hike. Only make recommendations if the weather is good or if people insist.
    You introduce yourself when first saying hello. When helping people out, you always ask them 
    for this information to inform the hiking recommendation you provide:

    1. Where they are located
    2. What hiking intensity they are looking for

    You will then provide three suggestions for nearby hikes that vary in length after you get that information. 
    You will also share an interesting fact about the local nature on the hikes when making a recommendation.
    """);

Затем вы можете добавить в модель сообщение пользователя с помощью AddUserMessage functon.

Чтобы модель создавала ответ на основе системного запроса и запроса пользователя, используйте функцию GetChatMessageContentAsync .

chatHistory.AddUserMessage("""
    Is the weather is good today for a hike?
    If yes, I live in the greater Montreal area and would like an easy hike. I don't mind driving a bit to get there.
    I don't want the hike to be over 10 miles round trip. I'd consider a point-to-point hike.
    I want the hike to be as isolated as possible. I don't want to see many people.
    I would like it to be as bug free as possible.
    """);

Console.WriteLine($"{chatHistory.Last().Role} >>> {chatHistory.Last().Content}");

chatHistory.Add(await service.GetChatMessageContentAsync(chatHistory, new OpenAIPromptExecutionSettings() { MaxTokens = 400 }));
Console.WriteLine($"{chatHistory.Last().Role} >>> {chatHistory.Last().Content}");

Настройте системный запрос и сообщение пользователя, чтобы узнать, как модель реагирует, чтобы помочь вам найти нужный поход.

Изучение кода

В нашем приложении используется клиентский Azure.AI.OpenAI пакет SDK, доступный в NuGet, для отправки и получения запросов в службу Azure OpenAI, развернутую в Azure.

Все приложение содержится в файле Program.cs . Первые несколько строк кода загружают секреты и значения конфигурации, заданные для dotnet user-secrets вас во время подготовки приложения.

// == Retrieve the local secrets saved during the Azure deployment ==========
var config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
string openAIEndpoint = config["AZURE_OPENAI_ENDPOINT"];
string openAIDeploymentName = config["AZURE_OPENAI_GPT_NAME"];
string openAiKey = config["AZURE_OPENAI_KEY"];

// == Creating the AIClient ==========
var endpoint = new Uri(openAIEndpoint);
var credentials = new AzureKeyCredential(openAiKey);

Класс OpenAIClient упрощает запросы и ответы. ChatCompletionOptions указывает параметры реагирования модели. Обратите внимание, как свойство Tools используется для добавления определения.

var openAIClient = new OpenAIClient(endpoint, credentials);

var completionOptions = new ChatCompletionsOptions
{
    MaxTokens = 400,
    Temperature = 1f,
    FrequencyPenalty = 0.0f,
    PresencePenalty = 0.0f,
    NucleusSamplingFactor = 0.95f, // Top P
    DeploymentName = openAIDeploymentName,
    Tools = { getWeather }
};

Класс ChatCompletionsFunctionToolDefinition используется для определения локальной функции, которая будет вызываться моделью.

var getWeather = new ChatCompletionsFunctionToolDefinition()
{
    Name = "get_current_weather",
    Description = "Get the current weather in a given location",
    Parameters = BinaryData.FromObjectAsJson(
    new
    {
        Type = "object",
        Properties = new
        {
            Location = new
            {
                Type = "string",
                Description = "The city, e.g. Montreal, Sidney",
            },
            Unit = new
            {
                Type = "string",
                Enum = new[] { "celsius", "fahrenheit" },
            }
        },
        Required = new[] { "location" },
    },
    new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }),
};

OpenAIClient После создания клиента мы предоставляем больше контекста модели, добавив системный запрос. Это указывает модели, как она будет действовать во время беседы. Обратите внимание, как погода подчеркивается в системном запросе.

var systemPrompt = 
"""
You are a hiking enthusiast who helps people discover fun hikes in their area. You are upbeat and friendly.
A good weather is important for a good hike. Only make recommendations if the weather is good or if people insist.
You introduce yourself when first saying hello. When helping people out, you always ask them 
for this information to inform the hiking recommendation you provide:

1. Where they are located
2. What hiking intensity they are looking for

You will then provide three suggestions for nearby hikes that vary in length after you get that information. 
You will also share an interesting fact about the local nature on the hikes when making a recommendation.
""";

completionOptions.Messages.Add(new ChatRequestSystemMessage(systemPrompt));

Затем можно добавить в модель сообщение пользователя с помощью ChatRequestUserMessage класса.

Для удобства и ясности в коде этот автономный локальный метод обрабатывает ответы вызова средства. Он будет поддельным вызовом к API погоды и возвращает текущую погоду для указанного расположения.

ChatRequestToolMessage GetToolCallResponseMessage(ChatCompletionsToolCall toolCall)
{
    var functionToolCall = toolCall as ChatCompletionsFunctionToolCall;
    if (functionToolCall?.Name == getWeather.Name)
    {
        string unvalidatedArguments = functionToolCall.Arguments;
        var functionResultData = (object)null;

        // == Here call a weather API to get the weather for specified the location ==========
        functionResultData = "Periods of rain or drizzle, 15 C";

        return new ChatRequestToolMessage(functionResultData.ToString(), toolCall.Id);
    }
    else
    {
        throw new NotImplementedException();
    }
}

Чтобы модель создавала ответ на основе системного запроса и запроса пользователя, используйте функцию GetChatCompletionsAsync .

string hikeRequest = """
Is the weather is good today for a hike?
If yes, I live in the greater Montreal area and would like an easy hike. I don't mind driving a bit to get there.
I don't want the hike to be over 10 miles round trip. I'd consider a point-to-point hike.
I want the hike to be as isolated as possible. I don't want to see many people.
I would like it to be as bug free as possible.
""";

Console.WriteLine($"\n\nUser >>> {hikeRequest}");
completionOptions.Messages.Add(new ChatRequestUserMessage(hikeRequest));

response = await openAIClient.GetChatCompletionsAsync(completionOptions);

Теперь необходимо проверить ответ. Если ответ включает в себя ToolCalls, метод объявляет его ранее и продолжает беседу. Важно отметить, что все сообщения ChatRequestAssistantMessage добавляются в журнал бесед. Это важно для поддержания контекста беседы.

ChatChoice responseChoice = response.Choices[0];
if (responseChoice.FinishReason == CompletionsFinishReason.ToolCalls)
{
    // == Include the FunctionCall message in the conversation history ==========
    completionOptions.Messages.Add(new ChatRequestAssistantMessage(responseChoice.Message));

    // == Add a new tool message for each tool call that is resolved ==========
    foreach (ChatCompletionsToolCall toolCall in responseChoice.Message.ToolCalls)
    {
        var ToolCallMsg = GetToolCallResponseMessage(toolCall);
        completionOptions.Messages.Add(ToolCallMsg);
    }

    // == Retrieve the answer from HikeAI Pro ==========
    response = await openAIClient.GetChatCompletionsAsync(completionOptions);
}

assistantResponse = response.Choices[0].Message;
Console.WriteLine($"\n\nAssistant >>> {assistantResponse.Content}");

Настройте системный запрос и сообщение пользователя, чтобы узнать, как модель реагирует, чтобы помочь вам найти нужный поход.

Очистка ресурсов

Если вам больше не нужен пример приложения или ресурсов, удалите соответствующее развертывание и все ресурсы.

azd down

Следующие шаги