「6月の売上」は答えられるのに、「顧客LTV」では間違える
「SQLってAIでどうやって作ればいいんですか」。ほんの2、3か月前、エンジニアからそう尋ねられたことがあるという。そう明かしたのは、SnowflakeでLead Developer Advocateを務める田中翔氏だ。tshoというハンドルで活動し、AI/MLとデータ領域の登壇やデモ開発を担当している。
問いを裏返せば、正しいテーブル定義さえ渡せばLLMは正しいSQLを書いてくれるのか、ということになる。田中氏は小売業を模したベンチマーク用データベースであるTPC-DSを使い、この前提を検証した。投げた質問は3つ。「6月の売上合計は?」「ブランド別売上は?」「顧客LTVは?」である。
結果は2勝1敗に分かれた。前の2問は、DDLだけを渡した場合でも正しいSQLが生成された。テーブル定義には外部キー制約が書かれており、どのテーブルをどう結合すべきかはそこから推論できるためだ。ところが3問目の顧客LTV(ライフタイムバリュー)で、生成されたSQLは誤った計算をした。
理由は単純である。LTVは「売上÷ユニーク顧客数」で求めるという計算ルールが、DDLのどこにも書かれていないからだ。「LLMは知らないわけですから。知らないことを分かってほしいというのは、やはり難しい」と田中氏は言う。
同じ問題は、カラム名の解釈でも起きる。田中氏が挙げたのは、TPC-DSの売上テーブルにあるss_sales_priceとss_ext_sales_priceという2つのカラムだ。どちらが実際の「売上」を指すのか、DDLからは判別できない。
これは架空の例ではない。「カラムの継ぎ足しを重ねていて、2つ以上に売上とついたカラムがあり、どちらが今使いたい売上に関するカラムなのか? ということがよくありました」。田中氏は事業会社にいた当時の実感をそう振り返る。更新を重ねるうちに、どちらが正しい売上を表すのか誰にも分からなくなる。多くの読者が心当たりのある光景だろう。
田中氏は原因をこう一般化した。DDLはデータの「形」のみを定義するもので、「意味」、すなわちビジネスルールや計算式は定義しない。同義語も、社内固有のKPIの算出ロジックも、そこには存在しない。
つまりこれは、LLMの性能の問題ではない。モデルに与えるコンテキストが欠けているという設計の問題である。だとすれば、欠けている「意味」をどう記述して渡すかが論点になる。
意味を規格化する動き──Open Semantic InterchangeからApache Ossieへ
その「意味」の記述形式を、企業をまたいで共通化しようという動きが進んでいる。2025年にSnowflakeが提唱したOpen Semantic Interchange(OSI)である。GitHub上のリポジトリは2025年11月に公開され、Apache 2.0ライセンスのもとで仕様策定が進む。当初の創業パートナーから、現在は50社以上へと参加が広がった。
参加企業の顔ぶれは、データ基盤とBIの主要プレイヤーをほぼ横断している。Salesforce、dbt Labs、ThoughtSpot、Mistral AI、BlackRock、Atlan、Sigma、Hexなどが名を連ねる。掲げる原則は3つで、定義のための統一言語をつくる「標準化」、シームレスなデータ変換を促す「相互運用性」、データニーズの変化にモデルを適応させる「拡張性」だ。
そして7月、このOSIがApache Software Foundationのインキュベータープロジェクトに採用された。同時に名称がApache Ossie(Incubating)へと変わっている。OSIという略称がオープンソースの世界で別のプロジェクトと重なるため、混同を避けるための改名だという。
実務上の注意点として、田中氏は表記の混在を挙げた。改名は完了しているものの、ドキュメントやWeb上には旧OSI表記の名残がまだある。「Apacheの下に入っているので、そこと間違えないようにしてください」。調べる際は、仕様はGitHubのapache/ossie、最新情報はApache Ossie公式サイトを起点にするのが確実だ。
セマンティックモデルとセマンティックレイヤーは何が違うのか
ここで田中氏は、混同されやすい2つの用語を切り分けた。業界でも会社によって解釈が異なると前置きした上で、本セッションでの定義を示している。
「セマンティックモデル」の実態は、指標や次元を記述したYAMLまたはJSONファイルである。「売上とは何か」「どう計算するか」といったルールをまとめた情報、いわばビジネス定義の設計図だ。Apache Ossieが標準化しているのは、こちらである。
対して「セマンティックレイヤー」は、データ基盤とBIツールやAIエージェントの間で実際に動く層を指す。モデルを読み込み、ユーザーの質問をSQLに変換してデータを返す、定義の実行エンジンにあたる。こちらは、リファレンス実装は存在するが、各社が自由に独自実装することも可能だと田中氏は位置づけた。
規格が定めるのは仕様書の書式まで。それを動かすエンジンは各社の実装に委ねられている、という住み分けである。
DDLのみとApache Ossieに準じたセマンティックモデル付きで、生成されるSQLはどう変わったか
田中氏のデモは、同じ質問を2系統のプロンプトに流して結果を並べる構成だった。片方はシステムプロンプトにDDLスキーマだけを入れた「without Ossie」、もう片方はそこにApache Ossie準拠のYAML定義書retail_model.yamlを加えた「with Ossie」である。
環境はLLMがLlama 3.1(70B)、データベースはDocker上のPostgreSQLで、17.7と18.4の両方を試したという。LLMの呼び出しにはSnowflakeのCortex REST APIを使ったが、「Snowflakeに限定した話ではありません」と田中氏は強調した。Ollamaでローカルで動かすことも、各社のAPIへ直接問い合わせることもできる。コードはllm-ossie-postgresで公開済みで、手元で追試できる。
前述のとおり、「6月の売上合計」と「ブランド別売上」ではOssieの有無で結果は変わらなかった。田中氏はこの点を隠さず、むしろ先に注意を促している。「最近の大規模言語モデルがかなり優秀になってきているので、結果に差が出にくくなってきているかもしれません」。
差が出たのは顧客LTVである。DDLのみの場合、生成されたSQLはSUM(ss_ext_sales_price)で止まった。売上を合計しただけで、これはLTVではない。一方、YAML定義書を添えた場合は、売上合計をCOUNT(DISTINCT ss_customer_sk)で割る式が生成された。顧客数で割らなければ全体のLTVにならないという計算ルールが、定義書を通じて伝わった結果だ。
====================================================================== Apache Ossie Demo: LLM SQL Generation Comparison Database: PostgreSQL (local) Semantic Model: retail_model.yaml LLM: cortex (llama3.1-70b) ====================================================================== ====================================================================== QUESTION: What is the total sales revenue for June? ====================================================================== --- WITHOUT Ossie (DDL only) --- SQL: SELECT SUM(ss_ext_sales_price) FROM store_sales INNER JOIN date_dim ON store_sales.ss_sold_date_sk = date_dim.d_date_sk WHERE date_dim.d_month_name = 'June' Result: sum ------- 1160.73 --- WITH Ossie (DDL + Semantic Model) --- SQL: SELECT SUM(T2.ss_ext_sales_price) FROM date_dim AS T1 INNER JOIN store_sales AS T2 ON T1.d_date_sk = T2.ss_sold_date_sk WHERE T1.d_month_name = 'June' Result: sum ------- 1160.73 ====================================================================== QUESTION: Show me sales by brand. ====================================================================== --- WITHOUT Ossie (DDL only) --- SQL: SELECT i.i_brand, SUM(ss.ss_ext_sales_price) AS total_sales FROM item i JOIN store_sales ss ON i.i_item_sk = ss.ss_item_sk GROUP BY i.i_brand Result: i_brand | total_sales ------------+------------ Lululemon | 272.00 Coach | 269.97 Nissin | 181.86 Anker | 239.84 Sony | 559.93 Nike | 649.95 Starbucks | 274.89 Hydro Flask | 244.93 --- WITH Ossie (DDL + Semantic Model) --- SQL: SELECT T2.i_brand, SUM(T1.ss_ext_sales_price) FROM store_sales AS T1 INNER JOIN item AS T2 ON T1.ss_item_sk = T2.i_item_sk GROUP BY T2.i_brand Result: i_brand | sum ------------+------- Lululemon | 272.00 Coach | 269.97 Nissin | 181.86 Anker | 239.84 Sony | 559.93 Nike | 649.95 Starbucks | 274.89 Hydro Flask | 244.93 ====================================================================== QUESTION: What is the customer lifetime value? ====================================================================== --- WITHOUT Ossie (DDL only) --- SQL: SELECT SUM(ss_ext_sales_price) FROM store_sales Result: sum ------- 2693.37 --- WITH Ossie (DDL + Semantic Model) --- SQL: SELECT SUM(T1.ss_ext_sales_price) / COUNT(DISTINCT T1.ss_customer_sk) FROM store_sales AS T1 Result: ?column? -------------------- 538.6740000000000000 ===================================
トレードオフもある。DDL全文に加えてYAML全文を送るため、プロンプトは確実に長くなる。それでもSQLの正確性はこちらが上だった、というのが検証の結論である。この長さの問題は、後述するセマンティックレイヤーの出番につながる。
YAML定義書には何を書くのか
では、その定義書には何を書くのか。田中氏が用意したretail_model.yamlは、Apache Ossie公式リポジトリのTPC-DS向けサンプルを土台にしたものだ。冒頭のversionは0.2.0.dev0。仕様がまだ策定途上であることが、バージョン番号にそのまま表れている。
ファイルの構成は大きく3つに分かれる。テーブルの所在とプライマリキー、各カラムの説明を記述するdatasets、テーブル間の結合を定義するrelationships、そして指標の計算式を書くmetricsである。SQLの方言も指定でき、この定義書ではANSI_SQLが使われている。
目を引くのはai_contextという欄だ。ここには自然言語でAIへの指示を書ける。田中氏の定義書には、「Salesまたはrevenueは常にSUM(ss_ext_sales_price)を意味し、SUM(ss_sales_price)ではない」という一文が明記されている。1ページ目で判別できなかった2つのカラムの正体もここで分かる。前者が単価、後者が数量と単価をかけた明細行の合計金額であり、売上として集計すべきは後者だ。
version: "0.2.0.dev0"
semantic_model:
- name: tpcds_retail_model
ai_context:
instructions: >
Use this semantic model for retail analytics queries.
Key rules:
- "Sales" or "revenue" always means SUM(ss_ext_sales_price), NOT SUM(ss_sales_price).
ss_sales_price is the unit price; ss_ext_sales_price is the extended (total line) amount.
- "Profit" means SUM(ss_net_profit).
- Always join fact table store_sales to dimension tables using the surrogate key relationships defined below.
# (中略:datasets、relationships の定義が続く)
metrics:
- name: total_sales
expression:
dialects:
- dialect: ANSI_SQL
expression: SUM(store_sales.ss_ext_sales_price)
description: Total sales revenue (extended price, not unit price)
- name: customer_lifetime_value
expression:
dialects:
- dialect: ANSI_SQL
expression: SUM(store_sales.ss_ext_sales_price) / COUNT(DISTINCT store_sales.ss_customer_sk)
description: Average total revenue per unique customer
ai_context:
synonyms:
- "CLV"
- "LTV"
- "customer value"
肝になるのはmetricsだ。売上合計だけでなく、LTVを「売上合計÷ユニーク顧客数」として式で明記する。従業員1人当たりの売上を表す店舗生産性のような指標も、同じ形式で定義されている。
そしてsynonyms、いわゆるシノニムの欄がある。CLVとLTVと顧客価値は同じ指標だと書いておけば、どの語で聞かれても同じ計算で答えが返る。指標の呼び名が部署ごとに違う現場ほど、この効き目は大きいだろう。
なお、仕様はまだ発展途上だ。田中氏は未収載の機能としてVerified Query、人間が正解と確認したクエリを検証用に保持する仕組みを挙げた。共通規格であるため、仕様の追加はGitHubやメーリングリスト上での公開議論を経て、正式な投票プロセスで決まっていく。投票に加わるコミッター権限は所属企業ではなく貢献によって得られる。
「プルリクエストやイシューなどで活発に議論されており、今後ますます発展していくことが楽しみです」という言葉どおり、いま仕様を読んでおくこと自体が議論への参加につながる段階にある。
自動化するなら実行層へ──SnowflakeのSemantic ViewsとCortex Analyst
最後に田中氏は、標準化の対象外であるセマンティックレイヤー側の実装例として、自社の取り組みを紹介した。Snowflakeでこの層に該当するのがSemantic Viewsである。
ポイントは、レイヤーを事前に登録しておける点だ。デモで見たようにプロンプトへ毎回定義を丸ごと入れる必要がなく、質問に必要な箇所だけが使われる。プロンプトが長くなるという先のトレードオフに対する答えがこれである。精度の評価機能も用意され、Verified Queryを使ってどの程度正確に答えられているかを測れる。
具体的なサービスとしてはCortex Analystが挙げられた。Apache Ossieにほぼ準拠したYAMLファイルをアップロードすればセマンティックモデルが登録され、それを基にレイヤーが構成される。田中氏が動画で示したデモでは、「商品カテゴリーごとの6月から8月までの売上トレンドを表示してください」という日本語の問いに対し、DDL全体を毎回送ることなく最適化されたSQLが生成された。データがSnowflakeの境界を離れず、既存のRBACと統合される点もフルマネージドサービスの利点として説明された。
田中氏が示した持ち帰りは2段階だった。まずApache Ossieの仕様を確認し、手元で試す。そのうえで、自力での運用が負担になるならセマンティックレイヤーを実装したツールで自動化・最適化を検討する。順序が逆でないことに意味がある。渡すべき「意味」を自分たちの言葉で書けているかどうかが先で、実行基盤の選択はその次だ。
「DDLだけでは不十分だということが、ご理解いただけたかと思います」。田中氏はそう締めくくった。自社のKPIの計算式が、いまどこに書かれているかを思い出せるだろうか。それが誰かの頭の中にしかないのなら、AIエージェントにも同じことが起きている。
Snowflakeからのお知らせ
本セッションでご紹介したサービスにご興味を持たれた方は、ぜひ公式サイトをご覧ください。

