見出し画像

大規模言語モデル(LLM)の内在的知識を引き出すプロンプトとその仕組み

はじめに

前回の記事で書ききれなかった続編にあたる内容です。

発端となった「法律事務所のためのChatGPT利活用ガイドブック」では、主にChain-of-Thoughtプロンプティング(以下、CoT) や Tree of Thoughts フレームワーク(以下、ToT)を取り上げて、複雑な推論タスクの解決に取り組んでいました。そこで、今回はそれらのプロンプト技術CoTを踏まえつつ、ToTやプロンプト技術の可能性を検証していきたいと思います。


プロンプトエンジニアリングとは

ChatGPTは、入力される質問に対してそれらしい回答をしてくれます。しかし、まだまだ不適切な回答が混在することがあります。これらの問題に対処するための1つに質問(入力プロンプト)を工夫する方法があります。

プロンプトエンジニアリングとは、LLMに対して最適な応答を引き出すための質問や指示の設計プロセスです。目的の回答を引き出すために入力文を工夫する技術と言えます(*1)。

苦手な推論タスク

最高峰のモデルGPT-4以降のChatGPTでは、普通に質問するだけでもかなり実用的な回答が返ってきます。しかし、有益な回答を引き出すためにはいくつか留意点があります。その1つは、そもそもLLMは複雑な推論タスクがあります。前回の記事でも足し算が苦手であることを紹介しましたが、どういうことか見ていきましょう。

たとえば以下の問題をLLMは解けるでしょうか。

ある会社に30人のスタッフがいて、そのうちの20%が病欠した。病欠した人の50%がコロナに罹ってしまい7日後まで復帰できない。残りのスタッフは1日後に回復する体調不良だった。その後に誰も病欠しなければ、3日後に会社に出社しているのは全部で何人か?

これを解かせて見ると以下の様な結果です。検証はGPT-3.5で実施しています。

出社人数を問う(GPT-3.5)

正解は27人です。上記の結果では惜しいところまでは推論できているようですが、結論が誤っていることが見てとれます。

もう一つ別のお題です。

事件の犯人を問う(GPT-3.5)

今回の設問では「犯人がいます」と記載しているものの、この情報だけでは犯人を特定できません。それにもかかわらず、Bさんが犯人だと断定しています。同じく指紋が見つかったCさんではなくBさんを犯人とする根拠もよくわかりません。

苦手と言われるもので代表的なのは「算数」「常識」「論理」に伴う推論タスクが挙げられます。最初の出社人数の質問では「算数と論理」、2つ目の事件の犯人の質問では「論理」などの苦手要素が含まれているかもしれません。「なぜ苦手なのか?」については後述で掘り下げるとして、まずこの苦手なタスクに対する回答精度を上げるための方法について触れたいと思います。

Chain-of-Thought Prompting(CoT)とは

この苦手なタスクを克服するために、CoTというプロンプト技術が有名です。 代表的な論文の概要で以下のように説明されています。

We explore how generating a chain of thought -- a series of intermediate reasoning steps -- significantly improves the ability of large language models to perform complex reasoning.
大規模言語モデルが複雑な推論を行う能力を大幅に向上させるため、一連の中間的な推論ステップ(思考の連鎖)を生成することを探求する

Chain-of-Thought Prompting Elicits Reasoning in Large Language Models

「中間的な推論ステップ」を設けることが「論理」タスクの解決に繋がるのでしょうか。

まずは、お手軽で有名な「Step by Stepで考えて」と追加するだけの Zero-Shot CoT(*2) で精度が上がるかを検証します。

出社人数を問う(GPT-3.5)

Zero-Shot CoTを追記するだけで精度が向上しており、先程の通常プロンプトとの比較で、追加の中間ステップが設けられています。

事件の犯人を問う(GPT-3.5)

回答が少しまともになったような気がします。設問からは犯人を特定することはできない事実に気がついたようです。Zero-Shot CoTを加えることで「わからないことがわかる」ようになる様子が見て取れます。

