🎮

Controlled Generation を使って、Gemini からの出力をコントロールしてみよう

2024/12/23に公開

tl;dr

  • Controlled Generationは、生成 AI モデルの出力が常に特定のスキーマに準拠するよう保証する機能
  • 後続の処理が特定の形式(JSON型)を前提としている場合に利用できる(ex: 既存のシステムの一部置き換え)
  • 文字列や数値などの基本的な型から、enum(特定の文字列)型など柔軟に対応
  • 説明が不要でどのように動かすのかを見たい方はこちら

はじめに

みなさん、こんにちは。Google Cloud パートナーエンジニアの Sho です。

この記事は Google Cloud Japan Advent Calendar 2024 Gemini 編の 12/23 の記事です。本記事では、Google が提供する生成 AI モデルである Gemini をより活用いただく機能として、Controlled Generation を紹介させていただきます。
※ 本ブログに掲載されている画像は、基本的にimageFX で生成したものを利用しています。

Gemini とは

Gemini は Google が提供する生成 AI モデル(基盤モデル、大規模言語モデルなど様々な呼び方がありますが、本記事では生成 AI モデルに統一します)です。品質の高い Pro、コストパフォーマンスに優れる Flash、そしてオンデバイス向けの Nano のラインナップを持ちます。
最大 100 万トークンのロングコンテキスト(長い入力)を扱えるほか、マルチモーダルモデルである(入力にテキストデータに加えて画像や音声、動画データを扱える)ことが特徴です。
動画を扱う例

[シナリオ] EC サイトの商品マスタ登録

例えば以下のような EC サイトの構成があったとします。本システムには商品マスタの登録機能があり、管理者は Cloud Run の Admin サーバーが提供する UIに、画像データ、及び画像データに紐づく商品情報(メタデータ)を登録します。
ECサイトアーキテクチャ
商品登録の流れ

1. Gemini API(Vertex AI) を利用した効率化

登録作業は担当者が目視で行っており、入力者には負荷がかかっていているとのことです。この登録作業を効率化することを考えてみましょう。
例えば、メタデータの抽出に生成 AI モデルを利用することを考えてみます。以下の様なフローになりました。
Vertex AI を追加した例
Gemini API(Vertex AI) を利用して、商品登録を効率化

画像をアップロードするだけであれば作業者のコストが大幅に低下しますし、画像のアップロードを一括で行えるようになれば、更に効率化が見込めそうです。

2. Gemini で画像情報を読み取る

以下の資料があったとして、メタ情報を抽出してデータベースに保存することを考えてみます。
プロンプト画像

上記の画像に加えて適切なプロンプト文字列を与えることで、メタデータを構造化されたデータ(例えば JSON 形式)として取得ができれば、後続の処理でスムーズにデータベースに格納する事ができそうです。早速試してみましょう。

プロンプトは、まず以下を利用してみます。

以下の商品の情報を JSON 形式で表現してください。
商品名、レビュー点数、レビュー件数、在庫の有り無し、価格、カテゴリー、及び説明文を抽出してください。

Google AI Studio を使って、上記のプロンプトを Gemini 1.5 Flash で出力した例を示します。

{
  "product": {
    "name": "Modern cutting-edge Sugoi Mobile Battery: 9000mAh",
    "review_score": 4.0,
    "review_count": 465,
    "in_stock": true,
    "price": 49.99,
    "category": "Mobile, battery for Mobile, Handy",
    "description": [
      "9000 mAh high-capacity mobile battery",
      "Supports fast charging",
      "Supports multiple types (Type-C, Type-A)",
      "Thin, lightweight, and easy to carry"
    ]
  }
}

それらしい結果が帰ってきました。画像から必要な情報が切り出せていることがわかります。
では、もう一度実行してみましょう。今度は以下のように出力されました。

