ChatGPTの性能を引き出すテクニックまとめ

# 概要
ChatGPTと親友になるためのテクニックをまとめています。
ゴリゴリのエンジニアよりはどのユーザーにも読めるような記事にしたかったので、理論は少なめです。

# プロンプトエンジニアリング

自然言語処理の概念の一つにプロンプトエンジニアリングと呼ばれるものがあります。

プロンプトエンジニアリングは、人間とAIが対話する際のプロンプト（質問や指示）を設計、最適化、評価する技術分野です。これは、AIが人間の質問に対して適切な応答を提供するために必要なスキルとなってきます。細かく3つのフェーズに分けていますが、それぞれの概要は以下の通りです。

**プロンプトの設計**：AIに対する質問や指示をどのように表現するかを決定します。これは、AIが理解できる形式で質問を表現するために必要となります。

**プロンプトの最適化**：AIが最も適切な応答を提供できるように、プロンプトを調整または改善します。これは、AIのパフォーマンスを向上させるために必要となります。

**プロンプトの評価**：AIの応答が適切かどうかを評価します。これは、AIのパフォーマンスを評価し、必要に応じて改善するために必要となります。

プロンプトエンジニアリングは、AIが人間の質問に対して適切な応答を提供するための重要なスキルであり、AIのパフォーマンスを向上させるための重要な手段となります。

AIを作るのではなく、AIに配慮するというスタンスになります。
AIを作るのとは異なり、特別なスキルは習得するのではなく、いくつかのポイントを押さえておくことが重要となります。

# ChatGPTが苦手なこと

- 学習した時点以降(2021年までの情報を用いている)の情報は持っていない
- 外部データソースを使用できない
- 情報の正確性が保証できない
- クイズやなぞなぞなど柔軟な思考が必要なもの

これらは後述する手法を利用することである程度解消できることがあります。

# 質問に関するテクニック

## 質問を具体的にする

質問や指示を与える場合は、曖昧な文章にするよりも、5W1Hなどの条件を指定した方が意図した結果を得られることがあります。

```:プロンプト1(抽象的な質問)
バナナの名産地はどこですか？
```

```:回答1(抽象的な質問)
バナナは、世界中で栽培されている果物であり、多くの国や地域で生産されています。
一部の主要なバナナの生産地域には以下のようなものがあります。

1. ラテンアメリカ: エクアドル、コロンビア、コスタリカ、ホンジュラス、グアテマラなど、中南米の国々が主要なバナナの生産地として知られています。
2. アフリカ: ウガンダ、コートジボワール、ガーナ、カメルーンなど、アフリカの一部の国々もバナナの生産が盛んです。
3. アジア: フィリピン、インド、中国、タイなど、アジアの一部の国々もバナナの生産地として重要です。

ただし、バナナの栽培は気候条件に依存するため、他の地域でも一部の品種が生産されています。
特に温暖な気候や湿度の高い地域がバナナの生育に適しています。

バナナは世界中で広く消費されている人気のある果物であり、多くの国や地域で栽培・輸出されているため、多様な生産地が存在します。
```

```:プロンプト2(具体的な質問)
日本国内のバナナの名産地はどこですか？
```

```:回答2(具体的な質問)
日本国内では、主に沖縄県がバナナの主要な生産地として知られています。
沖縄県は温暖な気候と適した環境条件を持ち、バナナの栽培に適しています。

沖縄県では、主に台湾から導入された種苗が使用され、バナナの栽培が行われています。
沖縄のバナナは、温暖な気候の影響を受けて成長し、比較的小ぶりながらも風味豊かな特徴を持っています。

他の地域でもバナナの一部の栽培が行われていますが、日本国内での商業的なバナナの生産は主に沖縄県に集中しています。
```

## 質問や指示を分解する

一つの質問に複数の要素を詰め込みすぎると出力の精度が落ちることがあります。
下の例は三角関数の変換と四則演算を組み合わせた場合に計算にミスが出る一例です。

```:プロンプト1(1つの質問)
sin30 + cos30 =
```
```:回答1(1つの質問)
sin30° + cos30° = (√3/2) + (√3/2) = √3
```

