利用来自 Hugging Face 的 SmolAgents 库构建多代理供应链模拟
- Rifx.Online
- Programming , Technology , Data Science
- 11 Jan, 2025
“smolagents — 一个构建优秀智能体的小型库”
供应链管理是一个复杂的领域,其中多个实体需要有效协调,以便将产品交付给最终消费者。现代供应链是一个复杂的网络,涉及供应商、制造商、分销商和零售商。对这些网络的仿真可以帮助我们理解瓶颈、优化操作并提高效率。
在本文中,我们将探讨如何使用 SmolAgents 构建一个复杂的供应链仿真,这是一个强大的多智能体系统创建库,包括:
- 动态供需管理
- 实时性能指标
- 成本计算
- 待发货跟踪
- 需求预测
什么是智能体?
任何使用 AI 的高效系统都需要为 LLM 提供某种访问现实世界的方式:例如,能够调用搜索工具以获取外部信息,或在某些程序上执行操作以解决任务。换句话说,LLM 应该具备 代理性。代理程序是 LLM 通往外部世界的门户。
AI 智能体是程序,其中 LLM 输出控制工作流程。
现在,让我们开始构建供应链仿真。
设置环境
1. 创建虚拟环境:
```bash
python -m venv venv
source venv/bin/activate # 在 Windows 上:venv\Scripts\activate
- 安装依赖:
pip install smolagents==0.1.0
- 运行模拟:
python main.py
## 系统架构
该供应链模拟由多个相互连接的组件组成,协同工作以模拟现实世界的供应链动态。我们的系统由四个主要代理组成,每个代理在 SmolAgent 中由一个 Tool 类表示:
1. **供应商代理**:管理原材料供应
2. **制造商代理**:将原材料转化为成品
3. **分销商代理**:处理物流和分配
4. **零售代理**:管理面向客户的操作
![](https://wsrv.nl/?url=https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*fEAT0jK9TfmDiauA)
## 技术深入分析
我们系统中的每个代理都是作为 SmolAgent Tool 实现的。让我们看看详细的实现:
```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
每个代理旨在处理特定的职责,同时与系统中的其他代理保持协调。
1. 需求预测
我们实施了一个复杂的需求预测系统,使用指数平滑法:
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 # 默认需求,如果历史数据不足
# 带趋势的简单指数平滑
alpha = 0.3 # 平滑因子
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. 性能指标
该模拟跟踪关键绩效指标(KPI):
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. 成本管理
我们跟踪供应链中的各种成本:
costs = {
"raw_material": 10,
"manufacturing": 15,
"distribution": 5,
"holding": 2,
"backorder": 20
}
4. 管理状态和更新
构建此模拟的关键挑战之一是管理所有代理的状态更新。我们是这样处理的:
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. 处理缺货订单
系统跟踪和管理缺货订单,以确保客户需求最终得到满足:
## Update backorders
new_backorders = total_demand - fulfilled_demand
state["backorders"] = new_backorders
## Update metrics
metrics.update_fill_rate(initial_demand, fulfilled_demand)
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)
仿真循环
我们系统的核心是协调所有代理的仿真循环:
- 更新需求预测
- 处理供应商操作
- 处理制造
- 管理分销
- 处理零售操作
- 更新指标和状态
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)
输出
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
多智能体供应链仿真中使用的模型
当前模型:Llama 3.3–70B-Instruct
在我们的实现中,我们通过 HuggingFace 的 API 使用 meta-llama/Llama-3.3-70B-Instruct
模型。该模型作为我们多智能体系统的核心协调者。
关键特性
- 模型大小: 70 亿参数
- 架构: 仅解码器的变换器
- 训练: 在多样化数据集上进行指令调优
- 专业化: 擅长遵循指令和协调复杂任务
- 上下文长度: 4096 个标记
- 响应风格: 结构化和遵循指令
我们选择这个模型的原因
- 指令遵循:擅长理解和执行复杂的供应链指令
- 上下文意识:能够在多个代理交互中保持上下文
- 输出质量:提供一致且结构良好的响应
- 性能:模型大小与推理速度之间的良好平衡
模型选择标准
实施考虑
- 模型加载
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. 自定义模型包装器
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. 性能监控
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))
未来模型改进
- 专业化训练
- 在供应链特定数据上进行微调
- 纳入行业特定约束
- 在历史供应链数据上进行训练
2. 混合方法
- 将机器学习与基于规则的系统结合
- 整合传统优化算法
- 使用强化学习进行动态适应
3. 模型优化
- 量化以加快推理速度
- 剪枝以减小模型大小
- 知识蒸馏以实现高效部署
未来增强
当前的供应链系统可以扩展为:
1. 基于机器学习的需求预测 2. 实时优化算法 3. 与外部数据源的集成 4. 更复杂的成本模型 5. 可视化分析和报告
## Sample code
def example_function():
print("This is an example.")
在使用 SmolAgent 过程中最佳实践和经验教训
1. 类型处理: 在 SmolAgent 工具中使用适当的类型定义2. 错误处理: 实施稳健的错误检查3. 状态管理: 保持状态更新的原子性和一致性4. 性能监控: 持续跟踪关键指标5. 代码组织: 保持关注点的清晰分离
结论
构建一个使用 SmolAgent 的多智能体供应链模拟展示了基于智能体建模在理解复杂系统中的强大能力。该模拟为测试不同策略和优化供应链操作提供了基础。
通过此实现,我们展示了如何:- 创建协调的多智能体系统 - 实现现实的供应链动态 - 跟踪和优化性能指标 - 处理复杂的状态管理 - 构建可扩展和可维护的代码