関数呼び出しを使用する

ML Kit の直接モデルアクセスでは、関数呼び出しを使用して、Gemini Nano モデルが書式なしテキストのレスポンスではなく、構造化された関数実行リクエスト(ツール呼び出し)を出力できるようにします。関数呼び出しを使用すると、オンデバイスの生成 AI モデルを外部ツール、API、ローカルアプリの機能に接続できます。

主な機能

関数呼び出しには、次の主な機能があります。

  • シングルターン関数呼び出し: Gemini Nano が 1 つ以上のツール呼び出し(FunctionCall)を予測し、アプリが関数をローカルで実行します。フローは、フォローアップ モデル レスポンスを必要とせずに完了します。
  • マルチターン関数呼び出し: Gemini Nano が 1 つ以上のツール呼び出し(FunctionCall)を予測し、アプリが関数をローカルで実行して、結果を返します(FunctionResponsePart)。これにより、さらにツール呼び出しを取得するか、最終的な合成テキスト レスポンスを取得します。

関数呼び出しを実装する際は、次の機能を利用できます。

  • プログラムによるツール定義: ML Kit GenAI Schema API(com.google.mlkit:genai-schema)を使用して、実行時に動的な FunctionDeclaration ツール定義と FunctionSchema ツール定義を構築します。
  • 構造化された引数の解析: モデル レスポンス候補から直接、厳密に型指定された引数値を受け取り、ローカルアプリ ロジックを実行します。

検索結果の例

関数呼び出しは、シングルターン フローとマルチターン フローの両方をサポートしています。どちらの場合も、モデルは関数名と引数で構成される 1 つ以上のツール呼び出しを予測します。マルチターンのフローでは、アプリの実行結果を受け取った後、アプリは会話履歴全体を含む別のリクエストをモデルに送信して、ユーザー向けのツール呼び出しや最終的なテキスト レスポンスを取得できます。

実行フロー ユーザーによるプロンプト モデル出力
シングルターン 「リビングの照明を明るさ 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.

前提条件

関数呼び出しを使用するには、次のデバイスとアカウントの要件を満たす必要があります。

これらの要件を満たしていることを確認するには、AICore アプリで Gemini Nano 4 Fast モデルが利用可能であることを確認します。AICore アプリを開き、[モデルを選択] プルダウンをクリックして、[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. ツール呼び出し(シングルターンまたはマルチターン)を処理する。

次のセクションでは、これらの手順を示す例について説明します。

ツールを定義する

com.google.mlkit.genai.schema.tools パッケージの FunctionDeclaration、FunctionSchema、FunctionType を使用して、プログラムでツールスキーマを構築します。(Android の @AppFunction アノテーションと自動実行を使用して、コンパイル時に宣言的にツールを定義するには、ツールを定義するをご覧ください)。

たとえば、アクション指向のツール(シングルターン実行でスマートライトをオンにするなど)を定義できます。

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 を使用して、ModelReleaseStage.PREVIEW と ModelPreference.FAST をターゲットとするように GenerativeModel インスタンスを構成します。

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 がツールを呼び出すことを決定すると、モデルのレスポンス候補には candidate.functionCalls に 1 つ以上の FunctionCall オブジェクトが含まれます。ツール呼び出しを処理するには、アプリはまずレスポンス候補を検査して、ツール呼び出しが予測されたかどうかを確認する必要があります。

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 サンプルアプリをご覧ください。

既知の問題

  • 直接モデルアクセス(genai-prompt)での AndroidX AppFunctions(@AppFunction): Prompt API(com.google.mlkit:genai-prompt:1.0.0-beta5)を介してコンパイル時の @AppFunction ツールを直接検出して実行することはまだできません。genai-prompt ライブラリのツールは、FunctionDeclaration クラスを使用してプログラムで定義する必要があります。@AppFunction ツールを今すぐ使用するには、Agentic Workflows(com.google.mlkit:genai-agent)を使用します。
  • ストリーミング リクエスト(generateContentStream)を使用する場合、ツール呼び出しはトークンごとにストリーミングされません。代わりに、モデルがツール呼び出しの生成を完了すると、完全な FunctionCall オブジェクトが(StreamingCallback.onNewFunctionCall 経由または最後のストリーミング GenerateContentResponse.candidates[0].functionCalls で)出力されます。