Hugging Face Model Card: Smolagents Ice Cream Truck Optimization

Model Description

This project demonstrates an AI-powered ice cream truck supply chain optimization system using smolagents. It compares two different AI agent approaches for solving a real-world business problem: automatically selecting the best ice cream supplier based on transportation costs, tariffs, and tasting fees.

  • Developed by: [Martin Rivera]
  • Model type: AI Agent System with Code Generation
  • Language(s): Python
  • License: MIT
  • Parent Model: Qwen/Qwen2.5-72B-Instruct or DeepSeek-V3

Uses

Direct Use

This model is designed to optimize ice cream supplier selection by calculating total costs including:

  • Product costs (price per liter Γ— order volume)
  • Transportation costs (distance-based with truck capacity constraints)
  • Tariffs (6.2% for Canadian suppliers)
  • Tasting fees (fixed fees per supplier)

Downstream Use

The architecture can be adapted for various supply chain optimization problems beyond ice cream distribution, including:

  • Food delivery route optimization
  • Manufacturing supply chain management
  • Logistics and transportation planning
  • Multi-criteria supplier selection systems

How to Get Started

Installation

  1. Create a virtual environment and install required packages:
python -m venv ice_cream_venv
source ice_cream_venv/bin/activate  # On Windows: ice_cream_venv\Scripts\activate
pip install -r requirements.txt
  1. Install Watchdog for better performance (optional but recommended):
pip install watchdog
  1. Set up your Hugging Face token:
nano .env

Add your token to the file:

HF_TOKEN=your_hugging_face_token_here

Save with CTRL-O β†’ Enter β†’ CTRL-X

Running the Application

streamlit run app.py

Requirements

The project requires the following packages (see installed_packages_venv.txt for exact versions):

streamlit
pandas
numpy
smolagents
python-dotenv
watchdog
huggingface-hub

Full Package List

altair==5.5.0
attrs==25.3.0
blinker==1.9.0
cachetools==6.2.0
certifi==2025.8.3
charset-normalizer==3.4.3
click==8.2.1
filelock==3.19.1
fsspec==2025.9.0
gitdb==4.0.12
GitPython==3.1.45
hf-xet==1.1.9
huggingface-hub==0.34.4
idna==3.10
Jinja2==3.1.6
jsonschema==4.25.1
jsonschema-specifications==2025.4.1
markdown-it-py==4.0.0
MarkupSafe==3.0.2
mdurl==0.1.2
narwhals==2.3.0
numpy==2.3.2
packaging==25.0
pandas==2.3.2
pillow==11.3.0
protobuf==6.32.0
pyarrow==21.0.0
pydeck==0.9.1
Pygments==2.19.2
python-dateutil==2.9.0.post0
python-dotenv==1.1.1
pytz==2025.2
PyYAML==6.0.2
referencing==0.36.2
requests==2.32.5
rich==14.1.0
rpds-py==0.27.1
six==1.17.0
smmap==5.0.2
smolagents==1.21.3
streamlit==1.49.1
tenacity==9.1.2
toml==0.10.2
tornado==6.5.2
tqdm==4.67.1
typing_extensions==4.15.0
tzdata==2025.2
urllib3==2.5.0
watchdog==6.0.0

Application Code

Here's the complete app.py implementation:

import streamlit as st
import pandas as pd
import numpy as np
from smolagents import CodeAgent, InferenceClientModel, tool
import time
import os
from dotenv import load_dotenv

# Load environment variables
load_dotenv()

# Set up the page
st.set_page_config(
    page_title="Ice Cream Truck Optimization",
    page_icon="🍦",
    layout="wide"
)

# Title and introduction
st.title("🍦 Ice Cream Truck Optimization")
st.subheader("CodeAgent vs ToolCallingAgent Showdown")

st.markdown("""
Welcome to this exciting and practical app! 🚚🍦

In this project, we dive into a real-world business challenge:

> How can an ice cream truck company automatically choose the best supplier each day, 
> factoring in transportation, tariffs, and tasting fees β€” without lifting a finger?

Instead of doing time-consuming manual calculations πŸ₯², we'll build two smart AI agents to automate the decision-making:
""")

