خروجی ساختاریافته

به طور پیش‌فرض، Gemini متن بدون ساختار تولید می‌کند، اما می‌توانید مدل را محدود کنید تا با خروجی ساختاریافته پاسخ دهد - یا JSON یا مقداری از enum. این ویژگی خروجی ساختاریافته زمانی مفید است که شما نیاز به استخراج اطلاعات از داده های بدون ساختار داشته باشید و سپس آنها را برای مصرف توسط یک برنامه پردازش کنید. برای مثال، می‌توانید از این ویژگی برای استخراج اطلاعات استاندارد از رزومه‌ها و سپس ساختن پایگاه داده از اطلاعات استفاده کنید. یا می توانید مواد تشکیل دهنده را از دستور العمل ها استخراج کنید و پیوندی به یک وب سایت خواربار فروشی برای هر یک از مواد تشکیل دهید.

این راهنما به شما نشان می دهد که چگونه با استفاده از Gemini API خروجی ساخت یافته تولید کنید.

در حال تولید JSON

دو راه برای تولید JSON با استفاده از Gemini API وجود دارد:

  • یک طرح واره را روی مدل پیکربندی کنید
  • یک طرح واره در یک درخواست متنی ارائه دهید

پیکربندی یک طرح واره بر روی مدل، روش پیشنهادی برای تولید JSON است، زیرا مدل را محدود به خروجی JSON می‌کند.

پیکربندی یک طرحواره

برای محدود کردن مدل برای تولید JSON، یک responseSchema را پیکربندی کنید. سپس مدل به هر درخواستی با خروجی فرمت JSON پاسخ می دهد.

from google import genai
from pydantic import BaseModel

class Recipe(BaseModel):
    recipe_name: str
    ingredients: list[str]

client = genai.Client(api_key="GOOGLE_API_KEY")
response = client.models.generate_content(
    model="gemini-2.0-flash",
    contents="List a few popular cookie recipes, and include the amounts of ingredients.",
    config={
        "response_mime_type": "application/json",
        "response_schema": list[Recipe],
    },
)
# Use the response as a JSON string.
print(response.text)

# Use instantiated objects.
my_recipes: list[Recipe] = response.parsed
import { GoogleGenAI, Type } from "@google/genai";

const ai = new GoogleGenAI({ "GOOGLE_API_KEY" });

async function main() {
  const response = await ai.models.generateContent({
    model: "gemini-2.0-flash",
    contents:
      "List a few popular cookie recipes, and include the amounts of ingredients.",
    config: {
      responseMimeType: "application/json",
      responseSchema: {
        type: Type.ARRAY,
        items: {
          type: Type.OBJECT,
          properties: {
            recipeName: {
              type: Type.STRING,
            },
            ingredients: {
              type: Type.ARRAY,
              items: {
                type: Type.STRING,
              },
            },
          },
          propertyOrdering: ["recipeName", "ingredients"],
        },
      },
    },
  });

  console.log(response.text);
}

main();
package main

import (
    "context"
    "fmt"
    "log"

    "google.golang.org/genai"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, &genai.ClientConfig{
        APIKey:  "GOOGLE_API_KEY",
        Backend: genai.BackendGeminiAPI,
    })
    if err != nil {
        log.Fatal(err)
    }

    config := &genai.GenerateContentConfig{
        ResponseMIMEType: "application/json",
        ResponseSchema: &genai.Schema{
            Type: genai.TypeArray,
            Items: &genai.Schema{
                Type: genai.TypeObject,
                Properties: map[string]*genai.Schema{
                    "recipeName": {Type: genai.TypeString},
                    "ingredients": {
                        Type:  genai.TypeArray,
                        Items: &genai.Schema{Type: genai.TypeString},
                    },
                },
                PropertyOrdering: []string{"recipeName", "ingredients"},
            },
        },
    }

    result, err := client.Models.GenerateContent(
        ctx,
        "gemini-2.0-flash",
        genai.Text("List a few popular cookie recipes, and include the amounts of ingredients."),
        config,
    )
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(result.Text())
}
curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=$GOOGLE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
      "contents": [{
        "parts":[
          { "text": "List a few popular cookie recipes, and include the amounts of ingredients." }
        ]
      }],
      "generationConfig": {
        "responseMimeType": "application/json",
        "responseSchema": {
          "type": "ARRAY",
          "items": {
            "type": "OBJECT",
            "properties": {
              "recipeName": { "type": "STRING" },
              "ingredients": {
                "type": "ARRAY",
                "items": { "type": "STRING" }
              }
            },
            "propertyOrdering": ["recipeName", "ingredients"]
          }
        }
      }
}' 2> /dev/null | head

