---
title: "Langfuse Monitorsが出たので、朝ブリーフィングWorkerの役割を見直す"
description: "LangfuseのMonitors機能を、自前で作ったSlack朝ブリーフィングWorkerの実験ログと比較し、どこまで公式機能に寄せるべきかを整理します。"
lang: "ja"
canonical: "https://llm-lab.dev/posts/langfuse-monitors-morning-briefing-followup/"
source: "https://llm-lab.dev/posts/langfuse-monitors-morning-briefing-followup.md"
publishedAt: "2026-06-10"
updatedAt: "2026-06-10"
category: "AgentOps"
tags:
  - "agentops"
  - "slack"
  - "observability"
  - "genaiops"
---

# Langfuse Monitorsが出たので、朝ブリーフィングWorkerの役割を見直す

前回までの記事では、Langfuse の trace を毎朝 Cloudflare Workers Cron で集計し、見るべき異常だけを Slack に流す「朝ブリーフィング」を作りました。

- 構想編: [Langfuseの異常だけをSlackに流す朝ブリーフィングを作りたい](/posts/langfuse-morning-briefing/)
- 実装編: [Langfuse朝ブリーフィングを実装して試す：異常traceだけをSlackに流せるか](/posts/langfuse-morning-briefing-trial/)

ところが、先日 Langfuse 側に Monitors というメトリクス監視機能が出てきました。
この記事では、Monitors を単なる新機能紹介としてではなく、自前の朝ブリーフィング Worker と比較しながら整理します。結論から言うと、コストやレイテンシのしきい値監視は Monitors に寄せた方がよさそうです。一方で、「昨日見るべき trace をまとめる」「調査入口として trace URL を並べる」「複数条件をまとめて朝に読む」といった用途は、まだ自前 Worker の余地があります。

## 先に、朝ブリーフィングWorkerは動いた

まず、自前実装の検証結果です。

Cloudflare Workers Cron から Langfuse API を叩き、JST の前日分を集計して Slack に投稿するところまでは動きました。実際に Cron 実行後、Slack には次のような通知が届いています。

```text
Langfuse Morning Briefing

対象日: 2026-06-14
対象範囲: 2026-06-13T15:00:00.000Z - 2026-06-14T15:00:00.000Z
traces: 8
errors: 0
total tokens: 440,000
estimated cost: $0.1560

見るべき異常:
1. sample-morning-briefing-token-spike - tokens 55,000, latency 12.3s
   https://jp.cloud.langfuse.com/project/***redacted***/traces/***redacted***
...

取れなかった項目: score
```

この結果から分かったことは2つあります。

1つ目は、Langfuse API から trace / observation をたどれば、token、cost、latency は Slack 通知に使える粒度で取れることです。最初は trace 一覧だけを見ていたため token が取れませんでしたが、trace 詳細 API で observation id を取り、さらに observation 詳細 API を呼ぶと `usageDetails` と `costDetails` が取れました。

2つ目は、自前実装は「昨日の異常候補をまとめて読む」用途には向いている一方で、メトリクスのしきい値監視を継続運用するには少し責務が重いことです。たとえば「直近1時間の合計コストが一定額を超えたら即時通知したい」だけなら、毎朝まとめる Worker よりも、評価窓を持つ監視機能の方が自然です。

## Langfuse Monitorsとは何か

Langfuse Monitors は、Langfuse 上のメトリクスに対して条件を設定し、しきい値を超えた場合に Slack、Webhook、GitHub Dispatch などへ通知する機能です。この記事を書いている時点では、私の環境では Langfuse Cloud 上で beta 機能として見えています。

自分の理解では、Monitors は次のような役割です。

```text
Langfuse の Observations / Scores
  ↓
指定した評価窓でメトリクスを集計
  ↓
WARNING / ALERT のしきい値を判定
  ↓
Automations の通知先へ送信
```

ここで重要なのは、Monitors が「個々の trace を読む機能」ではなく、「メトリクスの状態を定期評価する機能」として見えることです。私が作った朝ブリーフィング Worker は trace を起点に「昨日見るべき実行」を並べます。一方で Monitors は Observations や Scores を起点に「今、メトリクスがしきい値を超えているか」を判断します。

