Flaps

プロンプト ReAct

軽量モデルへ代表的なプロンプト手法を実際のコードで試しモデルの反応を確認します

記事作成日:2025-12-05, 著者: Hi6

このガイドはなぜ必要か?
現代のLLM(大規模言語モデル)は、正しく誘導されて初めて複雑な推論タスクを解決できます。以下に示す手法は、信頼性・説明可能性・高性能システム構築の「標準的ケア」として確立されています。それぞれが、モデルへの指示量や内部で考えるか外部ツールと対話するかという点で異なります。

影響力が大きい6つの手法を深掘り:


ReAct(Reason + Act)とは?

概要 LLM が「思考 (Reason) → 行動 (Act)」を繰り返しながら、外部情報の取得や計算・検索を行い、最終回答へ到達する手法です。


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: [ユーザーが入力する問題]

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️⃣ ベストプラクティス

  1. Action の定義は簡潔に
    • calculate, search, lookup など、わかりやすい名前に。
  2. 結果のフォーマット統一
    • Result: ... を必ず入れ、次の思考でパースしやすくする。
  3. ループ回数はタスクに応じて調整
    • 1〜5 回程度が多い。無限ループを避けるため「最大ステップ数」を設定。
  4. 外部API呼び出しは非同期化
    • Python の asyncio を使えば、複数行動を並列実行できる。
  5. ログ/デバッグ情報を残す
    • 例:Thought, Action, Result をファイルに書き出し、後から解析可能に。

🎯 まとめ

ReAct を導入すれば、LLM が「自ら質問を解決するための手段」を持ち、より高度で信頼性の高い応答が可能になります。 🚀