Coding Implementation to Build Multi-Agent AI Systems with SmolAgents Using Coding, Tool Calling, and Dynamic Orchestration

In this tutorial, we build an advanced, production-ready agent system using SmolAgents and show how modern, lightweight AI agents can think, code, handle dynamic tools, and interact across multiple agents. We start by installing dependencies and configuring the powerful yet efficient LLM backend, then gradually design custom tools, including statistical utilities, memory storage, and web search capabilities. We explore both the CodeAgent and ToolCallingAgent paradigms, understand how tools are managed dynamically through the agent.tools dictionary, and implement multi-agent orchestration.
import subprocess, sys
def pip(*args):
subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", *args])
pip("smolagents[all]", "duckduckgo-search", "wikipedia", "rich")
import os, math, textwrap
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich import print as rprint
console = Console()
def section(title: str, color: str = "bold cyan"):
console.rule(f"[{color}]{title}[/{color}]")
def show(label: str, value):
console.print(Panel(str(value), title=f"[bold yellow]{label}[/bold yellow]", expand=False))
import getpass
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
if not OPENAI_API_KEY:
OPENAI_API_KEY = getpass.getpass("🔑 Enter your OpenAI API key: ")
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
console.print("[green]✓ OpenAI API key loaded.[/green]")
section("SECTION 1 · SmolAgents Architecture")
console.print(Panel("""
SmolAgents (HuggingFace) is a minimalist agent framework.
Current stable release: 1.24.0 | Using: OpenAI gpt-4o-mini
CORE ABSTRACTIONS
Tool
agent.tools (dict)
ToolCollection
LiteLLMModel
CodeAgent
ToolCallingAgent
MULTI-AGENT (v1.8+ API)
Pass sub-agents directly via managed_agents=[sub_agent]
Sub-agents need name= and description= set at init.
ManagedAgent wrapper class was removed in v1.8.0.
EXECUTION LOOP (CodeAgent)
Task ──► LLM writes Python ──► sandbox executes it
◄── observation (tool output / exception) ◄──
Repeats up to max_steps, then calls final_answer(...)
""", title="[bold green]Architecture[/bold green]"))
We install all the necessary dependencies and set up the working environment. We're ready to load a secure API key and launch rich console resources for structured output formatting. We also present an overview of SmolAgents architecture to establish a solid conceptual foundation before building agents.
section("SECTION 2 · Building Custom Tools")
from smolagents import Tool, tool
@tool
def celsius_to_fahrenheit(celsius: float) -> str:
return f"{celsius}°C = {celsius * 9/5 + 32:.2f}°F"
class PrimeTool(Tool):
name = "prime_checker"
description = (
"If composite, returns the smallest prime factor."
)
inputs = {
"n": {"type": "integer", "description": "Positive integer to test."}
}
output_type = "string"
def forward(self, n: int) -> str:
if n < 2:
return f"{n} is not prime (must be >= 2)."
for i in range(2, int(math.isqrt(n)) + 1):
if n % i == 0:
return f"{n} is NOT prime. Smallest factor: {i}."
return f"{n} IS prime!"
class MemoTool(Tool):
name = "memory_store"
description = (
"Stores or retrieves key-value pairs. "
"action='set' stores key+value; "
"action='get' retrieves by key; "
"action='list' shows all keys."
)
inputs = {
"action": {"type": "string", "description": "set | get | list"},
"key": {"type": "string", "description": "Memory key (skip for list)", "nullable": True},
"value": {"type": "string", "description": "Value to store (set only)", "nullable": True},
}
output_type = "string"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._store: dict[str, str] = {}
def forward(self, action: str, key: str = None, value: str = None) -> str:
if action == "set":
self._store[key] = value
return f"Stored '{key}' = '{value}'"
elif action == "get":
return self._store.get(key, f"Key '{key}' not found.")
elif action == "list":
return "Keys: " + ", ".join(self._store.keys()) if self._store else "Memory empty."
return "Unknown action. Use: set | get | list"
We define custom tools using both decorator-based and class-based methods to provide flexibility in creating tools. We use mathematical reasoning and a good memory tool to enable continuous interaction in all steps of the agent. We build tools with clear schemas so agents can interpret and call them correctly.
class DuckDuckGoTool(Tool):
name = "web_search"
description = "Performs a web search and returns top results as plain text."
inputs = {
"query": {"type": "string", "description": "The search query."},
"max_results": {"type": "integer", "description": "Results to return (1-10).", "nullable": True},
}
output_type = "string"
def forward(self, query: str, max_results: int = 3) -> str:
try:
from duckduckgo_search import DDGS
with DDGS() as ddgs:
results = [
f"* {r['title']}n {r['href']}n {r['body'][:200]}"
for r in ddgs.text(query, max_results=max_results)
]
return "nn".join(results) if results else "No results found."
except Exception as e:
return f"Search failed: {e}"
@tool
def factorial(n: int) -> str:
return f"{n}! = {math.factorial(n)}"
show("celsius_to_fahrenheit(100)", celsius_to_fahrenheit(100))
show("PrimeTool — 97", PrimeTool().forward(97))
show("PrimeTool — 100", PrimeTool().forward(100))
m = MemoTool()
m.forward("set", "author", "Ada Lovelace")
show("MemoTool get 'author'", m.forward("get", "author"))
section("SECTION 3 · Managing Tools (agent.tools dict)")
console.print(Panel("""
The Toolbox class was removed in v1.x.
Tools live in agent.tools, a plain Python dict keyed by tool name.
""", title="[bold green]Tools Dict[/bold green]"))
section("SECTION 4 · LLM Engines")
console.print(Panel("""
SmolAgents supports multiple LLM backends via LiteLLMModel.
We use gpt-4o-mini.
""", title="[bold green]Engine Options[/bold green]"))
from smolagents import LiteLLMModel
MODEL_ID = "openai/gpt-4o-mini"
engine = LiteLLMModel(model_id=MODEL_ID, api_key=OPENAI_API_KEY)
console.print(f"[green]Engine ready:[/green] {MODEL_ID}")
We extend the system with a web search tool and a factorial service to increase the agent's capabilities. We independently test tools to ensure correctness before integrating them into agents. We also implement the LLM engine using LiteLLMModel, preparing the underlying logic for implementation.
section("SECTION 5 · CodeAgent")
from smolagents import CodeAgent
code_agent = CodeAgent(
tools = [celsius_to_fahrenheit, PrimeTool(), MemoTool(), DuckDuckGoTool()],
model = engine,
max_steps = 6,
verbosity_level = 1,
)
console.print("n[bold]Initial agent.tools keys:[/bold]", list(code_agent.tools.keys()))
code_agent.tools["factorial"] = factorial
console.print("[dim]After adding factorial:[/dim]", list(code_agent.tools.keys()))
console.print("n[bold yellow]Task 1:[/bold yellow]")
result1 = code_agent.run(
"Convert boiling point (100C) and body temperature (37C) to Fahrenheit. "
"Which is higher and by how much?"
)
show("CodeAgent — Task 1", result1)
console.print("n[bold yellow]Task 2:[/bold yellow]")
result2 = code_agent.run("What is 17 times 19? Is that result prime? Also check 7919.")
show("CodeAgent — Task 2", result2)
console.print("n[bold yellow]Task 3:[/bold yellow]")
result3 = code_agent.run("Compute 10! using the factorial tool.")
show("CodeAgent — Task 3", result3)
We're building a CodeAgent that can dynamically write and use Python to solve multi-step problems. We demonstrate runtime tool injection by adding a new tool without rebuilding the agent. We then perform complex logic operations further to verify convergence, arithmetic, and device connectivity.
section("SECTION 6 · ToolCallingAgent (ReAct)")
from smolagents import ToolCallingAgent
react_agent = ToolCallingAgent(
tools = [celsius_to_fahrenheit, PrimeTool(), MemoTool()],
model = engine,
max_steps = 5,
verbosity_level = 1,
)
console.print("n[bold yellow]Task 4:[/bold yellow]")
result4 = react_agent.run(
"Then retrieve both facts and summarise them."
)
show("ToolCallingAgent — Task 4", result4)
section("SECTION 7 · Multi-Agent Orchestration (v1.8+ API)")
math_agent = CodeAgent(
tools = [PrimeTool()],
model = engine,
max_steps = 4,
name = "math_specialist",
description = "Handles mathematical questions and primality checks.",
verbosity_level = 0,
)
research_agent = ToolCallingAgent(
tools = [DuckDuckGoTool(), MemoTool()],
model = engine,
max_steps = 4,
name = "research_specialist",
description = "Searches the web and stores or retrieves facts from memory.",
verbosity_level = 0,
)
manager_agent = CodeAgent(
tools = [],
model = engine,
managed_agents = [math_agent, research_agent],
max_steps = 8,
verbosity_level = 1,
)
console.print("n[bold yellow]Task 5:[/bold yellow]")
result5 = manager_agent.run(
"Find out what year Python was first released (use research_specialist), "
"then check whether that year is a prime number (use math_specialist)."
)
show("Manager Agent — Task 5", result5)
We created a ToolCallingAgent to demonstrate ReAct-style structured reasoning for managed tool requests. We then implement a multi-agent orchestration system where specialized agents interact under a manager agent. We demonstrate delegation, collaboration, and multi-agent reasoning to solve complex tasks efficiently.
In conclusion, we have built a fully functional multi-agent system that can reason, search, compute, store memory, and delegate tasks between specialized agents. We showed how SmolAgents allows flexible tool integration, runtime scalability, and streamlined interactions without unnecessary architectural complexity. We showed how CodeAgent implements the real Python concept of advanced integration, while ToolCallingAgent ensures structured, readable logic loops. Finally, we implemented a manager agent that coordinates specialized sub-agents, proving how scalable orchestration can be achieved with minimal overhead.
Check out Full Implementation Code and notebook. Also, feel free to follow us Twitter and don't forget to join our 130k+ ML SubReddit and Subscribe to Our newspaper. Wait! are you on telegram? now you can join us on telegram too.
Need to work with us on developing your GitHub Repo OR Hug Face Page OR Product Release OR Webinar etc.? contact us



