إخراج منظَّم

يمكنك ضبط Gemini لعرض مخرجات منظَّمة بدلاً من النص غير المنظَّم، ما سمح باستخراج المعلومات وتوحيدها بدقة لإجراء المزيد من المعالجة. على سبيل المثال، يمكنك استخدام الإخراج المنظَّم لاستخراج المعلومات من السير الذاتية، ثم توحيدها لإنشاء قاعدة بيانات منظَّمة.

يمكن أن ينشئ Gemini إما JSON أو قيمًا للترميز كإخراج منظَّم.

إنشاء ملف 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. للحصول على ردّ أكثر تحديدًا وذات جودة أعلى، عليك ضبط مخطّط في النموذج، وعدم تكرار المخطّط في الطلب النصي.

إنشاء قيم التعداد

في بعض الحالات، قد تحتاج إلى أن يختار النموذج خيارًا واحدًا من قائمة الخيارات. لتنفيذ هذا السلوك، يمكنك تمرير قائمة أرقام مميزة في مخطّطك. يمكنك استخدام خيار التعداد في أي مكان يمكنك فيه استخدام string في responseSchema، لأنّ التعداد هو مصفوفة من السلاسل. مثل مخطّط JSON، يتيح لك الجدول الدوار تقييد ناتج النموذج لتلبية متطلبات تطبيقك.

على سبيل المثال، لنفترض أنّك تُطوّر تطبيقًا لتصنيف الآلات الموسيقية إلى إحدى الفئات الخمس التالية: "Percussion" أو "String" أو "Woodwind" أو "Brass" أو ""Keyboard"". يمكنك إنشاء مصنّف للمساعدة في تنفيذ هذه المهمة.

في المثال التالي، يتم تمرير مصنّف على أنّه responseSchema، ما يفرض على النموذج اختيار الخيار الأنسب.

Python
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

ستترجم مكتبة Python بيانات أنواع واجهة برمجة التطبيقات. ومع ذلك، پذیرِع واجهة برمجة التطبيقات مجموعة فرعية من مخطّط OpenAPI 3.0 (المخطّط).

هناك طريقتان أخريان لتحديد قائمة. يمكنك استخدام Literal:

Python
Literal["Percussion", "String", "Woodwind", "Brass", "Keyboard"]

ويمكنك أيضًا تمرير المخطّط بتنسيق JSON:

Python
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

بالإضافة إلى المشاكل الأساسية التي تتضمّن خيارات متعدّدة، يمكنك استخدام قائمة بقيم ثابتة في أيّ مكان في ملف JSON schema. على سبيل المثال، يمكنك أن تطلب من النموذج قائمة بعناوين الوصفات واستخدام قائمة Grade لتصنيف كل عنوان حسب مدى رواجه:

Python
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"
  },
  ...
]

لمحة عن مخطّطات JSON

تعتمد عملية ضبط النموذج لإخراج JSON باستخدام المَعلمة responseSchema على عنصر Schema لتحديد بنيته. يمثّل هذا العنصر مجموعة ملفتة فرعية من عنصر مخطّط OpenAPI 3.0، ويضيف أيضًا حقل 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"]
}

للحصول على مستندات كاملة لحقول المخطط كما يتم استخدامها في واجهة برمجة التطبيقات Gemini API، يُرجى الاطّلاع على مرجع المخطط.

ترتيب المواقع

عند العمل مع مخطّطات JSON في Gemini API، يكون ترتيب السمات مهمًا. يرتّب واجهة برمجة التطبيقات السمات تلقائيًا أبجديًا ولا تحفظ الترتيب الذي تمّ به تعريف السمات (على الرغم من أنّ حِزم تطوير برامج الذكاء الاصطناعي التوليدي من Google قد تحافظ على هذا الترتيب). إذا كنت تقدّم أمثلة للنموذج الذي تم إعداد مخطّط له، ولم يكن ترتيب السمات للأمثلة متّسقًا مع ترتيب السمات في المخطّط، قد يكون الناتج غير متّسق أو غير متوقّع.

لضمان ترتيب ثابت ومتوقّع للخصائص، يمكنك استخدام الحقل propertyOrdering[] الاختياري.

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

