Open7

zodに入門ついでにOpenAIのStructured Outputを試す

LTKSKLTKSK

TODO

  • zodのtutorialをやる
  • structured outputにzodのschemeを投げるのを試す
  • streamingの時にstructured outputを指定しているとどうなるのか調べる
    • streamの途中でvalidなjsonだったりするのかが気になる
LTKSKLTKSK
const numParser = z.number();
const parsed = numParser.parse(num);

一番シンプル
これで型を満たしているかを判定してくれる。満たしていないときは例外を投げる
safeparse という関数だと結果がobjectで貰える。基本はこっちを使っている方が扱いやすそうだ

LTKSKLTKSK

objectの場合、以下のように引数の中にobjectを入れ込む。valueにあたる部分がzの関数になるわけでだいぶわかりやすい感じ

z.object({
    hoge: z.number()
})

z.arrayも引数にschemeを取る

LTKSKLTKSK

stringの文字数など引数にvalidationのための設定がたくさんある。
これらは欲しくなったらdocumentを探す感じでいいかも。文字数長とかは型に落としづらい(型パズルすれば頑張れるらしいが...)ので、使うときは命名やコメントでカバーしたい

LTKSKLTKSK

schemaから型を取るには

z.infer(typeof SomeSchema)

のようにinfer関数で取得できる。
unionもz.union関数が生えていた

ここまでわかればよく見る構造は大体parseできそうな予感
次はOpenAIのAPIに投げ込んでみる

LTKSKLTKSK

生のAPIたたいてもいいけれど、気になっていたvercelのaiを使ってみる。対応しているのか調べたらちゃんとあるみたい
https://sdk.vercel.ai/docs/ai-sdk-core/generating-structured-data

    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使えばいけそうな)