数据专家 API · 优缺点分析与优化方案

对象:现网契约 2026-06-10-aigent-AI对接说明(2).md数据专家部分(§1.1–1.9,9 个端点)。 范围:只针对数据专家场景(取数 / 趋势 / 环比 / 客单价 / 维度 / 导出),不含营销、会员操作。 结论:现网取数侧"能跑通但偏碎"——5 条取数端点 + 3 套指标命名 + 3 种时间格式并存,失败语义弱,部分能力被错标"无数据源"。本文先评优缺点,再给一套收敛为 2 个端点的优化方案 + 迁移对照。 真实库口径以 ai-Recs 全表分析为准(report_daily_statistics 263 店 / main_order 全量)。


一、现状概览(数据专家 9 端点)

端点作用指标口径时间载体
§1.1 GET metrics/capabilities可答维度声明
§1.2 POST metrics/resolveDateRange口语时间→区间yyyy-MM-dd HH:mm:ss
§1.3 POST metrics/query3 指标netIncome/successAmount/...(驼峰,5 字段 VO)yyyy-MM-dd HH:mm:ss
§1.4 POST metrics/compare净收入环比netIncome同上
§1.5 POST metrics/trend近 7 天趋势netIncomeyyyy-MM-dd
§1.6 POST metrics/report经营报表(含客单价)revenue/orders/avgTicket(第三套名)yyyy-MM-dd
§1.7 POST metrics/agent-bi通用 BI(11 指标,取数/趋势/环比合一)income/success_amount/...(蛇形,11 指标)13 位 ms
§1.8/1.9 POST report/export/*导出 preview→commit

二、优点(值得保留的设计)

#优点说明
✅1agent-bi 已合并取数/趋势/环比§1.7 用 metrics+aggregation+timeGranularity+compare 一个端点搞定三态,方向正确,是优化方案的基础
✅2指标白名单显式 + 白名单外丢弃不报错§1.7 11 指标白名单,传非法指标自动忽略而非报错,容错好
✅3zero 标志区分"零数据"与"错误"§1.3 query VO 有 zero:bool,避免把无数据当异常
✅4比率口径明确§1.7 refund_rate/success_rate 注明"整段累加再除、分母 0 返 null",口径清晰
✅5环比无基线有判定baselineExists=false 表达上期无数据,避免 AI 编造环比(§1.4/§1.6)
✅6危险写 preview→commit + 一次性 token§0.4 导出走两步确认,token 10 分钟一次性,防重设计到位
✅7键名大小写/连字符不敏感§1.7 order-count=order_count=ORDER_COUNT,调用方容错

优化方案保留并强化这些:以 agent-bi 为基础收口、沿用白名单 + zero + baselineExists + preview→commit。


三、缺点 / 问题(按影响排序)

P0 · 结构性

#问题证据(原文)
D1取数端点 5 条冗余query/compare/trend 已被 agent-bi 完全覆盖§1.3–1.5 vs §1.7
D2同一指标三套名:"净收入" = netIncome(§1.3) / income(§1.7) / revenue(§1.6);驼峰蛇形混用§1.3/1.6/1.7
D3失败恒 HTTP 200R.code=500、错误码埋 data.errorCode,连接器无法 raise_for_status、监控把失败当成功§0.2/0.3
D4错误码无 retriable + 同码多义AIGENT_RANGE_TOO_LARGE 既表导出>90 天(§0.3)又表 agent-bi>400 天(§1.7);PRODUCT_SERVICE_DEGRADED 走"其他"兜底§0.3/§1.7

P1 · 口径一致 + 能力解锁

#问题证据
D5客单价自相矛盾:§1.7 说"客单价 minipos 没数据源",§1.6 又给 avgTicket=revenue/orders(现算,orders=0→0)§1.6/1.7
D6分渠道/客流/会员错标"无数据源":§1.6 customers/breakdown 恒 null、§1.7 说分渠道没源,但真实日报表这些列都在§1.6/1.7 vs 真实表
D7时间载体三种混用yyyy-MM-dd HH:mm:ss(§0.5/1.3) / yyyy-MM-dd(§1.5/1.6) / 13 位 ms(§1.7)§0.5/1.x
D8覆盖度不声明:全篇不提 263/5001 店、日报直取 vs 订单聚合、"无数据源"vs"真 0"通篇

P2 · 规范细节

#问题证据
D9无版本号(R<T>apiVersion、URL 无 /v1§0.2
D10timeGranularity=YEAR 真实性存疑(真实网关/mock 行为不一致)§1.7
D11dimensions 是语义漂移的兼容字段(填 trend/time_range 等价 timeGranularity=DAY§1.7
D12resolveDateRange 单独一跳:取数前先调一次解析时间,多一次往返§1.2
D13比率护栏与能力冲突:§1.7 提供比率,又注"对话侧护栏禁止算比率,自行斟酌"§1.7

四、优化方案:数据专家收敛为 2 个端点

核心思路:以 §1.7 agent-bi 为基础,①把 query/compare/trend(旧 3 指标链) 和 report(客单价) 也收进来;②加 dimension 解锁分渠道;③统一时间/命名/错误/覆盖度。导出(§1.8/1.9)单列,下文「4.5」给精简版。

约定:前缀 /pos/ai/v1;时间一律 13 位 epoch ms(UTC+4,含头含尾);金额 AED。

4.1 端点总览

端点用途替代现网
POST /metrics:query统一取数:汇总/趋势/同比/客单价/维度,靠参数区分query+compare+trend+report+agent-bi
GET /metrics/capabilities能力发现:逐店支持的指标/维度capabilities(增强)
(导出见 4.5,沿用 preview→commit)export/preview·commit

4.2 POST /metrics:query 请求参数

参数类型必填说明取值
store_idstring门店 ID
metricsstring[]查哪些指标,可多选(白名单外忽略不报错)§4.4(含 avg_ticket
aggregationstring区间内怎么合并,默认 SUMSUM/AVG 日均/MAX 单日最高/MIN
time_granularitystring出数颗粒,不填=整段 1 行DAY/MONTH(移除 YEAR,见 D10)
date_fromnumber区间起(13 位 ms)
date_tonumber区间止(13 位 ms)
comparestring同比,默认 NONENONE/WOW/MOM/YOY
dimensionstring按维度拆分,不填=不拆CHANNEL/PAYMENT/ORDER_SOURCE/MEMBER

参数组合 = 拿到哪种数据

你要的metricstime_granularitycomparedimension
上周营业额(一个数)["success_amount"]不填NONE不填
近 7 天每天营业额(趋势)["success_amount"]DAYNONE不填
本周营业额 + 比上周(环比)["success_amount"]不填WOW不填
客单价["avg_ticket"]不填NONE不填
分渠道营业额占比["success_amount"]不填NONECHANNEL

4.3 POST /metrics:query 响应

响应外壳(失败回真实 HTTP 状态,纠正 D3)

{ "api_version":"v1", "code":0, "message":"ok",
  "data": { ... },
  "meta": { "currency":"AED",
            "data_basis":"DAILY_REPORT",          // 三态:DAILY_REPORT / ORDER_AGGREGATED / NONE(纠正 D8)
            "metric_basis": {"income":"DAILY_REPORT","fail_count":"ORDER_AGGREGATED"} },  // 逐指标底座
  "error": null }                                  // 失败:{error_code,category,retriable,details}

① 不带 dimension(取数 / 趋势)

字段类型说明
seriesarray数据行;time_granularity 不填 1 行,填了多行
series[].periodstring周期标签 2026-06-10(汇总行可空)
series[].values.<m>.valuenumber本期值
series[].values.<m>.prevnumber|null对比期值(不带 compare 为 null)
series[].values.<m>.pctnumber|null变化率(不带 compare 为 null)
series[].values.<m>.baseline_existsbool上期是否有基线(false=上期无数据,prev/pct 为 null,沿用 ✅5)

② 带 dimension(维度拆分)

字段类型说明
breakdown[].dimension_valuestring维度值,如 DINING_ROOM/PAY_BY_CARD
breakdown[].valuenumber该切片指标值
breakdown[].sharenumber占比 0–1

4.4 指标白名单(12 项,统一蛇形,纠正 D2/D5)

key含义类型真实来源列data_basis
income净收入金额turnover − refund(待确认 actual_income_no_tips 后切换)DAILY_REPORT
success_amount成功交易额(营业额/流水)金额turnover 直取DAILY_REPORT
order_count订单总数order_quantity 直取DAILY_REPORT
success_count成功笔数order_quantity 近似直取DAILY_REPORT
refund_amount退款额金额refund 直取DAILY_REPORT
refund_count退款笔数main_order.order_status=refunded 聚合ORDER_AGGREGATED
fail_amount失败额金额blankout/cancel 聚合ORDER_AGGREGATED
fail_count失败笔数blankout+cancel 聚合ORDER_AGGREGATED
settle_amount总结算额金额turnover − refund(待 minipos 对齐)DAILY_REPORT
refund_rate退款率比率refund / turnoverDAILY_REPORT
success_rate成功率比率成功/(成功+失败)ORDER_AGGREGATED
avg_ticket客单价金额average_order_price 直取(解 D5,仅 263 日报店,不现算DAILY_REPORT

笔数级(refund_count/fail/success_rate)日报无、走订单聚合(与 真实库表校验确认.md 一致)。比率口径沿用 ✅4「整段累加再除、分母 0 返 null」。

4.5 导出(沿用 preview→commit,规范化)

POST /report:export-preview(>90 天→AIGENT_EXPORT_RANGE_TOO_LARGE)→ 出确认卡 → POST /report:export-commit(凭 previewToken,幂等)。沿用 §0.4 两步式 + 一次性 token;仅把错误码与时间格式对齐到下方统一规范。

4.6 统一错误模型(纠正 D3/D4)

优化
HTTP 状态失败回真实状态(400/409/410/422/429/503),不再恒 200
结构error{error_code, category, retriable, details}
categoryvalidation/conflict/degraded/not_found/rate_limited/unsupported
拆同码多义AIGENT_QUERY_RANGE_TOO_LARGE(400 天) / AIGENT_EXPORT_RANGE_TOO_LARGE(90 天),details{max_days,requested_days}
可重试*_DEGRADED/限流 retriable=true+retry_after_ms;校验类 retriable=false

4.7 capabilities 增强(纠正 D8)

{ "contract_version":"1.0.0", "currency":"AED", "tz_offset":"+04:00",
  "metrics":[ {"key":"avg_ticket","label":"客单价","available":true,"scope":["query"]}, ... ],
  "dimensions":[ {"dimension":"CHANNEL","available":true},
                 {"dimension":"ORDER_SOURCE","measure":"COUNT_ONLY"} ],   // 来源只有笔数
  "limits":{ "query_max_days":400, "export_max_days":90 } }               // 拆全两个上限

五、Agent 如何调用与匹配参数(消费侧,不进 API 契约)

一句话拆成几件事填到 /metrics:query:时间词→date_from/to;「日/每天/趋势」→time_granularity;指标词→metrics[];「日均/最高」→aggregation;「比上周/同比」→compare;「分渠道/各支付」→dimension

模糊词→指标:营业额/销售额/流水→success_amount;净收入/利润→income;营收/收入(模糊)→success_amount(商家口语优先流水);订单/单量→order_count;客单价→avg_ticket

「上周的日营业额」→ date_from/to=上周一~日 + time_granularity=DAY + metrics=[success_amount] + 其余默认 → 7 天逐日营业额。

时间解析建议挪到 Agent 侧(省去 §1.2 resolveDateRange 一跳,D12);若 Agent 不自算,可保留该端点作回退。


六、数据团队如何实现

/metrics:query 实现里按参数分支取真实表(§4.4 已列来源列):

  1. 三链收一端:现网 agent-bi 已合并取数/趋势/环比;再把 客单价(源 average_order_price)和维度拆分(源 dining_room/pay_by_*/member_* 列)接进同一端点,即可让 query/compare/trend/report 一并退役。这些源 ai-Recs 已确认在 report_daily_statistics 里存在(解 D6)。
  2. 覆盖度三态:日报 263 店走 report_daily_statisticsdata_basis=DAILY_REPORT);其余店 main_order/daily_record 按日聚合(ORDER_AGGREGATED);都没有→NONE不返 0(解 D8)。
  3. 性能:日报表本就是 per 店/日预聚合,直取即可,避免逐日拉下游(缓解 §1.7 自陈的性能问题)。
  4. capabilities 如实:哪些指标/维度这家店真有数据就标 available,让 Agent 据此门控。

