ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Metabase Metabot 技能解析:用 replace_sql_query 整体重写已有 SQL 查询

2026/9/14 17:55:40 拓冰建站 浏览量
Metabase Metabot 技能解析:用 replace_sql_query 整体重写已有 SQL 查询 Metabase Metabot 技能解析用 replace_sql_query 整体重写已有 SQL 查询【免费下载链接】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导读replace_sql_query是 Metabase 内置 AI AgentMetabot提供的 SQL 编辑工具之一用于将对话上下文中已存在的 SQL 查询整体替换为全新的 SQL 内容适合结构性调整、完全重写等大规模改动场景。阅读本文后你将掌握该工具的参数契约、与edit_sql_query/create_sql_query的选型边界、底层校验与权限实现以及在实际数据分析对话中安全使用它的完整规范。该技能定义位于仓库 resources/metabot/skills/replace-sql-query.md工具实现位于 src/metabase/metabot/tools/sql/replace.clj。一、技能定位什么时候该整体重写而不是定点修改在 Metabase 的技能体系中SQL 相关工具被刻意拆分为三个各司其职的技能replace-sql-query只是其中一环技能工具适用场景create-sql-query.mdcreate_sql_query用户要求新建 SQL 查询、基于模型或表做新分析edit-sql-query.mdedit_sql_query对已有查询做小范围、定向的字符串替换replace-sql-query.mdreplace_sql_query对已有查询做重大重写或结构性变更整段替换技能文档明确给出了两条关键原则更新的对象是展示给用户的查询文本工具本身不执行查询——SQL 的编写与落库由 Metabase 的查询执行链路另行处理优先原则当对话上下文中已经存在某个 SQL 查询、且改动范围很大时一次replace_sql_query调用比多次edit_sql_query调用更节省 token、更不易出错而小改动则应反过来选用edit_sql_query。从实现上看该工具在 src/metabase/metabot/tools/sql.clj 中以replace_sql_query为 tool-name 注册其:scope为agent-sql-edit所需能力为:permission-write-sql-queries说明它属于SQL 编辑型工具需要用户具备对应的写查询权限才会暴露给 Agent。二、参数契约四个必填参数缺一不可技能文档规定replace_sql_query的调用必须同时提供四个参数任何一个缺失都会被工具拒绝query_id要替换的查询 ID字符串或整数取自对话上下文中已经出现的查询checklist一段简短的纯文本检查清单记录你在重写前核验过的事项例如列存在、连接键匹配、使用了目标方言的函数。它不会展示给用户但缺失会导致调用失败——这是强制 Agent 在动手前先自我核验的机制new_query完整的替换后 SQL。由于是整段替换必须包含该查询所需的全部内容SELECT 字段、JOIN、WHERE、GROUP BY 等title简短、人性化的查询标题当查询以链接形式而非编辑器内联形式交还给用户时显示在结果上方。四个参数的校验在源码中有严格定义。工具入口 src/metabase/metabot/tools/sql.clj 使用mallischema 强制约束(def ^:private replace-sql-schema [:map {:closed true} [:query_id [:or :string :int]] [:checklist :string] [:new_query :string] [:title :string]])注意{:closed true}意味着不允许出现 schema 之外的额外键参数类型也做了强校验query_id只接受字符串或整数其余三个均为字符串不合法即抛出异常并被包装为工具错误返回。完整调用示例技能文档给出的标准示例{ query_id: 1, checklist: Re-read orders and customers; join is on customer_id, new_query: SELECT c.name, COUNT(*) AS order_count FROM customers c JOIN orders o ON o.customer_id c.id GROUP BY c.name, title: Orders per customer }在这个例子中Agent 在重写前核验了orders与customers两张表、确认连接键为customer_idnew_query提供了完整的聚合查询title用一句人话概括了查询含义。三、底层实现从参数到结果的完整调用链技能文档描述的是 Agent 侧的使用说明书而真正落地执行在 src/metabase/metabot/tools/sql/replace.clj 的replace-sql-query函数中。整个流程可以分为四步对应四个文件中的实现1. 从内存会话状态中定位查询工具首先将query-id归一化为字符串然后从queries-state当前对话会话的内存查询状态中取出目标查询(let [query-id (str query-id) query (get queries-state query-id)] (when-not query (throw (ex-info (tru Query {0} not found query-id) {:agent-error? true :query-id query-id :available-queries (keys queries-state)}))))如果查询不存在会抛出带:agent-error?标记的异常并附带当前可用的查询 ID 列表方便 Agent 修正。这也解释了技能文档反复强调取自上下文中已有的查询的原因。2. 权限检查必须有原生查询写入权限在真正修改之前会调用 src/metabase/metabot/tools/sql/common.clj 中的check-native-query-access!(defn check-native-query-access! [database-id] (when-not (and (int? database-id) ( :query-builder-and-native (perms/full-database-permission-for-user api/*current-user-id* :perms/create-queries database-id))) (throw (ex-info (tru You do not have permission to write SQL queries against this database. Native query permissions are required.) {:agent-error? true :terminal-error? true :database-id database-id}))))该实现刻意规避了qp.perms/current-user-has-adhoc-native-query-perms?的无用户逃逸问题且对非整数database-id采取失败关闭fail-closed策略——权限不足时直接抛出带:terminal-error?的终止性错误Agent 无法绕过。3. SQL 校验与方言转译权限通过后会依据查询所属数据库推断 SQL 方言并对新 SQL 做校验src/metabase/metabot/tools/sql/validation.cljquery-dialect通过database-driver将数据库 ID 映射为方言名postgresql、mysql、bigquery、clickhouse、snowflake 等validate-sql基于 sqlglot 对 SQL 进行解析转译返回{:valid? :dialect :error-message :transpiled-sql}。当 SQL 为空、方言未知、或 SQL 含 Metabase 模板标签{{ }}、[[ ]]时会短路放行——含模板标签的查询无法被通用解析器可靠校验因此跳过一个值得注意的细节h2与vertica两种方言被显式映射为nil跳过校验H2 的标识符折叠行为与 postgres 相反vertica 不被 sqlglot 支持。校验不通过时工具会返回方言与错误信息并附带sql-validation-error-instructions指引 Agent 修正校验通过时则使用转译后的 SQLtranspiled-sql写入查询。4. 更新查询内容兼容新旧两种查询格式src/metabase/metabot/tools/sql/common.clj 的update-query-sql负责把新 SQL 写回查询对象同时保留原有元数据技能实现注释明确写道Replace the SQL content of an existing query while preserving metadata(defn update-query-sql [query new-sql] (let [normalized (maybe-normalize-query query)] (cond (and normalized (lib/native-only-query? normalized) (string? (not-empty new-sql))) (lib/with-native-query normalized new-sql) (:native query) (assoc-in query [:native :query] new-sql) :else (throw (ex-info (tru Unsupported query format) {:agent-error? true})))))它同时兼容两种查询表示新版 MBQL 5:stages [{:lib/type :mbql.stage/native ...}]走lib/with-native-query旧版 legacy MBQL:type :native, :native {:query ...}走assoc-in直接替换[:native :query]字段两者都不匹配则抛错。5. 结果交付编辑器内联或结果卡片替换成功后工具在 src/metabase/metabot/tools/sql.clj 组织输出如果当前存在代码编辑器缓冲区first-code-editor-buffer-id则以code-edit-part将新 SQL 内联进编辑器否则构造viz-part结果卡片使用title参数作为展示标题并将查询转成 legacy MBQL 供前端渲染。四、使用边界与安全契约技能文档为replace_sql_query划定了清晰的安全边界这些约束与 create-sql-query.md 中定义的 SQL 契约完全一致只写 SELECT绝不输出 DDL/DML。CREATE TABLE、INSERT、UPDATE、DELETE、ALTER、DROP、TRUNCATE等均被禁止——Metabase 定位为只读分析平台标识符引用包含空格或保留字的标识符必须用双引号包裹例如order、column name方言适配必须使用目标数据库自身的 SQL 方言作用域只针对当前对话上下文中的查询绝不执行 SQL、也不做查询之外的其他动作。从源码看这些边界并非只有文档约束SQL 校验环节本身就会对非法语法报错而权限检查则从系统层面杜绝了越权写查询的可能形成文档契约 运行时校验的双重保障。五、与相关技能的配合使用replace-sql-query与另外两个 SQL 技能共同构成 Metabase Metabot 的完整 SQL 编辑能力矩阵新建查询用create_sql_query它会返回一个全新的查询供 Agent 展示支持{{#model_id}}模型引用语法如SELECT * FROM {{#5}} AS mymodel且引用必须带别名、要求使用全限定表名含 schema/catalog复杂变换用 CTE 组织小改动用edit_sql_query按{old_string: ..., new_string: ...}列表做原子化字符串替换old_string匹配多处时除非显式设置replace_all否则失败大重写用replace_sql_query一次调用替换整段 SQLtoken 开销远低于多次定点编辑。选择依据很直接改动是否涉及查询的整体结构。调整一个 WHERE 条件、重命名一张表用edit_sql_query改变聚合逻辑、增删 JOIN、完全换一种分析思路则用replace_sql_query。六、使用建议与注意事项结合技能文档与源码实现实际使用replace_sql_query时有几点值得注意checklist 要认真写它不仅是参数校验的硬性要求更是 Agent 自我质量门禁——核验列存在性、连接键、方言函数能显著降低重写后查询出错概率new_query 必须是完整的整段替换意味着旧查询中任何有用片段都不会保留遗漏的 JOIN 或过滤条件需要重新补齐标题要人性化title会出现在结果卡片上方是用户理解这次查询改动最直接的入口应概括查询目的而非复述 SQL模板标签查询会跳过语法校验如果新查询包含{{param}}或[[optional]]这类 Metabase 模板标签校验环节会短路放行此时更依赖 Agent 自身的谨慎权限前置用户对目标数据库没有查询生成器与原生查询权限时调用会直接以终止性错误失败不必尝试用其他工具绕过。小结replace_sql_query是 Metabase Metabot 面向结构性重写场景设计的专用工具四参数强校验保证调用完整性内存会话定位 原生查询权限检查 sqlglot 方言校验 新旧格式兼容写入构成了可靠的执行链路。理解它与edit_sql_query、create_sql_query的分工就能在 Agent 对话中更精准地驱动 SQL 编辑让大规模查询重构既高效又安全。【免费下载链接】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),仅供参考