こんにちは。Azureビジネス部の金重です。
今年に入って、LLMが大流行し、個人や企業でも活用する例には枚挙にいとまがありません。また、MicrosoftではOpenAIと手を組んでAzure OpenAI Serviceというサービスが提供され、開発に言語生成AIを含む生成AIの機能を組み込むことができるようになりました。そういった背景でサービスの開発やプロンプトエンジニアリングが盛り上がってきていますが、このプロンプトエンジニアリングを自動化したい!という試みです。
★この記事は…
NEXTSCAPE Advent Calendar 2023 8日目 です。
背景
LLM(Azure OpenAI Service)の会話の仕組み
Azure OpenAI Serviceを例に紹介します。LLMを用いてチャットを含めた何かしらの応答を受け取りたい場合、一般には以下の仕組みで会話を行います。
この会話文は本家ChatGPTをはじめとしたサービスでAPIが用意されており、Azure OpenAI Serviceにおいては以下の様なJson形式で会話文を送信します。
roleは誰が話しているか?を指します。最初のsystemと記載があるアイテムはLLMに与える強い制約として、会話セッションにおけるエージェントの性格や会話の目的、語尾、文章執筆といった特定の目的の会話エージェントであること等を明示してあげることで後の会話の仕方を制限します。
そして、userがユーザーの入力、assistantがLLMの返答として、ユーザーが会話をするとLLMが過去の会話履歴を基に返答を生成します。複数ターンの会話であれば、その会話履歴を含めることができ、例えば一度エージェントに質問をして回答が得られたときに、その回答を要約してと頼むことでより簡潔な回答を得るといったこともできます。特に、一度で大量の指示を出すとLLMは一度に解釈することが難しいらしいので、順番に指示を出してあげることが有効になりそうです。
プロンプトエンジニアリング
そこで、ChatGPTに良い応答をしてもらうために、プロンプトエンジニアリングという技術があります。例えば、few-shot promptingという方法ではいきなり質問をするのではなく、具体例を示してその例を基に質問に答えさせます。具体的には、「太郎は飴を買って嬉しかったです。という文章はポジティブ」「花子は雨が降っていて外に出られないので悲しかったです。という文章はネガティブ」と例示した後に、「XXという文章の感情を判定してください」と質問を投げます。そうすることで、いきなりXXという文章の感情を判定してくださいと質問するよりも、判断材料が明確になったような答えを得やすくなります。
プロンプトエンジニアリングの手法については、現段階では各々が試して得られた知見が体系化されきっておらずアップデートも激しいのでうまく語ることはできないのですが、特定のユースケースに特化したプロンプト集をまとめている方がいる他、汎用的な知見についてはMicrosoftのセミナー資料などがよくまとまっています。
プロンプトをLLM自身に考えさせてみる
プロンプトエンジニアリング、難しい…!ということで、ユーザーが入力するプロンプト自体をLLMに考えさせてみましょう。とはいっても、一から考えさせることは非常に難しいので、本投稿では最初に簡単な指示を用意して、そこに付随する細かい制約を考えさせて、追加していきます。うまく回答を生成できるようになってくれると嬉しいですね。
ここでの想定としては、一般の機械学習のように大量のデータを与えるよりは、レビューを2,3回繰り返すようなイメージです。というのも、評価結果を自然言語で出力するので、それに応じて具体例を直してもらう感じになりますし、一発で良い修正案を出してくれれば十分良い結果を出せるようになるはずです。
また、自然言語の評価には従来はクラウドソーシングで人手で評価をすることが多かったのですが、最近はArXiv上でLLMの生成結果をLLM自体に評価させる手法が登場しており、進歩を感じます(機械学習関係のここ最近で一番の驚きです)。勿論Domain-spesificな課題に対してはプロが見るべきですが、一般レベルの読解力を求めるのであればLLMの方が良いのかもしれません。
実装
というわけで、全体のアーキテクチャを以下に示します。
アーキテクチャはユーザーが会話するチャットモデルとチャットモデルの出力を評価及び提案するレビューモデルから構成されます。学習段階では質問を固定してチャットモデルに質問を行います。チャットモデルがLLMを用いて返答を返すと、その結果がレビューモデルの入力になります。レビューモデルはまず、その解答とレビュー観点を基に、LLMを用いてチャットモデルの返答の良しあしを判断してレビュー結果を出力します。一度出力されたレビュー結果はそのままチャットモデルに制約として加えるのではなく、制約を提案する為にレビュー結果をLLMに投げて、その結果制約を出力してもらいます。例えば、文章が短すぎれば"文章を長くしてください"のようなものになります。最後に、この提案された制約をチャットモデルに追加するのですが、学習を回すごとに制約文がどんどん追加されるとプロンプトが無限に長くなってしまうため、指摘事項が無い場合は追加しない分岐処理を挟んだうえで、制約の要約を行います。端的にいうと、重複する内容の制約を削除してあげます。
アーキテクチャとしては以上ですが、実際には各モデルに与えられるプロンプトの機微に影響する部分も大きいため、見ていきます。プロンプトはそれぞれ以下の通りです。今回は旅行プランを提案するエージェントとしました。こういったケースではRAGを構築して実際の旅行先データ等から最新の正しい情報を提供することが望ましいですが、自動化を試すだけなのでLLMの学習した内部の知識に頼ります。
長いのでサマリを示すと、チャットモデルの要約・チャット及びレビューモデルのレビュー・提案のそれぞれのリクエストに対するシステムプロンプト及びユーザープロンプトを順番に列挙しています。{}で囲まれた部分にはユーザーの入力や生成結果が代入されるイメージです。
実験
実験条件
今回はチャットモデル及びレビューモデルの双方にGPT4モデルを使用します(理由は後述)。三回ループを回してみた結果を以下に示します。東京の旅行プランについて質問し、出力は各ループ毎のチャットモデル出力、制約事項一覧、レビュー結果、提案された制約事項の四つとなります。また、回ごとのランダム性に影響する温度パラメータは0としました。一度のループで大量のレビュー結果を見たいようなケースだと役に立ちそうですが、今回は一度に一つの出力に対してレビューを回すのと、温度パラメータが高いと各回のチャット出力で制約を守ってくれない懸念があった為です。
結果・考察
長くなるのでサマリを先に記載します。まず、一度目のチャット時点でかなり良い旅行プランを提案しています。日ごとに朝昼夜と分けたプランを提供してくれています。それに対して、読みやすい構成となっているが移動手段や所要時間が足りない為追加してほしいとレビューされ、二度目のチャットではその内容を踏まえた旅行プランを提案してくれます。この時点で三回目は指摘事項が追加されない為、少しフォーマットは異なりますがほぼ同じ結果が出力されます。
また、回ごとにめぐる場所が異なりますが、それに関してはコンテキストにプランを渡していない為です。先述のRAGなどでプラン自体は渡してあげることで、そのプランをより魅力的にかつ分かりやすく、その他レビュー観点に則った形で出力できると思います。
GPT4モデルを使用した理由について、GPT3.5モデルだと制約事項を追加してもあまりよろしくない結果になった事情があります。試行錯誤する段階ではGPT4モデルを、実運用では安価なGPT3.5モデルを使用するような方法もあるのですが、今回はベースのプロンプトエンジニアリング力が足りず、といった事情です。レビューの観点なども少し変えるだけで結構出力が変わってしまい、人間の感覚的な少し違うとLLMの解釈の少し違うの間のズレがあるのを感じます。そういったプロンプトの機微の調整が大切である点は否めないです(結局プロンプトエンジニアリング力は必要なんですね)。
正直なところ、レビュー観点が出ていればそれに合わせた制約事項は思いつきそうなのですが、そこを思いつけない時に頭出ししてもらうような感じになりそうです。方針が大まかに決まったらあとは人力プロンプトエンジニアリング力の出番なので、ループを回し続けるよりもまず最初の一回を見て人間が考えてあげる方が良さそうでした。
終わりに
ここ最近LLMに関するブログはたくさんあるのですが、折角だから面白いことができないかな~と思ってやってみました。実用性の面では毎回この学習を回すよりも人間が実際のユースケースに即した知見を与える方が良いと思うのですが、AIが自己学習したら嬉しいなと思ったのでやってみました。
※タイトルはこの書籍のオマージュです。プロンプトエンジニアリング、奥深いですね。
O'Reilly Japan - 退屈なことはPythonにやらせよう (oreilly.co.jp)