Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

Bill Oneのデータ分析エージェントをインターンで開発した話

はじめに

こんにちは、はじめまして! Sansanの技術本部 CTO室 AI Solution Developmentでインターンをしていた広瀬エイトル(@Heitor_Hirose)です。*1

約1カ月半のインターンシップで、Bill One向けのデータ分析エージェントの開発に取り組みました。自然言語で質問するだけで、Bill Oneのデータを検索・集計・可視化できるツールです。

この記事では、技術スタックの選定理由、詰まったポイントを中心にまとめます。

なぜデータ分析エージェントが必要だったのか

Bill Oneは、Sansanが提供する経理AXサービスです。事業の成長に伴い、営業メンバーやPdMからのデータ集計・分析依頼が増加しています。

しかし、対応できるデータエンジニアのリソースには限りがあります。依頼のたびに「何を・なぜ取りたいか」を言語化して伝えるコストが双方に発生して、ボトルネックになりつつある状況でした。さらに、どのようなデータが存在するのかが非エンジニアには把握しづらく、データの存在自体がブラックボックス化していました。

このような背景から、「誰でも自然言語でデータにアクセスできる状態を作る」ことをゴールに据えて開発を始めました。

取り組みの全体像

今回のインターンでは主に2つの軸を中心に進めました。

① データモデリング

  • ディメンショナルモデリング・スタースキーマの設計
  • dbt + BigQueryを用いたデータ基盤の整備
  • データエンジニアの仕事を肌感覚で理解する

② AIエージェント開発

  • Google ADK(Agent Development Kit)を用いたエージェント実装
  • AG-UIプロトコルによるフロントエンドとの通信
  • Cloud Run + IAPによるインフラ構築
  • LLMOps(Langfuse)の導入

システムアーキテクチャ

プロダクト全体の基本的なシステムはすべてGoogle Cloud Platform上に構築されています。3つのコンポーネントを主軸に構成されています。

コンポーネント
iceberg-ui データ分析エージェントのフロントエンド Next.js / Cloud Run
penguin-agent-api エージェント実行・AG-UIミドルウェア ADK / FastAPI / Cloud Run
penguin-agent エージェントのセッション管理 Vertex AI Agent Engine

フロントエンド(iceberg-ui)とエージェントAPI(penguin-agent-api)はAG-UIプロトコルで通信しています。セッション管理にはVertex AI Agent Engineを使用していますが、後述する理由からエージェントの実行環境としては使用していません。

エージェント向けのデータ基盤層

エージェントがアクセス制限の必要な生データに直接触れないよう、エージェント専用のデータモデリング層を設けています。これにより、エージェントはエンジニアが用意・整形したデータのみを使って分析する構造になっています。

扱えるデータソースは主に2種類です。

modeled-data(BigQuery)

当社の統合データ基盤であるColossusから取得したCRM系データ・プロダクトデータを、エージェントが扱いやすい形に整形したデータがあります。ファクトテーブルとディメンションテーブルを想定している用途ごとに分離・整形しています。これらのデータはエージェントの回答精度の品質と設計に直結しているため、慎重に扱っています。

Knowledge System(Markdownファイル群)

Colossusに存在するデータソースのテーブル定義などが記述されたMarkdownファイル群です。プロジェクトのGitHub上で管理されており、ADKのツール呼び出しとして使用できるようになっています。Bill Oneの営業が使用する特殊な用語の説明・日々行っている分析手法・過去の実例をナレッジとしてまとめており、エージェントはクエリ実行前にこれを参照して適切なテーブル・カラムを選択できます。

LLMOps層

penguin-agent-apiから社内で構築・運用されているLangfuseに対してトレースを送信しています。各ユーザーが使用したBigQueryのコストやエージェントの動作を観測できる状態に保っています。

その他

このプロダクトでは、Bill Oneに関係する社員にのみ使用することを想定しているため、iceberg-uiにIAPを設定しています。これにより、指定したGoogleグループのみがアクセスできる状態を担保するようにしました。

AIエージェントの開発

ADK + AG-UIを選定した理由

エージェントの主要なフレームワークとして、Google ADK(Agent Development Kit)を採用しました。主な理由は2つです。

1つ目は、同じチームで開発している既存のエージェントサービスと技術スタックを合わせるためです。そちらも社内の社員向けに機能を提供しているのですが、ADK + AG-UIの構成を採用しています。同じチームで異なるフレームワーク、構成を並行してメンテナンスするコストを避けました。

2つ目は、ADKではBigQueryを前提とした標準ツールが複数整備されており、今回のケースととても相性が良かったためです。

フロントエンドとの通信にはAG-UI(Agent-User Interaction Protocol)を採用しました。AG-UIはCopilotKitチームが開発したオープンプロトコルで、エージェントとユーザーインターフェースの間のやり取りをイベントストリームとして標準化できます。社内の既存プロジェクトが同じ構成でAG-UIを採用していたため、フロントエンドに関する実装の一部を流用でき、開発効率の向上につながりました。

行き詰まったポイント: Vertex AI Agent Engineに対する調査不足

当初はVertex AI Agent Engineをエージェントの実行環境として使用する設計を試みました。しかし、以下の制約に直面しました。

  • Agent Engineをランタイムとして使う場合、通信方式をカスタマイズできない
  • 対応しているのはA2AとGoogle独自のSSEのみで、AG-UIには未対応
  • Next.jsのAPI RouteでAG-UIプロトコルを自前実装すれば対応可能だが、チームのメンテナンスコストを考えて断念