なぜCoTで精度が上がるのか?

なぜ「Step by Stepで考えて」と追記するだけで特定タスクの回答精度が向上するのか、正直よく理解できていない部分も多いです。

現段階で言えることは、Zero-Shot CoTで中間ステップが設けられることで、タスク(問題)の対象範囲を狭くなり、そのことで、LLMが取り組むタスク(問題)が小さくなります。そして、LLMは入力された文章(プロンプト)に基づいて、現在の入出力された単語と過去の計算結果(文脈)を考慮して、次の単語を確率的な予測に基づいて文章を生成します。

その際の対象範囲が狭くなれば、次の予測における回答の誤差も小さくなり、結果的に精度の向上に繋がっていると推測できます。

本当は、なんで入力プロンプトに手を加えるだけで精度が上がるの?と思っていました。一旦CoTの限界とToTプロンプトの検証後に、もう少し深堀りたいと思います。

CoTプロンプトの限界と課題

このCoTプロンプトにも課題があります。それは、タスク遂行の途中で軌道修正が難しいということです。

CoTプロンプトはタスクの段取り(中間ステップ) を最初に定義し、その定義通りに一つ一つ推論していきます。このことをLarge Language Model Guided Tree-of-Thought という論文では以下のように説明しています。

Solution generated linearly(逐次的に生成された解決策)
As mentioned above, LLMs typically generate a token based on the preceding sequence of tokens without backward editing. On the contrary, when a human solver attempts to solve a problem, she might backtrack to previous steps if a derivation step is incorrect, or if she becomes stuck and is unable to make further progress towards arriving at the final answer.

前述したように、LLMは通常、直前のトークン列に基づいて次のトークンを生成し、後から修正を行うことはない。それとは逆に、人間の解答者が問題を解こうとするとき、導出ステップが正しくなかったり、行き詰まって最終的な解答にたどり着けなない場合、前のステップに後戻りすることがある

Large Language Model Guided Tree-of-Thought

段取り(中間ステップ)の最初もしくは途中に誤りがある場合に、後戻りできないので、後続ステップに進むにつれて推論の誤りが大きくなり破綻してしまうことを示唆しています。つまり「軌道修正することが難しい」、これがCoTの課題でした。

GPT-3.5以前のモデルでは、急におかしな単語や文章をずっと吐き続けるような現象をちょくちょく拝見したのも、この辺りの「軌道修正できない」仕組みだったのかもな、と納得しました。

数式パズルで検証する

CoTの課題について、Game of 24という数式パズルをもとに簡単に説明します。Game of 24は与えられた4つの数字を用いて24を作るパズルです。

🧩Game of 24のルール🧩
①最初に1~9の間の整数4つが与えられる
  - 4つの数字 (例: 2, 3, 6, 8) を使用して四則演算で24を作る
②4つの数字は全て1回ずつ使用しなければならない
  - 繰り返しの使用も不可
③括弧 ( ) を使って計算の順序を変えても良い
④最終的な答えは整数でなければならない
  - 分数や小数は不可

このルールのもと、2, 3, 6, 8の4つの数値を、まずはGPT-4の Zero-Shot CoT試してみます。ちなみにCode Interpreterは使用禁止にしています。

💬プロンプト(Zero-Shot CoT)

Game of 24は、パズルゲームです。ルールは以下の通りです。

[ルール]
4つの数字が与えられます。これらの数字は通常1から9の間の整数ですが、ゲームによってはより大きな数字が使われることもあります。 1. 与えられた4つの数字を使って、四則演算(加算、減算、乗算、除算)を組み合わせ、24を作るという目標を達成します。 2. 4つの数字は、それぞれ1回ずつ使用しなければなりません。つまり、数字を繰り返し使用したり、使わなかったりすることはできません。 3. 括弧を使って、計算の順序を変更することができます。これにより、多様な解き方が可能になります。 4. 最終的な答えは、整数でなければなりません。つまり、分数や小数は認められません。 5. Code Interpreterは使用できません。 上記のルールに従い、Step by Stepで考えて、2, 3, 6, 8の数字を利用して24を作ってください。

