Type something to search...
Building a Multi-Agent Supply Chain Simulation with SmolAgents Library from Hugging Face

Building a Multi-Agent Supply Chain Simulation with SmolAgents Library from Hugging Face

smolagents — a smol library to build great agents”

Supply chain management is a complex domain where multiple entities need to coordinate effectively to deliver products to end consumers. Modern supply chains are intricate networks involving suppliers, manufacturers, distributors, and retailers. Simulating these networks can help us understand bottlenecks, optimize operations, and improve efficiency.

In this article, we’ll explore how to build a sophisticated supply chain simulation using SmolAgents, a powerful library for creating multi-agent systems, that includes:

  • Dynamic supply and demand management
  • Real-time performance metrics
  • Cost calculations
  • Backorder tracking
  • Demand forecasting

What are Agents?

Any efficient system using AI will need to provide LLMs some kind of access to the real world: for instance the possibility to call a search tool to get external information, or to act on certain programs in order to solve a task. In other words, LLMs should have agency. Agentic programs are the gateway to the outside world for LLMs.

AI Agents are programs where LLM outputs control the workflow.

Now, let’s start building a supply chain simulation.

Setting Up the Environment

1. Create a virtual environment:
```bash
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
  1. Install requirements:
pip install smolagents==0.1.0
  1. Run the simulation:
python main.py

## System Architecture

This supply chain simulation consists of multiple interconnected components working together to model real\-world supply chain dynamics. Our system consists of four main agents, each represented by a Tool class in SmolAgent:

1. **Supplier Agent**: Manages raw material supply
2. **Manufacturer Agent**: Converts raw materials into finished goods
3. **Distributor Agent**: Handles logistics and distribution
4. **Retail Agent**: Manages customer\-facing operations

![](https://wsrv.nl/?url=https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*fEAT0jK9TfmDiauA)


## Technical Deep Dive

Each agent in our system is implemented as a SmolAgent Tool. Let’s look at the detailed implementation:


```python
class SupplyTool(Tool):
    name = "supply_tool"
    description = "Supplies raw materials to the manufacturer."
    inputs = {
        "demand": {"type": "number", "description": "Demand from manufacturer"},
        "inventory": {"type": "number", "description": "Supplier's current inventory"}
    }
    output_type = "number"

    def forward(self, demand: int, inventory: int) -> int:
        supply = min(inventory, demand)
        return supply

Each agent is designed to handle specific responsibilities while maintaining coordination with other agents in the system.

1. Demand Forecasting

We implemented a sophisticated demand forecasting system using exponential smoothing:

class DemandForecast:
    def __init__(self, window_size=10):
        self.demand_history = deque(maxlen=window_size)
        self.window_size = window_size
        
    def update(self, actual_demand):
        self.demand_history.append(actual_demand)
        
    def forecast(self):
        if len(self.demand_history) < 2:
            return 30  # Default demand if not enough history
        
        # Simple exponential smoothing with trend
        alpha = 0.3  # Smoothing factor
        trend = (sum(np.diff(list(self.demand_history))) / (len(self.demand_history) - 1))
        last_demand = self.demand_history[-1]
        forecast = last_demand + alpha * trend
        return max(int(forecast), 0)

2. Performance Metrics

The simulation tracks key performance indicators (KPIs):

class PerformanceMetrics:
    def __init__(self):
        self.total_demand = 0
        self.fulfilled_demand = 0
        self.backorders = 0
        self.inventory_history = []
        self.total_costs = 0
        
    def update_fill_rate(self, demand, fulfilled):
        self.total_demand += demand
        self.fulfilled_demand += fulfilled
        self.backorders += demand - fulfilled
        
    def update_inventory(self, inventory_levels):
        # Calculate total inventory across all stages
        total_inventory = sum(inventory_levels.values())
        self.inventory_history.append(total_inventory)
        
    def update_costs(self, new_costs):
        self.total_costs += new_costs
        
    def calculate_metrics(self):
        fill_rate = (self.fulfilled_demand / self.total_demand * 100) if self.total_demand > 0 else 0
        avg_inventory = sum(self.inventory_history) / len(self.inventory_history) if self.inventory_history else 1
        inventory_turnover = self.fulfilled_demand / avg_inventory if avg_inventory > 0 else 0
        
        return {
            "fill_rate": round(fill_rate, 2),
            "inventory_turnover": round(inventory_turnover, 2),
            "backorders": self.backorders,
            "total_costs": round(self.total_costs, 2),
            "average_inventory": round(avg_inventory, 2)
        }

3. Cost Management

We track various costs throughout the supply chain:

costs = {
    "raw_material": 10,
    "manufacturing": 15,
    "distribution": 5,
    "holding": 2,
    "backorder": 20
}

