7.5 KiB
产品规则:邮件指令识别与拆分(锁定口径)
地位:本页为指令「怎么认、怎么拆、谁可确认」的产品真源之一。
实现真源:src/services/parse/instruction-lexicon.ts、split-instructions.ts、classify.ts。
约束:解析链路禁止依赖 LLM / Cursor 临场理解;改规则先改本页 + 词表 + 单测。
日期:2026-08-03
0. 一句话
主题与正文都重要、要分开用;一封多轮邮件里只有最新一轮指令可确认;标准四类走业务表单,非标准/软词走「客户指令」;同线程后续回复按新 UID再拉,不重做旧信。
1. 信号源(三者并列,来源可区分)
| 信号源 | 用途 | UI 来源标签 |
|---|---|---|
| 主题 | 柜号/提单/ETA/「新增预报」「DO请查收」等;可单独成指令单元 | 来自主题 |
| 正文 | 按时间轮/转发标签拆段;决定「当前可确认」 | 来自当前正文 / 来自历史引用 |
| 附件名 | 补 DO / 贴标清单等;不能仅凭正文「DO也同步上传」造空上传 DO | 来自附件名 |
冲突原则:
- 正文最新段已是硬工单(换标/覆盖贴/贴标/拍照/拦截等)→ 压过主题链路上历史「新增预报」。
- 同线程主题未变(仅 Re:/Fw: 前缀变化)时:后续轮次只认该时段正文,不得再用首封主题「新增预报」造当前/补缺预报卡;QQ 转发壳剥壳后的主题残片也不算指令。
- 主题有、正文完全无指令时 → 才可用主题补缺(只读或非当前)。
- 正文已覆盖同类型 → 主题不再重复出一张一样的卡。
- 正文写「DO 也同步上传」但本封无真实 DO 附件 → 不出空的上传 DO 指令。
2. 标准四类业务 ↔ UI
| UI kind | 典型关键词(见词表) | 确认动作 |
|---|---|---|
forecast |
新增预报、请查收新增预报 | 预报表单(人工确认) |
transfer |
新增转仓、转仓(「不转仓」除外) | 批量转仓 / 到仓后降级工单 |
work_order |
贴标/换标/覆盖贴/操作指令、拍照、指令性拦截、快递单号;mail1 仅柜号+预约码 | 客户留言 SaveForm(人工确认) |
do_upload |
DO请查收;或真实 *DO*.pdf 等 |
上传 DO(人工确认) |
主流程四类均需人工确认,不因主题残留「新增预报」自动再写 CC。
渠道件数 ≠ 整票指令:主题里的
拦截-209件/FedEx-29件只是渠道汇总;整票真实指令以「拆柜清单更新 / 派送要求」为准。禁止把渠道名写成备注「邮件动作:拦截」。
3. 客户指令(非标准 / 软词)
下列不硬套工单表单,归 customer_instruction(只读展示轮次/正文):
- 更新派送单
- 改自提 / 改为仓库自提 / 仓库自提
- 拆柜清单 / 卡转海 / 派送要求
- 按照正常预报接受、帮忙安排派单、安排派单
- 继续暂存 / 暂存等后续
- 有实质内容但无法归入标准四类的段落
4. 多轮线程拆分与「仅最新可确认」
4.1 如何切开
正文按下列边界切段(保留分隔标签到后一段,便于取时间/发件人):
在 yyyy-mm-dd … 写道/On … wrote:原始邮件/转发的邮件/Original Message/Original:- 发件人+发送时间 等邮件头块
不用单独的 Dear 作为切段点(避免同轮内误切)。
4.2 可确认范围
| 段 | isCurrent |
操作 |
|---|---|---|
| 最新一条有实质指令的段 | true |
可确认提交 |
| 更早的引用轮次(标准四类) | false |
只读(如历史预报) |
| 更早的软词「客户指令」 | false |
独立时间轮要出卡:按正常预报接受 / 仓库「好的」 / 无法接收;仅丢掉无时间轮的「更新派送单」噪声 |
| 纯主题补缺单元 | 一般为 false |
只读展示线索 |
同轮内允许多种 UI 并存(例如当前换标 + 历史预报只读)。
work_order_actions 仅含「转仓」、或正文已拆出转仓/预报等标准单元时,不得再补一张工单卡。
历史引用若正文指令相同(同线程连转同一份「拦截 + 改自提」等,仅抄送折行不同)→ 只保留最新一条,禁止出 2/3/4 张一样的工单卡。
工单备注须列出本段全部动作:硬词(拦截/贴标)与软词(改自提)并存时都写入「邮件动作」,不得只留拦截。
4.3 跳过 vs 仍展示的轮次
- 跳过(不出卡):QQ 转发壳、
发自我的iPhone、空的Original:、主题残片 - 仍按时间轮出卡(只读、不可确认):仓库 ACK「好的 / 收到」;「无法接收 / 产能有限」;「按照正常预报接受 / 安排派单」
- 同轮内
====分组(如换标 334 件两段 FBA)不切开,仍是这一轮一条工单
5. 同线程后续指令(拉取幂等)
| 情况 | 行为 |
|---|---|
| 客户在同主题下新回复(新 IMAP UID) | 会拉:新邮件入库、重新拆段;仅最新段可确认 |
| 已入库的旧 UID | 不再拉(knownUids / messageId / rawHash 幂等) |
超出 IMAP_LOOKBACK_DAYS(默认 3 天)的过旧回复 |
可能拉不到 |
| 新回复未过过滤规则 | 记拉取日志为跳过,不进业务列表 |
旧邮件保持原状态;不会因新回复自动把旧预报/旧工单再执行一遍。
6. 柜头 / 预报相关(与指令并存)
- 提拆派:预报时
F_OperationType=0表示提拆派服务包,不是三个独立管理端「提柜/拆柜/派送」界面。 - mail1 类(仅柜号+预约码、无标准关键词):
classify→WORK_ORDER;详情用work_order_actions补当前工单单元(见extractMailInstructions({ workOrderActions }))。 - 模板表尾「注意:…」是填写说明,不是货件行。
- 卡派清单列:附件有则填;UI 隐藏整列皆空的 FormOrder 列,避免满屏「-」。
- 工单留言内容:取当前指令段,并从
Dear/原箱号起,去掉转发头;禁止用整封线程正文盖住分段留言。
7. 实现与测试对照表
| 规则 | 代码 | 单测(示例) |
|---|---|---|
| 词表 / 软硬分流 | instruction-lexicon.ts |
mail4-time-rounds.test.ts |
| 拆段 / 最新可确认 / 主题补缺 | split-instructions.ts |
split-instructions.test.ts、mail4-time-rounds |
| 正文硬工单压过主题预报 | classify.ts |
classify.test.ts、instruction-product-rules |
| 线程拆单(Message 级) | thread.ts + poller |
thread.test.ts |
| UID 幂等拉取 | poller.ts knownUids |
集成/烟雾 |
| 空 DO 不出指令 | split-instructions + do-upload-extract |
mail4-time-rounds、do-upload-extract |
| 工单留言清洗 | CcWorkOrderForm extractWorkOrderMessageBody |
four-business.test.ts |
改口径流程:改本页 → 改词表/拆分 → 改/补单测 → pnpm test 相关文件通过。
8. 与旧文档关系
docx/需求规格-邮件自动预报-v0.2.md§4 类型打分仍有效;本页补充「拆分 / 客户指令 / 主题正文分工 / 仅最新确认」。- 若与旧表述冲突,以本页 + 上述实现文件为准,并回写需求规格对应章节。
- Cursor 对话纪要不是运行时真源。