簡単に高性能なプロンプトが作成できる!?OpenAIのプロンプトジェネレータついて

今回はOpenAIから提供されているプロンプトジェネレーターの実装方法についてご紹介します！

このプロンプトジェネレーターは、雑なプロンプトをメタプロンプトを活用することによって、精度の高いプロンプトに変換することができる優れたツールで、比較的簡単に実装することができます。

# プロンプトジェネレータの実装方法
OpenAIから提供されているコード：https://platform.openai.com/docs/guides/prompt-generation

OpenAIから提供されているコードをそのまま使用しても良いのですが、英語でプロンプトが生成されてしまうことがあるため、今回は日本語訳されたメタプロンプトを使用します

OpenAIから提供されているメタプロンプト日本語訳ver  ：https://github.com/Sunwood-ai-labs/MysticLibrary/blob/main/prompts/meta/openai_meta_prompt/openai_meta_prompt_JP.md


日本語訳verに差し替えたものがこちら

```python
from openai import OpenAI
import os

client = OpenAI()
client.api_key = os.environ['OPENAI_API_KEY']

META_PROMPT = """
タスクの説明または既存のプロンプトを基に、言語モデルがタスクを効果的に完了するための詳細なシステムプロンプトを作成してください。

# ガイドライン

- タスクを理解する: 主な目的、目標、要件、制約、期待される出力を把握する。
- 最小限の変更: 既存のプロンプトが提供されている場合、単純なものであれば改善する。複雑なプロンプトの場合は、元の構造を変更せずに明確さを向上させ、不足している要素を追加する。
- 結論の前に推論**: 結論を出す前に推論のステップを促す。注意！ユーザーが推論を後で行う例を提供した場合は、順序を逆にすること！例を結論から始めないこと！
    - 推論の順序: プロンプトの推論部分と結論部分（特定のフィールド名）を指摘する。それぞれについて、実行される順序を決定し、逆転が必要かどうかを判断する。
    - 結論、分類、または結果は常に最後に表示されるべきである。
- 例: 役立つ場合は高品質の例を含める。複雑な要素には[角括弧]内のプレースホルダーを使用する。
   - どのような種類の例を含める必要があるか、何個必要か、プレースホルダーが有益なほど複雑かどうかを判断する。
- 明確さと簡潔さ: 明確で具体的な言葉を使用する。不必要な指示や平凡な表現を避ける。
- フォーマット: 読みやすさのためにマークダウン機能を使用する。特に要求されない限り、```コードブロックは使用しないこと。
- ユーザーコンテンツの保持: 入力タスクやプロンプトに広範なガイドラインや例が含まれている場合は、それらを完全に、または可能な限り近い形で保持する。曖昧な場合は、サブステップに分解することを検討する。ユーザーが提供した詳細、ガイドライン、例、変数、プレースホルダーを保持する。
- 定数: プロンプトインジェクションの影響を受けないため、ガイド、ルーブリック、例などの定数はプロンプトに含める。
- 出力フォーマット: 最も適切な出力フォーマットを詳細に明示する。これには長さと構文（例：短文、段落、JSONなど）を含める。
    - 明確に定義された構造化データ（分類、JSONなど）を出力するタスクの場合、JSONでの出力を優先する。
    - JSONは明示的に要求されない限り、コードブロック（```）で囲まないこと。

最終的に出力するプロンプトは、以下の構造に従うべきです。追加のコメントは含めず、完成したシステムプロンプトのみを出力してください。特に、プロンプトの冒頭や末尾に追加のメッセージを含めないでください（例：「---」など）。

[タスクを簡潔に説明する指示 - これはプロンプトの最初の行にあるべきで、セクションヘッダーは不要]

[必要に応じて追加の詳細]

[詳細なステップのためのオプションのセクション（見出しまたは箇条書き）]

# ステップ [オプション]

[オプション: タスクを達成するために必要な詳細なステップの内訳]

# 出力フォーマット

[出力のフォーマット方法を具体的に指定する。応答の長さ、構造（例：JSON、マークダウンなど）を含む]

# 例 [オプション]

[オプション: 1〜3の明確に定義された例。必要に応じてプレースホルダーを使用する。例の開始と終了、入力と出力を明確に示す。]
[例が現実的な例よりも短い場合は、実際の例がどのように長く/短く/異なるべきかを（）内で説明する。そしてプレースホルダーを使用すること！]

# 注意事項 [オプション]

[オプション: エッジケース、詳細、特に重要な考慮事項を呼び出すまたは繰り返す領域]
""".strip()

def generate_prompt(task_or_prompt: str):
  completion = client.chat.completions.create(
      model="gpt-4o",
      messages=[
          {
              "role": "system",
              "content": META_PROMPT,
          },
          {
              "role": "user",
              "content": "タスク、ゴール、もしくは現在のプロンプト:\n" + task_or_prompt,
          },
      ],
  )

  return completion.choices[0].message.content
```

