数据专家 API · 优缺点分析与优化方案
对象:现网契约
2026-06-10-aigent-AI对接说明(2).md的数据专家部分(§1.1–1.9,9 个端点)。 范围:只针对数据专家场景(取数 / 趋势 / 环比 / 客单价 / 维度 / 导出),不含营销、会员操作。 结论:现网取数侧"能跑通但偏碎"——5 条取数端点 + 3 套指标命名 + 3 种时间格式并存,失败语义弱,部分能力被错标"无数据源"。本文先评优缺点,再给一套收敛为 2 个端点的优化方案 + 迁移对照。 真实库口径以 ai-Recs 全表分析为准(report_daily_statistics263 店 /main_order全量)。
一、现状概览(数据专家 9 端点)
| 端点 | 作用 | 指标口径 | 时间载体 |
|---|---|---|---|
§1.1 GET metrics/capabilities | 可答维度声明 | — | — |
§1.2 POST metrics/resolveDateRange | 口语时间→区间 | — | 出 yyyy-MM-dd HH:mm:ss |
§1.3 POST metrics/query | 查 3 指标 | netIncome/successAmount/...(驼峰,5 字段 VO) | 入 yyyy-MM-dd HH:mm:ss |
§1.4 POST metrics/compare | 净收入环比 | netIncome | 同上 |
§1.5 POST metrics/trend | 近 7 天趋势 | netIncome | yyyy-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 | — | — |
二、优点(值得保留的设计)
| # | 优点 | 说明 |
|---|---|---|
| ✅1 | agent-bi 已合并取数/趋势/环比 | §1.7 用 metrics+aggregation+timeGranularity+compare 一个端点搞定三态,方向正确,是优化方案的基础 |
| ✅2 | 指标白名单显式 + 白名单外丢弃不报错 | §1.7 11 指标白名单,传非法指标自动忽略而非报错,容错好 |
| ✅3 | zero 标志区分"零数据"与"错误" | §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 200:R.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 |
| D10 | timeGranularity=YEAR 真实性存疑(真实网关/mock 行为不一致) | §1.7 |
| D11 | dimensions 是语义漂移的兼容字段(填 trend/time_range 等价 timeGranularity=DAY) | §1.7 |
| D12 | resolveDateRange 单独一跳:取数前先调一次解析时间,多一次往返 | §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_id | string | 是 | 门店 ID | — |
metrics | string[] | 是 | 查哪些指标,可多选(白名单外忽略不报错) | §4.4(含 avg_ticket) |
aggregation | string | 否 | 区间内怎么合并,默认 SUM | SUM/AVG 日均/MAX 单日最高/MIN |
time_granularity | string | 否 | 出数颗粒,不填=整段 1 行 | DAY/MONTH(移除 YEAR,见 D10) |
date_from | number | 是 | 区间起(13 位 ms) | — |
date_to | number | 是 | 区间止(13 位 ms) | — |
compare | string | 否 | 同比,默认 NONE | NONE/WOW/MOM/YOY |
dimension | string | 否 | 按维度拆分,不填=不拆 | CHANNEL/PAYMENT/ORDER_SOURCE/MEMBER |
参数组合 = 拿到哪种数据
| 你要的 | metrics | time_granularity | compare | dimension |
|---|---|---|---|---|
| 上周营业额(一个数) | ["success_amount"] | 不填 | NONE | 不填 |
| 近 7 天每天营业额(趋势) | ["success_amount"] | DAY | NONE | 不填 |
| 本周营业额 + 比上周(环比) | ["success_amount"] | 不填 | WOW | 不填 |
| 客单价 | ["avg_ticket"] | 不填 | NONE | 不填 |
| 分渠道营业额占比 | ["success_amount"] | 不填 | NONE | CHANNEL |
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(取数 / 趋势)
| 字段 | 类型 | 说明 |
|---|---|---|
series | array | 数据行;time_granularity 不填 1 行,填了多行 |
series[].period | string | 周期标签 2026-06-10(汇总行可空) |
series[].values.<m>.value | number | 本期值 |
series[].values.<m>.prev | number|null | 对比期值(不带 compare 为 null) |
series[].values.<m>.pct | number|null | 变化率(不带 compare 为 null) |
series[].values.<m>.baseline_exists | bool | 上期是否有基线(false=上期无数据,prev/pct 为 null,沿用 ✅5) |
② 带 dimension(维度拆分)
| 字段 | 类型 | 说明 |
|---|---|---|
breakdown[].dimension_value | string | 维度值,如 DINING_ROOM/PAY_BY_CARD |
breakdown[].value | number | 该切片指标值 |
breakdown[].share | number | 占比 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 / turnover | DAILY_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} |
| category | validation/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 已列来源列):
- 三链收一端:现网 agent-bi 已合并取数/趋势/环比;再把 客单价(源
average_order_price)和维度拆分(源dining_room/pay_by_*/member_*列)接进同一端点,即可让query/compare/trend/report一并退役。这些源 ai-Recs 已确认在report_daily_statistics里存在(解 D6)。 - 覆盖度三态:日报 263 店走
report_daily_statistics(data_basis=DAILY_REPORT);其余店main_order/daily_record按日聚合(ORDER_AGGREGATED);都没有→NONE,不返 0(解 D8)。 - 性能:日报表本就是 per 店/日预聚合,直取即可,避免逐日拉下游(缓解 §1.7 自陈的性能问题)。
- capabilities 如实:哪些指标/维度这家店真有数据就标
available,让 Agent 据此门控。
七、迁移对照(现网 → 优化后)
| 现网 | 优化后 | 处置 |
|---|---|---|
metrics/query(3 指标) | metrics:query metrics=[...] | Deprecated,字段 1:1 映射 |
metrics/compare | metrics:query compare=wow/mom/yoy | Deprecated |
metrics/trend | metrics:query time_granularity=DAY | Deprecated |
metrics/report 的 avgTicket | metrics:query metrics=[avg_ticket] | 并入,源改直取 |
metrics/report 的 customers/breakdown(null) | metrics:query dimension=... | 解锁(真实列存在) |
metrics/agent-bi | metrics: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 / vat | income 精确口径 | 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