記事の都合上、プロンプト文を改行せずに記載していますが、実際には適切に改行を入れています。

実行結果(GPT-4)

出力からは、試行錯誤はしているものの、解答には辿りつけないことがわかります。何度か試しても駄目でした。誤りにも関わらず、正解だと認識することもありました。

Tree of Thoughts(ToT)

前述のCoTの軌道修正できない課題を改善するのが、ToTフレームワークと呼ばれるものです。論文の結論だけ先に取り上げると、GPT-4による検証でCoTでは 4%しか成功できませんでしたが、ToTでは 45%の成功率、幅優先探索(BFS)をより強めた指示をしたところ、74%の成功率を達成したようです。

IO, CoT, and CoT-SC prompting methods perform badly on the task, achieving only 7.3%, 4.0%, and 9.0% success rates. In contrast, ToT with a breadth of b=1  already achieves a success rate of 45%, while b=5 achieves 74%.

Tree of Thoughts: Deliberate Problem Solving with Large Language Models

しかも、CoTについてはIO(通常プロンプト)よりもスコアが悪い結果となっています。これは軌道修正できない性質がスコア悪化に影響した可能性があります。

ToTの検証

それでは、後ほどToTについて補足するとして、まずは検証してみましょう。適切なToTプロンプトになっているのかわかりませんが、見よう見まねでやってみます。

💬ToTプロンプト(見よう見まね)

Game of 24は、パズルゲームです。ルールは以下の通りです。

[ルール]
4つの数字が与えられます。これらの数字は通常1から9の間の整数ですが、ゲームによってはより大きな数字が使われることもあります。 1. 与えられた4つの数字を使って、四則演算(加算、減算、乗算、除算)を組み合わせ、24を作るという目標を達成します。 2. 4つの数字は、それぞれ1回ずつ使用しなければなりません。つまり、数字を繰り返し使用したり、使わなかったりすることはできません。 3. 括弧を使って、計算の順序を変更することができます。これにより、多様な解き方が可能になります。 4. 最終的な答えは、整数でなければなりません。つまり、分数や小数は認められません。 5. Code Interpreterは使用できません。2, 3, 6, 8の数字を利用して24を作るために、タスク遂行のために以下の手順に従ってください。

[タスク遂行のための手順]
2, 3, 6, 8の数字を利用して24を作るために問題を小さく分割してください。次の2, 3, 6, 8の数字を利用して24を作るためのアイデアを20つ生成してください。20つのアイデアをStep by Stepで考えて2, 3, 6, 8の数字を利用して24を作るために適切なアイデアであるかを検証してください。次に、Step by Stepで考えて2, 3, 6, 8の数字を利用して24を作るために適切なアイデアであるかをsure/maybe/impossibleの3つの評価してください。sureが24を作るために最も有望です。20のアイデアに対して、2, 3, 6, 8の数字を利用して24を作るために適切なアイデアであるかを、sure/maybe/impossibleで投票してください。その評価がsureの場合は最も有望なアイデアです。その最も有望なアイデアで、2, 3, 6, 8の数字を利用して24の作成を検討してください。もし、最も有望なsureのアイデアで 「2, 3, 6, 8の数字を利用して24の作成」検討した結果が、作成が困難であることが判明したら、それ以外のアイデアで最も有望なアイデアを選択して、2, 3, 6, 8の数字を利用して24の作成を検討してください。これらは1度のプロンプト出力で完了させる必要があります。上記の手順に従い、2, 3, 6, 8の数字を利用して24の作成が完了するまで手順を繰り返してください。それでは、2, 3, 6, 8の数字を利用して24を作ってください。

