19 KiB
邮件指令提取规则(对照实现)
用途:给产品/运营对照「接下来没见过、格式很怪」的邮件,判断系统会不会拉进库、认成哪类指令、字段从哪来。
约束:解析不走大模型,全部是词表 + 正则 + 固定模板。新格式要么命中现有规则,要么漏/错,不会「猜一下」。
实现真源:src/services/parse/(词表instruction-lexicon.ts、分类classify.ts、拆段split-instructions.ts、流水线pipeline.ts)。
产品口径:docx/产品规则-邮件指令识别与拆分.md(冲突时以代码为准,并回写产品页)。
日期:2026-08-14
0. 一句话
一封信要变成可确认的业务卡,必须连过四道门:
- 拉取:过滤规则 / 业务兜底认为「相关」才入库。
- 分类:主题+正文+附件名打分,得到整封主类型。
- 拆指令:按时间轮切开,每段映射到 UI 卡(预报 / 转仓 / 工单 / 上传 DO / 客户指令)。
- 抽字段:柜头来自主题模板或正文标签;货件行几乎只来自 xlsx/xls/csv(卡派表或贴标指令单)。
任何一步没命中,后面再「看起来像业务」也不会自动补全。
flowchart TD
A[IMAP 新信] --> B{拉取过滤}
B -->|SKIP_FILTER / 黑名单| Z[不入库]
B -->|入库| C[classify 打分]
C --> D[split 拆时间轮]
D --> E{有表格附件?}
E -->|xlsx/xls/csv| F[卡派表 / 贴标指令单]
E -->|无表| G[仅柜头 + 空货件]
F --> H[详情指令卡]
G --> H
H --> I[人工确认写入 CC]
1. 拉取:什么样的信根本进不来
实现:src/services/imap/pull-filter.ts + classify.ts isBusinessRelevantMail。
| 顺序 | 条件 | 结果 |
|---|---|---|
| 1 | 发件人在黑名单,或主题/正文命中关键词黑名单 | 不拉 SKIP_BLACKLIST |
| 2 | 发件人在白名单 | 拉 |
| 3 | 主题/正文命中设置页关键词 | 拉 |
| 4 | 过滤全空时走业务兜底 | 见下表 |
| 5 | 已配置过滤但以上都不中 | 不拉 SKIP_FILTER |
业务兜底(过滤全空才用)任一为真即拉:
- 分类结果不是
UNKNOWN - 主题/正文/附件名命中:
新增预报|转仓|换标|覆盖贴|贴标|拍照|拆柜清单|卡转海|拦截|改自提|留仓|卡派|装箱|货件清单|船名|航次|柜型|40HQ|20GP|ETA|预报资料|拆柜|柜号|快递单号|工单|DO|DO请查收 - 文本或附件名里有 ISO 柜号
[A-Z]{4}+ 7 位数字(如WHSU8127240) - 附件名像卡派/装箱/packing/清单/预报/转仓/换标/贴标/货件/DO
- 有表格附件 且 正文弱物流词:
资料|清单|柜|仓|FBA|shipment|container
未见过的信在这里就会丢:
- 纯英文、无柜号、无上表关键词(例如 “please book this container”)
- 只写「请安排」「帮忙处理」而无标准词
- 柜号不是 ISO 四字母+七数字(短柜号、带校验位空格、中文「柜」无号)
- 设置了关键词过滤,但新客户用了别的叫法,又不在白名单
2. 整封分类(主类型)
实现:classifyMail。优先级(同分取更靠前):
DO_UPLOAD > NEW_CONTAINER > TRANSFER > WORK_ORDER
总分 < 40 → UNKNOWN(列表里常变成忽略/无法确认)。
| 信号 | 加分 | 落到 |
|---|---|---|
DO请查收 / 请查收 DO / 上传 DO / 文件名独立 DO 的 PDF |
55(无真实 DO 且主题已是拆柜清单则降到 25) | DO_UPLOAD |
新增预报 / 请查收新增预报 |
50 | NEW_CONTAINER |
附件名 数据模版 或 预报资料|货件清单|装箱清单 的表格 |
45(已有预报分则 +15) | NEW_CONTAINER |
新增转仓 或 转仓(排除 不转仓) |
50 | TRANSFER |
| 硬工单:贴标/拦截/拍照/快递单号,或换标/覆盖贴/贴好拍照 | 45 | WORK_ORDER |
| 软词:拆柜清单 / 卡转海 / 派送要求 / 改自提 / 更新派送单 / 留仓 | 45 | WORK_ORDER |
附件名 换标|贴标指令 |
30 | WORK_ORDER |
| 正文最新段已是硬工单 | 压过主题上的历史「新增预报」/DO | WORK_ORDER |
| 分类仍 UNKNOWN,但有 ISO 柜号或「预约码」 | 40 兜底 | WORK_ORDER(mail1 类) |
会错的典型:
- 主题还挂着「新增预报」,最新回复是换标 → 会压成工单(这是刻意的)。
- 「拦截-209件」只是渠道汇总,不当整票拦截;真正拦截必须正文另有「拦截」且不是
拦截-数字件。 - 文件名叫
卡派资料.xlsx不会单独打成预报,还要有「新增预报」或「数据模版/装箱清单」等。 - 英文 “new booking / transload / relabel” 不加分。
3. 多轮拆段 → 指令卡
实现:split-instructions.ts + instruction-lexicon.ts。
3.1 怎么切开
按边界切(保留分隔标签到后一段):
---- 原始邮件 / 转发的邮件 / Original Message ----在 yyyy-mm-dd … 写道/在 yyyy年m月d日 … 写道/On … wrote:发件人+发送时间/日期邮件头- 行内嵌套
> 在 … 写道(QQ 引用)
不用单独的 Dear 当切段点。
弱切(独立成行才切):新增预报|请查收新增预报|新增转仓|更新派送单|拆柜清单|派送要求|换标|覆盖贴|贴标指令|出库|留仓|拆分|DO请查收|请查收 DO
3.2 关键词 → UI kind
| UI | 关键词(节选,见词表) | 确认动作 |
|---|---|---|
forecast |
新增预报、请查收新增预报;正文 柜号:XXXX1234567 派送单,请查收;提柜+柜型+卡派/拆柜 |
预报表单 |
transfer |
新增转仓、转仓(不转仓 除外) |
批量转仓;CC 到仓闸门失败则降级工单 |
work_order |
贴标/换标/覆盖贴/操作指令、拍照、拦截(非渠道件数)、快递单号;软词拆柜清单/卡转海/派送要求/改自提/更新派送单/改地址派送/点前送达 | 客户留言 / 转渠道 / 拆分 / 出库 |
do_upload |
DO请查收、请查收 DO、文件名独立 DO 的 PDF | 上传 DO |
customer_instruction |
按照正常预报接受、帮忙安排派单、继续暂存 | 只读,不提交 |
跳过(不出卡):QQ 转发壳、发自我的iPhone、空 Original、主题残片。
可确认的一般是最新一轮有实质指令的段。 历史预报/转仓可只读展示;历史转仓现在也允许单独执行。
同线程主题只变 Re:/Fw: 时,不得再用首封主题「新增预报」给最新轮再造一张预报卡。
3.3 附件挂到哪张卡
实现:match-segment-attachments.ts。顺序:
- 主键交叉:附件名与本段出现同一
FBA…/YT…/X0…(FNSKU)/WL…唛头。不用 ISO 柜号给工单分附件。 - 正文/主题出现该文件主名(去扩展名、去
(1))。 - 仅当前可确认段角色兜底:文件名含卡转海 / 换标|覆盖贴|操作指令|贴标交付。
*DO*.pdf只进上传 DO 卡。- 卡派/装箱 xlsx 是解析源,默认不进工单附件。
- 跳过
*邮箱.pdf/ QQ 截图。
4. 预报(NEW_CONTAINER / forecast)
4.1 主题柜头:两种互斥模板
A. 客户+提单预报(bl-plus-template.ts)
剥掉 Fw:/转发/新增预报N: 后,用 +(或全角+) 分段。无 + 才按空格切,二者互斥。
常见形态:
新辰泽+WHLC027G597465+WHSU8127240+洛杉矶+40HQ+EDT2026.04-25+ETA2026.05-15+船名航次HMM EMERALD 013E+提拆派+不带托架
能抽出:客户名、提单、柜号、目的港(美国港口白名单)、柜型、ETD/ETA、船名航次、服务(提拆派/直送)、是否带车架。
客户名不得是柜号/提单/「贴标/转发/柜号」等。目的港未进白名单(洛杉矶/长滩/纽约/萨凡纳/奥克兰/西雅图/塔科马/休斯顿/迈阿密/查尔斯顿等)→ 不写港口。
标签型(首段就是 柜号: / 提单号:,客户不在提单前):
Fw: Fw:回复:柜号:TRHU8524770+提单号:EGLV143661466958+封号:EMCEJJ0635+YWZD+不带车架+整柜直送
| 段 | 落到 |
|---|---|
柜号:TRHU8524770 |
柜号 |
提单号:EGLV143661466958 |
提单 |
封号:EMCEJJ0635 |
备注(预报 UI 无封号格) |
YWZD |
客户(排除已知字段后仅剩 1 个独立缩写) |
不带车架 |
车架 = 不带 |
整柜直送 |
业务类型 = 直送 |
带「名称:值」前缀的段,不得去抢客户名。 前缀已经说明这是有名字的字段;对不上预报 UI 的(封号/铅封/预约码等)一律进备注。无前缀的短码(如 YWZD)才参与客户竞争。
B. 工单/拆柜清单主题(ops-subject-template.ts)
形态:柜号+提单+船名航次:…+ETA:…+FedEx-29件+拦截-209件+…
一旦命中 B,不再当 A 的客户+提单预报。渠道 Xxx-N件 只作汇总,不是整票指令。
4.2 正文柜头补全(extract-container-header.ts)
只认带标签的字段,不扫全文乱截:
| 字段 | 规则 |
|---|---|
| 柜型 | \b(45HC|45HQ|40HC|40HQ|40GP|20GP|20HQ|45GP)\b |
| ETA | ETA|预计抵港|抵港日|到港 + 日期 |
| ETD | EDT|ETD|预计开船|开船日|离港 + 日期 |
| 提单 | 提单(号)|B/L|BLCopy + 号;否则跳过 ISO 柜号取裸 ABCD+数字串 |
| 装货港 | 装货港|起运港|POL |
| 目的港 | 目的港|卸货港|码头|POD + 白名单 |
| 船司 | 显式「船司」> 提单前 2–4 位前缀 > 正文别名 > 船名首词 |
| 车架 | 带车架/带托架 vs 不带车架/不带托架 |
| 操作 | 提拆派 → 0;直送 → 2 |
| 运输方式 | 柜型/船名航次/海运提单前缀 → 海运;否则航司别名 → 空运 |
| 封号/铅封 | 封号|铅封|封条 + 号 → 备注(预报 UI 无此格) |
正文没有这些标签时,柜头对应格就是空的(例如只写 “arriving LA next week”)。
附件解析结果优先;邮件文本只补空字段。
4.3 货件行(几乎只认表格)
选表优先级(文件名):数据模版|提拆派|卡派资料|卡派清单|装箱清单|packing > 其它表格 > 换标|覆盖贴|贴标|操作指令。
卡派表(packing-list.ts):
- 优先 sheet 名含「卡派」,否则第一张表。
- 前 15 行找表头:同时有「渠道」+(件数或 CTNS)+(仓库或 FBACode)。
- 必有列:仓库ID/
FBACode、渠道/Transporter、件数/CTNS。缺一则PARSE_FAILED,再尝试贴标指令单。 - 「注意:…」模板说明行不是货件。
- 渠道映射:卡派→TRUCK,UPS/FEDEX/DHL/USPS/SF/4PX/YunExpress,自提,留仓/存仓,换标,扣货/拦截。超 40 字或「注意:」开头不当渠道。
列名别名见代码 HEADER_ALIASES(中英混排、Custmer Ref No. 错拼也认)。
贴标指令单(label-instruction.ts)表头含「贴标项目 / 详细操作指令 / 新FBA / 覆盖贴 / 换标」或同时有柜号+操作箱数。
lineage.template=label-instruction 时:预报货件列表必须空,换标行不当 SaveContainer 货件。
无表格:预报可仅柜头进待确认;货件列表空。PDF/图片卡派表 不会当货件解析(转仓截图 OCR 是另一条路)。
4.4 柜头 Instruction / 备注(不是货件行备注)
| 表单格 | CC 字段 | 实际来源 |
|---|---|---|
| Instruction | F_Instruction 拆柜指引 |
① 预报正文段(含新增预报/提单/柜型/ETA/船名,且不含换标/贴标)截 500 字;② 否则 船名航次 xxx;③ 贴标单则用首行操作说明(预报卡会改回 ①②) |
| 备注 | F_MemoRemark |
优先:主题/正文里带标签但对不上预报 UI 的字段(封号:EMCEJJ0635、铅封:…、预约码:… 等),多段用 / 拼接。否则回退:客户名 / 提拆派或直送。贴标 sheet 标题含贴标/换标/指令时预报卡会清掉。 |
| 货件「行备注」 | F_Remark |
卡派列「备注 / Remark / Instruction / 配送时段」 |
未映射标签 → 备注(硬规则)
- 段内已有
名称:值(或名称:值)前缀,说明这是有名字的字段,禁止拿去填客户。 - 名称能对上预报 UI(柜号/提单/柜型/ETA/ETD/船名航次/目的港/装货港/船司/客户/运输方式/业务类型)→ 填对应格。
- 名称对不上(封号、铅封、预约码,以及其它未知标签)→ 整段原文进备注。
- 无前缀的剩余短码:仅当排除已知字段后恰好剩 1 个才当客户;剩多个则全部进备注,不强猜客户。
- 已占用的「柜号:」「提单号:」会从备注里剥掉,避免和柜号/提单格重复;封号保留。
去 QQ/Outlook/iPhone 转发壳后再填 Instruction。
5. 转仓(TRANSFER)
- 关键词:
新增转仓/转仓,排除不转仓。 - 货件:卡派表行备注「转 POC2」「转VGT2」等 →
extractTransferPairs。 - 截图/OCR 表(
transfer-instruction-table.ts):- 标准:
地址 PSC2 箱数 7 … 仓库重定向 POC2 - 宽松:同行
地址 X … 仓库重定向 Y - 仓码归一:FWA4 / PSC2 / POC2 / VGT2(含 OCR 错写 EWAD、WAAD4 等)
- 标准:
- 确认时查 CC 是否已到仓;不可转则自动改提交工单。
会漏: 英文 transload、没有「地址/仓库重定向」的自由句、目标仓不是上述几种代码、只在 PDF 里画了箭头。
6. 工单(WORK_ORDER)
硬动作:贴标 拦截 拍照 快递单号,同义 换标 覆盖贴 贴好拍照。
软词(也走工单卡,不硬套某张 CC 工单界面):拆柜清单、卡转海、派送要求、改自提、更新派送单、改地址派送、点前送达。
mail1:主题只有柜号+预约码、无标准词 → 分类工单,详情用 work_order_actions 补卡。
留言取当前段,从 Dear / 原箱号 起,禁止整封线程盖住本段。
面板分流(管理端/客户端):拦截/改渠道 → 转渠道;数量拆分 → Split;出库/贴标文件 → 出库;其余 → 客户留言。
7. 上传 DO
文件名:DO请查收 / 提货单 / delivery order,或 PDF 且独立单词 DO(WHSU8127240-DO.pdf、xxx-DO.pdf)。
正文写「DO 也同步上传」但没有这类附件 → 不出空 DO 卡。
柜号:已有柜头 > 文件名 ISO 柜号 > 主题/正文第一个 ISO 柜号。
.docx / 图片扫描件不叫 DO、文件名是 DeliveryOrder_final.pdf 无独立 DO 词 → 可能认不出。
8. 金样覆盖(已按这些规则调过)
| 样例 | 期望 | 规则依赖 |
|---|---|---|
| 邮件1 仅柜号 TIIU8073522 | 工单兜底 | ISO 柜号、无关键词 |
| 邮件2 MATU + 卡派 xlsx | 转仓 | 新增转仓 + 卡派表 |
| 邮件3 拆柜清单+渠道件数 | 工单 | 工单主题模板 + 软词;渠道件数不是拦截指令 |
| 邮件4 预报+换标+DO | 工单为主,预报/DO 可并存 | 最新段硬工单压预报;卡派表优先于换标表;DO 文件名 |
这四封能过,不代表换一套客户模板也能过。
9. 覆盖缺口清单(用来对照新邮件)
把新邮件贴到下面问:会在哪一层失败?
9.1 进不了库
- 没有 ISO 柜号,也没有第 1 节关键词
- 纯英文 booking / sailing / transload / relabel / hold
- 已配关键词过滤,新叫法不在列表、发件人不在白名单
- 主题乱码(GBK/UTF-8 错码)导致关键词对不上
9.2 能进库但类型错 / UNKNOWN
- 同义说法:新增订舱、做预报、改仓、贴新标、hold cargo、stop shipment
- 「转」但没写「转仓」;「不要转仓」以外的否定
- 预报附件不叫数据模版/装箱清单/卡派资料
- 主题预报 + 正文最新段换标(会变成工单,可能符合产品,但预报卡不是当前)
- 预报与 DO 分数接近(close_call),以优先级表为准
9.3 类型对但字段空
- 主题不用
+分隔(用空格/逗号/表格/HTML) - 港口不在美国白名单(如西雅图别称未收录、欧洲港)
- 柜型写成 40'HQ / 40 尺柜 / HC 无数字
- 日期无 ETA/ETD 标签(只写 5/15)
- 船名不写「船名航次」四字
- 只写「备注:」标签、没有
封号:这类字段名 — 当前不从「备注:」抽备注;未映射的名称:值才会进备注 - 封号写在无
+、无冒号的自由句里(如 “seal EMCEJJ0635”)
9.4 有附件但货件为空 / 错表
- 卡派是 PDF、图片、Word,不是 xlsx/xls/csv
- 表头不叫渠道+件数+仓库(例如全英文 Warehouse / Qty 但没有渠道)
- 缺仓库ID/渠道/件数三列之一
- 只有换标指令单被当成预报行(文件名若不像卡派,可能先吃换标表;预报卡会清空货件)
- 表在 zip 内层路径/加密压缩包
- 附件过大被拒
9.5 转仓 / 工单 / DO 细节
- 转仓目标仓不是 PSC2/POC2/FWA4/VGT2
- 工单附件只靠柜号关联(规则故意不用柜号分发)
- DO 是 JPG/扫描件,或文件名无独立 DO
9.6 编码与客户端壳
- QQ 转发壳、iPhone「发自我的」会剥;剥完若没剩指令词则跳过该段
- 正文 HTML 未转纯文本时,标签可能打断正则
- 繁体:新增預報、轉倉、貼標 — 词表是简体,繁体会漏
10. 扩展新格式时改哪里
不要在详情页临场「理解」一封信。按层改:
| 缺口 | 改 |
|---|---|
| 拉不进来 | 设置页关键词/白名单,或 BUSINESS_TEXT_RE / isBusinessRelevantMail |
| 类型错 | classify.ts 加分 + instruction-lexicon.ts 词表 + 单测 |
| 拆不出卡 | KEYWORD_RULES、切段边界、split-instructions |
| 主题柜头 | bl-plus-template 或 ops-subject-template(先判断像 A 还是 B);未映射标签进 memo_bits → 备注 |
| 正文柜头 | extract-container-header.ts 标签正则;港口 us-ports.ts;船司 carrier-aliases.ts |
| 卡派列名 | packing-list.ts HEADER_ALIASES |
| 贴标表 | label-instruction.ts LABEL_HEADER_ALIASES |
| 转仓 OCR | transfer-instruction-table.ts + 仓码归一 |
| DO 文件名 | do-upload-extract.ts |
| 附件挂段 | match-segment-attachments.ts |
流程:先在本页记下「哪一层缺口」→ 改对应文件 → 补 tests/unit 或 fixtures → pnpm test 相关文件。
11. 结论(给评审用)
当前规则覆盖的是:简体中文 + 固定口头禅 + ISO 柜号 + + 主题模板 + 中英列名接近金样的 xlsx。
对「还没拿到的邮件」:
- 同类客户、换柜号/换船名/换附件内容:一般能覆盖。
- 换一套邮件习惯(英文、繁体、无
+、无「新增预报」、PDF 清单、新仓码、新列名):不能默认覆盖,会按第 9 节某一层失败,需要加词或加模板,而不是调模型。
建议每来一类新失败信:先标失败层(拉取 / 分类 / 拆段 / 柜头 / 表格),再决定是加关键词还是加模板,避免一条超级正则吃所有格式。