AdventureWorks データセットを使用した AI スキルの例 (プレビュー)
この記事では、AdventureWorks データセットで AI スキルを構成する方法について説明します。
重要
この機能はプレビュー段階にあります。
前提条件
- 有料の F64 以上のファブリック容量リソース。
- AI スキル テナントの切り替え が有効になっています。
- Copilot テナント スイッチ が有効になっています。
- AI のクロス Geo 共有は、関連する場合に有効になります。
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
は推奨される販売価格ですが、FactInternetSales
とFactResellerSales
のUnitPrice
は各ユニットが販売された実際の価格です。 収益に関するほとんどのユース ケースでは、単価を使用する必要があります。- 売上金額で上位リセラーをランク付けします。
このテキストをモデルの [メモ] テキスト ボックスにコピーすると、AI は SQL クエリを生成するときにこれらの指示を参照します。
例を挙げる
指示に加えて、例は AI を指導するもう 1 つの効果的な方法として機能します。 AI スキルがよく受け取る質問や複雑な結合が必要な質問がある場合は、それらの例を追加することを検討してください。
たとえば、次のスクリーンショットに示すように、「2013 年 6 月 1 日のアクティブ顧客数は」という質問では、有効な SQL がいくつか生成されます。
しかし、それは良い回答ではありません。
問題の一部は、"アクティブな顧客" に正式な定義がないという点です。 モデルのテキスト ボックスへのメモの詳細な指示が役立つ場合がありますが、ユーザーはこの質問を頻繁に行う場合があります。 AI が問題を正しく処理していることを確認する必要があります。 関連するクエリは中程度に複雑であるため、編集ボタンを選択して例を示します。
その後、例をアップロードできます。
質問を繰り返すことで、改善された回答を返します。
例は手動で追加できますが、JSON ファイルからアップロードすることもできます。 ファイルから例を提供すると、クエリを 1 つずつ手動でアップロードするのではなく、一度にアップロードする 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, 0, 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 スキルを使用する
AI スキルは、Fabric ノートブック内でプログラムで使用できます。 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"])