Smolagents Cheat Sheet
Hugging Face’s minimal library for agents that think in code.
Core idea: the LLM writes Python snippets to call your tools instead of emitting JSON tool calls. (~1,000 lines of core code, model-agnostic.)
Install
pip install smolagents # core
pip install 'smolagents[toolkit]' # + default tools (web search, etc.)
pip install 'smolagents[litellm]' # OpenAI / Anthropic / 100+ via LiteLLM
pip install 'smolagents[transformers]' # local HF models
pip install 'smolagents[mcp]' # MCP server integration
pip install 'smolagents[openai]' # OpenAI-compatible servers
pip install 'smolagents[telemetry]' # OpenTelemetry tracing
pip install 'smolagents[gradio]' # GradioUIHello, agent
from smolagents import CodeAgent, InferenceClientModel
model = InferenceClientModel() # default HF Inference model
agent = CodeAgent(tools=[], model=model)
print(agent.run("Sum the numbers from 1 to 10"))Agent types
from smolagents import ToolCallingAgent, WebSearchTool
agent = ToolCallingAgent(tools=[WebSearchTool()], model=model)Common constructor args
agent = CodeAgent(
tools=[...], # list of Tool INSTANCES (not classes)
model=model,
add_base_tools=True, # include the default toolbox
max_steps=10, # cap reasoning steps
verbosity_level=1, # 0 silent, 1 steps, 2 detailed
planning_interval=3, # re-plan every N steps (None = off)
stream_outputs=True,
additional_authorized_imports=["numpy", "pandas"], # CodeAgent only
executor_type="local", # "local" | "e2b" | "docker" | "blaxel" | "modal" | "wasm"
step_callbacks=[my_callback],
name="...", description="...", # only needed if used as a managed sub-agent
)Running
agent.run("task") # returns final answer
agent.run("task", reset=False) # keep memory (follow-up)
agent.run("task", additional_args={"key": value}) # inject objects/state
agent.run("Describe this", images=[pil_image]) # vision input
for chunk in agent.run("task", stream=True): ... # stream stepsModels
# HF Inference providers (Cerebras, Together, Novita, SambaNova, Fireworks, ...)
from smolagents import InferenceClientModel
model = InferenceClientModel(model_id="deepseek-ai/DeepSeek-R1", provider="together")
# LiteLLM -> OpenAI, Anthropic, Gemini, etc.
from smolagents import LiteLLMModel
model = LiteLLMModel(model_id="anthropic/claude-sonnet-4-5", api_key=os.environ["ANTHROPIC_API_KEY"], temperature=0.2)
# Any OpenAI-compatible endpoint (OpenAI, OpenRouter, Together, vLLM, Ollama...)
from smolagents import OpenAIServerModel # newer alias: OpenAIModel
model = OpenAIServerModel(model_id="gpt-4o", api_base="https://api.openai.com/v1", api_key=os.environ["OPENAI_API_KEY"])
# Local transformers pipeline
from smolagents import TransformersModel
model = TransformersModel(model_id="Qwen/Qwen2.5-Coder-32B-Instruct")Also available: AzureOpenAIModel, AmazonBedrockModel, MLXModel (Apple Silicon).
Tools
Default toolbox ([toolkit] extra)
WebSearchTool · DuckDuckGoSearchTool · GoogleSearchTool · VisitWebpageTool · PythonInterpreterTool · FinalAnswerTool · UserInputTool · SpeechToTextTool
Add them all with add_base_tools=True.
Custom tool — decorator (quick)
The function needs type hints + a docstring with an Args: section (these become the schema the LLM sees).
from smolagents import tool
@tool
def get_product_price(product_name: str) -> float:
"""Gets the price of a product.
Args:
product_name: The name of the product to look up.
"""
return PRICES[product_name]
agent = CodeAgent(tools=[get_product_price], model=model)Custom tool — class (full control)
from smolagents import Tool
class QueryTool(Tool):
name = "qdrant_query"
description = "Semantic search over the movie collection."
inputs = {
"query": {"type": "string", "description": "Text query, semantically close to targets."}
}
output_type = "string"
def forward(self, query: str) -> str:
... # your logic
return resultImport existing tools
# A Hugging Face Space as a tool
from smolagents import Tool
image_gen = Tool.from_space("black-forest-labs/FLUX.1-schnell", name="image_generator", description="Generate an image")
# Hub-shared tool
from smolagents import load_tool
t = load_tool("m-ric/text-to-image", trust_remote_code=True)
# LangChain tool
from smolagents import Tool
lc_tool = Tool.from_langchain(some_langchain_tool)Tool collections & MCP
# From a Hub collection (pulls tools from all Spaces in it)
from smolagents import ToolCollection, CodeAgent
coll = ToolCollection.from_hub("huggingface-tools/diffusion-tools-...", trust_remote_code=True)
agent = CodeAgent(tools=[*coll.tools], add_base_tools=True, model=model)
---
# From an MCP server (stdio)
from mcp import StdioServerParameters
params = StdioServerParameters(command="uvx", args=["mcp-server-fetch"])
with ToolCollection.from_mcp(params, trust_remote_code=True) as tc:
agent = CodeAgent(tools=[*tc.tools], model=model)
agent.run("Fetch the homepage of huggingface.co")
# From an MCP server (HTTP)
with ToolCollection.from_mcp(
{"url": "http://127.0.0.1:8000/mcp", "transport": "streamable-http"},
trust_remote_code=True,
) as tc:
agent = ToolCallingAgent(tools=[*tc.tools], model=model)
---Multi-agent (orchestration)Give a sub-agent a name + description, then pass it via managed_agents. The manager calls it like any other tool.
from smolagents import CodeAgent, ToolCallingAgent, WebSearchTool, VisitWebpageTool
web_agent = ToolCallingAgent(
tools=[WebSearchTool(), VisitWebpageTool()],
model=model,
name="web_search_agent",
description="Runs web searches. Give it your query as an argument.",
)
manager = CodeAgent(
tools=[],
model=model,
managed_agents=[web_agent],
additional_authorized_imports=["time", "numpy", "pandas"],
)
manager.run("Who is the CEO of Hugging Face, and what year were they born?"Secure code executionSecure code execution
Get Deeptij’s stories in your inbox
Join Medium for free to get updates from this writer.
CodeAgent runs locally by default (restricted interpreter: only your tools + a safe builtins/imports list). Authorize more withadditional_authorized_imports. For untrusted workloads, sandbox it:
agent = CodeAgent(tools=[...], model=model, executor_type="e2b") # needs E2B_API_KEY
agent = CodeAgent(tools=[...], model=model, executor_type="docker")
agent = CodeAgent(tools=[...], model=model, executor_type="blaxel") # BL_API_KEY + BL_WORKSPACE⚠️ The LLM can generate arbitrary code. Never authorize unsafe imports on untrusted input; prefer a sandbox in production.
Inspect, debug, replay
agent.memory.steps # full step-by-step record (task, thoughts, tool calls, observations, timings, tokens)
agent.replay() # pretty re-print of the whole run
agent.logs # raw logsStep callback (runs after each step — handy for logging or trimming memory):
from smolagents import ActionStep, CodeAgent
def log_step(step: ActionStep, agent: CodeAgent) -> None:
print(f"Done step {step.step_number}")
if step.step_number > 5:
step.observations_images = None # drop images to save tokens
agent = CodeAgent(tools=[...], model=model, step_callbacks=[log_step])Drive the loop manually:
from smolagents import TaskStep, ActionStep
agent.memory.steps.append(TaskStep(task="...", task_images=[]))
final = None; n = 1
while final is None and n <= 10:
s = ActionStep(step_number=n, observations_images=[])
final = agent.step(s)
agent.memory.steps.append(s); n += 1Share & serve
# Push / pull agents and tools to the Hub
agent.push_to_hub("username/my-agent")
agent = CodeAgent.from_hub("username/my-agent", trust_remote_code=True)
my_tool.push_to_hub("username/my-tool")
# Web UI
from smolagents import GradioUI
GradioUI(agent).launch()CLI
# generalist multi-step CodeAgent
smolagent "Plan a trip to Tokyo, Kyoto and Osaka" \
--model-type InferenceClientModel \
--model-id "Qwen/Qwen2.5-Coder-32B-Instruct" \
--imports pandas numpy \
--tools web_search
smolagent # interactive setup wizard (no prompt)
# vision web-browsing agent (uses helium)
webagent "Go to example.com and find the pricing page" \
--model-type LiteLLMModel --model-id gpt-4oQuick decisions
- CodeAgent vs ToolCallingAgent → composition/reasoning vs reliable atomic calls.
- Which model class → HF Inference:
InferenceClientModel· OpenAI/Anthropic/etc.:LiteLLMModel· any OpenAI-compatible URL:OpenAIServerModel· local:TransformersModel. - Custom tool → simple fn:
@tool· stateful/complex: subclassTool. - Production → set a low
max_steps, use a sandbox (e2b/docker), never trust raw imports, keep a human in the loop for tool calls.
Resources
Docs: huggingface.co/docs/smolagents
Repo: github.com/huggingface/smolagents








