יצירת פלט מובנה לחוויות היברידיות באפליקציות ל-Android


כברירת מחדל, מודלים של Gemini מחזירים תשובות כטקסט לא מובנה. עם זאת, יש תרחישי שימוש שבהם נדרש טקסט מובנה (כמו JSON או enums). לדוגמה, יכול להיות שאתם משתמשים בתשובה למשימות אחרות בהמשך התהליך שדורשות סכימת נתונים מוגדרת.

כדי לוודא שהפלט שנוצר על ידי המודל תמיד תואם לסכימה ספציפית, אתם יכולים להגדיר סכימה, שפועלת כמו תוכנית לתשובות של המודל. לאחר מכן, אפשר לחלץ נתונים ישירות מהפלט של המודל עם פחות עיבוד לאחר מכן.

הנה מספר תרחישים לדוגמה:

  • לוודא שהתשובה של המודל היא JSON תקין ותואמת לסכימה שסיפקתם.
    לדוגמה, המודל יכול ליצור רשומות מובנות למתכונים שתמיד כוללות את שם המתכון, רשימת המרכיבים והשלבים. אחר כך תוכלו לנתח את המידע הזה ולהציג אותו בממשק המשתמש של האפליקציה בקלות רבה יותר.

  • הגבלת האופן שבו מודל יכול להגיב במהלך משימות סיווג.
    לדוגמה, אתם יכולים להגדיר שהמודל יוסיף הערות לטקסט עם קבוצה ספציפית של תוויות (למשל, קבוצה ספציפית של סוגי מנייה כמו positive ו-negative), במקום תוויות שהמודל יוצר (שיכולות להיות עם מידה מסוימת של שונות כמו good,‏ positive,‏ negative או bad).

בדף הזה מוסבר איך ליצור פלט מובנה (כמו JSON וספירות) בחוויות היברידיות באפליקציות ל-Android.

מעבר לפלט JSON מעבר לפלט enum

הגדרות לפלט מובנה

יצירת פלט מובנה (כמו JSON ו-enums) נתמכת גם בהסקת מסקנות במכשיר וגם בהסקת מסקנות באירוח בענן.

כדי ליצור פלט מובנה, מעבירים את הסכימה ישירות אל generateObject(). הדרישות לגבי הסכימה תלויות במצב ההסקה שהגדרתם:

  • למסקנות במכשיר ולמסקנות היברידיות (ONLY_ON_DEVICE, PREFER_ON_DEVICE ו-PREFER_IN_CLOUD):

    • נדרש שימוש בהערה @Generable ב-Kotlin data class עם מעבד KSP. לא ניתן להשתמש בסכימות ידניות ובהערות enum class ישירות.
    • כשמריצים היקשים במכשיר, ערכת ה-SDK מתרגמת באופן אוטומטי את הסכימה לאילוצים עבור המודל במכשיר (באמצעות ML Kit Prompt API).
    • אם בקשה היברידית חוזרת להסקת מסקנות בענן, ה-SDK מגדיר אוטומטית את responseMimeType ל-application/json ומעביר את הסכימה למודל Gemini שמתארח בענן.
  • למסקנות בענן בלבד (ONLY_IN_CLOUD):

    • הכלי תומך גם בהערות @Generable (מומלץ) וגם בסכימות ידניות (שנוצרו באמצעות JsonSchema שיטות עזר).
    • ה-SDK מגדיר אוטומטית את responseMimeType לערך application/json ומעביר את הסכימה למודל Gemini שמתארח בענן.

לפני שמתחילים

לוחצים על הספק Gemini API כדי לראות בדף הזה תוכן וקוד שספציפיים לספק.

לפני שיוצרים פלט מובנה, צריך לוודא שהשלמתם את ההגדרה הבאה:

  1. כדאי לעיין במדריך לתחילת העבודה בנושא יצירת חוויות היברידיות, שכולל הסברים על הגדרת פרויקט Firebase, הורדת המודל במכשיר והגדרת App Check.

  2. מגדירים את הפלאגין Kotlin Symbol Processing (KSP) ומוסיפים את התלות Firebase AI KSP לאפליקציה.

    בקובץ Gradle של המודול (ברמת האפליקציה) (למשל <project>/<app-module>/build.gradle.kts), מוסיפים את פלאגין KSP, את פלאגין הסריאליזציה של Kotlin ואת יחסי התלות הנדרשים:

    plugins {
       // ... other plugins
       id("com.google.gms.google-services")
       id("com.google.devtools.ksp") version "LATEST_VERSION"
       id("org.jetbrains.kotlin.plugin.serialization") version "LATEST_VERSION"
    }
    
    dependencies {
       // ... other androidx dependencies
    
       // Add the dependencies for the Firebase AI Logic and App Check libraries.
       implementation("com.google.firebase:firebase-ai:17.17.0")
       implementation("com.google.firebase:firebase-ai-ondevice:16.0.0-beta05")
       implementation("com.google.firebase:firebase-appcheck-debug:19.4.1")
    
       // Add the Firebase AI KSP processor for schema generation.
       ksp("com.google.firebase:firebase-ai-ksp-processor:16.0.2")
    
       // (Optional) Add kotlinx.serialization JSON library for object decoding.
       implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:LATEST_VERSION")
    }