4. Managing State and Updates

One of the key challenges in building this simulation was managing state updates across all agents. Here’s how we handle it:

def calculate_daily_costs(state, supply, production, distribution):
    daily_costs = (
        supply * costs["raw_material"] +
        production * costs["manufacturing"] +
        distribution * costs["distribution"] +
        (state["supplier_inventory"] + state["manufacturer_inventory"] + 
         state["distributor_inventory"] + state["retail_inventory"]) * costs["holding"] +
        state["backorders"] * costs["backorder"]
    )
    return daily_costs

5. Handling Backorders

The system tracks and manages backorders to ensure customer demand is eventually met:

## Update backorders
new_backorders = total_demand - fulfilled_demand
state["backorders"] = new_backorders
## Update metrics
metrics.update_fill_rate(initial_demand, fulfilled_demand)

6. Dynamic Inventory Management

The simulation includes dynamic inventory adjustments:

## Daily updates
state["manufacturer_capacity"] = 50
state["supplier_inventory"] += random.randint(10, 20)
state["retailer_customer_demand"] = max(30 + random.randint(-5, 5), 0)

The Simulation Loop

The heart of our system is the simulation loop that coordinates all agents:

  1. Update demand forecast
  2. Process supplier operations
  3. Handle manufacturing
  4. Manage distribution
  5. Process retail operations
  6. Update metrics and state

for step in range(5):
    print(f"\nStep {step + 1}")
    print("Starting state:", state)
    initial_demand = state["retailer_customer_demand"]

    # 1. Update demand forecast
    state["forecast_demand"] = demand_forecast.forecast()
    print(f"Forecast demand: {state['forecast_demand']}")

    # 2. Supply raw materials
    manufacturer_demand = max(state["forecast_demand"] - state["manufacturer_inventory"], 0)
    supply = supply_tool.forward(manufacturer_demand, state["supplier_inventory"])
    state["supplier_inventory"] -= supply
    print_state_changes(state, step, "Supply", {"Raw materials supplied": supply})
    time.sleep(0.5)

    # 3. Manufacturing
    production = manufacture_tool.forward(
        raw_material=supply,
        capacity=state["manufacturer_capacity"],
        demand=manufacturer_demand
    )
    state["manufacturer_capacity"] -= production
    state["manufacturer_inventory"] += production
    print_state_changes(state, step, "Production", {"Goods manufactured": production})

    # 4. Distribution
    distributor_intake = min(state["manufacturer_inventory"], 50 - state["distributor_inventory"])
    state["manufacturer_inventory"] -= distributor_intake
    state["distributor_inventory"] += distributor_intake
    
    retail_supply = distribute_tool.forward(
        inventory=state["distributor_inventory"],
        demand=state["retailer_customer_demand"] + state["backorders"]
    )
    state["distributor_inventory"] -= retail_supply
    state["retail_inventory"] += retail_supply

    # 5. Retail sales and backorder management
    total_demand = state["retailer_customer_demand"] + state["backorders"]
    fulfilled_demand = retail_tool.forward(
        customer_demand=total_demand,
        available_stock=state["retail_inventory"]
    )
    state["retail_inventory"] -= fulfilled_demand
    
    # Update backorders
    new_backorders = total_demand - fulfilled_demand
    state["backorders"] = new_backorders

    # Update metrics
    metrics.update_fill_rate(initial_demand, fulfilled_demand)
    metrics.update_inventory({
        "supplier": state["supplier_inventory"],
        "manufacturer": state["manufacturer_inventory"],
        "distributor": state["distributor_inventory"],
        "retail": state["retail_inventory"]
    })
    
    daily_costs = calculate_daily_costs(state, supply, production, retail_supply)
    metrics.update_costs(daily_costs)

    # 6. Daily updates
    state["manufacturer_capacity"] = 50
    state["supplier_inventory"] += random.randint(10, 20)
    state["retailer_customer_demand"] = max(30 + random.randint(-5, 5), 0)
    demand_forecast.update(state["retailer_customer_demand"])

    # Print performance metrics
    print("\nPerformance Metrics:")
    current_metrics = metrics.calculate_metrics()
    for metric, value in current_metrics.items():
        print(f"{metric}: {value}")

    print("\nEnd state:", state)

Output

Step 1
Starting state: {'supplier_inventory': 100, 'manufacturer_capacity': 50, 'manufacturer_inventory': 0, 'distributor_inventory': 50, 'retailer_customer_demand': 30, 'retail_inventory': 0, 'backorders': 0, 'forecast_demand': 30}
Forecast demand: 30

--- Step 1: Supply ---
Raw materials supplied: 30

