← Back to DevBytes

How to Implement Tree of Thoughts (ToT) Prompting

Introduction to Tree of Thoughts (ToT) Prompting

Tree of Thoughts (ToT) is an advanced prompting framework designed to enhance the reasoning capabilities of Large Language Models (LLMs). While traditional Chain of Thought (CoT) prompting encourages a model to think linearly—generating a single sequence of thoughts to reach a conclusion—ToT allows the model to explore multiple different reasoning paths simultaneously. It evaluates the progress of each path and can backtrack or look ahead, much like a human solving a complex puzzle.

This technique matters because many real-world problems are not strictly linear. Tasks that require strategic planning, mathematical problem-solving, or creative generation often involve dead ends. By framing the reasoning process as a search problem over a tree structure, ToT significantly improves an LLM's ability to solve complex tasks that require exploration, trial and error, and self-evaluation.

>>> NEW: The Self-Hosted Agent Factory — Production Kit

Run a 3-agent production line (orchestrator + workers + adversarial QC) on a $6/mo VPS. 120-page book + the complete working Docker stack: task ledger, model router, 15-min watchdog, QC rubric.

Launch price $29 (first 100 copies, then $59) →

How Tree of Thoughts Works

Implementing ToT requires breaking down the problem-solving process into four distinct components. Understanding these components is crucial before writing any code.

1. Thought Decomposition

The problem must be broken down into intermediate "thought" steps. Depending on the task, a thought could be a few words (for creative writing), a sentence (for crosswords), or a mathematical equation (for math problems). The granularity depends on what makes sense for the LLM to evaluate.

2. Thought Generation

At any given state in the tree, the LLM must generate multiple potential next thoughts. Instead of asking for one continuation, you prompt the model to provide several distinct, plausible next steps. This can be done by sampling multiple times with high temperature or by prompting the model to output a list of ideas in a single call.

3. State Evaluation

Once multiple thoughts are generated, the LLM acts as an evaluator to assess the quality of each state. The model can be prompted to either assign a numerical score (e.g., 1 to 10) or classify the state as "sure", "maybe", or "impossible". This heuristic helps the search algorithm decide which paths are worth exploring.

4. Search Algorithm

ToT utilizes classic search algorithms to traverse the tree of thoughts. The two most common are Breadth-First Search (BFS) and Depth-First Search (DFS). BFS keeps track of a set of the most promising states at each step, while DFS explores one path deeply, backtracking if the evaluator determines the current path is a dead end.

Implementing ToT in Python

To implement ToT, we will create a Python script that utilizes Breadth-First Search (BFS). We will use the OpenAI API to handle thought generation and evaluation. The script will explore multiple paths, evaluate them, and keep only the most promising ones until a solution is reached.

Setting Up the Environment

First, ensure you have the OpenAI Python package installed. You will also need an API key.

pip install openai

Generating and Evaluating Thoughts

Next, we will write the functions to generate multiple thoughts for a given state and evaluate the quality of a state. We will use a generic LLM wrapper to keep the logic clear.

import openai
import json

# Set your OpenAI API key here
openai.api_key = "YOUR_API_KEY"

def call_llm(prompt, temperature=0.7):
    """Helper function to call the LLM."""
    response = openai.ChatCompletion.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}],
        temperature=temperature
    )
    return response.choices[0].message.content.strip()

def generate_thoughts(problem, current_state, num_thoughts=3):
    """Generates multiple next steps based on the current state."""
    prompt = (
        f"You are solving this problem: {problem}\n"
        f"Current progress: {current_state}\n"
        f"Generate {num_thoughts} distinct next steps to continue solving the problem. "
        f"Format as a JSON array of strings."
    )
    response = call_llm(prompt, temperature=0.8)
    try:
        # Parse the JSON array of thoughts
        thoughts = json.loads(response)
        return thoughts
    except json.JSONDecodeError:
        return []

def evaluate_state(problem, state):
    """Evaluates the likelihood of the current state leading to a solution."""
    prompt = (
        f"You are evaluating progress on this problem: {problem}\n"
        f"Current proposed state: {state}\n"
        f"On a scale of 1 to 10, how likely is this state to lead to the correct final solution? "
        f"Output ONLY the integer score."
    )
    response = call_llm(prompt, temperature=0.2)
    try:
        score = int(response)
        return score
    except ValueError:
        return 0

Implementing the BFS Search

Now we combine the generation and evaluation functions into a Breadth-First Search algorithm. At each depth level, we will generate thoughts for all active states, evaluate the new states, and keep only the top breadth states for the next level.

def tree_of_thoughts_bfs(problem, max_depth=3, breadth=3):
    """Executes a Tree of Thoughts search using BFS."""
    # Start with an empty initial state
    current_states = [""]
    
    for depth in range(max_depth):
        print(f"Exploring depth {depth + 1}...")
        all_next_states = []
        
        for state in current_states:
            # Generate multiple thoughts for the current state
            thoughts = generate_thoughts(problem, state, num_thoughts=breadth)
            
            for thought in thoughts:
                # Append the new thought to the current state
                new_state = f"{state} {thought}".strip()
                
                # Evaluate the new state
                score = evaluate_state(problem, new_state)
                all_next_states.append((score, new_state))
        
        if not all_next_states:
            print("No valid thoughts generated. Stopping early.")
            break
            
        # Sort states by score in descending order
        all_next_states.sort(reverse=True, key=lambda x: x[0])
        
        # Keep only the top 'breadth' states for the next iteration
        current_states = [s[1] for s in all_next_states[:breadth]]
        
    # Return the highest scoring state at the final depth
    return current_states[0] if current_states else "No solution found."

# Example Usage
if __name__ == "__main__":
    problem = "Plan a 3-day itinerary for a trip to Paris for a history buff who loves food."
    best_plan = tree_of_thoughts_bfs(problem, max_depth=3, breadth=2)
    
    print("\n--- Best Plan Found ---")
    print(best_plan)

Best Practices for ToT Prompting

While ToT is powerful, it is also resource-intensive. Following best practices will help you get the most out of this technique without unnecessarily inflating costs or latency.

Conclusion

Tree of Thoughts prompting represents a significant leap forward in how we interact with Large Language Models. By treating reasoning as a search problem rather than a linear generation task, developers can unlock the ability of LLMs to solve complex, multi-step problems that were previously out of reach. While implementing ToT requires more setup and computational resources than standard prompting, the resulting improvements in accuracy, strategic planning, and problem-solving make it an invaluable tool for advanced AI applications. By carefully managing your search depth, breadth, and evaluation prompts, you can build robust systems that truly mimic human-like problem-solving strategies.

— Ad —

Google AdSense will appear here after approval

← Back to all articles