خروجی ممکن است به شکل زیر باشد:

[
  {
    "recipeName": "Chocolate Chip Cookies",
    "ingredients": [
      "1 cup (2 sticks) unsalted butter, softened",
      "3/4 cup granulated sugar",
      "3/4 cup packed brown sugar",
      "1 teaspoon vanilla extract",
      "2 large eggs",
      "2 1/4 cups all-purpose flour",
      "1 teaspoon baking soda",
      "1 teaspoon salt",
      "2 cups chocolate chips"
    ]
  },
  ...
]

ارائه طرحواره در یک اعلان متنی

به جای پیکربندی یک طرحواره، می توانید یک طرحواره را به عنوان زبان طبیعی یا شبه کد در یک اعلان متنی ارائه کنید. این روش توصیه نمی شود ، زیرا ممکن است خروجی با کیفیت پایین تری تولید کند، و به دلیل اینکه مدل محدود به پیروی از طرحواره نیست.

در اینجا یک مثال عمومی از طرحواره ارائه شده در یک اعلان متن است:

List a few popular cookie recipes, and include the amounts of ingredients.

Produce JSON matching this specification:

Recipe = { "recipeName": string, "ingredients": array<string> }
Return: array<Recipe>

از آنجایی که مدل طرح را از متن در اعلان دریافت می کند، ممکن است در نحوه نمایش طرحواره انعطاف پذیری داشته باشید. اما زمانی که شما یک طرحواره به صورت درون خطی مانند این ارائه می کنید، مدل در واقع محدود به بازگشت JSON نیست. برای پاسخ قطعی تر و با کیفیت بالاتر، یک طرح واره را روی مدل پیکربندی کنید، و طرح را در اعلان متن تکرار نکنید.

طرحواره های JSON

هنگامی که مدل را برای بازگرداندن پاسخ JSON پیکربندی می کنید، از یک شی Schema برای تعریف شکل داده های JSON استفاده می کنید. Schema یک زیرمجموعه انتخابی از شی OpenAPI 3.0 Schema را نشان می‌دهد و همچنین یک قسمت propertyOrdering اضافه می‌کند.

در اینجا یک نمایش شبه JSON از تمام فیلدهای Schema آمده است:

{
  "type": enum (Type),
  "format": string,
  "description": string,
  "nullable": boolean,
  "enum": [
    string
  ],
  "maxItems": integer,
  "minItems": integer,
  "properties": {
    string: {
      object (Schema)
    },
    ...
  },
  "required": [
    string
  ],
  "propertyOrdering": [
    string
  ],
  "items": {
    object (Schema)
  }
}

Type طرحواره باید یکی از انواع داده های OpenAPI یا ترکیبی از آن انواع باشد (با استفاده از anyOf ). فقط یک زیر مجموعه از فیلدها برای هر Type معتبر است. لیست زیر هر Type به زیر مجموعه ای از فیلدهایی که برای آن نوع معتبر هستند نگاشت می کند:

  • string -> enum , format , nullable
  • integer -> format , minimum , maximum , enum , nullable
  • number -> format ، minimum ، maximum ، enum ، nullable
  • boolean -> nullable
  • array -> minItems , maxItems , items , nullable
  • object -> properties , required , propertyOrdering , nullable

در اینجا چند نمونه طرحواره وجود دارد که ترکیبات نوع و فیلد معتبر را نشان می دهد:

{ "type": "string", "enum": ["a", "b", "c"] }

{ "type": "string", "format": "date-time" }

{ "type": "integer", "format": "int64" }

{ "type": "number", "format": "double" }

{ "type": "boolean" }

{ "type": "array", "minItems": 3, "maxItems": 3, "items": { "type": ... } }

{ "type": "object",
  "properties": {
    "a": { "type": ... },
    "b": { "type": ... },
    "c": { "type": ... }
  },
  "nullable": true,
  "required": ["c"],
  "propertyOrdering": ["c", "b", "a"]
}

برای مستندات کامل فیلدهای Schema همانطور که در Gemini API استفاده می شود، به مرجع Schema مراجعه کنید.

سفارش ملک

هنگامی که با طرحواره های JSON در Gemini API کار می کنید، ترتیب ویژگی ها مهم است. به‌طور پیش‌فرض، API ویژگی‌ها را بر اساس حروف الفبا مرتب می‌کند و ترتیب تعریف ویژگی‌ها را حفظ نمی‌کند (اگرچه Google Gen AI SDKs ممکن است این ترتیب را حفظ کند). اگر در حال ارائه مثال‌هایی برای مدل با طرح‌واره‌ای پیکربندی‌شده هستید، و ترتیب ویژگی‌های نمونه‌ها با ترتیب ویژگی‌های طرح سازگار نیست، خروجی می‌تواند نامشخص یا غیرمنتظره باشد.

