Tree of Thought プロンプティングは、あなたが紙の上で問題を解くときのように言語モデルに取り組ませる方法です。次に取りうるステップをいくつか書き出し、どれが見込みがありそうかを判断し、それを続け、行き止まりになった枝は捨てます。このアイデアは Yao らの2023年の論文「Tree of Thoughts: Deliberate Problem Solving with Large Language Models」から来ています。1本の推論の筋をたどる Chain-of-Thought プロンプティングを、多くの筋にわたる探索へと広げたものです。
このページでは、元の手法の仕組みを説明し、ChatGPT、Claude、Gemini で試せる1プロンプト版を紹介し、1つのプロンプトでは足りないときのためにコードでのループを示します。
Tree of Thoughts の仕組み
論文はこの手法を4つの判断に分けています。
- 何を1つの思考とするか。思考とは途中の1ステップで、モデルがうまく生成できるくらい小さく、評価できるくらい大きいものです。数学のパズルなら1つの式、文章を書くタスクなら短い構成案です。
- 思考をどう生成するか。途中までの解決策から、モデルが次のステップの候補を複数提案します。独立にサンプリングする方法と、1回の返答の中で列挙する方法があります。
- 思考をどう評価するか。モデルに、途中までの解決策をそれぞれ評価させます。論文では2つの方式を使いました。各状態を単独で評価する方式(たとえば「確実」「ありそう」「不可能」)と、複数の状態を見せて最良のものに投票させる方式です。
- どう探索するか。プログラムが各段階で最良のいくつかの状態を残す(幅優先探索)か、1本の枝を深くたどり、評価が見込みなしと言ったら引き返す(深さ優先探索)かです。
論文の「24ゲーム」のタスクを例にとります。4、9、10、13 の数をそれぞれ1回ずつ使い、四則演算で 24 を作ります。Chain-of-Thought は最初の式に決めたら、それと付き合い続けるしかありません。Tree of Thoughts なら、最初のステップとして 13 - 9 = 4、10 - 4 = 6、4 + 9 = 13 を試し、残った数でまだ 24 に届くのはどれかをモデルに尋ね、行き止まり(10、13、13 では 24 を作れない)を捨てて、(10 - 4) * (13 - 9) = 24 にたどり着けます。
論文が示したこと
著者たちは、計画や探索が必要なために GPT-4 が Chain-of-Thought を使っても苦戦する3つのタスクを選びました。24ゲーム、決まった結びの文を使う創作のタスク、5x5 のミニクロスワードです。GPT-4 で木の探索を使うと、24ゲームは Chain-of-Thought プロンプティングよりも、複数の連鎖をサンプリングして多数決をとる方法よりも、はるかに多く解けました。残りの2つのタスクでも成績が上がりました。
代償は呼び出しの数です。候補のステップも評価も1つ1つが別々のリクエストなので、Chain-of-Thought なら1回で済むところ、1問を解くのに何十回もモデルを呼び出すことがあります。難しい問題ならこのトレードオフには意味がありますが、簡単な問題にはまったくありません。
1つのプロンプトでの Tree of Thought
このアイデアは1つのメッセージで近似できます。はっきり違うアプローチを複数挙げさせ、それぞれに与えた事実に照らした判定を下させ、生き残ったものだけを掘り下げさせます。下のタブは、同じ問題を両方のやり方で送っています。
主な原因は、オーストラリアとフランクフルトのサーバーとの物理的な距離です。どのリクエストもヨーロッパまで行って戻ってこなければならず、ページを読み込むたびに40回のリクエストがあるので、その遅れが積み重なります。
定番の解決策は CDN(コンテンツ配信ネットワーク)です。CDN は世界中のサーバーにサイトのコピーを置くので、オーストラリアのユーザーはフランクフルトではなく近くの場所からダウンロードできます。多くのサービスでは、コードを変えずに既存のサイトの前に CDN を置けます。
さらに、画像を圧縮し、ブラウザのキャッシュを有効にすれば、読み込み時間をもっと短くできます。
直接の返答はでたらめではありません。40回のリクエストにも触れていますが、当てはまる最初の説明(「距離」)に飛びつき、そのまま突き進みました。枝分かれさせた返答は、各説明をプロンプトの詳細に照らして確認したので、「オーストラリア」より「1つずつ順番に」のほうが重要であること、そして CDN では API の呼び出しには手が届かないことに気づけました。
再利用できるテンプレート
同じ構成は、設計の選択や計画にも使えます。問題と、重視する基準を入れてください。返答はデフォルトの値を入れた場合のものです。
PaaS(マネージドのアプリホスティング) コスト:中程度で、トラフィックに応じて増える。セットアップ:Git リポジトリから1時間以内。保守:少ない。OS のパッチはホスト側が当てる。残す。
自前の仮想サーバー コスト:最も安い。セットアップ:サーバー、TLS、プロセスマネージャーで1日。保守:多い。アップデートも再起動も自分たちで行う。3人のチームには捨てる。
サーバーレス関数 コスト:小規模ならとても安い。セットアップ:中程度。既存のサーバーアプリは構成の見直しが必要なことがある。保守:少ないが、コールドスタートで遅延が増える。次点として残す。
最良:PaaS。最初のステップ:
- start スクリプトを追加し、ポートを環境変数から読み込む。
- シークレットをホストの環境設定に移す。
- リポジトリを接続し、main ブランチをデプロイする。
- ヘルスチェック用のエンドポイントを追加する。
- 支出のアラートを設定する。
1つのプロンプトの限界
1プロンプト版は、手法の用語は残しているものの、仕組みの大部分を失っています。
- 本当の後戻りがない。 モデルはすべての枝と判定を1回の流れで書きます。選んだ枝のステップ3が失敗しても、ステップ1に戻らせるものは何もありません。
- 審査員が作者でもある。 アイデアを提案したのと同じ返答がそれを評価するので、最初から考えていた枝をひいきしがちです。論文では、評価は候補ができたあとの別の呼び出しで行われます。
- 枝が独立していない。 1回の返答の中で挙げたアイデアは互いに影響し合い、1つのテーマの変形に終わることがよくあります。テンプレートのように「本当に異なる」アプローチを頼めばこれに抵抗できますが、なくなりはしません。
- 推論モデルはすでに枝分かれしている。 答える前に考えるモデルは、内部でアプローチを試しては捨てています。そうしたモデルでは、このプロンプトによる精度の上積みは小さく、残る価値は、却下された選択肢が見えて、その推論に異を唱えられることです。
コードで本物の木探索を実行する
完全な手法は、プログラムの中のループです。候補のステップを生成し、途中までの解決策を別々の呼び出しで評価し、最良のいくつかを残し、それを繰り返します。これは OpenAI の Python SDK を使った最小限の幅優先版で、同じ形はどの提供元でも使えます。
from openai import OpenAI
client = OpenAI()
MODEL = "your-model-id" # e.g. from your provider's model list
def ask(prompt, temperature=0.7):
response = client.chat.completions.create(
model=MODEL,
messages=[{"role": "user", "content": prompt}],
temperature=temperature,
)
return response.choices[0].message.content.strip()
def propose(problem, path, k=3):
steps = "\n".join(path) or "(none yet)"
prompt = f"Problem: {problem}\nSteps so far:\n{steps}\nPropose the next step only."
return [ask(prompt) for _ in range(k)]
def score(problem, path):
steps = "\n".join(path)
prompt = (f"Problem: {problem}\nPartial solution:\n{steps}\n"
"How likely is this to lead to a correct solution? Reply with a number from 1 to 10 only.")
try:
return float(ask(prompt, temperature=0))
except ValueError:
return 0.0
def tree_of_thought(problem, depth=3, keep=2):
frontier = [[]]
for _ in range(depth):
candidates = [path + [step] for path in frontier for step in propose(problem, path)]
candidates.sort(key=lambda p: score(problem, p), reverse=True)
frontier = candidates[:keep]
return frontier[0]
depth=3、keep=2、状態ごとに3つの提案なら、1回の実行でおよそ30回の呼び出しになります。多くのタスクでは、Self-Consistency プロンプティング(完成した答えを複数得て多数決)や、プロンプトチェーンによる決まったステップの連続のほうが、少ない呼び出しで効果の大部分を得られます。木を使うのは、タスクに探索が必要なときです。最初の一手が多くあり、行き止まりを早めに見分ける方法があるときです。
よくある質問
Tree of Thought プロンプティングとは何ですか?
Tree of Thought プロンプティングとは、モデルが次に取りうるステップを複数提案し、それぞれの見込みを評価し、最も良い枝だけを続け、枝が行き詰まったら引き返す、という問題の解き方です。Yao らの2023年の論文「Tree of Thoughts: Deliberate Problem Solving with Large Language Models」から来ています。論文では、枝分かれと評価は、モデルを何度も呼び出すプログラムが実行しています。
Tree of Thoughts と Chain-of-Thought の違いは何ですか?
Chain-of-Thought は最初から最後まで1本の推論の筋をたどるので、早い段階の間違いが答えまで持ち越されます。Tree of Thoughts は途中までの解決策を同時に複数保ち、それらを評価して弱いものを捨てるので、悪い最初の一歩から立ち直れます。代わりに、モデルの呼び出しがはるかに多くなります。
ChatGPT や Claude で Tree of Thoughts を使えますか?
近似版なら使えます。いくつかのアプローチを挙げさせ、あなたの基準でそれぞれを評価させ、弱いものを捨てて最良のものを掘り下げさせる、1つのプロンプトです。どのチャットアプリでも使えます。ただし完全な手法ではありません。すべてが1回の返答の中で起き、モデルは自分のアイデアを、それを書いたのと同じ流れの中で評価するからです。
推論モデルでも Tree of Thought プロンプティングは役に立ちますか?
以前ほどではありません。答える前に考えるモデルは、すでに内部でアプローチを試しては捨てているので、枝分かれを頼んでも上積みは小さくなります。それでも1プロンプト版は、選択肢と、それが却下された理由を見て、判断を自分で確かめたいときには役に立ちます。
Tree of Thought プロンプティングはどんなときに使えばいいですか?
もっともらしいアプローチが複数あり、最初の思いつきがよく外れる問題に使います。計画、設計の選択、症状からの問題の診断、探索が必要なパズルなどです。道筋が1つしかない質問なら、ふつうの Chain-of-Thought のほうが安く、同じくらいうまくいきます。