SkillAgentSearch skills...

Saplings

Plug-and-play tree search for agents

Install / Use

/learn @shobrook/Saplings
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

🌳 Saplings

Add tree search to your agent in two lines of code.

<!--**Build agents that can see the future.**-->

Most agents call tools on a loop: run a tool, observe the result, then pick the next one. But if they make a mistake early, it can snowball and ruin the final output. Since these agents can't look ahead or backtrack, one bad call can derail the whole loop.

Saplings fixes this by adding tree search. Agents can explore and evaluate tool-use trajectories to find the best one. Think of it like Stockfish for your agent. They can look multiple steps ahead, compare outcomes, and choose the optimal path.

Demo

<!--TODO: Show an animation of deep research using tree search side-by-side with regular deep research-->

Benchmarks

Saplings agents beat traditional ReAct-style agents across the board on a variety of benchmarks:

| Category | Benchmark | ReAct | ReAct + tree search | | -------------- | --------- | ----- | ------------------- | | Q&A / RAG | HotpotQA | 32.0% | 71.0% | | Programming | HumanEval | 56.9% | 83.8% | | Programming | MBPP | 67.0% | 81.1% | | Web Navigation | WebShop | 53.8% | 75.9% |

Source: Language Agent Tree Search Unifies Reasoning, Acting, and Planning in Language Models (ICML 2024)

Features

  • Two lines of code to add search to your agent
  • Supports popular search algorithms: Monte Carlo Tree Search (MCTS), A*, and greedy best-first search
  • Uses OpenAI/Anthropic-style tool-calling under the hood
  • Customize the value function, prompts, search parameters, etc.
  • Supports 100+ LLMs, including local models
<!--TODO: Build a simple visualizer like this: https://www.llm-reasoners.net/visualizer/709cb8d3-f6da-49be-b705-549fbfc44bf9?accessKey=b5681f71 -->

Installation

$ pip install saplings

Quickstart

<!--Let's build an agent that uses a web search tool to complete tasks. Our agent will be equipped with Monte Carlo Tree Search (MCTS) as a reasoning algorithm. ```python from saplings.examples import WebSearchTool from saplings import MonteCarloAgent, Evaluator, OpenAI model = OpenAI(model="gpt-4o") evaluator = Evaluator(model) tools = [WebSearchTool()] agent = MonteCarloAgent(tools, model, evaluator) messages, _, _ = agent.run("Create a table comparing ancient astronomical tools with their origin, accuracy, and modern equivalents.") ```-->

Below is a simple agent implementing Monte Carlo tree search (MCTS). It's equipped with a multiplication tool to solve tricky arithmetic problems.

from saplings.examples import MultiplicationTool
from saplings import MonteCarloAgent, Evaluator, Model

model = Model(model="openai/gpt-4o") # Wraps LiteLLM
evaluator = Evaluator(model)
tools = [MultiplicationTool()]

agent = MonteCarloAgent(tools, model, evaluator)
messages, _, _ = agent.run("Let x = 9418.343 * 8.11 and y = 2x. Calculate (xy)(x^2).")

This is the "bare minimum" for setting up a search agent with saplings –– just a few lines of code. There are a lot more parameters you can control, all covered in the docs. But let's first walk through the basics of creating your own tools and configuring an agent.

Creating a tool

Tools are what your agent will use to perform a task or answer a query. Each tool must extend the Tool base class and implement a few variables and methods. Here's an example of a simple tool that multiples two numbers together:

from saplings.abstract import Tool

class MultiplicationTool(Tool):
   def __init__(self, **kwargs):
      self.name = "multiply"
      self.description = "Multiplies two numbers and returns the result number."
      self.parameters = {
         "type": "object",
         "properties": {
            "a": {
               "type": "number",
               "description": "The number to multiply."
            },
            "b": {
               "type": "number",
               "description": "The number to multiply by."
            }
         },
         "required": ["a", "b"],
         "additionalProperties": False
      }
      self.is_terminal = False

   async def run(self, a, b, **kwargs):
      return a * b

