Руководство по вызову функций AI Edge для Android

AI Edge Function Calling SDK (FC SDK) — это библиотека, которая позволяет разработчикам использовать вызов функций с LLM на устройстве. Вызов функций позволяет подключать модели к внешним инструментам и API, позволяя моделям вызывать определенные функции с необходимыми параметрами для выполнения реальных действий.

Вместо того чтобы просто генерировать текст, LLM с помощью FC SDK может генерировать структурированный вызов функции, которая выполняет действие, например поиск актуальной информации, установку будильников или бронирование.

Это руководство проведет вас через базовый быстрый старт для добавления API вывода LLM с FC SDK в приложение Android. Это руководство фокусируется на добавлении возможностей вызова функций в LLM на устройстве. Для получения дополнительной информации об использовании API вывода LLM см. руководство LLM Inference for Android .

Быстрый старт

Используйте следующие шаги для использования FC SDK в вашем приложении Android. Это краткое руководство использует LLM Inference API с Hammer 2.1 (1.5B) . LLM Inference API оптимизирован для высокопроизводительных устройств Android, таких как Pixel 8 и Samsung S23 или более поздних версий, и не поддерживает надежно эмуляторы устройств.

Добавить зависимости

FC SDK использует библиотеку com.google.ai.edge.localagents:localagents-fc а LLM Inference API использует библиотеку com.google.mediapipe:tasks-genai . Добавьте обе зависимости в файл build.gradle вашего приложения Android:

dependencies {
    implementation 'com.google.mediapipe:tasks-genai:0.10.23'
    implementation 'com.google.ai.edge.localagents:localagents-fc:0.1.0'
}

Для устройств с Android 12 (API 31) или выше добавьте зависимость библиотеки OpenCL. Для получения дополнительной информации см. документацию по тегу uses-native-library .

Добавьте следующие теги uses-native-library в файл AndroidManifest.xml :

<uses-native-library android:name="libOpenCL.so" android:required="false"/>
<uses-native-library android:name="libOpenCL-car.so" android:required="false"/>
<uses-native-library android:name="libOpenCL-pixel.so" android:required="false"/>

Загрузить модель

Загрузите Gemma-3 1B в 4-битном квантованном формате с Hugging Face . Для получения дополнительной информации о доступных моделях см. документацию по моделям .

Скопируйте содержимое папки gemma3-1b-it-int4.task на устройство Android.

$ adb shell rm -r /data/local/tmp/llm/ # Remove any previously loaded models
$ adb shell mkdir -p /data/local/tmp/llm/
$ adb push gemma3-1b-it-int4.task /data/local/tmp/llm/gemma3-1b-it-int4.task

Объявить определения функций

Определите функции, которые будут доступны модели. Для иллюстрации процесса этот быстрый старт включает две функции как статические методы, которые возвращают жестко закодированные ответы. Более практичная реализация определила бы функции, которые вызывают REST API или извлекают информацию из базы данных.

Ниже приведены определения функций getWeather и getTime :

class ToolsForLlm {
    public static String getWeather(String location) {
        return "Cloudy, 56°F";
    }

    public static String getTime(String timezone) {
        return "7:00 PM " + timezone;
    }

    private ToolsForLlm() {}
}

Используйте FunctionDeclaration для описания каждой функции, давая каждой имя и описание, а также указывая типы. Это информирует модель о том, что делают функции и когда следует вызывать функции.

var getWeather = FunctionDeclaration.newBuilder()
    .setName("getWeather")
    .setDescription("Returns the weather conditions at a location.")
    .setParameters(
        Schema.newBuilder()
            .setType(Type.OBJECT)
            .putProperties(
                "location",
                Schema.newBuilder()
                    .setType(Type.STRING)
                    .setDescription("The location for the weather report.")
                    .build())
            .build())
    .build();
var getTime = FunctionDeclaration.newBuilder()
    .setName("getTime")
    .setDescription("Returns the current time in the given timezone.")

    .setParameters(
        Schema.newBuilder()
            .setType(Type.OBJECT)
            .putProperties(
                "timezone",
                Schema.newBuilder()
                    .setType(Type.STRING)
                    .setDescription("The timezone to get the time from.")
                    .build())
            .build())
    .build();

Добавьте объявления функций к объекту Tool :

var tool = Tool.newBuilder()
    .addFunctionDeclarations(getWeather)
    .addFunctionDeclarations(getTime)
    .build();

Создайте бэкэнд вывода

Создайте бэкэнд вывода с помощью LLM Inference API и передайте ему объект форматирования для вашей модели. Форматирование FC SDK ( ModelFormatter ) действует как форматирование и парсер. Поскольку в этом кратком руководстве используется Gemma-3 1B, мы будем использовать GemmaFormatter :

var llmInferenceOptions = LlmInferenceOptions.builder()
    .setModelPath(modelFile.getAbsolutePath())
    .build();
var llmInference = LlmInference.createFromOptions(context, llmInferenceOptions);
var llmInferenceBackend = new llmInferenceBackend(llmInference, new GemmaFormatter());

