こんにちは!DataIntelligenceチームの垣内です。
今回は6月27日(火)と28日(水)に日本マイクロソフト株式会社の品川オフィスとオンラインのハイブリット形式で開催されたイベント「Microsoft Build Japan」のExpoブースにて展示した「レシピ提案アプリ」について、人気だったプロンプトエンジニアリングについてお話しします。
プロンプトエンジニアリングについて
そもそもプロンプトとは
ユーザーが生成AIに対して行う質問や指示のことをプロンプトと呼びます。生成AIは入力内容を理解して何かしらの出力(Completion)を返します。 例えば「神戸市は何県にある?」という質問を大規模言語モデルに対して投げかけると「神戸市は兵庫県にあります」と返してくれます。
プロンプトエンジニアリングとは?
プロンプトエンジニアリングとは、生成AIから期待する出力結果を得る・制御するためにプロンプトを調整する行為の事を指します。
生成AIと書いているように、プロンプトエンジニアリングという言葉はLLMのみならず画像生成AIに対しても使われます。百聞は一見に如かずということで、実際にプロンプトエンジニアリングをするとしないでどのように結果が変わるかやってみました。
プロンプトエンジニアリングなし
まずはエンジニアリングをせずに入力します。従来のGoogle検索をするときのような書き方ですね。質問するときは文字数が少ないので入力は楽な一方で今回のような質問の場合は、ちょっと文章が長くなりがちです。
プロンプトエンジニアリングあり
先ほどの出力を見ると「技術的な内容が理解し辛い」や「1文が長い」といった出力を改善したいなと思うポイントが色々思い浮かんできます。より具体的に出力したい内容が浮かんできたら、どのように付け加えればよいか考えます。今回の場合
- 1文が長い→すっきりわかりやすく説明する
- 技術的な内容が理解し辛い→生成AIの概要とか簡単な説明が欲しい
という風に、改善ポイントをベースに追加で記述するプロンプトを考えてみます。どのように出力が変わるか見てみましょう。
どうでしょう!情報を整理しつつ、知りたいたいことを得られるようになりました!
このようにプロンプトエンジニアリングは、出力結果と自分の求めていた回答を照らし合わせて、差を埋めていくという改善活動のようなものなのだという事が分かりますね。言葉に気圧されやすいですが、難しいことは何もしていないという事がお判りいただけたかと思います。
さて、ではプロンプトエンジニアリングの一例をこれからご紹介していきます。
レシピ提案アプリについて
その前にこちらのレシピ提案アプリについて簡単にご紹介します。こちらのアプリは、家にある食材以外にも家族の健康情報や好き嫌い・アレルギーといった情報だけでなく「時短」や「簡単」といったキーワードをベースにメインディッシュを3つ提案してくれます。
提案されたレシピを選択すると、さらに必要な食材・調味料、作り方、副菜や汁物を提案してくれます。
但し、誤った情報を出してはシステムの信頼性を損ねる可能性があるため、今回はカロリーや成分についてはあらかじめ準備しておいた情報を出すように工夫をしています。
本日はこのあたりのプロンプトエンジニアリングについてご紹介いたします。
ちょっと余談ですが、実はこのアプリ、28日(火)のキーノートにてご紹介いただきました。もう少し前からスタートするとアプリの仕組みのご紹介をしていますのでご興味があれば見てみてください。
はじめに
今回はAzure OpenAI Serviceのgpt3.5-turboを利用して、レシピ提案をしてもらっています。そのためgpt-4や他のLLMモデルを利用する場合は精度が変わる可能性があるため、追加調整が必要になる可能性がございます。予めご了承ください。
それでは早速見ていきましょう~~!!!まず、このアプリでは、次の情報を入力設定していきます。
変数 | 概要 | 例 |
---|---|---|
family_profile | 家族のうち、誰が料理を食べるか | 母, 息子, 本人 |
ingredients_have | 持っている食材のリスト | 鶏モモ, キャベツ, なす |
health | 家族の健康状態 | 高血圧, 妊娠 |
menu_request | 作るメニューに対するリクエスト | 時短, ダイエット |
ng_food | 使いたくない食材 | サバ |
これらの情報を考慮して、メインディッシュを次のフォーマットに沿って3つ提案してもらいたいと考えました。 先のプロンプトエンジニアリングのチャプターでいうところの「期待する出力結果」がこちらになります。
{ "abst": "入力した情報の要約", "dish1": { "ja": "メインディッシュ名(日本語)", "en": "メインディッシュ名(英語)", "reason": "このメインディッシュをおススメした理由" } }
この結果を得るためにやったこと・試行錯誤を簡単にご紹介します。
①存在しないレシピを提案しないように制御する
何もしない状態だと、世の中に存在しない架空のレシピを提案するということが度々起こりました。
「さすが生成AI!」という思いもある反面、料理作りに失敗するリスクもあるので今回は架空のレシピを提案しないような制御をする必要が出てきました。
この場合は「架空の料理を作ったり重複してはいけない。」という1文を付け加えることでこの事態を回避することができました。このプロンプトは、架空のアウトプットを出さないようにするための制御でもあるので、他にも応用が利きます。
♦実際の使用例
エンジニアリング前、生成AIからは「Prompting Matters: A Large-scale Study of Language Models with Reinforcement Learning」という論文が該当すると教えてもらいました。
しかしながらこの論文は存在しません。そこで文末に「制約」を加えて再度調査依頼をしてみたところ、指定した内容の論文はないという回答が返ってきました。
②指定したフォーマットで出力させる
内容の制御ができたので、次はフォーマットを制御したいと思います。
今でこそfunctioncalling等の便利なライブラリやツールを使って出力を制御することはできます。しかしながら、これらの方法はシステムに組み込んだときに発揮されという事に注意が必要です。
システムに組み込んでいない素のChatGPTを用いて指定フォーマットで出力させたい場合、よく使われる手法として次のやり方が挙げられます。
- One-shot learning
- Few-shot learning
これらはプロンプトに入力と出力の例題のようなものを入力し、例題なしのプロンプトは「Zero-shot learning」といいます。 Azure OpenAI Service - Azure OpenAI | Microsoft Learn
本当は例題を提示するOne-shotもしくはFew-shotいずれかを使いたかったのですが、トークンの制限を超えてしまうということもあり今回は例題なしの「Zero-shot learning」で臨まなければなりませんでした。 絶体絶命の中で試行錯誤した結果、次のOne-shotに近い書き方で安定して指定したフォーマットで出力できるようになりました。
この書き方は、トークンが限られている中で毎回指定したフォーマットを出力させたいといった場合に有効です。
プロンプトエンジニアリングをやってみて思うこと
難しいことをやっていそうなプロンプトエンジニアリングですが、いざやってみると「誰かに何かをお願いするとき」の依頼文章を書いているのと変わりないということがお判りいただけたかと思います。 個人的な経験としては、思ったように出力されない場合は指示内容が抽象的で具体性が欠けているか、生成AIの出力にバイアスがかかっているのいずれかが当てはまります。
プロンプトエンジニアリングを通して人間も徐々に学習していくともいわれているので、どのようにプロンプトを変えれば良いかという仮説も立てやすくなるので、ぜひ一度挑戦してみてください!