Source: MarkTechPost
In this tutorial, we build an advanced, production-ready agentic system using SmolAgents and demonstrate how modern, lightweight AI agents can reason, execute code, dynamically manage tools, and collaborate across multiple agents. We start by installing dependencies and configuring a powerful yet efficient LLM backend, and then progressively design custom tools, including mathematical utilities, memory storage, and web search capabilities. We explore both 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 required dependencies and set up the execution environment. We configure secure API key loading and initialize the rich console utilities for structured output formatting. We also introduce the architectural overview of SmolAgents to establish a strong 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 approaches to demonstrate flexibility in tool creation. We implement mathematical reasoning and a stateful memory tool to enable persistent interactions across agent steps. We structure the tools with clear schemas so the agents can interpret and invoke 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 utility to broaden the agent’s capabilities. We test the tools independently to verify correctness before integrating them into agents. We also initialize the LLM engine using LiteLLMModel, preparing the core reasoning backend for execution.
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 construct a CodeAgent that can write and execute Python dynamically to solve multi-step problems. We demonstrate runtime tool injection by adding a new tool without rebuilding the agent. We then execute progressively complex reasoning tasks to validate chaining, arithmetic computation, and tool coordination.
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 build a ToolCallingAgent to showcase structured ReAct-style reasoning with controlled tool invocation. We then implement a multi-agent orchestration system where specialized agents collaborate under a manager agent. We demonstrate delegation, coordination, and cross-agent reasoning to solve compound tasks efficiently.
In conclusion, we constructed a fully functional multi-agent system capable of reasoning, searching, calculating, storing memory, and delegating tasks between specialized agents. We demonstrated how SmolAgents enables flexible tool integration, runtime extensibility, and structured collaboration without unnecessary architectural complexity. We showed how CodeAgent executes real Python logic for advanced chaining, while ToolCallingAgent ensures structured, auditable reasoning loops. Finally, we implemented a manager agent that coordinates specialized sub-agents, proving how scalable orchestration can be achieved with minimal overhead.
Check out the Full Implementation Code and Notebook. Also, feel free to follow us on Twitter and don’t forget to join our 130k+ ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.
Need to partner with us for promoting your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar etc.? Connect with us
