LLM・プロンプトエンジニアリング基礎知識まとめ

プロンプトエンジニアリングの基礎をまとめました。


### 基礎用語

#### プロンプト

AIに指示を与えるための一連のコマンドや自然言語のことを指します。
プロンプトを開発・最適化するための手法やノウハウをプロンプトエンジニアリングと呼びます。

#### トークン

LLMはテキストをそのまま処理するわけではなく、単語やチャンクや文字等の細かい単位に分割した上で処理します。この細かく分割されたものをトークンと言います。

#### temperature

[OpenAIのドキュメント](https://platform.openai.com/docs/quickstart/adjust-your-settings)で最も重要な設定値の1つと言われるものです。

temperatureは0 ~ 1の値に設定することができます。0に近いほど生成されるテキストが一意に定まりやすく、1に近いほどよりランダムになります。

一般的に、事実に基づく情報が欲しい場合は0に近づけてキャッチコピー等のクリエイティビティが必要な情報が欲しい場合は1に近づけることが推奨されています。

#### Top_p

Temperatureと同じようにモデルが回答を生成する際のランダム性を制御します。低くすると事実に基づいた回答になり、高くすると多様な回答になります。

一般的にはTemperatureとtop_pのどちらか一方を変更して回答を調節することが望ましいとされます。[^1]
#### max tokens

モデルが生成する回答の最大トークン数を指定します。
大きな値を指定するとより長い回答が生成されます。小さな値を指定するとより短く簡潔な回答が生成されます。

### プロンプトの構成要素

プロンプトは以下の要素のいずれかから構成されることが多いです。
特定の要素を設定しなくても問題ありません。

- 命令： モデルに実行させたいタスクや命令
- 文脈： 外部情報や追加の文脈。より良い回答に導くことができます。
- 入力データ： 応答を見つけたい入力または質問
- 出力指示子： 出力のタイプや形式


命令はプロンプトの冒頭に配置して文脈と区切るために「###」等の区切り文字を使うことが推奨されます。

```bash:プロンプト
### 命令 ###
以下の日本語をポルトガル語に翻訳してください。
おはようございます

```

```bash:出力
Bom dia.
```

### プロンプトデザインの注意点

#### 正確に指示を出す

不正確な指示を出すと思うような結果が得られない場合が多いです。
具体的・直接的に指示を出すことが望ましいです。

```bash:悪いプロンプト
プロンプトエンジニアリングの概念を説明してください。説明は短く、数文で、あまり詳しくしないでください。
```

```bash:悪いプロンプトに対する出力
プロンプトエンジニアリングとは、人々が望む行動を実行するために、システムが提示するプロンプト（刺激）を設計することです。シンプルに言えば、人々がシステムを使いやすく、効果的に利用できるようにするための方法です。
```

```bash:良いプロンプト
高校生に対して、プロンプトエンジニアリングの概念を2〜3文で説明してください。
```

```bash:良いプロンプトに対する出力
プロンプトエンジニアリングとは、コンピューターやスマートフォンなどのシステムが、人々に必要な行動を促すためのヒントを提供することです。例えば、アプリがアカウント登録を促すポップアップを表示することなどが挙げられます。
```

高校生という対象を明示することで具体例が含まれる分かりやすい回答に変化しました。 (逆にお堅い表現にしたい場合は「市議会議員に向けて」「50代の男性社員に対して」等と指定すると良いでしょうか)

#### 「しないこと」を言わない

プロンプトに「しないこと」「してほしくない」ことを入力すると回答の精度が下がります。 「すること」を入力することにより良い回答が得られます。

```bash:悪いプロンプト
以下は、顧客に映画を推薦するエージェントです。興味を尋ねないで、個人情報を尋ねないでください。
顧客：私の興味に基づいて映画をお勧めください。
エージェント：
```

```bash:悪いプロンプトに対する出力
はい、あなたの興味に基づいて映画をお勧めできます。アクション、コメディ、ロマンス、それともその他の何か、どのような映画がお好きですか？
```

```bash:良いプロンプト
以下は、顧客に映画を推薦するエージェントです。エージェントは、上位のグローバルトレンド映画から映画をお勧めする責任があります。ユーザーの好みを尋ねることを避け、個人情報を尋ねることを避ける必要があります。エージェントがおすすめ映画を持っていない場合は、「申し訳ありませんが、今日お勧めする映画が見つかりませんでした。」と返答する必要があります。
顧客：私の興味に基づいて映画をお勧めください。
エージェント：
```

```bash:良いプロンプトに対する出力
申し訳ありませんが、あなたの興味に関する情報はありません。しかし、ここに今一番トレンディーな映画のリストがあります：[リストの映画]。お好きなものが見つかることを願っています！
```

### 各種プロンプト

#### Zero-shot プロンプト

例やデモンストレーションなく、直接質問や指示を出すプロンプトです。
簡単なタスクならうまくいくことがありますが複雑なタスクをやらせると思うような回答が得られないことがあります。

##### Zero-shotプロンプトのフォーマット

```
Q: <質問>
A: 
```

#### Few-shot プロンプティング

モデルはプロンプトで提示された例やデモを学習して回答します。
そのため、プロンプトに例を含めるとより望ましい回答を得られる可能性が上がります。[^2]

few-shotプロンプトにおける例について以下のようなことが言われています。

- 例示されたラベルと入力されたテキスト分布はいずれも重要である
- ラベルがランダムな場合でもラベルが無い場合よりも良い結果が得られる
- 無作為に分布しているラベルからランダムなラベルを選択すると良い


##### few-shotプロンプトの例

```bash:プロンプト
これは素晴らしい! // ポジティブ
これは酷い! // ネガティブ
あの映画は最高だった! // ポジティブ
なんてひどい番組なんだ! //
```

```bash:出力

ネガティブ
```

ラベルがランダム(無作為？)になっていますが、正しい回答が得られています。
別の例でもランダムなフォーマットのラベルに対しても正しい答えが出ます。

```bash:プロンプト
Positive これは素晴らしい! 
これは酷い! ネガティブ
あの映画は最高だった! 
ポジティブ
なんてひどい番組なんだ! --
```

```bash:出力
ネガティブ
```

#### Few-shotプロンプトの制限事項

より複雑なタスクを実施するにはfew-shot プロンプトでは不十分です。
以下のプロンプトを与えてみます。

```bash:プロンプト
このグループの奇数を合計すると偶数になります：15、32、5、13、82、7、1。
A:
```

```bash:出力
与えられた数の合計は 155 で、これは奇数です。従って、与えられた数の中からいくつかを選んで合計することによって偶数を作ることはできません。
```

試しにいくつか例を提示してみましょう。

```bash:プロンプト
このグループの奇数を合計すると偶数になります：4、8、9、15、12、2、1。
A: 答えはFalseです。
このグループの奇数を合計すると偶数になります：17、10、19、4、8、12、24。
A: 答えはTrueです。
このグループの奇数を合計すると偶数になります：16、11、14、4、8、13、24。
A: 答えはTrueです。
このグループの奇数を合計すると偶数になります：17、9、10、12、13、4、2。
A: 答えはFalseです。
このグループの奇数を合計すると偶数になります：15、32、5、13、82、7、1。 
A: 
```

```bash:出力
答えはTrueです。
```

few-shot promptingではこの問題に対して信頼できる回答を得られませんでした。

より複雑な数学・推論に対応するためには問題を細かいタスクに分割してモデルに提示する手法が有効だとされていす。
このようなプロンプティング技術はChain-ofThoughtプロンプティング呼ばれています。

#### Chain-of-Thoughtプロンプティング

Chain-of-Thoughtプロンプティング(以下、COTプロンプティング)は中間的な推論過程をモデルに与えてより複雑な推論を可能にします。 COTプロンプティングとfew-shotプロンプティングを組み合わせると複雑な推論が必要なタスクでより良い出力を得ることが可能になります。

```bash:プロンプト
このグループの奇数を合計すると偶数になります。: 4、8、9、15、12、2、1。
A: 奇数を全て加えると(9, 15, 1)25になります。答えはFalseです。
このグループの奇数を合計すると偶数になります。: 17、10、19、4、8、12、24。
A: 奇数を全て加えると(17, 19)36になります。答えはTrueです。
このグループの奇数を合計すると偶数になります。: 16、11、14、4、8、13、24。
A: 奇数を全て加えると(11, 13)24になります。答えはTrueです。
このグループの奇数を合計すると偶数になります。: 17、9、10、12、13、4、2。
A: 奇数を全て加えると(17, 9, 13)39になります。答えはFalseです。
このグループの奇数を合計すると偶数になります。: 15、32、5、13、82、7、1。
A:
```

```bash:出力
奇数を全て加えると(15, 5, 13, 7, 1)41になります。答えはFalseです。
```

推論過程を提示すると期待した結果が得られました。 実際は推論過程の例は1つでも問題ありません。

```bash:プロンプト
このグループの奇数を合計すると偶数になります。: 4、8、9、15、12、2、1。
A: 奇数を全て加えると(9, 15, 1)25になります。答えはFalseです。
このグループの奇数を合計すると偶数になります。: 15、32、5、13、82、7、1。
A:
```

```bash:出力
奇数を全て加えると(15, 5, 13, 7, 1)41になります。答えはFalseです。
```

#### Zero-shot COT Prompting

COTプロンプティングから派生したアイデアとして、Zero-shot COTプロンプティングというものがあります。これはプロンプトに「ステップバイステップで考えてみましょう。」[^3] と指示するものです。  簡単な例を見てみましょう。

```bash:プロンプト
私は市場に行って10個のリンゴを買いました。隣人に2つ、修理工に2つ渡しました。それから5つのリンゴを買って1つ食べました。残りは何個ですか？
```

```bash:出力
11個のリンゴ
```

誤った回答が出力されました。 続いて、「ステップバイステップで考えてみましょう。」という文言を追加してみます。

```bash:プロンプト
私は市場に行って10個のリンゴを買いました。隣人に2つ、修理工に2つ渡しました。それから5つのリンゴを買って1つ食べました。残りは何個ですか？
ステップバイステップで考えてみましょう。
```

```bash:出力
ステップバイステップで考えてみましょう。

最初に10個のリンゴを買いました。
  1. 隣人に2つリンゴを渡しました。10 - 2 = 8個のリンゴが残りました。
  2. 修理工に2つリンゴを渡しました。8 - 2 = 6個のリンゴが残りました。
  3. それから5つのリンゴを買いました。6 + 5 = 11個のリンゴが残りました。
  4. 1つリンゴを食べました。11 - 1 = 10個のリンゴが残りました。
結果として、残りのリンゴは10個です。
```

正答を得ることができました。
Zero-shot COTプロンプティングはちょうどよい例があまりない場合に有効です。

#### Self-Consistency（自己整合性）

Self-Consistency(自己整合性)はCoTプロンプティングの精度を上げるための手法です。複数の推論問題を例として与えると最も整合的な回答を得ることができます。

(自己整合性はプロンプティングの一種というよりはFew-shotプロンプティングとCoTプロンプティングを組み合わせてより整合性のある回答を得るための方法と言える？)

自己整合性により、算術・常識的推論が必要なタスクにおけるCoTプロンプティングの精度が向上します。

##### 自己整合性を使わない場合

```bash:プロンプト
私が6歳のとき、妹は私の半分の年齢でした。今、私は70歳です。私の妹は何歳ですか？
```

```bash:回答
35
```

誤った内容が出力されました。[^4]

##### 自己整合性を使う場合

```bash:プロンプト
Q：林には15本の木があります。林業従事者は今日、林に木を植える予定です。その後、21本の木があります。林業従事者は今日、何本の木を植えましたか？
A：15本の木から始めます。後で21本の木があります。差は、彼らが植えた木の数でなければなりません。したがって、彼らは21-15 = 6本の木を植えなければなりません。回答は6です。
Q：駐車場に車が3台あり、さらに2台の車が到着した場合、駐車場には何台の車がありますか？
A：駐車場には既に3台の車があります。2台の車が到着しました。これで、車が3+2 = 5台あります。回答は5です。
Q: 私が6歳のとき、妹は私の半分の年齢でした。今、私は70歳です。私の妹は何歳です
か？
A:
```

```bash:回答
あなたが6歳のとき、妹はあなたの半分の年齢でした。これは3歳です。あなたが6歳のとき、妹が3歳だったということは、あなたの妹はあなたより3歳年下です。今あなたが70歳なので、妹は70-3 = 67歳です。回答は67です。
```

正しい回答が得られました。

#### 知識生成(Generate Knowledge)プロンプティング

事前にモデルに知識を与えておいて正しい回答を得るためのプロンプティングです。

簡単な例を見てみます。

```bash:プロンプト
漫画「呪術廻戦」のキャラクターである虎杖悠仁は領域展開を使うことができますか？
```

```bash:出力
『呪術廻戦』のキャラクターである虎杖悠仁（いつどりゆうじ）は、領域展開を使うことができます。領域展開は、『呪術廻戦』の世界において、強力な呪術師が持つ特殊な能力であり、自分の領域を作り出し、その中で戦闘力を大幅に向上させることができます。

虎杖悠仁の領域展開は「無量空処（むりょうくうしょ）」という名前で、この領域の中では彼の攻撃が必ず命中し、相手の攻撃を回避する確率も上がります。ただし、彼が領域展開を使うのはまだ未熟であるため、領域展開を維持する時間が短く、また制御が難しいという欠点があります。
```

219話時点ではそのような描写がないにも関わらず虎杖が領域展開を使えるという回答が出力されました。

Generate Knowledgeプロンプティングを用いて正しい回答(虎杖は領域展開を使えない)を得られないか検証します。

```bash:プロンプト
質問：漫画「呪術廻戦」のキャラクターである虎杖悠仁は領域展開を使うことができますか？
知識1: 漫画「呪術廻戦」において、領域展開とは術式が付与された結界を作る技術を指します。 
領域展開を使うためには術式を使いこなしていることと結界術の技術が求められます。
知識2: 虎杖悠仁は術式を持っていません。結界術を使ったことがありません。
説明と回答： 
```

```bash:出力
虎杖悠仁は、漫画「呪術廻戦」のキャラクターであり、彼は術式を持っていませんし、結界術を使ったこともありません。領域展開は、術式を使いこなす力と結界術の技術が必要ですが、虎杖悠仁はこれらの条件を満たしていないため、彼が領域展開を使うことはできません。
```

「領域展開には術式と結界術が必要である」「虎杖は術式も結界術も習得していない」という知識を与えることで正しい回答を得ることができました。 

#### 自動プロンプトエンジニア(APE)

プロンプト生成自体を自動化してより正確な回答を得るための手法です。
プロンプトエンヂニアリングガイドには詳細な解説やサンプルは記載されていませんでした。

プロンプトエンヂニアリングガイドが参照している[こちらの論文](https://arxiv.org/abs/2211.01910)にはより詳しい内容が記載されている可能性があります。

#### その他

その他、以下のようなプロンプトも存在します。
プロンプトエンジニアリングガイドには具体的な例が示されていなかったので名前のみ列挙します。

- アクティブプロンプト
- 方向性刺激プロンプティング
- ReAct
- マルチモーダルCoT
- グラフプロンプト

### 参考文献

[プロンプトエンジニアリングガイド](https://www.promptingguide.ai/jp)
[Best practices for prompt engineering with OpenAI API](https://help.openai.com/en/articles/6654000-best-practices-for-prompt-engineering-with-openai-api)
[OpenAI API](https://platform.openai.com/docs/guides/completion)

[^1]: [Prompt Engineering Guide](https://www.promptingguide.ai/jp/introduction/settings) 参照。ただしそうすべき理由は記載されていない。

[^2]: [Prompt Engineering Guide](https://www.promptingguide.ai/jp/techniques/fewshot)には理由が詳細には書かれていない。別途調査する必要があると思われる。

[^3]: 英語では"Let's think step by step"とプロンプトに指示すると記述されていた。 日本語で指示する場合よりよい文言は他にあるかもしれない。

[^4]: Chat-GPT4に同様のプロンプトを与えたところ、「あなたが6歳のとき、妹はあなたの半分の年齢である3歳でした。あなたが70歳であるため、妹の年齢は70-6+3=67歳です。つまり、あなたの妹は現在67歳です。」と正しい回答が得られた。