最終的に、エージェントの実行環境はFastAPI on Cloud Runに完全移行し、Vertex AI Agent Engineはセッション管理のみに用途を限定しました。この判断により、AG-UIミドルウェア(pypi.org/project/ag-ui-adk)をそのまま使用でき、実装量を大幅に削減できました。

from ag_ui_adk import ADKAgent, add_adk_fastapi_endpoint

adk_agent = ADKAgent(
    adk_agent=root_agent,
    app_name=app_name,
    session_service=shared_session_service
)

add_adk_fastapi_endpoint(app, adk_agent, path="/penguin-agent")

LLMOps - 可観測性のあるエージェントに

Langfuse SDKを使用してトレースを管理・送信するようにしました。

LLMの生成は本質的に不安定なので、出力した結果の追跡性を確保することが重要です。penguin-agent-apiから社内で構築・運用されているLangfuseにトレースを送信する仕組みを実装しました。

社内Langfuse基盤の活用

SansanではLLMを活用した機能開発において、LLMOpsに取り組んでいます。複数プロダクトでの利用を前提に、セルフホスト型のLangfuseを社内共通基盤として整備しており、その背景や選定経緯は以下の発表資料を参照いただくとわかりやすいです。

speakerdeck.com buildersbox.corp-sansan.com

今回のデータ分析エージェントでも、この社内Langfuse基盤にそのまま接続する形でLLMOpsを実現しました。環境を構築する必要がなく、インターン期間内でもスムーズに可観測性を確保できた点は、社内整備の恩恵を大きく受けた部分だと思います。

Langfuse SDKによるトレース管理

社内Langfuseをフル活用するために、アプリケーションに対してLangfuse SDKを導入しました。ADKのCallback機能を活用して指定したツールのトレースや必要なユーザー情報を取得するようにしました。

  • 実行されたプロンプト・レスポンス全文
  • レイテンシ・トークン使用量
  • BigQueryの実行コスト(クエリごとのコストをspanに保存)
  • トレースに対して社員情報の付与

これにより、セッション単位での評価・分析や、エラー・異常レスポンスのトレース単位での特定・調査が可能になりました。

アプリケーション上での透明性確保

LLMの生成結果に対する検証可能性をアプリケーション上でも提供するため、エージェントが実行したSQL・Web検索クエリと結果をiceberg-uiのUI上に表示しています。非エンジニアでも「エージェントが何をしたか」を確認できるようにしています。

ユーザーヒアリングから生まれた機能

PdMやエンジニアとのランチ・Slackを通じたヒアリングをもとに、以下の機能を追加実装しました。

グラフ表示機能

「テーブル表示だけでは生成結果がわかりづらい」という声をもとに実装。推移・軸比較・割合など一般的なグラフ種別に対応しています。

エージェントワークフローの可視化

エージェントが実行したSQL・Web検索クエリをUI上に表示する機能です。生成結果の妥当性をエンジニアが検証しやすくすることを目的としています。

会話共有機能

画面から共有専用URLを発行でき、適切なIAM権限を持つユーザーが会話内容を閲覧できます。「エージェントの出力をエンジニアに確認してもらいたい」というユースケースに対応しました。

おわりに

実現できたこと

  • 自然言語でBill Oneのデータを検索・集計・可視化できる状態の構築
  • Langfuseによるログ・トレースの整備と可観測性の確保
  • ユーザーヒアリングをもとにした機能拡張

インターン期間内に着手できなかったこと

  • Langfuseのデータをもとにしたエージェントの継続的改善サイクルの構築
  • MCPなど他のアプローチとの比較、データ分析エージェント運用の優位性の検証

学んだこと

Vertex AI Agent Engineで行き詰まった経験から実感したように、新しい技術、手法はまず手を動かして制約を早めに把握することが設計判断につながることを学びました。また、エージェントの精度はモデルよりデータ基盤の品質に依存する部分が大きく、データモデリングへの投資が回答品質に直結しました。このことから、開発してアプリケーションを動かせるようにするだけではなく、改善フローを運用できる状態にする重要性を特に感じました。Langfuseを入れて初めてエージェントの挙動やコストが見えるようになったことで、作って終わりではなく、最初から可観測性を意識して開発することの重要性を実感しています。

それと同じくらい、Sansanという会社への解像度も上がりました。LLMOpsの社内共通が基盤整備されていることを証拠に、データに対して本気で向き合っている組織であることがわかり、またプロダクトの方向性に直結するような、職種を越えたコミュニケーションが自然に生まれる文化も印象的でした。ここで得た経験と視点を、今後の学びと開発に生かしていきたいと思います。

最後に、メンターの中村さん、斉藤さん、データモデリング師匠の矢田さん、ランチでお話しいただいたPdM・エンジニアの皆さん、本当にありがとうございました!




Sansanでは就業インターンを募集しています

Sansanでは、就業インターンを学年を問わず募集しています。

newgradsevents.corp-sansan.com

Sansanのエンジニア職インターンでは、インターン用のタスクを実施するわけではありません。 サービスに関わる技術選定からリリースまでの一気通貫した開発といったような、やりがいを得られる環境を準備しています。
チャレンジの場として、ぜひSansanの就業インターンへの応募をお待ちしております!

*1:記事は、執筆者本人の了承を得て、代理で投稿しています。

© Sansan, Inc.