营销专家 API · 优化定义(目标态 v2)
给 Agent 使用的营销专家 API 目标态定义。v2 相比 v1 的关键改进(来自实现回评): ① 折扣收敛为带判别式的
discount子对象;② 活动类型(场景) 与 优惠机制 解耦(修 v1「类型既是场景又是机制」的自相矛盾);③activity-types+member-tags合并为meta/capabilities;④ 写操作补Idempotency-Key;⑤available_actions补disabled_reason。 设计目标:Agent 能确定性把口语映射到端点+参数,prompt 尽量精简(可枚举映射全下沉到参数/词库,不进 prompt)。 约定:前缀/pos/ai/v1;时间 13 位 epoch ms(UTC+4);金额Money对象。与现网契约2026-06-10-aigent-AI对接说明(2).md的差异见末尾「迁移对照」。
1. 端点总览(共享 3 + 活动 4 + 会员 3 = 10)
端点收敛原则(本轮 review 核心):端点选择 + 参数匹配由消费侧确定性纯函数完成 —— 不进 prompt、不靠 LLM 选,所以端点数与 prompt 长度/准确性解耦(prompt 恒 0 端点)。因此「减端点」只合真冗余:所有危险写收成一对共享
marketing:preview/commit(kind由消费侧确定性设置);而list/detail/products等读端点形态各异,不强合(合了变多态汤、不增准确性)。 演进:v1 13 → v2 12(capabilities 合一)→ v2.1 10(危险写三对 preview/commit → 一对共享)。
共享(能力 + 危险写)
| 端点 | 用途 |
|---|---|
GET /marketing/capabilities | 一次取全:活动场景 + 优惠机制 + 会员标签 + 限制(合法值不进 prompt) |
POST /marketing:preview | 所有危险写预演:kind(CAMPAIGN/MEMBER_TAG/MEMBER_DELETE) + payload → 配置卡 + preview_token |
POST /marketing:commit | 确认执行:preview_token + Idempotency-Key;kind 由消费侧确定性设置(非 LLM 猜) |
活动域(读 + 生命周期)
| 端点 | 用途 |
|---|---|
GET /campaigns | 活动列表(过滤/排序/投影,消歧用) |
GET /campaigns/{id} | 活动详情(含复盘 + 可执行动作) |
POST /campaigns/{id}:action | 生命周期合一(pause/resume/terminate/withdraw + Idempotency-Key + 状态机) |
GET /products | 选品(秒杀建活动用) |
会员域(读 + 直接写)
| 端点 | 用途 |
|---|---|
POST /members:filter | 4 维筛选 |
POST /members | 新增会员(直接写,非两段确认) |
POST /members:import | 批量导入(逐行部分成功,直接写) |
建活动 / 打移标签 / 删会员的危险写统一走共享
marketing:preview→commit(kind=CAMPAIGN/MEMBER_TAG/MEMBER_DELETE);导出(数据侧)同样可挂kind=EXPORT,全平台危险写收成一对。生命周期:action是即时状态机、非两段确认,单列;新增/导入是直接写,不走 preview。
2. 公共约定
2.1 响应外壳
{ api_version, code(0=成功), message, data, error };失败回真实 HTTP 状态 + error{error_code,category,retriable,details}。
2.2 金额 Money
{ amount, currency:"AED", minor_unit:2 }(裸值禁用)。
2.3 危险写 preview → commit + 幂等
:preview 出配置卡 + preview_token给用户确认 → :commit 执行。
preview_token一次性、10min;commit 校验门店绑定(跨店→AIGENT_TOKEN_SCOPE_MISMATCH)。commit/:action/标签/删除等写操作带Idempotency-Key头:网络重试/重复点不会重复发布/重复终止(同 key TTL 内返同一结果)。
2.4 活动类型(场景) × 优惠机制(核心:v2 解耦)
v1 把"机制"焊进类型名(FIXED_AMOUNT_OFF/WHOLE_ORDER_PERCENT),又让首单能 percent 或 amount,自相矛盾。v2 拆成两个正交维度:
activity_type(场景 / 对谁)
| code | 含义 |
|---|---|
WHOLE_ORDER | 全场活动(所有顾客) |
FIRST_ORDER | 首单优惠(新客,长期有效) |
FLASH | 秒杀(限时低价,需选品) |
discount(机制 / 怎么减,带 model 判别式)
| model | 字段 | 含义 |
|---|---|---|
PERCENT | percent_to_pay(10-99) | 付 X%(打折) |
AMOUNT_OFF | amount_off(Money) + min_order(Money?) | 满减 / 立减 |
FLASH | flash_items[] | 秒杀逐 SKU(见 §3.2) |
场景×机制自然组合:全场×PERCENT=全场折扣、全场×AMOUNT_OFF=满减、首单×PERCENT=首单折、首单×AMOUNT_OFF=首单减、FLASH 场景配 FLASH 机制。枚举从「为每个组合起名」塌成 3 场景 + 3 机制。
2.5 schedule(时间,子对象)
schedule: { period: {start, end} | "LONG_TERM", daily_slot: {start, end} | "ALL_DAY" }(epoch ms)。
period=LONG_TERM:长期有效(首单常用)。daily_slot:每日时段(午市/晚市);ALL_DAY=全天。- 替代 v1 的
date_start/end+time_start/end+is_long_term+is_all_day四散字段。
3. 端点详解
3.1 POST /marketing:preview(kind=CAMPAIGN)—— 建活动预演
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
store_id | string | 是 | 门店 |
activity_type | enum | 是 | 场景 §2.4(非法→AIGENT_INVALID_ACTIVITY_TYPE) |
activity_name | string | 是 | 活动名 |
discount | object | 是 | 优惠机制 §2.4(带 model 判别式) |
schedule | object | 条件 | 时间 §2.5(FIRST_ORDER 可省=LONG_TERM) |
输出:{ preview_token, draft_id, card }(card 含算好的 display_summary)。
校验失败:透传 MKT_* 码(如折扣超范围/秒杀价过高),Agent 转述让用户改。
示例
// 全场午市8折
{ "store_id":"B1", "activity_type":"WHOLE_ORDER", "activity_name":"午市8折",
"discount": { "model":"PERCENT", "percent_to_pay":80 },
"schedule": { "period":{"start":..,"end":..}, "daily_slot":{"start":..,"end":..} } }
// 满100减20
{ "activity_type":"WHOLE_ORDER", "discount":{ "model":"AMOUNT_OFF",
"amount_off":{"amount":2000,"currency":"AED","minor_unit":2}, "min_order":{"amount":10000,...} } }
// 首单8折(长期)
{ "activity_type":"FIRST_ORDER", "discount":{"model":"PERCENT","percent_to_pay":80},
"schedule":{"period":"LONG_TERM"} }
3.2 秒杀机制(discount.model=FLASH)
flash_items: [{ sku_id, spu_id, flash_price:Money, flash_stock, per_order_limit }],flash_price < 原价;sku 从 /products 选。
3.3 POST /marketing:commit(kind=CAMPAIGN)
preview_token + action(PUBLISH/DRAFT) + Idempotency-Key 头 → 活动详情;token 失效→AIGENT_PREVIEW_EXPIRED。同一端点凭 preview_token 里的 kind 分派(CAMPAIGN/MEMBER_TAG/MEMBER_DELETE/EXPORT)。
3.4 POST /campaigns/{id}:action —— 生命周期合一
| 参数 | 类型 | 说明 |
|---|---|---|
action | enum | PAUSE/RESUME/TERMINATE/WITHDRAW |
confirmed | bool | TERMINATE 必须 true(归还库存恰好一次) |
expected_status | enum | CAS 乐观并发,防 TOCTOU |
Idempotency-Key(头) | — | 幂等去重 |
状态前置不满足→AIGENT_STATE_CONFLICT(409, details{current_status, allowed_actions});目标态已达成→幂等成功。
3.5 GET /campaigns —— 列表
入参:store_id、statuses[]、activity_type、keyword、created_from/to、ended_reason、sort:[{field,order}](默 created DESC)、view(SLIM|FULL)、分页。
出参:行含机读原始 schedule(period/daily_slot) + discount(model+值);display_* 标 presentation-only。
3.6 GET /campaigns/{id} —— 详情
列表行超集 + 复盘统计 + available_actions:[{action, endpoint, available, status, disabled_reason?}](不可用时带机读原因如 STATE_NOT_ACTIVE)+ 秒杀 flash_items[]。
3.7 GET /products —— 选品
store_id、spu_keyword、分页 → items[]{ spu_id, spu_name, sku_list:[{sku_id, spec, price:Money, original_price:Money, stock, conflict, conflict_campaign}] }。
3.8 GET /marketing/capabilities
{ "contract_version":"2.0.0",
"activity_types":[{"code":"WHOLE_ORDER","label":"全场活动"}, {"code":"FIRST_ORDER",...}, {"code":"FLASH",...}],
"discount_models":[{"model":"PERCENT","range":[10,99]}, {"model":"AMOUNT_OFF"}, {"model":"FLASH"}],
"member_tags":[{"code":"HIGH_VALUE","label":"高价值","is_system":true,"editable":false}, ...],
"limits":{ "flash_max_sku":50, "campaign_name_max":30 } }
Agent 建活动/打标签前一次取全合法场景/机制/标签 —— 合法值不进 prompt。
3.9 会员域(参数从简)
members:filter:keyword(昵称/手机)·min_net_consumption·tags[]→ 分页会员。- 打/移标签(危险写)→
marketing:preview(kind=MEMBER_TAG, payload{op:ASSIGN/UNASSIGN, member_ids[], tag_codes[]})→commit;affected_count标is_estimate:true,commit 后返实际。系统标签(HIGH_VALUE/AT_RISK)只筛不可改。 members:新增(直接写)phone(+country_code/nickname/tag_codes)。- 删除会员(危险写)→
marketing:preview(kind=MEMBER_DELETE, payload{member_id})→commit(confirmed=true);下游未实现→AIGENT_DOWNSTREAM_UNSUPPORTED(非重试、不消耗 token)。 members:import:直接写,items[]逐行部分成功,返inserted/skipped/format_errors。
4. Agent 如何匹配口语 → 端点 + 参数(确定性,少 prompt)
可枚举映射在词库/纯函数;prompt 只留语气 + 安全 + 澄清。
4.1 端点路由
| 用户口语 | 端点 | 出参 |
|---|---|---|
| 建/做活动/促销/折扣 | campaigns:preview | 见 4.2 |
| 暂停/恢复/终止/撤回 | campaigns/{id}:action | action=PAUSE/RESUME/TERMINATE/WITHDRAW |
| 看/查活动、进行中的 | campaigns | statuses=[...] |
| 选品/加商品 | products | spu_keyword |
| 筛会员/打标签/删会员/导入 | members:* / member-tags:* | — |
4.2 口语 → 场景 + 机制(确定性解析,不靠 prompt 算)
| 用户口语 | activity_type | discount |
|---|---|---|
| 全场9折 / 打9折 | WHOLE_ORDER | {model:PERCENT, percent_to_pay:90} |
| 8.5折 / 85折 | WHOLE_ORDER | {model:PERCENT, percent_to_pay:85} |
| 满100减20 | WHOLE_ORDER | {model:AMOUNT_OFF, amount_off:20, min_order:100} |
| 立减30 | WHOLE_ORDER | {model:AMOUNT_OFF, amount_off:30} |
| 新客首单8折 | FIRST_ORDER | {model:PERCENT, percent_to_pay:80} |
| 秒杀 / 限时特价 | FLASH | {model:FLASH, flash_items:[...]}(走选品) |
解析规则(消费侧纯函数):
X折→percent(9折→90,85折→85);满X减Y→amount_off+min_order;立减/直减Y→amount_off;付X%→percent。命中即填,未命中回退 LLM。场景词(全场/首单/秒杀)+ 机制由这套解析确定,prompt 不写换算规则。
4.3 类型/标签靠 capabilities
模糊「做个活动」→ 出 pick_type 引导卡;合法场景/机制/标签从 capabilities 取。清单不进 prompt。
4.4 Prompt 只留 4 件事
语气专业简洁 · 危险写必走 preview→commit · 终止/删除要 confirmed · 模糊出 pick_type / 拿不准就澄清。
5. 数据团队如何实现
| 优化点 | 实现要点 |
|---|---|
| discount 子对象 | 按 discount.model 分支校验/落库;映射现网 discountValue/directAmount(带 legacy_code),消除字段-类型耦合 |
| 场景×机制解耦 | activity_type 只判场景;机制走 discount.model;首单×percent / 首单×amount 自然支持 |
| schedule 子对象 | 落库映射 dateStart/end+timeStart/end;LONG_TERM/ALL_DAY 用显式枚举 |
| :action 合一 | 端点内分派 + AIGENT_STATE_CONFLICT + Idempotency-Key 去重(终止库存归还一次) |
| capabilities 合一 | 一个端点返活动/机制/标签/限制,由白名单同源生成 |
| token 门店校验 | commit 校验鉴权门店==token 门店 |
6. 迁移对照
v1 → v2
| v1 | v2 | 原因 |
|---|---|---|
percent_to_pay/amount_off/flash_price 顶层 | discount{model, ...} 子对象 | 消除字段-类型耦合,校验按 model 分支 |
类型 FIXED_AMOUNT_OFF/WHOLE_ORDER_PERCENT | activity_type(场景) × discount.model(机制) | 修「类型既场景又机制」自相矛盾 |
date/time/is_long_term/is_all_day 四散 | schedule{period, daily_slot} | 收敛,显式枚举 |
activity-types + member-tags 两端点 | marketing/capabilities 一端点 | 一次取全合法值 + 门控 |
| 活动/标签/删会员 三对 preview/commit(6 端点) | marketing:preview + marketing:commit 一对(kind 判别) | 全平台危险写收一对(导出同挂 kind=EXPORT);消费侧本就一个 commit,无损准确性 |
| 仅 export 提幂等 | :commit/:action/标签/删除 加 Idempotency-Key | 写安全 |
available_actions 无原因 | 补 disabled_reason | 可解释 |
现网 → v2(要点)
| 现网 | v2 |
|---|---|
campaign/pause+resume+terminate | campaigns/{id}:action |
discountValue(多态)+directAmount | discount{model,...} |
DIRECT_AMOUNT_OFF/ORDER_DISCOUNT | activity_type×discount.model(legacy_code 过渡) |
| 失败 200 + data.errorCode | 真实 HTTP + error{category,retriable} |
附:相关文档
- 评审依据:
营销专家API-优缺点与优化方案(针对2026-06-10契约).md - 现网契约:
2026-06-10-aigent-AI对接说明(2).md - 对照(数据侧):
数据分析API-简版(Agent调用+数据团队实现).md