← Back to list

A Beginner’s Guide to Smolagents in Python

Part 8: Building Smarter Agents by Planning and Reflection

Partha Mishra in Data And Beyond · 2026-07-07 17:03 · 50 claps · 6.4 min read paywalled
#ai-agent #generative-ai-tools #python #smolagents #ai-agent-development
Open on Medium ↗
Wiki topics: AGT · AI Agents AI · AI · General

A Beginner’s Guide to Smolagents in Python

Part 8: Building Smarter Agents by Planning and Reflection

Photo by Maximalfocus on Unsplash

Photo by Maximalfocus on Unsplash

By the end of this chapter, you will be able to:

  • Understand why planning is essential for any autonomous agent.
  • Distinguish between reactive and planning-based agents.
  • Learn how we can decompose complex goals into smaller tasks.
  • Build a simple planning engine in Python.
  • Implement plan execution and monitoring.
  • Add reflection and self-correction to an agent.
  • Understand replanning and adaptive behavior.
  • Recognize how these ideas appear in modern agent frameworks.

Introduction

So far, we have built an agent that can:

  • Observe its environment.
  • Maintain state.
  • Use tools.
  • Store memories.
  • Reason about the next action.

Although this agent is considerably more capable than the one we built in Chapter 4, it still suffers from an important limitation.

It thinks one step at a time.

Imagine asking the agent: Research the latest developments in renewable energy, summarize the findings, create a presentation, and save it as a PDF.

A naive agent might attempt to solve the entire problem immediately.

A more intelligent agent would first pause and ask:

  1. What subtasks are required?
  2. In what order should they be completed?
  3. Which tools are needed?
  4. How will I know when the task is complete?

This process is called planning.

Planning transforms an agent from a reactive system into a deliberate problem solver.

Reactive vs. Planning Agents

A reactive agent responds directly to its current observation.

Image by Author

Image by Author

Reactive systems work well for simple tasks such as:

  • Answering questions.
  • Cleaning rooms.
  • Looking up information.
  • Performing calculations.

However, they struggle with large objectives.

Planning agents insert an additional step.

Image by Author

Image by Author

This extra layer allows the agent to solve much more complex problems.

Why Planning Matters

Suppose your task is to organize an international conference.

Would you immediately begin booking flights? Probably not.

Instead, you would create a plan.

For example:

  1. Select a venue.
  2. Determine the budget.
  3. Invite speakers.
  4. Arrange travel.
  5. Prepare presentation materials.
  6. Conduct the event.

Humans naturally decompose large problems. Agents must learn to do the same.

Goal Decomposition

Large goals become manageable when divided into smaller tasks.

Goal: Publish Technical Book

Possible decomposition:

To publish a book, do the following:

  1. Research
  2. Write Chapters
  3. Edit Manuscript
  4. Create Figures
  5. Format for KDP
  6. Publish

We can decompose each subtask into smaller tasks.

This hierarchical organization is one of the defining characteristics of intelligent planning systems.

Building a Simple Planner

Our planner receives a goal and returns an ordered list of tasks.

class Planner:
  def create_plan(self, goal):
    if goal == "Write Blog":
      return ["Research","Write Draft","Edit","Publish"]
    return []

The following is the usage of the above code:

planner = Planner()
plan = planner.create_plan("Write Blog")
print(plan)

Output:

Image by Author

Image by Author

Although simplistic, this introduces the idea that planning is a separate component from execution.

Separating Planning from Execution

The planner creates tasks, and the executor performs them. The following code executes the task from the plan list in the given sequence.

for task in plan:
  print(f"Executing: {task}")

Image by Author

Image by Author

Keeping these responsibilities separate makes the system easier to extend.

Tracking Progress

Agents should know where they are within a plan.

state =       {
          "current_step": 0,
          "completed_tasks": [],
          "remaining_tasks": plan.copy()
              }

After each completed task:

completed = state["remaining_tasks"].pop(0)
state["completed_tasks"].append(completed)
state["current_step"] += 1

Now the agent can monitor its own progress.

Reflection

Planning alone is insufficient.

The agent must evaluate whether its actions produced the desired outcome.

This process is called reflection.

After every action, the agent asks questions such as:

  • Did the action succeed?
  • Was the result expected?
  • Do I need additional information?
  • Should I revise my plan?

Reflection introduces self-awareness into the execution loop.

Building a Reflection Function

def reflect(task, result):
  if result == "Success":
    return "Continue"
  return "Replan"

The above reflection mechanism evaluates the outcomes rather than mindlessly executing the next task.

Updating the Agent Loop

Our execution loop now becomes:

Image by Author

Image by Author

Notice that execution is no longer strictly linear.

The agent can adapt based on what it observes.

Replanning

Suppose the plan contains the following steps:

Download the dataset, and the download fails.

Should the agent stop? No.

Instead, it should create a new plan, and the following are the possible alternatives:

  • Try another source.
  • Retry the download.
  • Notify the user.
  • Continue with available data.

