关于 fabriciq-ontology-authoring-cli
fabriciq-ontology-authoring-cli 是通过 Microsoft Fabric 控制平面 API 编写 Ontology 项目定义的 CLI 技能,支持实体类型、数据绑定和关系,并在写入前预览确认。
主要功能
- 01创建和更新 Ontology 定义
- 02编写实体类型及属性
- 03绑定 Lakehouse 和 Eventhouse 表
- 04定义关系及上下文映射
- 05写入前预览拟议变更
适用场景
- 01根据 Fabric 表数据建模实体
- 02配置来自 Eventhouse 的时序绑定
- 03通过关系连接实体类型
- 04创建或修改 Ontology 项目
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ microsoft/ skills-for-fabric --skill fabriciq-ontology-authoring-cli安装后在 Claude Code 中输入/fabriciq-ontology-authoring-cli确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/authoring-mechanics.mddefinition-script-templates.mdexamples.mdONTOLOGY-AUTHORING-CORE.mdpreview-and-confirm.md详细介绍
更新检查——每个会话仅执行一次(必须) 本技能在一个会话中首次使用时,继续操作前请先运行 check-updates 技能。
- GitHub Copilot CLI / VS Code:调用
check-updates技能(例如/fabric-skills:check-updates)。- Claude Code / Cowork / Cursor / Windsurf / Codex:读取本地
package.json版本,然后通过git fetch origin main --quiet && git show origin/main:package.json(或 GitHub API)与远程版本比较。如果远程版本较新,请显示更新日志和更新说明。- 如果本会话中已执行过检查,则跳过。
重要说明
- Ontology 处于 预览版。项类型值为
Ontology。功能和线格式可能会发生变化;用于生产环境前,请对照当前文档进行验证。- 要根据工作区名称查找工作区详细信息(包括其 ID),请列出所有工作区并使用 JMESPath 进行筛选。
- 要根据工作区 ID、项类型(
Ontology)和项名称查找项的详细信息(包括其 ID),请列出该工作区中此类型的所有项并使用 JMESPath 进行筛选。- 创建关系类型需要使用本体中已存在的 两种不同实体类型。
source.entityTypeId和target.entityTypeId的值是你分配的实体类型 ID,而非项 ID。- 数据绑定通过
workspaceId、itemId、sourceTableName以及湖仓源的sourceSchema引用源表。湖仓(LakehouseTable)源携带湖仓项 ID;Eventhouse(KustoTable)源携带 Eventhouse 项 ID,以及clusterUri和databaseName。源端的键列必须与实体类型的键属性匹配。Eventhouse 源仅适用于TimeSeries;静态(NonTimeSeries)绑定必须来自湖仓。
fabriciq-ontology-authoring-cli — 通过 CLI 创建 Fabric Ontology
目录
本体项概念
Fabric 本体项以定义中的 JSON 文件树形式编写。每个文件都作为一个部分,包含在创建/更新定义信封的 parts[] 数组中(payloadType InlineBase64)。
| 概念 | 定义文件路径 | 用途 |
|---|---|---|
| 本体信封 | definition.json | 空 {};必需 |
| 平台元数据 | .platform | { "metadata": { "type": "Ontology", "displayName": "<name>" } } |
| 实体类型 | EntityTypes/{entityTypeId}/definition.json | 名称、命名空间、键、显示名称属性、properties[]、timeseriesProperties[] |
| 实体类型数据绑定 | EntityTypes/{entityTypeId}/DataBindings/{guid}.json | 将 lakehouse 或 eventhouse 表映射到属性;dataBindingType = NonTimeSeries 或 TimeSeries。仅 TimeSeries 允许使用 Eventhouse(KustoTable)源 |
| 实体类型文档 | EntityTypes/{entityTypeId}/Documents/{name}.json | 可选文档链接 |
| 实体类型概览 | EntityTypes/{entityTypeId}/Overviews/definition.json | 可选小组件布局 |
| 实体类型资源链接 | EntityTypes/{entityTypeId}/ResourceLinks/definition.json | 可选 Power BI / 项目链接 |
| 关系类型 | RelationshipTypes/{relTypeId}/definition.json | 源实体类型 ID、目标实体类型 ID、名称 |
| 关系上下文化 | RelationshipTypes/{relTypeId}/Contextualizations/{guid}.json | 将源/目标键绑定到 lakehouse 表 |
属性 valueType 允许的值(必须完全一致):String、Boolean、DateTime、Object、BigInt、Double。整数请使用 BigInt,不要使用 Int64;没有 Guid 值类型(请将模型 GUID 设为 String)。时间序列绑定需要时间戳列(源类型为 datetime / date / timestamp),并且绑定类型须为 TimeSeries,且包含 timestampColumnName。完整的源列 → valueType 映射请参阅 ONTOLOGY-AUTHORING-CORE.md § EntityTypeProperty。
⚠️ 单个实体类型中,
properties[]和timeseriesProperties[]里的属性名称必须唯一。如果 lakehouse 表和 Eventhouse 表中都包含同名列(例如tenant_id),则必须重命名其中一个本体属性名称,以避免冲突。绑定中的sourceColumnName仍可指向原始列——只有本体属性的name必须唯一。例如,静态属性保留为TenantId,时间序列属性命名为TsTenantId。⚠️ 不同实体类型中具有相同
name的属性必须使用相同的valueType——本体会在整个定义中强制执行名称级别的类型一致性。如果某个实体类型中的SerialNum为String,则另一个实体类型中不能将其设为BigInt。请在所有位置使用相同的valueType,或添加前缀以区分(例如SerialNumStr与SerialNumInt)。⚠️ 部分路径必须始终使用正斜杠(
EntityTypes/{id}/definition.json),不能使用反斜杠。在 Windows 上,PowerShell 路径拼接运算符(Join-Path、\)会生成反斜杠,Fabric API 会因此返回ALMOperationBadRequest。请始终使用字符串插值和/构建部分路径。
工具栈
本体创作使用与其他 CLI 技能相同的 Fabric 控制平面工具栈 — 规范列表(安装命令、先决条件检查、base64 助手、JSON 工具)请参阅 COMMON-CLI.md § 工具选择理由,az login 和令牌获取请参阅 COMMON-CLI.md § 身份验证方法。
以下本体专属工具指南仅涵盖 createItem / updateDefinition 有效负载中遇到的问题。
⚠️ PowerShell
ConvertTo-Json警告:PowerShell 的ConvertTo-Json可能会静默地重新排列键,并以不同于 JSONnull的方式序列化$null,从而导致updateDefinition出现ALMOperationImportFailed错误。为避免此问题:
- 始终使用
[System.IO.File]::WriteAllText,并搭配[System.Text.UTF8Encoding]::new($false)写入 JSON 文件 —Out-File和Set-Content会添加 BOM,导致有效负载损坏。- 尽可能使用
jq构建 JSON,而不是ConvertTo-Json—jq -nc可生成确定且紧凑的 JSON,不受 PowerShell 序列化问题影响:$json = '{}' | jq -nc --arg id "$ET_ID" --arg name "Site" '{id:$id,name:$name}'- 发送前验证 JSON:
Get-Content envelope.json | jq .— 如果jq失败,则说明有效负载格式错误。- 对
ConvertTo-Json使用-Depth 10— 默认深度为 2,会静默截断嵌套对象。
⚠️ 避免对
InlineBase64部分使用certutil -encode。 它的输出会按行换行,并带有页眉和页脚,使用前必须进行后处理。在 Windows 上,请改用 PowerShell 的[Convert]::ToBase64String([IO.File]::ReadAllBytes($path))。
连接
本体创作的目标是 Fabric 控制平面。在编写定义之前,你需要:WS_ID(工作区)、LH_ID(用于静态绑定和湖仓时序绑定的湖仓项 ID),以及 — 对于由 Eventhouse 提供支持的时序 — Eventhouse 项 ID、KQL 群集 URI 和 KQL 数据库名称。
- 登录并获取 Fabric 控制平面令牌 → COMMON-CLI.md § 身份验证方法(始终使用
--resource https://api.fabric.microsoft.com)。 - 按
displayName查找工作区、文件夹、湖仓和本体项 ID → COMMON-CLI.md § 在 Fabric 中查找工作区和项(涵盖分页和 JMESPath 筛选)。 - 通用
az rest调用模板 → COMMON-CLI.md § 通过 az rest 调用 Fabric 控制平面 API。
以下是本体专属的查找注意事项(文件夹 GUID 与门户数字 ID、Eventhouse ID 字段映射、绑定的架构发现,以及在预览版重定向主机上捕获 LRO 标头)。
文件夹(本体专属注意事项)
本体创建有效负载中的 folderId 字段需要文件夹 GUID — 而不是门户 URL 中显示的数字 subfolderId。传入门户中的数字会导致 400 InvalidParameter … cannot convert "<numeric>" to Guid … Path 'folderId'。请按照 COMMON-CLI.md § 在 Fabric 中查找工作区和项 中所述,列出 GET /v1/workspaces/{WS_ID}/folders 并按 displayName 筛选,以查找 GUID。
Eventhouse / KQL 数据库(用于 TimeSeries 绑定)
由 Eventhouse 提供支持的 TimeSeries 本体绑定,需要在 KustoTable 数据绑定负载中包含三个字段——这些字段取自 GET /v1/workspaces/{WS_ID}/kqlDatabases 返回的 KQL 数据库记录:
| KustoTable 绑定字段 | KQL 数据库记录中的源字段 |
|---|---|
itemId | properties.parentEventhouseItemId — Eventhouse 项目 ID,而不是 KQL 数据库自身的 id |
clusterUri | properties.queryServiceUri |
databaseName | displayName(使用 API 返回的规范大小写) |
Eventhouse 表只能用于
TimeSeries绑定。 实体类型的静态(NonTimeSeries)绑定仍必须来自托管 lakehouse 表。
常见错误:将 KQL 数据库自身的
id作为KustoTable.itemId传入。请使用同一记录中的parentEventhouseItemId。
有关通用的 kqlDatabases 列表调用(分页 + 按 displayName 使用 JMESPath 筛选),请参阅 COMMON-CLI.md § 在 Fabric 中查找工作区和项目。
架构发现
编写绑定前,请先发现源表架构,以便映射正确的列名。请使用配套技能发现架构——它们比原始 REST 调用更快捷、更可靠。
- Lakehouse 表 → 使用
sqldw-consumption-cli技能,并针对 lakehouse SQL 终结点查询INFORMATION_SCHEMA.COLUMNS(一次查询即可返回所有表和列)。如果无法使用,请改用 Fabric Tables REST API 和 OneLake Table API 获取 Iceberg 元数据。 - Eventhouse / KQL 表 → 使用
eventhouse-consumption-cli技能并运行.show database schema as json(单次响应即可返回所有表和列)。如需查询单个表,请使用.show table <name> schema as json。
使用此处返回的列类型为每个 EntityTypeProperty 填写 valueType——请参阅 ONTOLOGY-AUTHORING-CORE.md § EntityTypeProperty 中的源列 → valueType 映射。
使用 az rest 捕获 LRO 标头
默认情况下,az rest 不会公开响应标头。createItem 和 updateDefinition 都会返回 202 Accepted,并带有 x-ms-operation-id 标头(以及 Location 标头)。请使用 --verbose 并解析 stderr,以捕获操作 ID:
本体创建/更新时,优先使用
x-ms-operation-id轮询,而不是直接使用Location标头。 公共 Fabric LRO 合约支持通过Location标头或https://api.fabric.microsoft.com/v1/operations/{operationId}(使用x-ms-operation-id)轮询。在当前本体预览版行为中,观测到的Location值指向analysis.windows.net重定向主机(例如https://df-…-redirect.analysis.windows.net/v1/operations/{id}),而非api.fabric.microsoft.com;使用az rest --resource https://api.fabric.microsoft.com轮询该 URL 时,会针对错误的受众重新进行身份验证,并因 401/403 而失败——这会隐藏 LRO 状态/错误,并导致盲目重试。因此,请捕获x-ms-operation-id并轮询https://api.fabric.microsoft.com/v1/operations/{operationId}(Fabric 主机,Fabric 令牌)。如果确实要使用Location,请使用该 URL 所需的受众。
# Bash — capture x-ms-operation-id from az rest --verbose stderr
OP_ID=$(az rest --method POST \
--url "https://api.fabric.microsoft.com/v1/workspaces/${WS_ID}/items" \
--resource "https://api.fabric.microsoft.com" \
--headers "Content-Type=application/json" \
--body @envelope.json --verbose 2>&1 \
| grep -oiP "(?<=x-ms-operation-id': ')[^']+")
# Poll the Fabric operations endpoint (stays on api.fabric.microsoft.com)
while :; do
OP=$(az rest --method GET \
--url "https://api.fabric.microsoft.com/v1/operations/${OP_ID}" \
--resource "https://api.fabric.microsoft.com")
STATUS=$(printf '%s' "$OP" | jq -r .status)
case "$STATUS" in
Succeeded) break ;;
Failed|Cancelled)
# Read the error and FIX the payload — never blind-retry the same body.
printf '%s' "$OP" | jq -r '.error | "\(.errorCode // .code): \(.message)"' >&2
exit 1 ;;
*) sleep 5 ;;
esac
done
# PowerShell — capture x-ms-operation-id from az rest --verbose stderr
$result = az rest --method POST `
--resource "https://api.fabric.microsoft.com" `
--url "https://api.fabric.microsoft.com/v1/workspaces/$WS_ID/items" `
--headers "Content-Type=application/json" `
--body "@envelope.json" --verbose 2>&1
$opId = ($result | Select-String -Pattern "x-ms-operation-id': '([^']+)'" |
ForEach-Object { $_.Matches[0].Groups[1].Value })
# Poll the Fabric operations endpoint (stays on api.fabric.microsoft.com)
do {
Start-Sleep -Seconds 5
$op = az rest --method GET `
--url "https://api.fabric.microsoft.com/v1/operations/$opId" `
--resource "https://api.fabric.microsoft.com" | ConvertFrom-Json
} while ($op.status -notin 'Succeeded','Failed','Cancelled')
if ($op.status -ne 'Succeeded') {
# Read .error and FIX the payload — never blind-retry the same body.
throw "createItem LRO $($op.status): $($op.error.errorCode) $($op.error.message)"
}
重要:
createItem返回 202,且没有响应正文——az rest以代码 0 退出,不会打印任何内容。这是正常现象。操作达到Succeeded后,请列出项目以获取新项目 ID。如果status为Failed,error字段会指出原因(例如实体类型部分格式错误)——请修正负载并提交更正后的请求,而不要重新发送相同的正文。
编写范围
| 操作 | Fabric REST 调用 | 涉及的定义部分 |
|---|---|---|
| 创建空本体 | POST /v1/workspaces/{ws}/items,其中 type=Ontology | .platform、definition.json |
| 添加 / 修改实体类型 | POST /v1/workspaces/{ws}/items/{id}/updateDefinition | EntityTypes/{id}/definition.json |
| 将实体类型绑定到表(非时序) | updateDefinition | EntityTypes/{id}/DataBindings/{guid}.json,包含 NonTimeSeries |
| 将实体类型绑定到表(时序) | updateDefinition | EntityTypes/{id}/DataBindings/{guid}.json,包含 TimeSeries + timestampColumnName |
| 添加关系类型 | updateDefinition | RelationshipTypes/{id}/definition.json |
| 绑定关系(上下文化) | updateDefinition | RelationshipTypes/{id}/Contextualizations/{guid}.json |
| 删除实体 / 关系 | 使用省略该路径部分的 updateDefinition | — |
| 重命名本体 | 使用 updateMetadata=true 和新的 .platform 的 updateDefinition | .platform |
**更新项目定义会替换所包含部分的完整树结构。**务必先通过
Get Item Definition获取当前定义,在本地修改各部分,然后重新发送完整的目标部分集合。
编写参考
每项操作的完整 JSON 结构、字段约定和验证方法见 authoring-mechanics.md。端到端 Bash 操作示例见 examples.md。以下各节可用作快速索引:
| 主题 | 参考 |
|---|---|
定义封装(parts[]、InlineBase64、base64 辅助函数) | authoring-mechanics.md § Definition Envelope |
ID 生成(64 位整数、GUID、name → id 映射) | authoring-mechanics.md § ID Generation Pattern |
| 创建空本体 | authoring-mechanics.md § Create the Ontology Item |
| 添加实体类型 | authoring-mechanics.md § Add an Entity Type |
| 绑定到 lakehouse / eventhouse | authoring-mechanics.md § Bind an Entity Type |
| 关系类型 + 上下文化 | authoring-mechanics.md § Add a Relationship Type |
| 应用定义更新(获取 → 修改 → 发送) | authoring-mechanics.md § Apply a Definition Update |
| 验证和检查 | authoring-mechanics.md § Verify and Inspect |
| 完整的 Bash / PowerShell 脚手架 | definition-script-templates.md |
编写时需牢记的核心不变量(完整细节见参考文件):
- 封装结构:
{ "displayName", "type": "Ontology", "definition": { "parts": [ { "path", "payload", "payloadType": "InlineBase64" } ] } };definition.json的内容就是{};.platform包含metadata.type: "Ontology"+displayName。 - ID:实体 / 关系 / 属性 ID 是正 64 位整数,数据绑定 / 上下文化 ID 是 GUID。在源代码管理中保存
name → id映射;切勿将同一 ID 用于不同概念。
ID 映射模板——将其与部署脚本一同保存(JSON 或 YAML):
{
"ontologyName": "SkillTest_Fleet",
"entityTypes": {
"Site": { "id": "1048860412765431174", "properties": { "SiteId": "1428056703884423742", "SiteName": "4251708967918658190" } },
"Equipment": { "id": "3332700945676096991", "properties": { "EquipmentId": "4585483423451989345" } }
},
"relationshipTypes": {
"EquipmentAtSite": { "id": "4242053467032157032" }
},
"bindings": {
"Site_static": "25e3a44a-b62a-40e3-a64a-a43caaa92d19",
"Equipment_static": "5dc4cadd-3700-4c96-bb1e-41e4c909ae4d"
}
}
- 绑定:
NonTimeSeries仅适用于 lakehouse,且每种实体类型最多只能有一个;同一实体类型上的任何TimeSeries绑定之前,都必须先有NonTimeSeries绑定;TimeSeries可绑定到 lakehouse 或 Eventhouse;对于KustoTable,itemId是 Eventhouse 项目 ID(而非 KQL 数据库 ID)。 - 关系:
source.entityTypeId和target.entityTypeId必须不同,并且必须引用 parts 树中存在的实体类型。 - 更新会整体替换其中包含的 parts——务必先获取当前定义,在本地修改,然后发送。
必须 / 优先 / 避免 / 故障排除
必须遵守
- 路由到此处前,必须明确要求提供本体上下文——提示词必须要求创建或更改“本体”(或引用某个本体项)。没有本体上下文的通用“Fabric IQ”提示词不属于本体创作任务;应转交给匹配的技能。这可以避免共享的“Fabric IQ”品牌导致此技能被过度触发。
- 对含糊的提示词,先澄清再操作——绝不推断架构或绑定。如果用户说“为航空公司数据创建一个本体”,却没有说明实体类型、实体键或湖仓表,应询问具体有哪些实体、实体键是什么,以及使用哪些湖仓表。替换本体定义等不可逆副作用操作,必须得到用户明确授权。
- 编写任何绑定前,先解析
WS_ID和源项 ID——硬编码 GUID 是最常见的三大故障原因之一。湖仓绑定需要湖仓的itemId;事件中心绑定需要事件中心的itemId、群集 URI 和数据库名称。 - 更新前先获取当前定义——
updateDefinition会整体替换所包含的部分。与过时的本地状态合并会悄无声息地丢弃近期更改。处理getDefinition返回的 LRO 202 状态(轮询并通过该操作的result端点获取结果)。 - 在源代码管理中,和技能使用者的代码库放在一起,持久化实体类型、关系类型和属性的
name → id映射。每次运行都重新生成 ID 会产生重复项并破坏引用。 - 在实体类型上添加任何时间序列绑定之前,先添加静态(
NonTimeSeries)绑定——每个实体类型最多支持一个静态绑定,而且时间序列绑定要求静态键属性已填充。 - 只绑定到托管湖仓表——不支持外部表、启用了 OneLake 安全性的湖仓,以及启用了列映射的 delta 表。
- 确保每个实体类型内
properties[]和timeseriesProperties[]中的属性名称唯一。当湖仓表和 Eventhouse 表包含同名列(例如tenant_id、device_id)时,应重命名本体时间序列属性(例如TsTenantId),同时让sourceColumnName指向原始列。属性名称重复会导致ALMOperationImportFailed。 - 观察到的行为(预览版):将实体键(
entityIdParts)限制为valueType为String或BigInt的属性——根据当前预览版行为,其他值类型尚未被接受为键。Microsoft Learn 公共文档未说明此限制;依赖此限制前,请在你的租户中验证。 - 所有部分路径都使用正斜杠——使用
EntityTypes/{id}/definition.json,绝不要使用EntityTypes\{id}\definition.json。在 Windows 上,Join-Path和\会生成 Fabric API 不接受的反斜杠。请使用字符串插值构建路径:"EntityTypes/$ET_ID/definition.json"。 - 验证权限——创作至少需要工作区上的
Contributor权限。 - 在信封的
type和.platform元数据中,均将项类型设为Ontology(而不是OntologyPreview或类似类型)。 - 每次 LRO 写入前都显示预览并确认环节——显示 ASCII 提案(全新创建)或与
getDefinition对比的变更集差异(已有内容),并在调用createItem或updateDefinition前取得用户明确的yes。请参阅 preview-and-confirm.md。除yes以外的任何回应都意味着停止并修改;绝不部分应用。
建议做法
- 在磁盘上构建定义树(每个逻辑部分一个 JSON 文件,并遵循
EntityTypes/{id}/...布局),发送前再对每个文件进行 Base64 编码。这样可以方便地审查差异。 - 入门时,先从现有且已验证可用的本体的
getDefinition转储开始,再进行修改。 - 静态绑定优先使用 Lakehouse;时间序列使用 Eventhouse——对于
NonTimeSeries绑定,唯一支持的数据源是 OneLake(lakehouse)。对于TimeSeries绑定中的高吞吐遥测数据,使用 Eventhouse(KustoTable);如果团队更倾向于使用单一数据源类型,也可以将数据镜像或快捷方式接入 lakehouse 表。 - 确保部署脚本具备幂等性——输入不变时,重复运行脚本应生成不变的本体。
- 涉及多个实体类型或环境时,优先使用脚本化工作流,而非 UI。
- 上游数据写入后,手动触发图模型刷新——在刷新本体之前,绑定源中的新行不会显示在预览体验中。
避免
- 生成单体
.ps1或.sh脚本文件——直接在 Shell 中执行命令。大型生成脚本容易引入转义错误和 PowerShell 解析错误,而且单行失败时很难调试。使用jq -nc构建 JSON,将其写入临时文件,然后传递给az rest --body @file。 - 手动编辑 Base64 载荷——始终先解码、编辑 JSON,再重新编码。
- 将某个属性、实体或关系 ID 复用于不同概念。
- 依赖本体范围以外的关系名称唯一性——目前观察到,关系名称似乎在本体内唯一;请预先收集所有所需的关系名称,以便在需要时使用前缀消除歧义。遇到命名冲突时,应向使用方确认,而非自行猜测。
- 在
.platform或任何部分中嵌入机密、SAS 令牌或用户令牌。 - 在源实体类型和目标实体类型尚未出现在部分列表中时创建关系类型。
- 将
Object/ JSON 属性视为可完全查询——目前观察到,绑定到Object属性的嵌套 JSON 会以不透明载荷的形式呈现,无法像标量一样寻址。对于嵌套载荷,请将原始数据保留在 Eventhouse 中,只绑定可寻址的标量字段。在向下游使用方承诺特定查询形式之前,请通过getDefinition往返验证。 - 依赖“省略即删除”——观察到,未包含在
updateDefinition正文中的部分会被移除,但技能应告知用户此操作具有破坏性,并在生成会丢弃部分的封套前征得确认。
故障排除
| 症状 | 可能原因 | 修复方法 |
|---|---|---|
创建时出现 400 Bad Request — “Invalid item type” | 项目类型字符串错误 | 在 .platform 中使用 "type": "Ontology" 和 metadata.type: Ontology |
使用 type: Ontology 调用 createItem 时出现 400 InvalidItemType | 租户 / 工作区未启用 Fabric IQ Ontology(预览版) | 向用户说明此情况——不要重试。必须在租户级别加入 Ontology 预览版计划。 |
创建时出现 400 InvalidParameter — Error converting value "<number>" to … Guid … Path 'folderId' | 传入了门户 URL 中的数字 subfolderId,而不是文件夹 GUID | 通过 GET /v1/workspaces/{WS_ID}/folders 获取文件夹 GUID(参见连接 § 文件夹),并传入该 GUID |
出现 400 — 属性上的 “Invalid value type” | 将 Int64 / Guid / Float 用作 valueType | 允许的值仅为 String、Boolean、DateTime、Object、BigInt、Double |
实体类型 / 属性上出现 400 — “Invalid identifier” | 名称不符合正则表达式 | 符合 ^[a-zA-Z][a-zA-Z0-9_-]{0,127}$;为确保兼容性,建议采用更严格的 1–26 个字符门户规则 |
出现 400 — “Source and target must differ” | 关系两端指向了同一实体类型 | 选择不同的源实体类型和目标实体类型 |
出现 400 — “Referenced property not found” | targetPropertyId 与实体类型中的任何属性都不匹配 | 检查 ID;确保属性已在同一次更新中添加 |
出现 400 — “Time series binding requires existing static binding” | 在实体类型上添加时序绑定之前,尚未添加静态绑定 | 先添加带有键属性的 NonTimeSeries 绑定,然后再添加 TimeSeries 绑定 |
出现 400 — 键列问题 | 键属性的 valueType 不是 String 或 BigInt | 将属性改为 String / BigInt,或选择其他键 |
绑定时出现 404 | workspaceId / itemId 错误,或源项目已删除 | 通过 list items / list lakehouses / list eventhouses 重新解析 ID |
| 绑定已接受,但没有实例出现 | 源是外部表、列映射的 delta 表,或受 OneLake 安全保护 | 将表重建为不带列映射的托管 delta 表;移除 lakehouse 上的 OneLake 安全设置 |
| 绑定后实例为空 | propertyBindings 列名与源列不匹配 | 检查源架构并修正 sourceColumnName / sourceSchema |
| 上游新增行未显示 | 尚未执行刷新 | 在 ontology 项目上触发手动图模型刷新 |
| 时序小组件没有数据显示 | 未设置 timestampColumnName,或时间戳列不是受支持的日期 / 时间类型 | 在 TimeSeries 绑定中设置 timestampColumnName;确保列类型为 datetime / date / timestamp |
getDefinition 返回 200 或 202 | 支持 LRO 的响应(可能是内联信封或操作 ID) | 如果是 202,轮询操作直到状态为 Succeeded,然后执行 GET https://api.fabric.microsoft.com/v1/operations/{operationId}/result;如果是 200,直接解析返回的信封——参见 LRO Header Capture |
LRO 轮询返回 401 / 403,或 Location 标头的主机为 *.analysis.windows.net | 创建 / 更新时的 Location 重定向到了 Analysis Services 主机;使用 az rest --resource https://api.fabric.microsoft.com 轮询会针对错误的受众重新进行身份验证 | 在 Fabric 主机上轮询 https://api.fabric.microsoft.com/v1/operations/{x-ms-operation-id},不要跟随 Location URL——参见 LRO Header Capture。轮询失败期间不要盲目重试创建操作 |
updateDefinition 出现 Conflict | 门户中有并发编辑 | 重新获取定义、重新应用修改并重新发送 |
updateDefinition 出现 ALMOperationImportFailed | JSON 负载格式错误——通常由 PowerShell ConvertTo-Json 序列化问题导致($null 与 null 的差异、键重排、文件中的 BOM) | 使用 jq -nc 构建 JSON,而不是使用 ConvertTo-Json;使用 [System.IO.File]::WriteAllText + UTF8Encoding($false) 写入文件以避免 BOM;发送前用 jq . 验证——参见 工具栈 § PowerShell 警告 |
createItem 或 updateDefinition 出现 ALMOperationImportFailed — 属性名称重复 | 同一实体类型的 properties[] 和 timeseriesProperties[] 中出现了相同的属性名称 | 两个数组中的属性名称必须唯一。如果 lakehouse 表和 Eventhouse 表共享列名,请重命名时序 ontology 属性(例如,TenantId → TsTenantId)——绑定的 sourceColumnName 仍可引用原始列 |
ALMOperationImportFailed — “Property 'X' has conflicting value types” | 相同的属性 name 出现在两个不同的实体类型中,且 valueType 值不同(例如,一个为 String,另一个为 BigInt) | 属性名称在整个 ontology 中必须唯一——如果两个实体类型共享属性名称,两者必须使用相同的 valueType。可通过添加前缀来区分(例如,SerialNumStr 与 SerialNumInt),或统一类型 |
ALMOperationBadRequest — “directory name … is not valid for EntityType” | Part path 使用了反斜杠(EntityTypes\\{id}\\definition.json),而不是正斜杠 | Part 路径始终使用正斜杠:EntityTypes/{id}/definition.json。在 Windows 上,避免使用 Join-Path 或 \ 构造 part 路径——改用带 / 的字符串插值 |
createItem 返回退出代码 0,但没有输出 | 正常情况——createItem 返回不带正文的 202 Accepted;az rest 会将其视为成功 | LRO 完成后列出项目以获取新项目 ID;使用 --verbose 捕获 x-ms-operation-id 标头以轮询 LRO |
createItem 出现 409 ItemDisplayNameAlreadyInUse | 工作区中已存在具有相同 displayName 的 ontology | 先列出现有 ontology;删除或重命名现有项,或选择不同的名称 |
definition.json 负载导致导入错误 | base64 负载中有多余空格、BOM 或换行符 | definition.json 必须严格为 {}——其 base64 为 e30=。在 Windows 上,使用带有 UTF8Encoding($false) 的 [System.IO.File]::WriteAllText 确保没有 BOM |
Agentic 工作流
⚠️ 请勿生成单体
.ps1/.sh脚本文件。 请直接在 shell 中逐条执行每个步骤。生成大型脚本文件容易引入转义错误、解析错误和属性访问问题,而且很难调试。请改为:
- 在终端中直接运行
az rest、jq和 PowerShell 命令- 使用通过变量传递的
jq -nc,逐步构建 JSON 载荷- 将最终封装写入临时文件,然后通过
az rest --body @file传入- 如果某个步骤失败,请修复并重新运行——不要重新生成整个脚本
编写前先探索
Greenfield 与 brownfield 执行策略:
- Greenfield(新本体):构建完整定义——实体类型、绑定、关系、上下文化和时间序列——并在一个封装中通过单次
createItem调用完成。createItem载荷接受完整的definition.parts[]数组,而不只是.platform+definition.json。- Brownfield(更新现有内容):逐步执行——获取当前定义、修改、发送。每次
updateDefinition后都用getDefinition验证,以便尽早发现错误。即使中途失败,也会保留之前的进度。
并行发现架构
当本体绑定到多个数据源(Lakehouse 表 + Eventhouse 表)时,应并行发现架构,而不是顺序执行。启动单独的发现任务并发运行:
┌─────────────────────────────────────────────────────────────────┐
│ ORCHESTRATOR (this skill) │
│ │
│ Step 0 → Resolve workspace, folder, lakehouse ID, eventhouse ID │
│ │
│ Step 1 → Fan out schema discovery (parallel): │
│ ┌──────────────────────────┐ ┌────────────────────────────┐ │
│ │ TASK A: Lakehouse schemas │ │ TASK B: Eventhouse schemas │ │
│ │ sqldw-consumption-cli │ │ eventhouse-consumption-cli │ │
│ │ or INFORMATION_SCHEMA │ │ or .show database schema │ │
│ │ → all tables + columns │ │ → all tables + columns │ │
│ └──────────┬───────────────┘ └──────────┬─────────────────┘ │
│ │ │ │
│ Step 2 → Merge schemas ◄────────────────────┘ │
│ - Match entity tables (lakehouse) to telemetry (eventhouse) │
│ - Detect property name collisions across sources │
│ - Detect property type conflicts across entity types │
│ - Rename collisions (e.g., TenantId → TsTenantId) │
│ │
│ Step 3 → Propose model → PREVIEW & CONFIRM │
│ │
│ Step 4 → Build full envelope → createItem (single call) │
└─────────────────────────────────────────────────────────────────┘
如何分发任务(因 Agent 而异):
- GitHub Copilot CLI / Claude Code:启动两个后台
taskAgent——一个负责 Lakehouse(sqldw-consumption-cli或INFORMATION_SCHEMA.COLUMNS查询),另一个负责 Eventhouse(.show database schema as json)。两者完成后读取结果。 - 单线程环境:依次运行两个发现查询——每个查询只需调用一次,因此开销很小。
大多数编写错误会在合并步骤(步骤 2)中被发现——请对属性名称去重、统一各实体间的 valueType,并为与静态属性冲突的时间序列属性添加前缀。
详细步骤流程
Step 0 → Is the request specific? Are the entity types, keys, and lakehouse tables named?
→ NO → Ask: "Which entity types? What is the key of each? Which lakehouse table binds to each?
Any timeseries properties? Any relationships and their link tables?"
STOP — do not proceed until the user answers.
→ YES → Continue.
Step 1 → Resolve IDs: workspace, folder, lakehouse, eventhouse [COMMON-CLI.md]
Step 2 → Discover source schemas (parallel where possible):
a. Lakehouse: invoke `sqldw-consumption-cli` or query INFORMATION_SCHEMA.COLUMNS
b. Eventhouse: invoke `eventhouse-consumption-cli` or run `.show database schema as json`
Step 3 → Merge schemas: detect property name collisions + type conflicts; rename as needed
Step 4 → If ontology exists: getDefinition → decode parts (capture current IDs)
Else: plan `createItem` with the FULL definition (all parts in one call).
Step 5 → For each entity type:
a. Generate/reuse 64-bit IDs for entity + properties
b. Build EntityTypes/{id}/definition.json
c. Build one or two DataBindings/{guid}.json files
Step 6 → For each relationship:
a. Confirm both entity types exist in Step 5 output
b. Generate/reuse relationship type ID
c. Build RelationshipTypes/{id}/definition.json
d. Build RelationshipTypes/{id}/Contextualizations/{guid}.json
Step 7 → Base64-encode all parts; assemble envelope
Step 8 → **PREVIEW & CONFIRM** — render proposal (greenfield) or change-set diff (brownfield)
and obtain explicit `yes` from the user. See [preview-and-confirm.md](references/preview-and-confirm.md).
Do not proceed on anything other than `yes`.
Step 9 → createItem OR updateDefinition (LRO)
Step 10 → Poll LRO until Succeeded; getDefinition; verify IDs and bindings; persist post-write snapshot for next-run diff
脚本生成工作流
Step 1 → Capture user intent (entity types, keys, properties, relationships, source tables)
Step 2 → Save intent as a YAML/JSON spec in the consumer's repo — single source of truth
Step 3 → Generate: (a) the ID map, (b) per-file JSON parts, (c) the composite envelope
Step 4 → **PREVIEW & CONFIRM** — render proposal/diff and require explicit `yes`
(see [preview-and-confirm.md](references/preview-and-confirm.md)). The textual
diff against the last-applied envelope snapshot feeds the brownfield change-set.
Step 5 → Apply via az rest --body @envelope.json (createItem or updateDefinition)
Step 6 → Poll LRO; on success, commit the envelope snapshot + ID map
示例
端到端的完整示例(创建空本体 → 添加实体类型 + 非时间序列绑定 → 添加关系类型 + 上下文化 → 添加时间序列属性 + Eventhouse 绑定)位于 examples.md。完整的 fetch-mutate-send bash 和 PowerShell 脚本位于 definition-script-templates.md。
Agent 集成说明
- 此技能专注于编写。请搭配使用消费技能(例如 Fabric Graph 查询技能),以端到端验证本体。
- 当本体绑定到多种源类型时,并行执行架构发现:
- 启动后台
sqldw-consumption-cli任务来发现 Lakehouse 架构(INFORMATION_SCHEMA.COLUMNS)——一次查询即可返回所有表和列。 - 启动后台
eventhouse-consumption-cli任务来发现 Eventhouse 架构(.show database schema as json)——一次调用即可返回所有表和列。 - 两项任务并发运行。两者完成后合并结果,再构建本体模型。
- 启动后台
- 合并步骤至关重要——发现完成后,在
properties[]和timeseriesProperties[]中对属性名称去重,统一不同实体类型中同名属性的valueType,并在构建封装前为冲突项添加前缀。 - 编排跨越 Ontology + Eventhouse + Lakehouse 的多步骤客户工作流时,应通过 Agent(例如
FabricDataEngineer)进行路由,而不是直接串联技能。 - 可合理假设上游依赖已就绪:Lakehouse 表已存在,且包含用户描述的关键列。若未满足此条件,调用方应先调用 Lakehouse 编写技能。