برای اطمینان از یک ترتیب ثابت و قابل پیش‌بینی خواص، می‌توانید از فیلد اختیاری propertyOrdering[] استفاده کنید.

"propertyOrdering": ["recipeName", "ingredients"]

propertyOrdering[] - یک فیلد استاندارد در مشخصات OpenAPI نیست - آرایه ای از رشته ها است که برای تعیین ترتیب خواص در پاسخ استفاده می شود. با مشخص کردن ترتیب ویژگی ها و سپس ارائه مثال هایی با ویژگی ها به همان ترتیب، به طور بالقوه می توانید کیفیت نتایج را بهبود بخشید. propertyOrdering تنها زمانی پشتیبانی می شود که به صورت دستی types.Schema ایجاد کنید.

طرحواره ها در پایتون

این بخش راهنمایی های بیشتری در مورد کار با طرحواره های JSON با استفاده از کتابخانه Python ارائه می دهد.

هنگامی که از کتابخانه پایتون استفاده می کنید، مقدار response_schema باید یکی از موارد زیر باشد:

  • یک نوع، همانطور که در حاشیه نویسی نوع استفاده می کنید (به ماژول typing پایتون مراجعه کنید)
  • نمونه ای از genai.types.Schema
  • معادل dict genai.types.Schema

ساده ترین راه برای تعریف طرحواره با نوع Pydantic است (همانطور که در مثال قبلی نشان داده شده است):

پایتون
config={'response_mime_type': 'application/json',
        'response_schema': list[Recipe]}

هنگامی که از یک نوع Pydantic استفاده می کنید، کتابخانه Python یک طرح JSON برای شما می سازد و آن را به API ارسال می کند. برای مثال‌های بیشتر، به اسناد کتابخانه پایتون مراجعه کنید.

کتابخانه پایتون از طرحواره های تعریف شده با انواع زیر پشتیبانی می کند (که در آن AllowedType هر نوع مجاز باشد):

  • int
  • float
  • bool
  • str
  • list[AllowedType]
  • AllowedType|AllowedType|...
  • برای انواع ساختار یافته:
    • dict[str, AllowedType] . این حاشیه نویسی همه مقادیر dict را یک نوع اعلام می کند، اما مشخص نمی کند که چه کلیدهایی باید گنجانده شوند.
    • مدل های Pydantic تعریف شده توسط کاربر. این رویکرد به شما امکان می دهد نام کلیدها را مشخص کنید و انواع مختلفی را برای مقادیر مرتبط با هر یک از کلیدها از جمله ساختارهای تودرتو تعریف کنید.

ایجاد مقادیر enum

در برخی موارد ممکن است بخواهید مدل یک گزینه را از لیست گزینه ها انتخاب کند. برای پیاده سازی این رفتار، می توانید یک enum را در طرحواره خود ارسال کنید. می‌توانید در هر جایی که می‌توانید از یک string در responseSchema استفاده کنید، از گزینه enum استفاده کنید، زیرا enum آرایه‌ای از رشته‌ها است. مانند یک طرح JSON، یک enum به شما امکان می دهد خروجی مدل را برای برآورده کردن الزامات برنامه خود محدود کنید.

به عنوان مثال، فرض کنید که در حال توسعه برنامه‌ای برای طبقه‌بندی آلات موسیقی به یکی از پنج دسته هستید: "Percussion" ، "String" ، "Woodwind" ، "Brass" یا « "Keyboard" ». شما می توانید یک enum برای کمک به این کار ایجاد کنید.

در مثال زیر، یک enum را به عنوان responseSchema ارسال می‌کنید، که مدل را محدود می‌کند تا مناسب‌ترین گزینه را انتخاب کند.

پایتون
from google import genai
import enum

class Instrument(enum.Enum):
  PERCUSSION = "Percussion"
  STRING = "String"
  WOODWIND = "Woodwind"
  BRASS = "Brass"
  KEYBOARD = "Keyboard"

client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
    model='gemini-2.0-flash',
    contents='What type of instrument is an oboe?',
    config={
        'response_mime_type': 'text/x.enum',
        'response_schema': Instrument,
    },
)

print(response.text)
# Woodwind