記事の都合上、プロンプト文を改行せずに記載していますが、実際には適切に改行を入れています。

実行結果(GPT-4)

結果は駄目でした。。。

ToTプロンプトが適切ではないからなのか、あるいは日本語と英語の差なのか、何度か試しても駄目でした。これでは検証にならないな。。。と思っていたところ、颯爽と現れたのがClaud3 Opusでした。

さっそく実行してみました。

実行結果(Claud3 Opus)

できました。これは感動しました。

正確には、Claud3 Opusに対しては、50個のアイデアを思考生成させています。最初はGPT-4にも同様の指示をしましたが、30個すら「(多過ぎで)現実的ではないので生成しません」と拒否されます。このChatGPTのプロンプト制限があることで、何度試してもうまくいきませんでした。

ちなみに、Zero-Shot CoTだとClaude3 Opusでも成功には辿りつけませんでした。

## Claude3 Opus の Zero-Shot CoTで試した際の出力結果
 
では、2, 3, 6, 8の数字を使って24を作る方法を考えていきましょう。
ステップ1: まず、24を作るために使える乗算と除算の組み合わせを考えます。8 × 3 = 24 ですが、残りの数字が26になるので、これだけでは24を作れません。6 × 2 = 1212 × 2 = 24 の組み合わせが使えそうです。
ステップ2: 6 × 2 = 1212 × 2 = 24 の組み合わせを使うために、8から2を作る方法を考えます。8 ÷ 3 = 2 remainder 2 なので、ここで2を作ることができます。
ステップ3: 以上の考察をまとめると、次のような計算式が得られます。(8 ÷ 3) × 6 × 2 = 24
ステップ4: 式に括弧をつけて、計算の順序を明確にします。 ((8 ÷ 3) × 6) × 2 = 24
したがって、2, 3, 6, 8の数字を使って24を作る方法の一つは、((8 ÷ 3) × 6) × 2 = 24 です。


ToTを実現する4つの問い

ToTの仕組みを作用させるには、以下4つの方法を引き出すためにプロンプトを工夫する必要があります(*3)。

・中間プロセスを各ステップに分解する方法
・各状態から考えられる思考を生成する方法
・状態をヒューリスティックに評価する方法
・使用する探索アルゴリズムを選択する方法

Tree of Thoughts: Deliberate Problem Solving with Large Language Models

なお、検証時の出力結果(画像)を見ていただくだけでも理解しやすいかもしれません。

🛠️中間プロセスを各ステップに分解する方法

これは、タスクを小さく分割する方法です。プロンプトもそのままなので特に説明は不要かなと思います。

## プロンプト例
2, 3, 6, 8の数字を利用して24を作るために問題を小さく分割してください。
次の2, 3, 6, 8の数字を利用して24を作るためのアイデアを可能な限りたくさん生成してください。


💭各状態から考えられる思考を生成する方法

タスク遂行のためのアイデアを洗い出す方法です。Game of 24では、数字の組み合わせ (例: 2, 3, 6, 8) から 24を作り出すアイデア(計算方法)を提案させます。

## プロンプト例
生成されたアイデアをStep by Stepで考えて2, 3, 6, 8の数字を利用して24を作るために適切なアイデアであるかを検証してください。


📝状態をヒューリスティックに評価する方法

思考の生成で提案されたアイデアの妥当性(解答にどれだけ有効か)を評価する方法です。各アイデアの妥当性を「sure/maybe/impossible」で評価します。

## プロンプト例
次に、Step by Stepで考えて2, 3, 6, 8の数字を利用して24を作るために適切なアイデアであるかをsure/maybe/impossibleの3つの評価してください。
sureが24を作るために最も有望です。
20のアイデアに対して、2, 3, 6, 8の数字を利用して24を作るために適切なアイデアであるかを、sure/maybe/impossibleで投票してください。

