שימוש בבקשה להפעלת פונקציה

בעזרת גישה ישירה למודל של ML Kit, אתם יכולים להשתמש בקריאה להפעלת פונקציות כדי לאפשר למודלים של Gemini Nano להפיק בקשות מובנות להפעלת פונקציות (קריאות לכלי) במקום תשובות בטקסט פשוט. התכונה "קריאה לפונקציות" מאפשרת לחבר מודלים של AI גנרטיבי במכשיר לכלים חיצוניים, לממשקי API ולתכונות של אפליקציות מקומיות.

יכולות עיקריות

היכולות העיקריות של קריאה להפעלת פונקציות:

  • קריאה להפעלת פונקציות בסבב יחיד: Gemini Nano חוזה בקשה אחת או יותר להפעלת פונקציה (FunctionCall), האפליקציה מריצה את הפונקציות באופן מקומי והתהליך מסתיים בלי צורך בתגובת המשך מהמודל.
  • קריאה להפעלת פונקציות רב-שלבית: Gemini Nano חוזה בקשה אחת או יותר להפעלת פונקציה (FunctionCall), האפליקציה מריצה את הפונקציות באופן מקומי ומעבירה את התוצאות בחזרה (FunctionResponsePart) כדי לאחזר עוד בקשות להפעלת פונקציה או תשובת טקסט מסונתזת סופית.

כשמטמיעים קריאה להפעלת פונקציות, אפשר להשתמש בתכונות הבאות:

  • הגדרות של כלים פרוגרמטיים: יוצרים הגדרות דינמיות של כלים ב-FunctionDeclaration וב-FunctionSchema בזמן הריצה באמצעות ML Kit GenAI Schema API‏ (com.google.mlkit:genai-schema).
  • ניתוח ארגומנטים מובנים: קבלת ערכי ארגומנטים עם סוגים מוגדרים ישירות מהתשובה של המודל כדי להפעיל את הלוגיקה של האפליקציה המקומית.

תוצאות לדוגמה

התכונה "קריאה להפעלת פונקציות" תומכת גם בתהליכים של פנייה אחת וגם בתהליכים רב-שלביים. בשני המקרים, המודל חוזה קריאה אחת או יותר לפונקציה, שמורכבת משם הפונקציה והארגומנטים. בתהליכים עם כמה שלבים, אחרי שהאפליקציה מקבלת את תוצאות ההפעלה, היא יכולה לשלוח עוד בקשה למודל עם היסטוריית השיחות המלאה כדי לקבל עוד קריאות לפונקציות או תשובת טקסט סופית למשתמש.

תהליך ההרצה הנחיה למשתמש הפלט מהמודל
סיבוב אחד "Turn on the living room lights to 80% brightness" קריאה לכלי:
turn_on_light(room="living room", brightness=80)
סיבוב אחד "תפתח את אפליקציית המצלמה". קריאה לכלי:
open_app(appName="Camera")
רב-שלבי "What's the weather like in San Francisco in Celsius?‎" קריאה לכלי ביניים:
get_current_weather(location="San Francisco, CA", unit="celsius")

הפלט הסופי מהמודל שמוצג למשתמש:
In SF it's currently 25 degrees Celsius.

דרישות מוקדמות

כדי להשתמש בקריאה להפעלת פונקציות, אתם צריכים לעמוד בדרישות הבאות לגבי המכשיר והחשבון:

כדי לוודא שאתם עומדים בדרישות האלה, ודאו שהמודל Gemini Nano 4 Fast זמין באפליקציית AICore: פתחו את אפליקציית 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
            // ...
        }
    }
    

איך משתמשים ב-Function Calling 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
}

קריאה להפעלת פונקציה בסבב יחיד

השתמשו בקריאה להפעלת פונקציות בסבב יחיד למשימות שמתמקדות בפעולות שבהן האפליקציה ממלאת את הבקשה באופן ישיר (לדוגמה, "פתח את אפליקציית המצלמה" או "הדלק את האורות ב-Living Room"). אחרי שהאפליקציה מפעילה את הפונקציה באופן מקומי, התהליך מסתיים ואין צורך בתגובה נוספת מהמודל.

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")

קוד לדוגמה

באפליקציה לדוגמה של ML Kit יש דוגמה מלאה לקריאה לפונקציות באפליקציה ל-Android.

בעיות מוכרות

  • ‫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 הסופי בסטרימינג) אחרי שהמודל מסיים ליצור את הקריאה לפונקציה.