三角関数の変換と四則演算を別々の質問にすることで解消できることがあります。
```:プロンプトと回答(質問の分解) ※複数のプロンプトの結果を表示しています
================
# 質問1
sin30 =

# 回答1
sin30° = 0.5
================
# 質問2
cos30 =

# 回答2
cos30° = √3/2
================
# 質問3
0.5 + √3/2 =

# 回答3
0.5 + √3/2 = (1 + √3)/2
================
```

## 同じ質問をする
同じ質問でも返答が変わることがあります。
この仕様を利用することで、回答に一貫性があるか確認したり、情報に間違いがないかを確認できるようになります。

# 情報の付与に関するテクニック

## 例を提示する(Zero-Shot Prompting / Few-Shot Prompting)
ChatGPTは強力なLLMを使用しており、ある程度の質問や指示では例を挙げなくても精度の高い出力します。
このように例を提示しないプロンプトを**Zero-Shot Prompting**といいます。

一方、複雑なタスクにおいては例を提示しない場合に精度が低くなることもあります。
このような場合は例をいくつか提示することで精度が高くなることがあります。
例を提示することで精度を向上させる手法を**Few-Shot Prompting**といいます。

```:プロンプト1(例なし：Zero-Shot Prompting)
二つの単語の母音の並びが全く同じことを「韻を踏んでいる」と言います。
二つの単語が韻を踏んでいるか判定してもらいます。

「エンジニア」と「返事しな」は韻を踏んでいますか？
```

```:回答1(例なし：Zero-Shot Prompting)
「エンジニア」と「返事しな」の母音の並びを考えてみましょう。

「エンジニア」の母音の並びは「エ」「イ」「ア」です。
「返事しな」の母音の並びは「エ」「イ」「シ」「ナ」です。

両単語の最後の母音が一致していることから、通常は韻を踏んでいると言えます。
しかし、「返事しな」は「シ」「ナ」が追加的に存在するため、完全には韻を踏んでいないとも言えます。
ですので、完全な韻を求める場合には「エンジニア」と「返事しな」は韻を踏んでいないと判断するべきです。
しかし、一部韻を踏んでいると考えることもできます。

この質問の答えは、ある程度、詩や歌の作り方や、あなたが韻をどの程度重視するかなど、文脈や視点によるところが大きいです。
```

```:プロンプト2(例あり：Few-Shot Prompting)
二つの単語の母音の並びが全く同じことを「韻を踏んでいる」と言います。
二つの単語が韻を踏んでいるか判定してもらいます。

例1：「エンジニア」と「電池見た」は母音の並びが「エンイイア」と「エンイイア」で一致しているので、韻を踏んでいます
例2：「エンジニア」と「身に染みた」は母音の並びが「エンイイア」と「イイイイア」で一致していないので、韻を踏んでいません
例3：「エンジニア」と「延期した」は母音の並びが「エンイイア」と「エンイイア」で一致しているので、韻を踏んでいます

「エンジニア」と「返事しな」は韻を踏んでいますか？
```

```:回答2(例あり：Few-Shot Prompting)
「エンジニア」の母音の並びは「エ」「イ」「ア」です。
「返事しな」の母音の並びは「エ」「イ」「ア」です。

この定義に基づくと、母音の並びが全く同じなので、「エンジニア」と「返事しな」は韻を踏んでいると言えます。
```

## 知識を付与する

一般常識を解かせる(commonsense reasoning task)場合に、追加の知識を付与することで精度が向上します。
LLMの幅広い知識からドメインを絞ることができ、入力の知識を利用できるためです。