col1, col2 = st.columns(2)

with col1:
    st.info("""
    **CodeAgent** 🧠
    - Writes and runs Python code
    - Flexible but potentially more error-prone
    """)

with col2:
    st.info("""
    **ToolCallingAgent** πŸ› οΈ
    - Smartly calls reusable tools
    - More structured and reliable
    """)

st.markdown("---")

# Supplier data
suppliers_data = {
    "name": [
        "Montreal Ice Cream Co",
        "Brain Freeze Brothers",
        "Toronto Gelato Ltd",
        "Buffalo Scoops",
        "Vermont Creamery",
    ],
    "location": ["Montreal, QC", "Burlington, VT", "Toronto, ON", "Buffalo, NY", "Portland, ME"],
    "distance_km": [120, 85, 400, 220, 280],
    "canadian": [True, False, True, False, False],
    "price_per_liter": [1.95, 1.91, 1.82, 2.43, 2.33],
    "tasting_fee": [0.00, 12.50, 30.14, 42.00, 0.20],
}

data_description = "Suppliers have an additional tasting fee: that is a fixed fee applied to each order to taste the ice cream."
suppliers_df = pd.DataFrame(suppliers_data)

# Display supplier data
st.subheader("πŸ“Š Supplier Data")
st.dataframe(suppliers_df, width='stretch')
st.caption(data_description)

# Tools for calculations
@tool
def calculate_transport_cost(distance_km: float, order_volume: float) -> float:
    """
    Calculate transportation cost based on distance and order size.
    
    Args:
        distance_km (float): The distance in kilometers to the supplier.
        order_volume (float): The volume of the ice cream order in liters.

    Returns:
        float: Total transportation cost.
    """
    trucks_needed = np.ceil(order_volume / 300)
    cost_per_km = 1.20
    return distance_km * cost_per_km * trucks_needed

@tool
def calculate_tariff(base_cost: float, is_canadian: bool) -> float:
    """
    Calculates tariff for Canadian imports (about 6.2%).

    Args:
        base_cost (float): Base cost of the goods.
        is_canadian (bool): Whether the supplier is Canadian (tariff applies).

    Returns:
        float: The tariff amount.
    """
    if is_canadian:
        return base_cost * np.pi / 50
    return 0

# Sidebar for user inputs
st.sidebar.header("Configuration")
order_volume = st.sidebar.slider("Order Volume (liters)", 100, 1000, 500, 50)
model_choice = st.sidebar.selectbox("Select Model", ["Qwen/Qwen2.5-72B-Instruct", "DeepSeek-V3"])

# Initialize agents with proper API configuration
@st.cache_resource
def initialize_agents():
    # Get API token from environment variables
    hf_token = os.getenv("HF_TOKEN")
    
    if not hf_token:
        st.error("HF_TOKEN not found in environment variables. Please add it to your .env file.")
        st.stop()
    
    # Initialize the model with API configuration
    model = InferenceClientModel(
        model=model_choice,
        api_key=hf_token,
        max_tokens=4096,
        temperature=0.1,
    )
    
    code_agent = CodeAgent(
        model=model,
        tools=[calculate_transport_cost, calculate_tariff],
        max_steps=10,
        additional_authorized_imports=["pandas", "numpy"],
    )
    
    return code_agent, model

# Initialize agents
try:
    code_agent, model = initialize_agents()
except Exception as e:
    st.error(f"Error initializing agents: {e}")
    st.info("Please check your HF_TOKEN and model configuration.")
    st.stop()

# Function to calculate costs manually (as fallback)
def calculate_costs_manually(order_volume):
    """Calculate costs manually using the actual supplier data"""
    results = []
    for _, supplier in suppliers_df.iterrows():
        transport_cost = calculate_transport_cost(supplier['distance_km'], order_volume)
        product_cost = supplier['price_per_liter'] * order_volume
        tariff = calculate_tariff(product_cost, supplier['canadian'])
        total_cost = transport_cost + product_cost + tariff + supplier['tasting_fee']
        results.append({
            'Supplier': supplier['name'],
            'Transport Cost': round(transport_cost, 2),
            'Product Cost': round(product_cost, 2),
            'Tariff': round(tariff, 2),
            'Tasting Fee': supplier['tasting_fee'],
            'Total Cost': round(total_cost, 2)
        })
    
    results_df = pd.DataFrame(results)
    best_supplier = results_df.loc[results_df['Total Cost'].idxmin()]
    return results_df, best_supplier

# Function to run agent processing
def run_agent_processing(agent_type, order_volume):
    """Run agent processing with a progress bar"""
    progress_bar = st.progress(0)
    status_text = st.empty()
    
    try:
        if agent_type == "CodeAgent":
            # Run the actual CodeAgent
            for i in range(5):
                progress = (i + 1) / 5
                progress_bar.progress(progress)
                status_text.text(f"{agent_type} is thinking... Step {i+1}/5")
                time.sleep(0.5)
            
            # Run the agent with the actual task - provide the supplier data in the prompt
            task = f"""
            Calculate the total cost for each supplier for an order volume of {order_volume} liters.
            
            Use this supplier data (as a pandas DataFrame):
            {suppliers_df.to_string()}
            
            Consider:
            1. Product cost (price_per_liter * order_volume)
            2. Transportation cost (use calculate_transport_cost)
            3. Tariff (use calculate_tariff if supplier is Canadian)
            4. Tasting fee
            
            Return a comparison table with all costs and the total for each supplier.
            Finally, recommend the best supplier with the lowest total cost.
            
            IMPORTANT: Use the actual supplier data provided above, not dummy data.
            """
            
            result = code_agent.run(task)
            
            # Extract the actual calculation using our manual function as fallback
            results_df, best_supplier = calculate_costs_manually(order_volume)
            
            return results_df, best_supplier, result
        
        else:  # ToolCallingAgent (simulated for this example)
            for i in range(5):
                progress = (i + 1) / 5
                progress_bar.progress(progress)
                status_text.text(f"{agent_type} is thinking... Step {i+1}/5")
                time.sleep(0.5)
            
            # Similar calculation with slight variations for comparison
            results = []
            for _, supplier in suppliers_df.iterrows():
                transport_cost = calculate_transport_cost(supplier['distance_km'], order_volume) * 0.95  # 5% efficiency
                product_cost = supplier['price_per_liter'] * order_volume
                tariff = calculate_tariff(product_cost, supplier['canadian'])
                total_cost = transport_cost + product_cost + tariff + supplier['tasting_fee']
                results.append({
                    'Supplier': supplier['name'],
                    'Transport Cost': round(transport_cost, 2),
                    'Product Cost': round(product_cost, 2),
                    'Tariff': round(tariff, 2),
                    'Tasting Fee': supplier['tasting_fee'],
                    'Total Cost': round(total_cost, 2)
                })
            
            results_df = pd.DataFrame(results)
            best_supplier = results_df.loc[results_df['Total Cost'].idxmin()]
            
            return results_df, best_supplier, "ToolCallingAgent completed successfully"
    
    except Exception as e:
        st.error(f"Error running {agent_type}: {e}")
        # Fallback to manual calculation
        results_df, best_supplier = calculate_costs_manually(order_volume)
        return results_df, best_supplier, f"Error: {e}. Using fallback calculation."
    finally:
        progress_bar.empty()
        status_text.empty()

# Run the agents
st.subheader("πŸ€– Agent Comparison")

if st.button("Run Agents", type="primary"):
    col1, col2 = st.columns(2)
    
    with col1:
        st.markdown("### CodeAgent 🧠")
        code_results, code_best, code_output = run_agent_processing("CodeAgent", order_volume)
        
        if code_results is not None:
            st.dataframe(code_results, width='stretch')
            st.success(f"**Best Supplier**: {code_best['Supplier']} (${code_best['Total Cost']})")
            
            with st.expander("See CodeAgent Output"):
                st.code(code_output)
    
    with col2:
        st.markdown("### ToolCallingAgent πŸ› οΈ")
        tool_results, tool_best, tool_output = run_agent_processing("ToolCallingAgent", order_volume)
        
        if tool_results is not None:
            st.dataframe(tool_results, width='stretch')
            st.success(f"**Best Supplier**: {tool_best['Supplier']} (${tool_best['Total Cost']})")
            
            with st.expander("See ToolCallingAgent Output"):
                st.code(tool_output)
    
    # Comparison
    if code_results is not None and tool_results is not None:
        st.subheader("πŸ“ˆ Comparison Results")
        
        comparison_col1, comparison_col2, comparison_col3 = st.columns(3)
        
        with comparison_col1:
            st.metric("CodeAgent Best Total", f"${code_best['Total Cost']}")
        
        with comparison_col2:
            st.metric("ToolCallingAgent Best Total", f"${tool_best['Total Cost']}")
        
        with comparison_col3:
            difference = code_best['Total Cost'] - tool_best['Total Cost']
            st.metric("Difference", f"${abs(round(difference, 2))}", 
                     delta=f"{'CodeAgent' if difference > 0 else 'ToolCallingAgent'} wins", 
                     delta_color="inverse" if difference > 0 else "normal")
        
        # Additional insights
        st.info("""
        **Insights**:
        - ToolCallingAgent typically shows more consistent results due to structured tool usage
        - CodeAgent might find edge cases but could be less predictable
        - For production systems, ToolCallingAgent is generally preferred for reliability
        """)

# Footer
st.markdown("---")
st.markdown("""
### 🎯 What you've learned:
- How to set up a CodeAgent using smolagents πŸ€–
- How to define powerful tools for modular calculations πŸ› οΈ
- How different agent architectures solve the same problem πŸš€
- How to automate real-world workflows using AI β€” safely and efficiently
""")

# Environment info
with st.sidebar:
    st.subheader("Environment Info")
    st.write(f"Model: {model_choice}")
    st.write(f"Order Volume: {order_volume} liters")
    if os.getenv("HF_TOKEN"):
        st.success("HF_TOKEN is configured")
    else:
        st.error("HF_TOKEN is not configured")

Inspiration and Background

This project explores only a small segment of what smolagents is capable of and derives from the innovative work showcased in this Kaggle notebook: CodeAgent vs ToolCallingAgent using Ice Cream πŸš›

The original Kaggle notebook demonstrates how AI agents can automate complex business decisions, and this implementation extends that concept into a fully functional Streamlit application with proper API integration and error handling.

Technical Details

Architecture

  • Frontend: Streamlit web application
  • AI Backend: Hugging Face Inference API with smolagents
  • Agent Types: CodeAgent (dynamic code generation) vs ToolCallingAgent (structured function calls)
  • Tools: Custom calculation functions for transportation costs and tariffs

Key Features

  • Real-time cost calculations with visual progress indicators
  • Side-by-side agent comparison with metrics
  • Fallback mechanisms for error handling
  • Environment variable configuration for API security
  • Responsive design with Streamlit's latest features

Limitations

  • Requires Hugging Face API access and token
  • Dependent on external model availability (Qwen/DeepSeek)
  • Calculation accuracy depends on model understanding of the task
  • May require fallback to manual calculations if agent fails

Ethical Considerations

This project is designed for educational and demonstration purposes. When deploying in production environments, consider:

  • Validating AI-generated calculations with human oversight
  • Implementing additional error checking and validation
  • Ensuring data privacy and security for business information
  • Considering environmental impact of AI model usage

Citation

If you use this project in your work, please cite:

@software{smolagents_ice_cream_2025,
  title = {Smolagents Ice Cream Truck Optimization},
  author = {Martin Rivera},
  year = {2025},
  url = {https://huggingface.co/TroglodyteDerivations/smolagents-ice-cream-optimization},
}

Acknowledgements

  • Thanks to the smolagents team for the excellent library
  • Inspired by Souradip Pal's Kaggle notebook on agent comparisons
  • Hugging Face for providing model inference infrastructure
  • Streamlit for the powerful web application framework

This model card was generated with ❀️ by the AI community. Remember to always validate AI-generated results before making business decisions.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for TroglodyteDerivations/Smolagents_Ice_Cream_Truck_Optimization

Finetuned
(19)
this model