Android アプリのハイブリッド エクスペリエンス向けに構造化出力を生成する


Gemini モデルは、デフォルトでレスポンスを非構造化テキストとして返します。ただし、一部のユースケースでは、構造化テキスト(JSON や列挙型など)が必要です。たとえば、確立されたデータ スキーマを必要とする他のダウンストリーム タスクにレスポンスを使用している場合があります。

モデルの生成済み出力が常に特定のスキーマに準拠するようにするには、モデルのレスポンスのブループリントのように機能するスキーマを定義します。これにより、後処理をあまり行わずにモデルの出力からデータを直接抽出できます。

次のような処理が例として挙げられます。

  • モデルのレスポンスが有効な JSON を生成し、指定したスキーマに準拠していることを確認します。
    たとえば、モデルはレシピ名、材料リスト、手順を常に含むレシピの構造化されたエントリを生成できます。これにより、アプリの UI でこの情報をより簡単に解析して表示できます。

  • 分類タスク中にモデルが応答する方法を制限します。
    たとえば、モデルが生成するラベル(goodpositivenegativebad など、ある程度のばらつきがある可能性がある)ではなく、特定のラベルセット(positivenegative などの特定の列挙型セットなど)でテキストにアノテーションを付けるようにモデルを設定できます。

このページでは、Android アプリのハイブリッド エクスペリエンスで構造化された出力(JSON や列挙型など)を生成する方法について説明します。

JSON 出力に移動 列挙型出力に移動

構造化出力の構成

構造化出力(JSON や列挙型など)の生成は、オンデバイス推論とクラウドホスト型推論の両方でサポートされています。

構造化出力を生成するには、スキーマを generateObject() に直接渡します。スキーマの要件は、構成された推論モードによって異なります。

  • オンデバイスとハイブリッド推論(ONLY_ON_DEVICEPREFER_ON_DEVICEPREFER_IN_CLOUD)の場合:

    • KSP プロセッサで Kotlin data class@Generable アノテーションを使用する必要があります。手動スキーマと直接 enum class アノテーションはサポートされていません。
    • 推論がデバイス上で実行される場合、SDK はスキーマをデバイス上のモデルの制約に自動的に変換します(ML Kit Prompt API を使用)。
    • ハイブリッド リクエストがクラウド推論にフォールバックすると、SDK は responseMimeTypeapplication/json に自動的に設定し、スキーマをクラウドホストの Gemini モデルに渡します。
  • クラウド専用の推論(ONLY_IN_CLOUD)の場合:

    • @Generable アノテーション(推奨)と手動スキーマ(JsonSchema ヘルパー メソッドを使用して構築)の両方をサポートします。
    • SDK は responseMimeTypeapplication/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 出力に移動 列挙型出力に移動

JSON 出力

次の例では、一般的な JSON 出力の例をハイブリッド推論(PREFER_ON_DEVICE など)に対応するように変更しています。

これらの例のシナリオでは、モデルはファンタジー ストーリーのキャラクター プロファイルのリストを生成します。これには、名前、年齢、種族、オプションのアクセサリーなどの構造化された属性が含まれます。