### Generated Knowledge Prompting
**Generated Knowledge Prompting**は[論文](https://arxiv.org/abs/2110.08387)として公開されており、知識を付与するための手法の一つです。
問題に関する知識を自ら生成するステップと、生成した知識を組み込んで回答するステップに分かれています。

:::note warn
Generated Knowledge Promptingについては、細かい制御方法が理解でき次第追記させていただきます。
:::


# 回答に関するテクニック

## 回答のコンセプトを指定する

どんなコンセプトで出力するかを指定することができます。
以下は一例となります。
- 「小説風に出力して」
-  「(コードを)コメント文多めで出力して」
-  英語で出力して

下の例では「エンジニアとは何か」を訪ねようとした際の対話になります。
曖昧にすると広い範囲での回答が得られますが、具体的に「小学生向けの説明」という要素を提示してあげることで精度が高まります。
また、曖昧にすることで回答の幅を広げることも選択肢となりますので目的に応じた粒度をプロンプトで与えてあげる必要があります。

```:プロンプト1(出力指定なし)
エンジニアとは何ですか？
```

```:回答1(出力指定なし)
エンジニアとは、科学的な原理や数学的な方法を用いて、実世界の問題を解決するために設計・開発・構築する専門家です。
エンジニアは、さまざまな分野で活躍し、例えばソフトウェアエンジニア、電気エンジニア、機械エンジニア、土木エンジニアなどの特定の領域に特化することがあります。

エンジニアは、科学的な原理や理論、技術的なスキルを応用して、問題解決のためのシステムや製品を設計・開発します。
彼らは、計画立案、設計、プロトタイプの作成、テスト、製品の製造や実装、保守など、開発ライフサイクルのさまざまな段階に携わることがあります。

エンジニアは、クリエイティブな問題解決能力、科学的な思考、技術的な専門知識、チームワーク、コミュニケーションスキルなどを持っています。
彼らは新しい技術やイノベーションを生み出し、社会や産業の発展に貢献する重要な役割を果たしています。
```

```:プロンプト2(出力指定あり)
エンジニアとは何ですか？
小学生向けに説明してください。
```
```:回答2(出力指定あり)
エンジニアは、技術的な問題を解決するスーパーヒーローのような存在です！
彼らは、科学や数学を使って、私たちの日常生活をより便利で楽しくするためのものを作ります。

例えば、ゲームやアプリを作るエンジニアは、私たちが楽しんで遊べるゲームや便利なアプリを作ります。
また、建物や橋を作るエンジニアは、私たちが安全に使える建物や便利な交通手段を作ります。

エンジニアは、アイデアを形にするために図面や計算を使い、実際にモノを作り上げます。
彼らはクリエイティブな考え方や問題解決の能力を持っていて、新しいものを作り出すのが得意です。

エンジニアになるためには、好奇心を持ち、学ぶことや試行錯誤を楽しむことが大切です。
そして、困ったことに対して「どうすれば解決できるかな？」と考えることがエンジニアの仕事です。

将来エンジニアになりたいなら、勉強や実験を楽しんで、数学や科学の勉強を頑張ってください。
そうすれば、あなたも素晴らしいエンジニアになることができます！
```

## 回答の文字数を制限する

ChatGPTが1回の応答でどれだけの情報を出力するかはChatGPTが自動で判断しています。
自分が知りたい情報の粒度に合わせて、文字数を指定することで回答の要点がわかりやすくなります。

代表的な制限できる要素としては、文字数、行数、トークン数などがあげられます。
文字数に制限をかけすぎると文章が読みづらくなることもありますので適切に設定を行いましょう
文字数の場合日本語だとあまり精度が高くないので、望んだ出力量になるようほかの条件でも試してみるのが良いかと思います。

```:プロンプト
エンジニアとは何ですか？
3行で説明してください。
```

```:回答
エンジニアは、科学や数学を使って問題を解決する専門家です。
彼らは新しいものを作り出し、私たちの生活を便利にしたり楽しくしたりします。
勉強や好奇心を持っている人がなれます！
```

## 複数の回答を生成させる

プロンプトで生成する回答の数を指定することができます。

```:プロンプト
バナナの名産地を5つ提示してください
```

```:回答
以下に、バナナの主な名産地をいくつか挙げます。

1. エクアドル: エクアドルは、世界最大のバナナの輸出国であり、高品質なバナナの生産地として知られています。
2. コロンビア: コロンビアも大量のバナナを生産し、世界のバナナ市場で重要な役割を果たしています。
3. フィリピン: フィリピンはアジアで主要なバナナの生産国であり、多くのバナナが輸出されています。
4. コスタリカ: コスタリカは中米で主要なバナナの生産地であり、高品質のバナナを供給しています。
5. ホンジュラス: ホンジュラスも中米で主要なバナナの生産国であり、バナナ産業が重要な経済的役割を果たしています。

これらは主要なバナナの生産地の一部ですが、世界中には他にも多くの国や地域でバナナの栽培が行われています。
```

## 出力をフォーマット化/テンプレ化する
出力の形式を指定することで、その形式に沿った出力だけしてくれるようになります。
必ず出力の形を固定したい場合や、大量の質問に対して同じ出力を期待したい場合に有効です。

記号を使用してChatGPTが理解しやすいようフォーマットを作る必要があります。
- 大項目、中項目、小項目がわかるよう括弧を使い分ける
- 箇条書きにする
- ここからここまでの範囲がわかるよう記号で区切りを入れる
  - 連続する記号の数は2のn乗個がよいという噂

### フォーマット
```:フォーマット用プロンプト
【要件】
 - 以後の会話では、あなたは要約BOTとして振る舞います
 - 「要約の難しさ」と「元の文章の要約」を出力してもらいます
 - 要約の難しさは1から10の10段階で評価されます。
【出力形式】
出力形式は以下のフォーマットとします。
--------
要約の難しさ：(要約の難しさ)

要約：
(要約)
--------
```

```:プロンプト例1
エンジニアとは、科学的な原理や数学的な方法を用いて、実世界の問題を解決するために設計・開発・構築する専門家です。
エンジニアは、さまざまな分野で活躍し、例えばソフトウェアエンジニア、電気エンジニア、機械エンジニア、土木エンジニアなどの特定の領域に特化することがあります。
```

```:回答1
要約の難しさ：2

要約：
エンジニアは、科学的な原理や数学的な方法を用いて、実世界の問題を解決する専門家です。さまざまな分野で活躍し、ソフトウェアエンジニア、電気エンジニア、機械エンジニア、土木エンジニアなどの特定の領域に特化することがあります。
```

```:プロンプト例2
エンジニアとは、科学的な原理や数学的な方法を用いて、実世界の問題を解決するために設計・開発・構築する専門家です。
エンジニアは、さまざまな分野で活躍し、例えばソフトウェアエンジニア、電気エンジニア、機械エンジニア、土木エンジニアなどの特定の領域に特化することがあります。

エンジニアは、科学的な原理や理論、技術的なスキルを応用して、問題解決のためのシステムや製品を設計・開発します。
彼らは、計画立案、設計、プロトタイプの作成、テスト、製品の製造や実装、保守など、開発ライフサイクルのさまざまな段階に携わることがあります。

エンジニアは、クリエイティブな問題解決能力、科学的な思考、技術的な専門知識、チームワーク、コミュニケーションスキルなどを持っています。
彼らは新しい技術やイノベーションを生み出し、社会や産業の発展に貢献する重要な役割を果たしています。
```

```:回答2
要約の難しさ：4

要約：
エンジニアは、科学的な原理や数学的な方法を用いて、実世界の問題を解決するために設計・開発・構築する専門家です。エンジニアは、ソフトウェアエンジニア、電気エンジニア、機械エンジニア、土木エンジニアなど、特定の領域に特化することもあります。彼らは科学的な原理や技術的なスキルを応用し、システムや製品の設計・開発を行います。エンジニアは、問題解決のための計画立案から製造・実装・保守まで、開発のさまざまな段階に関与します。彼らはクリエイティブな問題解決能力や科学的な思考、技術的な専門知識、チームワーク、コミュニケーションスキルを持っています。彼らは新しい技術やイノベーションを生み出し、社会や産業の発展に貢献しています。
```

### JSON形式での出力
ChatGPTではJSON形式で出力するよう指定するとコードブロック上にJSONを出力します。
キー名も指定することで任意のデータを生成可能になります。
※JSONだと動作するが、Jsonだと動作しないことがあります。

```:JSONフォーマット用プロンプト
- これから果物の名前が入力された場合は名産地を5つ提示してください
- 出力は以下の形のJSON形式とします
================
{
  "name" : (果物の名前),
  "answer" : [
    { "location" : (名産地) },
  ]
}
================

それでは始めます。
```

```:プロンプト例1
ブドウ
```

```:回答1
{
"name": "ブドウ",
"answer": [
{ "location": "フランス" },
{ "location": "イタリア" },
{ "location": "スペイン" },
{ "location": "アメリカ" },
{ "location": "チリ" }
]
}
```

```:プロンプト例2
レモン
```

```:回答2
{
"name": "レモン",
"answer": [
{ "location": "イタリア" },
{ "location": "スペイン" },
{ "location": "アメリカ" },
{ "location": "メキシコ" },
{ "location": "アルゼンチン" }
]
}
```

## 回答に中間ステップを介すよう指示する(Chain-Of-Thought Prompting)
思考の途中過程を出力するよう指示することで複雑な推論の精度が向上します。
小学校のテストで見覚えのある「途中式も書いてください」の概念をプロンプトに反映させるようなものです。

計算式の答えだけを出力させようとすると間違った値になることがあります。
また、同じ計算でも結果が変わることもあります。

```:プロンプト1
以下の計算の答えのみ出力してください
4.5 + (3.567 + (4 × 2.1)) × (3 ÷ 3) =
```

```:回答1
9.267
```
```:プロンプト2
4.5 + (3.567 + (4 × 2.1)) × (3 ÷ 3) =
```

```:回答2
12.767
```
そこで途中式も表示するように促すことで、精度の向上を狙います。

### Few-Shot Promptingとの組み合わせ
前述したFew-Shot Promptingと組み合わせることができます。
回答例に途中の式を記述することで、実際の問題でも途中式を記入するようになります。

計算の例では3つほどヒントを与えています。

```:プロンプト3(Chain-Of-Thought Prompting × Few-Shot Prompting)
Q. 2 + (3 + (4 × 2)) × (2 ÷ 2)
A. = 2 + (3 + 8) × (1)  = 2 + 11 × 1 = 13
Q. 4.5 + (3.5 + (4 × 2.5)) × (3 ÷ 3)
A. = 4.5 + (3.5 + 10) × (1)=  4.5 + 13.5 × 1 = 18

Q. (3.567 + (4 × 2.1)) × (2 ÷ 2)  + 2.5
A. = (3.567 + 8.4) × (1) = 3.567 + 8.4 × 1= 14.467
========
Q. 4.5 + (3.567 + (4 × 2.1)) × (3 ÷ 3)
```

```:回答3(Chain-Of-Thought Prompting × Few-Shot Prompting)
Q. 4.5 + (3.567 + (4 × 2.1)) × (3 ÷ 3)
A. = 4.5 + (3.567 + 8.4) × (1) = 4.5 + 11.967 × 1 = 16.467
```

正しい答えが得られていますね。

Chain-Of-Thought PromptingにFew-Shot Promptingを組み合わせる手法は、プロンプトエンジニアリングでは **Self-Consistency(自己整合性)** と呼ばれます。
各種サイトでは別用語として説明されていますが、説明内容が同一のため自分は同じものとして解釈しています。

### Zero-Shot Promptingでの実装
[論文](https://arxiv.org/abs/2205.11916)によると、タスクの最後に「Let's think step by step.」と添えることで経過も出力するようになります。
日本語に対応する文章がわからなかったので、「ステップバイステップで考えてみよう」にしてみましたが、意図した挙動になることを確認しています。
実際には中間過程を出力させるよう促す文脈であれば動作する可能性が高いです。
```:プロンプト4(Chain-Of-Thought Prompting × Zero-Shot Prompting)
4.5 + (3.567 + (4 × 2.1)) × (3 ÷ 3) =
ステップバイステップで考えてみましょう
```

```:回答4(Chain-Of-Thought Prompting × Zero-Shot Prompting)
もちろん、一つずつ計算していきましょう。
1. まず、内側の括弧を計算します。4 × 2.1 = 8.4 です。
2.次に、括弧内の足し算を計算します。3.567 + 8.4 = 11.967 です。
3. 次に、外側の括弧を計算します。3 ÷ 3 = 1 です。
4. 最後に、計算式全体を計算します。11.967 × 1 = 11.967 です。

最終的な答えは、4.5 + 11.967 = 16.467 です。
```

### ReAct
このChain-Of-Thought Promptingをさらに発展させたものが**ReAct**と呼ばれる手法です。
答えを導く過程で外部のデータソースを参照させる手法になります。
思考と行動の2つのプロセスに分けてLLMモデルに考えさせて、行動の際に外部のデータソースを参照できる仕組みになっています。

ReActは[論文](https://arxiv.org/abs/2210.03629)で発表された内容です。
現状外部のデータソースを参照する機能は無料版には搭載されていません。
しかし、有料版で使用できるWebPilotというプラグインを使用することで外部サイトの情報を参照できます。
もしかすると無料版でも利用できるようになるかもしれませんね。


# LLMのパラメータを変更する

## 動的パラメータによる出力の調整
APIからChatGPTを利用する場合に、いくつかのパラメータが存在します。
このパラメータはモデルの出力に影響を及ぼすため、変更することでより求めている情報が得られることがあります。
代表的なものをいくつか紹介します。

### Top P
Nucleus Sampling(Top-p Sampling)という手法に用いるパラメータです。
言語モデルの詳しい話は省略しますが、簡単に言うと「文章的に出力される可能性が低い単語は使わない」という手法です。
言語モデルでは出力にある程度のランダム要素を持つため、そのランダム要素を減らしたい場面があります。
この可能性の低さの閾値を設定するのがTop Pと呼ばれるパラメータです。

最近のLLMはそもそも精度が高いので、これ単体では大きな精度の向上は起こらないと思います。

### Temperature
Top Pでも説明した「ある単語が文章的に出力される可能性」について、はっきりとさせるかあいまいにさせるかを設定するパラメータです。
Temperatureが高いほど曖昧に、低いほどはっきりとさせます。
可能性が高いものを出力しやすくしたい場合はTemperatureを低く設定してみましょう。

### n
各入力に対して出力の数を設定できます

### presence_penalty
同じ単語やフレーズを繰り返すことへのペナルティを設定します。
値が低い場合、生成された文章が同じ単語やフレーズを繰り返すことが少なくなります。
値が髙い場合、生成された文章に既に含まれている単語やフレーズが強調されやすくなります。
### frequency_penalty
同じ内容の行を繰り返すことへのペナルティを設定します。
値が低い場合、生成された文章が同じ内容の行を繰り返すことが少なくなります。
値が髙い場合、生成された文章に同じ内容の行が出力されやすくなります。

## ファインチューニング
ML界隈では有名ですが、LLMモデルを自分のタスク向けになるよう再学習を行う手法です。
ここまでくるとかなりエンジニア寄りな手法になります。

# 有料プランの利用
毎月20ドル(2023年7月時点)で有料プランChatGPT Plusにグレードアップできます。
個人的には豊富なプラグインを利用することでできることの幅が広がる印象です。
例えばGithubの内容を要約して、コードを図で解説することもできます。
以下のメリットもあるので興味がある方は一カ月でも試してみるのがおすすめです。

- 次世代LLMモデル **「GPT-4」** を利用可能
- 接続の安定性が向上
- プラグインが利用可能

# その他
より複雑な方法を利用した手法が論文で公開されており、名前のみの表記とさせていただきます。

- Tree of Thoughts (ToT)
- Automatic Prompt Engineer (APE)
- Active-Prompt
- Directional Stimulus Prompting

# 参考文献

- [ChatGPTの回答の精度を上げるテクニック7選！](https://bocek.co.jp/media/exercise/chatgpt/1754/)
- [YouTube - プロンプトエンジニアリングを学ぼう！ -大規模言語モデル（LLM）の真価を引き出す技術-](https://www.youtube.com/watch?v=jlvrtqKpZvA)
- [Prompt Engineering Guide](https://www.promptingguide.ai/jp)
- [ChatGPT API Reference](https://platform.openai.com/docs/api-reference/chat/create)