この状態評価の結果は、次の検索アルゴリズムの選択に直結します。Game of 24の場合、幅優先探索(BFS)が用いられていますが、この選択は状態のヒューリスティックな評価に基づいていて選択されるとのことです。

To perform deliberate BFS in ToT, as shown in Figure 2(b), we prompt LM to evaluate each thought candidate as "sure/maybe/impossible" with regard to reaching 24.


🔎使用する探索アルゴリズムを選択する方法

各ステップで生成された思考のアイデアのうち、状態評価によって高く評価された上位5つ(b=5)の候補が選ばれ、次のステップに進むことになります。

We perform a breadth-first search (BFS) in ToT, where at each step we keep the best b = 5 candidates.

つまり「sure」と評価された候補が最優先で探索されます。

ここでToTの注目すべき特徴は、優先して探索されたアイデアが後に「不可能(impossible)」と評価された場合、そのアイデアの探索は打ち切られ、別のアイデアの探索に切り替えることができるのです (つまりバックトラッキングが可能) (*4)

このことは、CoTプロンプトの課題で説明した「重大な誤りや見落としがあっても、軌道修正して別のアプローチを取ることが難しい」ことに対する解決策になり得るということです。

⚠️ToTプロンプトの留意点

もちろん、留意点があります。まず、ToTのアルゴリズムを引き出すプロンプトを作成するのが面倒です。また、毎回同じ結果が得られる保証はありません。そのため得られた結果を再検証して、試行錯誤しつつ効果的なタスクを見つける必要があります(*5)。


なぜToTで回答精度が向上するのか?

率直に「なんで、これらのプロンプトの工夫で状態評価とバックトラックが可能になるの?」という感想でした。そこで、CoTに関する論文「Chain-of-Thought Prompting Elicits Reasoning in Large Language Models」を良く見てみると、その背景を示唆する記載がありました。

Chain-of-thought prompting appears to expand the set of tasks that large language models can perform successfully—in other words, our work underscores that standard prompting only provides a lower bound on the capabilities of large language models.
思考の連鎖プロンプティングは、大規模言語モデルが成功裏に実行可能なタスクの範囲を広げることができるように見える。言い換えると、我々の研究は、標準的なプロンプトは大規模言語モデルの能力の下限を提供するに過ぎないということだ

Chain-of-Thought Prompting Elicits Reasoning in Large Language Models

この引用が意味するのは、普通にプロンプト(質問)するだけでは LLMの潜在能力を引き出せてない ということです。

💡学習済み内部表現の活性化

そのことを補強する先行研究はもっと以前に既にありました(自分が無知過ぎるのをただただ痛感)。

We argue that contrary to the common interpretation of the few-shot format implied by the title of the original GPT-3 paper [3], Language models are few-shot learners, GPT-3 is often not actually learning the task during run time from few-shot examples. Rather than instruction, the method's primary function is task location in the model's existing space of learned tasks. This is evidenced by the effectiveness of alternative prompts which, with no examples or instruction, can elicit comparable or superior performance to the few-shot format.

我々は、GPT-3の元の論文[3]のタイトルが示唆するfew-shotフォーマットの一般的な解釈とは対照的に、GPT-3が実行時にfew-shotの例示から、実際にはタスクを学習しているわけではないと主張します。few-shotの主な機能(役割)は、指示(例示)ではなく、モデルの既存の学習済みタスクの空間におけるタスクの位置になります。これは、例や指示なしで、few-shotフォーマットに匹敵するまたはそれ以上の性能を引き出すことができる代替プロンプトの有効性によって裏付けられています。

この引用は、LLM は Few-Shot で 学習しているのではなく、「学習済みの知識を活性化させているに過ぎない」と解釈できると主張しています。Few-Shot で 例示(leaning)しているのではなく、記憶に働きかけるきっかけになっていると解釈できるようです。

よくよく考えればプロンプト次第で様々なコードの生成が可能なので、内部パラメータに膨大な手順(アルゴリズム)自体は存在していて、それをプロンプトで引き出しているだけなのだと腑に落ちました。