--- Step 1: Production ---
Goods manufactured: 30

Performance Metrics:
fill_rate: 100.0
inventory_turnover: 0.25
backorders: 0
total_costs: 1140
average_inventory: 120.0

End state: {'supplier_inventory': 90, 'manufacturer_capacity': 50, 'manufacturer_inventory': 30, 'distributor_inventory': 20, 'retailer_customer_demand': 26, 'retail_inventory': 0, 'backorders': 0, 'forecast_demand': 30}

Step 2
Starting state: {'supplier_inventory': 90, 'manufacturer_capacity': 50, 'manufacturer_inventory': 30, 'distributor_inventory': 20, 'retailer_customer_demand': 26, 'retail_inventory': 0, 'backorders': 0, 'forecast_demand': 30}
Forecast demand: 26

--- Step 2: Supply ---
Raw materials supplied: 0

--- Step 2: Production ---
Goods manufactured: 0

Performance Metrics:
fill_rate: 100.0
inventory_turnover: 0.48
backorders: 0
total_costs: 1498
average_inventory: 117.0

End state: {'supplier_inventory': 100, 'manufacturer_capacity': 50, 'manufacturer_inventory': 0, 'distributor_inventory': 24, 'retailer_customer_demand': 29, 'retail_inventory': 0, 'backorders': 0, 'forecast_demand': 26}

Step 3
Starting state: {'supplier_inventory': 100, 'manufacturer_capacity': 50, 'manufacturer_inventory': 0, 'distributor_inventory': 24, 'retailer_customer_demand': 29, 'retail_inventory': 0, 'backorders': 0, 'forecast_demand': 26}
Forecast demand: 26

--- Step 3: Supply ---
Raw materials supplied: 26

--- Step 3: Production ---
Goods manufactured: 26

Performance Metrics:
fill_rate: 100.0
inventory_turnover: 0.78
backorders: 0
total_costs: 2483
average_inventory: 109.67

End state: {'supplier_inventory': 87, 'manufacturer_capacity': 50, 'manufacturer_inventory': 0, 'distributor_inventory': 21, 'retailer_customer_demand': 28, 'retail_inventory': 0, 'backorders': 0, 'forecast_demand': 26}

Step 4
Starting state: {'supplier_inventory': 87, 'manufacturer_capacity': 50, 'manufacturer_inventory': 0, 'distributor_inventory': 21, 'retailer_customer_demand': 28, 'retail_inventory': 0, 'backorders': 0, 'forecast_demand': 26}
Forecast demand: 27

--- Step 4: Supply ---
Raw materials supplied: 27

--- Step 4: Production ---
Goods manufactured: 27

Performance Metrics:
fill_rate: 100.0
inventory_turnover: 1.11
backorders: 0
total_costs: 3458
average_inventory: 102.25

End state: {'supplier_inventory': 72, 'manufacturer_capacity': 50, 'manufacturer_inventory': 0, 'distributor_inventory': 20, 'retailer_customer_demand': 26, 'retail_inventory': 0, 'backorders': 0, 'forecast_demand': 27}

Step 5
Starting state: {'supplier_inventory': 72, 'manufacturer_capacity': 50, 'manufacturer_inventory': 0, 'distributor_inventory': 20, 'retailer_customer_demand': 26, 'retail_inventory': 0, 'backorders': 0, 'forecast_demand': 27}
Forecast demand: 27

--- Step 5: Supply ---
Raw materials supplied: 27

--- Step 5: Production ---
Goods manufactured: 27

Performance Metrics:
fill_rate: 100.0
inventory_turnover: 1.46
backorders: 0
total_costs: 4395
average_inventory: 95.0

End state: {'supplier_inventory': 65, 'manufacturer_capacity': 50, 'manufacturer_inventory': 0, 'distributor_inventory': 21, 'retailer_customer_demand': 33, 'retail_inventory': 0, 'backorders': 0, 'forecast_demand': 27}

Final Simulation Metrics:
fill_rate: 100.0
inventory_turnover: 1.46
backorders: 0
total_costs: 4395
average_inventory: 95.0

Model used in Multi-Agent Supply Chain Simulation

Current Model: Llama 3.3–70B-Instruct

In our implementation, we use the meta-llama/Llama-3.3-70B-Instruct model through HuggingFace’s API. This model serves as the central coordinator for our multi-agent system.

Key Characteristics

  • Model Size: 70 billion parameters
  • Architecture: Decoder-only transformer
  • Training: Instruction-tuned on diverse datasets
  • Specialization: Strong at following instructions and coordinating complex tasks
  • Context Length: 4096 tokens
  • Response Style: Structured and instruction-following

Why We Chose This Model

  1. Instruction Following: Excellent at understanding and executing complex supply chain instructions
  2. Context Awareness: Can maintain context across multiple agent interactions
  3. Output Quality: Provides consistent and well-structured responses
  4. Performance: Good balance between model size and inference speed

Model Selection Criteria

Implementation Considerations

  1. Model Loading
from smolagents import HfApiModel

def initialize_model(model_type="large"):
    model_configs = {
        "large": "meta-llama/Llama-3.3-70B-Instruct",
        "medium": "meta-llama/Llama-2-13b-chat",
        "small": "meta-llama/Llama-2-7b-chat"
    }
    
    return HfApiModel(model_id=model_configs[model_type])

2. Custom Model Wrapper

class SupplyChainModel:
    def __init__(self, base_model, config=None):
        self.model = base_model
        self.config = config or {}
        
    def process_agent_action(self, agent_type, state, action):
        context = self._build_context(agent_type, state)
        response = self.model.generate(context)
        return self._parse_response(response)

3. Performance Monitoring

class ModelPerformanceTracker:
    def __init__(self):
        self.response_times = []
        self.accuracy_metrics = []
        
    def log_performance(self, start_time, end_time, predicted, actual):
        self.response_times.append(end_time - start_time)
        self.accuracy_metrics.append(self._calculate_accuracy(predicted, actual))

Future Model Improvements

  1. Specialized Training
  • Fine-tune on supply chain specific data
  • Incorporate industry-specific constraints
  • Train on historical supply chain data

2. Hybrid Approaches

  • Combine machine learning with rule-based systems
  • Integrate traditional optimization algorithms
  • Use reinforcement learning for dynamic adaptation

3. Model Optimization

  • Quantization for faster inference
  • Pruning for smaller model size
  • Knowledge distillation for efficient deployment

Future Enhancements

The current supply chain system could be extended with:

1. Machine learning-based demand forecasting2. Real-time optimization algorithms3. Integration with external data sources4. More sophisticated cost models5. Visual analytics and reporting

Best Practices and Lessons Learned while working with SmolAgent

1. Type Handling: Use proper type definitions in SmolAgent tools2. Error Handling: Implement robust error checking3. State Management: Keep state updates atomic and consistent4. Performance Monitoring: Track key metrics continuously5. Code Organization: Maintain clear separation of concerns

Conclusion

Building a multi-agent supply chain simulation with SmolAgent demonstrates the power of agent-based modeling in understanding complex systems. The simulation provides a foundation for testing different strategies and optimizing supply chain operations.

Through this implementation, we’ve shown how to:- Create coordinated multi-agent systems- Implement realistic supply chain dynamics- Track and optimize performance metrics- Handle complex state management- Build extensible and maintainable code

Source Code

I am still making some changes in the code. Please comment if you want me to share the complete code on GitHub.

#Python, #SupplyChain, #MultiAgentSystems #SmolAgent #HuggingFace

Related Posts

10 Creative Ways to Use ChatGPT Search The Web Feature

10 Creative Ways to Use ChatGPT Search The Web Feature

For example, prompts and outputs Did you know you can use the “search the web” feature of ChatGPT for many tasks other than your basic web search? For those who don't know, ChatGPT’s new

Read More
📚 10 Must-Learn Skills to Stay Ahead in AI and Tech 🚀

📚 10 Must-Learn Skills to Stay Ahead in AI and Tech 🚀

In an industry as dynamic as AI and tech, staying ahead means constantly upgrading your skills. Whether you’re aiming to dive deep into AI model performance, master data analysis, or transform trad

Read More
10 Powerful Perplexity AI Prompts to Automate Your Marketing Tasks

10 Powerful Perplexity AI Prompts to Automate Your Marketing Tasks

In today’s fast-paced digital world, marketers are always looking for smarter ways to streamline their efforts. Imagine having a personal assistant who can create audience profiles, suggest mar

Read More
10+ Top ChatGPT Prompts for UI/UX Designers

10+ Top ChatGPT Prompts for UI/UX Designers

AI technologies, such as machine learning, natural language processing, and data analytics, are redefining traditional design methodologies. From automating repetitive tasks to enabling personal

Read More
100 AI Tools to Finish Months of Work in Minutes

100 AI Tools to Finish Months of Work in Minutes

The rapid advancements in artificial intelligence (AI) have transformed how businesses operate, allowing people to complete tasks that once took weeks or months in mere minutes. From content creat

Read More
17 Mindblowing GitHub Repositories You Never Knew Existed

17 Mindblowing GitHub Repositories You Never Knew Existed

Github Hidden Gems!! Repositories To Bookmark Right Away Learning to code is relatively easy, but mastering the art of writing better code is much tougher. GitHub serves as a treasur

Read More