| name | fbo-orchestrator |
| description | Ozon FBO 端到端发货编排. 当用户说"丝绸生活账号补 N 天 FBO"、"按安全天数发货"、"清空海外仓"、"补海外仓没货的 SKU"、"Q_X 发 N 箱你帮分集群"、"全自动发货"、"FBO 一键发"时触发. 自动 4 mode 决策 + 跑 create_fbo_plan + cron-style 自动 retry 直到全发完, 终态出对照表 Excel. wrapper 调用老 fbo-* 子 skill 的脚本, 不重复实现. |
FBO Orchestrator — 一键发货编排
5 个老 skill (fbo-fill-boxes / fbo-plan / fbo-retry / fbo-service-up / fbo-status) 仍单独可用 — 本 skill 只是把它们组合成端到端流程, 处理决策 + 自动 retry + 终态报告.
4 种触发 mode
| 用户说法 | mode | 触发条件 |
|---|
| "丝绸生活补 60 天", "按安全天数发" | safety_days | 用户给 SKU 列表 + 想要的目标天数, 走 4180 算每集群 gap |
| "清空海外仓", "全部发 FBO" | force_dispatch | 走老 /ozon-restock-force-dispatch skill (Bitable HITL) |
| "Q_MeiGongDao 24 箱, Q_ChongQiZui 12 箱, 帮我分集群" | manual_matrix | 用户给 {SKU: 总箱数}, skill 按各集群 need_pieces 占比分摊 |
| "海外仓没货的 SKU 都补一下" | missing_sku_top_up | 4180 inventory==0 的 SKU 用 4181 plan.allocations 全发 |
入口脚本
/Users/mac/.claude/skills/fbo-orchestrator/orchestrate.py (~250 行) — 出 plan.json 喂下游.
python3 ~/.claude/skills/fbo-orchestrator/orchestrate.py \
--mode safety_days --account 丝绸生活 \
--skus Q_MeiGongDao-HeiSe-Free,Q_ChongQiZui-HuangSe-Free \
--out /tmp/orch_plan.json
python3 ~/.claude/skills/fbo-orchestrator/orchestrate.py \
--mode manual_matrix --account 丝绸生活 \
--boxes 'Q_MeiGongDao-HeiSe-Free=24,Q_ChongQiZui-HuangSe-Free=12' \
--out /tmp/orch_plan.json
python3 ~/.claude/skills/fbo-orchestrator/orchestrate.py \
--mode missing_sku_top_up --account 丝绸生活 \
--out /tmp/orch_plan.json
python3 ~/.claude/skills/fbo-orchestrator/orchestrate.py \
--mode force_dispatch --account 丝绸生活
输出 plan.json 跟 list_pending --emit-plan 同结构 (3 个键: source_warehouse_keyword / drop_off_keyword / matrix), 直接喂 create_fbo_plan.py.
SOP (Claude 在 session 里编排)
Step 0 — 健康检查:
curl -s http://localhost:4180/api/health 2>/dev/null || curl -s -o /dev/null -w "4180 %{http_code}\n" http://localhost:4180/api/rows?date=2026/04/26
curl -s -o /dev/null -w "4181 %{http_code}\n" http://localhost:4181/docs
rtk proxy curl -s http://localhost:4182/health
任何一个挂 → push 报警退. 不需要全 200, 但至少 4181/4182 要活 (4180 必备 if mode in [safety_days, manual_matrix, missing_sku_top_up]).
Step 1 — 选 mode + 跑 orchestrate.py:
按用户说法定 mode (上面表), 跑 orchestrate.py 出 /tmp/orch_plan.json.
如果 mode = force_dispatch, 跳到 /ozon-restock-force-dispatch skill, 等用户 Bitable 审批后再继续 — 此时本 skill 暂停, 等用户回到本 skill 继续 retry.
Step 2 — dry-run 检查:
cat /tmp/orch_plan.json | python3 -c "import sys, json; d=json.load(sys.stdin); m=d['matrix']; print(f'集群 {len(m)}, SKU {len({s for c in m.values() for s in c})}, 总 {sum(q for c in m.values() for q in c.values())} 件')"
让用户看一眼 — 如果数字明显不对 (如 manual_matrix 给了 24 箱但分到 0 集群), 拒跑.
Step 3 — 跑 create_fbo_plan:
cd /Users/mac/Documents/ozns/丝绸生活/海外仓发货表/2026-04-23海外仓发货
nohup python3 create_fbo_plan.py --config /tmp/orch_plan.json --box-size 300 --account <账号> > /tmp/orch_run_$(date +%H%M).log 2>&1 &
Monitor PID 退出, grep alloc|fallback:|state=|reason=|order_id|✓|✗|!|shipped=|skipped=|完成|done|scoring|cancel|实接|shift|Traceback.
Step 4 — 解析 ledger:
LEDGER=$(ls -t ledger/shipment_ledger_*.json | head -1)
python3 -c "import json; d=json.load(open('$LEDGER')); print(f'shipped: {len(d[\"shipped\"])} orders / {sum(sum(it[\"quantity\"] for it in s[\"items\"]) for s in d[\"shipped\"])} 件; skipped: {len(d[\"skipped\"])} 条 / {sum(s[\"quantity\"] for s in d[\"skipped\"])} 件')"
Step 5 — 自动 retry loop:
- 用
/loop 1h <retry-prompt> 启动每小时 cron (复用 fbo-retry skill 的模板)
- 每轮: list_pending --emit-plan → create_fbo_plan → 解析 ledger
- 失败原因分类:
NOT_AVAILABLE_MATRIX / NOT_AVAILABLE_ROUTE: 静默 retry (24h+ 才有意义松开)
- 限流踩 > 半数: push "限流踩 N/8, 考虑加严限流"
- 实接 < box/2 的 supply 自动 cancel (
MIN_BOX_FILL_RATE, 80h shift 规则)
- 其他错误 (网络/4182 503): 静默
- 直到
python3 list_pending.py 输出 0 条 → push "✅ <账号> 全发完, 共 X 件 / Y 集群"
Step 6 — 终态报告 (双视角):
(a) 按集群×SKU 决策视角 — 计划/已发/差额/状态 (老板/决策视图):
python3 build_shipment_overview.py --exclude-before <run_start_iso>
"改派抵扣已完成" 状态自动展示.
(b) 按发运日期实操视角 — 司机交货前打印用 (调度/实操视图):
python3 build_by_date.py
输出 by_date/YYYY-MM-DD/{对照表.xlsx, 箱唛合并.pdf}. 默认只取 Ozon 后台 "准备交货" tab (READY_TO_SUPPLY), 同日所有 supply 的箱唛 PDF 合并为 1 个文件方便打印.
决策算法 (orchestrate.py 内)
safety_days (per-cluster gap)
对每 (sku, cluster):
target = safety_days * daily_sales (4180 /api/rows[].FBO安全天数 × 每日销量)
on_hand = FBO上架数量 + FBO越库在途数量
gap = max(0, target - on_hand)
effective = floor_box(gap, box_size, ≥ box/2 残箱保留, 否则砍)
matrix[cluster][sku] = effective
manual_matrix (用户给总箱数, skill 分配)
for sku, total_boxes in user_input:
total_pieces = total_boxes * 300
rows = 4180 /api/rows?sku=X
weights = need_pieces / sum(need_pieces) # 优先按集群缺口比例
# 兜底 daily_sales 比例 (无缺口时)
按 weights 大→小遍历, 每集群 alloc = total_pieces * weight
+ floor_box (≥ box/2 残保留)
remaining 在最后集群兜底
missing_sku_top_up
plans = 4181 /plans?account=X (status in approved/dispatched, 取最新 created_at)
for sku, plan in plans:
if 4180 /api/overseas_inventory?sku=X .value > 0:
skip
else:
detail = 4181 /plans/<plan_id>
for alloc in detail.allocations:
matrix[alloc.cluster][sku] = floor_box(alloc.pieces)
force_dispatch (跳老 skill)
不出 plan.json, stderr 提示用户在 session 里走 /ozon-restock-force-dispatch.
常见问题
Q1: safety_days 跑出来 matrix 空
- 可能所有集群都已超 safety 上限 (一般是节后) → 不需补
- 4180 服务挂 (
/api/rows 拿不到) — 检查 4180 health
- SKU 名错 (4180 找不到) — 看 stderr
Q2: manual_matrix 分配不均匀
- 算法按
集群需补货数量 占比 — 4180 算法已偏好缺口大的集群
- 整箱 floor + 残箱 ≥ box/2 规则会损失一些零头, 这是用户硬规则
- 如果用户想精确分到某集群, 直接手写 plan.json 不走本 skill
Q3: force_dispatch 之后回到本 skill 怎么继续 retry
跑完 ozon-restock-force-dispatch 后, 4181 plans 已 approved/dispatched. 直接进 Step 5 retry loop (list_pending 会捡起未发的).
Q4: 多账号怎么搞
一次只跑一个账号 (跟老 skill 一致). 跨账号: 用户连续起两个 cron, 各自带 --account.
Q5: 不同 box_size 的 SKU
本 skill 默认全部 300 (--box-size 覆盖). 若混 SKU 不同 box_size, 用 4181 plan-id 模式: orchestrate.py 出 plan.json 后, 跑 create_fbo_plan.py --plan-id <pid1>,<pid2> (绕开 cfg 模式), box_size 自动按 plan.
同步 .py 副本
orchestrate.py 是 skill 自带的, 不会被 sync 脚本动. 改 orchestrate.py 直接编辑 ~/.claude/skills/fbo-orchestrator/orchestrate.py.
工作目录的 list_pending.py / create_fbo_plan.py 改了用 bash ~/.claude/skills/sync_fbo_scripts.sh 同步到老 5 个 skill (本 skill 不依赖副本).
相关 skill / memory
/fbo-service-up — 4182 docker 运维
/fbo-plan — 直接跑 plan.json (本 skill Step 3 调它的脚本)
/fbo-retry — list_pending 算法 (本 skill Step 5 复用)
/fbo-fill-boxes — 单 order fill (--skip-fill 后补流程)
/fbo-status — build_shipment_overview (本 skill Step 6 调)
/restock-to-fbo — 单 SKU safety_days (本 skill 多 SKU 版的灵感来源)
/ozon-restock-force-dispatch — force_dispatch 走老 skill 链 (Bitable HITL)
- memory
reference_restock_api.md — 4180 端点契约
- memory
reference_fbo_rs_integration.md — 4181 plan 模型
- memory
reference_create_fbo_plan_sop.md — create_fbo_plan SOP 6 步
- memory
feedback_partial_box_residue_rule.md — 整箱 floor + 残箱 ≥ box/2
- memory
feedback_safe_cancel_80h_rule.md — 取消 supply 必先 shift ≥80h
- memory
feedback_reallocate_to_moscow_capacity.md — per-SKU 总量算法 + 改派抵扣