کتابخانه پایتون اعلان‌های نوع API را ترجمه می‌کند. با این حال، API زیرمجموعه ای از طرحواره OpenAPI 3.0 ( Schema ) را می پذیرد.

دو راه دیگر برای تعیین یک شمارش وجود دارد. می توانید از Literal استفاده کنید:

پایتون
Literal["Percussion", "String", "Woodwind", "Brass", "Keyboard"]

و همچنین می توانید این طرح را به عنوان JSON ارسال کنید:

پایتون
from google import genai

client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
    model='gemini-2.0-flash',
    contents='What type of instrument is an oboe?',
    config={
        'response_mime_type': 'text/x.enum',
        'response_schema': {
            "type": "STRING",
            "enum": ["Percussion", "String", "Woodwind", "Brass", "Keyboard"],
        },
    },
)

print(response.text)
# Woodwind

فراتر از مشکلات اساسی چند گزینه ای، می توانید از enum در هر نقطه از طرح JSON استفاده کنید. به عنوان مثال، می‌توانید از مدل فهرستی از عناوین دستور غذا را بخواهید و از Grade enum برای دادن درجه محبوبیت به هر عنوان استفاده کنید:

پایتون
from google import genai

import enum
from pydantic import BaseModel

class Grade(enum.Enum):
    A_PLUS = "a+"
    A = "a"
    B = "b"
    C = "c"
    D = "d"
    F = "f"

class Recipe(BaseModel):
  recipe_name: str
  rating: Grade

client = genai.Client(api_key="GEMINI_API_KEY")
response = client.models.generate_content(
    model='gemini-2.0-flash',
    contents='List 10 home-baked cookie recipes and give them grades based on tastiness.',
    config={
        'response_mime_type': 'application/json',
        'response_schema': list[Recipe],
    },
)

print(response.text)

پاسخ ممکن است به این صورت باشد:

[
  {
    "recipe_name": "Chocolate Chip Cookies",
    "rating": "a+"
  },
  {
    "recipe_name": "Peanut Butter Cookies",
    "rating": "a"
  },
  {
    "recipe_name": "Oatmeal Raisin Cookies",
    "rating": "b"
  },
  ...
]

ملاحظات

هنگام استفاده از طرح پاسخ، ملاحظات و بهترین شیوه های زیر را در نظر داشته باشید:

  • اندازه طرح پاسخ شما در حد توکن ورودی به حساب می آید.
  • به طور پیش فرض، فیلدها اختیاری هستند، به این معنی که مدل می تواند فیلدها را پر کند یا آنها را رد کند. می‌توانید فیلدهایی را که لازم است تنظیم کنید تا مدل را مجبور به ارائه یک مقدار کنید. اگر زمینه کافی در اعلان ورودی مرتبط وجود نداشته باشد، مدل پاسخ‌هایی را عمدتاً بر اساس داده‌هایی که روی آن آموزش داده شده است تولید می‌کند.
  • یک طرح واره پیچیده می تواند منجر به خطای InvalidArgument: 400 شود. پیچیدگی ممکن است از نام های طولانی، محدودیت های طول آرایه طولانی، enum هایی با مقادیر زیاد، اشیاء با خواص اختیاری زیاد یا ترکیبی از این عوامل ناشی شود.

    اگر این خطا را با یک طرحواره معتبر دریافت کردید، یک یا چند مورد از تغییرات زیر را برای رفع خطا انجام دهید:

    • نام های دارایی یا نام های فهرست را کوتاه کنید.
    • آرایه های تو در تو را صاف کنید.
    • تعداد ویژگی های دارای محدودیت، مانند اعداد با محدودیت های حداقل و حداکثر را کاهش دهید.
    • تعداد ویژگی‌های دارای محدودیت‌های پیچیده، مانند خواص با قالب‌های پیچیده مانند date-time را کاهش دهید.
    • تعداد خواص اختیاری را کاهش دهید.
    • تعداد مقادیر معتبر برای enums را کاهش دهید.
  • اگر نتایج مورد انتظارتان را نمی‌بینید، زمینه بیشتری را به درخواست‌های ورودی خود اضافه کنید یا طرح پاسخ خود را اصلاح کنید. برای مثال، پاسخ مدل را بدون خروجی ساختاریافته مرور کنید تا ببینید مدل چگونه پاسخ می دهد. سپس می توانید طرح پاسخ خود را به روز کنید تا بهتر با خروجی مدل مطابقت داشته باشد.

بعدش چی

اکنون که نحوه تولید خروجی ساختاریافته را یاد گرفتید، ممکن است بخواهید از ابزار Gemini API استفاده کنید: