
LangfuseとBigQueryを繋いだ話 ─ LLMの改善も、LLMによる分析もBigQueryで
こんにちは!Scene Live・ New Standard室のまっすーです。
2025年からデータサイエンティスト兼データエンジニアとして、Scene Liveに中途入社しました。bqというサービスのLLMを用いた検証・研究をおこなったり、プロダクトに関するデータ収集から利活用までの『データ基盤』を作ったりしています。
連載:「Langfuse×データ基盤」 第 2 回 / 全 2 回(最終回)
前回: プロダクトに Langfuseを入れた話 ─ LLM 運用を“見える化”するまで
関連:なぜ Airflow から Dagster に乗り換えたのか /Dagster 移行、500 テーブル超を止めずに引っ越した話/Dagster の“ネイティブ統合”が効いた話(dlt / dbt + リバースETL)
既刊:【1ヶ月半で構築】bq事業のモダンデータスタック
はじめに
前回の記事 は プロダクトにLangfuseを入れて、LLMの振る舞いを観測できるようにするまで の話を書きました。
今回はその続きで、 LangfuseとBigQueryを繋いで、改善サイクルを1周回せるようにした話 です。これによって、ここまでの連載で書いてきた データ基盤 と LLM観測基盤 が 1 つに合流します。 以前のAIネイティブの記事で登場した LLM Quality Agent や Cost Watch Agent が、まさにこの仕組みの上で動いています。
トーンとしては前回と地続きで、 データサイエンティスト視点 で「観測したデータをどうプロダクトの改善ループに繋げるか + LLM 自身に分析させるか」 という話を中心に書きます。 役割としても前回と同じく、 プロダクト組み込みではなく、データ基盤とエージェントの関係の話 です。

この記事の前提(用語の整理)
これまでの記事で出てきた用語 (Dagster/ dbt/dlt/BigQuery/ リバース ETL / Langfuse / trace / observation / score / LLMOps等) は引き続き使います。本記事で初めて深く登場するのは、 改善ループ に関わる言葉です。
L2B (Langfuse → BigQuery): Langfuse に溜まった trace / score 等のデータを BigQuery に同期する仕組み。 本記事では2経路で実装。①Dagster schedule (毎日定期取り込みの本流) と ② GitHub Actions (アドホック / 即時同期用)。 裏では同じ dlt パイプラインを呼ぶ
B2L (BigQuery → Langfuse): 逆方向。 BigQuery でラベル付けしたデータを Langfuse に Score や Dataset として書き戻す仕組み。 こちらは GitHub Actions の手動 dispatch で運用
アノテーション: LLM の出力に 人間が評価ラベルを付ける 作業。LLM-as-a-judge の精度を測ったり、Experiment用のテストケースを作るのに使う
LLM-as-a-judge: 「LLM の出力を、別の LLM が評価する」仕組み (以前の AI ネイティブの記事でも登場)。 自動でスコアを付け続けるための役割
Experiment: Langfuse の機能。同じテストケース集 (Dataset) に対して、 プロンプトの v1 / v2 / v3 などを並べて評価 する。改善の前後比較に使う
critical_mismatch: |human_score - eval_score| > 0.2 の割合。 LLM-as-a-judge と人間評価がどれだけズレているかを定量化する指標。 0.2 という閾値は社内で経験的に決めた値で、 「この差が出ると判定の意味が変わる」 と言える境目をスコアレンジに合わせて取っています
※ L2B / B2L / critical_mismatch は社内で便宜的に使っている呼称です。
まず全体地図 ─ LLMOpsの3ループ
具体的な実装の話に入る前に、 LLM 運用全体の中で 本記事の主役 (改善サイクル) がどこに位置するか を 1 枚の地図にしておきます。

LLM 運用は大きく 3 つのループの組み合わせで動きます。
①仕様ループ「何が正解か」 を決める: 「この機能で LLM は何を出力すべきか」 を要件 + 例で固定する。 アノテーション基準や human_reasons の語彙はここで決める
②品質ループ「測って改善する」: 評価器 (Judge) を作り、 凍結 (Freeze) したうえで、 凍結 Judge で評価しながらモデル / プロンプトを改善するサイクルを回す
③運用ループ「本番で監視する」: 本番で trace / score を継続収集し、 ドリフトを検知したら ① / ② に戻す
連載で 本記事が扱うのは、 主に ② 品質ループの「改善サイクル」 部分 です。 前回の記事 で扱った Langfuse 観測基盤は ② のうち 「評価器の構築」 「データ準備」 を支える基盤、 以前の AI ネイティブの記事で扱った LLM Quality Agent / Cost Watch Agent は ③ 運用ループにあたります。
特に ② で重要なのが 「評価器の凍結 (Judge Freeze)」 という考え方です。 「改善幅を測るには、 物差し自体は動かしてはいけない」 という単純なルールで、 これを守らないと 「v1 → v2 で改善した」 と思っても、 実は judge が変わっただけで本番の出力品質は変わっていない、 という事故が起きます。 後段で触れる judge_train / judge_test のデータ分割も、 凍結された judge を作るための前準備 として効いてきます。
そしてこの 3 ループを実際に動かすには、 道具立ても揃っている必要があります。 うちの場合はBigQuery (観測ログ + アノテーション結果の置き場として、 ループ間でデータを橋渡し) / Langfuse (Trace / Score / Dataset / Experiment の母艦) / Claude Code の skill (アノテーションを対話的に進める仕組み) の 3 つが連携することで、 ループが滑らかに回るようになっています。 以前の記事で書いてきたデータ基盤がここで効いてくる、 という構図ですね。
ここから先は、 この 3 ループを実際に動かすための具体実装に入っていきます。 まずは「なぜ BigQueryに流すのか」 から。
なぜBigQueryに流すのか
Langfuseの管理画面でも、 trace の検索や、簡単なメトリクスは見られます。コスト推移、レスポンスタイム、エラー率くらいなら Langfuse 単体で足ります。
それでも BigQuery に流すことにしたのは、 Langfuse 単体ではどうしても足りない役割があった からです。 一番大きかったのは、 上で書いた 3 ループの橋渡し役 が必要だったこと。
3 ループを横断する場所として: ① 仕様ループで決めた「アノテーション基準」、 ② 品質ループで動かす「Judge / プロンプト改善」、 ③ 運用ループで観測する「ドリフト」 ─ これらは全部 同じデータの上で繋げて 初めて意味を持ちます。 SQL で誰でも触れる場所が要るのは、 ループ間の 情報の合流点 が要るから。 Langfuse 単体だと観測 (③) は綺麗にできるが、 ① の語彙定義や ② の改善履歴を 横断で結合する場所 には向いていない
そのうえで、 分析の深さ という観点でも BigQuery が要りました。
プロダクトDB / マーケ・営業データとの結合分析: 「ある機能の LLM 出力品質が、 どの顧客セグメント で低いか」 「特定のフェーズの利用シーン で LLM の精度が落ちていないか」 のような問いに答えるには、 LLM のログだけ見ていても無理。プロダクトDB やマーケ・営業データと 同じ場所で結合する 必要がある
LLM-as-a-judge の長期トレンド分析: 評価のドリフトを見るには、 数週間から数ヶ月単位で score の分布を追う必要があります。Langfuseのダッシュボードでも見られなくはないけど、 SQL を自由に書ける場所のほうが楽
コスト分析の深掘り: 「どの機能の・どのプロンプトの・どのトークン消費が・全体コストの何%を占めているか」 のような Pivot を切る分析は、BigQuery + dbtで組み立てた集計テーブルの方が圧倒的にやりやすい
エージェント (LLM) からの参照源にする: ここが大きい。以前の AI ネイティブの記事で書いた通り、 LLM エージェント自身がデータの消費者 になっています。 エージェントが SQL で叩く先を BigQuery1箇所に集約しておくと、 「Langfuseの trace を見ながら、プロダクトDB の状態と突き合わせる」 みたいな分析を LLM が自分でやれる
つまり、 「観測の母艦は Langfuse、 改善ループと AI 分析の母艦はBigQuery」 という役割分担です。
L2B:Langfuse→ BigQueryの実装
L2B 側は、以前のDagster連載で書いた dlt + dbt + Dagster の枠組みにそのまま乗せる だけです。
取り込み (dlt): Langfuse の API から trace / observation / score / session / dataset / prompt 等の15テーブル を取得。 以前の記事で書いた前提に従って、 Bronze層に並べる
整形 (dbt): Bronze の生データを Silver で staging (型統一・列名整理)、Intermediate で 複数プロジェクト分を UNION (int_langfuse_all_traces / int_langfuse_all_scores 等)、 Gold で fct_langfuse_eval_traces (人間とジャッジのスコアを横並びに揃えたファクト) や fct_langfuse_usage (トークン消費 + コスト集計) のような分析向けテーブルを作る
オーケストレーション (本流): 深夜 0:00から1:00 JST に 複数プロジェクトを15分ずらしで Dagster schedule から取り込む。 Bronze 取り込み → dbt 変換まで Asset Lineage で繋がっているので、 失敗箇所がすぐに分かる (以前の Dagster連載 第3回参照)
オーケストレーション (アドホック): 「定期実行を待たずに今すぐ取り込みたい」 場面のために、 GitHub Actions で手動 dispatch ワークフローも用意してあります。 Dagster schedule との二重実装ではなく、 裏では同じ dlt パイプラインを呼ぶ 設計。 「明日のレビュー会までに最新データを揃えたい」 みたいな緊急同期用
要するに 以前の Dagster 連載で作った仕組みの上に、Langfuse を追加の source として乗せただけ です。新しい基盤を作る必要はなく、既存基盤を 再利用 できる ─ これが、データ基盤を先に整えておいたことの効用です。
B2L: BigQuery → Langfuse の書き戻し
ここからが連載で初めて出てくる話です。 BigQuery で人間がラベル付けした結果を、 Langfuse に書き戻す 仕組みも用意しています。
Score 同期: BigQuery 上で人間がアノテーションした human_score を、 Langfuse の対応する trace に Score として書き戻す。これによって Langfuse 側でも「人間が評価した正解スコア」 が見られるようになる
Dataset 作成: BigQuery 上で「この trace 集合を Experiment のテストケースに使いたい」 と決めたものを、 Langfuse の Dataset として転送する。 一度作っておけば、 プロンプト v1 / v2 / v3 等を Experiment で順番に走らせて比較できる
実装は GitHub Actions の手動 dispatch ワークフローで運用しています。 一発もので済むので、 定期実行は不要としています。
改善サイクルの全貌
ここからが ②品質ループ の中身です。 冒頭で見た L2B と B2L が両方揃うと、 改善サイクル が1周回せるようになります。 これがデータサイエンティストとして一番やりたかったことです。
サイクルの中心にいるのが、 前回の記事で紹介した Langfuse の 4 本柱のうち Dataset + Experiment です。 同じテストケース集に対して プロンプト v1 / v2 / v3 等を順番に流して、 Score を並べて比較する ─ これが改善判断の核心になります。


