📝

ZodでGeminiのStructured Outputsに対応する際の注意点

に公開

結論

Zod v4からはJSON Schemaがサポートされているので、zod-to-json-schemaは使わずに、z.toJSONSchema()を使いましょう。

経緯

Gemini APIを利用する際に、Structured Outputsを利用したい場合、公式ドキュメントのサンプルコードを参照すると、以下のようにzod-to-json-schemaというライブラリを使うようになっています。

import { GoogleGenAI } from "@google/genai";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";

// 省略

const response = await ai.models.generateContent({
  model: "gemini-2.5-flash",
  contents: prompt,
  config: {
    responseMimeType: "application/json",
    responseJsonSchema: zodToJsonSchema(recipeSchema),
  },
});

// 省略

しかし、実際に実行すると、以下のようなZodのエラーが発生します。

ZodError: [
  {
    "expected": "string",
    "code": "invalid_type",
    "path": [
      "recipe_name"
    ],
    "message": "Invalid input: expected string, received undefined"
  },
  {
    "expected": "object",
    "code": "invalid_type",
    "path": [
      "ingredients",
      0
    ],
    "message": "Invalid input: expected object, received string"
  },
  {
    "expected": "object",
    "code": "invalid_type",
    "path": [
      "ingredients",
      1
    ],
    "message": "Invalid input: expected object, received string"
  },
  {
    "expected": "object",
    "code": "invalid_type",
    "path": [
      "ingredients",
      2
    ],
    "message": "Invalid input: expected object, received string"
  },
  {
    "expected": "object",
    "code": "invalid_type",
    "path": [
      "ingredients",
      3
    ],
    "message": "Invalid input: expected object, received string"
  },
  {
    "expected": "object",
    "code": "invalid_type",
    "path": [
      "ingredients",
      4
    ],
    "message": "Invalid input: expected object, received string"
  },
  {
    "expected": "object",
    "code": "invalid_type",
    "path": [
      "ingredients",
      5
    ],
    "message": "Invalid input: expected object, received string"
  },
  {
    "expected": "object",
    "code": "invalid_type",
    "path": [
      "ingredients",
      6
    ],
    "message": "Invalid input: expected object, received string"
  },
  {
    "expected": "object",
    "code": "invalid_type",
    "path": [
      "ingredients",
      7
    ],
    "message": "Invalid input: expected object, received string"
  },
  {
    "expected": "object",
    "code": "invalid_type",
    "path": [
      "ingredients",
      8
    ],
    "message": "Invalid input: expected object, received string"
  }
]

解決策

zod-to-json-schemaREADMEをみると

Zod v4 natively supports generating JSON schemas

とあるので、Zod v4がJSON schemaをサポートしていることがわかります。

実際、Zod公式ドキュメントをみると

To convert a Zod schema to JSON Schema, use the z.toJSONSchema() function.

とあるので、これを使うようにすると、エラーが発生せずに結果が表示されます。

修正したサンプルコード

import { GoogleGenAI } from "@google/genai";
import { z } from "zod";

const ingredientSchema = z.object({
  name: z.string().describe("Name of the ingredient."),
  quantity: z.string().describe("Quantity of the ingredient, including units."),
});

const recipeSchema = z.object({
  recipe_name: z.string().describe("The name of the recipe."),
  prep_time_minutes: z.number().optional().describe("Optional time in minutes to prepare the recipe."),
  ingredients: z.array(ingredientSchema),
  instructions: z.array(z.string()),
});

const apiKey = "your-gemini-api-key";
const ai = new GoogleGenAI({ apiKey });

const prompt = `
Please extract the recipe from the following text.
The user wants to make delicious chocolate chip cookies.
They need 2 and 1/4 cups of all-purpose flour, 1 teaspoon of baking soda,
1 teaspoon of salt, 1 cup of unsalted butter (softened), 3/4 cup of granulated sugar,
3/4 cup of packed brown sugar, 1 teaspoon of vanilla extract, and 2 large eggs.
For the best part, they'll need 2 cups of semisweet chocolate chips.
First, preheat the oven to 375°F (190°C). Then, in a small bowl, whisk together the flour,
baking soda, and salt. In a large bowl, cream together the butter, granulated sugar, and brown sugar
until light and fluffy. Beat in the vanilla and eggs, one at a time. Gradually beat in the dry
ingredients until just combined. Finally, stir in the chocolate chips. Drop by rounded tablespoons
onto ungreased baking sheets and bake for 9 to 11 minutes.
`;

const response = await ai.models.generateContent({
  model: "gemini-2.5-flash",
  contents: prompt,
  config: {
    responseMimeType: "application/json",
    responseJsonSchema: z.toJSONSchema(recipeSchema),
  },
});

const recipe = recipeSchema.parse(JSON.parse(response.text));
console.log(recipe);

実行結果

{
  recipe_name: 'Chocolate Chip Cookies',
  ingredients: [
    { name: 'all-purpose flour', quantity: '2 and 1/4 cups' },
    { name: 'baking soda', quantity: '1 teaspoon' },
    { name: 'salt', quantity: '1 teaspoon' },
    { name: 'unsalted butter (softened)', quantity: '1 cup' },
    { name: 'granulated sugar', quantity: '3/4 cup' },
    { name: 'packed brown sugar', quantity: '3/4 cup' },
    { name: 'vanilla extract', quantity: '1 teaspoon' },
    { name: 'large eggs', quantity: '2' },
    { name: 'semisweet chocolate chips', quantity: '2 cups' }
  ],
  instructions: [
    'Preheat the oven to 375°F (190°C).',
    'In a small bowl, whisk together the flour, baking soda, and salt.',
    'In a large bowl, cream together the butter, granulated sugar, and brown sugar until light and fluffy.',
    'Beat in the vanilla and eggs, one at a time.',
    'Gradually beat in the dry ingredients until just combined.',
    'Finally, stir in the chocolate chips.',
    'Drop by rounded tablespoons onto ungreased baking sheets and bake for 9 to 11 minutes.'
  ]
}

Discussion