ここまで準備できたら、実際に雑なプロンプトを入力してみましょう。  
今回は童話が掲載されているwebサイトのURLを入力するとその物語のタイトル、主人公名、要約を出力させるプロンプトを作ってみます。
```python
output_prompt=generate_prompt("次に入力されるURLから内容を取得し、キー名titleに物語のタイトル、main_characterに主人公名、summaryに物語の要約を含むJSON形式で出力してください。")
print(output_prompt)
```


実行結果


```
URLから物語の内容を取得し、その情報をJSON形式で整理してください。JSONは、物語のタイトル、主人公の名前、および物語全体の要約を含むべきです。

# ステップ

1. 指定されたURLから物語の内容を取得します。
2. 物語の内容を分析し、以下の情報を抽出します：
   - title: 物語のタイトル
   - main_character: 主人公の名前
   - summary: 物語の要約、2〜3文で重要なプロットポイントを含む
3. 上記の情報をプロンプトされたJSON形式に従って整理します。

# 出力フォーマット

JSON形式で出力し、以下のキーを含めます：
- `title`: 物語のタイトル（文字列）
- `main_character`: 主人公の名前（文字列）
- `summary`: 物語の要約（文字列）

# 例

入力されたURLから次のような物語の内容を取得した場合：

URL内容: "『不思議の国のアリス』は、ルイス・キャロルによって書かれた物語で、アリスという少女がウサギの穴を通って奇妙な世界に迷い込む話です。彼女は面白いキャラクターに出会い、さまざまな冒険をします。物語は彼女が元の世界に戻ることで終わります。"

出力例:
json
{
  "title": "不思議の国のアリス",
  "main_character": "アリス",
  "summary": "アリスという少女がウサギの穴を通って奇妙な世界に迷い込む物語。 彼女は面白いキャラクターに出会い、冒険を経て元の世界に戻ります。"
}


# 注意事項

- 物語の要約は、核心的な内容を簡潔に伝えるものでなければなりません。
- 主人公の名前は、物語の進行において中心的な役割を果たす人物の名前である必要があります。
- インターネットからの直接データ取得は行わず、提供されたテキストデータに基づいて情報を整理してください。
```

プロンプトが生成出来ました。  
このように、出力例や注意事項などもユーザーの意図をくみ取って勝手に生成してくれます。


実際にこのプロンプトを使用してみましょう！


```python
from openai import OpenAI
import os

client = OpenAI()
client.api_key = os.environ['OPENAI_API_KEY']

PROMPT='''
URLから物語の内容を取得し、その情報をJSON形式で整理してください。JSONは、物語のタイトル、主人公の名前、および物語全体の要約を含むべきです。

# ステップ

1. 指定されたURLから物語の内容を取得します。
2. 物語の内容を分析し、以下の情報を抽出します：
   - title: 物語のタイトル
   - main_character: 主人公の名前
   - summary: 物語の要約、2〜3文で重要なプロットポイントを含む
3. 上記の情報をプロンプトされたJSON形式に従って整理します。

# 出力フォーマット

JSON形式で出力し、以下のキーを含めます：
- `title`: 物語のタイトル（文字列）
- `main_character`: 主人公の名前（文字列）
- `summary`: 物語の要約（文字列）

# 例

入力されたURLから次のような物語の内容を取得した場合：

URL内容: "『不思議の国のアリス』は、ルイス・キャロルによって書かれた物語で、アリスという少女がウサギの穴を通って奇妙な世界に迷い込む話です。彼女は面白いキャラクターに出会い、さまざまな冒険をします。物語は彼女が元の世界に戻ることで終わります。"

出力例:
json
{
  "title": "不思議の国のアリス",
  "main_character": "アリス",
  "summary": "アリスという少女がウサギの穴を通って奇妙な世界に迷い込む物語。 彼女は面白いキャラクターに出会い、冒険を経て元の世界に戻ります。"
}


# 注意事項

- 物語の要約は、核心的な内容を簡潔に伝えるものでなければなりません。
- 主人公の名前は、物語の進行において中心的な役割を果たす人物の名前である必要があります。
- インターネットからの直接データ取得は行わず、提供されたテキストデータに基づいて情報を整理してください。
'''

completion = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {
            "role": "system",
            "content": PROMPT,
        },
        {
            "role": "user",
            "content": "https://ja.wikipedia.org/wiki/%E7%94%9F%E6%88%90%E7%9A%84%E4%BA%BA%E5%B7%A5%E7%9F%A5%E8%83%BD",
        },
    ],
)

print(completion.choices[0].message.content)
```

出力結果
```
{
  "title": "シンデレラ",
  "main_character": "シンデレラ",
  "summary": "シンデレラは、継母と義姉たちに虐げられている不幸な少女です。魔法の助けを得て舞踏会に参加し、王子の心を射止めます。最後にガラスの靴を通じて王子と再会し、幸せに暮らします。"
}
```
命令通り、指定されたJSON形式で出力されてますね。  
このように雑なプロンプトでも、プロンプトジェネレータを使用することでより精度の高いプロンプトを作成することが出来ます。  

比較的簡単に実装できるのでプロンプトを作成する際は是非利用してみてください！