この違いを混ぜると、設定で詰まります。実際、私も `npm run seed:langfuse` で投入したサンプル trace に Monitors が反応しないケースに当たりました。

## 自前WorkerとMonitorsの違い

同じ Slack 通知でも、自前 Worker と Monitors は得意なことが違います。

| 観点 | 自前の朝ブリーフィングWorker | Langfuse Monitors |
|---|---|---|
| 主な目的 | 前日分の異常候補をまとめて読む | 指定した評価窓のしきい値超過を検知する |
| 起点 | trace 一覧、trace 詳細、observation 詳細 | Observations / Scores などのメトリクス |
| 通知タイミング | Cron 実行時。今回は毎朝 | Monitor の評価間隔に依存 |
| 通知内容 | trace URL と異常理由を並べやすい | メトリクス値と状態変化の通知に向く |
| 複数条件の集約 | 自由に実装できる | Monitor ごとに条件を分ける前提になりやすい |
| 運用負荷 | API変更、pagination、secret、Worker保守が必要 | 公式機能に寄せられる |

この比較を見ると、役割分担はかなりはっきりします。

- コスト急騰、レイテンシ悪化、トラフィック断は Monitors に寄せる
- 朝に読む前日サマリー、trace URL の一覧、複数異常の要約は Worker に残す
- score 監視は、Score が安定して投入されるようになってから Monitors と Worker のどちらで扱うか決める

つまり、Monitors が出たから Worker が完全に不要になる、という話ではありません。ただし、Worker に「監視基盤」まで背負わせる必要は薄くなりました。

## seed traceにMonitorが反応しないときの見方

ここが今回いちばん実務的な詰まりです。

`npm run seed:langfuse` では、Langfuse ingestion API に次の3種類のイベントを送っています。

```text
trace-create
generation-create
score-create
```

このうち、Monitors の View を `Observations` にしている場合、監視対象になるのは trace ではなく generation の observation 側です。したがって、「trace は画面に見えているのに Monitor が反応しない」場合、まず疑うべきなのは Slack 連携ではなく、Monitor の対象 View、集計窓、フィルター、しきい値です。

今回の seed では、generation は observation として作られ、observation 詳細 API では次の値が取れました。

```json
{
  "type": "GENERATION",
  "usageDetails": {
    "input": 30000,
    "output": 25000,
    "total": 55000
  },
  "costDetails": {
    "input": 0.0045,
    "output": 0.015,
    "total": 0.0195
  },
  "latency": 12.3
}
```

つまり、Observations の `Total Cost` や latency を見る Monitor であれば、理屈の上では監視対象に入るはずです。それでも反応しない場合は、次を順番に確認します。

### 1. 評価窓に入っているか

Monitors は「Over the past」で指定した期間を集計します。seed を打った直後に `Over the past: 5m` で見ているなら、5分を過ぎると対象から外れます。逆に、Cron の朝通知は JST の前日 00:00 から 24:00 を対象にしているため、同じ trace でも見ている時間窓が違います。

まずは `Over the past: 1h` または `1d` など、seed trace が確実に入る窓に広げて確認するのが安全です。

### 2. MeasureとAggregationが合っているか

seed のコストは `costDetails.total = 0.0195` です。コスト監視で ALERT threshold を `50` USD のような大きな値にしていると、当然反応しません。

検証用には、いったんかなり低い値にします。

```text
View: Observations
Measure: Total Cost
Aggregation: Sum
Trigger: above or equal to
ALERT Threshold: 0.001
Over the past: 1h
```

この条件なら、seed が1件でも入れば `0.0195` がしきい値を超えるはずです。複数回 seed を打っている場合は、合計値がさらに増えます。

### 3. フィルターで落としていないか

Monitor に environment、tag、name、model などのフィルターを設定している場合、seed の observation がそこから外れている可能性があります。