Variables:

The instance variables in the class tell the agent when and how to call the tool. If you've used OpenAI function calling before, most of this should be familiar to you.

  • name (str): Name of the tool.
  • description (str): Description of what the tool does and when to call it.
  • parameters (dict): Arguments for the tool as a JSON schema.
  • is_terminal (bool): If True, calling this tool will terminate a search trajectory –– meaning, no subsequent tools can be called after this one. This is typically used for tools that generate a final output for the user (e.g. an answer to a question). More on this here.

run() method:

This is what actually executes the tool when the agent calls it. Arguments should be the same as the input parameters in the tool schema.

Advanced options:

There are additional things you can do with tools, such as accessing the agent's memory during tool execution, or controlling how tool output is shown to the model (vs. how it's stored in memory). You can read about these options here.

Configuring an agent

Choosing a model:

Saplings wraps LiteLLM to provide access to 100+ LLMs. Choose a model from their list of supported providers and create a Model object with it:

from saplings import Model

model = Model("openai/gpt-4o")

Note: any additional kwargs will be passed down to all the LiteLLM completion calls.

Setting up the evaluator:

This is what will guide the search process. The evaluator takes a search trajectory (i.e. a list of OpenAI-style messages) and returns a score between 0 and 1, indicating how promising the trajectory is. By default, a score of 1.0 means the agent has solved the problem and can terminate the search. You can change the solution cutoff by setting the threshold parameter in the agent –– more on that here.

from saplings import Evaluator

evaluator = Evaluator(model)

The default evaluator provided by saplings uses a LLM (i.e. the model you pass in above) to score trajectories. The Evaluator object has parameters that let you control things like the system prompt used and the sampling rate. You can also define your own custom evaluator if necessary. Read more about evaluators here.

Choosing an agent/search algorithm:

Once your tools, model, and evaluator are ready, you can simply plug them into a saplings agent. There are multiple to choose from, each implementing their own tree search algorithm: MonteCarloAgent, AStarAgent, and GreedyAgent. There's also a regular chain-of-thought agent available, COTAgent, which does not implement any search. Each agent has their own advantages and disadvantages, which you can read about here.

from saplings import MonteCarloAgent

agent = MonteCarloAgent(tools, model, evaluator)

This will initialize your agent. To actually run it on an input, call the run method. To run it asynchronously, call the run_async method.

messages, score, is_solution = agent.run("What's 2 * 2?") # await agent.run_async("What's 2 * 2?")

The output is a list of messages representing the best tool-use trajectory, the final score of the trajectory (as given by the evaluator), and whether or not the search terminated because the evaluator deemed the trajectory a solution to the prompt. The messages are Message objects, which are special objects native to saplings that wrap OpenAI messages.

Notably, there are many more parameters you can set for the agent, such as the system prompt that governs it.

Docs

Agents

Parameters

Every agent in saplings has the same parameters, listed below:

  1. tools (List[Tool]): List of tools your agent can use.
  2. model (Model): LLM provider that your agent will use to call tools.
  3. evaluator (BaseEvaluator): Evaluation function that the agent will use to guide the search process.
  4. prompt (str): System prompt for the agent.
  5. b_factor (int): Branching factor, i.e. the number of potential next tool calls to evaluate at each step in a search trajectory. Note that this parameter does not do anything for COTAgent.
  6. max_depth (int): Maximum depth of the search tree, indicating how many levels the agent can explore.
  7. threshold (float): A cutoff value for the evaluation function. If a trajectory's evaluation score is above this threshold, the search will terminate and that trajectory will be accepted as the solution.<!--TODO: Note the exception here-->
  8. verbose (bool): Whether to print logging statements when you run the agent.
  9. tool_choice ("auto" | "re
View on GitHub
GitHub Stars271
CategoryDevelopment
Updated14d ago
Forks19

Languages

Python

Security Score

100/100

Audited on Mar 8, 2026

No findings