מעבר לפלט JSON מעבר לפלט enum

פלט JSON

בדוגמאות הבאות מותאמת דוגמת הפלט הכללית של JSON כדי להתאים להסקת מסקנות היברידית (לדוגמה, PREFER_ON_DEVICE).

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

אפשר להגדיר את סכימות התגובה באמצעות אחת מהגישות הבאות:

  • הערות KSP (@Generable ו-@Guide)

    • התכונה נתמכת בכל מצבי ההסקה נדרשת להסקה במכשיר ולהסקה היברידית (במיוחד ONLY_ON_DEVICE, PREFER_ON_DEVICE ו- PREFER_IN_CLOUD).
    • הגדרת מחלקות נתונים ב-Kotlin כדי ליצור סכימות באופן אוטומטי בזמן ההידור ולבצע דה-סריאליזציה של תגובות ישירות לאובייקטים עם הקלדה חזקה באמצעות getObject().
  • שיטות עזר JsonSchema ידניות

    • התמיכה ב-רק מבוססת על הסקה מבוססת-ענן (במיוחד, ONLY_IN_CLOUD).
    • יוצרים באופן ידני JsonSchema בקוד בלי להשתמש במעבד KSP, וקוראים את מחרוזת ה-JSON הגולמית מ-response.response.text.

דוגמה 1: שימוש בהערות @Generable ו-@Guide עם KSP

הגדרת Kotlin data class עם ההערות @Serializable ו-@Generable. אפשר להשתמש בהערות @Guide במאפיינים כדי לספק למודל תיאורים, גבולות ערכים או אילוצים של פריטים.

הגישה הזו נתמכת בכל מצבי ההסקה, והיא נדרשת לחוויות במכשיר ולחוויות היברידיות (במיוחד ONLY_ON_DEVICE,‏ PREFER_ON_DEVICE ו-PREFER_IN_CLOUD).

לפני שמנסים את הדוגמה הזו, צריך להשלים את השלבים שבקטע לפני שמתחילים במדריך הזה כדי להגדיר את הפרויקט והאפליקציה.
בקטע הזה, צריך גם ללחוץ על לחצן של ספק Gemini API שבחרתם כדי שיוצג בדף הזה תוכן שספציפי לספק.

ב-Kotlin, המתודות ב-SDK הזה הן פונקציות השהיה וצריך להפעיל אותן מתוך היקף של Coroutine.
import com.google.firebase.Firebase
import com.google.firebase.ai.type.GenerativeBackend
import com.google.firebase.ai.InferenceMode
import com.google.firebase.ai.OnDeviceConfig
import com.google.firebase.ai.annotations.Generable
import com.google.firebase.ai.annotations.Guide
import com.google.firebase.ai.ai
import kotlinx.serialization.Serializable

// Define data classes representing the schema, annotated with @Serializable and @Generable.
// You can provide descriptions on @Generable and @Guide to guide the model's output.
@Serializable
@Generable(description = "A character profile for a fantasy story")
data class Character(
    val name: String,
    val age: Int,
    val species: String,
    // Use @Guide to add property descriptions, value bounds (minimum/maximum), or formats.
    // Properties with default values or nullable types are treated as optional in the schema.
    @Guide(description = "An accessory the character wears or carries")
    val accessory: String? = null
) {
    // An empty companion object is required for KSP to generate the firebaseAISchema() extension.
    companion object
}

@Serializable
@Generable(description = "A list of character profiles")
data class CharacterList(
    // Use minItems or maxItems to specify collection size bounds for the model.
    @Guide(description = "List of characters", minItems = 1)
    val characters: List<Character>
) {
    // An empty companion object is required for KSP to generate the firebaseAISchema() extension.
    companion object
}

// Initialize the Gemini Developer API backend service.
// Create a GenerativeModel instance configured for hybrid inference (like PREFER_ON_DEVICE).
val model = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        modelName = "CLOUD_MODEL_NAME",
        onDeviceConfig = OnDeviceConfig(mode = InferenceMode.INFERENCE_MODE)
    )

// Obtain the schema generated by KSP via the firebaseAISchema() extension.
val schema = CharacterList.firebaseAISchema()
val prompt = "Create profiles for some characters for a fantasy story."

