# 機能設計書 100-テレメトリ

## 概要

本ドキュメントは、GiselleプラットフォームにおけるLangfuseを使用したテレメトリ（トレース）機能について記述する。

### 本機能の処理概要

**業務上の目的・背景**：AI生成（テキスト、画像、埋め込み）の実行状況を可視化・分析するため、Langfuseを使用したトレース機能を提供する。トークン使用量、コスト、処理時間、エラー情報などを記録し、LLM運用の最適化とデバッグに活用する。

**機能の利用シーン**：
- テキスト生成完了/失敗時のトレース記録
- 画像生成完了/失敗時のトレース記録
- 埋め込み（Embedding）処理のトレース記録
- LLM使用状況の分析・モニタリング

**主要な処理内容**：
1. Generation完了/失敗時のトレース送信（traceGeneration）
2. ContentGeneration専用トレース処理（traceContentGeneration）
3. 埋め込み処理のトレース送信（traceEmbedding）
4. 入力メッセージのLangfuse形式変換（prepareLangfuseInput）
5. タグ抽出（extractTags）
6. メタデータ抽出（extractMetadata）
7. コスト計算（calculateDisplayCost）

**関連システム・外部連携**：
- Langfuse（LLMオブザーバビリティプラットフォーム）
- language-model（コスト計算）
- language-model-registry（モデル設定解析）

**権限による制御**：なし（バックエンド処理）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | ワークフローエディタ画面 | 間接参照 | Generation実行時にトレース記録 |

## 機能種別

モニタリング / 分析 / LLMオブザーバビリティ

## 入力仕様

### 入力パラメータ（traceGeneration）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| generation | CompletedGeneration \| FailedGeneration | Yes | 生成結果 | - |
| inputMessages | ModelMessage[] | Yes | 入力メッセージ | - |
| userId | string | No | ユーザーID | - |
| metadata | Record<string, unknown> | No | カスタムメタデータ | - |
| tags | string[] | No | カスタムタグ | - |
| outputFileBlobs | OutputFileBlob[] | No | 出力ファイル（画像生成時） | - |
| sessionId | string | No | セッションID | - |

### 入力パラメータ（traceEmbedding）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| metrics | EmbeddingMetrics | Yes | 埋め込み処理メトリクス | - |
| userId | string | No | ユーザーID | - |
| sessionId | string | No | セッションID | - |
| tags | string[] | No | カスタムタグ | - |
| metadata | Record<string, unknown> | No | カスタムメタデータ | - |

### 入力データソース

- Generation実行結果
- 埋め込み処理結果（EmbeddingMetrics）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| - | void | Langfuseへのトレース送信（非同期） |

### 出力先

- Langfuse（外部サービス）

## 処理フロー

### 処理シーケンス

```
1. traceGeneration
   └─ ノード種別判定 → タグ/メタデータ抽出 → 入力変換 → トレース作成 → 送信

2. traceContentGeneration
   └─ 入力変換 → トレース作成 → タグ/メタデータ付与 → コスト計算 → 送信

3. traceEmbedding
   └─ タグ生成 → トレース作成 → コスト計算 → 送信

4. prepareLangfuseInput
   └─ メッセージ走査 → file/imageをLangfuseMedia変換 → 配列返却
```

### フローチャート

```mermaid
flowchart TD
    A[Generation完了] --> B{ノード種別}
    B -->|query/action| C[スキップ]
    B -->|contentGeneration| D[traceContentGeneration]
    B -->|textGeneration| E[traceGeneration - Text]
    B -->|imageGeneration| F[traceGeneration - Image]

    D --> G[prepareLangfuseInput]
    E --> G
    F --> G

    G --> H[Langfuse.trace作成]
    H --> I[extractTags]
    I --> J[extractMetadata]
    J --> K{成功/失敗}

    K -->|成功| L[コスト計算]
    L --> M[trace.generation - DEFAULT]
    K -->|失敗| N[trace.generation - ERROR]

    M --> O[langfuse.flushAsync]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | ノードスキップ | query/actionノードはトレース対象外 | 常時 |
| BR-002 | タグ自動付与 | provider、feature、toolタグを自動抽出 | 常時 |
| BR-003 | メディア変換 | file/imageはLangfuseMedia形式に変換 | 入力処理時 |
| BR-004 | コスト計算 | トークン使用量からコストを算出 | テキスト生成時 |
| BR-005 | エラーレベル | 失敗時はERROR、成功時はDEFAULT | 常時 |
| BR-006 | 非同期送信 | flushAsyncで非同期送信、エラーはログのみ | 常時 |

### 計算ロジック

**タグ抽出**:
- `provider:{llm.provider}` - プロバイダー名
- `feature:thinking` - Anthropic Thinking有効時
- `tool:web-search` - Web検索ツール使用時
- `tool:github` - GitHubツール使用時
- `tool:postgres` - PostgreSQLツール使用時

**コスト計算**:
```typescript
const cost = await calculateDisplayCost(provider, modelId, {
  inputTokens: usage.inputTokens,
  outputTokens: usage.outputTokens,
});
```

## データベース操作仕様

### 操作別データベース影響一覧

なし（外部サービスへの送信のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| Telemetry emission failed | 送信エラー | Langfuse送信失敗 | エラーログ出力のみ（処理続行） |
| Unsupported node type | 警告 | 未対応ノード種別 | console.warnでログ出力 |

### リトライ仕様

- Langfuseライブラリの内部リトライに依存
- エラー時は処理を中断せず、ログ出力のみ

## トランザクション仕様

なし（外部サービスへの非同期送信）

## パフォーマンス要件

- 非同期送信のためメイン処理をブロックしない
- flushAsyncによるバッファリング

## セキュリティ考慮事項

- Langfuse API Key環境変数での管理
- ユーザー入力のサニタイズ（LangfuseMedia変換）

## 備考

- Langfuseは環境変数LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEYで設定
- 埋め込みベクトル自体は保存しない（コメント参照）

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: 型定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/giselle/src/telemetry/types.ts` | TelemetrySettings型定義 |