レスポンス スキーマは、次のいずれかの方法で定義できます。

  • KSP アノテーション(@Generable@Guide

    • すべての推論モードでサポートされ、オンデバイス推論とハイブリッド推論(具体的には ONLY_ON_DEVICEPREFER_ON_DEVICEPREFER_IN_CLOUD)で必須です。
    • Kotlin データクラスを定義して、コンパイル時にスキーマを自動的に生成し、getObject() を使用してレスポンスを厳密に型指定されたオブジェクトに直接逆シリアル化します。
  • 手動の JsonSchema ヘルパー メソッド

    • クラウドベースの推論(具体的には ONLY_IN_CLOUD)でのみサポートされます。
    • KSP プロセッサを使用せずにコードで JsonSchema を手動で構築し、response.response.text から未加工の JSON 文字列を読み取ります。

例 1: KSP で @Generable アノテーションと @Guide アノテーションを使用する

@Serializable@Generable でアノテーションが付けられた Kotlin の data class を定義します。プロパティに @Guide アノテーションを使用すると、モデルに説明、値の境界、アイテムの制約を指定できます。

このアプローチは、すべての推論モードでサポートされており、オンデバイス エクスペリエンスとハイブリッド エクスペリエンス(具体的には ONLY_ON_DEVICEPREFER_ON_DEVICEPREFER_IN_CLOUD)では必須です。

このサンプルを試す前に、このガイドの始める前にのセクションを完了して、プロジェクトとアプリを設定してください。
このセクションでは、選択した Gemini API プロバイダのボタンをクリックして、このページにプロバイダ固有のコンテンツが表示されるようにします。

Kotlin の場合、この SDK のメソッドは suspend 関数であり、コルーチンスコープから呼び出す必要があります。
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のみを使用している場合は、Firebase AI Logic SDK で提供されるヘルパー メソッドを使用して JsonSchema を手動でビルドできます。

このサンプルを試す前に、このガイドの始める前にのセクションを完了して、プロジェクトとアプリを設定してください。
このセクションでは、選択した Gemini API プロバイダのボタンをクリックして、このページにプロバイダ固有のコンテンツが表示されるようにします。

Kotlin の場合、この SDK のメソッドは suspend 関数であり、コルーチン スコープから呼び出す必要があります。
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)

列挙型の出力

次の例では、一般的な列挙型出力の例をハイブリッド推論(PREFER_ON_DEVICE など)に対応するように変更しています。

これらの例のシナリオでは、モデルは、許可されているオプション(dramacomedydocumentary)の事前定義されたリストから 1 つのジャンルを選択して、映画の説明を分類します。

レスポンス スキーマは、次のいずれかの方法で定義できます。

  • KSP アノテーション(@Generable

    • すべての推論モードでサポートされ、オンデバイス推論とハイブリッド推論(具体的には ONLY_ON_DEVICEPREFER_ON_DEVICEPREFER_IN_CLOUD)で必須です。
    • Kotlin の data class でラップされた列挙型を定義して、スキーマを自動的に生成し、getObject() を使用してレスポンスを厳密に型指定されたオブジェクトに直接逆シリアル化します。
  • 手動の JsonSchema ヘルパー メソッド

    • クラウドベースの推論(具体的には ONLY_IN_CLOUD)でのみサポートされます。
    • KSP プロセッサを使用せずに JsonSchema.enumeration() を使用して列挙型 JsonSchema を手動でビルドし、response.response.text から選択した文字列を読み取ります。

例 1: KSP で @Generable アノテーションを使用する

許容される値を表す enum class を定義し、@Serializable@Generable でアノテーションが付けられた Kotlin の data class 内のプロパティとしてラップします。

このアプローチは、すべての推論モードでサポートされており、オンデバイス エクスペリエンスとハイブリッド エクスペリエンス(具体的には ONLY_ON_DEVICEPREFER_ON_DEVICEPREFER_IN_CLOUD)では必須です。

このサンプルを試す前に、このガイドの始める前にのセクションを完了して、プロジェクトとアプリを設定してください。
このセクションでは、選択した Gemini API プロバイダのボタンをクリックして、このページにプロバイダ固有のコンテンツが表示されるようにします。

Kotlin の場合、この SDK のメソッドは suspend 関数であり、コルーチンスコープから呼び出す必要があります。
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)のみを使用している場合は、Firebase AI Logic SDK で提供されるヘルパー メソッドを使用して、列挙型 JsonSchema を手動でビルドできます。

このサンプルを試す前に、このガイドの始める前にのセクションを完了して、プロジェクトとアプリを設定してください。
このセクションでは、選択した Gemini API プロバイダのボタンをクリックして、このページにプロバイダ固有のコンテンツが表示されるようにします。

Kotlin の場合、この SDK のメソッドは suspend 関数であり、コルーチンスコープから呼び出す必要があります。
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 の使用感についてフィードバックを送信する