The Core Difference

Smolagents ships two agent types with fundamentally different execution models. Most frameworks hide this choice. Smolagents makes it explicit.

CodeAgent ToolCallingAgent
How it calls tools Writes and executes Python code Calls tools via structured JSON (like OpenAI function calling)
Flexibility Very high — can compose tools in loops, conditionals, list comprehensions Moderate — one tool per step, structured inputs only
Security risk Code execution — requires sandboxing in production Low — no arbitrary code execution
Model requirement Works best with models that can write clean Python Works with any instruction-following model
Debugging Inspect the generated code directly Inspect the tool call JSON

CodeAgent: What It Actually Does

CodeAgent asks the model to write a Python snippet that calls your tools, then executes that snippet in a local Python interpreter. The model can use loops, string manipulation, and multi-step logic in a single turn — something JSON-based tool calling cannot do without multiple API calls.

from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel
 
model = HfApiModel('meta-llama/Meta-Llama-3.1-70B-Instruct')
 
agent = CodeAgent(
    tools=[DuckDuckGoSearchTool()],
    model=model,
)
 
result = agent.run(
    'Find the 3 most recent Python releases and return their version numbers and dates'
)
# The model writes a Python loop to search, parse, and format the results
 

The generated code is something like:

# Model-generated code (you can inspect this with agent.logs)
results = []
for query in ['Python 3.13 release date', 'Python 3.12 release date', 'Python 3.11 release date']:
    r = search(query)
    results.append(r)
final_answer(', '.join(results))
 
CodeAgent executes Python in the same process by default. In production, enable the sandboxed executor: CodeAgent(..., executor_type='e2b') to run code in an E2B sandbox, or use the 'local' executor only behind strict input validation.

ToolCallingAgent: When to Use It

ToolCallingAgent uses the model's native function-calling capability. One tool per turn, structured JSON inputs. Safer, more predictable, slower for multi-step tasks that need iteration.

from smolagents import ToolCallingAgent, DuckDuckGoSearchTool, HfApiModel
from smolagents import tool
 
@tool
def get_stock_price(ticker: str) -> str:
    '''Get the current stock price for a given ticker symbol.
    Args:
        ticker: The stock ticker symbol (e.g. AAPL, GOOG)
    '''
    # Your implementation here
    return f'${ticker}: $150.00'
 
agent = ToolCallingAgent(
    tools=[DuckDuckGoSearchTool(), get_stock_price],
    model=HfApiModel('meta-llama/Meta-Llama-3.1-70B-Instruct'),
)
 
result = agent.run('What is Apple\'s current stock price?')
 

The @tool Decorator

Both agent types use the same @tool decorator to define custom tools. The docstring is critical — Smolagents uses it to build the tool description the model sees. Write it clearly.

from smolagents import tool
 
@tool
def query_database(sql: str, database: str = 'production') -> str:
    '''Execute a read-only SQL query and return results as JSON.
    Only SELECT statements are allowed. Use this to look up customer records,
    order history, or product inventory.
    Args:
        sql: The SELECT query to run
        database: Database name: 'production' or 'staging'
    '''
    if not sql.strip().upper().startswith('SELECT'):
        return 'Error: Only SELECT queries are allowed'
    # ... execute query ...
    return '{"rows": [...]}'
 
For CodeAgent, write tool docstrings as if explaining to a programmer. For ToolCallingAgent, write them as if explaining to a helpful assistant who needs to decide when to use the tool. The audiences are slightly different.

Model Selection by Agent Type

Agent Type Recommended Models Avoid
CodeAgent Llama 3.1 70B+, Qwen 2.5 Coder, GPT-4o, Claude Sonnet Small models (< 7B) — code quality degrades quickly
ToolCallingAgent Any model with function calling support — Llama 3.1 8B works well Models without native function calling

Decision Guide

Use CodeAgent when:

  • Your task requires iterating over a list and calling a tool once per item
  • You want the agent to do post-processing (filter, sort, format) without an extra tool
  • You are prototyping and want maximum flexibility
  • You can sandbox code execution (E2B, container, or trusted internal environment)

Use ToolCallingAgent when:

  • You are exposing the agent to untrusted inputs (user-submitted queries)
  • You need predictable, auditable tool calls (compliance, logging requirements)
  • Your task is straightforward single-tool lookups
  • You are using a smaller or less capable model