ChatGPTを数倍賢くするCoTと「数ショットプロンプト」テクニックまとめ

ChatGPTを勉強しています。いろいろ学んで行く中で、ChatGPTは使う人によって、無能にも有能にもなる非常に面白いAIと思っています。使い方次第で、世界を変えることのできる大規模言語モデルの活用的クニックをぜひ身につけたいものです。

https://chat.openai.com/

それで、今回まとめるのは、『思考の連鎖(CoT / Chain of Thought Prompting)』の手法に欠かせない『数ショットプロンプト(Few-shot prompting)』です。とても面白い手法なので、ぜひマスターしたい技です。これは、ChatGPTを学ぶ時に、必ずマスターしたい[「プロンプトエンジニアリングガイド」](https://www.promptingguide.ai/jp)にも載っているテクニックです。

https://www.promptingguide.ai/jp


# ゼロショットプロンプトと数ショットプロンプトの違いについて

ChatGPTは大規模言語モデル(LLM)で訓練された素晴らしく知識の豊富なＡＩです。そのため、何の前提もなしに質問することを『ゼロショットプロンプト(Zero-shot Prompting)』と呼びます。

これに対して、『数ショットプロンプト(Few-shot prompting)』は、ChatGPTに対して、最初に「この問題はこうやって解くんだよ」というヒントを与えた上で、問題を与えるプロンプトテクニックです。

## 簡単な例

まずは、簡単なゼロショットプロンプトの例として、次のような例が有名です。

```
市場に行ってリンゴを買いました。
隣人に2つ、修理工に2つ渡しました。それから、自分で1つ食べました。
手元に5つ残っています。
最初に買ったリンゴの数を教えてください。
```

この問題をChatGPT(モデルGPT-3.5)で解くと次のような答えが表示されます。

```
最初に買ったリンゴの数は10個です。

最初に購入したリンゴの数をxとすると、隣人に2つ渡し、修理工に2つ渡し、自分で1つ食べた後、手元に5つ残っているという情報から以下の方程式が成り立ちます:
x - 2 - 2 - 1 = 5
両辺を計算すると、
x - 5 = 5
x = 10

したがって、最初に買ったリンゴの数は10個です。
```

正解です。実に賢いです。
この程度の問題は、ゼロショットプロンプトでも問題なく問題を解くことができました。

## ゼロショットプロンプトでは解けない問題

次に以下のような問題はどうでしょうか。

```
市場に行ってリンゴを20個買いました。兄と兄の友人3人と妹に2つずつ配りました。
その後5つ買い足し、自分で2つ食べました。手元にはいくつ残っているでしょうか？
```

ChatGPTに尋ねると次のように間違った答えを返します。

```
最初に20個のリンゴを買いました。兄と兄の友人3人、妹にそれぞれ2つずつ配ったため、
配ったリンゴの総数は6個です（兄と兄の友人3人、妹の計5人 × 2個）。
残りのリンゴの数は、20個から6個引いた14個です。
その後5個のリンゴを買い足し、自分で2つ食べたため、手元には残りのリンゴが17個になります。
```

もっともらしいことを述べていますが、残念ながら計算が間違っています。
答えは、20個-(5人*2)+5個買う-2個食べ=13が答えです。

どうしたら、ChatGPTでも問題が解けるようになるのでしょうか。

##　CoTによる解決方法

ここで役立つのが、「連想の連鎖(CoT)」と呼ばれるテクニックです。

まず、直接的な答えですが、以下のようなプロンプトを作成することで問題を解決できます。
問題を解く前に、問題を解く方法を例示するのです。これが、数ショットプロンプト(Few-shot prompting)です。

```
Q: 市場に行ってリンゴを30個買いました。兄と兄の友人3人と妹に3つずつ配りました。その後5つ買い足し、自分で2つ食べました。手元にはいくつ残っているでしょうか？
A: 兄と兄の友人3人と妹の合計5人に3つずつ配り、自分で2つ食べたので、5*3+2=17個消費し、5個買ったので、20-17+5=8です。8が答えです。
Q: 市場に行ってリンゴを20個買いました。兄と兄の友人3人と妹に2つずつ配りました。その後5つ買い足し、自分で2つ食べました。手元にはいくつ残っているでしょうか？
A:
```

これをChatGPTに与えてみました。すると・・・

```
兄と兄の友人3人と妹の合計5人に2つずつ配り、自分で2つ食べたので、
5*2+2=12個消費し、5個買ったので、20-12+5=13です。
13が答えです。
```

今度は正しく計算することができました！！
問題の計算方法を例示することで、ChatGPTが正しく問題を解く方法を学ぶことができたのです。

![ChatGPTに数ショットプロンプトを与えたところ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33180/e27ee807-a70f-c05b-d332-dbf873a5102b.png)


## ナベアツ問題とは？

次に、数ショットプロンプトが必須となる別の例を紹介します。

ChatGPTでは、次のような計算問題を解くことができません。と言うか、普通の人には、何の問題か分からないことでしょう。

```
Q: ナベアツ問題で、15は？
A:
```

しかし、あらゆる人類の叡智を学んだ、ChatGPTは最初から知っているようです。もっともらしく次のように答えます。

```
ナベアツ問題は、「1から順番に数を数えていく際に、3の倍数の場合は「ナベ」と言い、
5の倍数の場合は「アホ」と言う。ただし、3と5の両方の倍数の場合は「ナベアホ」と言う。」という問題です。

したがって、15は「ナベアホ」と言うことになります。
```

一体、どこから学んだゲームでしょうか、この答えも素晴らしいものです。
確かに、上記の答えにある例から言えば、ナベアホというのが正しいのです。
しかし、私がもともと想定していたのは次のような問題です。

```
お笑い芸人「世界のナベアツ」の持ちネタに「3の倍数と3のつく数字だけアホになります。」というものがあります。
つまり、3の倍数の時と、3のつく数字であれば、「アホ」と表示し、それ以外は数値を出力してください。
```

そこで、模範的な回答が何かをChatGPT(モデルGPT-3.5)に事前に次のようなプロンプトを与えることにします。

```
### ルール ###
ナベアツ問題とは、1からNまでの数字を数えます。ただし、3の倍数の時と、数字に「3」を含むときに、「アホ」と表示し、それ以外は数値を出力するものです。

### サンプル ###
Q: ナベアツ問題で、9は？
A: アホ
Q: ナベアツ問題で、4は?
A: 4
Q: ナベアツ問題で、13は?
A: アホ

### 問題 ###
Q: ナベアツ問題で、15は？
```

さて、正しく「アホ」と答えてくれるでしょうか。上記のプロンプトをChatGPTに与えてみます。

```
A: アホ
```

出ました！正解です。

しかし、たまたま15を正しく判断しただけという場合もあるかもしれません。続けて、問題を解いてもらいましょう。以下のようなプロンプトを入力してみました。

```
Q: ナベアツ問題で、23は？
```

すると次のように答えました。

```
A: アホ
```

正解です。ChatGPTはナベアツ問題を理解し、問題を解くことができました。

このように、事前にいくつかの前提条件やヒントを与えるテクニックを『数ショットプロンプト(Few-shot prompting)』と呼びます。

## 1から50までの値を出力してみる

なお、1から50までの値を順に出力させることもできました。次のようなプロンプトを入力してみました。

```
### ルール ###
ナベアツ問題とは、1からNまでの数字を数えます。ただし、Nが3の倍数の時と、Nに「3」を含むときに、「アホ」と表示し、それ以外は数値を出力するものです。

### サンプル ###
Q: ナベアツ問題で、9は？
A: アホ
Q: ナベアツ問題で、4は?
A: 4
Q: ナベアツ問題で、13は?
A: アホ

### 問題 ###
1から50までの数値を数字を表示してください。
```

すると、ずらりと1から50まで、ナベアツ問題に沿った数値を出力しました。
しかし、数が多いので正しいのか確認できません。

ここは、プログラミングの力を借りて検証してみましょう。


## ルールに則ったPythonプログラムを生成させてみる

それで、ルールに沿ったプログラムを生成させてみることにしました。

```
### ルール ###
ナベアツ問題とは、1からNまでの数字を数えます。ただし、Nが3の倍数の時と、Nに「3」を含むときに、「アホ」と表示し、それ以外は数値を出力するものです。

### サンプル ###
Q: ナベアツ問題で、9は？
A: アホ
Q: ナベアツ問題で、4は?
A: 4
Q: ナベアツ問題で、13は?
A: アホ

### 問題 ###
1から50までの数値を数字を表示するPythonプログラムを作ってください。
```

すると、素晴らしいです。ChatGPTは次のようなプログラムを生成しました。

```python:nabeatu.py
for i in range(1, 51):
    if i % 3 == 0 or '3' in str(i):
        print("アホ")
    else:
        print(i)
```

生成されたプログラムを見る限り、問題ないようです。
ただし、念のためテストを生成させてみましょう。

```
生成したプログラムを検証するテストをPyTest形式で書いてください。
```

するち、次のようなプログラムを生成しました。

```python:nabeatu_test.py
def test_nabeatsu():
    output = []
    for i in range(1, 51):
        if i % 3 == 0 or '3' in str(i):
            output.append("アホ")
        else:
            output.append(str(i))

    expected_output = [
        "1", "2", "アホ", "4", "5", "アホ", "7", "8", "アホ", "10",
        "11", "アホ", "アホ", "14", "アホ", "16", "17", "アホ", "19",
        "20", "アホ", "22", "アホ", "アホ", "25", "26", "アホ", "28",
        "29", "アホ", "アホ", "アホ", "アホ", "アホ", "アホ", "アホ", "アホ",
        "アホ", "アホ", "40", "41", "アホ", "アホ", "44", "アホ",
        "46", "47", "アホ", "49", "50"
    ]

    assert output == expected_output
```

素晴らしいコード生成能力です。
ただ、テストデータ(exptected_output)が間違っていたので、少し直しました。

そして、プログラムの出力結果と先ほどのChatGPTの1から50までの結果を見比べてみました。
だいたい合っていましたが、2箇所間違っていました。

ChatGPTのモデルをGPT-3.5と、GPT-4の両方で試してみましたが、似たような結果になりました。
やはり、ChatGPTは数値が大きくなると正しく数値を文字列として見られないようです。とは言え、1から30までの数値であれば全く問題なく値を出力しました。

# 数ショットプロンプトまとめ

数ショットプロンプトを利用することで、普通では解けないような難しい問題もChatGPTを使って解くことができるようになりました。

問題を解くためのヒントをプロンプトに埋め込むことで、答えられない質問にも答えられるようになるというのは、素晴らしいアイデアです。

これを発展させることで、ChatGPTの利用範囲が非常に広くなるという点も理解できました。引き続き、ChatGPT、大規模言語モデルを学んで行きたいと思います。