构建指标平台(语义层)的指标数据查询 API 请求。当用户需要查询指标数据、构造指标查询API请求体、使用同环比/占比/排名/时间限定等快速计算、定义临时指标、设置维度筛选过滤条件时,必须使用此 Skill。 触发场景包括但不限于:用户提到"查询指标"、"指标API"、"指标数据"、"语义层查询"、"metric...
根据用户自然语言描述, 先通过 Gateway 检索指标和维度,再生成语义接口 /semantic/api/v1.1/metrics/query 的请求体 JSON。
搜索指标: GET https://gateway.can.aloudata.com/api/metrics/search?keyword={关键词,可逗号分隔}&pageSize={数量} 单指标维度: GET https://gateway.can.aloudata.com/api/metrics/{metricName}/dimensions?keyword={可选过滤词} 批量指标维度: GET https://gateway.can.aloudata.com/api/metrics/dimensions?metricNames={指标1,指标2}&keyword={可选过滤词} 指标列表: GET https://gateway.can.aloudata.com/api/metrics/list?pageNumber={页码}&pageSize={数量} 指标目录: GET https://gateway.can.aloudata.com/api/metrics/categories 目录下指标: GET https://gateway.can.aloudata.com/api/metrics/categories/{categoryId}?pageSize={数量} 认证方式:所有请求必须携带 API Key,通过请求头 X-API-Key 传递(也可通过 ?apikey= 查询参数传递)。 返回格式为纯文本,非 JSON。
⚠️ 调用 Gateway 的两条铁律:
-H "X-API-Key: $CAN_API_KEY", $CAN_API_KEY 从环境变量读取(用户需在 ~/.openclaw/.env 中配置 CAN_API_KEY=cgk-xxxxxxxx),未携带或无效 Key 将返回 401--data-urlencode + -G 让 curl 自动编码,禁止中文直接拼入 URL示例:
bash
# 搜索单个指标 curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/search?pageSize=5" --data-urlencode "keyword=客单价" -G # 批量搜索多个指标(逗号分隔) curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/search?pageSize=3" --data-urlencode "keyword=客单价,销售额" -G # 单指标维度查询(路径参数直接用 metricName) curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/AOV/dimensions" # 按关键词过滤维度(只返回匹配的维度,keyword 支持逗号分隔多关键词,匹配任一即返回) curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/AOV/dimensions" --data-urlencode "keyword=渠道" -G # 多关键词过滤维度(逗号分隔,匹配维度名/展示名/描述/维度值样本中任一关键词的维度都会返回) curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/AOV/dimensions" --data-urlencode "keyword=渠道,地区,品牌" -G # 批量指标维度查询(自动计算维度交集,keyword 同样支持多关键词) curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/dimensions?metricNames=AOV,retail_amt" --data-urlencode "keyword=渠道" -G # 指标目录(查看所有类目层级) curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/categories" # 查看指定目录下的指标 curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/categories/{categoryId}?pageSize=20" # 指标列表(分页浏览全部指标) curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/list?pageNumber=1&pageSize=50"
接口: POST https://gateway.can.aloudata.com/api/metrics/query 认证方式:同上,必须携带 API Key 认证头。
示例(⚠️ 因为 timeConstraint 含单引号
['metric_time'],必须用 heredoc 传 JSON body,禁止用-d '...'单引号包裹):bash
curl -X POST "https://gateway.can.aloudata.com/api/metrics/query" \ -H "X-API-Key: $CAN_API_KEY" \ -H "Content-Type: application/json" \ -d @- <<'EOF' {"metrics": ["AOV"], "timeConstraint": "['metric_time__day']= DATEADD(DateTrunc(NOW(), \"DAY\"), -1, \"DAY\")"} EOF
构建 JSON 前,先逐条过一遍:
铁律 1 — 相对时间必须用 NOW(),禁止硬编码日期(包括 timeConstraint 和 period 锚定)
"上月""上周""本年""昨天""近N天""去年""本季""上季" 等相对时间 → 必须 NOW()。
DATEADD(DateTrunc(NOW(), "MONTH"), -1, "MONTH")DATEADD(DateTrunc('2026-03-05', "MONTH"), -1, "MONTH")"2025-04-01"⚠️ 特别注意:period 锚定的 timeConstraint 也必须用 NOW()
当使用 metricDefinitions + period 时,timeConstraint 作为 period 的锚定基准。如果用户说的是"本年至今""本月至今""近30天"等相对时间,锚定日期必须用 DATEADD(DateTrunc(NOW(), "DAY"), -1, "DAY") 表示"昨天", 绝不可 将当前日期(如 2026-03-06)直接写入 timeConstraint。
"timeConstraint": "['metric_time__day']= DATEADD(DateTrunc(NOW(), \"DAY\"), -1, \"DAY\")""timeConstraint": "['metric_time__day']= \"2026-03-06\""(硬编码当前日期)"timeConstraint": "['metric_time__day']= \"2026-03-05\""(硬编码昨天日期)铁律 2 — metricDefinitions 中每个 key 必须同时在 metrics 数组中(包括辅助指标)
定义了就必须注册。自检:数 metricDefinitions 的 key → 逐个确认在 metrics 中存在。
⚠️ 特别注意"辅助指标": 即使某个临时指标仅作为 expr 的中间计算变量(如 "total": { "refMetric": "metric_A", "specifyDimension": ... } 被 "ratio": { "expr": "[val]/[total]" } 引用),该辅助指标 也必须 出现在 metrics 数组中。API 不会自动推断依赖关系——metricDefinitions 中的每个 key 无论是最终输出还是中间计算,都需要在 metrics 中显式注册。
"metrics": ["ratio"] + "metricDefinitions": { "total": {...}, "ratio": { "expr": "[val]/[total]" } }( total 未注册)"metrics": ["total", "ratio"] + "metricDefinitions": { "total": {...}, "ratio": { "expr": "[val]/[total]" } }铁律 3 — 占比/排名 + filters = 分母/范围被缩小 → 结果恒 100%/恒为 1 要"某个值在全局中的占比/排名" → 用 resultFilters 做展示筛选, 不用 filters。
⚠️ 特别注意"渠道内占比/排名"场景: 当用户问"Wholesale 渠道的 渠道内占比/排名"时,含义是 Wholesale 在所有渠道中的占比/排名。此时:
first_channel),让所有渠道参与占比/排名计算resultFilters 仅展示 Wholesale 的行"filters": ["[first_channel]= \"Wholesale\""] → 只剩 Wholesale 自己,占比恒 100%、排名恒 1"resultFilters": ["[first_channel]= \"Wholesale\""] → 分母包含所有渠道铁律 4 — "同比"默认 = yoy;带粒度前缀时按前缀选择
yoymom(与上月同期比)wow(与上周同期比)qoq(与上季同期比)铁律 5 — 一个指标只能做一次快速计算,不可链式叠加 需要多步(如先算环比再排名)→ 用 metricDefinitions 分步。
retail_amt__sameperiod__mom__growth__rank__desc__first_channel(链式:环比 + 排名)retail_amt__sameperiod__yoy__growth__rankDense__desc__first_channel(链式:同比 + 排名)json
"metrics": ["mom_growth", "mom_growth__rankDense__desc__first_channel"],
"metricDefinitions": {
"mom_growth": {
"refMetric": "retail_amt",
"indirections": ["sameperiod__mom__growth"]
}
}
典型场景——"各渠道增速前N的品牌": 这类需求必须分步:第1步用 metricDefinitions 定义环比增速临时指标;第2步对临时指标做渠道内排名。
铁律 6 — MetricMatches 只能在 metricDefinitions 的 filters 中使用,禁止放在顶层 filters MetricMatches 是"基于指标值筛选维度值"的高级功能, 必须 包裹在临时指标定义(metricDefinitions)的 filters 中。
"metricDefinitions": { "temp": { "refMetric": "buyer_cnt", "filters": ["MetricMatches([vip_code], [retail_amt] >= 10000)"] } }"filters": ["MetricMatches([vip_code], [retail_amt] >= 10000)"](顶层 filters 不支持 MetricMatches)铁律 7 — 派生指标的 metric_time 粒度限制必须遵守
候选指标中标注"metric_time维度仅支持日粒度"的派生指标(如 sales_yoy、retail_amt_ytd 等), 只能在 timeConstraint 锚定到天粒度时使用(如 ['metric_time__day']= ...)。当 timeConstraint 为周/月/季/年粒度时, 禁止使用 这些日粒度限制的派生指标,必须改用原子指标 + 快速计算语法。
retail_amt__sameperiod__yoy__growth(原子指标+快速计算)sales_yoy(日粒度派生指标 + 月级 timeConstraint = 不兼容)铁律 8 — "月变化趋势"中的占比/排名范围维度必须是 metric_time__month
当查询涉及"XX在YY内排名/占比的 月变化趋势"时,范围维度必须是 metric_time__month(每月内独立计算排名/占比),而 非 实体维度或留空。
retail_amt__proportion__metric_time__month(每月内各渠道占比)retail_amt__rank__desc__metric_time__month(每月内各渠道排名)retail_amt__proportion__(全局占比,无月内分组 → 排名/占比跨月混淆)retail_amt__proportion__first_channel(每渠道内占比 → 恒100%)铁律 9 — 上下文不足时必须拒绝生成查询,返回空 JSON {},禁止虚构指标或忽视维度兼容性
在生成 JSON 前,必须执行以下三项上下文充分性检查。任何一项不通过, 必须拒绝生成查询,在 buildReason 中说明缺失原因,并返回空 JSON {}。
{}核心原则: 宁可在 buildReason 中诚实说明"候选指标/维度不足以回答此问题",也不要为了"产出内容"而硬凑一个错误的查询。错误的查询比没有查询更有害——它会返回误导性数据。
⚠️ 非查询意图判断: 如果用户消息 不包含任何数据查询意图(如"你好""谢谢""当前日期是XX"等对话性消息),则 不应生成查询请求体。此时应返回空 JSON {} 或在 buildReason 中说明"用户消息不含查询意图"。切勿为了"产出内容"而生成一个空 metrics 或无意义的请求体。
在写任何 JSON 之前,先把用户的问题拆解为四个维度:
维度问自己示例看什么(指标)用户要看的业务量是什么?有没有修饰语(日均、不含税…)?"销售额""日均订单数""客单价(不含税)"怎么看(分析方式)直接看值?还是要对比/占比/排名/趋势?"同比增长率""占比""排名前5""月趋势"看谁的(维度 & 筛选)按什么维度拆分?筛选哪些范围?"各品牌""某渠道""某地区"看哪段时间(时间)时间范围是什么?是否涉及时间对比?"上月""近7天""某月 vs 另一月"
以下 9 条规则解决的是"怎么理解用户的中文",而非"怎么写 JSON"。
规则 A — "总和" vs "分别"
用户说含义dimensions 处理"A 和 B 的某指标 分别 是多少"按 A、B 分组展示保留维度"A 和 B 的某指标 总和"A+B 合并为一个数字不放该维度"A 和 B 的某指标"(无修饰)歧义,默认"分别"保留维度
规则 B — 修饰语的作用域
"日均/月均/平均" 修饰的是 紧跟其后的所有并列项:
规则 C — "占比" 的两种含义
用户说含义实现方式"某指标 占比"(如"销售额占比")值占比(金额/数量占比)直接用 proportion 快速计算" 某实体 占比"(如"款色占比""客户占比""门店数占比")数量占比需要先用 计数指标 统计数量,再对计数指标做 proportion
判断标准:如果"占比"前面是一个 实体类型(款色、客户、门店、SKU)而非指标(销售额、订单数),则是数量占比。
规则 D — "XX均" 的聚合维度
"XX均"中的"XX"就是聚合维度,不要替换为其他维度。在候选维度表中找到"XX"对应的维度名称,用 multi_level_agg__avg,{该维度名} 实现。
示例:
multi_level_agg__avg,{门店维度}multi_level_agg__avg,{客户维度},或用 expr: [总指标]/[计数指标]规则 E — "同比" vs "环比"
用户说映射说明"同比"(无限定)yoy默认=年同比,详见铁律 4"年同比"yoy"月同比"mom与上月同期比"周同比"wow与上周同期比"季同比"qoq与上季同期比"环比"根据时间粒度选:日→dod,周→wow,月→mom,季→qoq❌ 不可映射为 yoy
规则 F — "对比去年末" ≠ "年同比"
用户说含义实现方式"同比""年同比"与 去年同期 对比__sameperiod__yoy__growth"与 去年末 相比"与去年12月/去年最后一天对比metricDefinitions + period 定位去年末(如 SPECIFY_DATE end day of -1 year)"与 上月末 相比"与上月最后一天对比__sameperiod__moeom__growth(需 day 粒度)
规则 G — "趋势" ≠ 同环比
"趋势"/"变化趋势" = 按时间展开看值的变化,只需指标 + 时间维度。除非用户明确提到"同比""环比""增长率",否则 不要 额外添加同环比指标。
规则 H — "差异/差距/对比" ≠ 同环比
"各XX之间的差异""A和B的差距" = 直接查出各自的值让用户比较, 不是 同比/环比。只有用户明确说"同比""环比""增长率"时才加同环比计算。
规则 I — 简单优先
如果用户问题可以用简单查询(指标 + 维度 + 时间)回答,就不要添加不必要的 metricDefinitions、同环比、占比、排名。例如:
metric_A__sameperiod__yoy__growth,不需要 metricDefinitions[{"granularity": "DAY", "calculateType": "AVG"}], 不要 在 dimensions 中加 metric_time__day(那样是按天展开,不是日均)retail_amt + timeConstraint 上月,dimensions 为空, 不要 加 metric_time__day 展开⚠️ 构建查询前,必须先通过 Gateway API 检索指标和维度,禁止凭记忆猜测。
从用户问题中提取核心业务关键词,调用 Gateway 搜索( 支持逗号分隔批量搜索):
bash
# 单个关键词
curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/search?pageSize=5" --data-urlencode "keyword=客单价" -G
# 多个关键词(逗号分隔,中英文逗号均可)
curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/search?pageSize=3" --data-urlencode "keyword=客单价,销售额" -G
返回纯文本格式(已过滤非 ONLINE 指标),每行一个指标:
text
[客单价] 3 metric(s):
- AOV | 客单价 | 销售金额/购买客户数 (53 dims)
- l7d_AOV | 近7天客单价 [DERIVED] (53 dims)
[销售额] 2 metric(s):
- retail_amt | 销售金额 | 销售金额求和 (53 dims)
AOV 是 metricName,放入 metrics 数组[DERIVED] = 派生指标, (53 dims) = 可用维度数量每次构建都做以下检查:
[DERIVED] 指标使用前必须确认其展示名语义与用户意图 完全一致。对 Step 1 选定的指标,调用 Gateway 获取可用维度。 支持单指标和批量指标两种方式:
bash
# 单指标维度(路径参数直接用 metricName)
curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/AOV/dimensions"
# 单指标 + keyword 过滤(大幅减少返回量,keyword 支持逗号分隔多关键词,匹配任一即返回)
curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/AOV/dimensions" --data-urlencode "keyword=渠道" -G
# 多关键词过滤维度(同时搜索多个维度方向,匹配维度名/展示名/描述/维度值样本中任一关键词)
curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/AOV/dimensions" --data-urlencode "keyword=渠道,地区,品牌" -G
# 批量指标维度(逗号分隔,自动计算维度交集,keyword 同样支持多关键词)
curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/dimensions?metricNames=AOV,retail_amt" --data-urlencode "keyword=渠道" -G
单指标返回格式:
text
Metric '客单价' (AOV), 53 dimension(s):
- first_channel(一级渠道): Direct, E-commerce, Retail, Wholesale
- gender(性别): 女, 男
批量指标返回格式(包含各指标维度 + 交集):
text
## 客单价 (AOV), 2 dim(s):
- first_channel(一级渠道): Direct, E-commerce, Retail, Wholesale
- second_channel(二级渠道): Offline, Online
## 销售金额 (retail_amt), 2 dim(s):
- first_channel(一级渠道): Direct, E-commerce, Retail, Wholesale
- second_channel(二级渠道): Offline, Online
## COMMON dimensions (intersection), 2 dim(s):
- first_channel(一级渠道): Direct, E-commerce, Retail, Wholesale
- second_channel(二级渠道): Offline, Online
first_channel 是 dimName,放入 dimensions / filters⚠️ 优先使用 keyword 过滤:当用户提到了具体的维度名或维度值(如"渠道""淘宝""女装"),用 keyword 参数过滤,只返回匹配的维度。 keyword 支持逗号分隔多关键词(中英文逗号均可),匹配任一关键词即返回该维度,适合一次性搜索多个维度方向(如 keyword=渠道,地区,品牌)。匹配范围包括维度名、展示名、描述和维度值样本。
⚠️ 多指标查询必须用批量接口:一次拿到交集,避免多次调用。
每次构建都做以下检查:
从返回结果中取 dimName(行首英文名)放入 dimensions / filters
维度兼容性:dimensions 中的 每一个 维度都必须出现在该指标的返回列表中
__day, __month, __year 等)按指标类型限制:DERIVED 类型的时间限定派生指标通常仅支持 __day 粒度维度值匹配:用 keyword 搜维度值可直接定位维度。例如用户说"淘宝" → 搜 keyword=淘宝 → 返回 order_platform_code(订单来源平台): ..., 天猫淘宝, ...,直接用 order_platform_code 维度,filter 值为 天猫淘宝
维度值精确抄写(⚠️ 极易出错):构建 filters 和 resultFilters 时, 必须严格按返回的维度值样本原始写法 填写,包括大小写、空格、标点符号
contains() 模糊匹配或告知用户值可能不存在请求体为标准 JSON。 所有字符串值内部的双引号必须转义为 \"。
json
"filters": ["[dim_A]= \"value_1\""]
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = \"2025-04-01\""
json
"metrics": ["metric_A", "metric_B"]
快速计算不可链式叠加(铁律 5): 每个指标只能应用 一次 快速计算。需要多步计算时用 metricDefinitions 分步。
语法: {指标}__sameperiod__{偏移粒度}__{方法}
偏移粒度:
用户说偏移粒度用户说偏移粒度日环比dod对比上月末moeom周环比wow对比上季末qoeoq月环比mom对比去年末yoeoy季环比qoq对比上月初mosom年同比yoy对比去年初yosoy
所有偏移粒度支持 {N}_ 前缀(如 -2_yoy = 2年前同期)。
选择规则: "同比"→详见铁律 4;"环比"→按粒度选
dod/wow/mom/qoq。 仅当 用户明确说"对比XX期末/期初"时才用期末/期初偏移。
方法:
用户说方法计算同期/环比的值value对比期原值增长了多少growthvalue当前 − 对比增长率/增速growth(当前 − 对比) / 对比下降了多少decrease对比 − 当前下降率decreaserate(对比 − 当前) / 对比
约束: metric_time 须在 dimensions 或 timeConstraint 中出现;偏移粒度不可小于 metric_time 粒度;期末/期初偏移仅 metric_time__day 粒度可用。
已有时间限定指标叠加同环比: 候选指标中名称含时间限定后缀(如 _ytd、 _mtd 等)的派生指标,可以叠加 __sameperiod__ 快速计算,但必须:dimensions 含 metric_time__day,有 timeConstraint 锚定具体日期。 推荐用 metricDefinitions + period + indirections 替代,语义更清晰。
语法: {指标}__proportion__{范围维度}
数学含义: 占比 = 当前行值 / 范围维度分组的汇总值
范围维度写法分母proportion__(⚠️ 末尾有 两个下划线,后面无维度名)全部数据汇总(全局占比)proportion__dim_A按 dim_A 每组分别汇总(组内占比)
选择规则: 问"这一行占 谁 的比"。"占总体"→留空;"占 A 组内"→填 A。
⚠️ 前提条件 — dimensions 必须包含参与占比计算的维度: 使用 proportion__(全局占比)时,参与占比计算的实体维度(如渠道、品牌) 必须 出现在 dimensions 中,否则系统无法按该维度分组计算占比。
"dimensions": [] + proportion__ → 没有分组维度,无法计算占比"dimensions": ["first_channel"] + proportion__ → 按渠道分组,计算各渠道全局占比⚠️ 陷阱一 — 恒为 100%: 范围维度覆盖了 dimensions 中所有非日期维度时,每行分母就是自己,占比恒为 100%。例如 dimensions: ["dim_A"] + proportion__dim_A → 100%。应改用 proportion__。
⚠️ 陷阱二 — filters 缩小分母: filters 在占比计算 前 过滤数据。如果用 filters 只留一个维度值,再算 proportion__,分母只有该值自身,占比恒为 100%。正确做法:用 resultFilters 做展示筛选。详见 §3.4 和示例 5.12。
语法: {指标}__{方式}__{顺序}__{范围维度}
rank(并列跳号)、 rankDense(并列不跳)、 rowNumber(不并列)desc(大=1)、 asc(小=1)陷阱与占比完全相同: 范围维度覆盖所有非日期维度 → 恒为 1;filters 缩小范围 → 排名失真。用 resultFilters 做展示筛选。
语法: {指标}__period__{限定}
类型语法示例近N期7d, 3w, 6m, 2q, 1y本期至今ytd, qtd, mtd, wtd当前期间cy, cq, cm, cw, cd
约束: 被引用指标不能已有时间限定; 必须有明确的时间锚定(timeConstraint 或 dimensions 中的 metric_time)。
⚠️ 核心规则(铁律 2)— 必须双重注册: metricDefinitions 中的 每一个 key 都必须同时出现在 metrics 数组中(含辅助指标)。
临时指标命名: 必须与所有已有指标名称不同,避免命名冲突。建议加业务前缀/后缀以示区分。
json
"metrics": ["my_temp_metric"],
"metricDefinitions": {
"my_temp_metric": { "refMetric": "metric_A", ... }
}
可配置属性:
属性说明约束refMetric引用已有指标expr复合表达式 "[m1]+[m2]"可引用其他临时指标period时间限定仅支持相对偏移; of 后锚定粒度不可细于 timeConstraint 粒度metricGrain时间粒度DAY/WEEK/MONTH/QUARTER/YEARpreAggs时间维度多层聚合格式为数组 [{...}];必须配合 periodfilters业务限定支持维度筛选和 MetricMatchesindirections衍生方式同环比/占比/排名/多层聚合specifyDimension聚合维度控制EXCLUDE 排除外层分组影响
仅支持相对日期偏移,基于 timeConstraint 锚定的日期做偏移。
of 后锚定粒度规则: of 后的粒度 不可细于 timeConstraint 锚定粒度。
of 可用 day、 week、 month、 quarter、 yearof 可用 month、 quarter、 year( 不可用 day、 week)to_date(区间:偏移日 ~ 锚定日):
text
"to_date -6 day of 0 day" → 基准日前6天 ~ 基准日(共7日)
"to_date -29 day of 0 day" → 共30日
"to_date -7 day of -1 day" → 基准日前8天 ~ 前1天(共7日,不含基准日)
grain_to_date(某粒度起点 ~ 锚定点):
text
"grain_to_date 0 year of 0 day" → 本年初 ~ 基准日(本年至今)
"grain_to_date 0 month of 0 day" → 本月初 ~ 基准日(本月至今)
"grain_to_date -1 year of -1 day" → 去年初 ~ 去年的基准日前1天
"grain_to_date 0 year of 0 month" → 本年初 ~ 基准月(锚定到月时)
relative_date(单一日期/月定位):
text
"relative_date 0 month of 0 day" → 基准日所在月
"relative_date -1 month of 0 day" → 上月
"relative_date -5 month of 0 month" → 5个月前(锚定到月时)
SPECIFY_DATE(期初/期末定位):
text
"SPECIFY_DATE start day of -1 year" → 上年第一天
"SPECIFY_DATE end day of -1 month" → 上月最后一天
"SPECIFY_DATE end day of -1 year" → 上年最后一天
"SPECIFY_DATE end month of -1 year" → 上年最后一个月
period 与 timeConstraint 配合:
of 0 day 表示该天of 0 month 表示该月relative_date -5 month of 0 month 定位1月格式为数组,必须配合 period。
json
"preAggs": [{"granularity": "DAY", "calculateType": "AVG"}]
granularity: DAY / WEEK / MONTH / QUARTER / YEARcalculateType: AVG / MAX / MIN典型场景: "近30天日均" = period 限定30天 + preAggs 按 DAY 求 AVG。
⚠️ preAggs 与 dimensions 中的时间粒度: 使用 preAggs 按 DAY 聚合时, 不要 在外层 dimensions 中放 metric_time__day。preAggs 已经按日聚合再取 AVG/MAX/MIN,如果外层再按天展开,等于没有聚合。同理,preAggs 按 MONTH 聚合时不要在 dimensions 中放 metric_time__month。
preAggs + 同比: 含 preAggs 时不能直接叠加 __sameperiod__。须分别定义今年和去年的临时指标(各自含 period + preAggs),再用 expr 计算增长率。见示例 5.13。
临时指标可附加维度筛选:
json
"my_metric": {
"refMetric": "metric_A",
"filters": ["[dim_X]= \"value_1\""]
}
MetricMatches — 基于指标值筛选维度值,再用筛选后的维度值计算指标:
MetricMatches([维度名], [指标名] 运算符 值)
MetricMatches vs resultFilters: 同指标筛选("指标A≥某值的维度有哪些")→ resultFilters;跨指标筛选("指标A≥某值的维度有多少个"→ 用 A 筛维度值,再算 B)→ MetricMatches。
MetricMatches 约束: 每个 MetricMatches 仅支持一个指标条件。多指标条件须拆分为多个 MetricMatches(数组内为 AND):
json
"filters": [
"MetricMatches([dim_X], [metric_C] > 30)",
"MetricMatches([dim_X], [metric_D] < 0.2)"
]
text
"indirections": ["sameperiod__yoy__value"] → 年同比
"indirections": ["proportion__dim_A"] → dim_A 组内占比
"indirections": ["rank__desc__dim_A"] → dim_A 组内排名
"indirections": ["multi_level_agg__avg,dim_A"] → 非时间维度多层聚合
多层聚合选择: 时间维度多层聚合 → preAggs + period;非时间维度多层聚合 → indirections 的 multi_level_agg。
period + indirections 组合(推荐): 不含 preAggs 的 period 指标做同环比 → 用 period + indirections: ["sameperiod__yoy__growth"]。含 preAggs 时不可用此组合,须手动分两步 + expr。
multi_level_agg 与外层 dimensions 冲突: 当聚合维度同时在外层 dimensions 中时,结果恒等于自身。必须添加 specifyDimension: { "type": "EXCLUDE", "dimensions": "dim_X" }。
日期维度支持粒度后缀: __year, __quarter, __month, __week, __day。
⚠️ 粒度后缀必须全部小写: 维度名中的粒度后缀( __day, __month, __year, __week, __quarter) 必须使用小写字母。这是 API 的硬性要求,大写会导致查询失败或返回空结果。
metric_time__day, metric_time__month, metric_time__yearmetric_time__DAY, metric_time__MONTH, metric_time__YEAR(大写后缀 = 错误)同理,orders 中引用维度名时也必须保持小写:
{"metric_time__day": "asc"}{"metric_time__DAY": "asc"}json
"dimensions": ["metric_time__month", "dim_A"]
⚠️ 维度兼容性校验: 多指标查询时,dimensions 只能包含 所有指标都支持的维度(取交集)。详见 §1 候选指标表检查 3。
filters****resultFilters等价于SQL WHERESQL HAVING影响计算过程(分母、排名范围都会被影响)仅过滤返回行
选择规则:
timeConstraint(⚠️ 禁止放 filters)resultFiltersfiltersresultFiltersfilters 语法:
text
[dim_A]= "value" 精确匹配
IN([dim_A], "v1", "v2") 包含
NotIn([dim_A], "v1") 排除
contains([dim_A], "x") 模糊
[dim_num]>= 100 数值比较
['date_dim']>= "2023-08-01" 日期比较
resultFilters 语法:
json
"resultFilters": ["[metric_M] > 1000"]
"resultFilters": ["[metric_M__sameperiod__mom__growth] > 0.05"]
"resultFilters": ["[dim_A]= \"value_1\""]
timeConstraint 有 两个不同的角色,构建时必须区分:
角色说明形式角色 A:时间范围过滤限定"查哪段时间的数据"一个区间(如近7天、上月)角色 B:period 锚定基准给 period/sameperiod 提供相对偏移的基准点一个具体日期或月份
📋 timeConstraint 速查表(根据用户时间表达直接查表复制):
用户说timeConstraint昨天"['metric_time__day']= DATEADD(DateTrunc(NOW(), \"DAY\"), -1, \"DAY\")"今天"['metric_time__day']= DateTrunc(NOW(), \"DAY\")"上周"DateTrunc(['metric_time'], \"WEEK\") = DATEADD(DateTrunc(NOW(), \"WEEK\"), -1, \"WEEK\")"本周"DateTrunc(['metric_time'], \"WEEK\") = DateTrunc(NOW(), \"WEEK\")"上月"DateTrunc(['metric_time'], \"MONTH\") = DATEADD(DateTrunc(NOW(), \"MONTH\"), -1, \"MONTH\")"本月"DateTrunc(['metric_time'], \"MONTH\") = DateTrunc(NOW(), \"MONTH\")"上季"DateTrunc(['metric_time'], \"QUARTER\") = DATEADD(DateTrunc(NOW(), \"QUARTER\"), -1, \"QUARTER\")"本季"DateTrunc(['metric_time'], \"QUARTER\") = DateTrunc(NOW(), \"QUARTER\")"本年"DateTrunc(['metric_time'], \"YEAR\") = DateTrunc(NOW(), \"YEAR\")"去年"DateTrunc(['metric_time'], \"YEAR\") = DATEADD(DateTrunc(NOW(), \"YEAR\"), -1, \"YEAR\")"近7天"DateTrunc(['metric_time'], \"DAY\") >= DATEADD(DateTrunc(NOW(), \"DAY\"), -7, \"DAY\") AND ['metric_time__day'] < DateTrunc(NOW(), \"DAY\")"近30天"DateTrunc(['metric_time'], \"DAY\") >= DATEADD(DateTrunc(NOW(), \"DAY\"), -30, \"DAY\") AND ['metric_time__day'] < DateTrunc(NOW(), \"DAY\")"近12个月"DateTrunc(['metric_time'], \"MONTH\") >= DATEADD(DateTrunc(NOW(), \"MONTH\"), -12, \"MONTH\") AND DateTrunc(['metric_time'], \"MONTH\") < DateTrunc(NOW(), \"MONTH\")"2025年4月(具体月份)"DateTrunc(['metric_time'], \"MONTH\") = \"2025-04-01\""2025-06-15(具体日期)"['metric_time__day']= \"2025-06-15\""
⚠️ 表中除最后两行外,全部使用 NOW()(详见铁律 1)。只有用户指定了具体日期/月份才用字面日期。
用户未指定时间时的默认策略(⚠️ 从上到下匹配,命中第一行即停止):
优先级条件默认 timeConstraint说明1查询中有 period / __period__ / 已有时间限定派生指标锚定昨天(角色 B)period 自身定义时间窗口,timeConstraint 只提供基准点2查询中有 __sameperiod__mom__上月3查询中有 __sameperiod__wow__上周4查询中有 __sameperiod__qoq__上季5查询中有 __sameperiod__yoy__上月6查询中有 __sameperiod__dod__昨天7查询中有排名/TOP-N 且无时间维度近 30 天或上月排名需足够数据量8dimensions 含 metric_time__month近 12 个月9dimensions 含 metric_time__quarter本年10dimensions 含 metric_time__week近 12 周11其他近 7 天
⚠️ 排名/TOP-N 查询的时间范围: 当用户问"TOP10商品""排名前5的XX"但未指定时间时,默认用 近 30 天 或 上月(而非近 7 天)。原因:排名类查询需要足够数据量才有统计意义,7 天可能样本不足。
⚠️ 不可双重偏移: 当 timeConstraint 已限定到某时段(如"上季度"),metricDefinitions 的 period 不应再做同方向的额外偏移,否则会叠加成"上上季度"。正确做法:timeConstraint 锚定基准,period 从基准点偏移到目标。
orders — 排序列须在 metrics 或 dimensions 中:
json
"orders": [{"metric_time__day": "asc"}, {"metric_M": "desc"}]
limit(默认100)/ offset(默认1)
queryResultType — SQL_AND_DATA(默认)/ SQL / DATA
API Json 查询请求体的构建思路,需要记录以下关键决策:
按 §0 将用户问题拆解为"看什么 / 怎么看 / 看谁的 / 看哪段时间"四维度,并逐条检查 §0.1 的 9 条消歧规则(A~I)。
输出:明确的指标列表、分析方式、维度筛选需求、时间范围。
从用户问题中提取核心业务关键词,调用 Gateway API 搜索指标:
bash
curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/search?pageSize=10" --data-urlencode "keyword={关键词}" -G
从返回结果中取 metricName 放入 metrics 数组。 校验: status 须为 ONLINE。
决策点:
候选中有"看似相关"的已有派生指标( type=DERIVED)?→ 查看其 displayName 的完整描述,验证其语义是否与用户意图完全一致。常见误用场景:
用户说了"日均""月均"?→ 按规则 B 判断修饰范围,确保所有被修饰的指标都有对应的 preAggs 处理
如果搜索结果为空或不匹配,尝试更换关键词重新搜索(如"销售额"搜不到可试"销售金额")
对步骤 1 选定的指标,调用 Gateway API 获取可用维度:
bash
curl -H "X-API-Key: $CAN_API_KEY" "https://gateway.can.aloudata.com/api/metrics/{metricCode}/dimensions"
从返回结果中取 dimName 作为维度名称。返回的维度列表即该指标的 全部可分析维度。
决策点:
sampleValues 判断用户提到的值属于哪个维度。例如用户说"淘宝" → 查看各维度的 sampleValues,发现 订单来源平台 包含"天猫淘宝" → 使用 order_platform_code,filter 值为"天猫淘宝"同环比: 按规则 E 选择偏移粒度;按规则 F 区分"同比" vs "对比期末"。
占比: 确定范围维度后,执行以下检查:
text
范围维度是否覆盖了 dimensions 中所有非日期维度?
├─ 是 → 恒为 100%!改为 proportion__(全局占比)或调整范围维度
└─ 否 → OK
排名: 同上检查恒为 1。
跨时段对比、自定义计算、附加业务限定 → 使用 metricDefinitions。
校验:
of 后粒度不细于 timeConstraint 锚定粒度?[{...}] 且配合了 period?filters vs resultFilters 决策树:
text
需要筛选?
│
├─ 筛选字段是指标值或计算结果?
│ └─ 是 → resultFilters
│
├─ 查询涉及占比或排名?
│ ├─ 是 → 该筛选是否应影响占比分母/排名范围?
│ │ ├─ 是(如"某渠道内各品牌占比"→ 该渠道限定范围) → filters
│ │ └─ 否(如"某渠道在所有渠道中的占比"→ 只展示该渠道) → resultFilters
│ └─ 否 → filters
│
└─ 普通维度值筛选 → filters
校验: 筛选值须与 dimensions.csv 维度值一致。
按 §3.5 的默认策略决策树,确定 timeConstraint 的形式和值。
校验:
排序列须在 metrics 或 dimensions 中。rank 排序用 asc(排名小=好)。
生成 JSON 后,逐项检查:
\" 转义of 后粒度不细于 timeConstraint 锚定粒度NOW(),未硬编码日期(铁律 1)metric_time__month;TOP-N 排序指标正确-d @- <<'EOF')传递 JSON body, 禁止 用 -d '...' 单引号包裹( ['metric_time'] 中的单引号会导致 shell 解析错误或产生非法转义如 \x27)每次执行指标查询时,必须向用户展示完整的查询请求 JSON 体。
在通过 curl 执行查询时,必须以格式化的 JSON 代码块向用户展示本次发送的请求体,格式如下:
text
📋 **查询请求 JSON:**
```json
{
"metrics": [...],
"dimensions": [...],
...
}
```
具体要求:
上周某维度值每天的 metric_A,按日期升序:
json
{
"metrics": ["metric_A"],
"dimensions": ["metric_time__day"],
"filters": ["[dim_A]= \"value_1\""],
"timeConstraint": "DateTrunc(['metric_time'], \"WEEK\") = DATEADD(DateTrunc(NOW(), \"WEEK\"), -1, \"WEEK\")",
"orders": [{"metric_time__day": "asc"}]
}
上月 A渠道和 B 渠道销售金额:
json
{
"metrics": ["retail_amt"],
"dimensions": ["channel"],
"filters": ["IN([channel], \"A\", \"B\")"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = DATEADD(DateTrunc(NOW(), \"MONTH\"), -1, \"MONTH\")",
"limit": 100,
"offset": 1
}
上月各 dim_A 的 metric_A 及月环比增长率,增速前10名:
json
{
"metrics": ["metric_A", "metric_A__sameperiod__mom__growth"],
"dimensions": ["dim_A"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = DATEADD(DateTrunc(NOW(), \"MONTH\"), -1, \"MONTH\")",
"orders": [{"metric_A__sameperiod__mom__growth": "desc"}],
"limit": 10
}
上月各 dim_A 的 metric_A 占总体的比例:
json
{
"metrics": ["metric_A", "metric_A__proportion__"],
"dimensions": ["dim_A"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = DATEADD(DateTrunc(NOW(), \"MONTH\"), -1, \"MONTH\")"
}
今年各 dim_A 的 metric_A 月内占比和月内排名趋势:
json
{
"metrics": [
"metric_A",
"metric_A__proportion__metric_time__month",
"metric_A__rank__desc__metric_time__month"
],
"dimensions": ["metric_time__month", "dim_A"],
"timeConstraint": "DateTrunc(['metric_time'], \"YEAR\") = DateTrunc(NOW(), \"YEAR\")",
"orders": [{"metric_time__month": "asc"}]
}
注意:范围维度是 metric_time__month(每月内比较各 dim_A),不是 dim_A(否则每个 dim_A 值只有自己,恒 100%/恒为 1)。
某年5月 vs 2月各 dim_A 的 metric_A 增幅(⚠️ 此处用字面日期因为用户指定了具体月份):
json
{
"metrics": ["may_val", "feb_val", "growth_rate"],
"metricDefinitions": {
"may_val": {
"refMetric": "metric_A",
"period": "relative_date 0 month of 0 month"
},
"feb_val": {
"refMetric": "metric_A",
"period": "relative_date -3 month of 0 month"
},
"growth_rate": { "expr": "([may_val]-[feb_val])/[feb_val]" }
},
"dimensions": ["dim_A"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = \"2025-05-01\"",
"orders": [{"growth_rate": "desc"}]
}
某个指定日期的近11天日均 metric_A(⚠️ 此处用字面日期因为锚定到特定日期):
json
{
"metrics": ["daily_avg"],
"metricDefinitions": {
"daily_avg": {
"refMetric": "metric_A",
"period": "to_date -10 day of 0 day",
"preAggs": [{"granularity": "DAY", "calculateType": "AVG"}]
}
},
"timeConstraint": "['metric_time__day']= \"2024-11-11\""
}
上月 metric_A ≥ 某阈值的 dim_X 数量(用 metric_B 计数):
json
{
"metrics": ["filtered_cnt"],
"metricDefinitions": {
"filtered_cnt": {
"refMetric": "metric_B",
"filters": ["MetricMatches([dim_X], [metric_A] >= 10000)"]
}
},
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = DATEADD(DateTrunc(NOW(), \"MONTH\"), -1, \"MONTH\")"
}
某个指定月份 metric_A 在指定范围内的 dim_A 及排名(⚠️ 字面日期:用户指定了具体月份):
json
{
"metrics": ["metric_A", "metric_A__rank__desc"],
"dimensions": ["dim_A"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = \"2025-12-01\"",
"resultFilters": ["[metric_A] >= 300000 AND [metric_A] <= 500000"],
"orders": [{"metric_A": "desc"}]
}
上季度某筛选条件下的 dim_X 均 metric_A:
json
{
"metrics": ["avg_per_dim_X"],
"metricDefinitions": {
"avg_per_dim_X": {
"refMetric": "metric_A",
"indirections": ["multi_level_agg__avg,dim_X"]
}
},
"filters": ["[dim_B]= \"value_1\"", "[dim_C]= \"value_2\""],
"timeConstraint": "DateTrunc(['metric_time'], \"QUARTER\") = DATEADD(DateTrunc(NOW(), \"QUARTER\"), -1, \"QUARTER\")"
}
近7天和近30天某筛选条件下的 metric_A:
json
{
"metrics": ["val_7d", "val_30d"],
"metricDefinitions": {
"val_7d": {
"refMetric": "metric_A",
"period": "to_date -6 day of 0 day",
"filters": ["[dim_A]= \"value_1\""]
},
"val_30d": {
"refMetric": "metric_A",
"period": "to_date -29 day of 0 day",
"filters": ["[dim_A]= \"value_1\""]
}
},
"timeConstraint": "['metric_time__day']= DATEADD(DateTrunc(NOW(), \"DAY\"), -1, \"DAY\")"
}
某月各 dim_A、dim_B 的 metric_A,及 dim_A 组内排名和全局排名:
json
{
"metrics": [
"metric_A",
"metric_A__rank__desc__dim_A",
"metric_A__rank__desc"
],
"dimensions": ["metric_time__day", "dim_A", "dim_B"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = DateTrunc(NOW(), \"MONTH\")",
"limit": 100
}
上月 dim_A 某值的 metric_A 全局占比:
✅ 正确:
json
{
"metrics": ["metric_A", "metric_A__proportion__"],
"dimensions": ["dim_A"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = DATEADD(DateTrunc(NOW(), \"MONTH\"), -1, \"MONTH\")",
"resultFilters": ["[dim_A]= \"value_1\""]
}
❌ 错误(占比恒为 100%):
json
{
"filters": ["[dim_A]= \"value_1\""],
"metrics": ["metric_A", "metric_A__proportion__"],
"dimensions": ["dim_A"]
}
原因: filters 在计算前过滤掉其他值,分母只剩 value_1 自身。
本年至今日均 metric_A 及年同比:
json
{
"metrics": ["ytd_daily_avg", "ly_ytd_daily_avg", "yoy_growth"],
"metricDefinitions": {
"ytd_daily_avg": {
"refMetric": "metric_A",
"period": "grain_to_date 0 year of 0 day",
"preAggs": [{"granularity": "DAY", "calculateType": "AVG"}]
},
"ly_ytd_daily_avg": {
"refMetric": "metric_A",
"period": "grain_to_date -1 year of -1 day",
"preAggs": [{"granularity": "DAY", "calculateType": "AVG"}]
},
"yoy_growth": {
"expr": "([ytd_daily_avg]-[ly_ytd_daily_avg])/[ly_ytd_daily_avg]"
}
},
"timeConstraint": "['metric_time__day']= DATEADD(DateTrunc(NOW(), \"DAY\"), -1, \"DAY\")"
}
本年至今 metric_A 及年同比(不含 preAggs 时的推荐写法):
json
{
"metrics": ["ytd_val", "ytd_val_ly", "ytd_yoy_growth"],
"metricDefinitions": {
"ytd_val": {
"refMetric": "metric_A",
"period": "grain_to_date 0 year of 0 day"
},
"ytd_val_ly": {
"refMetric": "metric_A",
"period": "grain_to_date 0 year of 0 day",
"indirections": ["sameperiod__yoy__value"]
},
"ytd_yoy_growth": {
"refMetric": "metric_A",
"period": "grain_to_date 0 year of 0 day",
"indirections": ["sameperiod__yoy__growth"]
}
},
"timeConstraint": "['metric_time__day']= DATEADD(DateTrunc(NOW(), \"DAY\"), -1, \"DAY\")"
}
某个指定季度各 dim_A 的 metric_A 与全局平均值的对比(⚠️ 字面日期:用户指定了具体季度):
json
{
"metrics": ["metric_A", "global_avg"],
"metricDefinitions": {
"global_avg": {
"refMetric": "metric_A",
"indirections": ["multi_level_agg__avg,dim_A"],
"specifyDimension": { "type": "EXCLUDE", "dimensions": "dim_A" }
}
},
"dimensions": ["dim_A"],
"timeConstraint": "DateTrunc(['metric_time'], \"QUARTER\") = \"2025-01-01\""
}
注意:缺少 specifyDimension 时,每个 dim_A 分组内只有自己,均值恒等于自身值。
上月各渠道销售额环比增速前3的品牌(先算环比再排名, 禁止链式叠加):
json
{
"metrics": ["retail_amt", "mom_growth", "mom_growth__rankDense__desc__first_channel"],
"metricDefinitions": {
"mom_growth": {
"refMetric": "retail_amt",
"indirections": ["sameperiod__mom__growth"]
}
},
"dimensions": ["first_channel", "product_brand_name"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = DATEADD(DateTrunc(NOW(), \"MONTH\"), -1, \"MONTH\")",
"resultFilters": ["[mom_growth__rankDense__desc__first_channel] <= 3"],
"orders": [{"first_channel": "asc"}, {"mom_growth__rankDense__desc__first_channel": "asc"}]
}
关键: retail_amt__sameperiod__mom__growth__rankDense__desc__first_channel 是链式叠加(违反铁律5)。正确做法是先定义环比临时指标 mom_growth,再对它做排名快速计算。
2025年4月 Wholesale 渠道的销售额、年同比、渠道内占比、渠道内排名:
json
{
"metrics": [
"retail_amt",
"retail_amt__sameperiod__yoy__growth",
"retail_amt__proportion__",
"retail_amt__rankDense__desc"
],
"dimensions": ["first_channel"],
"timeConstraint": "DateTrunc(['metric_time'], \"MONTH\") = \"2025-04-01\"",
"resultFilters": ["[first_channel]= \"Wholesale\""]
}
关键: 渠道内占比和排名需要所有渠道参与计算,所以 Wholesale 筛选必须放在 resultFilters(而非 filters)。如果用 filters 筛选 Wholesale,分母/排名范围只剩自己,占比恒 100%、排名恒 1。
模式现象对应规则1. 占比恒为 100%proportion 结果全为 100%铁律 3 + §3.1.2 陷阱一/二2. 排名恒为 1rank 结果全为 1铁律 33. 硬编码日期替代 NOW()timeConstraint 出现 DateTrunc('YYYY-MM-DD', ...)铁律 14. 临时指标未加入 metrics临时指标在结果中缺失铁律 25. 时间条件放在 filters时间过滤不生效§3.4 选择规则 16. MetricMatches 放在顶层 filters查询报错铁律 67. 链式快速计算metric__sameperiod__mom__growth__rank__desc__dim铁律 5 + 示例 5.168. 占比缺少分组维度dimensions 为空但使用 proportion__§3.1.2 前提条件9. 粒度后缀大小写错误metric_time__DAY 导致报错§3.3 小写规则10. 非查询消息生成无效请求体"你好"生成空 metrics 请求体铁律 9 检查 C11. 幻觉指标使用候选表外的指标名铁律 9 检查 A12. 维度不兼容使用指标不支持的维度铁律 9 检查 B13. 该拒不拒上下文不足仍硬凑查询铁律 9
❌ 模式 14:timeConstraint + period 双重偏移 timeConstraint 已偏移到目标时段,period 又额外偏移 → 叠加成"上上期"。正确做法:timeConstraint 锚定基准,period 从基准点偏移到目标。
❌ 模式 15:临时指标命名冲突 metricDefinitions 中临时指标名与已有指标重名 → 查询行为不可预测。临时指标名加业务前缀/后缀以示区分。
❌ 模式 16:用错已有派生指标 已有派生指标的语义(展示名描述的实体、范围、时间口径)与用户意图不匹配。 必须回到候选指标表核查展示名描述,不匹配时改用原子指标 + 快速计算。
❌ 模式 17:累计指标当当期指标 用了"至今累计"类派生指标做月度/日度趋势,导致值逐月递增。趋势场景用原始指标 + 时间粒度维度。
❌ 模式 18:候选维度不足时强行替代 候选维度中无用户要的实体维度,模型用不相关维度替代。应在 buildReason 中说明缺失,不强行替代。
❌ 模式 19:preAggs 时 dimensions 含同粒度时间维度
preAggs 按 DAY 聚合但 dimensions 有 metric_time__day → 先按日展开再取均值,日均=原值。preAggs 聚合粒度不应与 dimensions 时间粒度相同。
❌ 模式 20:多指标查询未校验维度兼容性 多个指标的可分析维度不同时,必须取交集。特别注意"所有维度"标注的指标与有限列表指标混用的场景。
❌ 模式 21:维度值大小写/格式不匹配
filters 中的维度值与候选维度表不一致(如 "e-commerce" vs "E-commerce"; "2025 新款" vs "2025新款")。 必须严格按候选维度表原始写法。
❌ 模式 22:用户问总量却添加了不必要的 dimensions
用户问"上月销售额是多少"(总数),dimensions 应为空。 ⚠️ 例外: 问题含" 每天/每日/分天/分日/每一天"时应添加 metric_time__day。
❌ 模式 23:"日均"误用 metric_time__day 维度替代 preAggs
"日均" = metricDefinitions + period + preAggs [{"granularity": "DAY", "calculateType": "AVG"}], 不是 在 dimensions 中加 metric_time__day。
❌ 模式 24:"近N年"时间范围缺少上界
"近3年"须同时有下界和上界: >= DATEADD(DateTrunc(NOW(), "YEAR"), -3, "YEAR") AND < DateTrunc(NOW(), "YEAR")。
❌ 模式 25:排名/TOP-N 按错误指标排序 排序指标必须与用户关注的指标一致。TOP-N 默认按 用户提到的第一个指标 desc 排序。