Lightdash MCP Filter Expressions 全指南为 run_metric_query 与 search_field_values 编写过滤器表达式【免费下载链接】lightdashAgentic BI. Analytics at the speed of code ⚡️项目地址: https://gitcode.com/GitHub_Trending/li/lightdash导读Lightdash 的 AI Agent 系统在通过 MCPModel Context Protocol调用run_metric_query、search_field_values等工具时过滤器不再使用结构化的 JSON 对象而是采用一种紧凑的**过滤器表达式Filter Expression**字符串语法。本文以仓库内置技能文档 SKILL.md 为骨架深入讲解该语法的放置规则、四类字段操作符、字面量引号规则、硬性限制并结合packages/common与packages/backend中的解析器、Zod schema 与测试源码说明这一套机制在底层是如何被生成、解析和校验的。读完本文你将能准确为 AI 工具编写可被 Lightdash 后端正确解析的过滤器表达式并理解其与结构化过滤器对象的边界。一、这个 Skill 是什么生成与加载机制filter-expressions是 Lightdash 内置技能Built-in Skill之一其前端定义位于 filterExpressionSkill.ts而实际下发到 MCP 的 Markdown 文件是 builtInSkills/filter-expressions/SKILL.md。文件头部的注释明确说明它由命令生成pnpm -F backend generate:filter-expression-skill即该 Markdown 并非手写维护的静态文案而是由源码模板filterExpressionSkill.ts拼接MCP_FILTER_EXPRESSION_GUIDANCE_SECTION程序化生成保证文档与实现永不脱节。Skill 的 frontmatter 声明了它的元信息--- name: filter-expressions description: Author filter expressions for run_metric_query and search_field_values, including conditional custom metric filters. availability: [mcp] ---其中availability: [mcp]表示这是一个MCP 专用技能。在 builtInSkills.test.ts 中可以看到两条针对性断言filter-expressions与table-calculations这两个 skill永远不会被暴露给 AI Agent 运行时并且 Agent 直接读取也会被拦截getAiAgentSkill(filter-expressions)返回undefined。这意味着这套过滤器表达式语法只服务 MCP 场景下的工具调用。从加载机制看builtInSkills.ts 中BuiltInSkills类会扫描builtInSkills目录下的每个子目录读取其中的SKILL.md解析 frontmattermatter并计算sha256内容摘要每个技能通过skill://lightdash/name/SKILL.md这样的命名空间 URI 以 MCP Resource 形式暴露。测试builtInSkills.test.ts验证了通过原生资源getMcpResourceBody(uri)与回退工具readSkillTool拿到的内容逐行一致且skill://index.json中注册了该技能名。适用边界本技能只适用于使用表达式语法的工具如run_metric_query、search_field_values。对于 schema 中使用结构化过滤器对象structured filter objects的工具本文语法不适用。写作过滤器前务必先查看每个工具的输入 schema——技能本身不能启用本不可用的工具或过滤模式。二、核心概念三个过滤器类别与放置规则对run_metric_query而言过滤器的入口是queryConfig.filters。其 Zod schema 定义于 expressionSchemas.tsexport const filterExpressionsSchema z .object({ dimensions: filterExpressionInputSchema .nullable() .describe(Flat filter expression for dimension fields.), metrics: filterExpressionInputSchema .nullable() .describe(Flat filter expression for metric fields.), tableCalculations: filterExpressionInputSchema .nullable() .describe(Flat filter expression for table calculations.), }) .strict()由此可以提炼出四条铁律无需过滤时将queryConfig.filters整体设为null否则dimensions、metrics、tableCalculations三个类别各自独立可以是字符串表达式也可以是null。非 null 的类别只包含一条扁平字符串表达式。例如dimensions只能填一个字符串不能填数组。类别由字段元数据决定一个字段放进dimensions还是metrics取决于它在探查field discovery元数据中的 kinddimension/metric绝不能凭字段名或数字看起来像指标来臆断。裸的数字维度raw numeric dimension应放在dimensions只有指标和自定义指标custom metrics才放在metrics。每个类别内部是扁平的只用 AND 或只用 OR二者不可混用而三个类别之间隐式地用 AND 组合。例如 schema 描述中给出的语义dimensions为D1 AND D2、metrics为M1 OR M2时整体等价于(D1 AND D2) AND (M1 OR M2)。放置示例filterGuidance.tsfilterGuidance.ts中的placementExamples与FILTER_EXPRESSION_PLACEMENT_EXPRESSIONS提供了被直接注入 SKILL.md 的原始示例dimensions: orders_status equalscompleted,shipped AND orders_order_date inThePast2{unit:weeks,completed:true} dimensions (alternatives): orders_promo_code startsWithVIP OR orders_promo_code endsWith25 metrics: orders_total_order_amount greaterThan100 tableCalculations: rank lessThanOrEqual10这些示例还揭示了几条重要细节dimensions内部用 AND 连接多个规则状态等于 completed/shipped并且订单日期在过去两周内备选条件用 OR促销码以 VIP 开头或以 25 结尾表计算table calculations只能出现在tableCalculations类别即使它的底层字段类型是数字维度也不能塞进dimensions或metrics一个仅用于限制行数、用户并没有要求分组或展示的字段应当只出现在过滤器表达式里不要额外加进queryConfig.dimensions——多选的 dimension 会改变聚合粒度和表计算粒度grain导致结果错位。聚合自定义指标的过滤器对自定义指标custom metrics中的聚合类指标aggregation custom metric其条件过滤conditional filter是扁平的 AND 表达式。这在 expressionSchemas.ts 中有明确实现export const aggregationCustomMetricExpressionSchema aggregationCustomMetricSchema.extend({ filters: filterExpressionInputSchema .nullable() .describe( Optional flat AND expression for conditional metric filters., ), });即filters是一个可空的扁平 AND 表达式字符串用于给自定义指标附加行级条件。search_field_values 的过滤器对search_field_values工具无范围搜索时应省略filters字段当filters存在时它是一段扁平且仅含维度dimension-only的 AND 表达式用于收窄候选值的搜索范围。相关指导文本定义在 filterGuidance.ts 的EXPRESSION_SEARCH_FIELD_VALUES_FILTER_GUIDANCE常量中。三、操作符语法全表string / number / date / boolean每个类别中的一条规则rule遵循统一语法field operator form其中 field 是字段 IDoperator form 由操作符及其参数构成。操作符按字段类型分四组定义其权威来源是 operators.ts 中的filterExpressionOperatorDefinitions数组以及 expressionSchemas.ts 中按argumentCountByFilterType生成的语法描述。下表完整覆盖 SKILL.md 中给出的全部操作符string字符串维度语法field operator form操作符参数形式值数量isNullfield isNull0 个值notNullfield notNull0 个值equalsfield equalsvalue[,value...]1 个值notEqualsfield notEqualsvalue[,value...]1 个值startsWithfield startsWithvalue[,value...]1 个值endsWithfield endsWithvalue[,value...]1 个值includefield includevalue[,value...]1 个值doesNotIncludefield doesNotIncludevalue[,value...]1 个值number数字维度/指标语法field operator form操作符参数形式值数量isNull/notNull同 string0 个值equals/notEqualsfield equalsvalue[,value...]1 个值lessThanfield lessThanvalue1 个值lessThanOrEqualfield lessThanOrEqualvalue1 个值greaterThanfield greaterThanvalue1 个值greaterThanOrEqualfield greaterThanOrEqualvalue1 个值inBetweenfield inBetweenfirst,second2 个值notInBetweenfield notInBetweenfirst,second2 个值date日期维度语法field operator form操作符参数形式值数量isNull/notNull同 string0 个值equals/notEqualsfield equalsvalue[,value...]1 个值lessThan/lessThanOrEqual/greaterThan/greaterThanOrEqual各 1 个值1 个值inThePastfield inThePastcount{unit:unit,completed:bool}1 个 countsettings 必填notInThePast同上1 个 countsettings 必填inTheNext同上1 个 countsettings 必填inTheCurrentfield inTheCurrentunit1 个 unitnotInTheCurrentfield notInTheCurrentunit1 个 unitinBetweenfield inBetweenfirst,second2 个值日期单位units限定为days、weeks、months、quarters、years常量filterExpressionDateUnits定义于 operators.ts。其中completed语义为completedfalse表示包含未满的、部分经过的周期如过去 2 周含当前这一周completedtrue表示只统计完整周期。boolean布尔维度语法field operator form操作符参数形式值数量isNull/notNull同 string0 个值equalsfield equalsvalue1 个值notEqualsfield notEqualsvalue1 个值从 operators.ts 可以看到布尔类型的equals/notEquals的argumentCount被固定为1不像 string/number/date 那样是oneOrMore且布尔值直接写成true/false即可。操作符 × 类型矩阵的实现依据上述矩阵并非文档臆造而是由argumentCountByFilterType这张表驱动生成的isNull/notNullpresence 类对四种类型全部可用参数个数为 0equals/notEquals四种类型都可用但布尔仅限 1 值startsWith/endsWith/include/doesNotInclude通过stringOperators数组映射仅 string 类型可用其余类型在unsupportedTypes中被置为null四个比较操作符lessThan等经comparisonOperators映射仅 number 与 date 可用且固定 1 个值inThePast等相对日期操作符、inTheCurrent等当前周期操作符仅 date 可用inBetween仅 number/date各 2 值notInBetween仅 number2 值。getFilterTypeGrammarexpressionSchemas.ts正是遍历该定义数组把上述表格逐条渲染成 SKILL.md 中的### string/### number/### date/### boolean小节——文档与代码由同一份数据驱动这也是以代码为唯一事实源的体现。四、字面量规则裸标量、引号与转义表达式中的字段 ID 与值标量遵循一套格式规则其精确实现位于 examples.ts裸标量bare scalar可用。一个值若匹配正则/^[^\s,{}()\\]$/不含空白、逗号、花括号、等号、括号、反斜杠、引号且不是保留字and、or、null不区分大小写就可以不带引号直接书写。需要加双引号的场景包含保留字的值如字段或值恰好叫and/or/null包含空白、标点的字符串典型如撇号、括号()例如 SKILL.md 中给出的示例orders_product_name equalsCoffee Filters (100pk)该示例由常量FILTER_EXPRESSION_PUNCTUATED_STRING_EXAMPLE生成于 examples.ts不确定时一律加引号。引号与转义语义双引号内的逗号、花括号按字面量处理不再作为参数分隔符或 settings 结构解析反斜杠\用于转义如\、\\字段 ID 同理若字段名包含特殊字符或恰好是and/or用反引号包裹并转义见formatFieldIdexamples.ts。四种操作符参数形态argumentSyntax在 expressionSchemas.ts 中参数形态按语法类型区分为四种形态输出示例说明noneoperator [0 values]如isNull不带valuesoperatorvalue[,value...]普通值列表连接relativeDateoperatorcount{unit:unit,completed:bool} [1 count; settings required]相对日期count 必填、settings 必填currentDateoperatorunit [1 unit]当前周期只填一个单位例如inThePast2{unit:weeks,completed:true}中2是 count{unit:weeks,completed:true}是 settings花括号结构。settings 中的值会与 arguments 一起计入规则值总数见下节限制。五、硬性限制四条边界parse.ts 定义了四条防失控边界SKILL.md 中的 Limits 一行即来源于此export const FILTER_EXPRESSION_MAX_LENGTH 16_384; // 整个表达式最长 16384 字符 export const FILTER_EXPRESSION_MAX_RULES 256; // 最多 256 条规则 export const FILTER_EXPRESSION_MAX_VALUES_PER_RULE 256; // 每条规则最多 256 个值含 settings 值 export const FILTER_EXPRESSION_MAX_LITERAL_LENGTH 256; // 每个字面量字段名/值/setting 名/值最长 256 字符这些限制在validateParsedFilterExpressionparse.ts中被逐一强制执行任何超限都会返回带span出错位置的FILTER_EXPRESSION_BOUNDS_EXCEEDED错误表达式整体超长则会在解析前直接拦截parse.ts。此外输入 schema 层也做了z.string().min(1).max(FILTER_EXPRESSION_MAX_LENGTH)的预校验expressionSchemas.ts。六、底层解析PEG 语法、AST 与连接符约束解析器与 AST过滤器表达式不是正则硬匹配而是由PEGParsing Expression Grammar语法生成的解析器解析。语法源文件为 grammar.tsfilterExpressionGrammar共 219 行配合 parser.ts 使用AST 类型定义于 ast.ts。解析入口parseFilterExpression(input)parse.ts的流程为检查整体长度是否超过FILTER_EXPRESSION_MAX_LENGTH调用生成的 PEG 解析器捕获语法错误并映射为FILTER_EXPRESSION_SYNTAX错误带行号/列号定位getPositionAtOffset会把偏移量换算为{line, column}对解析出的 AST 执行四条边界校验返回{ success: true, expression }或带错误码、消息、span 的失败结果。连接符约束AND 与 OR 不可混用PEG 语法中EXPRESSION产生式grammar.ts在遍历规则间的连接符时一旦发现前后连接符不一致就立即返回专用错误FILTER_EXPRESSION_MIXED_CONNECTORS A flat filter expression cannot mix AND and OR connectors.因此dimensions: a equals1 OR b equals2 AND c equals3这类混合写法必然解析失败。同时需要注意schema 对不同的工具/类别有**连接符策略connector policy**差异——FilterExpressionConnectorPolicy分为andOnly与andOr两种expressionSchemas.tsandOr规则可用 AND 或 OR 连接但同一表达式内不可混用run_metric_query的dimensions/metrics/tableCalculations即此策略对应FILTER_EXPRESSION_GRAMMAR_DESCRIPTIONandOnly只允许 ANDOR 不受支持对应FILTER_EXPRESSION_AND_ONLY_GRAMMAR_DESCRIPTION适用于search_field_values.filters等 AND-only 场景。两条语法描述字符串分别由getFilterExpressionGrammarDescription(andOr)与getFilterExpressionGrammarDescription(andOnly)生成SKILL.md 中写入的是 andOr 版本。错误信息的工程化所有解析错误都携带span起止 offset、行、列便于 MCP 客户端把错误定位回表达式原文语法错误统一归并为FILTER_EXPRESSION_SYNTAX配合生成器原生错误信息parse.ts一起返回方便 LLM 在下一轮修正自己的输出。七、运行时差异MCP 与 Agent 的指导内容并不相同filterGuidance.tsfilterGuidance.ts中定义了filterExpressionGuidanceByRuntime为agent与mcp两种运行时生成不同的指导段落维度agent 运行时mcp 运行时本 SKILL.md适用工具generateVisualizationrun_metric_query额外规则无聚合自定义指标过滤器是扁平 AND 表达式searchFieldValuessearchFieldValues.filters驼峰search_field_values.filters下划线此外agent 运行时还额外附加了时间过滤Time-based filtering指导filterGuidance.ts 与结构化过滤器版本的STRUCTURED_FILTER_GUIDANCE_SECTION只要用户提到时间窗口last 3 months、this quarter、since March就必须在维度表达式里显式加入日期规则描述性文字、排序、limit 或结果数据中观察到的日期都不能替代真正的过滤器相对窗口用inThePast显式区间用inBetween相对窗口以提示词顶部声明的今天为基准解析绝不能锚定字段元数据或查询结果里的日期多个粒度高对齐的周期如 2025-03 与 2025-05优先用一条多值equals规则让所有条件保持在 AND 之下limit只能用于用户明确要求的 top N 场景不能用来近似时间窗口。MCP 版本的 SKILL.md 虽未内联这段长文但inThePast/inBetween的操作符语义与之一致。八、实战要点速查先看工具 schemarun_metric_query用queryConfig.filterssearch_field_values用顶层filters若工具 schema 是结构化过滤器对象则本语法不适用。无过滤就写nullqueryConfig.filters: nullsearch_field_values直接省略filters。类别归属看元数据 kind维度进dimensions指标/自定义指标进metrics表计算进tableCalculations。每类别一条扁平字符串内部统一 AND 或统一 OR类别间隐式 AND。值写法裸标量优先含保留字and/or/null、空白或标点时用双引号不确定就加引号引号内逗号、花括号为字面量\转义。日期相对窗口inThePast2{unit:weeks,completed:true}settings 必填当前周期inTheCurrentmonth显式区间inBetween2025-01-01,2025-01-31。别越界≤256 条规则、每条 ≤256 值含 settings、每个字面量 ≤256 字符、整个表达式 ≤16384 字符不要混用 AND/OR。修错看 span解析错误会带行/列定位据此精确修改表达式而不是整段重写。延伸阅读技能文档本体filter-expressions/SKILL.md生成该文档的模板与指导段落filterExpressionSkill.ts、filterGuidance.ts操作符定义与语法渲染operators.ts、expressionSchemas.ts解析与校验parse.ts、grammar.ts、ast.ts字面量格式与示例生成examples.ts技能加载与 MCP 资源暴露builtInSkills.ts、builtInSkills.test.ts【免费下载链接】lightdashAgentic BI. Analytics at the speed of code ⚡️项目地址: https://gitcode.com/GitHub_Trending/li/lightdash创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考