各ステップの位置づけはこんな感じです。
アノテーション: 人間が「この出力は実用的か」 を判断する
データサイエンティストとしての専門性が出る部分です。BigQuery 上で対話的に進められるよう、社内では Claude Code の skill(専用のアノテーションワークフロー)を整えています。やっていることは 4 つです。
①対話的レビュー
Claude が BigQuery の trace を 1 件ずつ提示 → 人間がスコア + 根拠(human_reasons)を付ける → そのまま BigQuery に書き戻す。ここまでを 1 つの対話で最後まで進められます。
②根拠の語彙化
スコアの理由を false_positive / カテゴリ誤り / polarity 誤り のように語彙として定義しておくと、後段の集計で「何が・どこで・どれくらい」ズレているかが定量的に見える。改善案を立てるときの根拠にもなります。
③エッジケースの追加 (データ拡張)
本番データだけだと境界ケースや失敗例が不足するので、 明確な失敗 / 境界ケース / 高品質例 を Claude に生成させて、 本番データの 2〜3 割を上乗せします。
④用途別の分割
アノテーション結果を 4 種類に分割しておきます。分け方は「何を改善するか」×「改善用か評価用か」の 2 軸です。
judge(LLM-as-a-judgeの改善)
・train(改善用):judge_train
・test(評価用):judge_test
prompt(本番プロンプトの改善)
・train(改善用):prompt_train
・test(評価用):prompt_test
ここの理由は少し機械学習寄りなので、補足します。
train と test を分ける理由
改善に使ったデータで評価すると、そのデータには当然良いスコアが出ます。未知のデータでの実力を測るには、改善時に見ていないデータが要る ── これが train / test 分割の本来の意味です。
judge と prompt を分ける理由
「LLM-as-a-judge を改善する作業」と「本番プロンプトを改善する作業」は別々の最適化です。同じデータを両方に使うと、judge を直したことで本番プロンプトの評価結果が見かけ上良くなる、という相互汚染が起きます。
結果として「凍結 judge で本番プロンプトを評価する」という品質ループの基本動作が、データの分け方で支えられる構造になっています。
「人間が判断すべきところに集中して、Claude が周辺の作業を引き受ける」という分担が、アノテーション作業の重さを大きく下げています。
critical_mismatch 判定:どちらを直すかが数字で決まる
|human_score - eval_score| > 0.2の割合を測ります。これが 10% を超えていたら judge そのものが信用できないので、judge プロンプトの方を直す。10% 以下なら judge は信頼できるので、本番のプロンプトの方を直す。どちらを直すべきかが数字で決まる、というのが大事なところです。
Experiment:改善が効いたかを共通の物差しで見る
Langfuse 上で、同じ Dataset に対して異なるプロンプトを走らせて比較します。v1 / v2 / v3 等が並んで見えるので、改善が効いたか効かなかったかを、共通の物差しで議論できます。
Langfuse内のExperimentsの様子

