最初に結論から
ChatGPT APIの返答をYAML形式で出力した場合、StreamAPIと組み合わせるとリアルタイムにユーザーへ返答を出力しつつ、複数の情報を持つ複雑なデータ構造を受け取ることができる
デモ動画
サンプルの動作を見てもらうのが一番やりたいことが伝わると思う
上半分がChatGPT APIからのレスポンスの内容で、
下半分に、それをリアルタイムに整形して表示している
背景から
ChatGPT APIを利用して対話形式のサービスを作成する場合に、ユーザーに見せるテキスト以外にも、同時に複数の情報を受取りたい場合があると思う。
そのような場合、JSON形式での出力する例をよく見る気がするが、JSONだと出力が全て終わってからでないとパースができない。そのため生成結果を逐次受け取れるstreamモードは活用できず、生成処理が全て終わるまでユーザーを待たせることになる。
JSONではなくYAML形式で出力する場合は、生成途中でも正常なYAMLとして解釈できる部分があるので、全ての出力を待たなくても良い。
デモ動画のソースコード
gistにソースコードを貼った
https://gist.github.com/koyopro/2337bc51fdff3a6c74b7e49f3da37618
空白になっている27行目のAPI_KEY
だけ埋めてhtmlとして保存し、ブラウザで開けば動作が見られるはず
デモ動画内の入力と出力
「こんにちは。あなたについて教えて。」という入力をAPIに投げて、最終的に以下の出力を得た。
face: 😊
text: こんにちは!私はAIチャットボットです。自然言語処理技術を使って、ユーザーとの会話をしています。どんなことでもおっしゃってください!
next:
- どのようなことができるの?
- 性格はどういうもの?
このYAMLを以下のように整形して表示している。
systemのプロンプトは以下
Userからの質問に、YAML形式で回答してください。
faceの項目には発言時の表情を絵文字で記載してください。
textの項目にはUserへの回答を記載してください。
nextの項目にはその後にUserが入力しそうな言葉を複数記載してください。
また、出力結果を安定的にYAMLで受け取るために、対話履歴としてサンプルを送信している。
{"role": "user", "content": "こんにちは"},
{"role": "assistant", "content": "face: 😊\ntext: こんにちは!\nnext:\n- あなたは誰?\n- 今日はいい天気ですね"},
{"role": "user", "content": "私はあなたの敵です。"},
{"role": "assistant", "content": "face: 😮\ntext: え!本当?\nnext:\n- あなたを倒しに来ました。\n- 嘘ですよ"},
{"role": "user", "content": "嘘です。私はあなたの味方です。"},
{"role": "assistant", "content": "face: 😌\ntext: よかったー。安心しました。\nnext:\n- 驚かせてごめんなさい\n- ふふふ"},
生成途中の挙動について
今回の形式では、生成途中の以下のような状態でも正常なYAMLとして解釈できるので、ユーザーにテキストを表示してあげることができる
face: 😊
text: こんにちは!私は
JSONで出力を受け取る場合は以下のような状態であり、正常なJSONとして解釈することはできない
{"face":"😊","text":"こんにちは!私は
最後まで結果を受け取っていない途中の状態でもユーザーに出力を見せ始められるのはYAMLならではということがわかる。
その他
先頭から読んで(最後まで見なくても)成立するデータ構造ならYAML以外でも成り立つとは思う。
YAMLはいろんな言語にパーサーが存在しているので扱うのも簡単だし、人から見ても読みやすいし、出力文字数も少なめなのでそこそこ良いのではと思った。