// Generate the structured object (the SDK applies the schema to on-device or cloud models).
val response = model.generateObject(schema, prompt)

// Access the strongly-typed deserialized object directly via getObject().
val characterList: CharacterList? = response.getObject()
characterList?.characters?.forEach { character ->
    println("Name: ${character.name}, Species: ${character.species}, Age: ${character.age}")
    println("Accessory: ${character.accessory ?: "None"}")
}

דוגמה 2: שימוש בשיטות עזר ידניות של JsonSchema

אם האפליקציה שלכם משתמשת רק בהסקת מסקנות מבוססת-ענן (במיוחד, ONLY_IN_CLOUD), אתם יכולים ליצור באופן ידני JsonSchema באמצעות שיטות עזר שזמינות ב-Firebase AI Logic SDK.

לפני שמנסים את הדוגמה הזו, צריך להשלים את השלבים שבקטע לפני שמתחילים במדריך הזה כדי להגדיר את הפרויקט והאפליקציה.
בקטע הזה, צריך גם ללחוץ על לחצן של ספק Gemini API שבחרתם כדי שיוצג בדף הזה תוכן שספציפי לספק.

ב-Kotlin, המתודות ב-SDK הזה הן פונקציות השהיה וצריך להפעיל אותן מתוך היקף של Coroutine.
import com.google.firebase.Firebase
import com.google.firebase.ai.type.GenerativeBackend
import com.google.firebase.ai.InferenceMode
import com.google.firebase.ai.OnDeviceConfig
import com.google.firebase.ai.ai
import com.google.firebase.ai.type.JsonSchema

// Define the schema manually using JsonSchema helper methods.
// Properties are required by default unless specified in optionalProperties.
val jsonSchema = JsonSchema.obj(
    properties = mapOf(
        "characters" to JsonSchema.array(
            items = JsonSchema.obj(
                properties = mapOf(
                    "name" to JsonSchema.string(),
                    "accessory" to JsonSchema.string(),
                    "age" to JsonSchema.integer(),
                    "species" to JsonSchema.string()
                ),
                optionalProperties = listOf("accessory")
            )
        )
    )
)

// Initialize the Gemini Developer API backend service.
// Manual schemas are only supported for cloud-based inference (specifically, ONLY_IN_CLOUD).
val model = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        modelName = "CLOUD_MODEL_NAME",
        onDeviceConfig = OnDeviceConfig(mode = InferenceMode.ONLY_IN_CLOUD)
    )

// Call generateObject() with the manual schema and prompt.
val response = model.generateObject(
    jsonSchema,
    "Create profiles for some characters for a fantasy story."
)

// Access the generated JSON string conforming to the schema from response.response.text.
println(response.response.text)

פלט של טיפוסים בני מנייה (enum)

בדוגמאות הבאות מותאמת דוגמת הפלט הכללית של enum כדי להתאים להסקת מסקנות היברידית (לדוגמה, PREFER_ON_DEVICE).

בתרחיש של הדוגמאות האלה, המודל מסווג תיאור של סרט על ידי בחירת ז'אנר יחיד מתוך רשימה מוגדרת מראש של אפשרויות מותרות (drama,‏ comedy או documentary).

אפשר להגדיר את סכימות התגובה באמצעות אחת מהגישות הבאות:

  • הערות KSP (@Generable)

    • התכונה נתמכת בכל מצבי ההסקה נדרשת להסקה במכשיר ולהסקה היברידית (במיוחד ONLY_ON_DEVICE, PREFER_ON_DEVICE ו- PREFER_IN_CLOUD).
    • אפשר להגדיר enum שעטוף ב-Kotlin data class כדי ליצור אוטומטית את הסכימה ולבטל את הסריאליזציה של התשובות ישירות לאובייקטים עם הקלדה חזקה באמצעות getObject().
  • שיטות עזר JsonSchema ידניות

    • התמיכה ב-רק מבוססת על הסקה מבוססת-ענן (במיוחד, ONLY_IN_CLOUD).
    • בונים ידנית enum JsonSchema באמצעות JsonSchema.enumeration() בלי להשתמש במעבד KSP, וקוראים את המחרוזת שנבחרה מ-response.response.text.

דוגמה 1: שימוש בהערות @Generable עם KSP

מגדירים enum class שמייצג את הערכים המותרים, ומקיפים אותו כמאפיין בתוך Kotlin data class עם ההערות @Serializable ו-@Generable.

הגישה הזו נתמכת בכל מצבי ההסקה, והיא נדרשת לחוויות במכשיר ולחוויות היברידיות (במיוחד ONLY_ON_DEVICE,‏ PREFER_ON_DEVICE ו-PREFER_IN_CLOUD).

