AdventureWorks 数据集的 AI 技能示例(预览)
本文介绍如何在 AdventureWorks 数据集上配置 AI 技能。
重要
此功能目前为预览版。
先决条件
- F64 Microsoft Fabric 容量或更高容量。
- 已启用 Copilot 租户切换。
- 已启用适用于 AI 的跨地区共享(如相关)。
使用 AdventureWorksDW 创建湖屋
首先,创建湖屋并使用必要的数据进行填充。
如果仓库或湖屋中已有 AdventureWorksDW 实例,则可以跳过此步骤。 如果没有,请从笔记本创建湖屋。 使用笔记本将数据填充到湖屋中。
在要在其中创建 AI 技能的工作区中创建新的笔记本。
在“资源管理器”窗格左侧,选择“+ 数据源”。 此选项可添加现有湖屋或创建新的湖屋。
在顶部单元格中,添加以下代码片段:
import pandas as pd from tqdm.auto import tqdm base = "https://synapseaisolutionsa.blob.core.windows.net/public/AdventureWorks" # load list of tables df_tables = pd.read_csv(f"{base}/adventureworks.csv", names=["table"]) for table in (pbar := tqdm(df_tables['table'].values)): pbar.set_description(f"Uploading {table} to lakehouse") # download df = pd.read_parquet(f"{base}/{table}.parquet") # save as lakehouse table spark.createDataFrame(df).write.mode('overwrite').saveAsTable(table)
选择“全部运行”。
几分钟后,系统将对湖屋填充必要的数据。
创建 AI 技能
选择数据
选择你创建的湖屋,然后选择“连接”。 然后,必须选择希望 AI 技能可以访问的表。
本练习使用以下表:
DimCustomer
DimDate
DimGeography
DimProduct
DimProductCategory
DimPromotion
DimReseller
DimSalesTerritory
FactInternetSales
FactResellerSales
提供指令
使用所选列示表首次询问 AI 技能问题时,AI 技能会很好地回答这些问题。 例如,对于问题“最畅销的产品是什么?”,AI 技能返回:
Long-Sleeve Logo Jersey, L
但是,SQL 查询需要一些改进。 首先,它只查看 FactResellerSales
表。 它忽略表 FactInternetSales
。 其次,当与产品关联的总销售收入是最重要的考虑因素时,它会按订单数量订购产品,如以下屏幕截图所示:
若要改进查询生成,请提供部分指令,如以下示例所示:
- 每当我询问“最畅销”的产品或商品时,应该关注的指标是总销售收入,而非订购数量。
- 要使用的主表是
FactInternetSales
。 仅当明确询问转售或总销售额时,才使用FactResellerSales
。
再次提问后,系统将返回不同答案“Mountain-200 Black, 46
”,如以下屏幕截图所示:
相应的 SQL 从 FactInternetSales
表提取,并按销售金额的总和进行排序。 AI 遵循了指令。
继续试验查询时,应添加更多指令。
此应用场景使用以下一组指令:
- 每当我询问“最畅销”的产品或商品时,应该关注的指标是销售收入,而非订购数量。
- 要使用的主表是
FactInternetSales
。 仅当明确询问转售或总销售额时,才使用FactResellerSales
。 - 当询问促销的影响时,应询问对销售收入的增加,而不仅仅是销售单位的数量。
- 对于客户见解,请专注于每个客户的总销售额,而非订单数。
- 在执行基于时间的分析时,使用
DimDate
提取特定时间段(例如年份和月)。 - 分析地理数据时,确定每个区域的总销售收入和平均销售额的优先级。
- 对于产品类别见解,请始终使用
DimProductCategory
对产品进行相应分组。 - 比较不同区域之间的销售额时,请使用
DimSalesTerritory
获取准确的区域详细信息。 - 如果以不同的货币分析销售额,请使用
DimCurrency
规范化销售数据。 - 有关详细的产品信息,请始终将
FactInternetSales
与DimProduct
联接。 - 使用
DimPromotion
分析不同促销活动的有效性。 - 对于经销商业绩,请专注于总销售额,而不仅仅是售出的产品数。
- 分析随时间推移的趋势时,请使用
FactInternetSales
并与DimDate
联接,按月份、季度或年份对数据进行分组。 - 始终通过将
FactInternetSales
与相应的维度表联接来检查数据一致性。 - 使用 SUM 聚合销售数据,以确保准确捕获总值。
- 将销售收入指标的优先级设为高于订单数量,以准确衡量财务影响。
- 始终按相关维度(例如产品、客户、日期)分组,以获取详细见解。
- 当询问客户人口统计数据时,请将
DimCustomer
与相关事实数据表进行联接。 - 对于按促销销售,请将
FactInternetSales
与DimPromotion
联接,并按促销名称分组。 - 使用
DimCurrency
规范化销售数据,以进行涉及不同货币的数据比较。 - 使用
ORDER BY
子句按兴趣指标(如销售收入、订单总数)对结果进行排序。 DimProduct
中的ListPrice
是建议的销售价格,而UnitPrice
和FactInternetSales
中的FactResellerSales
是每个单位销售的实际价格。 对于收入的大多数用例,应使用单位价格。- 按销售金额对排名靠前的经销商排序。
如果将此文本复制到“模型的注释”文本框中,则 AI 会在生成其 SQL 查询时引用这些指令。
提供示例
除指令外,示例也可作为指导 AI 的另一有效方法。 如果对 AI 技能的常见接收信息存在疑问,或存在需要复杂联接的问题,请考虑为它们添加示例。
例如,问题“在 2013 年 6 月 1 日,我们有多少活跃客户”会生成部分有效的 SQL,如以下屏幕截图所示:
然而,这不是优秀答案。
部分问题是“活跃客户”无正式定义。 “模型的注释”文本框中的更多说明可能会有所帮助,但用户可能会经常提出此问题。 需要确保 AI 能够正确处理问题。 相关查询比较复杂,因此请选择“编辑”按钮提供示例。
然后,可以上传示例。
重复提问问题可以返回优化后的答案。
可以手动添加示例,但也可以通过 JSON 文件上传示例。 如果存在多个要同时上传的 SQL 查询,请勿手动上传查询,提供文件中的示例非常有帮助。 对于本练习,请使用以下示例:
{
"how many active customers did we have June 1st, 2010?": "SELECT COUNT(DISTINCT fis.CustomerKey) AS ActiveCustomerCount FROM FactInternetSales fis JOIN DimDate dd ON fis.OrderDateKey = dd.DateKey WHERE dd.FullDateAlternateKey BETWEEN DATEADD(MONTH, -6, '2010-06-01') AND '2010-06-01' GROUP BY fis.CustomerKey HAVING COUNT(fis.SalesOrderNumber) >= 2;",
"which promotion was the most impactful?": "SELECT dp.EnglishPromotionName, SUM(fis.SalesAmount) AS PromotionRevenue FROM FactInternetSales fis JOIN DimPromotion dp ON fis.PromotionKey = dp.PromotionKey GROUP BY dp.EnglishPromotionName ORDER BY PromotionRevenue DESC;",
"who are the top 5 customers by total sales amount?": "SELECT TOP 5 CONCAT(dc.FirstName, ' ', dc.LastName) AS CustomerName, SUM(fis.SalesAmount) AS TotalSpent FROM FactInternetSales fis JOIN DimCustomer dc ON fis.CustomerKey = dc.CustomerKey GROUP BY CONCAT(dc.FirstName, ' ', dc.LastName) ORDER BY TotalSpent DESC;",
"what is the total sales amount by year?": "SELECT dd.CalendarYear, SUM(fis.SalesAmount) AS TotalSales FROM FactInternetSales fis JOIN DimDate dd ON fis.OrderDateKey = dd.DateKey GROUP BY dd.CalendarYear ORDER BY dd.CalendarYear;",
"which product category generated the highest revenue?": "SELECT dpc.EnglishProductCategoryName, SUM(fis.SalesAmount) AS CategoryRevenue FROM FactInternetSales fis JOIN DimProduct dp ON fis.ProductKey = dp.ProductKey JOIN DimProductCategory dpc ON dp.ProductSubcategoryKey = dpc.ProductCategoryKey GROUP BY dpc.EnglishProductCategoryName ORDER BY CategoryRevenue DESC;",
"what is the average sales amount per order by territory?": "SELECT dst.SalesTerritoryRegion, AVG(fis.SalesAmount) AS AvgOrderValue FROM FactInternetSales fis JOIN DimSalesTerritory dst ON fis.SalesTerritoryKey = dst.SalesTerritoryKey GROUP BY dst.SalesTerritoryRegion ORDER BY AvgOrderValue DESC;",
"what is the total sales amount by currency?": "SELECT dc.CurrencyName, SUM(fis.SalesAmount) AS TotalSales FROM FactInternetSales fis JOIN DimCurrency dc ON fis.CurrencyKey = dc.CurrencyKey GROUP BY dc.CurrencyName ORDER BY TotalSales DESC;",
"which product had the highest sales revenue last year?": "SELECT dp.EnglishProductName, SUM(fis.SalesAmount) AS TotalRevenue FROM FactInternetSales fis JOIN DimProduct dp ON fis.ProductKey = dp.ProductKey JOIN DimDate dd ON fis.ShipDateKey = dd.DateKey WHERE dd.CalendarYear = YEAR(GETDATE()) - 1 GROUP BY dp.EnglishProductName ORDER BY TotalRevenue DESC;",
"what are the monthly sales trends for the last year?": "SELECT dd.CalendarYear, dd.MonthNumberOfYear, SUM(fis.SalesAmount) AS TotalSales FROM FactInternetSales fis JOIN DimDate dd ON fis.ShipDateKey = dd.DateKey WHERE dd.CalendarYear = YEAR(GETDATE()) - 1 GROUP BY dd.CalendarYear, dd.MonthNumberOfYear ORDER BY dd.CalendarYear, dd.MonthNumberOfYear;",
"how did the latest promotion affect sales revenue?": "SELECT dp.EnglishPromotionName, SUM(fis.SalesAmount) AS PromotionRevenue FROM FactInternetSales fis JOIN DimPromotion dp ON fis.PromotionKey = dp.PromotionKey WHERE dp.StartDate >= DATEADD(MONTH, -1, GETDATE()) GROUP BY dp.EnglishPromotionName ORDER BY PromotionRevenue DESC;",
"which territory had the highest sales revenue?": "SELECT dst.SalesTerritoryRegion, SUM(fis.SalesAmount) AS TotalSales FROM FactInternetSales fis JOIN DimSalesTerritory dst ON fis.SalesTerritoryKey = dst.SalesTerritoryKey GROUP BY dst.SalesTerritoryRegion ORDER BY TotalSales DESC;",
"who are the top 5 resellers by total sales amount?": "SELECT TOP 5 dr.ResellerName, SUM(frs.SalesAmount) AS TotalSales FROM FactResellerSales frs JOIN DimReseller dr ON frs.ResellerKey = dr.ResellerKey GROUP BY dr.ResellerName ORDER BY TotalSales DESC;",
"what is the total sales amount by customer region?": "SELECT dg.EnglishCountryRegionName, SUM(fis.SalesAmount) AS TotalSales FROM FactInternetSales fis JOIN DimCustomer dc ON fis.CustomerKey = dc.CustomerKey JOIN DimGeography dg ON dc.GeographyKey = dg.GeographyKey GROUP BY dg.EnglishCountryRegionName ORDER BY TotalSales DESC;",
"which product category had the highest average sales price?": "SELECT dpc.EnglishProductCategoryName, AVG(fis.UnitPrice) AS AvgPrice FROM FactInternetSales fis JOIN DimProduct dp ON fis.ProductKey = dp.ProductKey JOIN DimProductCategory dpc ON dp.ProductSubcategoryKey = dpc.ProductCategoryKey GROUP BY dpc.EnglishProductCategoryName ORDER BY AvgPrice DESC;",
}
测试和修改 AI 技能
指令和示例均已添加到 AI 技能中。 随着测试的进行,更多示例和指令可以进一步提高 AI 技能。 与你的同事协作,确定你是否提供了涵盖他们想要提问的问题的示例和说明。
通过编程使用 AI 技能
可以在 Fabric 笔记本中通过编程使用 AI 技能。 若要确定 AI 技能是否具有已发布的 URL 值,请选择“设置”,如以下屏幕截图所示:
在发布 AI 技能之前,该技能没有已发布的 URL 值,如以下屏幕截图所示:
验证 AI 技能的性能后,你可能会决定予以发布。 在这种情况下,请选择“发布”,如以下屏幕截图所示:
系统将显示 AI 技能的已发布 URL,如以下屏幕截图所示:
然后,可以复制已发布的 URL 并将其用于 Fabric 笔记本。 以此,就可以通过在 Fabric 笔记本中调用 AI 技能 API 来查询 AI 技能。 将复制的 URL 粘贴到此代码片段中。 然后,将问题替换为与 AI 技能相关的任何查询。 此示例使用 \<generic published URL value\>
作为 URL。
import requests
import json
import pprint
from synapse.ml.mlflow import get_mlflow_env_config
# the URL could change if the workspace is assigned to a different capacity
url = "https://<generic published URL value>"
configs = get_mlflow_env_config()
headers = {
"Authorization": f"Bearer {configs.driver_aad_token}",
"Content-Type": "application/json; charset=utf-8"
}
question = "{userQuestion: \"what is an example product?\"}"
response = requests.post(url, headers=headers, data = question)
print("RESPONSE: ", response)
print("")
response = json.loads(response.content)
print(response["result"])