Langfuse内のDatasetの様子

LLM が消費者として参戦する
以前の AI ネイティブの記事で書いた LLM エージェント群 は、 まさにこの仕組みの上で動いています。
LLM Quality Agent:BigQuery の fct_langfuse_eval_traces を SQL で読んで、 LLM-as-a-judge の score 分布の週次変動 を監視。 ドリフトを検知したら Slack に通知
Cost Watch Agent :GCP の課金データに加えて、 BigQuery の fct_langfuse_usage を読んで LLM のトークン消費 + コスト も監視対象に含めている。 「今週、どの機能のどのプロンプトでコストが膨らんでいるか」 を診断つきで Slack に投げてくる
つまり 改善サイクルの中に、人間の隣で LLM 自身が監視役として座っている わけです。 以前の AI ネイティブの記事では「LLM が SQL で BigQuery を読む」 と書きましたが、 その読み先のテーブルが、ここで作っている Langfuse 由来の Gold 層テーブル ということです。

これが、 以前の AI ネイティブの記事で予告した「LLM-as-a-judge のスコアが Langfuse 経由で BigQuery に来ている」 の実態です。

おわりに
前回の内容に引き続き、 データ基盤 と LLM 観測基盤 の両方を、 1 つの絵として書き切れたかなと思います。ちょっとした総括です。
プロダクトに Langfuse を入れて、 LLM の振る舞いを観測できるようにするまで (=LLMOps 導入)
Langfuse と BigQuery を繋いで、 改善サイクルを 1 周回せるようにした話 (=合流)
データ基盤を作るのは目的じゃなくて、 その上で何を回すか が本題です。 LLM プロダクトの観測 → 分析 → 改善 → 再観測のループが回り始めて、ようやく「作ってよかった」 と思えるようになってきました。
ここまで付き合っていただいた方、ありがとうございました。 これからも、 やらかしたら正直に書く という方針は続けるつもりです。 よかったらまた読みに来てください。
関連記事
なぜ Airflow から Dagster に乗り換えたのか
Dagster 移行、500 テーブル超を止めずに引っ越した話
Dagster の "ネイティブ統合" が効いた話
データの消費者は「ヒト」だけじゃない ─ AI ネイティブなデータ基盤の実態
前回の記事:プロダクトに Langfuseを入れた話 ─ LLM 運用を“見える化”するまで
最後に
まだまだ発展途上のデータ基盤。これからも生成AI・LLMを使った改善を続けていきます!
データ基盤に興味がある方、LLMを活用した開発やデータ分析に興味がある方、ぜひお話ししましょう。
▼Scene Live 採用情報
▼新規AIプロダクトのエンジニア採用