はじめに
メダリスト「一番上手になりたい」、泣いた😭 nikkieです。
OpenAIのGPTではおなじみのJSON形式出力1。
「Geminiでどうやるんだろう」と手を動かしました。
今回はGoogle AI篇です(Vertex AIは登場しません)2
目次
ドキュメントより
ライブラリによって方法が異なると理解しました。
google-generativeai
「JSONを生成」より、モデルにJSONスキーマを提供する方法は2つ
- プロンプトのテキストを渡す
- TypedDictで表した型を渡す
- Kaggle講座で話題になっているのを見かけた覚え https://www.kaggle.com/code/markishere/day-1-prompting#JSON-mode
どちらのアプローチも、Gemini 1.5 Flash と Gemini 1.5 Pro の両方で機能します。
cookbookより
google-genai
https://googleapis.github.io/python-genai/#json-response-schema
Gemini 2.0 Flashに渡しているのは、PydanticのBaseModelを継承したモデルです。
またJSONスキーマの辞書を手で書いてもよさそうでした
動作確認スクリプト
Google AI Studioで払い出したAPIキーを、環境変数GOOGLE_API_KEYに指定しています。
- uv 0.5.17 (Homebrew 2025-01-10)
- スクリプトにinline script metadataを書き、
uv runで実行しています
- スクリプトにinline script metadataを書き、
- Python 3.12.5
- google-generativeai 0.8.3
- google-genai 0.5.0
google-generativeaiでプロンプト・Gemini 1.5
これ、ちょっと欲しい形と違いました。
マークダウンのコードブロックで返ってきています。
ほしいのはコードブロックの中身なんですよね。
プロンプト調整の余地がありそうです(正規表現で抜き出せないこともないかな)
※実際はバッククォートのみです(バックスラッシュはエスケープの意図です)
\`\`\`json
[
{
"recipe_name": "Chocolate Chip Cookies",
"ingredients": [
"1 cup (2 sticks) unsalted butter, softened",
"1 cup granulated sugar",
"1 cup packed brown sugar",
"2 teaspoons pure vanilla extract",
"2 large eggs",
"3 cups all-purpose flour",
"1 teaspoon baking soda",
"1 teaspoon salt",
"2 cups chocolate chips"
]
},
# 省略
{
"recipe_name": "Snickerdoodles",
"ingredients": [
"1 cup (2 sticks) unsalted butter, softened",
"1 3/4 cups granulated sugar",
"2 large eggs",
"2 teaspoons cream of tartar",
"1 teaspoon vanilla extract",
"3 cups all-purpose flour",
"2 teaspoons ground cinnamon",
"1/4 teaspoon salt",
"Coarse granulated sugar for rolling"
]
}
]
\`\`\`
google-generativeaiでTypedDict・Gemini 1.5
JSONで得られました!
[ { "ingredients": [ "1 cup (2 sticks) unsalted butter, softened", "1 1/2 cups granulated sugar", "1 cup packed brown sugar", "2 large eggs", "2 teaspoons vanilla extract", "3 cups all-purpose flour", "1 teaspoon baking soda", "1 teaspoon salt", "1 cup chocolate chips" ], "recipe_name": "Chocolate Chip Cookies" }, // 省略 { "ingredients": [ "1/2 cup (1 stick) unsalted butter, softened", "1/2 cup shortening", "1 cup granulated sugar", "1/2 cup packed brown sugar", "1 large egg", "1 teaspoon vanilla extract", "2 1/4 cups all-purpose flour", "1 teaspoon baking soda", "1/2 teaspoon salt", "1/2 cup oatmeal" ], "recipe_name": "Oatmeal Cookies" } ]
google-genaiでPydanticのBaseModel・Gemini 2.0
JSONで得られました!
ただし複数のレシピの例はPydanticのValidationError3が解決できず、ドキュメントの例を使いました。
{ "capital": "Washington, D.C.", "continent": "North America", "gdp": 25460000000000, "name": "United States", "official_language": "English", "population": 331000000, "total_area_sq_mi": 3797000 }
終わりに
Google AIのGemini APIでJSON出力を得るには以下の方法があります。
- google-generativeaiでTypedDictを渡す(Gemini 1.5)
- プロンプトエンジニアリングでもいけるかもしれません(ドキュメント記載が再現しなかったので、私はTypedDictにしたいと思いました)
- google-genaiでPydanticのBaseModelを継承したモデルを渡す(Gemini 2.0)
もしかするとgoogle-generativeaiからGemini 2.0や、google-genaiからGemini 1.5も叩けるかもしれませんが、今回の検証はここまでとします(方法が1つは見つかったということで)
Vertex AIについては別で書こうと考えていますが、なんと異なる方法なんですよ...
- https://platform.openai.com/docs/guides/structured-outputs/json-mode↩
- Gemini APIはGoogle AIとVertex AIの双方から利用できます ↩
-
list[Recipe]を持たせたRecipesクラスを導入したのですが、 https://errors.pydantic.dev/2.10/v/extra_forbidden が案内されます。Issueを見たところlistが未サポートで対応中とのこと ref: https://github.com/googleapis/python-genai/issues/60#issuecomment-2577440301↩