七、迁移对照(现网 → 优化后)

现网优化后处置
metrics/query(3 指标)metrics:query metrics=[...]Deprecated,字段 1:1 映射
metrics/comparemetrics:query compare=wow/mom/yoyDeprecated
metrics/trendmetrics:query time_granularity=DAYDeprecated
metrics/reportavgTicketmetrics:query metrics=[avg_ticket]并入,源改直取
metrics/reportcustomers/breakdown(null)metrics:query dimension=...解锁(真实列存在)
metrics/agent-bimetrics:query重命名 + 加 dimension/avg_ticket
netIncome/revenue/income统一 income蛇形单一字典
yyyy-MM-dd HH:mm:ss / ms 混用统一 13 位 ms
失败 200 + data.errorCode真实 HTTP + error{}
AIGENT_RANGE_TOO_LARGE(两义)拆 query/export 两码

八、待数据团队确认(实现前先核实)

列(report_daily_statistics用途未确认前回退
actual_income_no_tips / tips / vatincome 精确口径income = turnover − refund
customer_number 是否有/填充率客流量指标暂不提供
member_* 各列填充率会员维拆分填充率低→available:false

附:相关文档

  • 现网契约:2026-06-10-aigent-AI对接说明(2).md(§1.1–1.9 数据专家)
  • 真实库校验:数据报表API-真实库表校验确认.md(11 指标逐列、avg_ticket 源确认)
  • 简版对外:数据分析API-简版(Agent调用+数据团队实现).md