Как использовать вызов функций

Благодаря прямому доступу к модели ML Kit вы можете использовать вызов функций, чтобы модели Gemini Nano выводили структурированные запросы на выполнение функций (вызовы инструментов) вместо обычных текстовых ответов. Вызов функций позволяет подключать встроенные модели генеративного ИИ к внешним инструментам, API и функциям локальных приложений.

Основные возможности

Вызов функций предоставляет следующие ключевые возможности:

  • Одноэтапный вызов функций. Gemini Nano прогнозирует один или несколько вызовов инструментов (FunctionCall), ваше приложение выполняет функции локально, и процесс завершается без необходимости последующего ответа модели.
  • Многоэтапный вызов функций. Gemini Nano прогнозирует один или несколько вызовов инструментов (FunctionCall), ваше приложение выполняет функции локально и передает результаты обратно (FunctionResponsePart), чтобы получить больше вызовов инструментов или окончательный синтезированный текстовый ответ.

При реализации вызова функций вы можете воспользоваться следующими возможностями:

  • Программные определения инструментов. Создавайте динамические определения инструментов FunctionDeclaration и FunctionSchema во время выполнения с помощью ML Kit GenAI Schema API (com.google.mlkit:genai-schema).
  • Структурированный синтаксический анализ аргументов. Получайте строго типизированные значения аргументов непосредственно из ответа модели, чтобы выполнять логику локального приложения.

Пример результатов

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

Процесс выполнения Запрос пользователя Выходные данные модели
Один поворот "Включи свет в гостиной на 80 %". Вызов инструмента:
turn_on_light(room="living room", brightness=80)
Один поворот "Открой приложение "Камера". Вызов инструмента:
open_app(appName="Camera")
Пошаговый "Какая сейчас погода в Москве в градусах Цельсия?" Промежуточный вызов инструмента:
get_current_weather(location="San Francisco, CA", unit="celsius")

Окончательный результат работы модели, показанный пользователю:
In SF it's currently 25 degrees Celsius.

Требования

Чтобы использовать вызов функций, ваше устройство и аккаунт должны соответствовать следующим требованиям:

Чтобы проверить, выполнены ли эти требования, убедитесь, что модель Gemini Nano 4 Fast доступна в приложении AICore. Для этого откройте приложение AICore, нажмите на раскрывающийся список Select a model (Выбрать модель) и проверьте, есть ли в нем Gemini Nano 4 Fast. Если модели нет, значит устройство не поддерживается или аккаунт не зарегистрирован, и вызов функций работать не будет.

Кроме того, ваш проект должен соответствовать следующим требованиям:

  • Kotlin 2.3.0 или более поздней версии;
  • Минимальная версия SDK (minSdk) – 26 или выше.

Начать

Вот как начать использовать вызов функций.

  1. В файле settings.gradle.kts (или settings.gradle) на уровне проекта добавьте mavenCentral() в блок repositories {}.

    dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            google()
            mavenCentral()
        }
    }
    
  2. В файле build.gradle.kts (или build.gradle) на уровне модуля добавьте зависимости ML Kit Prompt API и схемы:

    Kotlin

    plugins {
        id("com.android.application")
        id("org.jetbrains.kotlin.android")
    }
    
    dependencies {
        // ML Kit GenAI Prompt and Schema SDKs
        implementation("com.google.mlkit:genai-prompt:1.0.0-beta5")
        implementation("com.google.mlkit:genai-schema:1.0.0-alpha2")
    }
    

    Groovy

    plugins {
        id 'com.android.application'
        id 'org.jetbrains.kotlin.android'
    }
    
    dependencies {
        // ML Kit GenAI Prompt and Schema SDKs
        implementation 'com.google.mlkit:genai-prompt:1.0.0-beta5'
        implementation 'com.google.mlkit:genai-schema:1.0.0-alpha2'
    }
    
  3. В файле build.gradle (или build.gradle.kts) на уровне модуля задайте для minSdk версию 26 или выше.

    Kotlin

    android {
        defaultConfig {
            // ...
            minSdk = 26
            // ...
        }
    }
    

    Groovy

    android {
        defaultConfig {
            // ...
            minSdk 26
            // ...
        }
    }
    

Как использовать API вызова функций

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

  1. Определите инструменты.
  2. Выберите модель.
  3. Прикрепите инструменты к запросу.
  4. Обработка вызовов инструментов (одно- или многоэтапных).

В следующих разделах приведен пример, демонстрирующий эти шаги.

Определите инструменты