לפני שמנסים את הדוגמה הזו, צריך להשלים את השלבים שבקטע לפני שמתחילים במדריך הזה כדי להגדיר את הפרויקט והאפליקציה.
בקטע הזה, צריך גם ללחוץ על לחצן של ספק Gemini API שבחרתם כדי שיוצג בדף הזה תוכן שספציפי לספק.

ב-Kotlin, המתודות ב-SDK הזה הן פונקציות השהיה וצריך להפעיל אותן מתוך היקף של Coroutine.
import com.google.firebase.Firebase
import com.google.firebase.ai.type.GenerativeBackend
import com.google.firebase.ai.InferenceMode
import com.google.firebase.ai.OnDeviceConfig
import com.google.firebase.ai.annotations.Generable
import com.google.firebase.ai.annotations.Guide
import com.google.firebase.ai.ai
import kotlinx.serialization.Serializable

// Define an enum class representing the allowed options.
@Serializable
enum class FilmGenre {
    DRAMA,
    COMEDY,
    DOCUMENTARY
}

// Wrap the enum in a data class annotated with @Serializable and @Generable.
// On-device inference requires an @Generable data class.
// Direct enum annotations are not supported on-device.
@Serializable
@Generable(description = "The classification result for the film")
data class FilmClassification(
    @Guide(description = "The genre of the film")
    val genre: FilmGenre
) {
    // An empty companion object is required for KSP to generate the firebaseAISchema() extension.
    companion object
}

// Initialize the Gemini Developer API backend service.
// Create a GenerativeModel instance configured for hybrid inference (like PREFER_ON_DEVICE).
val model = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        modelName = "CLOUD_MODEL_NAME",
        onDeviceConfig = OnDeviceConfig(mode = InferenceMode.INFERENCE_MODE)
    )

// Obtain the schema generated by KSP via the firebaseAISchema() extension.
val schema = FilmClassification.firebaseAISchema()
val prompt = """
    The film aims to educate and inform viewers about real-life subjects, events, or people.
    It offers a factual record of a particular topic by combining interviews, historical footage,
    and narration. The primary purpose of a film is to present information and provide insights
    into various aspects of reality.
    """

// Generate the structured object (the SDK applies the schema to on-device or cloud models).
val response = model.generateObject(schema, prompt)

// Access the strongly-typed deserialized object and enum value directly via getObject().
val classification: FilmClassification? = response.getObject()
val genre: FilmGenre? = classification?.genre
println("Selected genre: $genre")

דוגמה 2: שימוש בשיטות עזר ידניות של JsonSchema

אם האפליקציה שלכם משתמשת רק בהסקת מסקנות מבוססת-ענן (בספציפיות, ONLY_IN_CLOUD), אתם יכולים ליצור ידנית סוג enum‏ JsonSchema באמצעות שיטות עזר שזמינות ב-Firebase AI Logic SDK.

לפני שמנסים את הדוגמה הזו, צריך להשלים את השלבים שבקטע לפני שמתחילים במדריך הזה כדי להגדיר את הפרויקט והאפליקציה.
בקטע הזה, צריך גם ללחוץ על לחצן של ספק Gemini API שבחרתם כדי שיוצג בדף הזה תוכן שספציפי לספק.

ב-Kotlin, המתודות ב-SDK הזה הן פונקציות השהיה וצריך להפעיל אותן מהיקף של Coroutine.
import com.google.firebase.Firebase
import com.google.firebase.ai.type.GenerativeBackend
import com.google.firebase.ai.InferenceMode
import com.google.firebase.ai.OnDeviceConfig
import com.google.firebase.ai.ai
import com.google.firebase.ai.type.JsonSchema

// Define an enum schema with allowed string values and a description.
val enumSchema = JsonSchema.enumeration(
    values = listOf("drama", "comedy", "documentary"),
    description = "The genre of the film"
)

// Initialize the Gemini Developer API backend service.
// Manual schemas are only supported for cloud-based inference (specifically, ONLY_IN_CLOUD).
val model = Firebase.ai(backend = GenerativeBackend.googleAI())
    .generativeModel(
        modelName = "CLOUD_MODEL_NAME",
        onDeviceConfig = OnDeviceConfig(mode = InferenceMode.ONLY_IN_CLOUD)
    )

val prompt = """
    The film aims to educate and inform viewers about real-life subjects, events, or people.
    It offers a factual record of a particular topic by combining interviews, historical footage,
    and narration. The primary purpose of a film is to present information and provide insights
    into various aspects of reality.
    """

// Call generateObject() with the enum schema and prompt.
val response = model.generateObject(enumSchema, prompt)

// Access the selected enum value string from response.response.text.
println(response.response.text)


רוצה לתת משוב על חוויית השימוש ב-Firebase AI Logic?