LLMのAPI SchemaではJSON Schemaがよく使用されている。例えばFunction CallingのAPI定義(バリデーション)は、JSON Schemaを使って送受信するデータを定義する。
JSONにはJSON Type Definition(JTD)というRFCで標準化された型定義ルールがあるが、あまり使われてない気がする。JSON Schemaの方が汎用性が高く、JTDでできなくてJSON Schemaではできることの方が多いので、今やJTDを使う理由がない。JTDの方がシンプルなので、バリデーションの実行時間が早い、くらい?
と思ってJTDの仕様を見ていたら、Tagged unionが表現できることを知る。例えば、描画オブジェクトの circle
と square
があったとして、バリデーションは以下のように書く。
{
"type": "object",
"properties": {
"shape": {
"discriminator": "type",
"mapping": {
"circle": {
"properties": {
"radius": { "type": "number" }
},
"required": ["radius"]
},
"square": {
"properties": {
"sideLength": { "type": "number" }
},
"required": ["sideLength"]
}
}
}
},
"required": ["shape"]
}
以下のようなJSONは受け付けられる。
{ "shape": { "type": "circle", "radius": 5 } }
{ "shape": { "type": "square", "sideLength": 10 } }
以下の値は、型としては合っていても、不正となる。
{ "shape": { "type": "equilateral_triangle", "length": 3 } }
Pythonだとjsontypedef/json-typedef-pythonでバリデーションができる。
import jtd
schema = {
"type": "object",
"properties": {
"shape": {
"discriminator": "type",
"mapping": {
"circle": {
"properties": {
"radius": {"type": "number"}
},
"required": ["radius"]
},
"square": {
"properties": {
"sideLength": {"type": "number"}
},
"required": ["sideLength"]
}
}
}
},
"required": ["shape"]
}
data = data = {"shape": {"type": "circle", "radius": 5}}
jtd.validate(schema, data) # return List[jtd.ValidationError]
全体をチェックするコードはGistに上げた。
JSON Schemaで同等のバリデーションをするのは、以下かな。Copilotは「同じ」と大小判を押していたが、自信はない。python-jsonschema/jsonschemaを使っている。
import jsonschema
schema = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"shape": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["circle", "square"]
}
},
"required": ["type"],
"oneOf": [
{
"properties": {
"type": {"const": "circle"},
"radius": {"type": "number"}
},
"required": ["type", "radius"],
"additionalProperties": False
},
{
"properties": {
"type": {"const": "square"},
"sideLength": {"type": "number"}
},
"required": ["type", "sideLength"],
"additionalProperties": False
}
]
}
},
"required": ["shape"],
"additionalProperties": False
}
data = data = {"shape": {"type": "circle", "radius": 5}}
## require to catch jsonschema.SchemaError and jsonschema.ValidationError
jsonschema.validate(data, schema)
同じく、全体をチェックするコードをGistに上げた。
JSON Schemaはjson-schema.orgで議論・公開されている。現在のバージョンは2020-12。