Создавайте схемы инструментов программно, используя FunctionDeclaration, FunctionSchema и FunctionType из пакета com.google.mlkit.genai.schema.tools. Чтобы определить инструменты декларативно во время компиляции с помощью аннотации @AppFunction в Android и автоматического выполнения, ознакомьтесь с разделом Определение инструментов.

Например, вы можете определить инструмент, ориентированный на действие (например, включение умного светильника за один шаг):

import com.google.mlkit.genai.schema.tools.FunctionDeclaration
import com.google.mlkit.genai.schema.tools.FunctionSchema
import com.google.mlkit.genai.schema.tools.FunctionType

val turnOnLightTool = FunctionDeclaration(
    name = "turn_on_light",
    description = "Turn on the lights in a room and set the brightness",
    parameters = FunctionSchema(
        type = FunctionType.OBJECT,
        properties = mapOf(
            "room" to FunctionSchema(
                type = FunctionType.STRING,
                description = "The room name"
            ),
            "brightness" to FunctionSchema(
                type = FunctionType.INTEGER,
                description = "Brightness level from 0 to 100"
            )
        ),
        required = listOf("room")
    )
)

Или определите инструмент извлечения данных (например, получение текущей погоды для многоэтапного синтеза):

import com.google.mlkit.genai.schema.tools.FunctionDeclaration
import com.google.mlkit.genai.schema.tools.FunctionSchema
import com.google.mlkit.genai.schema.tools.FunctionType

val getWeatherTool = FunctionDeclaration(
    name = "get_current_weather",
    description = "Get the current weather for a location",
    parameters = FunctionSchema(
        type = FunctionType.OBJECT,
        properties = mapOf(
            "location" to FunctionSchema(
                type = FunctionType.STRING,
                description = "The city and state, e.g. San Francisco, CA"
            ),
            "unit" to FunctionSchema(
                type = FunctionType.STRING,
                description = "The temperature unit, either 'celsius' or 'fahrenheit'"
            )
        ),
        required = listOf("location")
    )
)

Выберите модель

Для вызова функций требуется Gemini Nano 4. Чтобы получить доступ к Gemini Nano 4, используйте API выбора модели и настройте экземпляр GenerativeModel для работы с ModelReleaseStage.PREVIEW и ModelPreference.FAST.

import com.google.mlkit.genai.prompt.Generation
import com.google.mlkit.genai.prompt.ModelPreference
import com.google.mlkit.genai.prompt.ModelReleaseStage
import com.google.mlkit.genai.prompt.generationConfig
import com.google.mlkit.genai.prompt.modelConfig

// Target the preview fast model (Gemini Nano 4)
val config = generationConfig {
    modelConfig = modelConfig {
        releaseStage = ModelReleaseStage.PREVIEW
        preference = ModelPreference.FAST
    }
}
val generativeModel = Generation.getClient(config)

Прикрепите инструменты к запросу

При создании объекта GenerateContentRequest передайте список FunctionDeclaration в setTools() в конструкторе запросов.

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

import com.google.mlkit.genai.prompt.SystemInstruction
import com.google.mlkit.genai.prompt.TextPart
import com.google.mlkit.genai.prompt.generateContentRequest

val requestText = "Turn on the living room lights and set brightness to 50"

val request = generateContentRequest(
    SystemInstruction("You are a helpful home automation assistant."),
    TextPart(requestText)
) {
    // Attach the FunctionDeclaration tool schemas
    setTools(listOf(turnOnLightTool))
    temperature = 0.2f
}

// Run non-streaming inference
val response = generativeModel.generateContent(request)

Или прикрепить список FunctionDeclaration для многоэтапного запроса:

import com.google.mlkit.genai.prompt.SystemInstruction
import com.google.mlkit.genai.prompt.TextPart
import com.google.mlkit.genai.prompt.generateContentRequest

val availableTools = listOf(getWeatherTool)

// Use the generateContentRequest DSL
val request = generateContentRequest(
    TextPart("What is the weather in San Francisco, CA in celsius?")
) {
    setTools(availableTools)
}
val response = generativeModel.generateContent(request)

Как обрабатывать вызовы инструментов

Когда Gemini Nano решает вызвать инструмент, ответ модели содержит один или несколько объектов FunctionCall в candidate.functionCalls. Чтобы обработать вызовы инструментов, ваше приложение должно сначала проверить вариант ответа и убедиться, что в нем есть вызовы инструментов.

import com.google.mlkit.genai.common.FunctionArgValue
import com.google.mlkit.genai.prompt.Content
import com.google.mlkit.genai.prompt.FunctionCallPart
import com.google.mlkit.genai.prompt.FunctionResponsePart
import com.google.mlkit.genai.prompt.GenerateContentRequest
import com.google.mlkit.genai.prompt.TextPart
import com.google.mlkit.genai.prompt.content

