拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Metabase Metabot 核心技能解读:用 `construct_notebook_query` 以 MBQL 5 JSON 构建 Notebook 查询

Metabase Metabot 核心技能解读用construct_notebook_query以 MBQL 5 JSON 构建 Notebook 查询【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase本指南围绕 Metabase 开源仓库中面向 AI AgentMetabot的技能文档 construct-notebook-query-core.md 展开完整讲解如何通过construct_notebook_query工具将自然语言需求翻译为一段 MBQL 5Metabase 查询语言JSON 描述交给 Metabase 校验、修复与执行。读完本文你将掌握该工具的调用契约、子句形状、字段引用规则、最小可行示例以及最容易触发的反模式并理解这些规则背后的服务端实现管线可直接用于二次开发、Agent 集成或排查构造出的查询不可运行类问题。技能定位为什么要在首次构造查询前加载construct-notebook-query-core是 Metabase AgentMetabot技能体系中的一份核心技能skill其 frontmatter 中标注了id: construct-notebook-query-core、tools: [construct_notebook_query]、priority: 60。从 skills.clj 的实现可以看到技能通过load_skill工具按需加载返回形如skill id....../skill的指令体注入对话流。该技能在描述中明确要求在你第一次构造查询之前加载它以便先掌握子句形状、字段引用以及规则/反模式避免在首个查询上就犯错。它并不是孤立文档而是三份配套技能之一construct-notebook-query-core本文主体子句形状、字段引用、基础规则与反模式对应[op, {}, ...args]通用形态与 portable FKconstruct-notebook-query-advancedjoin显式/隐式、多阶段查询、source-card、metrics/measures/segments、表达式与聚合引用construct-notebook-query-operators完整的聚合、过滤、表达式与时间分桶算子目录。其最终真相位于 src/metabase/lib/schema/ 下的aggregation.cljc、filter.cljc、temporal_bucketing.cljc与expression/*.cljc。理解这一点很重要技能文档是给 LLM 看的速查手册而 malli schema 才是服务端实际校验的依据。工具契约query/title/description/visualization调用construct_notebook_query需要返回四个字段其中只有visualization可选字段必填说明query是一个 JSON对象绝不能是带引号的字符串。目标数据库从第一个 stage 的source-table或source-card推断因此要使用 search /read_resource/ 元数据工具报告的精确数据库名title是简短、人类友好的查询名称写法类似一个已保存问题的名称description是一句话描述查询返回什么visualization否可选的{chart_type: bar}是query的兄弟字段绝不能内嵌进query里从源码看这个契约与 construct.clj 中的construct-notebook-query-args-schema一一对应[:query [:map {:json-schema ...}]]、[:title :string]、[:description :string]、可选[:visualization construct-visualization-schema]。值得注意的是args schema 对:query只断言是 map真正的结构校验发生在入口边界HTTP defendpoint 的 string-transformer 与lib.normalize/normalize ::lib.schema/query这正是为了让修复层repair有机会补救 LLM 常见的手误如缺失{}选项位。另外工具定义处还有一段手写的 JSON Schemaconstruct-notebook-query-json-schema见 construct.clj它不参与校验只是替换呈现给 LLM 的 schema 描述——因为 malli 对开放的 property-less map 会输出空properties弱模型如 gpt-4.1-mini会误读为该对象没有字段而返回{}。这一实现细节解释了为什么技能文档里反复强调query 是 JSON 对象而非字符串。Slackbot 变体的差异注意该工具的 Slackbot 变体契约不同——reasoning必填、title可选、没有description且使用displaySlack 专用的可视化类型枚举代替visualization。详见 Slackbot 系统提示词仓库中的 slackbot.selmer 与 streaming.clj。最小示例按月统计订单数量技能文档给出的最小完整查询如下{lib/type: mbql/query, stages: [{lib/type: mbql.stage/mbql, source-table: [Sample Database, PUBLIC, ORDERS], aggregation: [[count, {}]], breakout: [[field, {temporal-unit: month}, [Sample Database, PUBLIC, ORDERS, CREATED_AT]]]}]}这个例子同时演示了技能文档强调的两条最容易违反的规则每个子句都是[op, {}, ...args]位置 1 必须有强制存在的{}选项 map每个字段引用都在最后一个槽位使用4 段 portable FK数据库/模式/表/字段。在 construct.clj 的 JSON Schema 描述中source-table被定义为 3 元素数组[db-name, schema-or-null, table-name]而字段引用则是 4 元素数组二者形状一致地贯穿整个系统。通用子句形状[op, {options}, ...args]每个操作都是[operator, {options}, ...args]选项 map始终存在即使为空正确[count, {}]、[field, {}, [DB, SCH, TBL, COL]]、[sum, {}, expr]错误[count]、[field, [DB, SCH, TBL, COL]]服务端管线确实会修复缺失的{}槽位——construct.clj 的注释明确说明 args schema 故意保持宽松就是为了让 repair 层有机会修补这类 shortcut。但技能文档要求你写出的输出应该与后续检查看到的结果一致即直接写规范形态不要把修复机制当作文档兜底。顶层查询与 Stage 形状顶层lib/type: mbql/query——必需的类型标记stages: [...]——至少一个 stage。Stagelib/type: mbql.stage/mbql为必需标记source-table或source-card——二选一仅限第一个 stage后续 stage 隐式消费上一个 stage 的输出可选键filters、aggregation、breakout、expressions、fields、joins、order-by、limit。特别强调LLM 契约中不存在顶层database:字段数据库完全从 source 推导。这一点在源码中得到了精确印证——resolve-database-id-from-first-stage 明确注释顶层database:是 spec 规定的冗余字段修复 pass 会在解析出数据库 id 之后才把它盖章写回而且当source-table是 portable FK 时按数据库名查找重名会抛出:ambiguous-database-name查无此库抛:unknown-database。这正是技能文档要求使用精确数据库名如Sample Database而非Sample的底层原因——近似名不会静默匹配而是直接报错。字段引用Portable FK 与跨阶段字符串名字段引用通用形式[field, {}, [db-name, schema-or-null, table-name, field-name]]第三个槽位是portable field FK——一个 4 元素的字符串数组。关键变体无 schema 的数据库MongoDB 等在 schema 槽位用null[Mongo, null, orders, created_at]JSON 展开字段会追加额外段[DB, SCH, TBL, PARENT, CHILD]。在后续 stage中引用上一个 stage 产生的列时改用字符串名而不是 portable FK[field, {}, count]、[field, {}, PRODUCT_ID]。字段选项全部可选选项作用temporal-unit对日期/时间字段分桶如month、day、hour完整列表见 construct-notebook-query-operators 技能join-alias显式 join 内的每个字段引用必须携带source-field源表上 FK 列的 portable FK仅在隐式 join 自动填充有歧义时使用source-field-name当 FK 列来自上一 stage 输出时的列名罕见不会自动填充source-field-join-aliasFK 列所属的显式 join 别名通常自动填充binning对数值字段分桶base-type在跨 stage 引用时会被自动填充——不要手写。从源码看portable field FK 的解析逻辑在 portable-field-fk-table要求向量、≥4 个元素、第 0 位是字符串、第 1 位为nil或字符串、第 2 位是字符串。字段引用同时承担着权限检查的职责——referenced-table-fks会递归收集查询中所有表引用并逐一执行api/query-check见 check-source-table-query-permissions!且对:sensitive/:retired字段与隐藏表一律拒绝visible-table/visible-field实现。各类子句的完整示例技能文档逐一给出了核心子句的写法下面全部继承并标注要点。过滤比较 布尔组合filters: [[and, {}, [, {}, [field, {}, [Sample Database, PUBLIC, ORDERS, TOTAL]], 100], [, {}, [field, {}, [Sample Database, PUBLIC, ORDERS, STATUS]], paid]]]聚合字段上的sumcountaggregation: [[sum, {}, [field, {}, [Sample Database, PUBLIC, ORDERS, TOTAL]]], [count, {}]]带时间分桶的 Breakoutbreakout: [[field, {temporal-unit: month}, [Sample Database, PUBLIC, ORDERS, CREATED_AT]]]排序方向包裹引用可作用于字段引用或聚合引用order-by: [[desc, {}, [field, {}, [Sample Database, PUBLIC, ORDERS, CREATED_AT]]], [desc, {}, [aggregation, {}, 0]]]标量/列表形式limit: 50与fields: [field-ref, ...]是直白的标量与列表写法。注意order-by中[aggregation, {}, 0]是第 0 个聚合的 0 基索引引用——这与 advanced 技能中的聚合引用规则衔接内联形式必须与aggregation列表中的条目逐字完全一致同样的 op 与参数不确定时优先用[aggregation, {}, 0-based-idx]。越界索引会得到一条清晰错误列出所有可用聚合及其索引。规则与常见错误技能文档将易错点分为形状规则与反幻觉规则两组。形状规则每个子句都要写{}选项即使为空。[count]是错的必须是[count, {}]query 是 JSON 对象而非字符串直接作为调用的query字段传入使用 search /read_resource报告的精确数据库名作为每个 portable FK 的第一个元素。近似名会得到Unknown database而非静默选库跨数据库查询不受支持使用 portable FK 而非数字 ID。无 schema 数据库用nullJSON 展开字段追加路径段子句头是小写连字符风格count、sum-where、time-interval、get-day-of-week。不要下划线不要驼峰绝不臆造source-card的 entity_id必须是 21 字符字符串逐字复制自 search /read_resource——没有模式、没有数字 id、没有card__idsource-card的列用输出名引用槽位 3 的字符串不是 portable FK。从源码角度source-cardentity_id 查找发生在 resolve-database-id-from-first-stage用 entity_id 查卡片并取其:database_id未知 id 抛:unknown-card。而metabase://...URI 误写进source-table会被专门的 detect-metabase-uri-source-table! 捕获并给出定向错误——该正则故意宽松匹配一切以metabase://开头的内容确保错误消息始终是指令性的。反幻觉规则不要用-相减日期。计算两个时间值之间相差的整数单位要用[datetime-diff, {}, left, right, unit]多值分类过滤用in/not-in不要用加列表字面量。工具虽会重写列表形式但应写规范形式[in, {}, field, a, b]提取的季度值是数字1, 2, 3, 4绝不是Q1之类的字符串不要在同一 stage 对同一个底层字段 breakout 两次。如果已按{temporal-unit: month}breakout不要再按原始字段 breakoutvisualization是query的兄弟字段绝不内嵌按内联聚合排序必须与aggregation:条目完全一致同 op 同参数。不确定就用[aggregation, {}, 0-based-idx]绝不把metabase://...URI 写进source-table或source-card——那些 URI 是给read_resource用的不是查询源不要把[aggregate, ...]、[filter, ...]、[order-by, ...]、[breakout, ...]、[limit, ...]写成子句头——这些是 stage 的容器键不是子句。内部子句直接放进 stage 的aggregation:/filters:等数组中常见拼写错误count-if、variance、stddev-pop、count-distinct、dayofweek、hour-of-day、month-of-year、quarter-of-year、temporal-diff、relative-date会被自动纠正但应写规范名count-where、var、stddev、distinct、get-day-of-week、get-hour、get-month、get-quarter、datetime-diff、relative-datetime使工具输出与后续检查结果一致。底层实现从 JSON 到可执行查询的完整管线技能文档描述的是契约而 construct.clj 中的execute-representations-query*才是契约的落地者。理解这条管线有助于判断哪些错误可重试、哪些必须重写边界校验将 keyword 键的输入按::lib.schema/external-query校验捕获结构性错误——缺失stages、拼错的 stage 键如aggreagation、错误的顶层lib/type等转 portable 形式转换为修复管线操作的 string-keyed portable 形式并断言所有 stage 键已知防止 LLM 拼写错误被lib.schema静默丢弃解析数据库从stages[0]的source-table/source-card解析数据库 id构建基于应用数据库的MetadataProvider修复repair填充缺失的{}选项、缺失的lib/type标记、盖章顶层database:、为隐式 join 自动接线source-field、把内联order-by聚合改写为引用等形状复查对修复后的 portable 形式再做 schema 校验解析与归一化把 portable FK 解析为数字 ID并基于 metadata-provider 通过lib.schema/query归一化可运行性后门镜像前端canRun的 schema 校验query-not-runnable-explanation再跑前端表达式编辑器自带的诊断assert-editor-accepts-expressions!——任一失败都是可重试的:agent-error?导出把最终的数字 MBQL 5 导回 portable 形式作为 LLM 可见的:query-json/query-content输出。权限检查check-source-table-query-permissions!刻意放在修复/解析之前确保 metadata-provider 支撑的管线永远不会检视当前用户无权使用的表/卡片元数据。最终结果会附带:result-columnsresult-columns-for-query通过lib/returned-columns生成让 Agent 在下一轮就能引用实际会执行的字段路径。整个工具入口construct-notebook-query-toolconstruct.clj还会联动创建图表返回Chart链接与下一步指令若查询构造失败且错误带:agent-error?或 403则把消息原样作为工具输出返回给 LLM 自行纠正而不是抛出堆栈。配套技能与算子目录何时继续深入本文覆盖的 core 技能足以处理绝大多数单表 过滤 聚合 分组 排序场景。当查询需要以下能力时应加载配套技能而非在 core 文档内硬编**join显式joins条目、join-alias、四种strategy与隐式 joinsource-field自动填充、:ambiguous-fk/:no-fk-path错误**→ construct-notebook-query-advanced.md多阶段查询后置聚合过滤、再聚合、跨 stage 字符串名引用、distinct聚合输出名为count等细节→ 同上比率/占比count-where ÷ count的单 stage 或双 stage 写法以及表达式内不允许聚合的边界→ 同上**source-card查询已保存问题/模型、metrics[metric, {}, entity_id]、measures/segments不透明 id 子句优先**→ 同上完整算子目录聚合、过滤、表达式、时间分桶单位的精确名称与参数个数如time-interval、inside、temporal-extract的独立枚举、offset窗口函数仅限aggregation:/order-by:→ construct-notebook-query-operators.md其标注的真相来源是 src/metabase/lib/schema/ 下的 schema 文件。这三份技能文档本身服务于同一个工具且系统提示词中对应的工具说明位于 resources/metabot/prompts/tools/construct_notebook_query.md——它是技能的常驻精简版还额外包含翻译请求一节约束条件是 filter 而非 breakout、不要擅自加分析、显式日期用绝对过滤等请求意图映射准则与技能文档互为补充。小结construct_notebook_query的核心使用心法可以浓缩为三句话每个子句都写成[op, {}, ...args]、每个字段都写成 4 段 portable FK、整个 query 是一个 JSON 对象而非字符串。在此基础上善用精确数据库名 不臆造 entity_id 规范算子名这三条纪律就能避开绝大多数修复失败与幻觉错误。而当你需要了解这些规则为何如此时src/metabase/metabot/tools/construct.clj 中的数据库解析、权限预检与修复管线就是最完整的答案。【免费下载链接】metabaseThe easy-to-use open source Business Intelligence and Embedded Analytics tool that lets everyone work with data :bar_chart:项目地址: https://gitcode.com/GitHub_Trending/me/metabase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门