プロンプト ReAct
軽量モデルへ代表的なプロンプト手法を実際のコードで試しモデルの反応を確認します
記事作成日:2025-12-05, 著者: Hi6
このガイドはなぜ必要か?
現代のLLM(大規模言語モデル)は、正しく誘導されて初めて複雑な推論タスクを解決できます。以下に示す手法は、信頼性・説明可能性・高性能システム構築の「標準的ケア」として確立されています。それぞれが、モデルへの指示量や内部で考えるか外部ツールと対話するかという点で異なります。
影響力が大きい6つの手法を深掘り:
ReAct(Reason + Act)とは?
概要 LLM が「思考 (Reason) → 行動 (Act)」を繰り返しながら、外部情報の取得や計算・検索を行い、最終回答へ到達する手法です。
-
2006 年に Peter L. Klein et al. が提案した「Reason + Act」の略称。
-
実際には「思考 → 行動 → 思考 …」というループで、必要な情報を逐次取得して答えを導きます。
-
主な特徴
- 外部 API / データベース呼び出し(検索、計算、データ取得)を自然に組み込める。
- 推論過程が可視化できる → 推論過程を可視化できます。具体的には「何を調べたか」や「どの情報を元に答えに到達したか」を追跡可能です。
- 対話形式で実装しやすい(「思考」「行動」をプロンプト内で明示)。
2️⃣ 基本構造(テンプレート)
Task: [タスクの簡潔な説明]
あなたは役に立つアシスタントです。
Follow the ReAct pattern:
1. Think about what to do next (Reason).
2. Execute an action (Act) if needed.
3. Repeat until you can answer.
Example 1:
Input: 7 + 5
Thought: I need to compute a sum.
Action: calculate(7, '+', 5)
Result: 12
Answer: 12
Now solve:
Input: [ユーザーが入力する問題]
- 思考(Reason):
Thought:の下に「何を調べるか、どのアクションを取るか」を記述。 - 行動(Act):外部 API 呼び出しや計算指示。例として
Action: calculate(…)やSearch: ...など。 - 結果(Result):行動の返却値を受け取り、次の思考へ。
- 最終回答:
Answer:で最終答えを提示。
3️⃣ 実装手順
| ステップ | 方法 |
|---|---|
| 1. タスク定義 | Task: で何を求めるか明示。 |
| 2. ReAct プロンプト | 「You are a helpful assistant…」で思考・行動のパターンを宣言。 |
| 3. 行動定義 | 実際に呼び出す外部関数/API(例:calculate, search, lookup)を決める。 |
| 4. ループ実装 | - Python: 1 回の ChatCompletion 呼び出しで「思考・行動」を生成させ、 - 行動結果を外部で処理(計算や検索)し、 - 次のプロンプトに反映。 | |
| 5. 終了条件 | 「Answer:」が返ってきたらループ終了。 |
4️⃣ 実際の実装例(Python + Ollama)
import ollama
import re
from datetime import datetime
def now_time() -> str:
"""現在時刻を返すツール"""
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def react(prompt: str, n_steps: int = 5) -> str | None:
system_prompt = (
"あなたは ReAct ループ内で実行される便利なアシスタントです。\n"
"これらのルールを厳守してください:\n"
"1. 時間を確認するには、「Action: get_current_time」のみを出力します。\n"
"2. `Result: ...` を受け取ったら、すぐに `Answer: ...` を\
出力しなければなりません。\n"
"3. 回答の前に考え、説明、空行を出力しないでください。\n"
"4. Example:\n"
" User: Result: 2025-01-01 12:00:00\n"
" Assistant: Answer: It is 2025-01-01 12:00:00."
)
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt}
]
client = ollama.Client(host="http://127.0.0.1:11434")
for step in range(n_steps):
# --- Stop Sequence を設定 ---
# "Result:" や "Observation:" が出そうになったら強制停止させる
response = client.chat(
#深く推論できるモデルを使用しないと無駄なモデル呼び出しで空回りする
model="qwen3-coder:latest",
messages=messages,
options={
"stop": ["Result:", "Observation:", "\nResult:"]#stop条件
}
)
reply = response["message"]["content"].strip()
print(f"Step {step+1} Assistant:\n{reply}\n")
# --- モデルの回答(Action)を履歴に追加 ---
# これをしないと、モデルは自分がActionしたことを忘れてしまいます
messages.append({"role": "assistant", "content": reply})
# Actionが含まれているか判定
if "Action:" in reply:
action_line = next((l for l in reply.splitlines() \
if l.startswith("Action:")), None)
if action_line:
raw_action = \
action_line.replace("Action:", "").strip().lower()
action_name = re.sub(r'\s+', '_', raw_action)
if action_name == "get_current_time":
# ツールの実行
tool_result = now_time()
print(f"[System] Tool Output: {tool_result}\n")
# --- ツールの結果を履歴に追加 ---
# 次のターンでモデルがこれを読み取れるようにします
# roleは "user" として渡し、「外部からの入力」として認識させます
messages.append(\
{"role": "user", "content": f"Result: {tool_result}"})
elif "Answer:" in reply:
# 最終回答が見つかったら終了
return reply.replace("Answer:", "").strip()
return None
# -------------------------------------------------------------
if __name__ == "__main__":
user_prompt = "現在の時刻を教えてください。"
print(f"User: {user_prompt}\n" + "-"*30)
final_answer = react(user_prompt, n_steps=10)
print("-" * 30)
print("Final Answer:", final_answer)
出力結果:
User: 現在の時刻を教えてください。
------------------------------
Step 1 Assistant:
Action: get_current_time
[System] Tool Output: 2025-12-06 03:15:44
Step 2 Assistant:
Answer: 2025-12-06 03:15:44
------------------------------
Final Answer: 2025-12-06 03:15:44
5️⃣ ReAct のメリット
| メリット | 説明 |
|---|---|
| 外部情報取得が簡単 | Action: で検索・計算・データベース呼び出しを自然に組み込める。 |
| 推論過程の可視化 | 「Thought」「Action」「Result」の順でログが残るので、誰でも追跡可能。 |
| 柔軟性 | タスクが変わっても「思考・行動」を追加するだけで対応できる。 |
| 対話型アプリに最適 | チャットボットやサポートシステムで、必要に応じて外部APIを呼び出せる。 |
6️⃣ ReAct のデメリット
| デメリット | 説明 |
|---|---|
| 実装が複雑 | 行動結果を処理するロジック(例:計算・検索)を自前で書く必要。 |
| 遅延増大 | 外部API呼び出しがあると応答時間が伸びる。 |
| エラー管理 | 行動失敗時の再試行やフェイルオーバーを設計する必要。 |
7️⃣ ベストプラクティス
- Action の定義は簡潔に
calculate,search,lookupなど、わかりやすい名前に。
- 結果のフォーマット統一
Result: ...を必ず入れ、次の思考でパースしやすくする。
- ループ回数はタスクに応じて調整
- 1〜5 回程度が多い。無限ループを避けるため「最大ステップ数」を設定。
- 外部API呼び出しは非同期化
- Python の
asyncioを使えば、複数行動を並列実行できる。
- Python の
- ログ/デバッグ情報を残す
- 例:
Thought,Action,Resultをファイルに書き出し、後から解析可能に。
- 例:
🎯 まとめ
- ReAct (Reason + Act) は「思考→行動」のループで外部情報取得を自然に組み込む手法。
- テンプレート:
Task → ReAct pattern → Example → Now solve - 実装ステップ:プロンプト作成 → 1 回呼び出しで思考・行動生成 → 行動結果処理 → 次の思考へ → 最終回答。
- メリット:外部情報取得が簡単、推論過程可視化、対話型アプリに最適。
- デメリット:実装複雑・遅延増大・エラー管理必要。
ReAct を導入すれば、LLM が「自ら質問を解決するための手段」を持ち、より高度で信頼性の高い応答が可能になります。 🚀