| name | quanlaidian-quotation-skill |
| description | 全来店报价技能:当用户需要根据品牌名称、餐饮类型、门店数量、套餐和模块勾选来生成全来店报价单时触发。按运行环境选择采集方式——飞书对话场景用 `feishu_ask_user_question` 消息卡片分轮点选;OpenClaw 等其他平台用原生表单;两者都不可用时进入少打字的引导式对话兜底。最终输出 PDF、Excel 和 JSON 三份报价文件。 |
全来店报价技能
本技能用于把 OpenClaw 业务表单或引导式对话输入转换为全来店标准报价文件。
触发场景
当用户需要以下能力时使用本技能:
- 为餐饮客户按品牌名 / 餐饮类型 / 门店数 / 套餐 / 模块一键出报价单(对客 PDF、内部 Excel、留档 JSON)
- 原生表单未弹出时,用少打字的引导式对话兜底完成报价
输入方式
送给 scripts/quote.py 的都是结构化字段,不是完整报价 JSON;采集路径(飞书卡片 / OpenClaw 原生表单 / 引导式对话兜底)的选择见『工作流程』第 2 步。
核心字段:
- 客户品牌名称
- 餐饮类型
- 门店数量
- 门店套餐
- 门店增值模块
- 总部模块
- 配送中心数量
- 生产加工中心数量
工作流程
- 执行
python3 scripts/update_notice.py。若有输出(说明本节点被 check_openclaw_update.py 升级过且当前版本尚未告知过用户),将其原样作为本次回复的首段 Markdown 展示在用户面前,然后再进入正式报价流程。输出为空则直接跳过,不要刻意提及版本号或脚本细节。
- 按运行环境采集字段:① 飞书环境 → 走『飞书消息卡片采集(飞书环境首选)』;② 其他平台且原生表单已加载 → 走『OpenClaw 原生表单采集(非飞书平台首选)』;③ 两者都不可用 → 进入『引导式对话兜底』。任一路径采集完整即可进入下一步。
- 调用
scripts/quote.py 生成报价文件——产出报价的唯一方式,不得跳过此步在对话里拼装结果(详见『约束』)。
- 在当前工作目录生成三份结果文件
- 在 OpenClaw 对话中返回”报价内容预览 + 文件下载入口”
交互策略
交互原则
- 让用户点选/确认,少打字;一次只问当前缺失的关键字段
- 标准小连锁优先走默认值,不反复确认已明确信息
- 提问尽量短("轻餐还是正餐?"),允许数字 / 中文名称 / 混合方式回复
- 不在生成前单独发"请确认"卡;直接调用 API,再把配置摘要与报价预览一起放进最终回复
- 仅在非标商务条件、复杂联购、≥301 店时提示转人工
飞书消息卡片采集(飞书环境首选)
-
触发条件:运行环境为飞书对话。此场景下不存在 OpenClaw 原生表单,直接走卡片,不要等表单。
-
工具:feishu_ask_user_question。
-
预填跳过规则:若用户首条消息已经明确给出部分字段,Agent 必须把这些字段视为已采集——决策树推导时把这些字段当作输入,不在卡片里重复确认(与上节『交互原则』一致)。"全部字段已知"是触发下文『全通』状态、走单张『推荐方案确认卡』的关键前提;"部分已知"会落到半通/二级软推荐/未全通等其它路径。
-
决策树推导优先(前置必做):调用任何卡片之前,必须用首条消息 + 已知字段静默跑一次决策树(含『行业关键字 → 餐饮类型判定』+『套餐默认决策树』+ 业态推荐表),按下表选路径:
| 状态 | 触发条件 | 路径 |
|---|
| 全通 | 下方『全通判定』6 条全部满足 | 1 张『推荐方案确认卡』→ 出报价 |
| 多档全通 | 用户给出 2–5 个门店数,对各档跑决策树后除门店数外字段完全一致 | 1 张『多档推荐方案确认卡』→ 串行 N 次 API |
| 半通 | 全通仅缺配送/加工数量 | 推荐方案确认卡 + 同卡内追加 question 补问数量 |
| 弱全通 | 全通但业态推荐为空(包子/早餐/无命中等) | 推荐方案确认卡 + question 文案加 ⚠️ 提醒 |
| 二级软推荐 | 餐饮类型只命中二级桶,其它字段已知 | 合并卡:餐饮类型单选(⭐推荐 前缀)+ "假设走推荐类型"前提下的修改多选 |
| 未全通 | 缺关键字段、关键词冲突、三级歧义、用户陈述前后矛盾 | 退到下文『顺序卡兜底』 |
| 拒答 | 门店数 ≥ 301 | 不发卡,回复"上限 300 店,走大客户人工定价通道" |
-
全通判定:全通 = c1 and c2 and c3 and c4 and c5 and c6,6 条全真才算全通:
c1 餐饮类型已定:一级关键词命中,或用户首条消息显式说轻餐/正餐
c2 门店数为精确数字:首条消息给出精确数字(不接受"几十家""上百家"等模糊量词)
c3 门店数 1–300
c4 总部模块状态明确:用户提了 → 按表述;未提 → 当无
c5 若总部模块含 配送中心 或 生产加工,则配送/加工数量已给(否则降级为"半通")
c6 关键词无冲突:不同时命中一级轻餐词和一级正餐词
-
全通只凭首条消息判一次(防折返跑):上述 6 条用首条消息 + 首条已知字段判定,判定时点就是发任何卡片之前那一次。首条消息缺门店数(或缺其它关键字段)即第 2 条不满足 → 直接判「未全通」走『顺序卡兜底』,不要先单独发一张卡补门店数、补完再回头判全通走推荐方案确认卡——那张补门店数的卡本身就是顺序卡兜底·卡片 1,后面直接接卡片 2,不存在"补字段后升级成全通"这条路径。WHY:缺字段补问→又走推荐确认卡,会让用户先答"要不要改总部/增值"再答"改成什么",凭空多一轮折返;而真·全通(首条消息字段已齐)才有"预览+零点击通过"的价值。
-
推荐方案确认卡(全通路径):单卡片,单 question,多选。
question 文案 四要素:品牌名 + 餐饮类型(标注是关键词自动判定还是用户表述)+ 门店数(落入大客户段时显式标注锚点和阶梯对比对)+ 方案摘要 4 行(门店套餐 / 总部模块 / 门店增值模块 / 算法分段)。方案摘要的"门店增值模块"行:业态推荐非空时,即便当前取值为"无"也要内联列出推荐项(如"无 —— 咖啡业态常配 ⭐厨房KDS、⭐叫号取餐,需要请勾下方『✏️ 改 门店增值模块』"),让销售/客户一眼看到可加项,不靠点开才发现。结尾必须含通过指引"无需修改 → 勾『✅ 确认方案』即可出报价(全空提交同样视为通过)";业态推荐非空时再补一句 💡(与下文弱全通 ⚠️ 对称)"💡 已标记 N 项 <业态> 推荐模块(⭐…),需要请勾『✏️ 改 门店增值模块』展开"。
- options:首项为哨兵
✅ 确认方案,直接出报价(description="对以上品牌 / 餐饮类型 / 门店数 / 套餐无异议 → 立即调 API 生成报价单;与下方各『✏️ 改』项互斥,同勾时以『改』为准");其后每个可改字段一个 ✏️ 改 <字段>,description 写当前值 + 改动影响(如"改成正餐会切套餐 SKU"、"勾配送中心会自动切到全能版 + 追加供应链基础-门店点位")。✏️ 改 门店增值模块 的 description 必须列出业态推荐项 + 推荐理由(只写功能/场景、不写价格,遵『卡片设计规则』),如"咖啡业态常配 ⭐厨房KDS(出餐/制作进度)、⭐叫号取餐(排队取餐叫号);勾此展开多选,可加可不加,不展开按『无增值模块』出报价"。门店数也作为可改项。门店套餐不作为可改项——它由『套餐默认决策树』从总部模块自动判定,要换套餐就改总部模块(或在对话里直说要标准版 / 供应链版等非默认套餐),不在卡里单列 改 门店套餐。
- 用户提交语义:
- 勾
✅ 确认方案(或选项全空)→ 直接调 scripts/quote.py 出报价。WHY 双入口:飞书卡片在部分环境下不允许零选择提交,✅ 确认方案 是稳定的显式通过入口,"全空亦通过"仅作兼容兜底。
- 勾了任一
✏️ 改 X(无论是否同勾 ✅ 确认方案,一律以"改"为准)→ 发"修改卡"只问被勾字段,其它保持决策树值;修改卡提交后重新跑决策树,根据新状态再选路径。勾了 改 总部模块 / 改 门店增值模块 时,修改卡即『顺序卡兜底 · 卡片 2』的结构(先问总部模块 + 门店增值模块,门店套餐不在卡内采集、提交后由决策树重算)。
- 弱全通(业态推荐为空)的额外约束:
question 文案必须含 ⚠️ 提醒"未匹配到业态推荐模块,需要加请勾选『改 门店增值模块』",防止销售一路 Enter 把"无增值"当默认通过。弱全通因推荐为空 → 不出上面的 💡 推荐列表,但仍出 ✅ 确认方案 哨兵入口。
-
多档推荐方案确认卡(多档全通路径):单卡片,单 question,多选。
- 触发条件:用户给 2–5 个门店数(如"10/30/100 家"),对各档跑决策树后除门店数外字段完全一致。
question 文案:品牌名 + 餐饮类型 + 档位列表 + 共享方案 3 行(套餐/总部/增值)+ 各档算法分段标注(仅在落入大客户段的档前加锚点说明,如"100 落入大客户段,按 100 店锚点 + 100/200 阶梯对比")。共享方案的增值模块行:各档业态一致且推荐非空时,内联列出 ⭐ 推荐项(如"无 —— 咖啡业态常配 ⭐厨房KDS、⭐叫号取餐")。结尾"无需修改 → 勾『✅ 确认方案』即可串行出 N 套报价文件 + 对话内汇总表(全空提交同样视为通过)"。
- options:首项为哨兵
✅ 确认方案,串行出 N 套(与下方各『✏️ 改…(影响全档)』互斥,同勾时以『改』为准);其后 ✏️ 改 餐饮类型(影响全档) / ✏️ 改 门店套餐(影响全档) / ✏️ 改 总部模块(影响全档) / ✏️ 改 门店增值模块(影响全档) / ✏️ 调整 档位列表。禁止出现 "改第 X 档" 选项 —— 一档需要单独调字段就不是批量对比,退化成 N 张串行单档确认卡。
- 档数硬约束:≥ 2 且 ≤ 5。超过 5 档拒绝合卡,提示销售拆请求。
- 跨 300 上限的档:在
question 文案里显式剔除并告知(如"350 落在 300+ 上限,已剔除;如需 350 店报价请走大客户人工通道"),不让销售提交后才发现。
- 各档套餐或模块不一致:退化成串行单档确认卡,每档 1 张。
- 提交后:按『多档主动对比』串行出 N 套报价文件 + 对话汇总表(每次只改门店数)。
-
半通路径(配送/加工数量缺失):仍发推荐方案确认卡,但同卡内追加 question 2 单选"配送中心数量 1/2/3/4+"或"生产加工数量 1/2/3/4+"(按需)。用户答完数量、其它选项不勾 → 直接出报价,仍是 1 轮卡片 + API。
-
二级软推荐路径:单卡片,两个 question。
- question 1(单选,必答):餐饮类型,推荐项标
⭐推荐(标记机制见『卡片设计规则』)。
- question 2(多选):在"假设走 ⭐推荐 类型"前提下列出"改 套餐/总部/增值"等可改字段,文案点明"假设你选 ⭐推荐 <类型>"。
- 用户答 question 1 后 skill 用最终类型重跑决策树;若与"假设"一致且 question 2 全空,直接出报价。
-
循环保护:max_confirmation_rounds = 2 —— 最多发 2 次推荐方案确认卡(含多档版)。第 2 张确认卡用户仍勾改 → 不再发第 3 张,对话里说明冲突点并退到下文『顺序卡兜底』,或让销售用『引导式对话兜底』节逐字段定调。
-
顺序卡兜底(决策树未全通时使用):
- 适用:缺门店数、餐饮类型三级歧义、关键词冲突、用户陈述前后矛盾、确认卡循环超限。
- 进了顺序卡兜底就走到底:用单卡补完缺失字段后,继续按卡片 1→2→3 往下走,禁止中途切回推荐方案确认卡。例如首条消息缺门店数:单独发的那张"门店数量"卡即卡片 1(品牌已知、餐饮类型一级命中都跳过,只剩门店数),拿到数字后直接发卡片 2 问总部 / 增值模块,不要再插一张"方案摘要 + 改不改"的推荐确认卡。
- 卡片 1 · 客户信息:品牌名(文本输入,
options: [])+ 餐饮类型(单选 轻餐 / 正餐;一级高置信度命中跳过此问,二级软推荐时推荐项标 ⭐推荐)+ 门店数量(文本输入精确数字,options: [],不用档位单选)。卡片 1 上品牌名 / 餐饮类型 / 门店数已知的项逐一跳过,只问真正缺的;三项只缺门店数时,卡片 1 就退化成一张单问门店数的卡。
- 卡片 2 · 产品方案(选项按卡片 1 答案动态组装):先问 总部模块(多选,首项为「无总部模块」,不做业态推荐标记),再问 门店增值模块(多选,首项为「无门店增值模块」,其余按
references/module_candidates.md 短列表;命中业态推荐时推荐项标 ⭐推荐,机制见『卡片设计规则』)。门店套餐不在本卡采集:销售先表态总部/增值业务需求,提交后由『套餐默认决策树』终判,判定结果写进配置摘要并提示"如需改套餐(如标准版 / 供应链版)直接说明即可回退"。先选模块再顺势推出套餐,避免信息不全时先锁套餐。
- 「无…」哨兵首项的互斥标记:总部模块、门店增值模块两个多选的首项(「无总部模块」/「无门店增值模块」)参照 ⭐推荐 的"标记 + 文字"形式,
label 加前缀 🚫『与下方各项互斥,勾此忽略其余勾选』(如 🚫『与下方各项互斥,勾此忽略其余勾选』无总部模块),description 重申"选此项 = 不要该类模块"。飞书卡片点击时拦不住互斥,仍靠下文『卡片答案 → API 字段修正映射』在提交后以「无」为准清空其他勾选;标记只给销售一个提前的视觉提醒。
- 卡片 3 · 配套数量(按需触发,全不命中则跳过):
- 仅当卡片 2 选了
配送中心,问配送中心数量(1 / 2 / 3 / 4+);
- 仅当卡片 2 选了
生产加工,问生产加工中心数量(1 / 2 / 3 / 4+)。
- 顺序卡兜底走完后不再单独发"配置摘要确认"卡,直接调用
scripts/quote.py 出报价。仅当字段冲突无法消歧时才单独追一张"请确认"卡说明问题。
-
卡片设计规则:
- 选项
description 字段是关键,决策树后果、推荐理由必须写在这里。
- 文本在前、卡片在后,且每轮至多一句过渡:同一轮回复里若既有文本说明又要发卡片,先输出文本、最后才发卡片(卡片是这轮的收尾动作)。过渡文本最多一句,点明"接下来选什么"即可(如"轻餐已确认,接下来选总部模块和门店增值模块 👇"),紧贴卡片上方。禁止为同一张卡连发多条重复旁白(如先"好的轻餐+11店"、再"现在走顺序卡流程"、再"请选择总部和增值模块"三条说一件事);也不要在卡片之后再补一段解释卡片怎么填。WHY:卡片渲染在文本下方,文本啰嗦或排在卡片后面会把操作入口挤走、读起来像系统在自言自语。
- 禁止在任何卡片文案出现价格信息:
label / description / question 任一处都不得写具体金额(如 ¥39,000/个/年、2600元/店/年)、单价、折扣率或任何计价单位(X元/店/年、X/个/年 等);description 只描述功能 / 适用场景。此规则适用于全部卡片路径(推荐方案确认卡 / 多档卡 / 二级软推荐 / 顺序卡兜底)。价格统一由 API 返回后在最终配置摘要中展示,避免卡片层与 API 报价口径不一致,也避免泄露内部标价。
- 门店数字段经卡片采集后不再二次追问:卡片 1 拿到精确数字即视为采集完成(31–300 段锚点折算由 API 处理,见『大客户段』),禁止追发第二张"准确门店数"卡。
- 单卡片 ≤ 6 个问题;总部模块选项控制在 4–5 项内,门店增值模块控制在 6 项内。
- 卡片不支持动态显隐,必须用多轮 + 动态组装解决,不要把所有可能字段塞进一张卡。
feishu_ask_user_question 不支持预设默认勾选:所有多选/单选都以未勾选状态发出。要让某个选项"看起来被推荐",只能在 label 加 ⭐推荐 前缀 + description 写推荐理由,并在 question 文案里点名"已标记 N 项推荐,请勾选"。禁止在卡片外文字声称"已为你预选 / 已默认勾上"——卡片里没勾就是没勾,措辞与实际渲染必须一致。
- 校验逻辑放在 Agent 端收到答案后执行,不要塞进卡片。
✅ 确认方案 哨兵:全通 / 多档 / 半通确认卡的显式通过入口,按互斥哨兵处理(同「无…」)——飞书点击拦不住互斥,提交后由 Agent 判定,同勾任一 ✏️ 改 项时以"改"为准。它是流程信号、非 API 字段,不进『卡片答案 → API 字段修正映射』表、不作为表单字段发给 scripts/quote.py。
-
卡片答案 → API 字段修正映射:
| 输入组合 | 自动修正 |
|---|
选了 配送中心 / 生产加工,但门店套餐选了 旗舰版 | 修正为 全能版,摘要标注「为承接总部配送/生产加工自动修正」 |
选了 配送中心 / 生产加工,门店增值模块未选 | 自动追加 供应链基础-门店点位 |
| 门店数 31–300(精确数字) | 走大客户段(large-segment-v1),按下文『大客户段(31–300 店)处理规则』执行;不再二次追问精确数字 |
| 总部模块同时勾「无总部模块」+ 其他项 | 以「无」为准,清空其他勾选;摘要标注「按『无总部模块』处理,其他勾选已忽略」 |
| 门店增值模块同时勾「无门店增值模块」+ 其他项 | 以「无」为准,清空其他勾选;摘要标注「按『无门店增值模块』处理,其他勾选已忽略」 |
-
上表「配送/生产→全能版」「追加门店点位」「『无』哨兵清空」三条执行态以 tests/rules.py 为准。
-
字段中文名映射 API 参数:参考 references/openclaw_form_submission.example.json。
-
采集完成后调用 python3 scripts/quote.py --form <JSON字符串> 生成报价文件。
-
回退:feishu_ask_user_question 接口报错 / 用户在卡片里明确要求改用对话 → 直接退到下文『引导式对话兜底』。飞书场景不会回退到原生表单(飞书没有原生表单)。
OpenClaw 原生表单采集(非飞书平台首选)
- 触发条件:运行环境为 OpenClaw Web、IDE 集成或其他非飞书平台,且原生表单已加载。
- 若 OpenClaw 已展示原生表单,直接引导用户填写表单
references/openclaw_form_schema.json 与 references/openclaw_form_config.json 可作为字段参考,但如果平台未自动加载,不要卡住流程
- 原生表单的「无总部模块」「无门店增值模块」是互斥哨兵首项:schema 已用字段级
none_option.exclusive 声明,渲染层在点击时即清空其他勾选、勾其他模块即取消「无…」,无需等到提交后修正(契约见 schema 的 none_option)
- 原生表单在飞书环境下不会出现,所以非飞书平台无需 fallback 到飞书卡片;若表单缺位,直接退到『引导式对话兜底』。
行业关键字 → 餐饮类型判定(三级策略,优先级高于"问轻餐还是正餐")
按 references/dining_type_keywords.md 三级策略对品牌名 + 用户首条消息做一次匹配(大小写不敏感,中英文混排都要命中,如"国际化 Coffee"应命中 coffee):
- 一级(高置信度) → 直接把
餐饮类型 自动设为对应值,跳过"轻餐还是正餐?"这一问(卡片 1 不显示该单选;兜底对话直接跳过步骤 2)。在最终回复里的配置摘要中显式标注"已根据关键词 <词> 自动判定为 <类型>,如需修改请回退",给用户一次校对机会。
- 二级(软推荐) → 不自动设定,但在卡片里给推荐选项标
⭐推荐(机制见『卡片设计规则』);对话兜底场景按模板一句话确认。
- 三级(歧义) → 必须显式追问,不要猜。
禁止:对已经命中一级关键词的输入再追问"轻餐还是正餐?"——这是过度提问。例如品牌名含 Coffee / 咖啡 / 奶茶 / 火锅 等,直接自动判定,把确认动作并入最终回复的配置摘要。
引导式对话兜底(卡片/表单都不可用时)
路径对照 —— 卡片/表单均不可用时走下方 8 步逐字段对话。卡片化路径见上节『飞书消息卡片采集(飞书环境首选)』,覆盖相同字段:全通走 1 张推荐方案确认卡,未全通退化为顺序卡 1→2→3。两条路径都不再单独发"配置摘要确认"卡(见『交互原则』)。
按以下顺序逐步收集,优先给用户选项:
- 客户品牌名称
- 餐饮类型:
轻餐 / 正餐(先走上节『行业关键字 → 餐饮类型判定(三级策略)』:一级高置信度命中直接跳过此步、并在最终摘要里展示自动判定结果;二级软推荐用户一键确认;三级歧义或无命中时才让用户单选)
- 门店数量:优先让用户直接输入数字
- 门店套餐:若用户已指定就用指定值;未指定时暂不锁定,等步骤 6 收完总部模块后按下一节『套餐默认决策树』终判
- 门店增值模块:根据餐饮类型给出可多选的候选项;若品牌名/首条消息命中具体子业态,按
references/module_candidates.md 末节『业态 → 门店增值模块推荐映射』把对应模块作为推荐项呈现给销售(兜底对话里可以直接代勾:"按 <子业态> 给你勾上 <模块A>、<模块B>,有需要去掉的直接说";卡片路径则标 ⭐推荐,见『卡片设计规则』)
- 总部模块:给出可多选候选项
- 若选择了
配送中心,再追问配送中心数量
- 若选择了
生产加工,再追问生产加工中心数量
套餐默认决策树(1–300 店全段;门店套餐 API 必填,不可留空)
if 总部模块 为空:
门店套餐 = 餐饮类型对应『营销旗舰版』 # 含单门店库存;档位→全称见下方映射表
elif 总部模块 含 配送中心 或 生产加工:
门店套餐 = 餐饮类型对应『营销全能版』 # 档位→全称见下方映射表
门店增值模块 += 供应链基础-门店点位 # 承接收货;摘要标注"为承接配送/生产加工自动追加"
档位 → API 门店套餐 全称映射(落 payload 前必须查此表换成全称):
| 档位 | 正餐 | 轻餐 |
|---|
| 标准版 | 正餐连锁标准版 | 轻餐连锁标准版 |
| 营销基础版 | 正餐连锁营销基础版 | 轻餐连锁营销基础版 |
| 营销全能版 | 正餐连锁营销全能版 | 轻餐连锁营销全能版 |
| 营销旗舰版 | 正餐连锁营销旗舰版 | 轻餐连锁营销旗舰版 |
| 供应链版 | 正餐连锁供应链版 | 轻餐连锁供应链版 |
门店套餐 字段必须用上表全称,禁止用「正餐旗舰版」之类「餐饮类型+档位」简称拼接。决策树/卡片里的「旗舰版」「全能版」只是档位代号,落到 API payload 前先查表换成全称。WHY:API 只认全称,简称少了「连锁营销」会直接 400,触发多余的查表重试往返。
- 不要默认到「旗舰版 + 配送中心」:
单门店库存 与 供应链基础-门店点位 是互斥业务路线,service 端 400 拒。
- 不要默认到
供应链版(ZC-05 / QC-05):会丢「会员营销」;仅当销售明确"客户不要会员营销"才手动切。
- 未提门店增值模块 / 总部模块时按"不选"处理,最终摘要中显式展示。
- 执行态以
tests/rules.py 为准(本块与『卡片答案 → API 字段修正映射』须与其一致)。
卡片场景下的选项呈现: 通过 feishu_ask_user_question 让用户选门店套餐时,把上述决策树后果写进选项 description:
label="全能版",description="含总部管理 + 供应链,适合配送/加工中心场景;若选了配送中心或生产加工,系统会自动匹配此版本"
label="旗舰版",description="标准功能,不含总部模块;总部模块为空时默认推荐"
模块候选项
- 门店增值模块:按餐饮类型给出对话候选短列表,详见
references/module_candidates.md
- 门店增值模块业态推荐:当品牌名/首条消息命中具体子业态(茶饮/快餐/火锅/酒楼……)时,按
references/module_candidates.md 末节『业态 → 门店增值模块推荐映射』把对应模块作为推荐项呈现——飞书卡片路径标 ⭐推荐(机制见『卡片设计规则』);引导式对话兜底路径可以代销售先把推荐模块勾上,销售明确取消才撤回。推荐范围仅命中 SKU 化模块(如 厨房KDS、叫号取餐、宴秘书标准版套餐、晓食菜单(固定模版) 等);套餐内置功能和无 SKU 的硬件不出现在推荐里。
- 总部模块:通用项 + 餐饮类型特定附加项,详见同一文件;不做业态推荐标记(依赖客户是否自建中央厨房/配送中心,提前标记会破坏套餐默认决策树)
- 完整 SKU、价格、套餐说明以
references/product_catalog.md 为准
大客户段(31–300 店)处理规则
-
31–300 店直接调用 API,不要在客户端拦截或改写。API 会按下锚点(50 / 100 / 200 / 300)生成主报价单,并在文件里附带"夹住输入值的两档阶梯对比页"。
-
夹住规则(区间查表):
| 输入 N | 阶梯对比对 |
|---|
| 30 ≤ N < 50 | [30, 50] |
| 50 ≤ N < 100 | [50, 100] |
| 100 ≤ N < 200 | [100, 200] |
| 200 ≤ N ≤ 300 | [200, 300] |
-
当响应里 pricing_info.algorithm_version == "large-segment-v1"(或 preview.stores 与用户输入的 门店数量 不一致)时,必须在对话回复里显式说明:"你填了 N 店(落在大客户段),主报价按 M 店方案生成,随单附 M / M' 两档阶梯对比表",不要让客户误以为这就是 N 店的原生报价。
-
301+ 店:API 会返 422,skill 回复 "系统当前上限 300 店,超出需走大客户人工定价通道,请联系销管"。禁止给出任何估算数字。
-
大客户段同样适用上节『套餐默认决策树』。门店套餐 是 API 必填字段,任何分段都不允许留空。
-
锚点/分段的执行态以 tests/rules.py 的 segment 分类为准。
多档主动对比(任意门店数对比)
- 当用户明确要多个门店数(例如 10 / 20 / 30 或 50 / 100 / 200)一起对比时:串行调用
scripts/quote.py 多次,每次只改 门店数量,其余字段保持一致。
- 飞书场景下,多档对比由上节『多档推荐方案确认卡(多档全通路径)』承载——一张卡片展示档位列表 + 共享方案 + 各档算法分段,用户确认后再串行调 API;各档字段不一致或超过 5 档时按该节规则退化。
- 每次调用拿到的就是该档对应的主报价单(≥31 店段还会附 API 自动给的相邻两档对比页);skill 侧不做 PDF 合并,只在对话回复里用一张汇总表并排展示各档的总价与单店均价,并给出对应的文件下载链接。
输出结果
对话输出格式(预览 + 3 文件下载入口 + PDF 对话直接发送)见下节『OpenClaw 对话输出规范』。
默认文件输出:
品牌名-全来店-报价配置-YYYYMMDD.json
品牌名-全来店-报价单-YYYYMMDD.pdf
品牌名-全来店-报价单-YYYYMMDD.xlsx
用途说明:
- PDF:对外发送客户,同时在对话中直接发送文件附件
- Excel:内部调整与复核,同时在对话中直接发送文件附件
- JSON:内部留档与再次生成
读取参考资料
必要时读取以下文件:
references/product_catalog.md(完整 SKU 与对客标准价)
references/sales_guide.md
references/dining_type_keywords.md(行业关键字 → 餐饮类型软推荐)
references/module_candidates.md(对话场景下的模块推荐候选短列表)
references/openclaw_form_schema.json
references/openclaw_form_config.json
调用脚本
生成完整报价文件:
python3 scripts/quote.py --form <submitted-json>
- payload 字段 key 的唯一来源:构建
--form JSON 时,字段 key 必须与 references/openclaw_form_schema.json 的 fields[].key 完全一致(可直接照抄 references/openclaw_form_submission.example.json 的 key),不要用口语缩写——品牌字段是 客户品牌名称,不是「品牌名称」。
- 调用脚本属内部机制,不要在对话里描述过程:写临时 JSON 文件、
--form 路径、字段名纠错、重试等都属内部步骤,一律不输出到对话;对话只给最终的报价预览 + 下载入口(见『OpenClaw 对话输出规范』)。
OpenClaw 对话输出规范
生成报价文件后,必须在对话中同时返回以下两类结果:
- 报价内容预览(直接可读)
- 使用清晰的小结展示关键字段,例如:品牌名称、餐饮类型、门店数量、门店套餐、总部模块。
- 至少给出“本次配置摘要 + 主要费用项”两部分,避免只返回“已生成成功”。
- 预览段落末尾应提示:PDF/Excel 中包含所选套餐的『套餐说明』以及底部『权益类』附加条款(小程序验证次数 / 外卖接单费用),文本来源为
references/product_catalog.md。
- 互斥 / 自动修正说明必须醒目:触发字段修正(互斥哨兵清空、配送/加工自动切套餐、自动追加门店点位等)时,抽成
> ⚠️ 配置已自动调整 引用块紧贴配置摘要下方,逐条列被忽略/改写的勾选并加粗关键词,不要混在正文里。口径同『卡片答案 → API 字段修正映射』表。
- 文件下载入口(直接可点)
- 在对话中给出 3 个文件的可下载链接或可点击文件引用:PDF、Excel、JSON。
- 链接文字应明确区分文件类型,例如:
下载报价单 PDF、下载报价单 Excel、下载报价配置 JSON。
- 如果运行环境不支持超链接,至少返回完整文件路径,保证用户可以在对话中直接拿到文件位置。
- 链接整段原样照抄:把
scripts/quote.py 输出的链接整段复制进回复,勿缩写、加省略号(…)或凭记忆补全;不确定时重跑脚本取原值。
- WHY:
url 可能是后端短链(不含签名,访问时由后端 302 重定向到实时签名),也可能是 OSS 长签名直链——取决于后端是否启用短链(QUOTE_ENABLE_SHORTLINK,默认启用)。长签名直链含高熵随机串,LLM 极易逐字符抄错导致 SignatureDoesNotMatch;故无论链接长短都必须整段照抄,抄错一个字符就指向错文件或直接失效。
- PDF 与 Excel 文件直接发送到对话
- 调用报价脚本生成文件后,从输出中提取两条链接:PDF(
result["files"]["pdf"]["url"])、Excel(result["files"]["xlsx"]["url"]),分别用 curl -L -o /tmp/<品牌名>-全来店-报价单.pdf "<PDF URL>"、curl -L -o /tmp/<品牌名>-全来店-报价单.xlsx "<Excel URL>" 下载到本地。
- 发送顺序:先发卡片(报价摘要),再发文件附件。卡片提供视觉概览和下载按钮,文件附件作为补充材料随后发送。
- 使用
message 工具(action=send、channel=feishu、card=...)先发送报价卡片;再使用 message 工具(action=send、channel=feishu、filePath、caption)分别发送 PDF 和 Excel 文件到当前对话;PDF 的 caption 用 📄 <品牌名>-全来店-报价单.pdf,Excel 的 caption 用 📊 <品牌名>-全来店-报价单.xlsx。
- 不阻塞流程,逐个文件独立处理:任一文件下载失败、发送失败、或当前环境(非飞书)不支持附件发送,静默跳过该文件,仍按第 2 步返回 3 个下载链接作为 fallback,不报错、不中断;某个文件失败不影响另一个文件的发送。
- ⚠️ 飞书消息工具一次只能发送一个附件:
message 工具的 filePath 参数只接受单个文件路径,同时传入多个文件会只发第一个。PDF、Excel 须分开发送——先发卡,再发 PDF,再发 Excel,共 3 条独立消息。禁止把多个文件放入同一条 message 调用试图一次发送。
- 注意:
curl -L 必须带 -L 跟进短链 302 重定向(不加 -L 会把 302 响应体存成文件);文件命名固定用 品牌名-全来店-报价单.pdf 与 品牌名-全来店-报价单.xlsx。
- 报价利润评估(内部,自动输出)
scripts/quote.py 在输出末尾自动追加『报价利润评估(内部)』区块:汇总(报价/成本/利润总额、利润率)+ 逐项成本利润表。数据来自 files.json.url 下载的报价配置 JSON(result 不含财务字段),由脚本下载渲染,无需 Agent 介入。
- 下载/解析失败时静默跳过该区块,不阻塞主报价输出。
- 此为内部毛利数据:当前报价能力未对外开放,全部视为内部场景。若未来开放对客,必须剥离此区块——与本节『约束』里「对外只展示
totals.final、不展示标价/折扣率」一致。
报价输出推荐模板(飞书交互卡片)
飞书环境下,报价输出使用 飞书交互卡片(而非纯 Markdown),以获得更好的视觉效果:蓝色主题面板、可点击下载按钮、无灰色背景问题。
scripts/quote.py 输出的是原始材料(文本段落),Agent 须提取其中的数据并按以下卡片 JSON 模板组装为 message 工具的 card 参数发出。
卡片 JSON 模板
{
"header": {
"title": {"tag": "plain_text", "content": "📋 {品牌} · 报价单"},
"template": "blue"
},
"elements": [
{"tag": "div", "text": {"tag": "lark_md", "content": "**🏷️ 品牌** {品牌} **🍽️ 类型** {类型}\n**🏪 门店** {门店数} 店 **📦 套餐** {套餐}\n**💰 总价** **¥{total}**"}},
{"tag": "hr"},
{"tag": "div", "text": {"tag": "lark_md"
说明:模板中的 "hidden": true 元素(自动修正 ⚠️ 块)在未触发修正时设为 true 不显示;触发修正时改为 false 或删除该字段使其显示。
卡片填充规则
- header.template:固定
"blue"(深蓝底白字),保持专业感
- 判定来源:在
🍽️ 类型 中附加,如 轻餐(已根据关键词「咖啡」自动判定) 或 轻餐(用户选择)
- 自动修正 ⚠️ 块:触发互斥哨兵清空/配送加工自动切套餐/自动追加门店点位时,将
"hidden": true 改为 "hidden": false;修正条目如「按无门店增值模块处理,其他勾选已忽略」「为承接配送/生产加工自动切换为全能版」
- 费用明细:每个计费项目一段。多档对比时在卡片正文用列表平铺多个条目(品牌 / 门店数 / 套餐 / 总价 / 单店均价)
- 下载按钮 URL:直接使用
quote.py 输出的裸 URL(整段照抄),不要做任何 URL 变换
- 内部利润评估:分隔到独立段落,使用
\n 换行分隔报价/成本/利润行
- 非飞书环境(OpenClaw Web、Discord 等不支持 card 的平台):退回到纯 Markdown 摘要 + 3 个下载链接(裸 URL,见第 2 节)
- 费用明细行:每个计费项目一行。多档对比时平铺汇总表(品牌 / 门店数 / 套餐 / 总价 / 单店均价)
- 下载链接:直接写
quote.py 输出的裸 URL(整段照抄),不要用 Markdown [text](url) 包裹——LLM 极易在 [...](...) 的括号内抄错字符。前置 emoji 和文件类型标注(📄 / 📊 / 📋)即可
- 链接有效期提示:
⏱ 链接有效期 7 天,紧随下载文件区块下方,保持与模板一致
- 利润评估:使用分隔线包裹标题行(
━━━…💰 内部 · 利润评估━━━…),与费用明细视觉隔离
Agent 的任何报价回复在发出之前,必须逐项对照下表自查,缺一项就不准发出。
此自查属内部动作,不要输出给用户:检查表勾选过程(如「✅ 配置摘要 ✅ 费用项表格 ✅ 报价利润评估…」)、「核对检查表」「已全部齐备」等元话术一律不写进对话;对话里只给组装好的最终报价回复。口径同上文「调用脚本属内部机制,不要在对话里描述过程」。
| # | 区块 | 来源 | 必填? | 遗漏后果 |
|---|
| 1 | 本次配置摘要(品牌/餐饮类型/门店数/套餐/总价) | quote.py 输出首段 | ✅ | 用户看不到是什么方案的报价 |
| 2 | 主要费用项表格(逐项列数量和价格) | quote.py 输出 ## 本次配置摘要 下方信息 | ✅ | 用户不知道钱花在哪 |
| 3 | PDF / Excel 已直接发送本对话提示(飞书环境) | 文件发送成功后补充 | ✅(飞书) | 用户不知道去找文件 |
| 4 | 3 个文件下载链接(PDF / Excel / JSON) | quote.py 输出的 ## 下载文件 区块,整段照抄 | ✅ | 用户拿不到文件 |
| 5 | 报价利润评估(内部) — 总金额 + 利润率 + 逐项表 | quote.py 输出的 ## 报价利润评估(内部) 区块 | ✅ | 内部同事看不到毛利数据 |
| 6 | ⚠️ 配置已自动调整(仅触发时) | 互斥哨兵清空/配送切套餐/自动追加门店点位时 | 条件必填 | 用户以为系统出错 |
| 7 | 链接有效期提示:「⏱ 链接有效期 7 天」 | 统一加在下载入口下方 | ✅ | 文件过期用户不知道怎么处理 |
发出前自问 3 条(任何一条不满足 → 不发出,先回去补上):
- 我是否逐字段检查了上面 7 行?
- 报价利润评估的逐项表格我直接用了
quote.py 的输出,还是自己手写的?→ 只能用脚本输出,手写=伪造
- 下载链接是整段照抄还是只抄了前几个字符?→ 必须整段,差一个字符文件失效
注意:scripts/quote.py 输出的是原始材料。Agent 须把这些原始段落按上节『报价输出推荐模板(飞书交互卡片)』组装进最终的对话回复中(飞书环境走卡片,非飞书环境走纯 Markdown 摘要),不能直接贴原始输出也不能跳过某些段落。
失败时返回规则:
- 若生成失败,先用一句话说明失败原因,再给出可执行的修复建议。
- 不允许只返回堆栈信息。
- 若失败原因是飞书卡片接口异常或原生表单未出现,不要要求用户重新安装或重新触发,直接降级到引导式对话继续完成报价。
约束(最高优先级,覆盖一切)
强制 API 调用
- 生成报价单的唯一路径是
scripts/quote.py(内部调用全来店报价 API):任何 PDF / Excel / JSON 报价文件、对话里的任何价格数字,都必须来自该脚本的真实返回值。禁止用模板拼接、本地估算、历史经验、记忆中的价格表伪造;口头给价但实际未调用脚本,等同伪造,明确禁止。
- API 返回字段(
preview、pricing_info、totals.final 等)是价格信息的唯一来源,逐字段透传、不二次加工;禁止任何形式的折扣率外推 / 推演 / 估算(skill 不持有因子表、不本地算折扣,只从 result["preview"] / result["pricing_info"] 透传)。用户问"50 店大概多少"就调 API;API 不支持就说不支持,不编数字。
- 对外只展示最终价
totals.final,不展示标价(list price)、不展示折扣率;totals.list 仅供内部校对 / 毛利分析,不进客户可见渲染。
- API 调用失败(429 / 5xx / 网络 / 超时 / 参数被拒):如实告知失败原因和可重试动作,绝不回退到本地生成或估算。
- API 返回业务冲突(如套餐与模块互斥):优先按本 SKILL 决策树自动修正后重新调用 API,仅在决策树无法消歧时再追问用户——决策树能定的不要把选择题甩给用户。
其他约束
- 报价单抬头仅展示品牌名称;本期不包含硬件报价。
- 门店数 ≥ 301:回复"系统上限 300 店,超出请走大客户人工定价通道",不允许给任何估算数字或折扣推测(机制见『大客户段(31–300 店)处理规则』)。
- 配置或依赖异常时,优先返回清晰错误,不静默失败。