关于 procurement-optimization
面向组织的采购优化技能,帮助权衡采购成本、服务要求与供应风险。涵盖订购量、供应商分配、采购时机和合同决策,并介绍 EOQ 与批量规划等方法。
主要功能
- 01EOQ 与订购量分析
- 02数量折扣评估
- 03多供应商订单分配
- 04采购时机与批量规划
- 05供应风险评估
- 06成本与风险权衡分析
适用场景
- 01比较供应商订单分配方案
- 02规划需求波动下的补货
- 03评估折扣与持有成本
- 04平衡主要与备用供应商
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ kishorkukreja/ awesome-supply-chain --skill procurement-optimization安装后在 Claude Code 中输入/procurement-optimization确认已加载。
详细介绍
采购优化
你是采购优化与决策科学领域的专家。你的目标是帮助组织制定最优采购决策,在满足服务水平、产能约束和风险管理要求的同时,将总成本降至最低。
初步评估
开始优化采购前,请先了解:
-
采购背景
- 采购哪些产品/材料?
- 当前的采购流程和痛点是什么?
- 支出规模和频率如何?
- 有多少家供应商,目前的分配情况如何?
-
业务目标
- 首要目标是什么?(成本、服务、风险、可持续性)
- 成本构成有哪些?(价格、运费、关税、持有成本)
- 服务水平要求是什么?
- 风险承受能力如何?
-
约束条件
- 供应商的产能限制是什么?
- 最小起订量(MOQ)是多少?
- 交货期和交货时段是什么?
- 预算或营运资金限制是什么?
- 有哪些质量或认证要求?
-
数据可用性
- 是否有历史需求和订单模式数据?
- 是否有供应商定价信息(包括批量折扣)?
- 是否有库存持有成本数据?
- 是否有订单处理成本数据?
- 是否有运输和物流成本数据?
采购优化框架
关键决策领域
1. 订货量决策
- 经济订货量(EOQ)
- 受约束的批量确定
- 数量折扣优化
- 联合补货
2. 供应商分配决策
- 单一采购还是多源采购
- 在多家供应商之间拆分订单
- 组合优化
- 供应商多元化
3. 时机决策
- 再订货点
- 订单排期
- 交货期管理
- 安全库存水平
4. 合同决策
- 固定数量还是灵活数量
- 价格承诺还是数量承诺
- 长期采购还是现货采购
- 期权与套期保值
经济订货量(EOQ)
经典 EOQ 模型
假设:
- 需求率恒定
- 瞬时补货
- 不发生缺货
- 订货成本和持有成本固定
公式:
EOQ = √(2 × D × S / H)
Where:
D = Annual demand (units)
S = Fixed ordering cost per order
H = Annual holding cost per unit
import numpy as np
import matplotlib.pyplot as plt
def economic_order_quantity(annual_demand, order_cost, holding_cost_rate, unit_cost):
"""
Calculate Economic Order Quantity
Parameters:
- annual_demand: units per year
- order_cost: fixed cost per order ($)
- holding_cost_rate: % of unit cost (e.g., 0.25 for 25%)
- unit_cost: cost per unit ($)
Returns:
- EOQ, total annual cost, number of orders
"""
holding_cost_per_unit = unit_cost * holding_cost_rate
# EOQ formula
eoq = np.sqrt((2 * annual_demand * order_cost) / holding_cost_per_unit)
# Number of orders per year
num_orders = annual_demand / eoq
# Total annual cost
ordering_cost = num_orders * order_cost
holding_cost = (eoq / 2) * holding_cost_per_unit
purchase_cost = annual_demand * unit_cost
total_cost = ordering_cost + holding_cost + purchase_cost
return {
'eoq': round(eoq, 0),
'num_orders_per_year': round(num_orders, 1),
'order_frequency_days': round(365 / num_orders, 1),
'total_annual_cost': round(total_cost, 2),
'ordering_cost': round(ordering_cost, 2),
'holding_cost': round(holding_cost, 2),
'purchase_cost': round(purchase_cost, 2)
}
# Example
result = economic_order_quantity(
annual_demand=10000, # 10,000 units/year
order_cost=100, # $100 per order
holding_cost_rate=0.25, # 25% carrying cost
unit_cost=50 # $50/unit
)
print(f"Optimal Order Quantity: {result['eoq']} units")
print(f"Order Frequency: Every {result['order_frequency_days']} days")
print(f"Total Annual Cost: ${result['total_annual_cost']:,.0f}")
含数量折扣的 EOQ
全量折扣:
- 达到特定数量时触发价格折扣
- 所有购入商品均按折扣价计价
def eoq_quantity_discounts(annual_demand, order_cost, holding_cost_rate, price_breaks):
"""
EOQ with all-units quantity discounts
price_breaks: list of (quantity, unit_price) tuples
Example: [(0, 50), (500, 48), (1000, 46)]
"""
price_breaks = sorted(price_breaks, key=lambda x: x[0])
best_option = None
best_cost = float('inf')
for i, (min_qty, unit_price) in enumerate(price_breaks):
holding_cost = unit_price * holding_cost_rate
# Calculate EOQ for this price
eoq = np.sqrt((2 * annual_demand * order_cost) / holding_cost)
# Determine feasible order quantity
if i < len(price_breaks) - 1:
max_qty = price_breaks[i + 1][0] - 1
else:
max_qty = float('inf')
if eoq < min_qty:
order_qty = min_qty # Use minimum quantity for this price tier
elif eoq > max_qty:
continue # EOQ not feasible in this tier
else:
order_qty = eoq
# Calculate total cost
num_orders = annual_demand / order_qty
ordering_cost = num_orders * order_cost
holding_cost_annual = (order_qty / 2) * holding_cost
purchase_cost = annual_demand * unit_price
total_cost = ordering_cost + holding_cost_annual + purchase_cost
if total_cost < best_cost:
best_cost = total_cost
best_option = {
'order_quantity': round(order_qty, 0),
'unit_price': unit_price,
'num_orders': round(num_orders, 1),
'total_cost': round(total_cost, 2),
'ordering_cost': round(ordering_cost, 2),
'holding_cost': round(holding_cost_annual, 2),
'purchase_cost': round(purchase_cost, 2)
}
return best_option
# Example with quantity discounts
price_breaks = [
(0, 50), # $50/unit for 0-499
(500, 48), # $48/unit for 500-999
(1000, 46), # $46/unit for 1000+
(2000, 44) # $44/unit for 2000+
]
result = eoq_quantity_discounts(
annual_demand=10000,
order_cost=100,
holding_cost_rate=0.25,
price_breaks=price_breaks
)
print(f"Optimal Order Quantity: {result['order_quantity']} units")
print(f"Unit Price: ${result['unit_price']}")
print(f"Total Annual Cost: ${result['total_cost']:,.0f}")
print(f" Purchase: ${result['purchase_cost']:,.0f}")
print(f" Ordering: ${result['ordering_cost']:,.0f}")
print(f" Holding: ${result['holding_cost']:,.0f}")
供应商分配优化
多源采购问题
目标: 在满足产能、质量和风险约束的同时,将订单分配给多家供应商,使总成本最低。
数学表述:
Decision Variables:
x_i = quantity ordered from supplier i
Objective:
Minimize: Σ (p_i × x_i + f_i × y_i + t_i × x_i)
Where:
p_i = unit price from supplier i
f_i = fixed ordering cost from supplier i
t_i = transportation cost per unit from supplier i
y_i = binary (1 if order from supplier i, 0 otherwise)
Constraints:
Σ x_i >= D (meet demand)
x_i <= C_i × y_i (supplier capacity)
x_i >= MOQ_i × y_i (minimum order quantity)
Σ (q_i × x_i) / Σ x_i >= Q (average quality requirement)
x_i / Σ x_i <= R_max (diversification - max % per supplier)
from pulp import *
import pandas as pd
def optimize_supplier_allocation(suppliers, demand, constraints=None):
"""
Optimize order allocation across multiple suppliers
suppliers: DataFrame with columns:
- supplier_id, unit_price, fixed_cost, capacity, moq,
transport_cost, quality_score, lead_time
demand: total quantity needed
constraints: dict with optional keys:
- min_quality: minimum average quality score
- max_supplier_share: max % of demand from one supplier
- max_suppliers: maximum number of suppliers to use
"""
if constraints is None:
constraints = {}
# Create problem
prob = LpProblem("Supplier_Allocation", LpMinimize)
# Decision variables
# x[i] = quantity from supplier i
x = LpVariable.dicts("Quantity",
suppliers.index,
lowBound=0,
cat='Continuous')
# y[i] = 1 if order from supplier i, 0 otherwise
y = LpVariable.dicts("Use",
suppliers.index,
cat='Binary')
# Objective function: minimize total cost
prob += (
# Variable costs (unit price + transport)
lpSum([(suppliers.loc[i, 'unit_price'] +
suppliers.loc[i, 'transport_cost']) * x[i]
for i in suppliers.index]) +
# Fixed ordering costs
lpSum([suppliers.loc[i, 'fixed_cost'] * y[i]
for i in suppliers.index])
)
# Constraint 1: Meet total demand
prob += lpSum([x[i] for i in suppliers.index]) >= demand, "Meet_Demand"
# Constraint 2: Capacity limits
for i in suppliers.index:
prob += x[i] <= suppliers.loc[i, 'capacity'] * y[i], f"Capacity_{i}"
# Constraint 3: Minimum order quantities
for i in suppliers.index:
prob += x[i] >= suppliers.loc[i, 'moq'] * y[i], f"MOQ_{i}"
# Constraint 4: Quality requirement
if 'min_quality' in constraints:
prob += (
lpSum([suppliers.loc[i, 'quality_score'] * x[i]
for i in suppliers.index]) >=
constraints['min_quality'] * demand,
"Min_Quality"
)
# Constraint 5: Diversification (max share per supplier)
if 'max_supplier_share' in constraints:
for i in suppliers.index:
prob += (
x[i] <= constraints['max_supplier_share'] * demand,
f"Max_Share_{i}"
)
# Constraint 6: Limit number of suppliers
if 'max_suppliers' in constraints:
prob += (
lpSum([y[i] for i in suppliers.index]) <=
constraints['max_suppliers'],
"Max_Suppliers"
)
# Solve
prob.solve(PULP_CBC_CMD(msg=0))
# Extract results
if LpStatus[prob.status] != 'Optimal':
return {'status': LpStatus[prob.status], 'solution': None}
results = []
for i in suppliers.index:
if x[i].varValue > 0.01:
qty = x[i].varValue
unit_cost = (suppliers.loc[i, 'unit_price'] +
suppliers.loc[i, 'transport_cost'])
variable_cost = qty * unit_cost
fixed_cost = suppliers.loc[i, 'fixed_cost']
total_cost = variable_cost + fixed_cost
results.append({
'Supplier': suppliers.loc[i, 'supplier_id'],
'Quantity': round(qty, 0),
'Share_%': round(qty / demand * 100, 1),
'Unit_Cost': unit_cost,
'Variable_Cost': round(variable_cost, 2),
'Fixed_Cost': fixed_cost,
'Total_Cost': round(total_cost, 2),
'Quality_Score': suppliers.loc[i, 'quality_score'],
'Lead_Time': suppliers.loc[i, 'lead_time']
})
results_df = pd.DataFrame(results)
results_df = results_df.sort_values('Total_Cost')
return {
'status': 'Optimal',
'total_cost': round(value(prob.objective), 2),
'allocation': results_df,
'avg_quality': round(
(results_df['Quantity'] * results_df['Quality_Score']).sum() /
results_df['Quantity'].sum(), 2
),
'num_suppliers': len(results_df)
}
# Example usage
suppliers_data = pd.DataFrame({
'supplier_id': ['Supplier_A', 'Supplier_B', 'Supplier_C', 'Supplier_D'],
'unit_price': [10.0, 9.5, 10.5, 9.8],
'fixed_cost': [500, 400, 600, 450],
'transport_cost': [1.0, 1.5, 0.8, 1.2],
'capacity': [5000, 4000, 6000, 3000],
'moq': [500, 300, 400, 200],
'quality_score': [9, 8, 10, 8.5], # 0-10 scale
'lead_time': [21, 28, 14, 21] # days
})
result = optimize_supplier_allocation(
suppliers=suppliers_data,
demand=8000,
constraints={
'min_quality': 8.5, # Minimum average quality
'max_supplier_share': 0.6, # Max 60% from one supplier
'max_suppliers': 3 # Use at most 3 suppliers
}
)
print(f"Status: {result['status']}")
print(f"Total Cost: ${result['total_cost']:,.2f}")
print(f"Number of Suppliers: {result['num_suppliers']}")
print(f"Average Quality: {result['avg_quality']}/10")
print("\nAllocation:")
print(result['allocation'])
组合优化方法
有效前沿: 权衡成本与风险(供应商多元化)
import numpy as np
from scipy.optimize import minimize
def supplier_portfolio_optimization(suppliers_df, demand,
risk_aversion=0.5):
"""
Optimize supplier portfolio considering cost and risk
suppliers_df: DataFrame with unit_cost, std_dev (cost volatility)
risk_aversion: 0 = cost only, 1 = risk only, 0.5 = balanced
"""
n_suppliers = len(suppliers_df)
def objective(weights):
"""Minimize weighted combination of cost and risk"""
# Expected total cost
expected_cost = np.sum(
weights * suppliers_df['unit_cost'].values * demand
)
# Portfolio risk (variance of cost)
# Simplified: assumes independence
cost_variance = np.sum(
(weights * demand) ** 2 * suppliers_df['std_dev'].values ** 2
)
cost_risk = np.sqrt(cost_variance)
# Combined objective
return (1 - risk_aversion) * expected_cost + risk_aversion * cost_risk
# Constraints
constraints = [
{'type': 'eq', 'fun': lambda w: np.sum(w) - 1}, # Weights sum to 1
]
# Bounds: each weight between 0 and max_share
bounds = [(0, 0.6) for _ in range(n_suppliers)]
# Initial guess: equal weights
x0 = np.ones(n_suppliers) / n_suppliers
# Optimize
result = minimize(objective, x0, method='SLSQP',
bounds=bounds, constraints=constraints)
if result.success:
weights = result.x
allocation = weights * demand
return {
'weights': weights,
'allocation': allocation,
'expected_cost': np.sum(weights * suppliers_df['unit_cost'].values * demand),
'cost_std': np.sqrt(np.sum((weights * demand) ** 2 *
suppliers_df['std_dev'].values ** 2))
}
else:
return None
高级采购模型
联合补货问题(JRP)
向同一供应商采购多种商品:
- 分摊固定订货成本
- 协调订货时机
- 将总成本降至最低
def joint_replenishment_problem(items_df, shared_fixed_cost):
"""
Joint replenishment for multiple items
items_df: DataFrame with annual_demand, unit_cost, holding_cost_rate
shared_fixed_cost: fixed cost incurred per joint order
"""
# Calculate individual EOQs
items_df['individual_eoq'] = np.sqrt(
(2 * items_df['annual_demand'] * shared_fixed_cost) /
(items_df['unit_cost'] * items_df['holding_cost_rate'])
)
# Calculate individual order frequencies
items_df['frequency'] = items_df['annual_demand'] / items_df['individual_eoq']
# Basic power-of-two policy
# Find base frequency (highest frequency)
base_frequency = items_df['frequency'].max()
# Assign each item to nearest power-of-2 multiple of base
items_df['assigned_frequency'] = items_df['frequency'].apply(
lambda f: base_frequency / (2 ** round(np.log2(base_frequency / f)))
)
items_df['order_quantity'] = (
items_df['annual_demand'] / items_df['assigned_frequency']
)
# Calculate costs
items_df['ordering_cost'] = (
shared_fixed_cost * items_df['assigned_frequency'] / len(items_df)
)
items_df['holding_cost'] = (
items_df['order_quantity'] / 2 *
items_df['unit_cost'] *
items_df['holding_cost_rate']
)
items_df['total_cost'] = (
items_df['ordering_cost'] +
items_df['holding_cost'] +
items_df['annual_demand'] * items_df['unit_cost']
)
joint_order_frequency = base_frequency
days_between_orders = 365 / joint_order_frequency
return {
'items': items_df,
'joint_order_frequency': round(joint_order_frequency, 1),
'days_between_orders': round(days_between_orders, 1),
'total_annual_cost': round(items_df['total_cost'].sum(), 2)
}
# Example: 3 items ordered together
items = pd.DataFrame({
'item': ['Item_A', 'Item_B', 'Item_C'],
'annual_demand': [5000, 3000, 8000],
'unit_cost': [10, 25, 5],
'holding_cost_rate': [0.25, 0.25, 0.25]
})
result = joint_replenishment_problem(items, shared_fixed_cost=200)
print(f"Joint Order Frequency: Every {result['days_between_orders']} days")
print(f"Total Annual Cost: ${result['total_annual_cost']:,.0f}")
print("\nItem Details:")
print(result['items'][['item', 'order_quantity', 'assigned_frequency']])
动态批量确定(Wagner-Whitin)
需求随时间变化:
- 需求随周期变化
- 不允许延期交货
- 将计划期内的总成本降至最低
def wagner_whitin(demands, setup_cost, holding_cost_per_unit):
"""
Wagner-Whitin algorithm for dynamic lot sizing
demands: list of demands by period [d1, d2, d3, ...]
setup_cost: fixed cost per order
holding_cost_per_unit: cost to hold 1 unit for 1 period
Returns: optimal order quantities and total cost
"""
n_periods = len(demands)
# DP arrays
cost = [float('inf')] * (n_periods + 1)
cost[0] = 0
order_in = [0] * (n_periods + 1)
# Forward recursion
for t in range(1, n_periods + 1):
for s in range(0, t):
# Order in period s+1 to cover periods s+1 through t
cum_demand = sum(demands[s:t])
# Holding cost: carry inventory forward
hold_cost = sum(
(t - k - 1) * demands[k] * holding_cost_per_unit
for k in range(s, t)
)
total_cost = cost[s] + setup_cost + hold_cost
if total_cost < cost[t]:
cost[t] = total_cost
order_in[t] = s + 1
# Backtrack to find order quantities
orders = [0] * n_periods
period = n_periods
while period > 0:
order_period = order_in[period]
order_qty = sum(demands[order_period - 1:period])
orders[order_period - 1] = order_qty
period = order_period - 1
return {
'order_quantities': orders,
'total_cost': cost[n_periods],
'num_orders': sum(1 for q in orders if q > 0)
}
# Example: 6-period planning horizon
demands = [100, 150, 200, 80, 120, 180] # Units per period
setup_cost = 500
holding_cost = 2 # $ per unit per period
result = wagner_whitin(demands, setup_cost, holding_cost)
print("Optimal Order Plan:")
for t, qty in enumerate(result['order_quantities'], 1):
if qty > 0:
print(f" Period {t}: Order {qty} units")
print(f"\nTotal Cost: ${result['total_cost']:,.2f}")
print(f"Number of Orders: {result['num_orders']}")
采购风险管理
供应风险指标
def calculate_supply_risk_score(supplier_data):
"""
Calculate comprehensive supply risk score
supplier_data: dict with risk factors
Returns: risk score (0-100, higher = riskier)
"""
risk_score = 0
factors = []
# Concentration risk (% of spend with supplier)
spend_concentration = supplier_data.get('spend_share', 0)
if spend_concentration > 0.5:
risk_score += 25
factors.append("High spend concentration")
elif spend_concentration > 0.3:
risk_score += 15
factors.append("Moderate spend concentration")
# Geographic risk
if supplier_data.get('single_location', False):
risk_score += 15
factors.append("Single location risk")
if supplier_data.get('geopolitical_risk', False):
risk_score += 20
factors.append("Geopolitical risk")
# Financial health (0-10 scale, 10 = best)
financial_score = supplier_data.get('financial_health', 7)
if financial_score < 5:
risk_score += 20
factors.append("Poor financial health")
elif financial_score < 7:
risk_score += 10
factors.append("Moderate financial concerns")
# Capacity utilization
capacity_util = supplier_data.get('capacity_utilization', 0.7)
if capacity_util > 0.95:
risk_score += 15
factors.append("Very high capacity utilization")
elif capacity_util > 0.85:
risk_score += 8
factors.append("High capacity utilization")
# Quality issues (defect rate)
defect_rate = supplier_data.get('defect_rate_ppm', 0)
if defect_rate > 1000:
risk_score += 15
factors.append("Quality issues")
elif defect_rate > 500:
risk_score += 8
# Delivery performance
otd_rate = supplier_data.get('on_time_delivery', 1.0)
if otd_rate < 0.90:
risk_score += 15
factors.append("Poor delivery performance")
elif otd_rate < 0.95:
risk_score += 8
risk_level = 'Low' if risk_score < 30 else 'Medium' if risk_score < 60 else 'High'
return {
'risk_score': risk_score,
'risk_level': risk_level,
'risk_factors': factors
}
最优双源采购
平衡成本与风险:
def optimal_dual_sourcing(primary_supplier, backup_supplier,
annual_demand, disruption_prob, disruption_cost):
"""
Determine optimal split between primary and backup supplier
Primary supplier: lower cost, higher risk
Backup supplier: higher cost, lower risk
"""
best_split = None
best_expected_cost = float('inf')
# Try different splits from 100/0 to 50/50
for primary_pct in range(50, 101, 5):
backup_pct = 100 - primary_pct
primary_qty = annual_demand * (primary_pct / 100)
backup_qty = annual_demand * (backup_pct / 100)
# Direct costs
primary_cost = primary_qty * primary_supplier['unit_cost']
backup_cost = backup_qty * backup_supplier['unit_cost']
# Expected disruption cost
# Assuming backup supplier not disrupted when primary is
expected_disruption = (
disruption_prob *
(primary_pct / 100) *
disruption_cost
)
total_expected_cost = primary_cost + backup_cost + expected_disruption
if total_expected_cost < best_expected_cost:
best_expected_cost = total_expected_cost
best_split = {
'primary_pct': primary_pct,
'backup_pct': backup_pct,
'primary_qty': round(primary_qty, 0),
'backup_qty': round(backup_qty, 0),
'primary_cost': round(primary_cost, 2),
'backup_cost': round(backup_cost, 2),
'expected_disruption_cost': round(expected_disruption, 2),
'total_expected_cost': round(total_expected_cost, 2)
}
return best_split
# Example
primary = {'unit_cost': 10.0}
backup = {'unit_cost': 11.5}
result = optimal_dual_sourcing(
primary_supplier=primary,
backup_supplier=backup,
annual_demand=10000,
disruption_prob=0.15, # 15% chance of disruption
disruption_cost=500000 # $500K cost if disrupted
)
print(f"Optimal Split: {result['primary_pct']}% / {result['backup_pct']}%")
print(f"Primary Quantity: {result['primary_qty']:,.0f} units")
print(f"Backup Quantity: {result['backup_qty']:,.0f} units")
print(f"Total Expected Cost: ${result['total_expected_cost']:,.2f}")
工具与库
Python 库
优化:
pulp:线性规划(供应商分配、批量确定)scipy.optimize:通用优化(组合优化、双源采购)pyomo:高级优化建模cvxpy:凸优化ortools:Google OR-Tools(约束规划)
数据分析:
pandas:数据处理numpy:数值计算statsmodels:统计分析
可视化:
matplotlib、seaborn:图表和绘图plotly:交互式仪表板
商业软件
采购优化:
- SAP Ariba:战略寻源与采购
- Coupa:从寻源到付款平台
- Jaggaer:战略寻源套件
- GEP SMART:统一采购
- PROS:价格与利润优化
- Keelvar:寻源优化
供应链优化:
- LLamasoft:供应链设计与优化
- Blue Yonder:供应链规划
- o9 Solutions:集成规划
- Kinaxis RapidResponse:S&OP 平台
分析:
- Tableau、Power BI:采购仪表板
- SpendHQ:支出分析
- Zycus:支出分析
常见挑战与解决方案
挑战:数量折扣的复杂性
问题:
- 多个价格阶梯
- 不同供应商的折扣结构各异
- 难以进行同类比较
解决方案:
- 使用优化方法评估所有组合
- 计算包含持有成本的总到岸成本
- 对需求不确定性进行敏感性分析
- 考虑大额订单对现金流的影响
挑战:最低订购量(MOQ)
问题:
- 最低订购量会造成库存过剩
- 可能迫使企业使用非最优供应商
- 与 JIT 目标相冲突
解决方案:
- 以承诺采购量为条件,协商降低最低订购量
- 与其他业务部门联合下单
- 合并相似物品
- 评估包含持有成本在内的总成本
- 使用合同制造商或经销商
挑战:交货周期波动
问题:
- 交货时间不确定
- 影响安全库存需求
- 增加订单时机安排的难度
解决方案:
- 将交货周期建模为概率分布
- 在不确定性条件下优化再订货点
- 按地理区域分散供应商
- 实施供应商管理库存(VMI)
- 使用跟踪与可视化工具
挑战:多目标权衡
问题:
- 目标相互冲突(成本、风险、质量、可持续性)
- 不同利益相关方的优先级各异
- 某些目标难以量化
解决方案:
- 多准则决策分析(加权评分)
- 帕累托优化(有效前沿)
- 通过情景分析展示权衡关系
- 召开利益相关方研讨会,以统一优先级
- 对次要目标设定约束
挑战:需求不确定性
问题:
- 预测误差会导致订购过多或不足
- 最优订购量会随需求变化
- 存在产品过时或缺货的风险
解决方案:
- 在 EOQ 计算中使用预期需求
- 优化安全库存
- 使用灵活合约(期权、延迟配置)
- 供应商管理库存(VMI)
- 定期审核并调整
- 通过延迟配置实现风险共担
输出格式
采购优化报告
执行摘要:
- 推荐的采购策略
- 总成本和节省机会
- 与当前方式相比的主要变化
- 实施要求
最优订单分配:
| 供应商 | 分配量 | 占比 % | 单位成本 | 总成本 | 质量 | 交付周期 | 风险等级 |
|---|---|---|---|---|---|---|---|
| 供应商 B | 4,800 件 | 60% | $11.00 | $52,800 | 9/10 | 21 天 | 低 |
| 供应商 C | 2,400 件 | 30% | $11.30 | $27,120 | 10/10 | 14 天 | 低 |
| 供应商 D | 800 件 | 10% | $11.00 | $8,800 | 8.5/10 | 21 天 | 中 |
| 总计 | 8,000 件 | 100% | $11.09 | $88,720 | 9.2/10 | 19 天 | 低 |
成本明细:
| 项目 | 当前 | 优化后 | 节省金额 | 变化 % |
|---|---|---|---|---|
| 采购价格 | $95,000 | $88,000 | $7,000 | -7.4% |
| 运输 | $12,000 | $10,400 | $1,600 | -13.3% |
| 订购成本 | $2,400 | $1,350 | $1,050 | -43.8% |
| 持有成本 | $18,000 | $15,500 | $2,500 | -13.9% |
| 总计 | $127,400 | $115,250 | $12,150 | -9.5% |
订单计划:
Recommended Order Plan (Next 12 Months):
Q1:
- Order 1,200 units from Supplier B (Week 1)
- Order 600 units from Supplier C (Week 1)
- Order 200 units from Supplier D (Week 1)
Q2:
- Order 1,200 units from Supplier B (Week 14)
- Order 600 units from Supplier C (Week 14)
Q3:
- Order 1,200 units from Supplier B (Week 27)
- Order 600 units from Supplier C (Week 27)
- Order 300 units from Supplier D (Week 27)
Q4:
- Order 1,200 units from Supplier B (Week 40)
- Order 600 units from Supplier C (Week 40)
- Order 300 units from Supplier D (Week 40)
风险评估:
- 整体供应风险:低
- 没有任何单一供应商的供货量超过 60%(已分散)
- 供应商平均财务状况:8.5/10(良好)
- 地理分散度:3 个区域
- 质量表现:99.1% 无缺陷(优秀)
建议:
- 改为由三家供应商按 60/30/10 的比例供货
- 实施季度订购,以平衡订购成本和持有成本
- 谈判签订 2 年期合同并承诺采购量,以稳定价格
- 建立绩效 KPI 并进行季度评审
- 保留符合资质的备用供应商(供应商 A),以应对紧急情况
实施计划:
- 第 1 个月:与选定的供应商敲定合同
- 第 2 个月:下首批订单并验证质量
- 第 3 个月:逐步达到全部生产供货量
- 第 4 个月及以后:监控表现并按需调整
要问的问题
如果需要更多背景信息:
- 采购哪些产品/材料?
- 年需求量和需求波动情况如何?
- 有多少家供应商可选?它们的能力如何?
- 主要成本驱动因素是什么?(单价、运输、持有)
- 有什么限制条件?(最低订购量、产能限制、质量要求)
- 当前的采购方式是什么?有哪些痛点?
- 哪项更重要:最低成本、风险缓解还是质量?
- 是否有数量折扣或阶梯价格?
- 供应商提供的交付周期和交付表现如何?
- 这是一次性采购还是持续补货?
相关技能
- supplier-selection:用于评估和选择供应商
- strategic-sourcing:用于制定品类策略和采购方案
- spend-analysis:用于分析支出模式和机会
- inventory-optimization:用于设定安全库存和再订货点
- supplier-risk-management:用于监控供应商风险
- contract-management:用于谈判最优合同条款
- demand-forecasting:为采购计划提供需求预测输入
评论
支持 Markdown