今回の seed は trace に `tags: ["morning-briefing-test"]` を付けていますが、generation 側には同じ tag を明示していません。Observations View のフィルターが observation 側の属性を見ている場合、trace 側の tag を期待しても一致しない可能性があります。

検証時は、まずフィルターを全部外して反応を見るのがよいです。その後、必要なら generation の body に metadata や name を明示して、Monitor 側で絞り込める属性を使います。

### 4. no-dataモードを誤解していないか

no-data モードは、評価窓にデータがないときの扱いです。データがあるのにしきい値を超えないケースとは別です。

たとえばコスト監視で `Treat missing data as 0` にしても、seed の observation がフィルターで落ちている場合は「0として扱われている」だけに見えます。このとき通知が来ないのは Slack が悪いのではなく、Monitor の集計対象が空になっている可能性があります。

### 5. 通知先AutomationsがMonitorに紐づいているか

Monitors は既存の Automations 通知先を使います。Slack 連携そのものが正しくても、Monitor の Notifications で対象 channel にチェックが入っていなければ通知されません。

ここは地味ですが、UIで一度保存したあとに Monitor 詳細を開き直し、通知先が残っているか確認した方がよいです。

## Monitorsでまず作るならこの3つ

私の用途では、最初に作る Monitor は次の3つで十分そうです。全部を一気に監視し始めると、通知が増えてすぐ見なくなります。

### 1. コスト急騰

```text
View: Observations
Measure: Total Cost
Aggregation: Sum
Over the past: 1h
Trigger: above or equal to
WARNING: 運用上の注意ライン
ALERT: 即時に見るライン
No data: Treat missing data as 0
```

コストは「データがないなら0」と扱いやすい指標です。まずはこれが一番 Monitor に向いています。

### 2. レイテンシ悪化

```text
View: Observations
Measure: Latency
Aggregation: Avg または p95 相当
Over the past: 30m
Trigger: above
No data: Keep the previous severity
```

レイテンシは、データなしを0として扱うと意味が変わります。トラフィックがない時間に「0秒だから正常」と見えてしまうためです。ここは no-data の扱いをコスト監視と分ける必要があります。

### 3. パイプライン断

```text
View: Observations
Measure: Count
Aggregation: Count
Over the past: 30m
Trigger: below
ALERT: 1
No data: Treat missing data as 0
```

夜間バッチや定期実行 Agent のように、一定時間内に必ず observation が来るべき処理では、件数が0であること自体が異常です。この用途では no-data を0として扱う方が自然です。

## 残る課題はscore

朝ブリーフィング Worker では、token / cost / latency は取れるようになりました。一方で、score はまだきれいに取れていません。

seed では `score-create` を送っていますが、trace 詳細 API の `scores` は空でした。これは score が投入されていないという意味ではなく、trace 詳細レスポンスに同梱されない、または取得タイミングや endpoint が違う可能性があります。

Monitors 側には Scores を対象にする View があるため、品質スコア監視はむしろ Monitors の方が自然かもしれません。ただし、ここはまだ検証中です。score 名、数値型かカテゴリ型か、集計窓、no-data の扱いを確認してから判断します。

## 現時点の結論

今回の検証で、Langfuse の監視は次のように分けるのがよさそうだと感じています。

```text
即時に気づきたいメトリクス異常
  → Langfuse Monitors

朝にまとめて読みたい前日サマリー
  → 自前の朝ブリーフィングWorker

調査対象のtrace URL一覧
  → 自前Workerがまだ便利

品質scoreの継続監視
  → Monitors候補。ただしscore投入と取得方法を要検証
```

公式機能が出たことで、自前実装の価値がなくなったというより、自前で作るべき範囲がはっきりしました。Monitors は「鳴らす」機能、自前 Worker は「読む」機能として分ける。これが今のところ一番しっくりきています。

次は、実際に Monitors をいくつか設定し、seed trace に反応しない原因を UI と API の両方から確認します。特に、Observations のフィルターが trace 側の tag を見るのか、observation 側の属性だけを見るのかは、運用上かなり重要な論点になりそうです。
