Dify の評価基盤を俯瞰:観測・指標・人手評価の設計ポイント
生成 AI アプリケーションの開発では、モデルの性能を正確に評価し、継続的に改善することが成功の鍵となります。Dify は LLM アプリケーション開発プラットフォームとして、豊富な評価基盤を提供していますが、その全体像を把握し、適切に設計することは容易ではありません。
本記事では、Dify における評価基盤の全体像を俯瞰し、観測(Observability)、指標(Metrics)、人手評価(Human Evaluation)という 3 つの柱について、設計ポイントと実装方法を詳しく解説します。これにより、AI アプリケーションの品質向上と運用改善を実現できるでしょう。
背景
Dify における評価の重要性
Dify は、LLM を活用したアプリケーションを迅速に構築できるプラットフォームです。チャットボット、エージェント、ワークフローなど、さまざまな AI アプリケーションを GUI 上で設計できる点が特徴ですね。
しかし、AI アプリケーションは従来のソフトウェアと異なり、確定的な動作をしません。同じ入力でも異なる出力が生成される可能性があり、品質の定義や測定が難しいという特性を持ちます。
このため、継続的な評価と改善のサイクルを回すことが、AI アプリケーションの成功に不可欠なのです。
評価基盤の 3 つの柱
Dify の評価基盤は、以下の 3 つの要素で構成されています。
| # | 要素 | 目的 | 特徴 |
|---|---|---|---|
| 1 | 観測(Observability) | システム動作の可視化 | ログ、トレース、メトリクスの収集 |
| 2 | 指標(Metrics) | 定量的な品質評価 | 自動計算される客観的指標 |
| 3 | 人手評価(Human Evaluation) | 主観的な品質評価 | 人間による判断とフィードバック |
これら 3 つの要素を組み合わせることで、多角的な評価が可能になります。
以下の図は、評価基盤の全体像を示しています。
mermaidflowchart TB
user["ユーザー"] -->|リクエスト| app["Dify アプリケーション"]
app -->|実行| llm["LLM モデル"]
llm -->|レスポンス| app
app -->|結果| user
app -->|ログ出力| obs["観測基盤<br/>Logs/Traces"]
app -->|メトリクス計算| metrics["指標基盤<br/>自動評価"]
user -->|評価入力| human["人手評価<br/>フィードバック"]
obs -->|分析| dashboard["ダッシュボード"]
metrics -->|集計| dashboard
human -->|集約| dashboard
dashboard -->|改善施策| app
図で理解できる要点:
- ユーザーからのリクエストが Dify アプリケーションを経由して LLM に渡される流れ
- 観測、指標、人手評価の 3 つが並行して動作し、ダッシュボードで統合される仕組み
- 評価結果がアプリケーション改善にフィードバックされる循環構造
課題
AI アプリケーション評価の難しさ
生成 AI アプリケーションの評価には、従来のソフトウェアにはない特有の課題があります。
非決定的な動作
LLM は同じ入力に対して毎回異なる出力を生成する可能性があります。温度パラメータや Top-p などの設定により、出力の多様性が変化するためです。
このため、単純なユニットテストのようなアプローチでは品質を保証できません。
品質基準の曖昧さ
「良い回答」の定義は、ユースケースによって大きく異なります。正確性、有用性、安全性、トーン、長さなど、複数の観点が存在し、それらの優先順位も状況により変わるでしょう。
コストと時間の制約
すべての出力を人間が評価するには、膨大な時間とコストがかかります。一方で、完全に自動化された評価だけでは、微妙なニュアンスや文脈を捉えきれない可能性があります。
以下の図は、評価における課題の関係性を示しています。
mermaidflowchart LR
challenge1["非決定的な<br/>出力"] -->|結果| difficulty["評価の<br/>困難さ"]
challenge2["曖昧な<br/>品質基準"] -->|影響| difficulty
challenge3["コストと<br/>時間の制約"] -->|制限| difficulty
difficulty -->|要求| solution1["自動評価<br/>(指標)"]
difficulty -->|要求| solution2["人手評価<br/>(サンプリング)"]
difficulty -->|要求| solution3["観測基盤<br/>(モニタリング)"]
図で理解できる要点:
- 3 つの主要課題が評価の困難さを生み出している構造
- それぞれの課題に対応する解決策の関係性
運用上の課題
評価基盤を運用する上でも、いくつかの課題があります。
| # | 課題 | 詳細 | 影響 |
|---|---|---|---|
| 1 | データ量の増加 | ログやトレースが膨大になる | ストレージコストと分析の困難さ |
| 2 | 評価者の負担 | 人手評価に時間がかかる | フィードバックサイクルの遅延 |
| 3 | 指標の選定 | 適切な評価指標が不明確 | 誤った改善方向への誘導 |
| 4 | リアルタイム性 | 問題の早期発見が難しい | ユーザー体験の低下 |
これらの課題に対処するためには、体系的な評価基盤の設計が必要です。
解決策
観測(Observability)の設計
観測基盤は、アプリケーションの動作を可視化し、問題の早期発見と原因究明を支援します。
ログの構造化
Dify では、すべての会話とワークフロー実行がログとして記録されます。これらのログを効果的に活用するには、構造化が重要です。
以下は、ログデータの構造例です。
typescript// ログエントリの型定義
interface DifyLogEntry {
// 基本情報
conversationId: string; // 会話ID
messageId: string; // メッセージID
timestamp: Date; // タイムスタンプ
// リクエスト情報
input: {
query: string; // ユーザー入力
variables?: Record<string, any>; // 変数
};
// レスポンス情報
output: {
answer: string; // AI回答
tokens: number; // トークン数
latency: number; // レイテンシ(ms)
};
// メタデータ
metadata: {
modelName: string; // 使用モデル
appId: string; // アプリケーションID
userId?: string; // ユーザーID
};
}
このように型定義を行うことで、ログデータの一貫性が保たれます。
構造化されたログは、後の分析やメトリクス計算に活用できるでしょう。
トレースの活用
複雑なワークフローでは、どのノードでどれだけ時間がかかったかを追跡することが重要です。
typescript// トレース情報の型定義
interface WorkflowTrace {
workflowId: string; // ワークフローID
executionId: string; // 実行ID
startTime: Date; // 開始時刻
endTime: Date; // 終了時刻
totalDuration: number; // 総実行時間(ms)
// ノード単位のトレース
nodeTraces: NodeTrace[];
}
interface NodeTrace {
nodeId: string; // ノードID
nodeType: string; // ノードタイプ(LLM/Tool/Condition等)
startTime: Date; // 開始時刻
duration: number; // 実行時間(ms)
status: 'success' | 'error'; // 実行ステータス
error?: string; // エラーメッセージ
}
トレース情報により、ボトルネックの特定やエラーの原因究明が容易になります。
メトリクスの収集
観測基盤では、以下のようなメトリクスをリアルタイムで収集します。
typescript// メトリクスコレクターの実装例
class DifyMetricsCollector {
// レイテンシの記録
recordLatency(latency: number, appId: string): void {
// レイテンシをヒストグラムとして記録
this.histogram.observe(
{ app_id: appId, metric: 'response_latency' },
latency
);
}
// トークン使用量の記録
recordTokenUsage(
tokens: number,
modelName: string
): void {
// トークン数をカウンターとして記録
this.counter.inc(
{ model: modelName, metric: 'token_usage' },
tokens
);
}
// エラー率の記録
recordError(appId: string, errorType: string): void {
// エラーをカウンター として記録
this.counter.inc(
{ app_id: appId, error_type: errorType },
1
);
}
}
これらのメトリクスは、ダッシュボードでリアルタイムに監視できます。
以下の図は、観測基盤のデータフローを示しています。
mermaidflowchart LR
request["リクエスト"] -->|入力| app["Dify App"]
app -->|実行| workflow["ワークフロー<br/>実行"]
workflow -->|ログ出力| logger["ログ<br/>コレクター"]
workflow -->|トレース出力| tracer["トレース<br/>コレクター"]
workflow -->|メトリクス出力| metrics["メトリクス<br/>コレクター"]
logger -->|保存| storage[("ログ<br/>ストレージ")]
tracer -->|保存| storage
metrics -->|集計| timeseries[("時系列<br/>データベース")]
storage -->|クエリ| analytics["分析<br/>ツール"]
timeseries -->|可視化| analytics
図で理解できる要点:
- ワークフロー実行から 3 種類のデータ(ログ、トレース、メトリクス)が並行して収集される
- それぞれ適切なストレージに保存され、分析ツールで統合的に活用される
指標(Metrics)の設計
指標は、AI アプリケーションの品質を定量的に評価するための重要な要素です。
自動評価指標の種類
Dify では、複数の自動評価指標を活用できます。
| # | 指標名 | 評価対象 | 計算方法 |
|---|---|---|---|
| 1 | BLEU スコア | テキスト類似度 | n-gram の一致率 |
| 2 | ROUGE スコア | 要約品質 | 単語の重複率 |
| 3 | Perplexity | 言語モデル性能 | 次トークン予測の確信度 |
| 4 | Semantic Similarity | 意味的類似度 | 埋め込みベクトルの類似度 |
| 5 | Answer Relevance | 回答の適切性 | LLM による評価 |
これらの指標を組み合わせることで、多面的な評価が可能になります。
LLM-as-a-Judge パターン
より高度な評価として、LLM 自身を評価者として使用する「LLM-as-a-Judge」パターンがあります。
typescript// LLM-as-a-Judge による評価の実装例
interface EvaluationCriteria {
name: string; // 評価基準名
description: string; // 基準の説明
scale: number; // スケール(1-5など)
}
class LLMJudge {
// 回答を評価する
async evaluateAnswer(
query: string,
answer: string,
criteria: EvaluationCriteria[]
): Promise<EvaluationResult> {
// 評価プロンプトの構築
const prompt = this.buildEvaluationPrompt(
query,
answer,
criteria
);
// LLMに評価を依頼
const evaluation = await this.llm.complete(prompt);
// 評価結果をパース
return this.parseEvaluation(evaluation);
}
}
評価プロンプトには、明確な基準とスケールを含めることが重要です。
typescript// 評価プロンプトの構築
private buildEvaluationPrompt(
query: string,
answer: string,
criteria: EvaluationCriteria[]
): string {
// 評価基準をフォーマット
const criteriaText = criteria.map(c =>
`- ${c.name}: ${c.description} (1-${c.scale})`
).join('\n');
return `
以下の回答を評価してください。
【質問】
${query}
【回答】
${answer}
【評価基準】
${criteriaText}
各基準について、スコアと理由を JSON 形式で出力してください。
`.trim();
}
このアプローチにより、柔軟で文脈に応じた評価が可能になるでしょう。
カスタム指標の実装
ユースケースに応じて、独自の評価指標を実装することも重要です。
typescript// カスタム指標の実装例:回答の安全性チェック
class SafetyScoreCalculator {
private forbiddenPatterns: RegExp[];
constructor() {
// 禁止パターンの定義
this.forbiddenPatterns = [
/個人情報.*漏洩/,
/不適切.*内容/,
// その他のパターン
];
}
// 安全性スコアを計算(0-1の範囲)
calculateSafetyScore(answer: string): number {
let violations = 0;
// 各パターンをチェック
for (const pattern of this.forbiddenPatterns) {
if (pattern.test(answer)) {
violations++;
}
}
// スコアを計算(違反が多いほど低い)
const score = Math.max(0, 1 - violations * 0.2);
return score;
}
}
ドメイン固有の要件に合わせた指標を設計することで、より実用的な評価が実現します。
以下の図は、指標計算のフローを示しています。
mermaidflowchart TB
output["LLM 出力"] -->|入力| eval["評価エンジン"]
eval -->|計算| auto["自動指標<br/>BLEU/ROUGE等"]
eval -->|計算| llm_judge["LLM-as-a-Judge<br/>評価"]
eval -->|計算| custom["カスタム指標<br/>安全性等"]
auto -->|集約| aggregator["スコア<br/>集約"]
llm_judge -->|集約| aggregator
custom -->|集約| aggregator
aggregator -->|保存| db[("評価<br/>データベース")]
db -->|分析| report["評価<br/>レポート"]
図で理解できる要点:
- LLM 出力が評価エンジンに渡され、3 種類の指標で並行評価される
- すべての指標がスコア集約で統合され、データベースに保存される
人手評価(Human Evaluation)の設計
自動評価だけでは捉えきれない品質を、人間の判断で補完します。
評価タスクの設計
効率的な人手評価のためには、明確なタスク設計が必要です。
typescript// 評価タスクの型定義
interface HumanEvaluationTask {
taskId: string; // タスクID
conversationId: string; // 会話ID
// 評価対象
context: {
query: string; // ユーザー質問
answer: string; // AI回答
metadata?: Record<string, any>; // メタデータ
};
// 評価項目
evaluationItems: EvaluationItem[];
// ステータス
status: 'pending' | 'completed' | 'skipped';
assignedTo?: string; // 担当者
completedAt?: Date; // 完了日時
}
評価項目は、明確な質問と選択肢で構成します。
typescript// 評価項目の型定義
interface EvaluationItem {
itemId: string; // 項目ID
question: string; // 評価質問
type: 'scale' | 'choice' | 'text'; // 回答タイプ
// スケール評価の場合
scale?: {
min: number; // 最小値
max: number; // 最大値
labels: string[]; // ラベル
};
// 選択肢評価の場合
choices?: string[];
// 回答
answer?: any;
comment?: string; // コメント
}
具体的な評価項目の例を示します。
typescript// 評価項目の設定例
const evaluationItems: EvaluationItem[] = [
{
itemId: 'relevance',
question: '回答は質問に適切に答えていますか?',
type: 'scale',
scale: {
min: 1,
max: 5,
labels: [
'全く適切でない',
'やや不適切',
'どちらとも言えない',
'やや適切',
'非常に適切',
],
},
},
{
itemId: 'accuracy',
question: '回答の内容は正確ですか?',
type: 'choice',
choices: [
'正確',
'一部不正確',
'不正確',
'判断できない',
],
},
{
itemId: 'tone',
question: '回答のトーンは適切ですか?',
type: 'scale',
scale: { min: 1, max: 5, labels: [] },
},
];
このように、具体的で回答しやすい質問を用意することが重要です。
サンプリング戦略
すべての会話を評価するのは現実的ではないため、適切なサンプリング戦略が必要です。
typescript// サンプリング戦略の実装例
class EvaluationSampler {
// ランダムサンプリング
randomSample(
conversations: Conversation[],
sampleSize: number
): Conversation[] {
// シャッフルして指定数を取得
return this.shuffle(conversations).slice(0, sampleSize);
}
// 層化サンプリング
stratifiedSample(
conversations: Conversation[],
sampleSize: number,
stratifyBy: keyof Conversation
): Conversation[] {
// 層ごとにグループ化
const groups = this.groupBy(conversations, stratifyBy);
// 各層から均等にサンプリング
const samplesPerGroup = Math.floor(
sampleSize / Object.keys(groups).length
);
return Object.values(groups).flatMap((group) =>
this.randomSample(group, samplesPerGroup)
);
}
}
層化サンプリングを使用することで、偏りの少ない評価が可能になります。
typescript// 優先度ベースのサンプリング
class PrioritySampler {
// 優先度を計算
calculatePriority(conversation: Conversation): number {
let priority = 0;
// エラーがあれば優先度を上げる
if (conversation.hasError) {
priority += 10;
}
// レイテンシが高ければ優先度を上げる
if (conversation.latency > 5000) {
priority += 5;
}
// ユーザーフィードバックが否定的なら優先度を上げる
if (conversation.userFeedback === 'negative') {
priority += 8;
}
return priority;
}
// 優先度順にサンプリング
prioritySample(
conversations: Conversation[],
sampleSize: number
): Conversation[] {
// 優先度でソート
return conversations
.sort(
(a, b) =>
this.calculatePriority(b) -
this.calculatePriority(a)
)
.slice(0, sampleSize);
}
}
問題のある会話を優先的に評価することで、効率的な品質改善が可能です。
フィードバックループの構築
評価結果を改善に活かすためのフィードバックループを構築します。
typescript// フィードバック集約の実装
class FeedbackAggregator {
// 評価結果を集約
aggregateEvaluations(
evaluations: HumanEvaluationTask[]
): AggregatedFeedback {
// 項目ごとの平均スコアを計算
const scoresByItem =
this.calculateAverageScores(evaluations);
// 問題のあるパターンを特定
const issues = this.identifyIssues(evaluations);
// 改善提案を生成
const suggestions = this.generateSuggestions(
scoresByItem,
issues
);
return {
scoresByItem,
issues,
suggestions,
totalEvaluations: evaluations.length,
};
}
}
集約されたフィードバックは、プロンプト改善やモデル選択に活用できます。
以下の図は、人手評価のフローを示しています。
mermaidflowchart TB
conv["会話ログ"] -->|サンプリング| sampler["サンプリング<br/>エンジン"]
sampler -->|ランダム| random["ランダム<br/>サンプル"]
sampler -->|層化| stratified["層化<br/>サンプル"]
sampler -->|優先度| priority["優先度<br/>サンプル"]
random -->|タスク作成| task["評価<br/>タスク"]
stratified -->|タスク作成| task
priority -->|タスク作成| task
task -->|割り当て| evaluator["評価者"]
evaluator -->|回答| result["評価結果"]
result -->|集約| aggregator["フィードバック<br/>集約"]
aggregator -->|改善| improve["プロンプト/<br/>モデル改善"]
図で理解できる要点:
- 3 種類のサンプリング手法から評価タスクが生成される
- 評価者による回答が集約され、改善アクションにつながる循環
具体例
評価基盤の実装例
実際の Dify アプリケーションに評価基盤を実装する例を示します。
プロジェクト構成
以下のようなディレクトリ構成で評価基盤を実装します。
typescript// プロジェクト構成
/*
evaluation-platform/
├── src/
│ ├── observability/ # 観測関連
│ │ ├── logger.ts # ログ収集
│ │ ├── tracer.ts # トレース収集
│ │ └── metrics.ts # メトリクス収集
│ ├── metrics/ # 指標関連
│ │ ├── auto-eval.ts # 自動評価
│ │ ├── llm-judge.ts # LLM評価
│ │ └── custom.ts # カスタム指標
│ ├── human-eval/ # 人手評価関連
│ │ ├── sampler.ts # サンプリング
│ │ ├── task.ts # タスク管理
│ │ └── aggregator.ts # 集約
│ └── dashboard/ # ダッシュボード
│ └── api.ts # API
└── config/
└── evaluation.yaml # 設定ファイル
*/
統合クラスの実装
各コンポーネントを統合する評価基盤クラスを実装します。
typescript// 評価基盤の統合クラス
import { Logger } from './observability/logger';
import { MetricsCollector } from './observability/metrics';
import { AutoEvaluator } from './metrics/auto-eval';
import { LLMJudge } from './metrics/llm-judge';
import { EvaluationSampler } from './human-eval/sampler';
class DifyEvaluationPlatform {
private logger: Logger;
private metrics: MetricsCollector;
private autoEval: AutoEvaluator;
private llmJudge: LLMJudge;
private sampler: EvaluationSampler;
constructor(config: EvaluationConfig) {
// 各コンポーネントを初期化
this.logger = new Logger(config.logging);
this.metrics = new MetricsCollector(config.metrics);
this.autoEval = new AutoEvaluator(config.autoEval);
this.llmJudge = new LLMJudge(config.llmJudge);
this.sampler = new EvaluationSampler(config.sampling);
}
}
会話処理時に評価を実行するメソッドを追加します。
typescript// 会話の評価処理
async evaluateConversation(
conversation: Conversation
): Promise<EvaluationReport> {
// 1. ログの記録
await this.logger.log({
conversationId: conversation.id,
query: conversation.query,
answer: conversation.answer,
timestamp: new Date()
});
// 2. メトリクスの収集
this.metrics.recordLatency(
conversation.latency,
conversation.appId
);
this.metrics.recordTokenUsage(
conversation.tokens,
conversation.modelName
);
// 3. 自動評価の実行
const autoScores = await this.autoEval.evaluate(
conversation.query,
conversation.answer
);
return {
conversationId: conversation.id,
scores: autoScores,
timestamp: new Date()
};
}
バッチ評価の実装
定期的にバッチで評価を実行する処理を実装します。
typescript// バッチ評価の実装
async runBatchEvaluation(
startDate: Date,
endDate: Date
): Promise<BatchEvaluationReport> {
// 1. 期間内の会話を取得
const conversations = await this.fetchConversations(
startDate,
endDate
);
// 2. 自動評価を実行
const autoEvalResults = await Promise.all(
conversations.map(conv =>
this.autoEval.evaluate(conv.query, conv.answer)
)
);
// 3. サンプリングして人手評価タスクを作成
const samples = this.sampler.prioritySample(
conversations,
100 // 100件をサンプリング
);
const humanEvalTasks = samples.map(conv =>
this.createHumanEvalTask(conv)
);
return {
totalConversations: conversations.length,
autoEvalResults,
humanEvalTasks,
period: { startDate, endDate }
};
}
ダッシュボード API の実装
評価結果を可視化するための API を実装します。
typescript// ダッシュボード API の実装
import express from 'express';
class EvaluationDashboardAPI {
private platform: DifyEvaluationPlatform;
private app: express.Application;
constructor(platform: DifyEvaluationPlatform) {
this.platform = platform;
this.app = express();
this.setupRoutes();
}
private setupRoutes(): void {
// メトリクスの取得
this.app.get('/api/metrics', async (req, res) => {
const metrics = await this.getMetrics(
req.query.startDate as string,
req.query.endDate as string
);
res.json(metrics);
});
// 評価結果の取得
this.app.get('/api/evaluations', async (req, res) => {
const evaluations = await this.getEvaluations(
req.query.appId as string
);
res.json(evaluations);
});
}
}
メトリクスデータの集約処理を追加します。
typescript// メトリクスデータの集約
private async getMetrics(
startDate: string,
endDate: string
): Promise<MetricsSummary> {
// データベースからメトリクスを取得
const rawMetrics = await this.fetchMetricsFromDB(
new Date(startDate),
new Date(endDate)
);
// 集計処理
return {
averageLatency: this.calculateAverage(
rawMetrics.map(m => m.latency)
),
totalTokens: this.calculateSum(
rawMetrics.map(m => m.tokens)
),
errorRate: this.calculateErrorRate(rawMetrics),
conversationCount: rawMetrics.length
};
}
以下の図は、実装全体のアーキテクチャを示しています。
mermaidflowchart TB
subgraph frontend["フロントエンド"]
dashboard["ダッシュボード<br/>UI"]
end
subgraph backend["バックエンド"]
api["ダッシュボード<br/>API"]
platform["評価基盤<br/>コア"]
subgraph components["コンポーネント"]
obs["観測"]
met["指標"]
human["人手評価"]
end
end
subgraph storage["ストレージ"]
logs[("ログ<br/>DB")]
metrics_db[("メトリクス<br/>DB")]
eval_db[("評価<br/>DB")]
end
dashboard -->|HTTP| api
api -->|クエリ| platform
platform -->|利用| components
obs -->|保存| logs
met -->|保存| metrics_db
human -->|保存| eval_db
図で理解できる要点:
- フロントエンドからバックエンド API を経由して評価基盤コアにアクセスする構造
- 3 つのコンポーネントがそれぞれ専用のストレージに データを保存する
設定ファイルの例
評価基盤の動作を制御する設定ファイルの例です。
yaml# evaluation.yaml - 評価基盤の設定
# ログ設定
logging:
level: info
format: json
output:
- type: file
path: ./logs/evaluation.log
- type: elasticsearch
host: localhost:9200
index: dify-evaluations
# メトリクス設定
metrics:
collection_interval: 60 # 秒
retention_days: 90
exporters:
- type: prometheus
port: 9090
- type: cloudwatch
region: ap-northeast-1
# 自動評価設定
auto_evaluation:
enabled: true
metrics:
- name: semantic_similarity
threshold: 0.7
- name: answer_relevance
model: gpt-4
batch_size: 100
人手評価の設定を追加します。
yaml# 人手評価設定
human_evaluation:
enabled: true
# サンプリング設定
sampling:
strategy: priority # random, stratified, priority
sample_size: 100
frequency: daily
# 優先度設定
priority_factors:
- name: has_error
weight: 10
- name: high_latency
weight: 5
- name: negative_feedback
weight: 8
# 評価項目設定
evaluation_items:
- id: relevance
question: '回答は質問に適切に答えていますか?'
type: scale
scale: 1-5
required: true
- id: accuracy
question: '回答の内容は正確ですか?'
type: choice
choices:
- '正確'
- '一部不正確'
- '不正確'
- '判断できない'
required: true
このように、YAML ファイルで柔軟に設定を管理できます。
運用フローの例
実際の運用における評価フローを示します。
typescript// 日次評価バッチの実装例
import cron from 'node-cron';
class DailyEvaluationJob {
private platform: DifyEvaluationPlatform;
constructor(platform: DifyEvaluationPlatform) {
this.platform = platform;
}
// 日次バッチをスケジュール
schedule(): void {
// 毎日午前2時に実行
cron.schedule('0 2 * * *', async () => {
await this.runDailyEvaluation();
});
}
// 日次評価の実行
private async runDailyEvaluation(): Promise<void> {
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
yesterday.setHours(0, 0, 0, 0);
const today = new Date();
today.setHours(0, 0, 0, 0);
// バッチ評価を実行
const report = await this.platform.runBatchEvaluation(
yesterday,
today
);
// レポートを保存
await this.saveReport(report);
// アラートをチェック
await this.checkAlerts(report);
}
}
アラート機能の実装例です。
typescript// アラート機能の実装
private async checkAlerts(
report: BatchEvaluationReport
): Promise<void> {
const alerts: Alert[] = [];
// エラー率が閾値を超えていないかチェック
const errorRate = this.calculateErrorRate(
report.autoEvalResults
);
if (errorRate > 0.05) { // 5%を超える
alerts.push({
level: 'warning',
message: `エラー率が ${errorRate * 100}% に上昇しています`,
metric: 'error_rate',
value: errorRate
});
}
// レイテンシが閾値を超えていないかチェック
const avgLatency = this.calculateAverageLatency(
report.autoEvalResults
);
if (avgLatency > 3000) { // 3秒を超える
alerts.push({
level: 'critical',
message: `平均レイテンシが ${avgLatency}ms に上昇しています`,
metric: 'latency',
value: avgLatency
});
}
// アラートを通知
if (alerts.length > 0) {
await this.sendAlerts(alerts);
}
}
この実装により、問題を早期に発見し、迅速に対応できます。
まとめ
本記事では、Dify における評価基盤の全体像と設計ポイントについて解説しました。
観測(Observability)、指標(Metrics)、人手評価(Human Evaluation)という 3 つの柱を組み合わせることで、AI アプリケーションの品質を多角的に評価できます。これらの要素は互いに補完し合い、より正確で実用的な評価を実現するでしょう。
評価基盤を構築する際の重要なポイントをまとめます。
| # | ポイント | 詳細 |
|---|---|---|
| 1 | 構造化されたログ | 分析しやすい形式でデータを記録 |
| 2 | 適切な指標の選定 | ユースケースに合わせた評価軸の設定 |
| 3 | 効率的なサンプリング | 優先度を考慮した人手評価の実施 |
| 4 | フィードバックループ | 評価結果を改善に活かす仕組み |
| 5 | 自動化と定期実行 | 継続的な評価の実現 |
AI アプリケーション開発において、評価は一度きりの作業ではありません。継続的に評価し、改善を重ねることで、ユーザーに価値を提供できるアプリケーションへと成長させることができます。
本記事で紹介した設計パターンと実装例を参考に、皆様のプロジェクトに適した評価基盤を構築していただければ幸いです。評価データは、プロダクトの成長を導く貴重な資産となるでしょう。
関連リンク
以下のリンクでは、Dify や AI アプリケーション評価に関する詳細な情報を確認できます。
articleDify の評価基盤を俯瞰:観測・指標・人手評価の設計ポイント
articleDify フィードバック学習運用:人手評価・プロンプト AB テスト・継続改善
articleDify マルチテナント設計:データ分離・キー管理・レート制限の深掘り
articleDify ワークフロー定型 30:分岐・並列・リトライ・サーキットブレーカの型
articleDify を Kubernetes にデプロイ:Helm とスケーリング設計の実践
articleDify のベクトル DB 選定比較:pgvector・Milvus・Weaviate の実測レポート
articleCursor エディタ:キャッシュクリアで動作改善!Windows/Mac での手順とマウスカーソルの直し方
articlePinia ストアスキーマの変更管理:バージョン付与・マイグレーション・互換ポリシー
articleshadcn/ui コンポーネント置換マップ:用途別に最短でたどり着く選定表
articleOllama のコスト最適化:モデルサイズ・VRAM 使用量・バッチ化の実践
articleRemix Loader/Action チートシート:Request/Response API 逆引き大全
articleObsidian タスク運用の最適解:Tasks + Periodic Notes で計画と実行を接続
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来