【メモ
引用文の task location in the model's existing space of learned tasks.(学習済みタスクの空間におけるタスクの位置)  についての補足として、まずLLMの学習済み知識(パターン)はベクトル空間の点として配置されています。プロンプト(入力文)は、その点(位置)に働きかけるきっかけになり、LLMが既に蓄積している知識の中から、タスクに対応する知識を見つけ出す作用がある、という意味だと理解しました。

おわりに

本記事では、LLMの苦手なタスクを実際のプロンプトで検証しました。そしてまた、プロンプトを工夫することで回答精度が向上することの可能性を見ていただきました。

とはいえ前回のLLMの根本的な限界でも取り上げたように、プロンプトの工夫だけでもやはりすぐ限界が訪れます。そして人間によるプロンプトの工夫そのものが間もなく自動化(LLMOps)となり消えゆくものであることも説明しています。

LLMの進化とともに2025年中にはプロンプトを工夫する余地そのものが消える可能性も高そうです。逆にいえば、まだ工夫の余地があるので、色々と試すのは今が絶好のタイミングとも言えます。そして、この工夫で得られた知見は別の何かに転用すれば良いのだとも思います。

そしてLLMの深淵へ

そして最後にやや脱線して、LLMの深淵にほんの触りだけ迫りかけました。これ以上の深淵に迫る場合、避けて通れないのがLLMの中核となる注意機構(Attention Mechanism) です。色んな記事や書籍を読むことで改めて注意機構おもしろいな!と思うと同時に「しかし、なんでこれが知能らしき振る舞いになるんだ?」とさらに深淵にハマりかけています(これは完全にニーチェ)。

ということで、別の機会があればLLMのメカニズム(特に注意機構など)について、取り上げるような記事を書いてみようと思います。完走まで時間がかかるかもしれず、LangChainやRAG、その他の小休止的に寄り道をするかもですが、次回もまた読んでいただけたら嬉しいです。


参考記事

わからん過ぎて大変でしたが、たくさん参考にして、いやー楽し過ぎました(理解したとは言っていない)


余談と注釈

注釈は本来の用法ではなく恐縮ですが、どうでも良い余談として以下に書いています。良かったら読んでいってください。

(*1)最初は工学的な技術という認識をあまり持っていませんでした。しかし、書籍やPrompt Engineering Guideの記事、それらで引用された論文などを拝見すると、脳科学や生理学的な実験と同じように 未解明の機能に対して、外部からの刺激(入力)を通じてその反応(回答)を観察し、機能や振る舞い解明するアプローチ であって、(Engineeringというより) 実験科学っぽいなと考えるとしっくりきました。というのも、プロンプトエンジニアリングに関する論文も、LLMに条件やプロンプト設計し、テストと検証を繰り返して結果が公開されていますが、未だに「ブラックボックスわからん」という結論が多かったです。

(*2) Zero-Shot CoTは、事前に例示などを用意せず、単に「Step by Stepで考えて~」と指示するだけで、LLMの性能を少しだけ引き上げることができるお手軽な手法です。ただし、タスクによっては全く性能向上が見込めないことも多いです。

(*3) 論文を拝見すると何やら難しい数式がありましたが、これらは検証過程(あるいは結果)で導かれた式のようで、ToTを適切に作用させるための仮説となっているようです。

(*4) 論文からは読解できませんでしたが、きっとバックトラッキングの恩恵は、深さ優先探索(DFS)で挑んだ結果、その途中のステップで評価が不可(impossible)と判定されたときのはずですが、どんなタスクなのかあまりイメージ出来ていません。

(*5) 現時点では最高峰のモデルでもビジネスの実用性を考慮するとあと一歩のタスクが多い印象です。理由は色々ありますが、その辺りは別の機会があれば書きたいと思います


この記事が気に入ったらサポートをしてみませんか?