> Discover all available pages from the documentation index: https://mastra.zisheng.pro/ja/llms.txt # カスタム Scorer Mastra は統一された `createScorer` ファクトリーを提供しています。各ステップで JavaScript 関数または LLM ベースのプロンプトオブジェクトを使用して、カスタム評価ロジックを構築できます。この柔軟性により、評価パイプラインの各部分に最適な方法を選択できます。 ## 4ステップのパイプライン Mastra のすべての Scorer は、一貫した4ステップの評価パイプラインに従います。 1. **preprocess**(任意): 入出力データを準備または変換する 2. **analyze**(任意): 評価分析を実行して知見を収集する 3. **generateScore**(必須): 分析結果を数値スコアに変換する 4. **generateReason**(任意): 人が読める説明を生成する 各ステップでは**関数**または**プロンプトオブジェクト**(LLM ベースの評価)を使用できるため、必要に応じて決定論的なアルゴリズムと AI の判断を組み合わせられます。 ## 関数とプロンプトオブジェクト **関数**は JavaScript で決定論的なロジックを実装します。次の用途に適しています。 - 明確な基準に基づくアルゴリズム評価 - パフォーマンスが重視されるシナリオ - 既存ライブラリとの統合 - 一貫性と再現性のある結果 **プロンプトオブジェクト**は LLM を評価の Judge として使用します。次の用途に適しています。 - 人間のような判断を必要とする主観的な評価 - アルゴリズムとして実装するのが難しい複雑な基準 - 自然言語理解タスク - 微妙なニュアンスを含むコンテキスト評価 **「プロンプトオブジェクト」の意味:** 関数の代わりに、`description` と `createPrompt`(`preprocess`/`analyze` ではさらに `outputSchema`)を持つオブジェクトをステップに指定します。このオブジェクトは、そのステップで Judge LLM を実行し、構造化された出力を `results.StepResult` に保存するよう Mastra に指示します。 1つの Scorer 内で方法を組み合わせることもできます。たとえば、データの前処理には関数を使用し、品質の分析には LLM を使用できます。 ## Scorer を初期化する すべての Scorer は `createScorer` ファクトリー関数から始まります。ID と説明は必須で、型の指定と Judge の設定は任意です。 ```typescript import { createScorer } from '@mastra/core/evals'; const glutenCheckerScorer = createScorer({ id: 'gluten-checker', description: 'Check if recipes contain gluten ingredients', judge: { // Optional: for prompt object steps model: 'openai/gpt-5.6-sol', instructions: 'You are a Chef that identifies if recipes contain gluten.' } }) // Chain step methods here .preprocess(...) .analyze(...) .generateScore(...) .generateReason(...) ``` Judge の設定は、いずれかのステップでプロンプトオブジェクトを使用する場合にのみ必要です。個々のステップでは、独自の Judge 設定によってこのデフォルト設定を上書きできます。 すべてのステップが関数ベースの場合、Judge は呼び出されず、Judge の出力もありません。LLM の出力を確認するには、少なくとも1つのステップをプロンプトオブジェクトとして定義し、対応するステップ結果(たとえば `results.analyzeStepResult`)を読み取ります。 ### 最小限の Judge の例(プロンプトオブジェクト) この例では `analyze` にプロンプトオブジェクトを使用するため、Judge が実行され、その構造化された出力を `results.analyzeStepResult` として利用できます。 ```typescript import { createScorer } from '@mastra/core/evals' import { z } from 'zod' const quoteSourcesScorer = createScorer({ id: 'quote-sources', description: 'Check if the response includes sources', judge: { model: 'openai/gpt-5-mini', instructions: 'You are a strict evaluator.', }, }) .analyze({ description: 'Detect whether sources are present', outputSchema: z.object({ hasSources: z.boolean(), sources: z.array(z.string()), }), createPrompt: ({ run }) => ` Does the response contain sources? Extract them as a list. Response: ${run.output} `, }) .generateScore(({ results }) => (results.analyzeStepResult.hasSources ? 1 : 0)) // Run the scorer and inspect judge output const result = await quoteSourcesScorer.run({ input: 'What is the capital of France?', output: 'Paris is the capital of France [1]. Source: [1] Wikipedia', }) console.log(result.score) // 1 console.log(result.analyzeStepResult) // { hasSources: true, sources: ["Wikipedia"] } ``` ### Agent 評価の Agent 型 型安全性を確保し、稼働中の Agent のスコアリングと Trace のスコアリングの両方に対応するため、Agent 評価用の Scorer を作成するときは `type: 'agent'` を使用します。これにより、同じ Scorer を Agent に使用できるだけでなく、Trace のスコアリングにも使用できます。 ```typescript const myScorer = createScorer({ type: 'agent', // Automatically handles agent input/output types }).generateScore(({ run, results }) => { // run.output is automatically typed as ScorerRunOutputForAgent // run.input is automatically typed as ScorerRunInputForAgent }) ``` ## 各ステップの詳細 ### preprocess ステップ(任意) 特定の要素の抽出、コンテンツの絞り込み、複雑なデータ構造の変換が必要な場合に、入出力データを準備します。 **関数:** `({ run, results }) => any` ```typescript const glutenCheckerScorer = createScorer(...) .preprocess(({ run }) => { // Extract and clean recipe text const recipeText = run.output.text.toLowerCase(); const wordCount = recipeText.split(' ').length; return { recipeText, wordCount, hasCommonGlutenWords: /flour|wheat|bread|pasta/.test(recipeText) }; }) ``` **プロンプトオブジェクト:** `description`、`outputSchema`、`createPrompt` を使用して、LLM ベースの前処理を構造化します。 ```typescript const glutenCheckerScorer = createScorer(...) .preprocess({ description: 'Extract ingredients from the recipe', outputSchema: z.object({ ingredients: z.array(z.string()), cookingMethods: z.array(z.string()) }), createPrompt: ({ run }) => ` Extract all ingredients and cooking methods from this recipe: ${run.output.text} Return JSON with ingredients and cookingMethods arrays. ` }) ``` **データフロー:** 後続のステップでは、結果を `results.preprocessStepResult` として利用できます。 ### analyze ステップ(任意) 評価の中核となる分析を実行し、スコアの決定に使用する知見を収集します。 **関数:** `({ run, results }) => any` ```typescript const glutenCheckerScorer = createScorer({...}) .preprocess(...) .analyze(({ run, results }) => { const { recipeText, hasCommonGlutenWords } = results.preprocessStepResult; // Simple gluten detection algorithm const glutenKeywords = ['wheat', 'flour', 'barley', 'rye', 'bread']; const foundGlutenWords = glutenKeywords.filter(word => recipeText.includes(word) ); return { isGlutenFree: foundGlutenWords.length === 0, detectedGlutenSources: foundGlutenWords, confidence: hasCommonGlutenWords ? 0.9 : 0.7 }; }) ``` **プロンプトオブジェクト:** LLM ベースの分析には、`description`、`outputSchema`、`createPrompt` を使用します。 ```typescript const glutenCheckerScorer = createScorer({...}) .preprocess(...) .analyze({ description: 'Analyze recipe for gluten content', outputSchema: z.object({ isGlutenFree: z.boolean(), glutenSources: z.array(z.string()), confidence: z.number().min(0).max(1) }), createPrompt: ({ run, results }) => ` Analyze this recipe for gluten content: "${results.preprocessStepResult.recipeText}" Look for wheat, barley, rye, and hidden sources like soy sauce. Return JSON with isGlutenFree, glutenSources array, and confidence (0-1). ` }) ``` **データフロー:** 後続のステップでは、結果を `results.analyzeStepResult` として利用できます。 ### `generateScore` ステップ(必須) 分析結果を数値スコアに変換します。パイプラインで唯一必須のステップです。 **関数:** `({ run, results }) => number` ```typescript const glutenCheckerScorer = createScorer({...}) .preprocess(...) .analyze(...) .generateScore(({ results }) => { const { isGlutenFree, confidence } = results.analyzeStepResult; // Return 1 for gluten-free, 0 for contains gluten // Weight by confidence level return isGlutenFree ? confidence : 0; }) ``` **プロンプトオブジェクト:** 必須の `calculateScore` 関数を含め、generateScore でプロンプトオブジェクトを使用する方法の詳細については、[`createScorer`](https://mastra.zisheng.pro/ja/reference/evals/create-scorer) API リファレンスを参照してください。 **データフロー:** generateReason では、スコアを `score` パラメーターとして利用できます。 ### `generateReason` ステップ(任意) スコアについて人が読める説明を生成します。デバッグ、透明性の確保、ユーザーフィードバックに役立ちます。 **関数:** `({ run, results, score }) => string` ```typescript const glutenCheckerScorer = createScorer({...}) .preprocess(...) .analyze(...) .generateScore(...) .generateReason(({ results, score }) => { const { isGlutenFree, glutenSources } = results.analyzeStepResult; if (isGlutenFree) { return `Score: ${score}. This recipe is gluten-free with no harmful ingredients detected.`; } else { return `Score: ${score}. Contains gluten from: ${glutenSources.join(', ')}`; } }) ``` **プロンプトオブジェクト:** LLM で説明を生成するには、`description` と `createPrompt` を使用します。 ```typescript const glutenCheckerScorer = createScorer({...}) .preprocess(...) .analyze(...) .generateScore(...) .generateReason({ description: 'Explain the gluten assessment', createPrompt: ({ results, score }) => ` Explain why this recipe received a score of ${score}. Analysis: ${JSON.stringify(results.analyzeStepResult)} Provide a clear explanation for someone with dietary restrictions. ` }) ``` ## 入力のフィルタリング Agent の会話には、Tool 呼び出しやデータパートを含む数百件のメッセージに加え、システムメタデータが含まれることがあります。ほとんどの Scorer が必要とするのは、このデータの一部だけです。`prepareRun` オプションは Scorer パイプラインの実行前に実行データを変換し、ノイズを減らして Scorer が評価対象に集中できるようにします。 ### `filterRun()` による宣言的なフィルタリング [`filterRun()`](https://mastra.zisheng.pro/ja/reference/evals/filter-run) ユーティリティは、宣言的なオプションから `prepareRun` 関数を作成します。 ```typescript import { createScorer, filterRun } from '@mastra/core/evals' const toolScorer = createScorer({ id: 'tool-quality', description: 'Evaluates tool usage quality', type: 'agent', prepareRun: filterRun({ partTypes: ['tool-invocation', 'text'], maxRememberedMessages: 20, }), }).generateScore(({ run }) => { // run.input.rememberedMessages has only tool and text messages, max 20 return 1 }) ``` 一般的なオプションは次のとおりです。 - `partTypes`: 一致するパートタイプのメッセージのみを保持します(例: `'tool-invocation'`、`'text'`、`'reasoning'`) - `toolNames`: 特定の Tool に関連するメッセージのみを保持します(例: `['write_file', 'execute_command']`) - `maxRememberedMessages`: コンテキストウィンドウのサイズを制限します - `dropRequestContext`、`dropGroundTruth`、`dropExpectedTrajectory`: 使用しないフィールドを削除します オプションの完全な一覧については、[`filterRun()` リファレンス](https://mastra.zisheng.pro/ja/reference/evals/filter-run)を参照してください。 ### カスタム `prepareRun` 関数 `filterRun()` では対応できないロジックには、`prepareRun` 関数を直接記述します。 ```typescript import { createScorer } from '@mastra/core/evals' const customScorer = createScorer({ id: 'recent-output', description: 'Scores only the last response', type: 'agent', prepareRun: (run) => ({ ...run, output: run.output.slice(-1), // Keep only the last message requestContext: undefined, }), }) .generateScore(({ run }) => { return run.output.length > 0 ? 1 : 0 }) ``` `prepareRun` 関数は非同期にもできます。 > **システムメッセージは常に保持されます:** `filterRun()` は `systemMessages` や `taggedSystemMessages` をフィルタリングしません。これらには Agent の指示が含まれており、スコアリングに不可欠なコンテキストです。 ## 例: カスタム Scorer を作成する Mastra のカスタム Scorer は、`createScorer` と次の4つの主要コンポーネントを使用します。 1. [**Judge の設定**](#judge-configuration) 2. [**分析ステップ**](#analysis-step) 3. [**スコア生成**](#score-generation) 4. [**理由の生成**](#reason-generation) これらのコンポーネントを組み合わせることで、LLM を Judge として使用するカスタム評価ロジックを定義できます。完全な API と設定オプションについては、[createScorer](https://mastra.zisheng.pro/ja/reference/evals/create-scorer) を参照してください。 ```typescript import { createScorer } from '@mastra/core/evals' import { z } from 'zod' export const GLUTEN_INSTRUCTIONS = `You are a Chef that identifies if recipes contain gluten.` export const generateGlutenPrompt = ({ output, }: { output: string }) => `Check if this recipe is gluten-free. Check for: - Wheat - Barley - Rye - Common sources like flour, pasta, bread Example with gluten: "Mix flour and water to make dough" Response: { "isGlutenFree": false, "glutenSources": ["flour"] } Example gluten-free: "Mix rice, beans, and vegetables" Response: { "isGlutenFree": true, "glutenSources": [] } Recipe to analyze: ${output} Return your response in this format: { "isGlutenFree": boolean, "glutenSources": ["list ingredients containing gluten"] }` export const generateReasonPrompt = ({ isGlutenFree, glutenSources, }: { isGlutenFree: boolean glutenSources: string[] }) => `Explain why this recipe is${isGlutenFree ? '' : ' not'} gluten-free. ${glutenSources.length > 0 ? `Sources of gluten: ${glutenSources.join(', ')}` : 'No gluten-containing ingredients found'} Return your response in this format: "This recipe is [gluten-free/contains gluten] because [explanation]"` export const glutenCheckerScorer = createScorer({ id: 'gluten-checker', description: 'Check if the output contains any gluten', judge: { model: 'openai/gpt-5-mini', instructions: GLUTEN_INSTRUCTIONS, }, }) .analyze({ description: 'Analyze the output for gluten', outputSchema: z.object({ isGlutenFree: z.boolean(), glutenSources: z.array(z.string()), }), createPrompt: ({ run }) => { const { output } = run return generateGlutenPrompt({ output: output.text }) }, }) .generateScore(({ results }) => { return results.analyzeStepResult.isGlutenFree ? 1 : 0 }) .generateReason({ description: 'Generate a reason for the score', createPrompt: ({ results }) => { return generateReasonPrompt({ glutenSources: results.analyzeStepResult.glutenSources, isGlutenFree: results.analyzeStepResult.isGlutenFree, }) }, }) ``` ### Judge の設定 LLM モデルを設定し、ドメインエキスパートとしての役割を定義します。 ```typescript judge: { model: 'openai/gpt-5-mini', instructions: GLUTEN_INSTRUCTIONS, } ``` ### 分析ステップ LLM が入力をどのように分析し、どのような構造化出力を返すかを定義します。 ```typescript .analyze({ description: 'Analyze the output for gluten', outputSchema: z.object({ isGlutenFree: z.boolean(), glutenSources: z.array(z.string()), }), createPrompt: ({ run }) => { const { output } = run; return generateGlutenPrompt({ output: output.text }); }, }) ``` 分析ステップでは、プロンプトオブジェクトを使用して次の処理を行います。 - 分析タスクを明確に説明する - Standard JSON Schema で期待される出力構造を定義する(真偽値の結果とグルテン源の一覧) - 入力内容に基づいて実行時プロンプトを生成する ### スコア生成 LLM の構造化された分析を数値スコアに変換します。 ```typescript .generateScore(({ results }) => { return results.analyzeStepResult.isGlutenFree ? 1 : 0; }) ``` スコア生成関数は分析結果を受け取り、ビジネスロジックを適用してスコアを生成します。この例では、レシピがグルテンフリーかどうかを LLM が直接判定するため、その真偽値を使用します。グルテンフリーなら 1、グルテンを含む場合は 0 です。 ### 理由の生成 別の LLM 呼び出しを使用して、スコアについて人が読める説明を生成します。 ```typescript .generateReason({ description: 'Generate a reason for the score', createPrompt: ({ results }) => { return generateReasonPrompt({ glutenSources: results.analyzeStepResult.glutenSources, isGlutenFree: results.analyzeStepResult.isGlutenFree, }); }, }) ``` 理由生成ステップは、真偽値の結果と分析ステップで特定された具体的なグルテン源の両方を使用し、そのスコアになった理由をユーザーが理解するための説明を生成します。 ## グルテンフリーと高く評価される例 ```typescript const result = await glutenCheckerScorer.run({ input: [{ role: 'user', content: 'Mix rice, beans, and vegetables' }], output: { text: 'Mix rice, beans, and vegetables' }, }) console.log('Score:', result.score) console.log('Gluten sources:', result.analyzeStepResult.glutenSources) console.log('Reason:', result.reason) ``` ### グルテンフリーと高く評価された出力 ```typescript { score: 1, analyzeStepResult: { isGlutenFree: true, glutenSources: [] }, reason: 'This recipe is gluten-free because rice, beans, and vegetables are naturally gluten-free ingredients that are safe for people with celiac disease.' } ``` ## グルテンを含む例 ```typescript const result = await glutenCheckerScorer.run({ input: [{ role: 'user', content: 'Mix flour and water to make dough' }], output: { text: 'Mix flour and water to make dough' }, }) console.log('Score:', result.score) console.log('Gluten sources:', result.analyzeStepResult.glutenSources) console.log('Reason:', result.reason) ``` ### グルテンを含む場合の出力 ```typescript { score: 0, analyzeStepResult: { isGlutenFree: false, glutenSources: ['flour'] }, reason: 'This recipe is not gluten-free because it contains flour. Regular flour is made from wheat and contains gluten, making it unsafe for people with celiac disease or gluten sensitivity.' } ``` ## グルテンフリーと低く評価される例 ```typescript const result = await glutenCheckerScorer.run({ input: [{ role: 'user', content: 'Add soy sauce and noodles' }], output: { text: 'Add soy sauce and noodles' }, }) console.log('Score:', result.score) console.log('Gluten sources:', result.analyzeStepResult.glutenSources) console.log('Reason:', result.reason) ``` ### グルテンフリーと低く評価された出力 ```typescript { score: 0, analyzeStepResult: { isGlutenFree: false, glutenSources: ['soy sauce', 'noodles'] }, reason: 'This recipe is not gluten-free because it contains soy sauce, noodles. Regular soy sauce contains wheat and most noodles are made from wheat flour, both of which contain gluten and are unsafe for people with gluten sensitivity.' } ``` **例とリソース:** - [createScorer API リファレンス](https://mastra.zisheng.pro/ja/reference/evals/create-scorer): 完全な技術ドキュメント - [組み込み Scorer のソースコード](https://github.com/mastra-ai/mastra/tree/main/packages/evals/src/scorers): 参考にできる実際の実装