|

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

🔑

In this tutorial, we construct a sophisticated, production-ready agentic system utilizing SmolAgents and reveal how trendy, light-weight AI brokers can motive, execute code, dynamically handle instruments, and collaborate throughout a number of brokers. We begin by putting in dependencies and configuring a strong but environment friendly LLM backend, and then progressively design customized instruments, together with mathematical utilities, reminiscence storage, and net search capabilities. We discover each CodeAgent and ToolCallingAgent paradigms, perceive how instruments are managed dynamically by the agent.instruments 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", "wealthy")


import os, math, textwrap
from wealthy.console import Console
from wealthy.panel   import Panel
from wealthy.desk   import Table
from wealthy         import print as rprint


console = Console()


def part(title: str, shade: str = "daring cyan"):
   console.rule(f"[{color}]{title}[/{color}]")


def present(label: str, worth):
   console.print(Panel(str(worth), title=f"[bold yellow]{label}[/bold yellow]", increase=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]")


part("SECTION 1 · SmolAgents Architecture")


console.print(Panel("""
SmolAgents (HuggingFace) is a minimalist agent framework.
Current secure launch: 1.24.0   |   Using: OpenAI gpt-4o-mini


CORE ABSTRACTIONS
 Tool
 agent.instruments (dict)
 ToolAssortment
 LiteLLMModel
 CodeAgent
 ToolCallingAgent


MULTI-AGENT  (v1.8+ API)
 Pass sub-agents instantly through  managed_agents=[sub_agent]
 Sub-agents want  identify=  and  description=  set at init.
 ManagedAgent wrapper class was eliminated in v1.8.0.


EXECUTION LOOP (CodeAgent)
 Task ──► LLM writes Python ──► sandbox executes it
      ◄── commentary (device output / exception) ◄──
 Repeats up to max_steps, then calls final_answer(...)
""", title="[bold green]Architecture[/bold green]"))

We set up all required dependencies and arrange the execution setting. We configure safe API key loading and initialize the wealthy console utilities for structured output formatting. We additionally introduce the architectural overview of SmolAgents to set up a robust conceptual basis earlier than constructing brokers.

part("SECTION 2 · Building Custom Tools")


from smolagents import Tool, device


@device
def celsius_to_fahrenheit(celsius: float) -> str:
   return f"{celsius}°C = {celsius * 9/5 + 32:.2f}°F"


class PrimeTool(Tool):


   identify        = "prime_checker"
   description = (
       "If composite, returns the smallest prime issue."
   )
   inputs = {
       "n": {"sort": "integer", "description": "Positive integer to take a look at."}
   }
   output_type = "string"


   def ahead(self, n: int) -> str:
       if n < 2:
           return f"{n} isn't prime (have to be >= 2)."
       for i in vary(2, int(math.isqrt(n)) + 1):
           if n % i == 0:
               return f"{n} is NOT prime. Smallest issue: {i}."
       return f"{n} IS prime!"


class MemoTool(Tool):


   identify        = "memory_store"
   description = (
       "Stores or retrieves key-value pairs. "
       "motion='set' shops key+worth; "
       "motion='get' retrieves by key; "
       "motion='record' reveals all keys."
   )
   inputs = {
       "motion":  get ,
       "key":    {"sort": "string", "description": "Memory key (skip for record)", "nullable": True},
       "worth":  {"sort": "string", "description": "Value to retailer (set solely)",  "nullable": True},
   }
   output_type = "string"


   def __init__(self, *args, **kwargs):
       tremendous().__init__(*args, **kwargs)
       self._store: dict[str, str] = {}


   def ahead(self, motion: str, key: str = None, worth: str = None) -> str:
       if motion == "set":
           self._store[key] = worth
           return f"Stored '{key}' = '{worth}'"
       elif motion == "get":
           return self._store.get(key, f"Key '{key}' not discovered.")
       elif motion == "record":
           return "Keys: " + ", ".be part of(self._store.keys()) if self._store else "Memory empty."
       return "Unknown motion. Use: set | get | record"

We outline customized instruments utilizing each decorator-based and class-based approaches to reveal flexibility in device creation. We implement mathematical reasoning and a stateful reminiscence device to allow persistent interactions throughout agent steps. We construction the instruments with clear schemas so the brokers can interpret and invoke them accurately.

class DuckDuckGoTool(Tool):


   identify        = "web_search"
   description = "Performs an internet search and returns prime outcomes as plain textual content."
   inputs = {
       "question":       {"sort": "string",  "description": "The search question."},
       "max_results": {"sort": "integer", "description": "Results to return (1-10).", "nullable": True},
   }
   output_type = "string"


   def ahead(self, question: str, max_results: int = 3) -> str:
       strive:
           from duckduckgo_search import DDGS
           with DDGS() as ddgs:
               outcomes = [
                   f"* {r['title']}n  {r['href']}n  {r['body'][:200]}"
                   for r in ddgs.textual content(question, max_results=max_results)
               ]
           return "nn".be part of(outcomes) if outcomes else "No outcomes discovered."
       besides Exception as e:
           return f"Search failed: {e}"


@device
def factorial(n: int) -> str:
   return f"{n}! = {math.factorial(n)}"


present("celsius_to_fahrenheit(100)", celsius_to_fahrenheit(100))
present("PrimeTool — 97",             PrimeTool().ahead(97))
present("PrimeTool — 100",            PrimeTool().ahead(100))
m = MemoTool()
m.ahead("set", "creator", "Ada Lovelace")
present("MemoTool get 'creator'",      m.ahead("get", "creator"))


part("SECTION 3 · Managing Tools  (agent.instruments dict)")


console.print(Panel("""
The Toolbox class was eliminated in v1.x.
Tools reside in  agent.instruments, a plain Python dict keyed by device identify.
""", title="[bold green]Tools Dict[/bold green]"))


part("SECTION 4 · LLM Engines")


console.print(Panel("""
SmolAgents helps a number of LLM backends through  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 prepared:[/green] {MODEL_ID}")

We lengthen the system with an internet search device and a factorial utility to broaden the agent’s capabilities. We take a look at the instruments independently to confirm correctness earlier than integrating them into brokers. We additionally initialize the LLM engine utilizing LiteLLMModel, getting ready the core reasoning backend for execution.

part("SECTION 5 · CodeAgent")


from smolagents import CodeAgent


code_agent = CodeAgent(
   instruments           = [celsius_to_fahrenheit, PrimeTool(), MemoTool(), DuckDuckGoTool()],
   mannequin           = engine,
   max_steps       = 6,
   verbosity_level = 1,
)


console.print("n[bold]Initial agent.instruments keys:[/bold]", record(code_agent.instruments.keys()))
code_agent.instruments["factorial"] = factorial
console.print("[dim]After including factorial:[/dim]", record(code_agent.instruments.keys()))


console.print("n[bold yellow]Task 1:[/bold yellow]")
result1 = code_agent.run(
   "Convert boiling level (100C) and physique temperature (37C) to Fahrenheit. "
   "Which is increased and by how a lot?"
)
present("CodeAgent — Task 1", result1)


console.print("n[bold yellow]Task 2:[/bold yellow]")
result2 = code_agent.run("What is 17 instances 19? Is that outcome prime? Also examine 7919.")
present("CodeAgent — Task 2", result2)


console.print("n[bold yellow]Task 3:[/bold yellow]")
result3 = code_agent.run("Compute 10! utilizing the factorial device.")
present("CodeAgent — Task 3", result3)

We assemble a CodeAgent that may write and execute Python dynamically to clear up multi-step issues. We reveal runtime device injection by including a brand new device with out rebuilding the agent. We then execute progressively complicated reasoning duties to validate chaining, arithmetic computation, and device coordination.

part("SECTION 6 · ToolCallingAgent (ReAct)")


from smolagents import ToolCallingAgent


react_agent = ToolCallingAgent(
   instruments           = [celsius_to_fahrenheit, PrimeTool(), MemoTool()],
   mannequin           = engine,
   max_steps       = 5,
   verbosity_level = 1,
)


console.print("n[bold yellow]Task 4:[/bold yellow]")
result4 = react_agent.run(
   "Then retrieve each details and summarise them."
)
present("ToolCallingAgent — Task 4", result4)


part("SECTION 7 · Multi-Agent Orchestration  (v1.8+ API)")


math_agent = CodeAgent(
   instruments           = [PrimeTool()],
   mannequin           = engine,
   max_steps       = 4,
   identify            = "math_specialist",
   description     = "Handles mathematical questions and primality checks.",
   verbosity_level = 0,
)


research_agent = ToolCallingAgent(
   instruments           = [DuckDuckGoTool(), MemoTool()],
   mannequin           = engine,
   max_steps       = 4,
   identify            = "research_specialist",
   description     = "Searches the online and shops or retrieves details from reminiscence.",
   verbosity_level = 0,
)


manager_agent = CodeAgent(
   instruments           = [],
   mannequin           = 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 12 months Python was first launched (use research_specialist), "
   "then examine whether or not that 12 months is a chief quantity (use math_specialist)."
)
present("Manager Agent — Task 5", result5)

We construct a ToolCallingAgent to showcase structured ReAct-style reasoning with managed device invocation. We then implement a multi-agent orchestration system the place specialised brokers collaborate beneath a supervisor agent. We reveal delegation, coordination, and cross-agent reasoning to clear up compound duties effectively.

In conclusion, we constructed a completely practical multi-agent system able to reasoning, looking, calculating, storing reminiscence, and delegating duties between specialised brokers. We demonstrated how SmolAgents allows versatile device integration, runtime extensibility, and structured collaboration with out pointless architectural complexity. We confirmed how CodeAgent executes actual Python logic for superior chaining, whereas ToolCallingAgent ensures structured, auditable reasoning loops. Finally, we carried out a supervisor agent that coordinates specialised sub-agents, proving how scalable orchestration might be achieved with minimal overhead.


Check out the Full Implementation Code and Notebook. Also, be happy to observe us on Twitter and don’t overlook to be part of 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 companion with us for selling your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar and so on.? Connect with us

The put up A Coding Implementation to Build Multi-Agent AI Systems with SmolAgents Using Code Execution, Tool Calling, and Dynamic Orchestration appeared first on MarkTechPost.

Similar Posts