社内 AI エージェント Synapse と セマンティックレイヤーの育て方というタイトルで登壇しました+補足

エンジニアの佐野です。「セマンティックレイヤーをどう育て、信頼できるAI Agentを開発するか」というイベントにて「社内 AI エージェント Synapse と セマンティックレイヤーの育て方」というタイトルで登壇しました。本日は内容の補足を書きます。

イベントおよび Synapse について

イベント運営の Findy さん、タイミーのchanyou0311 さん, メルカリのhanon52_ さんありがとうございました。

findy.connpass.com

私の登壇資料はこちらになります。

speakerdeck.com

Synapse についてですが、社内向け AI エージェントで、カンムの製品であるバンドルカードのデータ分析や業務支援を行う機能が搭載されています。 Synapse については本ブログでも何度か記事になっています。特に意図していたわけではないのですが、結果的にシリーズ化してきました。こうして並べてみると Synapse がどのように進化してきたのかが見えるのは面白いところです。

tech.kanmu.co.jp tech.kanmu.co.jp tech.kanmu.co.jp

以下、補足を書いていきます。まず、これは登壇資料にも書いた通りですが、ここでいうセマンティックレイヤーとは、AI エージェントが社内の業務文脈で正しく答えるための用語・データ構造・業務ルールの知識層のことを指します。これを書いた意図としては、セマンティックレイヤー自体は AI 時代の新概念ではなく古くから存在している概念なのでここでの意味を明らかにするためです。

補足: セマンティックレイヤーの始め方

まとめの箇所に書きましたが、まずは小さく始めることです。登壇では不確実性という話をしました。ここでいう不確実性とは LLM は本当にカンムの業務内容を解釈してくれるのかどうか?です。LLM を利用したプログラミングを例に出し *1 、コンテキストにカンムの業務説明を与えたら本当にそれに沿って動いてくれるかどうかを検証したかった、という内容です。

期待通りの挙動をしてくれなかった例として、Synapse の運用中に起きたエピソードを書きます。一時期マルチLLMを導入していた時期がありました。次の様な処理シーケンスです。

  • User: ユーザプロンプトを投げる
  • Synapse: ユーザプロンプトを受信して Gemini 2.5 Flash にて内容の難易度を判定する
  • if easy: -> Gemini 2.5 Flash が処理を行う
  • else: -> Gemini 3.1 Pro が処理を行う
  • User: 応答を得る

このようにしていたのは、簡単な内容であれば応答速度が速くてコストも低い Flash の方がユーザ体験が良いだろう、という目論見でした。しかしながら Gemini 2.5 Flash が選択された場合、回答の精度が悪いケースが目立ったので今では Gemini 3.1 Pro に一本化されています。精度が悪い原因の中には、「セマンティックレイヤーに説明があるにもかかわらず、その説明を十分に踏まえた回答になっていない」と見えるものも含まれていました。これは、単にコンテキストに業務知識を書けばよいわけではなく、モデルがその知識をどの程度参照し、どの程度指示として守ってくれるかにも不確実性がある、ということを示しています。

よって皆様の環境で使っているモデルと業務内容や書き方の組み合わせで検証結果は白にも黒にもなると考えています。いきなり重厚なアーキテクチャで巨大なセマンティックレイヤーを食わせるよりも、最低限のコンポーネントのみで動くものを作り、簡単な内容を与えるところからスタートするとよいでしょう。うまくいかなかったときの原因が追いやすくなります。セマンティックレイヤーの記述のしかただけでなく、モデルを変更してどう挙動が変わるかも検証のポイントとして存在していると考えています。

補足: セマンティックレイヤーはないとダメなのか?

期待通りに動けばなくてもよいのですがそれはなかなか難しいと考えています。Text-to-SQL をする場合、LLM がテーブル名やカラム名からユーザが意図したとおりの SQL を生成してくれるかもしれません。しかしながらテーブル設計の意図や存在しているデータの意味や扱い方はテーブル名やカラム名からは判断することが困難だったりします。例えば customer テーブルというものがあるとして、そこにレコードが存在しているということは何を意味するのか?customer テーブルの1レコードは「アプリに登録したユーザ」を表すのか、「本人確認済みの顧客」を表すのか?そのような解釈によって生成されるべき SQL は変わります。

補足: ベクトルDBは使わないのか?

今のところ導入する予定はありません。不確実性の検証のためにまずは取り回しがしやすかったシステムプロンプトにセマンティックレイヤーを記述し、それがワークしたらアーキテクチャ変更もあって MCP サーバに記述する方式にして現在に至っています。これで特に大きな不具合もないためまだこの構成でいくつもりです。 ベクトルDBの導入は「小さく始める」というコンセプトから外れます。つまり複雑性を増やす要因になります。チャンクをどうするか?ミドルウェアの設定をどうするか?といった考慮事項が増えることに加えてインフラ運用コスト(人的・金銭的両方)にも力を割く必要があります。