**主要な型定義（types.ts）**:
1. **1-5行目**: TelemetrySettings - AI SDK互換のメタデータ設定

#### Step 2: Generationトレースを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | trace-generation.ts | `packages/langfuse/src/trace-generation.ts` | メイントレース処理 |

**主要処理フロー（trace-generation.ts）**:
1. **22-39行目**: toBuffer - DataContentをBuffer変換
2. **41-94行目**: prepareLangfuseInput - 入力メッセージのLangfuse形式変換
3. **96-188行目**: extractTags - タグ自動抽出
4. **190-279行目**: extractMetadata - メタデータ自動抽出
5. **281-370行目**: traceContentGeneration - ContentGeneration専用トレース
6. **372-550行目**: traceGeneration - メイントレース関数

**traceGeneration詳細**:
- **382-387行目**: query/actionノードスキップ
- **390-401行目**: ContentGeneration分岐
- **404-412行目**: 対応ノード種別チェック
- **414-424行目**: Langfuseトレース作成
- **441-460行目**: 失敗時ERRORレベルトレース
- **462-502行目**: テキスト生成成功時トレース
- **504-539行目**: 画像生成成功時トレース
- **541-549行目**: エラーハンドリング（ログのみ）

#### Step 3: 埋め込みトレースを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | trace-embedding.ts | `packages/langfuse/src/trace-embedding.ts` | 埋め込み処理トレース |

**主要処理フロー（trace-embedding.ts）**:
1. **5-15行目**: buildTags - 埋め込みタグ生成
2. **17-104行目**: traceEmbedding - 埋め込みトレース関数
3. **69-74行目**: コスト計算（textTokens + imageTokens）
4. **82-95行目**: trace.generation呼び出し

#### Step 4: React連携を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | context.tsx | `packages/react/src/telemetry/context.tsx` | TelemetryProvider/useTelemetry |

**主要処理フロー（context.tsx）**:
1. **4-6行目**: TelemetryContext作成
2. **8-20行目**: TelemetryProvider - 設定をContext提供
3. **22-25行目**: useTelemetry - 設定取得Hook

### プログラム呼び出し階層図

```
Generation完了
    │
    ├─ [traceGeneration呼び出し]
    │      │
    │      ├─ isQueryNode/isActionNode → スキップ
    │      │
    │      ├─ isContentGenerationNode
    │      │      └─ traceContentGeneration
    │      │             │
    │      │             ├─ prepareLangfuseInput
    │      │             │      └─ LangfuseMedia変換
    │      │             │
    │      │             ├─ Langfuse.trace
    │      │             │
    │      │             ├─ extractTags / extractMetadata
    │      │             │
    │      │             ├─ calculateDisplayCost
    │      │             │
    │      │             └─ langfuse.flushAsync
    │      │
    │      ├─ isTextGenerationNode
    │      │      │
    │      │      ├─ prepareLangfuseInput
    │      │      ├─ Langfuse.trace
    │      │      ├─ extractTags / extractMetadata
    │      │      ├─ calculateDisplayCost
    │      │      └─ trace.generation (TOKENS)
    │      │
    │      └─ isImageGenerationNode
    │             │
    │             ├─ prepareLangfuseInput
    │             ├─ Langfuse.trace
    │             ├─ LangfuseMedia (outputFileBlobs)
    │             └─ trace.generation (IMAGES)
    │
    └─ langfuse.flushAsync

Embedding完了
    │
    └─ traceEmbedding
           │
           ├─ buildTags
           ├─ Langfuse.trace
           ├─ calculateEmbeddingDisplayCost
           └─ langfuse.flushAsync
```

### データフロー図

```
[入力]                          [処理]                           [出力]

generation ─────────────────────┐
                                │
inputMessages ──────────────────┼──▶ prepareLangfuseInput
                                │         │
                                │         └──▶ LangfuseMedia変換
                                │
operationNode ──────────────────┼──▶ extractTags
                                │         │
                                │         └──▶ provider/feature/tool タグ
                                │
                                ├──▶ extractMetadata
                                │         │
                                │         └──▶ tools.*/llm.configuration
                                │
                                ├──▶ calculateDisplayCost
                                │         │
                                │         └──▶ inputCost/outputCost/totalCost
                                │
                                └──▶ Langfuse
                                           │
                                           ├──▶ trace (name, input, userId)
                                           │
                                           └──▶ generation (model, usage, cost)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| types.ts | `packages/giselle/src/telemetry/types.ts` | ソース | TelemetrySettings型定義 |
| index.ts | `packages/giselle/src/telemetry/index.ts` | ソース | エクスポート |
| trace-generation.ts | `packages/langfuse/src/trace-generation.ts` | ソース | Generationトレース処理 |
| trace-embedding.ts | `packages/langfuse/src/trace-embedding.ts` | ソース | 埋め込みトレース処理 |
| context.tsx | `packages/react/src/telemetry/context.tsx` | ソース | TelemetryProvider/useTelemetry |