Для получения дополнительной информации см. параметры конфигурации вывода LLM .

Создайте экземпляр модели

Используйте объект GenerativeModel для соединения бэкэнда вывода, системного приглашения и инструментов. У нас уже есть бэкэнд вывода и инструменты, поэтому нам нужно только создать системное приглашение:

var systemInstruction = Content.newBuilder()
      .setRole("system")
      .addParts(Part.newBuilder().setText("You are a helpful assistant."))
      .build();

Создайте экземпляр модели с помощью GenerativeModel :

var generativeModel = new GenerativeModel(
    llmInferenceBackend,
    systemInstruction,
    List.of(tool),
)

Начать сеанс чата

Для простоты этот быстрый старт запускает один сеанс чата. Вы также можете создать несколько независимых сеансов.

Используя новый экземпляр GenerativeModel , начните сеанс чата:

var chat = generativeModel.startChat();

Отправляйте подсказки модели через сеанс чата, используя метод sendMessage :

var response = chat.sendMessage("How's the weather in San Francisco?");

Анализ ответа модели

После передачи запроса модели приложение должно проверить ответ, чтобы определить, следует ли выполнить вызов функции или вывести текст на естественном языке.

// Extract the model's message from the response.
var message = response.getCandidates(0).getContent().getParts(0);

// If the message contains a function call, execute the function.
if (message.hasFunctionCall()) {
  var functionCall = message.getFunctionCall();
  var args = functionCall.getArgs().getFieldsMap();
  var result = null;

  // Call the appropriate function.
  switch (functionCall.getName()) {
    case "getWeather":
      result = ToolsForLlm.getWeather(args.get("location").getStringValue());
      break;
    case "getTime":
      result = ToolsForLlm.getWeather(args.get("timezone").getStringValue());
      break;
    default:
      throw new Exception("Function does not exist:" + functionCall.getName());
  }
  // Return the result of the function call to the model.
  var functionResponse =
      FunctionResponse.newBuilder()
          .setName(functionCall.getName())
          .setResponse(
              Struct.newBuilder()
                  .putFields("result", Value.newBuilder().setStringValue(result).build()))
          .build();
  var response = chat.sendMessage(functionResponse);
} else if (message.hasText()) {
  Log.i(message.getText());
}

Пример кода представляет собой чрезмерно упрощенную реализацию. Для получения дополнительной информации о том, как приложение может проверять ответы модели, см. Форматирование и анализ .

Как это работает

В этом разделе представлена ​​более подробная информация об основных концепциях и компонентах SDK вызова функций для Android.

Модели

Для вызова функций SDK требуется модель с форматером и парсером. FC SDK содержит встроенный форматер и парсер для следующих моделей:

  • Gemma : используйте GemmaFormatter .
  • Llama : используйте LlamaFormatter .
  • Hammer : используйте HammerFormatter .

Чтобы использовать другую модель с FC SDK, необходимо разработать собственный форматировщик и анализатор, совместимый с API вывода LLM.

Форматирование и анализ

Ключевой частью поддержки вызова функций является форматирование подсказок и разбор выходных данных модели. Хотя это два отдельных процесса, FC SDK обрабатывает как форматирование, так и разбор с помощью интерфейса ModelFormatter .

Форматировщик отвечает за преобразование структурированных деклараций функций в текст, форматирование ответов функций и вставку токенов для обозначения начала и конца реплик, а также ролей этих реплик (например, «пользователь», «модель»).

Анализатор отвечает за определение того, содержит ли ответ модели вызов функции. Если анализатор обнаруживает вызов функции, он анализирует его в структурированный тип данных. В противном случае он обрабатывает текст как ответ на естественном языке.

Ограниченное декодирование

Ограниченное декодирование — это метод, который направляет генерацию выходных данных LLM, чтобы гарантировать, что они соответствуют предопределенному структурированному формату, такому как объекты JSON или вызовы функций Python. Применяя эти ограничения, модель форматирует свои выходные данные таким образом, чтобы они соответствовали предопределенным функциям и их соответствующим типам параметров.

Чтобы включить ограниченное декодирование, определите ограничения в объекте ConstraintOptions и вызовите метод enableConstraint экземпляра ChatSession . При включении это ограничение ограничит ответ, включив только инструменты, связанные с GenerativeModel .

Следующий пример демонстрирует, как настроить ограниченное декодирование для ограничения ответа на вызовы инструментов. Он ограничивает вызов инструмента, чтобы он начинался с префикса ```tool_code\n и заканчивался суффиксом \n``` .

ConstraintOptions constraintOptions = ConstraintOptions.newBuilder()
  .setToolCallOnly( ConstraintOptions.ToolCallOnly.newBuilder()
  .setConstraintPrefix("```tool_code\n")
  .setConstraintSuffix("\n```"))
  .build(); chatSession.enableConstraint(constraintOptions);

Чтобы отключить активное ограничение в том же сеансе, используйте метод disableConstraint :

chatSession.disableConstraint()