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


Доступ к данным в функциях ИИ

При создании функций ИИ может потребоваться доступ к контекстным данным за пределами параметров, предоставляемых моделью ИИ. Библиотека Microsoft.Extensions.AI предоставляет несколько механизмов передачи данных делегатам функций.

Класс AIFunction

Тип AIFunction представляет функцию, которую можно описать в службе ИИ и вызвать. Вы можете создавать AIFunction объекты, вызывая одну из AIFunctionFactory.Create перегрузок. Но AIFunction также является базовым классом, и вы можете наследить его и реализовать собственный тип функции ИИ. DelegatingAIFunction предоставляет простой способ обернуть существующий AIFunction и добавить дополнительную функциональность, включая захват дополнительных данных для использования.

Передача данных

Вы можете связать данные с функцией во время ее создания с помощью закрытия или через AdditionalProperties. Если вы создаете собственную функцию, вы можете заполнить AdditionalProperties любым способом. Если вы используете AIFunctionFactory для создания функции, вы можете заполнить данные с помощью AIFunctionFactoryOptions.AdditionalProperties.

Вы также можете записать любые ссылки на данные в делегате, предоставленном для AIFunctionFactory. То есть, вы можете интегрировать все, к чему хотите ссылаться, как часть AIFunction.

Доступ к данным в делегатах функций

Вы можете вызвать ваш AIFunction напрямую или вызвать его косвенно с помощью FunctionInvokingChatClient. В следующих разделах описывается, как получить доступ к данным аргумента с помощью любого подхода.

Вызов функции вручную

Если вы вручную вызываете AIFunction, вызывая AIFunction.InvokeAsync(AIFunctionArguments, CancellationToken), передайте AIFunctionArguments. Тип AIFunctionArguments включает:

  • Словарь именованных аргументов.
  • Context: произвольное значение для передачи IDictionary<object, object> дополнительных внешних данных в функцию.
  • Services: IServiceProvider, который позволяет AIFunction извлекать произвольное состояние из контейнера для внедрения зависимостей (DI).

Если вы хотите получить доступ к AIFunctionArguments или IServiceProvider из делегата AIFunctionFactory.Create, создайте параметр, типизированный как IServiceProvider или AIFunctionArguments. Этот параметр будет привязан к релевантным данным, передаваемым в из .

В следующем коде показан пример:

Delegate getWeatherDelegate = (AIFunctionArguments args) =>
{
    // Access named parameters from the arguments dictionary.
    string? location = args.TryGetValue("location", out object? loc) ? loc.ToString() : "Unknown";
    string? units = args.TryGetValue("units", out object? u) ? u.ToString() : "celsius";

    return $"Weather in {location}: 35°{units}";
};

// Create the AIFunction.
AIFunction getWeather = AIFunctionFactory.Create(getWeatherDelegate);

// Call the function manually.
var result = await getWeather.InvokeAsync(new AIFunctionArguments
{
    { "location", "Seattle" },
    { "units", "F" }
});
Console.WriteLine($"Function result: {result}");

CancellationToken также имеет особую обработку: если делегат или лямбда-функция AIFunctionFactory.Create имеет параметр CancellationToken, он будет привязан к CancellationToken, который был передан в AIFunction.InvokeAsync().

Вызов через FunctionInvokingChatClient

FunctionInvokingChatClient публикует состояние текущего вызова FunctionInvokingChatClient.CurrentContext, включая не только аргументы, но и все входные ChatMessage объекты, ChatOptions, а также сведения о вызываемой функции (из общего количества вызовов функций). Вы можете добавить любые данные в ChatOptions.AdditionalProperties и извлечь их внутри вашего AIFunction из FunctionInvokingChatClient.CurrentContext.Options.AdditionalProperties.

В следующем коде показан пример:

FunctionInvokingChatClient client = new FunctionInvokingChatClient(
    new AzureOpenAIClient(new Uri(endpoint), new AzureKeyCredential(apiKey))
    .GetChatClient(model).AsIChatClient());

AIFunction getWeather = AIFunctionFactory.Create(() =>
    {
        // Access named parameters from the arguments dictionary.
        AdditionalPropertiesDictionary props =
            FunctionInvokingChatClient.CurrentContext.Options.AdditionalProperties;

        string location = props["location"].ToString();
        string units = props["units"].ToString();

        return $"Weather in {location}: 35°{units}";
    });

var chatOptions = new ChatOptions
{
    Tools = [getWeather],
    AdditionalProperties = new AdditionalPropertiesDictionary {
        ["location"] = "Seattle",
        ["units"] = "F"
    },
};

List<ChatMessage> chatHistory = [
    new(ChatRole.System, "You're a helpful weather assistant.")
];
chatHistory.Add(new ChatMessage(ChatRole.User, "What's the weather like?"));

ChatResponse response = await client.GetResponseAsync(chatHistory, chatOptions);
Console.WriteLine($"Response: {response.Text}");

Внедрение зависимостей

Если вы используете FunctionInvokingChatClient для автоматического вызова функций, то этот клиент настраивает объект AIFunctionArguments, который передается в AIFunction. Поскольку AIFunctionArguments включает IServiceProvider с FunctionInvokingChatClient, предоставленным как часть сущности, если вы создаете клиента с помощью стандартных средств DI, то IServiceProvider полностью передается в ваш AIFunction. На этом этапе вы можете запросить у него что угодно, связанное с DI.

Расширенные методы

Если требуется более точное управление привязкой параметров, можно использовать AIFunctionFactoryOptions.ConfigureParameterBinding, что позволяет контролировать заполнение каждого параметра. Например, пакет SDK для MCP C# использует этот метод для автоматической привязки параметров из DI.

При использовании перегрузки AIFunctionFactory.Create(MethodInfo, Func<AIFunctionArguments,Object>, AIFunctionFactoryOptions) можно также запустить собственную произвольную логику при создании целевого объекта, на котором метод экземпляра будет вызываться каждый раз. Вы можете сделать всё, что хотите, чтобы настроить этот экземпляр.