Библиотека AI Edge Function Calling SDK (FC SDK) позволяет разработчикам использовать вызов функций с LLM-моделями, работающими непосредственно на устройстве. Вызов функций позволяет подключать модели к внешним инструментам и API, давая моделям возможность вызывать определенные функции с необходимыми параметрами для выполнения действий в реальном мире.
Вместо простого генерирования текста, LLM, использующий FC SDK, может генерировать структурированный вызов функции, которая выполняет действие, например, поиск актуальной информации, установку оповещений или бронирование.
В этом руководстве описан базовый быстрый старт по добавлению API вывода LLM с помощью FC SDK в приложение Android. Основное внимание уделяется добавлению возможностей вызова функций к встроенному в устройство LLM. Более подробную информацию об использовании API вывода LLM см. в руководстве по выводу LLM для Android .
Быстрый старт
Для использования FC SDK в вашем Android-приложении выполните следующие шаги. В этом кратком руководстве используется API LLM Inference с Hammer 2.1 (1.5B) . API LLM Inference оптимизирован для высокопроизводительных Android-устройств, таких как Pixel 8 и Samsung S23 или более поздних моделей, и не обеспечивает надежную поддержку эмуляторов устройств.
Добавить зависимости
SDK FC использует библиотеку com.google.ai.edge.localagents:localagents-fc , а API вывода LLM использует библиотеку com.google.mediapipe:tasks-genai . Добавьте обе зависимости в файл build.gradle вашего Android-приложения:
dependencies {
implementation 'com.google.mediapipe:tasks-genai:0.10.24'
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"/>
Скачать модель
Скачайте Hammer 1B в 8-битном квантованном формате с сайта Hugging Face . Более подробную информацию о доступных моделях см. в документации по моделям .
Загрузите содержимое папки hammer2.1_1.5b_q8_ekv4096.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 hammer2.1_1.5b_q8_ekv4096.task /data/local/tmp/llm/hammer2.1_1.5b_q8_ekv4096.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();
Создайте бэкэнд для вывода результатов.
Создайте бэкенд для вывода результатов, используя API вывода LLM, и передайте ему объект форматтера для вашей модели. Форматтер SDK FC ( 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 functionResponseContent = Content.newBuilder()
.setRole("user")
.addParts(Part.newBuilder().setFunctionResponse(functionResponse))
.build();
var response = chat.sendMessage(functionResponseContent);
} else if (message.hasText()) {
Log.i(message.getText());
}
Приведённый пример кода представляет собой чрезмерно упрощённую реализацию. Для получения дополнительной информации о том, как приложение может анализировать ответы модели, см. раздел «Форматирование и разбор» .
Как это работает
В этом разделе представлена более подробная информация об основных концепциях и компонентах SDK для вызова функций в Android.
Модели
Для работы Function Calling SDK требуется модель с форматтером и парсером. FC SDK содержит встроенные форматтер и парсер для следующих моделей:
- Джемма : используйте
GemmaFormatter. - Лама : используйте
LlamaFormatter. - Hammer : используйте
HammerFormatter.
Для использования другой модели с FC SDK необходимо разработать собственный форматтер и парсер, совместимые с API вывода LLM.
Форматирование и анализ
Ключевым аспектом поддержки вызова функций является форматирование подсказок и анализ выходных данных модели. Хотя это два отдельных процесса, SDK FC обрабатывает как форматирование, так и анализ с помощью интерфейса 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();