Replanning enables resilience in the process.

Implementing Replanning

def replan(plan):
  print("Generating new plan…")
  plan.append("Retry Failed Task")
  return plan

Although this is a basic implementation of the idea, this demonstrates how plans can evolve during execution.

Reflection in Practice

Imagine the coding agent attempts to run a simple Python program, and we observe the following.

Observation: SyntaxError

Reflection: The program failed.

‘Identify the error,’ then ‘fix the code,’ and finally ‘run the code’ again.

This cycle continues until we achieve the goal.

Reflection allows the agent to learn from immediate feedback.

Monitoring Plan Completion

An agent should know when the entire plan gets complete.

if len(state["remaining_tasks"]) == 0:
  print("Goal Completed")

Without completion checks, an agent may continue executing unnecessary tasks.

Logging the Planning Process

Recording planning decisions makes debugging much easier.

state["plan_log"] = {
                      "goal": goal,
                      "plan": plan,
                      "completed": [],
                      "replans": 0
                    }

We should record every change to the plan.

Putting Everything Together

Our complete architecture now looks like this:

Image by Author

Image by Author

Notice how every component introduced in previous chapters now participates in a single integrated architecture.

Limitations of Our Planner

Although our planner works, it has several shortcomings.

Static Plans

Every plan is predefined. Real agents often generate plans dynamically.

No Prioritization

We are executing the tasks sequentially even if another order would be more efficient.

No Parallel Execution

Independent tasks cannot execute simultaneously in the process.

Limited Reflection

Our reflection mechanism checks only whether a task succeeded.

Sophisticated agents evaluate quality, efficiency, and correctness.

No Cost Awareness

The planner ignores execution time, API costs, and resource usage.

Production systems often optimize plans using these constraints.

How Modern Frameworks Extend These Ideas

Modern frameworks such as Smolagents build upon the planning concepts we’ve implemented by adding:

  • Plans generated by LLMs.
  • Dynamically decomposing the required tasks.
  • Automatic tool selection during planning.
  • Reflection driven by language models.
  • Structured execution traces.
  • Plan revision based on new observations.
  • Multi-step reasoning across complex workflows.
  • Integration with memory and retrieval systems.

Although their implementations are more sophisticated, the underlying architecture remains remarkably similar.

Looking Ahead

Over the past five chapters, we have built every major component of an autonomous agent:

  • An agent loop.
  • A reasoning mechanism.
  • A reusable tool system.
  • A memory architecture.
  • A planning and reflection engine.

At this point, you possess the conceptual foundation needed to understand modern agent frameworks.

In the next chapter, we will finally introduce Smolagents. Rather than treating it as a mysterious library, we will examine it through the lens of the systems we have already built. As you explore its architecture, you’ll recognize familiar ideas — agent loops, tools, memory, planning, and execution — implemented in a robust, production-ready framework.

Chapter Summary

In this chapter, we implemented the planning and reflection concepts in the agentic architecture and improved it over the previous architecture we saw in the last chapter.

We learned that reactive systems are often insufficient for solving complex, multi-step problems. By decomposing goals into subtasks, monitoring progress, evaluating outcomes, and revising plans when necessary, our agents became significantly more capable and resilient.

Planning, reflection, and replanning are the final foundational components of autonomous agent systems, and, together with the concepts developed in previous chapters, they provide a complete conceptual framework for understanding the design of modern agent libraries.

Exercises

Exercise 8.1

Please extend the logic of the previous ‘Planner class’ to generate different plans based on the goal type. Test the implementation with at least three distinct objectives.

Exercise 8.2

Modify the execution loop so that tasks can fail randomly. Implement a replanning strategy that retries failed tasks up to three times before abandoning the goal.

Exercise 8.3

Design a planner for an AI coding assistant. List the subtasks required to fix a software bug, and explain how reflection could improve the quality of the final solution.

Exercise 8.4

Enhance the reflection function to evaluate task quality using criteria such as correctness, efficiency, and completeness rather than a simple success/failure outcome.

Exercise 8.5

Draw a complete architecture diagram that combines the concepts from Chapters 4 through 8. Include the agent loop, tool registry, memory manager, planner, reflection module, state, and environment. Trace the flow of information through the system during the execution of a complex task.

If you have missed any of the previous articles, you can read them here.

I hope you have found this helpful. Thank you for reading.

Until we meet again!


메타데이터
post_id
0ed7fd23c8be
slug
a-beginners-guide-to-smolagents-in-python-0ed7fd23c8be
url
https://medium.com/data-and-beyond/a-beginners-guide-to-smolagents-in-python-0ed7fd23c8be
canonical_url
https://medium.com/data-and-beyond/a-beginners-guide-to-smolagents-in-python-0ed7fd23c8be
author_url
https://medium.com/@mishrapartha09
status
ok
fetched_at
2026-07-13 06:23:13