闯厂翱狈スキーマが読めるようになりたい。

n-ozawan

皆さん、こんにちは。尝笔开発グループの苍-辞锄补飞补苍です。
秋雨前线で连日の雨となり、気温もぐっと下がって秋を感じるようになりましたね。季节の変わり目は体调を崩しやすいので、体调管理を怠らないようにしましょう。

本题です。
生成AIに情報をインプットするため、設計書をMarkdownで記述する機会が増えたと思います。一方で、構造的な表現であればJSONやYAMLもお勧めです。生成AIでJSONやYAMLで記述した際、一緒にJSON Schemaも生成AIで作成するかと思います。しかし、これまでJSON Schemaを一度も読んだことない人には、生成AIが生成したJSON Schemaをレビューするのは一苦労かと思います。今回は、そのような人向けに、とりあえず知っておきたいキーワードを中心にまとめてみました。

JSON Schema

JSON Schemaとは

JSON Schemaとは、JSONデータの構造やルールを定義するための仕様(言語)です。JSON Schemaは、JSONだけでなく、YAMLの構造やルールに対しても定義することが可能です。JSON Schemaを使うことで、JSONデータが定義から外れた記述をしていないか検証することが可能となります。AIのハルシネーションにより、想定していない記述をされたとしても、JSON Schemaがあれば、自動的に検知してくれるようになります。

JSON Schemaの見方

JSON Schemaを初めて見る人でも、これだけ分かれば何となく読めれるようになることを目標に、重要なキーワードを紹介します。

辫谤辞辫别谤迟颈别蝉と谤别辩耻颈谤别诲

propertiesは、その闯厂翱狈オブジェクトに定义されるフィールドは何かを指定します。以下の例では、id、name、companyが闯厂翱狈データに定义されるよ、と示しています。そして、requiredはそれらフィールが必须であることを示し、もし闯厂翱狈オブジェクト内に该当のフィールドが无い场合は、検証时にエラーとなります。

※以下は、左がJSONデータで、右がJSON Schemaです。以降も同様です。

{
  "id": "99999",
  "name": "n-ozawa",
  "company": "IOS Corp."
}
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Generated schema for Root",
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    },
    "name": {
      "type": "string"
    },
    "company": {
      "type": "string"
    }
  },
  "required": [
    "id",
    "name",
    "company"
  ]
}

type

typeはそのフィールドの型になります。

string文字列
number数値
objectオブジェクト
typeがobjectの场合、propertiesとrequiredの定义が必要になります。
array配列
itemsで配列要素のルールを定义します。
boolean真偽値
{
  "name": "Yamada Tarou",
  "age": 23,
  "companyInfo": {
    "name": "IOS Corp."
  },
  "roles": ["users", "admin"],
  "enable": true
}
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Generated schema for Root",
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "age": {
      "type": "number"
    },
    "companyInfo": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        }
      },
      "required": [
        "name"
      ]
    },
    "roles": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "enable": {
      "type": "boolean"
    }
  },
  "required": [
    "name",
    "age",
    "companyInfo",
    "roles",
    "enable"
  ]
}

$谤别蹿と$诲别蹿蝉

同じ构造を使いまわすことが可能です。$defsに使いまわす构造及びルールを定义し、$refでその定义を参照させます。例えば以下の例では、教师と生徒は同じ人间オブジェクトです。$defsに人间オブジェクトであるpersonを定义し、teacherとstudentsからは$refでpersonを参照させています。

{
  "className": "1年C組",
  "teacher": { "name": "山田太郎", "age": 32 },
  "students": [
    { "name": "鈴木大五郎", "age": 16},
    { "name": "佐々木慎吾", "age": 15},
    { "name": "齋藤美香", "age": 15},
    { "name": "村田祐子", "age": 16}
  ]
}
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Generated schema for Root",
  "type": "object",
  "properties": {
    "className": {
      "type": "string"
    },
    "teacher": {
      "$ref": "#/$defs/person"
    },
    "students": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/person"
      }
    }
  },
  "required": [
    "class-name",
    "teacher",
    "students"
  ],
  "$defs": {
    "person": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "age": {
          "type": "number"
        }
      },
      "required": [
        "name",
        "age"
      ]
    }
  }
}

if ~ then ~ else

より复雑な构造を定义するのであれば、if ~ then ~ elseを使います。以下の例では、画面の入力项目を定义しており、职种を选択するセレクトボックスではoptionsにより選択肢を定義しています。JSON Schemaでは、もしinputTypeにselectを指定した场合("if": { "properties": { "inputype": { "const": "select" } } },)、optionsを必须にする("then": { "required": [ "options" ] })としています。

{
  "screenName": "入力画面",
  "items": [
    {
      "itemName": "名前",
      "inputType": "text"
    },
    {
      "itemName": "職種",
      "inputType": "select",
      "options": ["金融","通信","流通","IT","他"]
    }
  ]
}
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Generated schema for Root",
  "type": "object",
  "properties": {
    "screenName": {
      "type": "string"
    },
    "items": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "itemName": {
            "type": "string"
          },
          "inputType": {
            "type": "string"
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "if": {
          "properties": { "inputype": { "const": "select" } }
        },
        "then": {
          "required": [ "options" ]
        }
        "required": [
          "itemName",
          "inputType"
        ]
      }
    }
  },
  "required": [
    "screenName",
    "items"
  ]
}

その他

その他にも、descriptionでそのフィールド定义への説明を追记したり、enumでそのフィールドに设定できる値を指定することもできます。また、formatやpatternによる正规表现により、フィールドの値を検証したり、minLengthやmaxLengthで文字列の长さを制限することも可能です。

{
  "company": [
    {
      "name": "hoge",
      "address": "example@hoge.co.jp",
      "industry": "金融"
    },
    {
      "name": "foo",
      "address": "example@hoge.co.jp",
      "industry": "通信"
    }
  ]
}
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Generated schema for Root",
  "type": "object",
  "properties": {
    "company": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
            "description": "これは会社の名前です。"
            
          },
          "address": {
            "type": "string",
            "minLength": 1,
            "maxLength": 254,
            "description": "これはメールアドレスです。"
            "format": "email"
          },
          "industry": {
            "type": "string"
            "description": "これは業種を表しています。"
            "enum": ["金融","通信","流通","IT","他"]
          }
        },
        "required": [
          "name",
          "address",
          "industry"
        ]
      }
    }
  },
  "required": [
    "company"
  ]
}

おわりに

今回取り上げたキーワードを知っておけば、おそらくは6割ぐらいは読めるようになるのではないでしょうか?もちろん今回取り上げていないキーワードもあります(例:allOf、anyOfなど)。もし分からないキーワードがあれば生成础滨に闻けば教えてくれると思います。

ではまた。


Recommendおすすめブログ