
LANGCHAIN — What Are Planning Agents?
“Talk is cheap. Show me the code. — Linus Torvalds”
Planning agents are a type of agent architecture that separates the planning and execution of tasks. They promise faster, cheaper, and more performant task execution over traditional agent designs. In this article, we will explore three types of planning agents implemented in LangGraph.
Plan-and-Execute Agent
The Plan-and-Execute agent architecture is inspired by Wang, et. al.’s paper on Plan-and-Solve prompting and Yohei Nakajima’s BabyAGI project. It consists of a planner and executor components. The planner generates a multi-step plan using an LLM to complete a large task, and the executor accepts the user query and invokes one or more tools to execute the plan. Here’s a code snippet showcasing the basic structure of the Plan-and-Execute agent:
# Planner component
def generate_plan(user_query):
# Use LLM to generate a multi-step plan based on the user query
return multi_step_plan
# Executor component
def execute_step(user_query, step):
# Invoke one or more tools to execute the specified step in the plan
return step_resultReasoning WithOut Observations (ReWOO) Agent
The ReWOO agent architecture, proposed by Xu, et. al., removes the need to always use an LLM for each task while still allowing tasks to depend on previous task results by permitting variable assignment in the planner’s output. The planner generates a plan list consisting of interleaving “Plan” (reasoning) and “E#” lines, allowing tasks to execute without re-planning every time. Here’s a code snippet showcasing the ReWOO agent’s planner and worker components:
# Planner component
def generate_plan(user_query):
# Generate a plan list with interleaving "Plan" and "E#" lines
return interleaved_plan_list
# Worker component
def execute_task(task):
# Loop through each task and assign the task output to the corresponding variable
return task_outputLLMCompiler Agent
The LLMCompiler agent architecture, designed by Kim, et. al., is aimed at further increasing the speed of task execution. It consists of a planner that streams a Directed Acyclic Graph (DAG) of tasks, a Task Fetching Unit that schedules and executes the tasks, and a Joiner that dynamically replans or finishes based on the entire graph history. Here’s a code snippet showcasing the components of the LLMCompiler agent:
# Planner component
def stream_task_dag(user_query):
# Stream a Directed Acyclic Graph (DAG) of tasks
return task_dag_stream
# Task Fetching Unit component
def schedule_and_execute_task(task_stream):
# Schedule and execute tasks once their dependencies are met
return task_execution_result
# Joiner component
def dynamic_replanning_or_finish(task_execution_results):
# Dynamically replan or finish based on the entire graph history
return final_responseIn conclusion, planning agents offer a powerful design pattern for separating the planning and execution of tasks, resulting in faster, more cost-effective, and higher-performing task completion. These agent architectures can significantly reduce the time it takes to return a final result and help save costs by reducing the frequency of calls to more powerful LLMs.