ベクトルDBは、LLM のコンテキスト長が小さかった時代に、必要なコンテキストを必要なタイミングで必要な分だけ渡すための有力な選択肢だったと思います。ただし、少なくとも現在のカンムのワークロードでは、コンテキスト長の制約を主な理由としてベクトルDBを導入する必要性はあまり感じていません。

補足: 生成される SQL の評価について

Execution Accuracy でテストしているということを登壇中に言いました。他の手法について紹介しますと、Text-to-SQL の評価には概ね次のような手法があります。おおまかにいうと Execution Accuracy と Exact Match の2系統で、他はそれぞれの派生になります。

評価手法 説明
Execution Accuracy 期待された結果が返ってくるかを見る。
Exact Match 生成された SQL が期待された SQL と一致しているかを見る。
Component Match Accuracy Exact Match と近いが SQL の構成要素 (SELECT 句、WHERE 句、JOIN 句...) に分けてそれらが一致しているかを見る。
Valid Efficiency Score 結果だけでなく実行効率の良さも見る。
Query Variance Testing 異なる表現に対応できるか?を見る。「最も売れている商品は?」と「一番の売れ筋は?」が同じ意味であれば同じ SQL が生成されるかどうか。

例えば次の様な employee テーブルがあったとします。

id name start_date
1 suzuki 2026-01-01
2 tanaka 2026-02-01
3 sato 2026-03-01
4 suzuki 2026-03-01

重複を省いた全社員の名前を抽出する場合このような SQL が考えられます。

SELECT name FROM employee GROUP BY name ORDER BY name

もしくはこう。

SELECT DISTINCT name FROM employee ORDER BY name

どちらも実行結果は

name
sato
suzuki
tanaka

になります。データ分析であるということと、バックエンドが BigQuery であることを考えるとどのような SQL が生成されるかはそれほど関心がありません *2 。よって Execution Accuracy で評価を行うのがベターだと考えています。実行結果の一致/不一致はそのテストも記述しやすいです。ただし弱点もあり、SQL は間違っているがたまたま同じ結果になってしまうものが生成されたときにそれが正解として通ってしまうことです。そのため評価データには、たまたま同じ結果になりにくいデータ、を含めることが重要になります。

Exact Match は先ほどの例だと SELECT name FROM employee GROUP BY name ORDER BY name を期待してそれと全く同じものが生成されるかどうかをテストするもので、 SELECT DISTINCT name FROM employee ORDER BY name が生成されたら NG として判定します。オンライン処理に使う SQL で使ってほしいインデックスがある場合など、生成される SQL 自体が重要という局面においては価値が出る手法になります。

補足: セマンティックレイヤーの導入を含め、AIエージェント開発をする際の組織構造

これはタイミーさんとメルカリさんの発表を見ての感想も込みの補足です。タイミーさんは「セマンティックレイヤーの立ち上げ...」というページにて中央データチームと特定ドメインチームの話をしてくれました。メルカリさんも「中央組織と各ドメイン組織...」という話をしてくれました。対してカンムの Synapse のチームは「他の組織を巻き込んでやっていく」という意識があまりないな...と思ったりしました。

というのも、現チームメンバーの3人は元々バンドルカードのサーバサイド・インフラの開発をしていたというのもあり、データ構造やビジネスロジック、関連部署の関心ごとや業務の動きはだいたいわかっていたというのがあります。つまり3人が馬力を出せばセマンティックレイヤーは一気に書き上げて運用に乗せることができる、と。生成された回答が妥当かどうかについても判断が可能でした。 しかしながらここ1年くらいはバンドルカードの開発から離れているので知らないことがどんどん増えていっています。また新しいプロダクトが生まれてそこで Synapse と同じものを導入しよう、となったときにはおそらく今の組織構造のままでは導入は難しくなりそうだと思いました。

セマンティックレイヤーの記述にはアプリケーション開発に明るいメンバーや業務知識があるメンバーが必須ではあると言えます。セマンティックレイヤーを記述できる人間が社内のどこに存在しているか、その人を巻き込むことができるか、セマンティックレイヤーを始める上での重要な要素となります。

セマンティックレイヤーは一度作ったらプロダクトの成長にともなって育てていくものだと考えています。まずは小さく始め、実際の質問と失敗例を通じて更新し続けることが重要です。それが信頼できる AI エージェントを運用するための現実的な進め方だと思います。

おわり

*1:「このファイルは変更しないでください」と指示を出してもそれを無視することがあるetc

*2:まあ... SELECT * FROM UNNEST([ STRUCT('sato' AS name), STRUCT('suzuki' AS name), STRUCT('tanaka' AS name)]) のような噴飯物の SQL を生成していた...のようなことがなければ...