zodに入門ついでにOpenAIのStructured Outputを試す
OpenAIのレスポンスのformat指定にzodやPydanticが使えるらしい。雰囲気がわかるだけで、本業で導入ができているわけでもなく経験値が低い
tutorialを通した後、openaiのapiを触ってみる
TODO
- zodのtutorialをやる
- structured outputにzodのschemeを投げるのを試す
- streamingの時にstructured outputを指定しているとどうなるのか調べる
- streamの途中でvalidなjsonだったりするのかが気になる
const numParser = z.number();
const parsed = numParser.parse(num);
一番シンプル
これで型を満たしているかを判定してくれる。満たしていないときは例外を投げる
safeparse という関数だと結果がobjectで貰える。基本はこっちを使っている方が扱いやすそうだ
objectの場合、以下のように引数の中にobjectを入れ込む。valueにあたる部分がzの関数になるわけでだいぶわかりやすい感じ
z.object({
hoge: z.number()
})
z.arrayも引数にschemeを取る
stringの文字数など引数にvalidationのための設定がたくさんある。
これらは欲しくなったらdocumentを探す感じでいいかも。文字数長とかは型に落としづらい(型パズルすれば頑張れるらしいが...)ので、使うときは命名やコメントでカバーしたい
schemaから型を取るには
z.infer(typeof SomeSchema)
のようにinfer関数で取得できる。
unionもz.union関数が生えていた
ここまでわかればよく見る構造は大体parseできそうな予感
次はOpenAIのAPIに投げ込んでみる
生のAPIたたいてもいいけれど、気になっていたvercelのaiを使ってみる。対応しているのか調べたらちゃんとあるみたい
const result = await streamObject({
model: openai("gpt-4o"),
schema: z.object({
response: z.string(),
meta: z.string().max(10),
}),
prompt: "Hello",
});
stringの制約を設定すると守ってくれたのにびっくりした。
max(1)とかにすると一文字だけ出る。LLMは文字数数えるのが苦手なはずなので、専用の学習をしているのかな
streamにすると、streamが終わるまではjsonの途中までのようなobjが返ってきていたので、これだとあまりstreamの嬉しさがないかもしれない
jsonなので返ってきた文字を読んで、{}や""の対応を補完してあげると途中でも使えそう?(stack使えばいけそうな)