{
  "product_details": {
    "product_name": "Modern cutting-edge Sugoi Mobile Battery: 9000mAh",
    "rating": 4.0,
    "number_of_reviews": 465,
    "availability": "In stock",
    "price": 49.99,
    "category": "Mobile, battery for Mobile, Handy",
    "description": [
      "9000 mAh high-capacity mobile battery",
      "Supports fast charging",
      "Supports multiple types (Type-C, Type-A)",
      "Thin, lightweight, and easy to carry"
    ]
  }
}

こちらもそれらしい結果になりました。が、結果が微妙に異なっていることがわかります。

  • 変数名が異なる(review_score or rating
  • 在庫の有り無し、の表現方法が異なる(In stock なのか、Bool 値なのか)

3. 読み取った結果をシステムに組み込むために

Gemini は生成 AI モデルのため、出力結果は確率的になります(毎回出力が変わる可能性がある)。
そのため、意図した形式のデータが返される場合は良いのですが、意図しない形式のデータが来てしまうと、エラーが発生する場合があります。

エラーが発生する例
意図しない形式のデータを受け取ってしまった例

よりきめ細やかなプロンプトを指定(プロンプトエンジニアリング)を行うことで本リスクを軽減することが可能です。例えばデータベースに格納したい形式が決まっていたり、カラム名を決めておいたりしたい場合、以下のようなプロンプトを指定することで、出力をコントロールできます。

以下の商品の情報を JSON 形式で表現してください。
商品名(product_name)、
レビュー点数(review_score)、
レビュー件数(review_count)、
在庫の有り無し(availability)、
価格(price)、
通貨単位(currency_type)、
カテゴリー(category)、
及び説明文(description)を抽出してください。

カテゴリーは複数あるため、配列形式で出力してください。
説明文は配列ではなく、文字列型で連結して表現してください。
レビュー点数は、小数点第一位まで存在します。

結果は、以下のようになりました。

{
  "product_name": "Modern cutting-edge Sugoi Mobile Battery: 9000mAh",
  "review_score": 4.0,
  "review_count": 465,
  "availability": true,
  "price": 49.99,
  "currency_type": "USD",
  "category": [
    "Mobile",
    "battery for Mobile",
    "Handy"
  ],
  "description": "9000 mAh high-capacity mobile battery. Supports fast charging. Supports multiple types (Type-C, Type-A). Thin, lightweight, and easy to carry."
}

プロンプトの改善で、出力をコントロールできました。一件落着ですね!


Case closed, sherlock holmes, hat

…しかし、ちょっと待ってください。
例えば以下のような要望が出てきた場合はどうでしょう。

  • カラムを追加したい
  • 通貨のタイプは USD, JPY のいずれかにしたい

要望に対し、都度プロンプトを修正していくことでも対応は可能ですが、プロンプトは自然言語で表現されるため、担当者によって品質のムラが出るかもしれません。そのため、プログラムコードを変更するよりもコストがかかる可能性があります。
また、モデルからの出力は確率的であるため、毎回同じ出力が来ることが保証されず、想定と異なる結果が出力されるリスクは残ります。

これらの問題を解決してくれるのが、今回ご紹介する Controlled Generation 機能になります。

Controlled Generation

生成 AI モデルの出力は確率的でありながらも、出力形式を固定することでシステム側のエラー(データのパースエラー)を防ぐことができます。本機能はControlled Generation と呼ばれています。
本機能を利用することで、データの出力形式を制御することができます。直訳すると 制御された生成 になります。

記事執筆時点(2024/12/13)では、以下形式に対応しています。

  • application/json: JSON レスポンス。
  • text/plain : プレーン テキスト出力。
  • text/x.enum : スキーマで定義されている列データのうち、いずれかを返す(分類タスクの場合に利用)

また、対応モデルは以下の 2 つになります。

  • Gemini 1.5 Pro
  • Gemini 1.5 Flash

早速試してみる

それでは、早速試してみましょう。
Google Cloud のコンソールから Vertex AI を検索し、自由形式を開きます。
本エディタは Vertex AI Studio というサービスです。
※ 生成 AI モデルは gemini-1.5-flash-002 を利用します。

自由形式
Vertex AI Studioの画面

続けて、以下のサンプル画像をダウンロードし、上記のフォームにドラッグ & ドロップします。


サンプル画像
サンプル画像


プロンプトは以下を利用します。こちらもコピー & ペーストで貼り付けます。

以下の商品の情報を JSON 形式で表現してください。
商品名(product_name)、レビュー点数(review_score)、レビュー件数(review_count)、在庫の有り無し(availability)、
価格(price)、通貨単位(currency_type)、カテゴリー(category)、及び説明文(description)を抽出してください。

カテゴリーは複数あるため、配列形式で出力してください。
説明文は配列ではなく、文字列型で連結して表現してください。
レビュー点数は、小数点第一位まで存在します。

画像の添付、及びプロンプトの設定が完了(以下画面)したら、実行してみましょう。

実行結果例は以下になりました(出力結果は確率的なため、異なる結果が出力される可能性があります)。

Controlled Generation 機能を利用した結果

今度は、Controlled Generation 機能を利用して、出力形式を制御してみましょう。以下の JSON データをコピーします。以下の JSON データは、以下表を JSON データとして表現したものになります。

カラム名 意味
product_name 製品名 string
review_score レビュースコア number
review_count レビュー件数 integer
availability 在庫の有り無し boolean
price 価格 number
currency_type 通貨 string (USD or JPY)
category 商品カテゴリ string[]
description 商品概要 string
{
  "type": "object",
  "properties": {
    "product_name": {
      "type": "string"
    },
    "review_score": {
      "type": "number"
    },
    "review_count": {
      "type": "integer"
    },
    "availability": {
      "type": "boolean"
    },
    "price": {
      "type": "number"
    },
    "currency_type": {
      "type": "string",
      "enum": [
        "JPY",
        "USD"
      ]
    },
    "category": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "description": {
      "type": "string"
    }
  }
}

以下のスクリーンショットを参考に、Vertex AI Studio の画面のカスタマイズから出力形式を選択します。

書式なしテキスト から JSON に変更します。

その後、すぐ横の Edit リンクをクリックすると、カスタマイズウィンドウが開き、テキストエリアが表示されます。テキストエリアに上記でコピーした JSON データを貼り付けて、ウィンドウ下部の Apply を押してウィンドウを閉じます。エラーが表示された場合は、JSONデータに不要なデータが含まれている可能性があるため、ペーストしたデータをご確認ください。

...

結果は以下のようになりました。
※ 出力を jq コマンドで整形した結果を示しています。

{
  "availability": true,
  "category": [
    "Mobile",
    "battery for Mobile",
    "Handy"
  ],
  "currency_type": "USD",
  "description": "9000 mAh high-capacity mobile batterySupports fast chargingSupports multiple types (Type-C, Type-A)Thin, lightweight, and easy to carry",
  "price": 49.99,
  "product_name": "Modern cutting-edge Sugoi Mobile Battery: 9000mAh",
  "review_count": 465,
  "review_score": 4.0
}

何度か実行した場合でも、カラム名が変わらず、同様の出力が出ることを確認してみてください。
Temperature (温度) を変更しても、出力の結果が揺らがないことも確認してみましょう。

このように、生成 AI モデルの出力を制御することで、システムに組み込みやすくなりました。
また、スキーマを自然言語ではなく JSON データとして管理できる点もポイントです。
一方で、JSON データは人間が読みにくいという問題もあります。XML 形式や csv データ(スプレッドシート等)で管理し、実際に利用する JSON データに変換するような処理を組み込むことで、可読性を担保することもできるでしょう。


同じデータ形式が保証されることで、システムに組み込むことができた

おわりに

本記事では、Controlled Generation を利用して生成 AI モデルの出力形式をコントロールする方法をご紹介しました。2024 年は生成 AI を「試す」時代から「活用」する時代に変わってきていることを実感する年になったのではないかと感じておりますが、その活用の第一歩として、生成 AI モデルの出力を制御する機能は比較的イメージしやすいかと思いますので、ぜひお試しください!

Google Cloud Japan

Discussion