某制造企业供应链团队每天要处理大量供应商、库存、物流异常。核心问题:
| 痛点 | 具体表现 | 业务损失 |
|---|---|---|
| 异常发现滞后 | 库存低于安全水位时发现偏晚 | 断供停工风险高 |
| 补货决策不一致 | 相同水位,不同采购员处理不同 | 资金占用波动大 |
| 供应商管理靠人盯 | 交期、质检靠人工跟踪 | 采购大量时间耗在查进度 |
| 多系统切换 | ERP / WMS / SRM 来回切 | 一个异常要查多个系统 |
一、业务方案
1.1 目标
- 异常发现从"天级"变为"巡检级"
- 常规补货由 Agent 生成建议,小额可自动执行
- 采购人效提升:一人可覆盖更多 SKU
- 异常处理全流程可追踪
1.2 核心流程
text
数据层
├─ ERP → 库存水位、在途订单、历史消耗
├─ SRM → 供应商交期、质检合格率、评级
└─ WMS → 入库数据、库龄、呆滞料
Agent 巡检层
├─ 检测库存异常(低于安全水位 / 呆滞超期)
├─ 检测交期异常(预计延迟)
├─ 检测质检异常(批次合格率偏低)
└─ 自动生成异常报告
自动化处理层
├─ 常规补货 → 生成采购建议 / 小额自动下单
├─ 延迟预警 → 通知供应商并要求回复
├─ 呆滞处理 → 提出降价/退货/报废建议
└─ 严重异常 → 升级到供应链总监
二、技术落地(TeamAgent 实现)
说明 :供应链场景天然是多职责协作,更适合 TeamAgent + 多个 ReActAgent 成员。
2.1 系统架构
text
┌──────────────────┐
│ TeamAgent │
│ (供应链主管) │
└────────┬─────────┘
│
┌───────────────┼───────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ 库存监控 Agent│ │ 补货执行 Agent│ │ 异常处理 Agent│
│ (ReActAgent) │ │ (ReActAgent) │ │ (ReActAgent) │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
┌──────┴──────┐ ┌──────┴──────┐ ┌──────┴──────┐
│ ERP API │ │ 采购/OA API │ │ SRM/通知 API │
└─────────────┘ └─────────────┘ └─────────────┘
2.2 领域工具(真实 API)
java
import org.noear.solon.ai.annotation.ToolMapping;
import org.noear.solon.ai.chat.tool.AbsToolProvider;
import org.noear.solon.annotation.Param;
/** 库存监控工具 */
public class InventoryTools extends AbsToolProvider {
@ToolMapping(description = "查询指定 SKU 当前库存、安全水位、在途数量、日均消耗")
public String check_inventory(@Param(description = "SKU 编码") String sku) {
// 生产环境改为 ERP 查询
return """
{
"sku":"%s",
"quantity":850,
"safeLevel":2000,
"inTransit":0,
"dailyConsumption":380.0,
"alert":"below_safe_level"
}
""".formatted(sku);
}
@ToolMapping(description = "查询 SKU 补货提前期(天)")
public String get_lead_time(@Param(description = "SKU 编码") String sku) {
return "{\"sku\":\"" + sku + "\", \"leadTimeDays\": 12}";
}
}
/** 补货执行工具 */
public class ReplenishmentTools extends AbsToolProvider {
@ToolMapping(description = "根据当前库存、日均消耗、提前期计算建议补货量")
public String calc_reorder_qty(
@Param(description = "当前库存") int currentStock,
@Param(description = "安全水位") int safeLevel,
@Param(description = "日均消耗") double dailyConsumption,
@Param(description = "提前期天数") int leadTimeDays) {
int shortage = safeLevel - currentStock
+ (int) (dailyConsumption * leadTimeDays);
int reorderQty = Math.max(shortage, 0);
return "{\"reorderQty\": " + reorderQty + "}";
}
@ToolMapping(description = "创建采购单。小额可直接提交,大额返回待审批")
public String create_po(
@Param(description = "SKU") String sku,
@Param(description = "采购数量") int qty,
@Param(description = "供应商编码") String supplier,
@Param(description = "预估金额") double amount) {
if (amount >= 50_000) {
return "{\"status\":\"pending_approval\", \"sku\":\"" + sku
+ "\", \"qty\":" + qty + ", \"amount\":" + amount + "}";
}
return "{\"status\":\"submitted\", \"poNumber\":\"PO-"
+ System.currentTimeMillis() + "\", \"sku\":\"" + sku
+ "\", \"qty\":" + qty + ", \"supplier\":\"" + supplier + "\"}";
}
}
/** 异常处理工具 */
public class ExceptionTools extends AbsToolProvider {
@ToolMapping(description = "查询供应商交期与历史表现")
public String check_supplier(
@Param(description = "供应商编码") String supplierCode,
@Param(description = "SKU") String sku) {
return """
{
"supplier":"%s",
"sku":"%s",
"delayRate6m":0.12,
"passRate":0.983,
"preferred":true
}
""".formatted(supplierCode, sku);
}
@ToolMapping(description = "向主管发送异常升级通知")
public String notify_manager(
@Param(description = "异常摘要") String summary) {
return "已通知供应链主管:" + summary;
}
}
2.3 构建子代理与 TeamAgent
java
import org.noear.solon.ai.agent.AgentSession;
import org.noear.solon.ai.agent.react.ReActAgent;
import org.noear.solon.ai.agent.session.InMemoryAgentSession;
import org.noear.solon.ai.agent.team.TeamAgent;
import org.noear.solon.ai.agent.team.TeamProtocols;
import org.noear.solon.ai.chat.ChatModel;
ChatModel chatModel = LlmUtil.getChatModel();
// 1) 库存监控专家
ReActAgent inventoryAgent = ReActAgent.of(chatModel)
.name("inventory_monitor")
.role("你是库存监控专家。负责检查库存水位,识别低于安全水位的 SKU。")
.defaultToolAdd(new InventoryTools())
.build();
// 2) 补货执行专家
ReActAgent replenishAgent = ReActAgent.of(chatModel)
.name("replenishment")
.role("你是补货执行专家。根据缺货信息计算补货量并创建采购单。")
.defaultToolAdd(new ReplenishmentTools())
.build();
// 3) 异常处理专家
ReActAgent exceptionAgent = ReActAgent.of(chatModel)
.name("exception_handler")
.role("你是异常处理专家。分析供应商风险,必要时升级通知主管。")
.defaultToolAdd(new ExceptionTools())
.build();
// 4) 组建团队(顺序协作)
TeamAgent supplyChainTeam = TeamAgent.of(chatModel)
.name("supply_chain_group")
.agentAdd(inventoryAgent)
.agentAdd(replenishAgent)
.agentAdd(exceptionAgent)
.protocol(TeamProtocols.SEQUENTIAL)
.build();
AgentSession session = InMemoryAgentSession.of("supply_chain_round_001");
String task = """
巡检 SKU A-1002:
1. 检查库存是否低于安全水位
2. 若缺货,计算补货量并创建采购单(供应商 SUP-01,单价 0.12)
3. 若金额或供应商风险偏高,升级通知主管
""";
String result = supplyChainTeam.prompt(task)
.session(session)
.call()
.getContent();
2.4 大额补货加 HITL
补货涉及资金,建议对 create_po 做人工审批:
java
import org.noear.solon.ai.agent.react.intercept.HITLInterceptor;
HITLInterceptor hitl = new HITLInterceptor()
.onTool("create_po", (trace, args) -> {
double amount = Double.parseDouble(args.get("amount").toString());
return amount >= 50_000 ? "大额补货需主管审批" : null;
});
ReActAgent replenishAgent = ReActAgent.of(chatModel)
.name("replenishment")
.role("你是补货执行专家。")
.defaultToolAdd(new ReplenishmentTools())
.defaultInterceptorAdd(hitl)
.build();
2.5 定时巡检怎么做?
TeamAgent / ReActAgent 本身不内置 cron。用业务调度触发即可:
java
// 伪代码:每 15 分钟触发一次
@Scheduled(cron = "0 */15 * * * ?")
public void patrol() throws Throwable {
String skuList = String.join(",", erpService.getAllActiveSku());
supplyChainTeam.prompt("检查这些 SKU 的库存异常并给出处理建议:" + skuList)
.session(InMemoryAgentSession.of("patrol-" + System.currentTimeMillis()))
.call();
}
三、业务效果(定性)
- 异常发现从"人工发现"变为"定时巡检"
- 常规补货从手工填单变为 Agent 生成建议 / 小额自动提交
- 采购可把时间集中在战略物料与异常供应商
- 每条决策可留 session / 审批日志,便于审计
真实处理示例
巡检发现:SKU A-1002 库存 850,安全水位 2,000,日均消耗 380,在途 0
Agent 链路:
check_inventory→ below_safe_levelget_lead_time→ 12 天calc_reorder_qty→ 建议补 6,850- 金额 = 6,850 × 0.12 = 822(低于 5 万)→
create_po直接提交- 金额若 ≥ 5 万,则 HITL 挂起,等主管批准
四、同类场景扩展
| 业务场景 | 数据源 | 巡检逻辑 | 自动动作 |
|---|---|---|---|
| 零售门店补货 | POS、门店库存 | 销量接近安全库存 | 生成调拨单 |
| 医疗耗材 | 消耗记录、效期 | 近效期优先消耗 | 标记并通知临床 |
| 备件库 | 设备台账、故障率 | 备件低于历史消耗 | 生成采购需求 |
| 大宗原料 | 期货价、库存、产能 | 低价 + 低库存 | 生成采购方案 |
| 跨境 FBA | 平台库存、销量预测 | 可售天数不足 | 生成货件计划 |
五、落地建议
- 先巡检、后执行:前两周只发现异常并通知,不自动下单
- 分阶段放开金额阈值:1 万 → 5 万 → 常规 SKU 全自动
- 每条自动执行留审计日志:时间、SKU、数量、审批人