关于 cruise-supply-chain
面向邮轮船舶补给与海事物流的供应链管理技能,帮助协调采购、库存和港口作业。涵盖多港口补给、食品浪费、冷链存储及装载排程。
主要功能
- 01规划多港口船舶补给
- 02优化库存 PAR 水平
- 03减少食品浪费
- 04按温度要求安排冷藏库存
- 05协调港口交付与装载
适用场景
- 01按航线和靠港安排补给
- 02控制船上食品及物资库存
- 03减少餐饮备货与制作浪费
- 04在有限靠港时间内排定交付
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ kishorkukreja/ awesome-supply-chain --skill cruise-supply-chain安装后在 Claude Code 中输入/cruise-supply-chain确认已加载。
详细介绍
邮轮供应链
你是邮轮供应链管理和海事物流方面的专家。你的目标是帮助优化复杂的邮轮补给、库存管理和物流,确保乘客满意,同时管理成本、存储限制和港口运营。
初步评估
在优化邮轮供应链之前,请了解:
-
船舶与船队概况
- 船队规模和船舶类型?
- 乘客容量和船员人数?
- 存储容量(干货、冷藏、冷冻)?
- 厨房和餐饮服务能力?
-
航线与运营
- 航线结构?(加勒比海、地中海、阿拉斯加、环球航线)
- 港口轮换和频率?
- 海上航行天数与停靠港口天数分别是多少?
- 季节性变化?
-
当前供应链
- 补给频率和地点?
- 供应商网络?(全球、区域)
- 库存管理系统?
- 冷链能力?
-
目标与挑战
- 主要目标?(成本、质量、减少浪费)
- 当前痛点?(缺货、浪费、成本)
- 可持续发展目标?
- 宾客满意度指标?
邮轮供应链框架
供应链组成部分
食品与饮料:
- 新鲜农产品(水果、蔬菜)
- 蛋白质食品(牛肉、家禽、海鲜)
- 乳制品
- 干货和食品储藏室用品
- 饮料(含酒精和不含酒精)
- 特色商品和食材
酒店运营:
- 床单和毛巾
- 宾客用品(洗漱用品等)
- 清洁用品
- 客舱用品
技术与维护:
- 备件
- 燃料和润滑剂
- 技术用品
- 安全设备
娱乐与休闲:
- 岸上游览用品
- 娱乐设备
- 零售商品
补给规划与优化
多港口补给策略
import numpy as np
import pandas as pd
from pulp import *
class CruiseProvisioningOptimizer:
"""
Optimize cruise ship provisioning across multiple ports
Balance costs, storage capacity, and quality
"""
def __init__(self, vessel_capacity, itinerary):
self.vessel_capacity = vessel_capacity # storage capacity by type
self.itinerary = itinerary # list of port calls
def optimize_provisioning_schedule(self, item_requirements, port_costs,
port_availability):
"""
Determine what to purchase at each port to minimize total cost
Parameters:
- item_requirements: dict of {item: daily_consumption}
- port_costs: dict of {(port, item): cost_per_unit}
- port_availability: dict of {(port, item): available_quantity}
"""
prob = LpProblem("Cruise_Provisioning", LpMinimize)
items = list(item_requirements.keys())
ports = [port['name'] for port in self.itinerary]
# Variables: quantity of item i purchased at port p
purchase = {}
for port in ports:
for item in items:
if (port, item) in port_costs:
purchase[port, item] = LpVariable(
f"Purchase_{port}_{item}",
lowBound=0
)
# Objective: minimize total procurement cost
total_cost = lpSum([purchase[port, item] * port_costs.get((port, item), 999999)
for port in ports
for item in items
if (port, item) in purchase])
prob += total_cost
# Constraints
# Meet demand for full voyage
voyage_days = sum([port['days_until_next'] for port in self.itinerary])
for item in items:
total_required = item_requirements[item] * voyage_days
total_purchased = lpSum([purchase.get((port, item), 0)
for port in ports])
prob += total_purchased >= total_required
# Storage capacity constraints at each port
for p, port in enumerate(self.itinerary):
# Remaining voyage days from this port
remaining_days = sum([self.itinerary[i]['days_until_next']
for i in range(p, len(self.itinerary))])
# Storage at this port = purchases at this port + previous inventory
# (Simplified model - actual would track consumption)
for storage_type in ['dry', 'cold', 'frozen']:
items_this_type = [i for i in items
if item_requirements[i].get('storage_type') == storage_type]
# Total storage used
storage_used = lpSum([purchase.get((port['name'], item), 0) *
item_requirements[item].get('volume_per_unit', 1)
for item in items_this_type])
prob += storage_used <= self.vessel_capacity[storage_type]
# Port availability limits
for port in ports:
for item in items:
if (port, item) in port_availability:
if (port, item) in purchase:
prob += purchase[port, item] <= port_availability[port, item]
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract provisioning schedule
schedule = []
for port in ports:
port_orders = []
port_cost = 0
for item in items:
if (port, item) in purchase and purchase[port, item].varValue > 0.1:
quantity = purchase[port, item].varValue
cost = quantity * port_costs.get((port, item), 0)
port_orders.append({
'item': item,
'quantity': quantity,
'unit_cost': port_costs.get((port, item), 0),
'total_cost': cost
})
port_cost += cost
if port_orders:
schedule.append({
'port': port,
'orders': port_orders,
'total_port_cost': port_cost
})
return {
'status': LpStatus[prob.status],
'total_cost': value(prob.objective),
'provisioning_schedule': schedule
}
def calculate_food_requirements(self, passenger_count, crew_count,
voyage_days, menu_plan):
"""
Calculate food and beverage requirements based on passenger load
and menu planning
"""
requirements = {}
# Per-person-per-day consumption rates
consumption_rates = {
'beef': 0.25, # kg
'chicken': 0.20,
'seafood': 0.15,
'vegetables': 0.30,
'fruits': 0.25,
'dairy_milk': 0.15, # liters
'bread': 0.15, # kg
'wine': 0.10, # liters
'beer': 0.20, # liters
'soft_drinks': 0.30 # liters
}
total_pax = passenger_count + crew_count
for item, rate_per_day in consumption_rates.items():
daily_consumption = rate_per_day * total_pax
# Add safety factor
safety_factor = 1.15
requirements[item] = {
'daily_consumption': daily_consumption * safety_factor,
'total_voyage': daily_consumption * safety_factor * voyage_days
}
return requirements
# Example usage
vessel_capacity = {
'dry': 500, # cubic meters
'cold': 300,
'frozen': 200
}
itinerary = [
{'name': 'Miami', 'days_until_next': 3},
{'name': 'Cozumel', 'days_until_next': 2},
{'name': 'Grand Cayman', 'days_until_next': 2},
{'name': 'Miami', 'days_until_next': 0}
]
optimizer = CruiseProvisioningOptimizer(vessel_capacity, itinerary)
item_requirements = {
'beef': {'daily_consumption': 500, 'storage_type': 'frozen', 'volume_per_unit': 0.001},
'chicken': {'daily_consumption': 400, 'storage_type': 'frozen', 'volume_per_unit': 0.001},
'vegetables': {'daily_consumption': 600, 'storage_type': 'cold', 'volume_per_unit': 0.0015},
'wine': {'daily_consumption': 200, 'storage_type': 'dry', 'volume_per_unit': 0.001},
}
port_costs = {
('Miami', 'beef'): 12.00,
('Miami', 'chicken'): 6.00,
('Miami', 'vegetables'): 3.00,
('Miami', 'wine'): 8.00,
('Cozumel', 'beef'): 14.00,
('Cozumel', 'vegetables'): 2.50,
('Grand Cayman', 'beef'): 15.00,
}
port_availability = {
('Miami', 'beef'): 10000,
('Miami', 'chicken'): 10000,
('Miami', 'vegetables'): 10000,
('Miami', 'wine'): 5000,
('Cozumel', 'beef'): 2000,
('Cozumel', 'vegetables'): 3000,
}
result = optimizer.optimize_provisioning_schedule(item_requirements,
port_costs,
port_availability)
print(f"Total provisioning cost: ${result['total_cost']:,.2f}")
邮轮库存管理
最低库存水平优化
def calculate_par_levels(item, consumption_rate, lead_time_days,
service_level=0.95, storage_cost_per_unit=1.0):
"""
Calculate optimal par stock levels for cruise ship inventory
Parameters:
- item: item details
- consumption_rate: average daily consumption
- lead_time_days: days between ports (resupply time)
- service_level: target service level (stockout probability)
- storage_cost_per_unit: cost to hold inventory
"""
from scipy.stats import norm
# Demand during lead time
avg_demand = consumption_rate * lead_time_days
# Variability (assume coefficient of variation)
cv = 0.20 # 20% variability
std_demand = avg_demand * cv
# Safety stock
z_score = norm.ppf(service_level)
safety_stock = z_score * std_demand
# Reorder point (par level)
par_level = avg_demand + safety_stock
# Maximum stock level (par level + one order quantity)
max_level = par_level * 1.5
return {
'par_level': par_level,
'max_level': max_level,
'safety_stock': safety_stock,
'avg_inventory': (par_level + max_level) / 2,
'holding_cost': ((par_level + max_level) / 2) * storage_cost_per_unit
}
# Example
beef_par = calculate_par_levels(
item='beef',
consumption_rate=500, # kg/day
lead_time_days=7, # 1 week between ports
service_level=0.98 # High service level for critical item
)
print(f"Beef par level: {beef_par['par_level']:.0f} kg")
print(f"Safety stock: {beef_par['safety_stock']:.0f} kg")
减少浪费与可持续发展
食品浪费优化
class CruiseFoodWasteOptimizer:
"""
Optimize food ordering and preparation to minimize waste
"""
def __init__(self, historical_consumption):
self.historical_consumption = historical_consumption
def predict_actual_consumption(self, planned_menu, passenger_count,
day_of_cruise):
"""
Predict actual consumption to reduce overproduction
Factors:
- Port days vs. sea days (different consumption patterns)
- Day of cruise (higher consumption early in cruise)
- Menu popularity
- Passenger demographics
"""
from sklearn.ensemble import RandomForestRegressor
# Features for prediction
features = {
'passenger_count': passenger_count,
'day_of_cruise': day_of_cruise,
'is_sea_day': 1 if planned_menu['is_sea_day'] else 0,
'menu_popularity_score': planned_menu.get('popularity', 0.7)
}
# Simple model (would be trained on historical data)
# Predicted consumption factor vs. standard portion
consumption_factor = 0.85 # Typically 85% of planned is consumed
predicted_consumption = {}
for item, planned_quantity in planned_menu['items'].items():
# Adjust based on patterns
if features['is_sea_day']:
adjustment = 1.1 # Higher consumption on sea days
else:
adjustment = 0.9 # Lower on port days
predicted = planned_quantity * consumption_factor * adjustment
predicted_consumption[item] = {
'planned': planned_quantity,
'predicted_actual': predicted,
'recommended_prep': predicted * 1.05 # Small buffer
}
return predicted_consumption
def optimize_buffet_replenishment(self, current_inventory, consumption_rate,
time_remaining_hours):
"""
Optimize buffet replenishment to minimize waste at end of service
"""
# Calculate expected consumption in remaining time
expected_consumption = consumption_rate * time_remaining_hours
# Replenishment decision
if current_inventory < expected_consumption * 0.5:
# Replenish
replenish_quantity = expected_consumption - current_inventory
# Don't overproduce near end of service
if time_remaining_hours < 1:
replenish_quantity *= 0.7 # Conservative
return {
'action': 'replenish',
'quantity': replenish_quantity,
'reason': 'Current inventory below threshold'
}
else:
return {
'action': 'hold',
'quantity': 0,
'reason': 'Sufficient inventory for remaining service'
}
def donation_optimization(self, excess_inventory, port_donations):
"""
Optimize food donation to reduce waste and support communities
Match excess inventory with port-based donation opportunities
"""
donation_plan = []
for item, quantity in excess_inventory.items():
if quantity > 0:
# Find suitable donation partners
eligible_partners = [
p for p in port_donations
if item in p['accepted_items']
]
if eligible_partners:
# Allocate to highest-impact partner
best_partner = max(eligible_partners,
key=lambda x: x['impact_score'])
donation_plan.append({
'item': item,
'quantity': quantity,
'partner': best_partner['name'],
'estimated_impact': quantity * best_partner['meals_per_kg']
})
return donation_plan
冷链管理
温控库存
def optimize_cold_chain_storage(items, storage_zones, temperature_requirements):
"""
Optimize placement of items in cold storage zones
Parameters:
- items: list of items with temp requirements
- storage_zones: available cold storage with temp ranges
- temperature_requirements: optimal temps for each item
"""
from pulp import *
prob = LpProblem("Cold_Storage", LpMinimize)
# Variables: assign item i to zone z
x = {}
for i, item in enumerate(items):
for z, zone in enumerate(storage_zones):
# Check if zone can handle item's temp requirement
if (zone['temp_min'] <= temperature_requirements[item['name']]['optimal'] <= zone['temp_max']):
x[i, z] = LpVariable(f"Assign_{i}_{z}", cat='Binary')
# Objective: minimize energy cost (colder zones cost more)
energy_cost = lpSum([x[i, z] * storage_zones[z]['energy_cost_per_unit'] *
items[i]['volume']
for (i, z) in x])
prob += energy_cost
# Constraints
# Each item assigned to exactly one zone
for i in range(len(items)):
zones_for_item = [x[i, z] for z in range(len(storage_zones))
if (i, z) in x]
if zones_for_item:
prob += lpSum(zones_for_item) == 1
# Zone capacity
for z, zone in enumerate(storage_zones):
zone_volume = lpSum([items[i]['volume'] * x[i, z]
for i in range(len(items))
if (i, z) in x])
prob += zone_volume <= zone['capacity']
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract assignments
assignments = []
for (i, z) in x:
if x[i, z].varValue > 0.5:
assignments.append({
'item': items[i]['name'],
'zone': storage_zones[z]['name'],
'temperature': storage_zones[z]['temp_min'],
'volume': items[i]['volume']
})
return {
'total_energy_cost': value(prob.objective),
'assignments': pd.DataFrame(assignments)
}
# Example
items = [
{'name': 'Ice Cream', 'volume': 50},
{'name': 'Frozen Fish', 'volume': 100},
{'name': 'Fresh Vegetables', 'volume': 150},
{'name': 'Dairy Products', 'volume': 80},
]
storage_zones = [
{'name': 'Deep Freeze', 'temp_min': -25, 'temp_max': -18,
'capacity': 200, 'energy_cost_per_unit': 3.0},
{'name': 'Freezer', 'temp_min': -18, 'temp_max': -12,
'capacity': 250, 'energy_cost_per_unit': 2.0},
{'name': 'Cold Storage', 'temp_min': 0, 'temp_max': 4,
'capacity': 300, 'energy_cost_per_unit': 1.0},
]
temperature_requirements = {
'Ice Cream': {'optimal': -20},
'Frozen Fish': {'optimal': -15},
'Fresh Vegetables': {'optimal': 2},
'Dairy Products': {'optimal': 3},
}
result = optimize_cold_chain_storage(items, storage_zones, temperature_requirements)
港口物流与运营
岸上协调
def optimize_port_loading_schedule(deliveries, loading_bays, port_time_window):
"""
Optimize scheduling of supplier deliveries during port call
Constraints:
- Limited port time (6-10 hours typically)
- Limited loading bays
- Crew availability
- Customs clearance
"""
from pulp import *
prob = LpProblem("Port_Loading", LpMinimize)
n_deliveries = len(deliveries)
n_bays = loading_bays
time_slots = range(port_time_window) # hours
# Variables: assign delivery d to bay b in time slot t
x = {}
for d in range(n_deliveries):
for b in range(n_bays):
for t in time_slots:
x[d, b, t] = LpVariable(f"Assign_{d}_{b}_{t}", cat='Binary')
# Objective: minimize total makespan + priority penalties
makespan = LpVariable("Makespan", lowBound=0)
# Completion time of last delivery
prob += makespan
# Each delivery assigned once
for d in range(n_deliveries):
prob += lpSum([x[d, b, t]
for b in range(n_bays)
for t in time_slots]) == 1
# Bay can handle one delivery at a time
for b in range(n_bays):
for t in time_slots:
prob += lpSum([x[d, b, t] for d in range(n_deliveries)]) <= 1
# Makespan constraint
for d, delivery in enumerate(deliveries):
for b in range(n_bays):
for t in time_slots:
# If delivery starts at time t, it completes at t + duration
prob += makespan >= (t + delivery['duration_hours']) * x[d, b, t]
# Priority deliveries (perishables) should be early
for d, delivery in enumerate(deliveries):
if delivery.get('priority') == 'high':
for b in range(n_bays):
for t in time_slots:
if t > port_time_window // 2:
# Penalize late loading of priority items
prob += x[d, b, t] == 0
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract schedule
schedule = []
for d in range(n_deliveries):
for b in range(n_bays):
for t in time_slots:
if x[d, b, t].varValue > 0.5:
schedule.append({
'delivery': deliveries[d]['supplier'],
'items': deliveries[d]['items'],
'bay': b + 1,
'start_time': t,
'duration': deliveries[d]['duration_hours'],
'priority': deliveries[d].get('priority', 'normal')
})
return {
'makespan': makespan.varValue,
'schedule': pd.DataFrame(schedule).sort_values('start_time')
}
工具与库
Python 库
优化:
PuLP:线性规划scipy.optimize:通用优化OR-Tools:Google 优化工具
预测:
scikit-learn:机器学习prophet:时间序列预测
数据分析:
pandas、numpy:数据处理matplotlib:可视化
商业软件
邮轮运营:
- ShipServ:海事采购平台
- MarineCFO:邮轮财务管理
- Adonis:酒店管理系统
- ORIS:船舶运营和报告
库存管理:
- Visual Computers:邮轮库存系统
- Compeat:餐饮及酒店库存管理
- MarketMan:餐饮服务库存管理
补给:
- Navtor:海事航程规划
- Martek Marine:船舶管理软件
- Danaos:船舶管理系统
可持续发展:
- Cleantech:环境合规
- OCEANOS:环境监测
常见挑战与解决方案
挑战:港口停留时间有限
问题:
- 港口停留时间有限(4-10 小时)
- 涉及多个供应商和多批交付
- 海关和检查延误
解决方案:
- 提前规划和协调
- 由集货商整合交付
- 安排保税仓库
- 并行装载作业
- 预先审核供应商
挑战:存储空间有限
问题:
- 冷藏容量有限
- 各部门争用空间
- 季节性需求变化
解决方案:
- 优化最低库存水平
- 尽可能采用准时补给
- 优化多温区存储
- 采用紧凑型存储方案
- 战略性选择补给港口
挑战:品质与新鲜度
问题:
- 长时间航行,无法补给
- 保持农产品品质
- 满足宾客对新鲜度的期待
解决方案:
- 气调储存
- 船上水培花园
- 在多个港口进行策略性采购
- 根据产品保质期规划菜单
- 质量检验流程
挑战:废弃物管理
问题:
- 食物浪费(备餐和餐盘剩余)
- 环境法规
- 海上处置选择有限
解决方案:
- 预测性生产规划
- 优化份量控制
- 在港口开展捐赠计划
- 堆肥和厌氧消化器
- 废弃物转能源系统
输出格式
邮轮供应链报告
执行摘要:
- 船舶补给绩效
- 成本指标与趋势
- 减少废弃物的成果
- 主要机遇
补给绩效:
| 港口 | 装载品项 | 价值 | 交货时间 | 准时率 | 质量问题 |
|---|---|---|---|---|---|
| Miami | 1,250 | $185,000 | 4.5 hrs | 98% | 2 |
| Cozumel | 320 | $28,000 | 2.8 hrs | 100% | 0 |
| Grand Cayman | 180 | $15,000 | 3.2 hrs | 95% | 1 |
库存指标:
| 类别 | 当前库存 | 标准库存水平 | 可供天数 | 周转率 | 浪费率 |
|---|---|---|---|---|---|
| 蛋白质(冷冻) | 3,200 kg | 3,500 kg | 6.4 | 45x/yr | 2.1% |
| 新鲜农产品 | 1,800 kg | 2,000 kg | 3.0 | 120x/yr | 5.8% |
| 乳制品 | 1,200 L | 1,400 L | 4.0 | 90x/yr | 3.2% |
| 干货 | 5,500 kg | 6,000 kg | 18.0 | 20x/yr | 1.5% |
成本分析:
| 类别 | 总成本 | 每位乘客每日成本 | 占总额比例 | 与预算相比 |
|---|---|---|---|---|
| 蛋白质 | $125,000 | $8.50 | 35% | -2% |
| 农产品 | $85,000 | $5.80 | 24% | +1% |
| 乳制品 | $45,000 | $3.06 | 13% | 0% |
| 饮料 | $70,000 | $4.76 | 20% | -3% |
| 其他 | $30,000 | $2.04 | 8% | +2% |
| 总计 | $355,000 | $24.16 | 100% | -1% |
减少废弃物:
| 指标 | 本次航程 | 上次航程 | 年初至今平均值 | 目标 |
|---|---|---|---|---|
| 食物浪费(kg/乘客日) | 0.45 | 0.52 | 0.48 | < 0.40 |
| 废弃物减少率 | 13% | - | 8% | 15% |
| 捐赠餐食(份) | 1,250 | 980 | 1,100 | 1,000 |
建议:
- 将更多补给转至 Miami 采购(相比加勒比海港口可节省 15% 成本)
- 将农产品标准库存水平降低 10%(有减少浪费的空间)
- 实施自助餐预测性补餐系统
- 将捐赠计划扩展至所有港口
- 安装水培花园种植香草和生菜(成本降低 35%)
要提出的问题
如需更多背景信息:
- 船舶类型和载客量是多少?(大型邮轮、豪华邮轮、探险邮轮)
- 行程和航线是什么?
- 补给频率和主要港口有哪些?
- 当前的浪费和成本指标是什么?
- 目前使用哪些系统?(库存、采购)
- 主要挑战是什么?(成本、质量、浪费)
- 有哪些可持续发展目标?
相关技能
- hotel-inventory-management:酒店库存管理概念
- hospitality-procurement:采购和供应商管理
- tour-operations:乘客运营
- inventory-optimization:库存管理策略
- demand-forecasting:消费预测
- route-optimization:行程优化
- cold-chain-logistics:温控供应链
- food-beverage-supply-chain:餐饮运营
评论
支持 Markdown