この記事は、ChatGPTのAPIを利用して高度な自然言語処理を行う際に、プロンプトでの出力形式の制御について解説しています。特に、自然言語とTypeScriptの型表現、そしてzodのSchema表現の比較を行いながら、プロンプトを用いてモデルのLLMが正確に解釈できる方法に焦点を当てています。
Nisi enim consequat varius cras aliquam dignissim nam nisi volutpat duis enim sed. Malesuada pulvinar velit vitae libero urna ultricies et dolor vitae varius magna lectus pretium risus eget fermentum eu volutpat varius felis at magna consequat a velit laoreet pharetra fermentum viverra cursus lobortis ac vitae dictumst aliquam eros pretium pharetra vel quam feugiat litum quis etiam sodales turpis.
Porta nibh aliquam amet enim ante bibendum ac praesent iaculis hendrerit nisl amet nisl mauris est placerat suscipit mattis ut et vitae convallis congue semper donec eleifend in tincidunt sed faucibus tempus lectus accumsan blandit duis erat arcu gravida ut id lectus egestas nisl orci id blandit ut etiam pharetra feugiat sit congue dolor nunc ultrices sed eu sed sit egestas a eget lectus potenti commodo quam et varius est eleifend nisl at id nulla sapien quam morbi orci tincidunt dolor.
At risus viverra adipiscing at in tellus integer feugiat nisl pretium fusce id velit ut tortor sagittis orci a scelerisque purus semper eget at lectus urna duis convallis. porta nibh venenatis cras sed felis eget neque laoreet suspendisse interdum.
“Vestibulum eget eleifend duis at auctor blandit potenti id vel morbi arcu faucibus porta aliquet dignissim odio sit amet auctor risus tortor praesent aliquam.”
Lorem cras malesuada aliquet egestas enim nulla ornare in a mauris id cras eget iaculis sollicitudin. Aliquet amet vitae in luctus porttitor eget. parturient porttitor nulla in quis elit commodo posuere nibh. Aliquam sit in ut elementum potenti eleifend augue faucibus donec eu donec neque natoque id integer cursus lectus non luctus non a purus tellus venenatis rutrum vitae cursus orci egestas orci nam a tellus mollis.
Eget lorem dolor sed viverra ipsum nunc aliquet bibendum felis donec et odio pellentesque diam volutpat commodo sed egestas aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod eu tincidunt tortor aliquam nulla facilisi aenean sed adipiscing diam donec adipiscing ut lectus arcu potenti eleifend augue faucibus bibendum at varius vel pharetra nibh venenatis cras sed felis eget.
ChatGPTのAPIの登場によって、高度なNLPを利用したアプリケーションを簡単に作ることができる様になりました。 しかし、実際に製品レベルで使えるものを作ろうとしてみると、LLMの非決定論的な挙動をコントロールする必要があり、これがなかなか難しいことがわかります。
その課題の一つに「LLMの出力を、後続のプログラムがパース可能な形で出力させたい」というものがあります。出力の形式はJSONが選択されることが多いのでより具体的にすると、LLMにJSONを出力させる場合に、高い確率で正しいフォーマット&指定した構造で出力させたい場合にどの様なプロンプトが良いか?という課題です。
単純には、自然言語により構造を伝えた上で「JSONで出力して」と指定することになります。出力したいデータの構造が単純なうちはこれで事足りますが、複雑になれば自然言語での指定は長くなりがちだったり、曖昧な表現になるなどの問題がありそうです。そのため、TypeScriptの型やzodのスキーマ定義など、一般に広く使われている、データ構造の記法を使って表現する方法が思い浮かびます。
「プロンプトで出力に期待するデータの構造を伝える、と言う目的で適切な構造定義の記法を選ぶ」という課題は、プロンプトを与える対象であるモデルのLLMが、その定義の記法を正確に解釈するかどうか。また定義の記法の中でLLMのアテンションをコントロールしやすいかと言ったことが論点になります。
今、当社(SparkleAI)のプロダクトでは、特に検証を行わずに、エンジニアが慣れている方法として「TypeScriptの型定義」を採用することが多く、これで問題が起こることはないです。しかし、型には含めにくい表現(例えば文字数などの制限)があり、この点でzodなどのSchema定義と比較した場合に、どちらがより適切かについて評価が必要です。
このブログでは、自然言語/TypeScript/Zodでアウトプット形式を指定した場合にChatGPTがアウトプットの成形に成功する割合について調べてまとめます。
目的
コミュニケーション
手法の論点
曖昧さがあり、指定した型で返してこないことがありそうだ
目的
プログラムソースの型チェック
手法の論点
TSで書かれたプログラムは多いため正確に解釈されそうだ
目的
プログラム実行時のスキーマ検証
手法の論点
型表現より具体的な指定ができるが、結果に影響があるか
出力される文字数や、項目の数を指定した場合にChatGPTはその制約に従わないことが多いです。そのためプロンプトエンジニアリングでは、一度生成させて後から文字数などを直させる方法が採用されます。しかし、今回は、zodなど文字数や個数の制約が結果に与える影響も確認したいので、文字数に制約を入れた「問題の生成」プロンプトを題材にします。
以下のプロンプトで出力形式の定義をそれぞれ、自然言語/TypeScript型表現/ZodのSchema表現で入れ替えたものを使います。
NLとTSとZDのそれぞれで出力形式を指定した問題の生成プロンプトに、異なる10のドキュメントを30回づつ繰り返し与えて(計300回)出力し、結果に対して次の内容を集計し評価します。
生成の多様性が高い設定の方がプロンプトの違いが大きく出るだろうと仮定して、多様な結果の生成タスクで使われる現実的な上限値:Temperature=1.2の設定に固定しました。
parse
0.84 (251/300)
scheme
0.57 (143/251)
count
0.8 (114/143)
length
0.8 (1556/1950)
parse
0.95 (284/300)
scheme
1.0 (283/284)
count
0.73 (206/283)
length
0.76 (2861/3788)
parse
0.94 (278/296)
scheme
1.0 (278/278)
count
0.82 (228/278)
length
0.79 (2935/3736)
プロダクトで利用する場合、第一にParseとSchemaの精度が高いものが望まれます。praseとschemaのテストで「NL」と「TSおよびZOD」の間で大きな差がありますので、自然言語を使うよりもやはり人工言語を使って出力の構造を指定する方がよりコントロールしやすいことがわかります。
その上で、TypeScriptとZodにはparseおよびschemaのテストでは大した差がありません。一方でTypeScriptのcountとlengthの成績は、Zodや自然言語とも比べて悪いことがわかります。TypeScriptの型表現の中に、個数や文字数の制約を入れていく方法は、Schemaの仕様よりもアテンションが掛かりにくいのかもしれないです。
以上のことから、最も狙った構造を出しやすいという点では、Schema表現を使うのが数字上の成績が良いです。しかし、Schema表現にはZod以外にYup / io-ts / joiなど、記述方法が似通っていて細部が異なるライブラリがあり、こちらが指定した意図の通りにコントロールができるかの点で不安があります。またTypeScriptより普遍性が低いので、今後に記述に変更がある可能性に注意が必要です。
この記事では、自然言語、TypeScript、およびZodを用いてChatGPTによる出力形式を制御する方法を比較検討しています。その主な焦点は、これらの方法がChatGPTにどの程度正確なデータ構造を生成させられるか、またそれらの方法がChatGPTのアテンションをどの程度コントロールできるかという点にあります。
結果として、自然言語よりもプログラミング言語を使用して出力の構造を指定する方がより精度が高くなることがわかりました。具体的には、出力がパースに成功する率やスキーマ一が指定したものと一致する率はTypeScriptとZodの両方で自然言語よりも高く、またこれら二つの間では大きな差は見られませんでした。
ただし、項目の個数や文字列の長さを制約することに関しては、TypeScriptがZodや自然言語よりも劣っていることがわかりました。これは、TypeScriptの型表現が個数や文字数の制約を含めるのが難しく、そのためにSchemaの仕様に比べてアテンションが掛かりにくいことが理由と考えられます。
この観点から、最も狙った構造を出しやすいという点ではSchema表現が適切です。しかしSchema表現はTypeScriptに比べて普遍性が低く、記述が変更される可能性があるためその点に注意が必要です。
以上を踏まえ、JSONの出力を指定し、その構造を制御するための記述としてはTypeScriptの型表現が最も有用であると考えます。しかし、TypeScriptの型表現では個数や長さの制約がSchemaと比較して若干劣るため、これらの要素をプロンプトの平文の指示でさらに制御することが推奨されます。