探索
像分析工程师一样理解数据仓库或本地 DuckDB 数据库:对重要内容进行排序,有选择地深入分析,并持久化一份草稿映射。这是 Dex 的核心技能,完全只读。它已将数据轮廓分析和关系推断作为内建能力吸纳,不再作为独立的技能存在。
如何使用
通过包装器运行引擎。它会输出一个经脱敏处理的 JSON 信封,不输出其他任何内容;读取该信封并决定下一步。
uv run "${CLAUDE_SKILL_DIR}/scripts/run.py" <子命令> [标志]
常用顺序下的子命令:
connect test --path <文件.duckdb>确认只读连接并报告能力。explore inventory --rank返回按重要性排序的对象概要(计数和大小,从不返回行数据)。explore profile <对象>(空格或逗号分隔)返回列轮廓、PII 标志(记录为(列, 类别, 置信度),从不返回示例值)、候选键、可能的粒度(grain)以及数据质量警告(例如,会导致 Join 产生重复行的非唯一 id)。一个通用的*_name标志的置信度会通过同一次扫描的值形状证据进行细化调整:类人名值会提高置信度,封闭的参考词汇表或过长的标签会将其降至防火墙阻止阈值以下,缺失证据则不改变任何内容(该标志本身不会被移除)。去重计数近似于规模,但任何在近似噪声范围内看起来唯一的列都会被升级为精确的 COUNT(DISTINCT)(distinct_count_exact: true),因此唯一性和粒度判断基于证据;警告中的~前缀表示该计数仍是近似值。如果请求的对象的缓存轮廓仍然有效(同一连接器、模式未变、在profile_freshness_hours内,默认 24 小时),则从缓存中提供服务(cache_hit_count),而不是重新扫描,因此对映射刚刚写入的表进行轮廓分析无需额外成本;当源数据以自由元数据检查无法察觉的方式发生变化时,使用--refresh强制重新扫描。explore relationships返回推断和声明的 Join 及其置信度,以及解释推断所检查内容的注释(因此空列表是有意义的)。添加--verify可通过聚合重叠探测(孤立记录比例,置信度修正)测量每个推断的 Join。explore map写入或更新.dex/缓存并打印摘要(此处--verify也有效)。超过 50 个对象时,仅按重要性排序对前 25 个进行轮廓分析,并在notes中说明(带有skipped_count);使用--full对所有对象进行轮廓分析。在重新映射时,本次运行跳过的对象会保留其之前的轮廓(carried_forward_count),每个轮廓都带有自己的profiled_at时间戳,以便清晰显示过时情况,而不是列细节悄然消失。所选对象的缓存轮廓若仍有效(同一连接器、模式未变、在profile_freshness_hours内,默认 24 小时),则无需重新扫描即可重用(cache_hit_count),因此重新运行无需成本;当源数据发生变化但自由元数据检查无法察觉时(例如行已更改但模式未变),使用--refresh强制完全重新分析。explore relationships和独立的explore profile以相同方式重用有效轮廓。explore diagram [--full]将缓存映射渲染为 Mermaid ER 图并保存到data.mermaid。该操作免费且无需连接(仅读取缓存,从不访问仓库),因此在调整图形时可以安全地重复运行。在围栏的 ````mermaid 代码块中逐字复制该字符串,以便用户查看,并在用户想要磁盘文件时将其写入.mmd或 Markdown 文件:引擎故意不写入任何文件。 永远不要手动重绘或“整理”图表。这些字形是引擎从证据中推导出的声明,而一个看似合理的基数正是该命令要防止的过度声明:声明的 Join 用实线表示,推断的用虚线表示,未经验证的推断永远不会说“恰好一个”。在展示之前先阅读notes,因为它会说明任何被遗漏的对象或列;--full会从默认范围(进行过轮廓分析、有 Join 关系的对象及其粒度、键、Join 和 PII 列)扩大到所有符合条件的对象。explore query "<SELECT ...>" ["<SELECT ...>"]回答固定命令未涵盖的临时问题:你编写 SQL,引擎的查询防火墙会拒绝或限制它。每个参数传递一条语句,或使用--sql-file <路径>传递更长的列表,一次调用提出整串问题,而不是每次调用一个问题;每条语句被独立判断和回答,因此一个语句被拒绝不会影响其他语句,data.results为每条语句提供一个条目。你尚未进行轮廓分析的表(包括刚构建的模型)会先进行轮廓分析再执行语句,因此探查新内容只需一次调用而非三次;信封会说明它进行了哪些轮廓分析,在计量连接器上,该轮廓分析的成本与语句的成本计入同一确认中。结果以行优先返回并设有上限;被拒绝时,会指出违规列及修复方法,因此一次重写即可。在编写探查查询之前阅读${CLAUDE_SKILL_DIR}/references/probe-playbook.md:它将常见问题映射到有效的探查结构。explore cluster <对象> [--features a,b,c] [-k N]对对象的数值列的有界采样运行 k-means 算法,并返回分段结构:每个簇的大小和比例、形心(每个坐标是特征在该簇的均值,属于聚合值)、轮廓系数(silhouette score),以及当省略-k时,它自动选择的 k 值和选择的轮廓扫描结果。需要.dex/缓存(先运行map/profile),以便从已进行轮廓分析的数值、非 PII、非键列中自动选择特征;使用--features自行选择(命名 PII 列或键列会将其故意纳入,并且仅报告其均值)。键永远不会作为特征:其均值无意义,且事实表主要由键加少量度量组成,因此对它们进行聚类只会划分代理范围。键是唯一列、参与 Join 的列(来自map推断的 Join)以及命名类似键的列;在此处优先使用map而非单独的profile,因为如果没有推断出的 Join,外键仅在其名称暴露时才会被捕获。注释中会列出每个排除的列,因此在信任结果之前请检查它们。轮廓系数本身无法告诉你的两件事,注释中都会说明。持有少于 1% 采样的簇是离群点口袋而非分段,并且正是因为其高度离群而推高了系数:将其作为离群点检测报告,或使用-k重新运行以分割主体部分。在无法播种采样的连接器上,每次运行的抽取结果会不同,因此两次运行可能对 k 值意见不一;信封的sample_repeatable指示当前情况,比较不同抽取结果之间的运行是无意义的。只有聚合值跨越边界:采样行在进程内聚类,从不进入上下文。在计量连接器上,它采用与下方扫描命令相同的成本握手(仅扫描特征列,且方言感知的采样子句读取一部分),因此先估算成本并获取预算。需要[cluster]额外依赖(scikit-learn);包装器会为此子命令自动安装它。explore semantic list和explore semantic query访问 dbt 语义层(指标、维度、实体)。list是发现:存在哪些指标以及每个指标可按哪些维度分组。query在显式模式后接受位置指标(--metric保留以保持兼容性)和--group-by <entity__dim>(以及可选的--where、--grain和--limit),并以有上限的列式结果返回指标的值。名称标志接受逗号分隔列表或重复标志(--group-by a,b等价于--group-by a --group-by b);--where从不分割。两个后端负责回答这些命令,由.dex/config.yml的semantic.backend选择,可通过--local/--api覆盖。--local使用 MetricFlow 渲染 SQL,并通过 dex 自己的连接器和成本握手执行,因此在支出前呈现成本(需要 dbt 项目,对于query还需要[semantic]额外依赖;list是清单读取视图,两个都不需要)。--api将查询发送到托管的 dbt Cloud 部署(仅需主机、环境 ID 和DBT_SL_TOKEN,加上[semantic-api]额外依赖,无需本地项目)。托管后端是成本守卫无法应用的唯一地方:dbt Cloud 服务器端执行,因此结果会附带明确的警告,说明支出在那里管理,而非 dex,并且不会询问--confirm。无论哪种方式,形状像 PII 的分组或过滤维度(例如user__email)在查询运行前都会被拒绝。这查询的是层;编写层是transform的工作。
query 的参与规则:当固定命令能回答问题时优先使用它们;一次探查回答一个问题;将相关度量批量写入单个查询,而不是多次发出;对标记为 PII 的列的聚合必须是度量性的(COUNT、APPROX_COUNT_DISTINCT、AVG(LENGTH(...))),绝不能是数值型(MIN、ANY_VALUE、STRING_AGG)。FROM 子句可以使用连接器原生习惯做法解嵌套 JSON 和数组列,这是探索无模式数据的正确方式(例如“此 JSON 列的每一行中出现了哪些键”):BigQuery 使用 t, UNNEST(JSON_KEYS(doc)) AS k,Snowflake 使用 t, LATERAL FLATTEN(input => doc) f,Databricks 使用 t LATERAL VIEW EXPLODE(json_object_keys(doc)) x AS k,Postgres 使用 t, jsonb_object_keys(doc) AS k,Redshift 使用 t, UNPIVOT t.doc AS v AT k,DuckDB 使用 t, UNNEST(json_keys(doc)) AS u(k)。解嵌套的值必须来自查询中表的列(直接,或通过 JSON/数组函数);解嵌套子查询、另一个表、字面量或生成器都会被拒绝,并且解嵌套的输出继承源列的 PII 标志。PII 标志被降级至低于 0.5 阻止阈值的列会正常投影,并在信封中附带警告信息;将此警告视为用户信息,而非需要修复的错误。如果用户说被拒绝的列不是个人数据,建议在 .dex/config.yml 中添加 pii_overrides 条目(完全限定的列,可选理由):它能立即解除查询阻塞、在重新轮廓分析后仍然有效,并且在 git 中可审查。永远不要手动编辑 .dex/cache.json 来清除标志。永远不要退回到原始 Python 或数据库 CLI 来运行 SQL;防火墙路径是唯一被认可的路径。
云和数据库目标(BigQuery、Snowflake、Databricks、Postgres、Redshift)
远程仓库或数据库使用连接器配置代替 --path。以 connect test --connector <名称> 开始(或在 .dex/config.yml 中设置 connector: 以及匹配的模块:bigquery: 带有 project 和 datasets 允许列表,snowflake: 带有固定的 warehouse 和 databases 允许列表,databricks: 带有固定的 SQL warehouse 和 catalogs 允许列表,postgres: 带有 schemas 允许列表,redshift: 带有 Serverless workgroup 和 schemas 允许列表)。凭证是自动发现的,而不是索要的:如果信封报告凭证缺失或过期,请传达它指定的修复方法(对于 BigQuery 是 gcloud auth application-default login;对于 Snowflake 是 connections.toml 条目或 SNOWFLAKE_* 环境变量;对于 Databricks 是 databricks auth login 或 DATABRICKS_* 环境变量;对于 Postgres 是 DATABASE_URL、PG* 环境变量或 pg_service.conf 条目;对于 Redshift 是 AWS 凭证链(aws configure、AWS_* 环境变量)或 REDSHIFT_* 环境变量),并且永远不要要求用户粘贴密钥、令牌或密码。
在计量连接器上,扫描命令(profile、map、relationships、query)运行两步握手。第一次调用返回 needs_confirmation,其中包含 cost.estimate 中的估算(在相关时附带按表的明细):在 BigQuery 上是精确的干运行字节数,在 Snowflake 上是启发式标记为 estimate_quality: "heuristic" 的仓库秒数(附带积分),在 Databricks 上是标记为 estimate_quality: "low" 的仓库秒数下限(附带 DBU;在确认的预算内会自我细化),在 Redshift 上是计算秒数的启发式估算(附带 RPU 小时数;Serverless 估算包含一次性 60 秒唤醒最小值),而在 Postgres 上是数据库秒数(无美元;受保护的是对操作数据库的负载)。以人类单位向用户展示估算值,从他们那里获取明确的预算,并使用 --confirm 和 --budget <数量>(以范式单位)重新发出相同命令。永远不要凭空创建用户未同意的预算,也永远不要在未经询问的情况下在超限拒绝时以更高的预算重试。元数据操作是免费的(connect test、inventory 立即运行),正常信封会在 data.spend 下报告实际花费。
在 BigQuery 上,轮廓分析估算对于每个轮廓可能在其聚合扫描后仍会发出的升级查询,每张表会预留 10 MB 的下限,因此在包含许多小表的仓库上,大部分数字可能是为从未发生的工作预留的。握手和超限拒绝都会报告此拆分(reserved_bytes 和 reserved_queries,以及在文本中)。在展示估算值时将其传递:数字是扫描还是预留,决定了提高预算是购买工作还是买进余量。
当估算值大于实际工作所需时,缩小范围而不是提高预算。--scope(可重复)将命令限制在所配置源允许列表的一部分,使用连接器自己的词汇:在 BigQuery 上是数据集,在 Snowflake 上是 schema 或 database.schema,在 Databricks 上是 catalog.schema,在 Postgres 或 Redshift 上是 schema。它解析起来是免费的,并且只能缩小范围。
…[已截断以进行翻译]