val candidate = response.candidates.firstOrNull()
val functionCalls = candidate?.functionCalls ?: emptyList()

if (functionCalls.isNotEmpty()) {
    // Process tool calls using either the single-turn or multi-turn flow
    // described in the following sections
}

Вызов функции за один ход

Используйте одноэтапный вызов функций для задач, ориентированных на действия, когда приложение напрямую выполняет запрос (например, "Открой приложение Камера" или "Включи свет на устройствах в гостиной"). После того как приложение выполнит функцию локально, процесс завершится. Ответ модели не требуется.

for (functionCall in functionCalls) {
    val name = functionCall.name
    val args = functionCall.arguments // Map<String, FunctionArgValue>

    when (name) {
        "open_app" -> {
            val appName = (args["appName"] as? FunctionArgValue.StringValue)?.value
            launchApp(appName)
        }
        "turn_on_light" -> {
            val room = (args["room"] as? FunctionArgValue.StringValue)?.value
            val brightness = (args["brightness"] as? FunctionArgValue.IntValue)?.value ?: 100
            setLightState(room, brightness)
        }
        else -> Log.w(TAG, "Unhandled tool call: $name")
    }
}

Многоэтапный вызов функций

Используйте многоэтапный вызов функций, когда пользователь ожидает ответ на естественном языке, основанный на данных, полученных инструментом (например, "Какая погода в Сан-Франциско?").

В многоэтапном процессе приложение выполняет следующие действия:

  1. Выполняет запрошенную функцию локально.
  2. Упаковывает результат в объект FunctionResponsePart.
  3. Добавляет в историю чата вызов модели (роль MODEL) и результат выполнения (роль USER).
  4. Отправляет Gemini Nano запрос на создание окончательного ответа на естественном языке.
// 1. Execute each predicted tool call and collect results
val responseParts = mutableListOf<FunctionResponsePart>()

for (functionCall in functionCalls) {
    val responsePart: FunctionResponsePart = when {
        functionCall.name == "get_current_weather" -> {
            val location = (functionCall.arguments["location"] as? FunctionArgValue.StringValue)?.value ?: ""
            val unit = (functionCall.arguments["unit"] as? FunctionArgValue.StringValue)?.value ?: "celsius"

            val weatherData = fetchWeather(location, unit) // Local network/API call

            // Package the tool execution result as a key-value map
            FunctionResponsePart(
                id = functionCall.id,
                name = functionCall.name,
                response = mapOf("result" to weatherData)
            )
        }

        else -> throw IllegalArgumentException("Unknown tool: ${functionCall.name}")
    }
    responseParts.add(responsePart)
}

// 2. Append turns to conversation history to construct the multi-turn context
val history = request.contents.toMutableList().apply {
    // Turn 1: Model's request containing the predicted FunctionCallPart object
    add(
        content(Content.Role.MODEL) {
            for (call in functionCalls) {
                addPart(FunctionCallPart(call))
            }
        }
    )
    // Turn 2: User's response containing the executed FunctionResponsePart object
    add(
        content(Content.Role.USER) {
            for (responsePart in responseParts) {
                addPart(responsePart)
            }
        }
    )
}

// 3. Send the updated history back to Gemini Nano for final text synthesis
val followUpRequest = GenerateContentRequest.Builder(history)
    .setTools(availableTools) // Include tools in case the model requires subsequent tool calls
    .build()

val finalResponse = generativeModel.generateContent(followUpRequest)
val answer = finalResponse.candidates.firstOrNull()?.text

Log.d(TAG, "Final Model Response: $answer")

Образец кода

Полный рабочий пример вызова функций в приложении для Android можно найти в примере приложения ML Kit.

Известные проблемы

  • AndroidX AppFunctions (@AppFunction) в прямом доступе к модели (genai-prompt). Обнаружение и выполнение инструментов @AppFunction времени компиляции напрямую через Prompt API (com.google.mlkit:genai-prompt:1.0.0-beta5) пока недоступно. Инструменты в библиотеке genai-prompt должны быть определены программно с помощью класса FunctionDeclaration. Чтобы использовать инструменты @AppFunction, используйте агентные рабочие процессы (com.google.mlkit:genai-agent).
  • При использовании потоковых запросов (generateContentStream) вызовы инструментов не передаются по токенам. Вместо этого полные объекты FunctionCall передаются (через StreamingCallback.onNewFunctionCall или в последнем потоковом GenerateContentResponse.candidates[0].functionCalls), как только модель завершает генерирование вызова инструмента.