集装箱装柜测算 · 一柜能装多少箱
定位与服务边界
这个 Skill 只回答一个问题:这批货用一个柜能装下多少、装到什么程度、还剩多少。
不报价,不排船期,不推荐箱东,不算运费。
它做的是:你已经有了每种货的外箱尺寸和件数,现在需要知道
「到底要不要加柜、这柜装得亏不亏、会不会超重」。
两件事必须说在前面,否则这份报告会被误用:
- 摆放方案是可行解,不是数学最优解。
真实三维装箱是 NP-hard。本报告给的是可核对的下限——
按这个方案一定装得下这么多件;实际装柜师傅可能还能多塞,
但不要拿它给客户承诺。 - 箱型内尺寸与载重是 ISO 常见参考值,各箱东、各年份略有差异。
报告里会原样打印出来,也允许--spec/--max-payload覆盖。
本工具不会把它说成权威数据。
三分钟上手
第一步:先确认脚本本身是好的
python scripts/container_load.py --selftest
实测输出 selftest 43/43 通过,退出码 0。
它同时验证换算常数、别名匹配、装柜算法、超重判定、报告章节编号、退出码封闭。
第二步:跑内置 demo,看清报告长什么样
python scripts/container_load.py --demo --container 40HQ --out ./out
会在 ./out 下造 2 种示例货(120 件主机箱 + 300 件配件箱)并出报告。
第三步:跑自己的货
一货一个文件,放进同一个目录:
Name: 主机箱
Length: 60
Width: 40
Height: 40
Dim Unit: cm
Unit Weight: 18
Weight Unit: kg
Pcs: 120
python scripts/container_load.py --path ./货 --container 40HQ --out ./out
支持 .txt / .md / .markdown / .csv / .json / .ini / .properties;
中文键名与中文单位同样认,实测 品名 / 长 / 宽 / 高 / 尺寸单位: 厘米 / 单件重量 / 重量单位: 公斤 / 件数 可正常解析且 0 阻断。
字段名不要求统一写法,下面这些都能认:
| 你要表达的意思 | 认得的写法 |
|---|---|
| 长 | Length L Dim L 长 长度 |
| 宽 | Width W Dim W 宽 宽度 |
| 高 | Height H Dim H 高 高度 |
| 尺寸单位 | Dim Unit Dimension Unit Size Unit 尺寸单位;取值 cm / 厘米 / 公分 / in / inch / 英寸 |
| 单件重量 | Unit Weight Net Weight Weight N.W. 单件重量 单箱重量 每件重量 净重 |
| 重量单位 | Weight Unit Wt Unit 重量单位;取值 kg / 千克 / 公斤 / lb / lbs / 磅 |
| 件数 | Pcs Qty Quantity Cartons Pieces 箱数 件数 数量 |
| 品名 | Name SKU Item Product 品名 名称 货号 |
数字后面带单位也能剥掉(18kg、60cm 都认);千分位逗号会去掉。
别名字段按三级匹配:原名精确 → 归一化精确 → 子串(且要求别名归一化后不少于 4 字)。
第三级设长度门槛是必要的——单字别名会去抢别的键
(「单件重量」里的「重」会把它认成重量单位字段)。
箱型
--container 必填,不给就报错退出(不替你猜柜型)。可选:
| 箱型 | 内尺寸(cm,ISO 常见参考值) | 常见载重(kg) |
|---|---|---|
| 20GP | 589 × 234 × 238 | 28000 |
| 40GP | 1203 × 234 × 238 | 26700 |
| 40HQ | 1203 × 234 × 269 | 26500 |
| 45HQ | 1355 × 234 × 269 | 27600 |
| 20RF | 544 × 228 × 226 | 27400 |
| 40RF | 1156 × 228 × 250 | 27700 |
--spec 1203,234,269:用自己的内尺寸覆盖(三个正数,单位 cm)--max-payload 21000:用自己的限重覆盖(kg)
输出契约
每次运行产出两份同前缀文件,写到 --out 指定的目录:
集装箱装柜测算报告-<YYYYmmdd-HHMMSS>.md——给人看集装箱装柜测算报告-<YYYYmmdd-HHMMSS>.json——给程序消费
md 报告章节(编号连续,条件章节自动顺延)
| 章节 | 是否必有 | 内容 |
|---|---|---|
| 一、结论先行 | 必有 | 要装件数 / 柜内放得下 / 未装下 / 体积装载率 / 货物总重 / 载重利用率 |
| 二、逐货明细 | 必有 | 每种货的单件尺寸、要装、装下、余数、单件体积 |
| 三、摆放方案 | 有摆放才有 | 逐块的朝向、长宽高各放几个、本块件数、所在剩余空间 |
| 四、问题清单 | 必有 | 阻断 / 警告 / 提示三级,每条带「怎么改」 |
| 五、跳过清单 | 有跳过文件才有 | 被跳过的文件与原因,不静默吞掉 |
| 六、扫描范围与漏检边界 | 必有 | 明确写出本工具不覆盖什么 |
摆放方案里末层不满会标出来(如 20×5×2 配 120(末层 20 件)),
因为只放 120 件时占的是 200 件的两层,不标就会看起来像算错。
JSON 产物字段(给程序消费,逐字段固定)
顶层:generated_at / input / container / inner_cm / payload_kg / counts / aggregate / rows / issues
counts:blockwarninfoskusskippedaggregate:box_volused_volvol_ratetotal_kgwt_ratepcs_totalpcs_placed
——total_kg在任一货没填重量时为null,不会假装算出来rows[]:relnamepcsplacedleftdims(cm 三元组)vol(cm³)issues[]:固定 6 键scopelevelcatlinesnippetfix;
level取值封闭为阻断 / 警告 / 提示
issues 一律是 6 元组、级别取值封闭,已由自检结构不变式断言兜住——
数据结构不统一时下游解包不报错、只静默取错值,比崩溃更难查。
检查项清单
一、阻断级(算不出来或装了要出事)
| 检查项 | 触发条件 | 为什么阻断 |
|---|---|---|
| 缺尺寸(长/宽/高) | 任一维缺 | 算不出装柜数量 |
| 缺件数 | 件数缺 | 不知道要装多少 |
| 尺寸单位未声明 / 认不出 | 单位空或不在映射表 | 猜错差 2.54 倍 |
| 重量单位未声明 | 给了单件重量却没给重量单位 | 不猜单位;宁可不算总重 |
| 尺寸不是正数 | 长/宽/高 ≤ 0 | 数据抄错 |
| 件数不是正数 | 件数 ≤ 0 | 同上 |
| 单件重量不是正数 | 单件重量 ≤ 0 | 同上 |
| 尺寸单位混用 | 同批出现 cm 与 in | 混用时尺寸没有意义 |
| 超过箱型常见载重 | 总重 > 载重 | 装了也上不了船/车 |
缺项绝不静默成 0:自检有专门断言 缺项不静默成 0。
二、警告级(装得下,但有剩余)
| 检查项 | 触发条件 | 怎么改 |
|---|---|---|
| 装不下,有余数 | 某货件数超过柜内可放数量 | 加柜、改小包装,或换更大箱型 |
三、提示级(省钱线索)
| 检查项 | 触发条件 | 怎么改 |
|---|---|---|
| 体积装载率偏低 | 装载率 < 50% | 改小箱型或与其他货拼柜;空跑的体积也是钱 |
触发与不触发
会触发
- 「一柜能装多少箱」「这批货 40HQ 装不装得下」
- 「装柜怎么排」「装箱方案怎么出」
- 「装载率多少」「柜子还剩多少空间」
- 「要不要加柜」「超重了怎么办」
- 「20GP 和 40HQ 差多少」
不会触发(非触发边界)
- 「哪家货代便宜」「这一柜运费多少」——本工具不算运费、不比价,属报价比价类工具
- 「报关单证齐不齐」「发票箱单怎么开」——属出口单证体检
- 「关税多少、到岸成本多少」——属到岸成本测算
- 「选哪个国家出海」——属出海准备度诊断
- 「订舱、拖车、报关执行」——属执行动作,不是计算问题
扫描范围与漏检边界
会读的
- 指定目录下所有
.txt / .md / .markdown / .csv / .json / .ini / .properties
文本文件(子目录递归,跳过__pycache__ / .git / node_modules等) - 也接受
--path直接指向单个文件 - 编码按
utf-8-sig → utf-8 → gbk → utf-16依次尝试,最后才errors=replace
不读的(会计入「跳过」并列出,绝不静默吞掉)
- 其他扩展名的文件(如
.xlsx、图片、PDF) - 空文件
- 解析不出任何字段的文件
- 多行数据行的
.csv(要求一货一文件)
判不了的(本工具明确不做,也不是缺陷)
- 不报价、不排船期、不推荐箱东、不算运费——只算装得下多少
- 箱型内尺寸与载重是 ISO 常见参考值,各箱东略有差异
- 摆放方案是可行解不是最优解;真实装载还受堆叠限制、重不压轻、
托盘/缠膜、货物能否侧放(如向上箭头标识)影响,本工具一律不考虑 - 单件重量不填就不做超重判定,不会假装算出来
- 车轴限重、目的港限重通常比箱型载重更紧,需另行确认
- 不支持非长方体货物(桶装、异形件、裸装设备)
本报告 0 问题 ≠ 这柜一定能装,只代表上面的检查项没命中。
常见错误与应对
| 现象 | 原因 | 怎么改 |
|---|---|---|
报错 需要 --container(箱型) |
本工具不猜柜型 | 明确指定,如 --container 40HQ;可选项 20GP/40GP/40HQ/45HQ/20RF/40RF |
报错 未知箱型 99XX |
拼错或不在表里 | 用上面六个之一;非标箱用 --spec 给内尺寸 |
报错 --spec 需要三个正数(cm) |
只给了两个数,或混了单位 | 只写数字:1203,234,269,不要写 1203cm |
报错 --max-payload 必须是数字 |
限重里混了单位 | 只写数字:21000 |
报错 --demo 与 --path 不能同时使用 |
两个入口互斥 | 只留一个 |
报错 没有可测算的货物规格(共跳过 N 个) |
目录下没有能解析出字段的文件 | 看紧随其后的逐条跳过原因,多半是扩展名不对或键名不在别名表 |
| 报「尺寸单位未声明」但我明明写了 | 单位写法不在映射表 | 用 cm 或 in(或 厘米 / 英寸) |
| 报「尺寸单位混用」 | 同批里既有 cm 又有 in | 先统一单位再算 |
| 报「重量单位未声明」 | 给了单件重量却没给单位 | 补 Weight Unit: kg;本工具不默认按公斤算 |
| 报告里没有「货物总重」一行 | 至少有一种货没填单件重量 | 补齐重量与单位;不填就不做超重判定,这是刻意的 |
| 装柜数量比预期少很多 | 摆放方案是可行解不是最优解 | 换朝向试试 --spec 微调内尺寸;或接受它是保守下限 |
摆放表里写 20×5×2 却只有 120 件 |
末层没放满 | 这是正常的,件数后会标「末层 20 件」 |
异常与兜底
| 场景 | 行为 | 验证方式 |
|---|---|---|
| 某个货规文件损坏或解析失败 | 记入「跳过清单」,其余照算,单条坏数据不打断整批 | 混合批次实测 |
| 目录下全是二进制垃圾 | 不崩溃,报 没有可测算的货物规格,退出码 2 |
二进制-only 目录实测 |
| 空目录 | 同上,退出码 2 | 空目录实测 |
| 编码猜不出(GBK / UTF-16 混着) | 四级兜底,最后一级 errors=replace 也不抛异常 |
自检断言编码兜底顺序 |
--out 指向一个已存在的文件 |
报 输出目录不可写,退出码 3 |
退出码封闭探针实测 |
--path 不存在 |
报 路径不存在,退出码 2 |
退出码封闭探针实测 |
| 参数缺失 / 非法 | 报明确原因,退出码 2 | 无参数、缺 --out、缺 --container、未知箱型逐项实测 |
有阻断级问题且加了 --fail-on-block |
退出码 2 | 造「有重量无单位」输入实测 |
无阻断且加了 --fail-on-block |
退出码 0 | demo 实测 |
退出码封闭为 0 / 2 / 3:0 成功、2 数据或参数问题、3 输出不可写。
main() 顶层显式捕获异常并转为退出码 2,不会把 traceback 抛给调用方;
SystemExit 单独放行,不会被 except Exception 吞掉。
所有参数校验前置到分支之前——--demo 走的是同一套装柜逻辑,
不会因为它带内置示例数据就绕过 --container 校验。
实战案例(真实跑通,数字为脚本实跑输出)
案例一:内置 demo,40HQ 装两种货
命令:python scripts/container_load.py --demo --container 40HQ --out ./out
结果:货物 2 种(跳过 0),问题:阻断 0 / 警告 0 / 提示 1
| 口径 | 数值 |
|---|---|
| 要装的件数 | 420 |
| 柜内放得下 | 420 |
| 未装下 | 0 |
| 体积装载率 | 29.5% |
| 货物总重 | 3960 kg |
| 载重利用率 | 14.9% |
| 品名 | 单件尺寸(cm) | 要装 | 装下 | 余数 |
|---|---|---|---|---|
| 主机箱 | 60.0×40.0×40.0 | 120 | 120 | 0 |
| 配件箱 | 40.0×30.0×30.0 | 300 | 300 | 0 |
摆放方案:
| # | 品名 | 朝向(cm) | 长×宽×高各放 | 本块件数 | 所在空间(cm) |
|---|---|---|---|---|---|
| 1 | 主机箱 | 60.0×40.0×40.0 | 20×5×2 | 120(末层 20 件) | 1203×234×269 |
| 2 | 配件箱 | 40.0×30.0×30.0 | 30×6×2 | 300(末层 120 件) | 1200×200×189 |
手算复核:1203÷60 = 20(余 3 cm),234÷40 = 5(余 34 cm),269÷40 = 6 层;
每种货只放 2 层即够 → 20×5×1 + 20 件 = 120 ✓。
占用体积 120×0.096 + 300×0.036 = 11.52 + 10.80 = 22.32 CBM,
柜容 1203×234×269 = 75.72 CBM → 29.5% ✓。
总重 120×18 + 300×6 = 3960 kg,对常见载重 26500 kg → 14.9% ✓。
装载率只有 29.5%,所以报了一条「体积装载率偏低」——
这正是本工具最有用的地方:告诉你这一柜明显装亏了,该改小箱型或拼柜。
案例二:单 SKU 装满 40HQ
输入一种货 60×40×40 cm、单件 18 kg、件数 100000:
- 柜内放得下 600 件(1203÷60=20,234÷40=5,269÷40=6,20×5×6=600)
- 未装下 99400 件 → 报「装不下,有余数」
- 体积装载率 76.1%(600×0.096 = 57.6 CBM ÷ 75.72 CBM)
- 货物总重 600×18 = 10800 kg,载重利用率 40.8%
若把单件重量改成 100 kg,同样 600 件总重 60000 kg > 26500 kg
→ 报阻断「超过箱型常见载重」,--fail-on-block 时退出码 2。
已验证清单(全部 2026-10-05 实跑,未跑的不写)
python scripts/container_load.py --selftest→ 43/43 通过,退出码 0- 内置 demo(40HQ,2 种货)→ 阻断 0 / 警告 0 / 提示 1;要装 420 装下 420,装载率 29.5%
- 单 SKU 60×40×40 cm 装 40HQ → 600 件,与手算 20×5×6 一致
- 只放 10 件(少于整层 100 件)→ 实装 10 件,不多装(有专门断言防止按整层占满)
- 英寸与厘米输入结果一致(23.622 in ≈ 60 cm,装柜数量差 ≤ 6 件)
- 超重(60000 kg > 26500 kg)→ 判阻断,报告给出总重
- 缺高 → 判阻断,且不输出任何
0.00假装算出来的值 - 给重量不给单位 → 判阻断,不默认按公斤算
- 尺寸单位混用(cm + in)→ 判阻断
- 中文键名 + 中文单位(厘米 / 公斤)→ 正常解析,0 阻断
- 二进制-only 目录 → 不崩溃,退出码 2
- 空目录 → 退出码 2
--out指向已存在文件 → 退出码 3- 缺
--out/ 缺--container/ 未知箱型 /--spec维度不对 /--max-payload为 0 或非数字 → 退出码 2 - 换
--spec结果必须变化 → 已断言,确认参数真被消费 - 有阻断加
--fail-on-block→ 退出码 2;无阻断 → 退出码 0 - 报告章节编号连续、产物无
%%转义残留 → 已断言