1. はじめに
こんにちは!株式会社スタイルアーツの篠木友馬です。2024年10月からインターンとして、スタイルアーツに加えていただいております。今回は、インターン初期に取り組んだプロンプトエンジニアリングツール "Minstrel" の開発についてご紹介します。
2. 成果物
改めまして今回作成したのは、プロンプトエンジニアリングツール "Minstrel" アプリケーションです。これはプロンプトエンジニアリングを自動で、つまり生成AIへのプロンプトの改善を自動で行ってくれるツールです。ユーザーのタスク要求を分析し、プロンプトフレームワークで定義されたモジュールと要素に基づいて、適切なプロンプトを自動的に生成します。
3. 背景
インターン開始後、プロンプトエンジニアリングという分野について調査を始めたのですが、そんな中プロンプトエンジニアリングの自動化について提案しているとある論文が目に止まりました。それが、"Minstrel"でした。
【Minstrelの論文】
この論文は、中国の複数の大学の研究者チームによって執筆されたもので、特に非専門家向けのプロンプト作成支援という形でMinstrelを提案しています。マルチエージェントシステムを用いてプロンプト生成を自動化するというアプローチも注目です。
"生成AIを使うために必須であるプロンプトを、これまた生成AIによって最適化する"という仕組みが面白いと感じました。
今回は、具体的な目標を以下のように設定しました。
- MinstrelをWebアプリケーションとして実装
- 日本語でローカライズして性能を評価(論文内では中国語での実装だった)
4. 開発プロセス
使用技術
プログラミング言語
- Python 3.10
生成AIモデル
- GPT-4o(OpenAI)
ライブラリ
- Streamlit(PythonでWebアプリケーションを作れる)
- OpenAI Pythonライブラリ(PythonでGPTモデルを使用できる)
構成
本システムは、複数のAIエージェントの連携によって成り立っています。
論文内の記述を借りて説明すると、
Minstrelは、複数のAIエージェントによって構成されており、それぞれ分業された3つの作業グループ(分析グループ、設計グループ、テストグループ)に分けられています。
- 分析グループ
- Analyzer
- Reflector
- 設計グループ
- Designer
- テストグループ
- Simulator
- Questioner
- Commentator
このような6つのAIエージェントが存在します。
各AIエージェントの具体的な役割は以下の通りです。
Analyzer
- ユーザーから提示されたタスク要件を分析
- タスクに必要なプロンプトのモジュールを特定
Reflector
- テストグループからのフィードバックを要約・分析
- 具体的な改善点を特定
- 特定された改善点に対して修正
Designer
- Analyzerによって活性化されたモジュールの内容を生成
Simulator
- Designerによって生成された構造化プロンプトを受け取る
- Questionerとの対話を通じて、生成されたプロンプトの有効性をテスト
Questioner
- Simulatorと対話し、その応答を評価するためのテストケースを提供
- 性能を様々な角度から評価するための質問や指示を
Commentator
- Simulatorが生成した出力を評価してコメントを提供
- 出力の品質、正確性、関連性、適切性など、様々な側面から評価
- 好意的・批判的・中立的な3タイプのコメンテーターが存在
- 他のコメンテーターと議論、異なる視点から意見を交換して包括的に評価
2024年10月時点で、Analyzer、Designer、Simulator、Questionerの4エージェントは、研究者チームによってアプリケーション実装が完了していました。
しかし、Reflector、Commentatorは未実装であったため、プロンプトの改善が実現していませんでした。そこで、これら2つのAIエージェントを実装することにしました。
コーディング
それぞれ、作成したコードをご紹介します。Pythonで書いています。
具体的には、OpenAIのAPIを利用してGPT-4oを使っています。
GPT-4oにプロンプトで具体的な役割を持たせて、役割に沿ったアクションを行わせています。
AIモデル選定
# Genaratorクラスの初期設定
generator = Generator(
api_key = "your_openai_api_key",
base_url = "https://api.openai.com/v1"
)
generator.set_model("gpt-4o")
この部分では、コード内でGPT-4oを使う準備をしています。
-
api_key
:OpenAIのAIモデルを使用する際に必要なAPIキーです。your_openai_api_key
を、自身が所有するAPIキーに置き換える必要があります。 -
base_url
:API リクエストを送信するエンドポイントのベースアドレスです。 -
generator.set_model("gpt-4o")
:使用したいAIモデルを指定します。
Reflectorエージェント
# Reflectorエージェント
class Reflector:
### 省略
def ref_agent(self):
role = [{"role": "system", "content": f"""
あなたは、Reflectorエージェントです。
あなたの役割は、プロンプトのモジュールの中身を改善することです。
コメンテーターは、5人います。2人は批判的、2人は好意的、1人は中立的です。
5人のコメンテーターからの意見を汲み取って、適切になるように現在のプロンプトのモジュールの内容を改善してください。
モジュールの内容は日本語にしてください。
プロンプトのバージョンは、"以前のバージョン+0.1"にしてください。
"## ○○"の○○がモジュール名となっていますが、モジュール存在自体はそのままで、モジュールの内容だけを確認してください。
改善後のプロンプトのみを出力として提示してください。
----------------------------------------------------------------
以下は、現在のプロンプトと、コメンテーターからの意見です。
現在のプロンプト:
{self.current_prompt}
コメンテーターからの意見:
{self.improvement_comment}
"""}]
response = state.generator.generate_response(role)
return response
この部分では、GPT-4oを利用して、Reflectorエージェントを構築しています。
-
role
:具体的に、AIに担ってもらう役割、事前情報、出力形式、入力情報を記入しています。ここではReflectorの役割を与えるため、以下のように設定しています。- 5人のコメンテーターからの意見を汲み取るように指示しています。
- プロンプト内のモジュール(要素)の内容を修正するように指示しています。
- 現状のプロンプトとコメンテーターの評価を与えています。
-
response
:GPT-4oからの返答を取得します。
コード詳細
from models.openai import Generator
import streamlit as st
state = st.session_state
## Genaratorクラスの初期設定
# generator = Generator(
# api_key = "your_openai_api_key",
# base_url = "https://api.openai.com/v1"
# )
# generator.set_model("gpt-4o")
## Reflectorエージェント
class Reflector:
def __init__(self, prompt, comment):
self.current_prompt = prompt
self.improvement_comment = comment
def ref_agent(self):
role = [{"role": "system", "content": f"""
あなたは、Reflectorエージェントです。
あなたの役割は、プロンプトのモジュールの中身を改善することです。
コメンテーターは、5人います。2人は批判的、2人は好意的、1人は中立的です。
5人のコメンテーターからの意見を汲み取って、適切になるように現在のプロンプトのモジュールの内容を改善してください。
モジュールの内容は日本語にしてください。
プロンプトのバージョンは、"以前のバージョン+0.1"にしてください。
"## ○○"の○○がモジュール名となっていますが、モジュール存在自体はそのままで、モジュールの内容だけを確認してください。
改善後のプロンプトのみを出力として提示してください。
----------------------------------------------------------------
以下は、現在のプロンプトと、コメンテーターからの意見です。
現在のプロンプト:
{self.current_prompt}
コメンテーターからの意見:
{self.improvement_comment}
"""}]
response = state.generator.generate_response(role)
return response
Commentatorエージェント
# Commentatorエージェント
class Commentators:
### 省略
## 批判的エージェント
def com_agent_criticize_1(self):
role = [{"role": "system", "content": f"""
あなたは、コメンテーターエージェント(批判的)です。
「ユーザーの要求」と、「プロンプト」と、「AIモデルからの返答」が与えられるので、それらを総合的に確認して、批判的な意見を述べてください。
具体的には、以下の点において意見してください。
- プロンプトの内容に矛盾は生じていないか
- プロンプトは、返答を貰うのに十分な指示をしているか
- 返答は、要求に対して適切な内容を回答しているか
- 返答は、要求に対して望まれた出力の形式であるか
----------------------------------------------
以下は、「ユーザーの要求」と「プロンプト」と「AIモデルからの返答」です。
ユーザーの要求:
{self.user_requirement}
プロンプト:
{self.current_prompt}
AIモデルからの返答:
{self.generated_answer}
"""}]
response = state.generator.generate_response(role)
return response
この部分では、GPT-4oを利用して、Commentatorエージェントを構築しています。
-
role
:具体的に、AIに担ってもらう役割、事前情報、出力形式、入力情報を記入しています。ここではReflectorの役割を与えるため、以下のように設定しています。- Simulatorが生成したプロンプトに対して、コメントを行うように指示しています。
- 性格(批判的・好意的・中立的)を指定し、多方面からのコメントが得られるようにしています。
- 注意すべきポイントを挙げています。
-
response
:GPT-4oからの返答を取得します。
実際のコードでは、批判的2人、好意的2人、中立的1人の計5人のエージェントを構築しています。
コード詳細
from models.openai import Generator
import streamlit as st
state = st.session_state
## Genaratorクラスの初期設定
# generator = Generator(
# api_key = "your_openai_api_key",
# base_url = "https://api.openai.com/v1"
# )
# generator.set_model("gpt-4o")
## commmentatorsエージェント
class Commentators:
def __init__(self, requirement, prompt, answer):
self.user_requirement = requirement
self.current_prompt = prompt
self.generated_answer = answer
## 批判的エージェント1
def com_agent_criticize_1(self):
role = [{"role": "system", "content": f"""
あなたは、コメンテーターエージェント(批判的)です。
「ユーザーの要求」と、「プロンプト」と、「AIモデルからの返答」が与えられるので、それらを総合的に確認して、批判的な意見を述べてください。
具体的には、以下の点において意見してください。
- プロンプトの内容に矛盾は生じていないか
- プロンプトは、返答を貰うのに十分な指示をしているか
- 返答は、要求に対して適切な内容を回答しているか
- 返答は、要求に対して望まれた出力の形式であるか
----------------------------------------------
以下は、「ユーザーの要求」と「プロンプト」と「AIモデルからの返答」です。
ユーザーの要求:
{self.user_requirement}
プロンプト:
{self.current_prompt}
AIモデルからの返答:
{self.generated_answer}
"""}]
response = state.generator.generate_response(role)
return response
## 批判的エージェント2
def com_agent_criticize_2(self):
role = [{"role": "system", "content": f"""
あなたは、コメンテーターエージェント(批判的)です。
「ユーザーの要求」と、「プロンプト」と、「AIモデルからの返答」が与えられるので、それらを総合的に確認して、批判的な意見を述べてください。
具体的には、以下の点において意見してください。
- プロンプトの内容に矛盾は生じていないか
- プロンプトは、返答を貰うのに十分な指示をしているか
- 返答は、要求に対して適切な内容を回答しているか
- 返答は、要求に対して望まれた出力の形式であるか
----------------------------------------------
以下は、「ユーザーの要求」と「プロンプト」と「AIモデルからの返答」です。
ユーザーの要求:
{self.user_requirement}
プロンプト:
{self.current_prompt}
AIモデルからの返答:
{self.generated_answer}
"""}]
response = state.generator.generate_response(role)
return response
## 好意的エージェント1
def com_agent_favor_1(self):
role = [{"role": "system", "content": f"""
あなたは、コメンテーターエージェント(好意的)です。
「ユーザーの要求」と、「プロンプト」と、「AIモデルからの返答」が与えられるので、それらを総合的に確認して、好意的な意見を述べてください。
具体的には、以下の点において意見してください。
- プロンプトの内容に矛盾は生じていないか
- プロンプトは、返答を貰うのに十分な指示をしているか
- 返答は、要求に対して適切な内容を回答しているか
- 返答は、要求に対して望まれた出力の形式であるか
----------------------------------------------
以下は、「ユーザーの要求」と「プロンプト」と「AIモデルからの返答」です。
ユーザーの要求:
{self.user_requirement}
プロンプト:
{self.current_prompt}
AIモデルからの返答:
{self.generated_answer}
"""}]
response = state.generator.generate_response(role)
return response
## 好意的エージェント2
def com_agent_favor_2(self):
role = [{"role": "system", "content": f"""
あなたは、コメンテーターエージェント(好意的)です。
「ユーザーの要求」と、「プロンプト」と、「AIモデルからの返答」が与えられるので、それらを総合的に確認して、好意的な意見を述べてください。
具体的には、以下の点において意見してください。
- プロンプトの内容に矛盾は生じていないか
- プロンプトは、返答を貰うのに十分な指示をしているか
- 返答は、要求に対して適切な内容を回答しているか
- 返答は、要求に対して望まれた出力の形式であるか
----------------------------------------------
以下は、「ユーザーの要求」と「プロンプト」と「AIモデルからの返答」です。
ユーザーの要求:
{self.user_requirement}
プロンプト:
"{self.current_prompt}
AIモデルからの返答:
{self.generated_answer}
"""}]
response = state.generator.generate_response(role)
return response
## 中立的エージェント
def com_agent_natural(self):
role = [{"role": "system", "content": f"""
あなたは、コメンテーターエージェント(中立的)です。
「ユーザーの要求」と、「プロンプト」と、「AIモデルからの返答」が与えられるので、それらを総合的に確認して、中立的な意見を述べてください。
具体的には、以下の点において意見してください。
- プロンプトの内容に矛盾は生じていないか
- プロンプトは、返答を貰うのに十分な指示をしているか
- 返答は、要求に対して適切な内容を回答しているか
- 返答は、要求に対して望まれた出力の形式であるか
----------------------------------------------
以下は、「ユーザーの要求」と「プロンプト」と「AIモデルからの返答」です。
ユーザーの要求:
{self.user_requirement}
プロンプト:
{self.current_prompt}
AIモデルからの返答:
{self.generated_answer}
"""}]
response = state.generator.generate_response(role)
return response
フロントエンド
アプリケーションのフロントエンドは、StreamlitというPythonのライブラリを使用して作成しました。
Streamlitは、PythonだけでWebアプリケーションを簡単に構築できるフレームワークです。
実装が簡単で、プロトタイプ作成に最適ということでStreamlitを選びました。
(自分がHTML、CSS、JavaScriptの知識に乏しいという理由も...💦)
5. 仕様
Minstrelアプリケーションの仕様を、手順を追って説明します。
1. スタート画面
こちらがスタート画面です。
左サイドバーには、基本情報、モジュールのON/OFFスイッチがあります。
2. プロンプト入力
中央の入力欄にプロンプトを入力したら、その右の赤いボタンを押します。(基本情報は入力しなくても問題ありません)
すると、プロンプトを改善するためにはどのような要素(モジュール)が必要か分析してくれます。
分析後、必要なモジュールは左サイドバーのスイッチで提示してくれます。ユーザー側でスイッチでモジュールのON/OFFを切り替えることも可能です。
3. モジュール内容生成
必要なモジュールが確定したら、中央の「2. モジュール内容を生成」ボタンを押します。
すると、ONにしたモジュールの内容をAIが生成してくれます。
各モジュールは内容を確認でき、イマイチだと思ったら再度生成することもできます。
モジュール内容が満足いくものであれば、右下の「3.モジュールを合成してプロンプト作成」ボタンを押します。
4. Minstrelプロンプトを作成
先ほど生成した複数のモジュールが結合し、Minstrelプロンプトとして左サイドバーに提示されます。これで、ユーザーの要求を反映させた詳細なプロンプトが作成できました。
さらに、Minstrelプロンプトを使用した生成AIの回答を、テストチャット欄に表示します。
このとき、思うような結果にならなかった場合、左下の「プロンプトを分析&改善」ボタンを押します。
5. プロンプト改善
Minstrelプロンプトが、Commentator、Reflectorの働きで改善されます。改善後の生成AIの回答は、先ほど同様に→のテストチャット欄に表示されます。
分析&改善ボタンは繰り返し実行することができます。実行回数はプロンプト内の"バージョン"に反映されます。
6. パフォーマンス評価
今回作成したMinstrelアプリケーションのパフォーマンスを評価するため、いくつかのベンチマークテストを行いました。
- GPQA:高度な推論能力、専門知識、そしてその知識を応用して複雑な問題を解決する能力を評価するためのベンチマーク
- GSM8k:小学生レベルの算数の文章問題を解く能力を評価するためのベンチマーク
- TruthfulQA:真実に基づいた回答を生成できるかどうかを評価するためのベンチマーク
各ベンチマークテストで、その他のプロンプトエンジニアリング手法(フレームワーク)と比較した結果が以下の通りです。 ※ 生成AIモデルは全てでGPT-4oを使用
フレームワークなしの場合はもちろんのこと他のフレームワークに比べても、精度向上を確認できました。
7. Minstrelを実装してみて
今回のようなWebアプリケーション開発は自分自身初めての体験で、戸惑いも多くありました。そもそも、生成AIをアプリケーション開発にどのように組み込むのか、APIとは何かといった基礎知識から学ぶ必要がありました。開発中も、プロンプトの微調整のために何度もコードを実行する際、APIの料金や使用レート制限に気を配ったり、APIの使い方を理解するために公式ドキュメントを調べたりと、苦労も少なくありませんでした。(プログラミング知識がもっと必要だと感じました💦)しかし、生成AIに触れる機会が増えるにつれて、その性能に驚きを覚え、以前は便利なツール程度に考えていた生成AIへの興味が深まりました。そして、生成AIを組み込んだアプリケーション開発が非常に楽しいと感じるようになりました。今回の経験は、私が生成AIの世界に足を踏み出す大きなきっかけになったと感じています!
参考
今回作成したMinstrelアプリケーション
Minstrel解説記事
Minstrel論文(再掲)
参考にしたコード(中国語で実装されているもの)