propertyOrdering[] – ليس حقلًا عاديًا في مواصفات OpenAPI – هو مصفوفة من السلاسل المستخدَمة لتحديد ترتيب السمات في الاستجابة. من خلال تحديد ترتيب المواقع، ثم تقديم أمثلة باستخدام المواقع بالترتيب نفسه، يمكنك تحسين جودة النتائج. لا يمكن استخدام propertyOrdering إلا عند إنشاء types.Schema يدويًا.

المخططات في Python

عند استخدام مكتبة Python، يجب أن تكون قيمة response_schema أحد القيم التالية:

  • نوع، كما تستخدمه في تعليق توضيحي للنوع (راجِع typing وحدة Python)
  • مثيل لمحاولة genai.types.Schema
  • dict المكافئ لـ genai.types.Schema

إنّ أسهل طريقة لتحديد مخطّط هي باستخدام نوع Pydantic (كما هو موضّح في المثال السابق):

Python
config={'response_mime_type': 'application/json',
        'response_schema': list[Recipe]}

عند استخدام نوع Pydantic، تنشئ مكتبة Python مخطّطًا بتنسيق JSON وترسله إلى واجهة برمجة التطبيقات. للحصول على أمثلة إضافية، يُرجى الاطّلاع على مستندات مكتبة Python.

تتيح مكتبة Python المخططات المحدّدة بالأنواع التالية (حيث AllowedType هو أي نوع مسموح به):

  • int
  • float
  • bool
  • str
  • list[AllowedType]
  • AllowedType|AllowedType|...
  • بالنسبة إلى الأنواع من النوع "مُهيَّكلة":
    • dict[str, AllowedType]. يُعلن هذا التعليق التوضيحي أنّ جميع قيم القاموس هي من النوع نفسه، ولكنّه لا يحدّد المفاتيح التي يجب تضمينها.
    • نماذج Pydantic التي يحدّدها المستخدم يتيح لك هذا الأسلوب تحديد أسماء المفاتيح وتحديد أنواع مختلفة لل القيم المرتبطة بكل مفتاح، بما في ذلك البنى المُدمجة.

أفضل الممارسات

يُرجى مراعاة النقاط التالية وأفضل الممارسات عند استخدام مخطّط استجابة:

  • يتم احتساب حجم مخطّط الاستجابة ضمن الحد الأقصى المسموح به لرمز العلامة المميّزة للعنصر.
  • تكون الحقول اختيارية تلقائيًا، ما يعني أنّه يمكن للنموذج تعبئة الحقول أو تخطّيها. يمكنك ضبط الحقول على النحو المطلوب لإجبار النموذج على تقديم قيمة. إذا لم يكن هناك سياق كافٍ في طلب الإدخال المرتبط، ينشئ النموذج ردودًا استنادًا إلى البيانات التي تم تدريبه عليها بشكل أساسي.
  • يمكن أن يؤدي المخطط المعقّد إلى حدوث خطأ InvalidArgument: 400. قد تنتج الصعوبة عن أسماء السمات الطويلة أو الحدود القصوى لطول المصفوفات الطويلة أو القوائم المحددة التي تحتوي على العديد من القيم أو الكائنات التي تحتوي على الكثير من السمات الاختيارية أو مزيج من هذه العوامل.

    إذا ظهر لك هذا الخطأ مع مخطّط صالح، عليك إجراء واحد أو أكثر من الخطوات التالية لحلّ الخطأ:

    • اختصر أسماء المواقع أو أسماء التعداد.
    • تسطيح المصفوفات المُدمَجة
    • قلِّل عدد السمات التي تتضمّن قيودًا، مثل الأرقام التي تتضمّن الحدّ الأدنى والحدّ الأقصى.
    • قلِّل عدد المواقع التي تتضمّن قيودًا معقّدة، مثل المواقع التي تتضمّن تنسيقات معقّدة مثل date-time.
    • قلِّل عدد السمات الاختيارية.
    • قلِّل عدد القيم الصالحة لقوائم القيم المحدّدة.
  • إذا لم تظهر لك النتائج المتوقّعة، أضِف المزيد من السياق إلى طلبات الإدخال أو راجِع مخطّط الردود. على سبيل المثال، راجِع ردّ النموذج بدون إخراج منظَّم لمعرفة كيفية ردّ النموذج. يمكنك بعد ذلك تعديل مخطّط الردود لكي يلائم بشكلٍ أفضل الناتج الذي يقدّمه النموذج.

الخطوات التالية

بعد أن تعرّفت على كيفية إنشاء مخرجات منظَّمة، ننصحك بمحاولة استخدام أدوات Gemini API: