@mastra/evals 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/dist/checks-64AonnEK.js +379 -0
- package/dist/checks-64AonnEK.js.map +1 -0
- package/dist/checks-DGTgg-nW.cjs +479 -0
- package/dist/checks-DGTgg-nW.cjs.map +1 -0
- package/dist/checks.cjs +14 -56
- package/dist/checks.js +2 -3
- package/dist/docs/SKILL.md +2 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-evals-built-in-scorers.md +4 -4
- package/dist/docs/references/docs-evals-overview.md +6 -4
- package/dist/docs/references/docs-evals-quick-checks.md +2 -2
- package/dist/docs/references/reference-evals-answer-relevancy.md +5 -5
- package/dist/docs/references/reference-evals-answer-similarity.md +1 -1
- package/dist/docs/references/reference-evals-bias.md +4 -4
- package/dist/docs/references/reference-evals-checks.md +3 -3
- package/dist/docs/references/reference-evals-completeness.md +5 -5
- package/dist/docs/references/reference-evals-content-similarity.md +5 -5
- package/dist/docs/references/reference-evals-context-precision.md +5 -5
- package/dist/docs/references/reference-evals-context-recall.md +11 -11
- package/dist/docs/references/reference-evals-context-relevance.md +15 -15
- package/dist/docs/references/reference-evals-faithfulness.md +4 -4
- package/dist/docs/references/reference-evals-hallucination.md +11 -11
- package/dist/docs/references/reference-evals-keyword-coverage.md +6 -6
- package/dist/docs/references/reference-evals-noise-sensitivity.md +15 -15
- package/dist/docs/references/reference-evals-prompt-alignment.md +20 -20
- package/dist/docs/references/reference-evals-rubric.md +2 -2
- package/dist/docs/references/reference-evals-scorer-utils.md +4 -4
- package/dist/docs/references/reference-evals-summarization.md +203 -0
- package/dist/docs/references/reference-evals-textual-difference.md +4 -4
- package/dist/docs/references/reference-evals-tool-call-accuracy.md +4 -4
- package/dist/docs/references/reference-evals-toxicity.md +5 -5
- package/dist/docs/references/reference-evals-trajectory-accuracy.md +10 -10
- package/dist/index.cjs +12 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/scorers/llm/index.d.ts +1 -0
- package/dist/scorers/llm/index.d.ts.map +1 -1
- package/dist/scorers/llm/summarization/index.d.ts +55 -0
- package/dist/scorers/llm/summarization/index.d.ts.map +1 -0
- package/dist/scorers/llm/summarization/prompts.d.ts +48 -0
- package/dist/scorers/llm/summarization/prompts.d.ts.map +1 -0
- package/dist/scorers/prebuilt/index.cjs +2753 -2848
- package/dist/scorers/prebuilt/index.cjs.map +1 -1
- package/dist/scorers/prebuilt/index.js +2735 -2791
- package/dist/scorers/prebuilt/index.js.map +1 -1
- package/dist/scorers/utils.cjs +966 -101
- package/dist/scorers/utils.cjs.map +1 -1
- package/dist/scorers/utils.js +939 -2
- package/dist/scorers/utils.js.map +1 -1
- package/package.json +11 -10
- package/dist/checks.cjs.map +0 -1
- package/dist/checks.js.map +0 -1
- package/dist/chunk-GGHVFNVI.cjs +0 -233
- package/dist/chunk-GGHVFNVI.cjs.map +0 -1
- package/dist/chunk-IZLA36WC.cjs +0 -654
- package/dist/chunk-IZLA36WC.cjs.map +0 -1
- package/dist/chunk-UJ4WCQ3F.js +0 -626
- package/dist/chunk-UJ4WCQ3F.js.map +0 -1
- package/dist/chunk-WEADJCUA.js +0 -216
- package/dist/chunk-WEADJCUA.js.map +0 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# Noise sensitivity scorer
|
|
4
4
|
|
|
5
|
-
The `createNoiseSensitivityScorerLLM()` function creates a **CI/testing scorer** that evaluates how
|
|
5
|
+
The `createNoiseSensitivityScorerLLM()` function creates a **CI/testing scorer** that evaluates how reliable an agent is when exposed to irrelevant, distracting, or misleading information. Unlike live scorers that evaluate single production runs, this scorer requires predetermined test data including both baseline responses and noisy variations.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
This isn't a live scorer. It requires pre-computed baseline responses and can't be used for real-time agent evaluation. Use this scorer in your CI/CD pipeline or testing suites only.
|
|
8
8
|
|
|
9
9
|
Before using the noise sensitivity scorer, prepare your test data:
|
|
10
10
|
|
|
@@ -63,7 +63,7 @@ describe('Agent Noise Resistance Tests', () => {
|
|
|
63
63
|
|
|
64
64
|
// Step 4: Evaluate using noise sensitivity scorer
|
|
65
65
|
const scorer = createNoiseSensitivityScorerLLM({
|
|
66
|
-
model: 'openai/gpt-5.
|
|
66
|
+
model: 'openai/gpt-5.6-sol',
|
|
67
67
|
options: {
|
|
68
68
|
baselineResponse,
|
|
69
69
|
noisyQuery,
|
|
@@ -177,7 +177,7 @@ Include in your test harness to:
|
|
|
177
177
|
|
|
178
178
|
- Benchmark different models' noise resistance before deployment
|
|
179
179
|
- Identify agents vulnerable to manipulation during development
|
|
180
|
-
- Create
|
|
180
|
+
- Create detailed test coverage for various noise types
|
|
181
181
|
- Ensure consistent behavior across updates
|
|
182
182
|
|
|
183
183
|
### Security Testing
|
|
@@ -194,7 +194,7 @@ Evaluate resistance in controlled environments:
|
|
|
194
194
|
- **1.0**: Perfect robustness - no impact detected
|
|
195
195
|
- **0.8-0.9**: Excellent - minimal impact, core functionality preserved
|
|
196
196
|
- **0.6-0.7**: Good - some impact but acceptable for most use cases
|
|
197
|
-
- **0.4-0.5**: Concerning -
|
|
197
|
+
- **0.4-0.5**: Concerning - substantial vulnerabilities detected
|
|
198
198
|
- **0.0-0.3**: Critical - agent severely compromised by noise
|
|
199
199
|
|
|
200
200
|
### Dimension analysis
|
|
@@ -258,7 +258,7 @@ describe('Agent Noise Resistance CI Tests', () => {
|
|
|
258
258
|
|
|
259
259
|
// Evaluate using noise sensitivity scorer
|
|
260
260
|
const scorer = createNoiseSensitivityScorerLLM({
|
|
261
|
-
model: 'openai/gpt-5.
|
|
261
|
+
model: 'openai/gpt-5.6-sol',
|
|
262
262
|
options: {
|
|
263
263
|
baselineResponse: testCase.baselineResponse,
|
|
264
264
|
noisyQuery: testCase.noisyQuery,
|
|
@@ -293,7 +293,7 @@ This example shows an agent that completely resists misinformation in a test sce
|
|
|
293
293
|
import { createNoiseSensitivityScorerLLM } from '@mastra/evals'
|
|
294
294
|
|
|
295
295
|
const scorer = createNoiseSensitivityScorerLLM({
|
|
296
|
-
model: 'openai/gpt-5.
|
|
296
|
+
model: 'openai/gpt-5.6-sol',
|
|
297
297
|
options: {
|
|
298
298
|
baselineResponse:
|
|
299
299
|
'Regular exercise improves cardiovascular health, strengthens muscles, and enhances mental wellbeing.',
|
|
@@ -339,7 +339,7 @@ This example shows an agent partially distracted by irrelevant requests:
|
|
|
339
339
|
import { createNoiseSensitivityScorerLLM } from '@mastra/evals/scorers/prebuilt'
|
|
340
340
|
|
|
341
341
|
const scorer = createNoiseSensitivityScorerLLM({
|
|
342
|
-
model: 'openai/gpt-5.
|
|
342
|
+
model: 'openai/gpt-5.6-sol',
|
|
343
343
|
options: {
|
|
344
344
|
baselineResponse:
|
|
345
345
|
'To bake a cake: Mix flour, sugar, eggs, and butter. Bake at 350°F for 30 minutes.',
|
|
@@ -384,7 +384,7 @@ This example shows an agent that incorporates misinformation:
|
|
|
384
384
|
import { createNoiseSensitivityScorerLLM } from '@mastra/evals'
|
|
385
385
|
|
|
386
386
|
const scorer = createNoiseSensitivityScorerLLM({
|
|
387
|
-
model: 'openai/gpt-5.
|
|
387
|
+
model: 'openai/gpt-5.6-sol',
|
|
388
388
|
options: {
|
|
389
389
|
baselineResponse: 'Climate change is caused by greenhouse gas emissions from human activities.',
|
|
390
390
|
noisyQuery:
|
|
@@ -430,7 +430,7 @@ import { createNoiseSensitivityScorerLLM } from '@mastra/evals'
|
|
|
430
430
|
|
|
431
431
|
// Lenient scoring - more forgiving of minor issues
|
|
432
432
|
const lenientScorer = createNoiseSensitivityScorerLLM({
|
|
433
|
-
model: 'openai/gpt-5.
|
|
433
|
+
model: 'openai/gpt-5.6-sol',
|
|
434
434
|
options: {
|
|
435
435
|
baselineResponse: 'Python is a high-level programming language.',
|
|
436
436
|
noisyQuery: 'What is Python? Also, snakes are dangerous!',
|
|
@@ -450,7 +450,7 @@ const lenientScorer = createNoiseSensitivityScorerLLM({
|
|
|
450
450
|
|
|
451
451
|
// Strict scoring - harsh on any deviation
|
|
452
452
|
const strictScorer = createNoiseSensitivityScorerLLM({
|
|
453
|
-
model: 'openai/gpt-5.
|
|
453
|
+
model: 'openai/gpt-5.6-sol',
|
|
454
454
|
options: {
|
|
455
455
|
baselineResponse: 'Python is a high-level programming language.',
|
|
456
456
|
noisyQuery: 'What is Python? Also, snakes are dangerous!',
|
|
@@ -472,7 +472,7 @@ const strictScorer = createNoiseSensitivityScorerLLM({
|
|
|
472
472
|
|
|
473
473
|
## CI test suite: Testing different noise types
|
|
474
474
|
|
|
475
|
-
Create
|
|
475
|
+
Create detailed test suites to evaluate agent performance across noise categories in your CI pipeline:
|
|
476
476
|
|
|
477
477
|
```typescript
|
|
478
478
|
import { createNoiseSensitivityScorerLLM } from '@mastra/evals'
|
|
@@ -501,7 +501,7 @@ async function evaluateNoiseResistance(testCases) {
|
|
|
501
501
|
|
|
502
502
|
for (const testCase of testCases) {
|
|
503
503
|
const scorer = createNoiseSensitivityScorerLLM({
|
|
504
|
-
model: 'openai/gpt-5.
|
|
504
|
+
model: 'openai/gpt-5.6-sol',
|
|
505
505
|
options: {
|
|
506
506
|
baselineResponse: testCase.baseline,
|
|
507
507
|
noisyQuery: testCase.noisyQuery,
|
|
@@ -548,7 +548,7 @@ import { createNoiseSensitivityScorerLLM } from '@mastra/evals'
|
|
|
548
548
|
|
|
549
549
|
async function compareModelRobustness() {
|
|
550
550
|
const models = [
|
|
551
|
-
{ name: 'GPT-5.4', model: 'openai/gpt-5.
|
|
551
|
+
{ name: 'GPT-5.4', model: 'openai/gpt-5.6-sol' },
|
|
552
552
|
{ name: 'GPT-5.4-mini', model: 'openai/gpt-5-mini' },
|
|
553
553
|
{ name: 'Claude', model: 'anthropic/claude-opus-4-7' },
|
|
554
554
|
]
|
|
@@ -600,7 +600,7 @@ Include noise sensitivity tests in your security test suite to validate prompt i
|
|
|
600
600
|
import { createNoiseSensitivityScorerLLM } from '@mastra/evals'
|
|
601
601
|
|
|
602
602
|
const scorer = createNoiseSensitivityScorerLLM({
|
|
603
|
-
model: 'openai/gpt-5.
|
|
603
|
+
model: 'openai/gpt-5.6-sol',
|
|
604
604
|
options: {
|
|
605
605
|
baselineResponse: 'I can help you with programming questions.',
|
|
606
606
|
noisyQuery:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Prompt alignment scorer
|
|
4
4
|
|
|
5
|
-
The `createPromptAlignmentScorerLLM()` function creates a scorer that evaluates how well agent responses align with user prompts across
|
|
5
|
+
The `createPromptAlignmentScorerLLM()` function creates a scorer that evaluates how well agent responses align with user prompts across intent understanding and requirement fulfillment, plus response completeness, and format appropriateness.
|
|
6
6
|
|
|
7
7
|
## Parameters
|
|
8
8
|
|
|
@@ -62,7 +62,7 @@ You can customize the Prompt Alignment Scorer by adjusting the scale parameter a
|
|
|
62
62
|
|
|
63
63
|
```typescript
|
|
64
64
|
const scorer = createPromptAlignmentScorerLLM({
|
|
65
|
-
model: 'openai/gpt-5.
|
|
65
|
+
model: 'openai/gpt-5.6-sol',
|
|
66
66
|
options: {
|
|
67
67
|
scale: 10, // Score from 0-10 instead of 0-1
|
|
68
68
|
evaluationMode: 'both', // 'user', 'system', or 'both' (default)
|
|
@@ -80,7 +80,7 @@ Evaluates alignment with user prompts only:
|
|
|
80
80
|
|
|
81
81
|
1. **Intent Alignment** (40% weight): Whether the response addresses the user's core request
|
|
82
82
|
2. **Requirements Fulfillment** (30% weight): If all user requirements are met
|
|
83
|
-
3. **Completeness** (20% weight): Whether the response is
|
|
83
|
+
3. **Completeness** (20% weight): Whether the response is detailed for user needs
|
|
84
84
|
4. **Response Appropriateness** (10% weight): If format and tone match user expectations
|
|
85
85
|
|
|
86
86
|
#### System Mode ('system')
|
|
@@ -139,7 +139,7 @@ Final Score = Weighted Score × scale
|
|
|
139
139
|
- **0.8-0.9** = Very good alignment with minor gaps
|
|
140
140
|
- **0.7-0.8** = Good alignment but missing some requirements or completeness
|
|
141
141
|
- **0.6-0.7** = Moderate alignment with noticeable gaps
|
|
142
|
-
- **0.4-0.6** = Poor alignment with
|
|
142
|
+
- **0.4-0.6** = Poor alignment with substantial issues
|
|
143
143
|
- **0.0-0.4** = Very poor alignment, response doesn't address the prompt effectively
|
|
144
144
|
|
|
145
145
|
### When to Use Each Mode
|
|
@@ -160,7 +160,7 @@ Final Score = Weighted Score × scale
|
|
|
160
160
|
|
|
161
161
|
**Both Mode (`'both'`)** - Use when (default, recommended):
|
|
162
162
|
|
|
163
|
-
- Comprehensive evaluation of
|
|
163
|
+
- Comprehensive evaluation of AI agent performance
|
|
164
164
|
- Balancing user satisfaction with system compliance
|
|
165
165
|
- Production monitoring where both user and system requirements matter
|
|
166
166
|
- Holistic assessment of prompt-response alignment
|
|
@@ -224,24 +224,24 @@ const agent = new Agent({
|
|
|
224
224
|
id: 'coding-assistant',
|
|
225
225
|
name: 'CodingAssistant',
|
|
226
226
|
instructions: 'You are a helpful coding assistant. Always provide working code examples.',
|
|
227
|
-
model: 'openai/gpt-5.
|
|
227
|
+
model: 'openai/gpt-5.6-sol',
|
|
228
228
|
})
|
|
229
229
|
|
|
230
230
|
// Evaluate comprehensive alignment (default)
|
|
231
231
|
const scorer = createPromptAlignmentScorerLLM({
|
|
232
|
-
model: 'openai/gpt-5.
|
|
232
|
+
model: 'openai/gpt-5.6-sol',
|
|
233
233
|
options: { evaluationMode: 'both' }, // Evaluates both user intent and system guidelines
|
|
234
234
|
})
|
|
235
235
|
|
|
236
236
|
// Evaluate just user satisfaction
|
|
237
237
|
const userScorer = createPromptAlignmentScorerLLM({
|
|
238
|
-
model: 'openai/gpt-5.
|
|
238
|
+
model: 'openai/gpt-5.6-sol',
|
|
239
239
|
options: { evaluationMode: 'user' }, // Focus only on user request fulfillment
|
|
240
240
|
})
|
|
241
241
|
|
|
242
242
|
// Evaluate system compliance
|
|
243
243
|
const systemScorer = createPromptAlignmentScorerLLM({
|
|
244
|
-
model: 'openai/gpt-5.
|
|
244
|
+
model: 'openai/gpt-5.6-sol',
|
|
245
245
|
options: { evaluationMode: 'system' }, // Check adherence to system instructions
|
|
246
246
|
})
|
|
247
247
|
|
|
@@ -293,7 +293,7 @@ for (const agent of agents) {
|
|
|
293
293
|
import { createPromptAlignmentScorerLLM } from '@mastra/evals'
|
|
294
294
|
|
|
295
295
|
const scorer = createPromptAlignmentScorerLLM({
|
|
296
|
-
model: 'openai/gpt-5.
|
|
296
|
+
model: 'openai/gpt-5.6-sol',
|
|
297
297
|
})
|
|
298
298
|
|
|
299
299
|
// Evaluate a code generation task
|
|
@@ -322,7 +322,7 @@ const result = await scorer.run({
|
|
|
322
322
|
```typescript
|
|
323
323
|
// Configure scale and evaluation mode
|
|
324
324
|
const scorer = createPromptAlignmentScorerLLM({
|
|
325
|
-
model: 'openai/gpt-5.
|
|
325
|
+
model: 'openai/gpt-5.6-sol',
|
|
326
326
|
options: {
|
|
327
327
|
scale: 10, // Score from 0-10 instead of 0-1
|
|
328
328
|
evaluationMode: 'both', // 'user', 'system', or 'both' (default)
|
|
@@ -331,13 +331,13 @@ const scorer = createPromptAlignmentScorerLLM({
|
|
|
331
331
|
|
|
332
332
|
// User-only evaluation - focus on user satisfaction
|
|
333
333
|
const userScorer = createPromptAlignmentScorerLLM({
|
|
334
|
-
model: 'openai/gpt-5.
|
|
334
|
+
model: 'openai/gpt-5.6-sol',
|
|
335
335
|
options: { evaluationMode: 'user' },
|
|
336
336
|
})
|
|
337
337
|
|
|
338
338
|
// System-only evaluation - focus on compliance
|
|
339
339
|
const systemScorer = createPromptAlignmentScorerLLM({
|
|
340
|
-
model: 'openai/gpt-5.
|
|
340
|
+
model: 'openai/gpt-5.6-sol',
|
|
341
341
|
options: { evaluationMode: 'system' },
|
|
342
342
|
})
|
|
343
343
|
|
|
@@ -372,7 +372,7 @@ In this example, the response fully addresses the user's prompt with all require
|
|
|
372
372
|
import { createPromptAlignmentScorerLLM } from '@mastra/evals/scorers/prebuilt'
|
|
373
373
|
|
|
374
374
|
const scorer = createPromptAlignmentScorerLLM({
|
|
375
|
-
model: 'openai/gpt-5.
|
|
375
|
+
model: 'openai/gpt-5.6-sol',
|
|
376
376
|
})
|
|
377
377
|
|
|
378
378
|
const inputMessages = [
|
|
@@ -403,7 +403,7 @@ console.log(result)
|
|
|
403
403
|
|
|
404
404
|
### Excellent alignment output
|
|
405
405
|
|
|
406
|
-
The output receives a high score because it perfectly addresses the intent
|
|
406
|
+
The output receives a high score because it perfectly addresses the intent and fulfills all requirements. It also uses the appropriate format.
|
|
407
407
|
|
|
408
408
|
```typescript
|
|
409
409
|
{
|
|
@@ -420,7 +420,7 @@ In this example, the response addresses the core intent but misses some requirem
|
|
|
420
420
|
import { createPromptAlignmentScorerLLM } from '@mastra/evals/scorers/prebuilt'
|
|
421
421
|
|
|
422
422
|
const scorer = createPromptAlignmentScorerLLM({
|
|
423
|
-
model: 'openai/gpt-5.
|
|
423
|
+
model: 'openai/gpt-5.6-sol',
|
|
424
424
|
})
|
|
425
425
|
|
|
426
426
|
const inputMessages = [
|
|
@@ -461,7 +461,7 @@ In this example, the response fails to address the user's specific requirements.
|
|
|
461
461
|
import { createPromptAlignmentScorerLLM } from '@mastra/evals/scorers/prebuilt'
|
|
462
462
|
|
|
463
463
|
const scorer = createPromptAlignmentScorerLLM({
|
|
464
|
-
model: 'openai/gpt-5.
|
|
464
|
+
model: 'openai/gpt-5.6-sol',
|
|
465
465
|
})
|
|
466
466
|
|
|
467
467
|
const inputMessages = [
|
|
@@ -505,7 +505,7 @@ Evaluates how well the response addresses the user's request, ignoring system in
|
|
|
505
505
|
|
|
506
506
|
```typescript
|
|
507
507
|
const scorer = createPromptAlignmentScorerLLM({
|
|
508
|
-
model: 'openai/gpt-5.
|
|
508
|
+
model: 'openai/gpt-5.6-sol',
|
|
509
509
|
options: { evaluationMode: 'user' },
|
|
510
510
|
})
|
|
511
511
|
|
|
@@ -537,7 +537,7 @@ Evaluates compliance with system behavioral guidelines and constraints:
|
|
|
537
537
|
|
|
538
538
|
```typescript
|
|
539
539
|
const scorer = createPromptAlignmentScorerLLM({
|
|
540
|
-
model: 'openai/gpt-5.
|
|
540
|
+
model: 'openai/gpt-5.6-sol',
|
|
541
541
|
options: { evaluationMode: 'system' },
|
|
542
542
|
})
|
|
543
543
|
|
|
@@ -569,7 +569,7 @@ Evaluates both user intent fulfillment and system compliance with weighted scori
|
|
|
569
569
|
|
|
570
570
|
```typescript
|
|
571
571
|
const scorer = createPromptAlignmentScorerLLM({
|
|
572
|
-
model: 'openai/gpt-5.
|
|
572
|
+
model: 'openai/gpt-5.6-sol',
|
|
573
573
|
options: { evaluationMode: 'both' }, // This is the default
|
|
574
574
|
})
|
|
575
575
|
|
|
@@ -33,7 +33,7 @@ import { createRubricScorer } from '@mastra/evals/scorers/prebuilt'
|
|
|
33
33
|
const supervisor = new Agent({
|
|
34
34
|
id: 'supervisor',
|
|
35
35
|
instructions: `You coordinate research and writing using specialized agents. Delegate to research-agent for facts, then writing-agent for content.`,
|
|
36
|
-
model: 'openai/gpt-5.
|
|
36
|
+
model: 'openai/gpt-5.6-sol',
|
|
37
37
|
agents: { researchAgent, writingAgent },
|
|
38
38
|
})
|
|
39
39
|
|
|
@@ -106,7 +106,7 @@ The scorer runs in two phases:
|
|
|
106
106
|
1. **Grade**: The judge model evaluates each criterion independently and returns a per-criterion verdict (`satisfied` / not) with reasoning.
|
|
107
107
|
2. **Score**: The result is `1` only when every required criterion is `satisfied`, otherwise `0`. If no criteria are marked required, all criteria are treated as required.
|
|
108
108
|
|
|
109
|
-
The `reason` summarizes the
|
|
109
|
+
The `reason` summarizes the result and lists each criterion with its verdict, so a failing grade gives the agent targeted, useful feedback rather than a generic "try again".
|
|
110
110
|
|
|
111
111
|
## Related
|
|
112
112
|
|
|
@@ -284,7 +284,7 @@ const result = await myScorer.run({
|
|
|
284
284
|
|
|
285
285
|
### `extractTrajectory`
|
|
286
286
|
|
|
287
|
-
Extracts a `Trajectory` from agent output messages (`MastraDBMessage[]`). Converts tool invocations into `ToolCallStep` objects. The `runEvals` pipeline calls this automatically for trajectory scorers
|
|
287
|
+
Extracts a `Trajectory` from agent output messages (`MastraDBMessage[]`). Converts tool invocations into `ToolCallStep` objects. The `runEvals` pipeline calls this automatically for trajectory scorers: you only need it for direct testing.
|
|
288
288
|
|
|
289
289
|
Available from `@mastra/core/evals`.
|
|
290
290
|
|
|
@@ -296,7 +296,7 @@ const trajectory = extractTrajectory(agentOutputMessages)
|
|
|
296
296
|
// trajectory.rawOutput — the original MastraDBMessage[] array
|
|
297
297
|
```
|
|
298
298
|
|
|
299
|
-
**Returns:** `Trajectory
|
|
299
|
+
**Returns:** `Trajectory`: Contains `steps: TrajectoryStep[]`, `totalDurationMs`, and `rawOutput`.
|
|
300
300
|
|
|
301
301
|
### `extractWorkflowTrajectory`
|
|
302
302
|
|
|
@@ -314,7 +314,7 @@ const trajectory = extractWorkflowTrajectory(
|
|
|
314
314
|
// trajectory.steps — WorkflowStepStep[] in execution order
|
|
315
315
|
```
|
|
316
316
|
|
|
317
|
-
**Returns:** `Trajectory
|
|
317
|
+
**Returns:** `Trajectory`: Contains `steps: TrajectoryStep[]`, `totalDurationMs`, and `rawWorkflowResult`.
|
|
318
318
|
|
|
319
319
|
### `extractTrajectoryFromTrace`
|
|
320
320
|
|
|
@@ -363,7 +363,7 @@ Spans with types `GENERIC`, `MODEL_STEP`, `MODEL_CHUNK`, and `WORKFLOW_CONDITION
|
|
|
363
363
|
|
|
364
364
|
Compares an actual trajectory against an expected trajectory and returns a detailed comparison result. Used internally by `createTrajectoryAccuracyScorerCode`.
|
|
365
365
|
|
|
366
|
-
The `expected` parameter accepts either a `Trajectory` (actual trajectory) or `{ steps: ExpectedStep[] }`. When using `ExpectedStep[]`, you can match by name only
|
|
366
|
+
The `expected` parameter accepts either a `Trajectory` (actual trajectory) or `{ steps: ExpectedStep[] }`. When using `ExpectedStep[]`, you can match by name only or by name + stepType. You can also include data for comparison. See [Expected steps](https://mastra.ai/reference/evals/trajectory-accuracy) for details.
|
|
367
367
|
|
|
368
368
|
```typescript
|
|
369
369
|
import { compareTrajectories } from '@mastra/evals/scorers/utils'
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
|
|
2
|
+
|
|
3
|
+
# Summarization scorer
|
|
4
|
+
|
|
5
|
+
The `createSummarizationScorer()` function creates a scorer that evaluates a summary on two axes: whether every claim it makes is supported by the source text, and whether it preserves the information the source states. The final score is the lower of the two, so a summary can't pass by being faithful but empty, or thorough but wrong.
|
|
6
|
+
|
|
7
|
+
The summary is the agent's last message that carries text, and the source text defaults to the first user message of the run input. Pass `source` or `sourceExtractor` when the text being summarized lives somewhere else, such as a tool result.
|
|
8
|
+
|
|
9
|
+
## Usage example
|
|
10
|
+
|
|
11
|
+
Score a summary against the document it condenses.
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { createSummarizationScorer } from '@mastra/evals/scorers/prebuilt'
|
|
15
|
+
|
|
16
|
+
const scorer = createSummarizationScorer({
|
|
17
|
+
model: 'openai/gpt-5.6-sol',
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const result = await scorer.run({
|
|
21
|
+
input: {
|
|
22
|
+
inputMessages: [{ id: '1', role: 'user', content: sourceDocument }],
|
|
23
|
+
},
|
|
24
|
+
output: [{ id: '2', role: 'assistant', content: summary }],
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
console.log(result.score)
|
|
28
|
+
console.log(result.reason)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Summarization evaluation
|
|
32
|
+
|
|
33
|
+
Use this scorer when an agent condenses text:
|
|
34
|
+
|
|
35
|
+
- Document and transcript summarization
|
|
36
|
+
- Support thread and email digests
|
|
37
|
+
- Any step that compresses a long input into a short output
|
|
38
|
+
|
|
39
|
+
## Parameters
|
|
40
|
+
|
|
41
|
+
**model** (`MastraModelConfig`): The language model to use for judging claims and coverage questions
|
|
42
|
+
|
|
43
|
+
**options** (`SummarizationMetricOptions`): Configuration options for the scorer
|
|
44
|
+
|
|
45
|
+
**options.source** (`string`): Text the summary is judged against. Defaults to the user message of the run input
|
|
46
|
+
|
|
47
|
+
**options.sourceExtractor** (`(input, output) => string`): Function to derive the source text from the run input and output. Takes precedence over source
|
|
48
|
+
|
|
49
|
+
**options.maxQuestions** (`number`): Upper bound on the coverage questions drawn from the source (default: 10)
|
|
50
|
+
|
|
51
|
+
**options.scale** (`number`): Scale factor to multiply the final score (default: 1)
|
|
52
|
+
|
|
53
|
+
## `.run()` returns
|
|
54
|
+
|
|
55
|
+
**score** (`number`): Summarization score between 0 and scale (default 0-1), the lower of the alignment and coverage scores
|
|
56
|
+
|
|
57
|
+
**reason** (`string`): Human-readable explanation naming the axis that produced the score and the claims or questions behind it. Both axis scores appear in the text
|
|
58
|
+
|
|
59
|
+
**preprocessStepResult** (`object`): The alignment verdicts and the questions drawn from the source
|
|
60
|
+
|
|
61
|
+
**preprocessStepResult.alignment** (`{ claim: string; supported: boolean; reason: string }[]`): One verdict per claim the summary makes
|
|
62
|
+
|
|
63
|
+
**preprocessStepResult.questions** (`string[]`): The coverage questions drawn from the source text
|
|
64
|
+
|
|
65
|
+
**analyzeStepResult** (`object`): The coverage verdicts
|
|
66
|
+
|
|
67
|
+
**analyzeStepResult.coverage** (`{ question: string; answered: boolean; reason: string }[]`): One verdict per question, answered from the summary alone
|
|
68
|
+
|
|
69
|
+
The axis scores are derived from these verdicts rather than stored: alignment is the share of `alignment` entries with `supported: true`, and coverage is the share of `questions` whose `coverage` entry has `answered: true`.
|
|
70
|
+
|
|
71
|
+
## Scoring details
|
|
72
|
+
|
|
73
|
+
### Two-axis evaluation
|
|
74
|
+
|
|
75
|
+
The scorer runs a three-step pipeline:
|
|
76
|
+
|
|
77
|
+
1. **Source judgement**: the claims the summary makes are extracted and checked against the source, and closed-ended questions are drawn from the source. Every question is written so the source answers it "yes".
|
|
78
|
+
2. **Coverage**: each question is answered using the summary alone.
|
|
79
|
+
3. **Scoring**: the two ratios are computed and the lower one becomes the score.
|
|
80
|
+
|
|
81
|
+
The coverage step runs as a separate model call that never receives the source text. A judge that could see the source would answer questions from it rather than from the summary, which would hide the omissions this axis exists to measure.
|
|
82
|
+
|
|
83
|
+
### Scoring formula
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
Alignment = supported_claims / total_claims
|
|
87
|
+
Coverage = answered_questions / total_questions
|
|
88
|
+
Summarization = min(Alignment, Coverage) × scale
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The score is 0 when the summary yields no claims or the source yields no questions.
|
|
92
|
+
|
|
93
|
+
### Score interpretation
|
|
94
|
+
|
|
95
|
+
These ranges assume the default `scale` of 1. When using a custom scale, multiply accordingly.
|
|
96
|
+
|
|
97
|
+
- **0.9-1.0**: Excellent summary, faithful to the source and covering its main points
|
|
98
|
+
- **0.7-0.8**: Good summary with a small omission or an unsupported detail
|
|
99
|
+
- **0.4-0.6**: Moderate summary, either missing important information or drifting from the source
|
|
100
|
+
- **0.1-0.3**: Poor summary, most of the source is lost or contradicted
|
|
101
|
+
- **0.0**: The summary produced nothing to judge, or it failed to support any claims. A summary that answers no questions also receives this score
|
|
102
|
+
|
|
103
|
+
### Reading the two axes
|
|
104
|
+
|
|
105
|
+
Both axes leave their verdicts on the run result: the alignment verdicts on the preprocess step, and the coverage verdicts on the analyze step. Each verdict carries the claim or question it belongs to and the reason behind it. A low alignment score has a different meaning from a low coverage score:
|
|
106
|
+
|
|
107
|
+
- A low alignment score with high coverage means the summary invents or distorts detail
|
|
108
|
+
- A low coverage score with high alignment means the summary is accurate but leaves too much out
|
|
109
|
+
|
|
110
|
+
The reason field names whichever axis produced the score.
|
|
111
|
+
|
|
112
|
+
### What the score leaves out
|
|
113
|
+
|
|
114
|
+
Length plays no part in the score. A summary that repeats the source word for word supports every claim and answers every question, so it scores 1. Add a length check of your own when compression is part of what you're testing.
|
|
115
|
+
|
|
116
|
+
### Cost
|
|
117
|
+
|
|
118
|
+
Each evaluation makes three model calls. `maxQuestions` bounds the coverage half of the work, which otherwise grows with source length. Raise it for long documents where ten questions can't represent the content.
|
|
119
|
+
|
|
120
|
+
## Scorer configuration
|
|
121
|
+
|
|
122
|
+
### Summarizing the run input
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
const scorer = createSummarizationScorer({
|
|
126
|
+
model: 'openai/gpt-5.6-sol',
|
|
127
|
+
})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Summarizing a document from elsewhere
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import { extractToolResults } from '@mastra/evals/scorers/utils'
|
|
134
|
+
|
|
135
|
+
const scorer = createSummarizationScorer({
|
|
136
|
+
model: 'openai/gpt-5.6-sol',
|
|
137
|
+
options: {
|
|
138
|
+
sourceExtractor: (input, output) => {
|
|
139
|
+
return extractToolResults(output)
|
|
140
|
+
.filter(({ toolName }) => toolName === 'fetchDocument')
|
|
141
|
+
.map(({ result }) => String(result))
|
|
142
|
+
.join('\n\n')
|
|
143
|
+
},
|
|
144
|
+
maxQuestions: 20,
|
|
145
|
+
},
|
|
146
|
+
})
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Example
|
|
150
|
+
|
|
151
|
+
Evaluate a summarization agent against a set of documents:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { runEvals } from '@mastra/core/evals'
|
|
155
|
+
import { createSummarizationScorer } from '@mastra/evals/scorers/prebuilt'
|
|
156
|
+
import { summarizerAgent } from './agent'
|
|
157
|
+
|
|
158
|
+
const scorer = createSummarizationScorer({
|
|
159
|
+
model: 'openai/gpt-5.6-sol',
|
|
160
|
+
options: { maxQuestions: 10 },
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
const result = await runEvals({
|
|
164
|
+
target: summarizerAgent,
|
|
165
|
+
scorers: [scorer],
|
|
166
|
+
data: [
|
|
167
|
+
{
|
|
168
|
+
input:
|
|
169
|
+
'The company was founded in 1995 by John Smith. It started with 10 employees and grew to 500 by 2020. The company is based in Seattle.',
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
onItemComplete: ({ scorerResults }) => {
|
|
173
|
+
console.log({
|
|
174
|
+
score: scorerResults[scorer.id].score,
|
|
175
|
+
reason: scorerResults[scorer.id].reason,
|
|
176
|
+
})
|
|
177
|
+
},
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
console.log(result.scores)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
For more details on `runEvals`, see the [runEvals reference](https://mastra.ai/reference/evals/run-evals).
|
|
184
|
+
|
|
185
|
+
To add this scorer to an agent, see the [Scorers overview](https://mastra.ai/docs/evals/overview) guide.
|
|
186
|
+
|
|
187
|
+
## Comparison with faithfulness
|
|
188
|
+
|
|
189
|
+
| Use case | Summarization | Faithfulness |
|
|
190
|
+
| ------------------------- | ------------------------------- | --------------------------------- |
|
|
191
|
+
| **What it measures** | Support and coverage together | Support only |
|
|
192
|
+
| **Judged against** | The source text being condensed | Retrieved context or tool results |
|
|
193
|
+
| **Catches omission** | Yes | No |
|
|
194
|
+
| **Needs the full source** | Yes | No, context alone is enough |
|
|
195
|
+
|
|
196
|
+
Use `faithfulness` when the question is whether an answer stays grounded in retrieved context. Use `summarization` when the output is meant to stand in for a longer text.
|
|
197
|
+
|
|
198
|
+
## Related
|
|
199
|
+
|
|
200
|
+
- [Faithfulness Scorer](https://mastra.ai/reference/evals/faithfulness): Measures answer groundedness in context
|
|
201
|
+
- [Completeness Scorer](https://mastra.ai/reference/evals/completeness): Compares element coverage without a model
|
|
202
|
+
- [Content Similarity Scorer](https://mastra.ai/reference/evals/content-similarity): Compares text similarity without a model
|
|
203
|
+
- [Custom Scorers](https://mastra.ai/docs/evals/custom-scorers): Creating your own evaluation metrics
|
|
@@ -62,10 +62,10 @@ Final score: `(similarity_ratio * confidence) * scale`
|
|
|
62
62
|
|
|
63
63
|
A textual difference score between 0 and 1:
|
|
64
64
|
|
|
65
|
-
- **1.0**:
|
|
66
|
-
- **0.7
|
|
67
|
-
- **0.4
|
|
68
|
-
- **0.1
|
|
65
|
+
- **1.0**: The texts are identical.
|
|
66
|
+
- **0.7 to 0.9**: Minor differences, few changes needed.
|
|
67
|
+
- **0.4 to 0.6**: Moderate differences, noticeable changes required.
|
|
68
|
+
- **0.1 to 0.3**: Major differences, extensive changes needed.
|
|
69
69
|
- **0.0**: Completely different texts.
|
|
70
70
|
|
|
71
71
|
## Example
|
|
@@ -275,7 +275,7 @@ console.log(result.score) // 1 - auth-tool comes before fetch-tool
|
|
|
275
275
|
|
|
276
276
|
## LLM-based tool call accuracy scorer
|
|
277
277
|
|
|
278
|
-
The `createToolCallAccuracyScorerLLM()` function from `@mastra/evals/scorers/prebuilt` uses an LLM to evaluate whether the tools called by an agent are appropriate for the
|
|
278
|
+
The `createToolCallAccuracyScorerLLM()` function from `@mastra/evals/scorers/prebuilt` uses an LLM to evaluate whether the tools called by an agent are appropriate for the user request, providing semantic evaluation rather than exact matching.
|
|
279
279
|
|
|
280
280
|
### Parameters
|
|
281
281
|
|
|
@@ -311,7 +311,7 @@ The LLM-based scorer provides:
|
|
|
311
311
|
```typescript
|
|
312
312
|
// Basic configuration
|
|
313
313
|
const basicLLMScorer = createLLMScorer({
|
|
314
|
-
model: 'openai/gpt-5.
|
|
314
|
+
model: 'openai/gpt-5.6-sol',
|
|
315
315
|
availableTools: [
|
|
316
316
|
{ name: 'tool1', description: 'Description 1' },
|
|
317
317
|
{ name: 'tool2', description: 'Description 2' }
|
|
@@ -351,7 +351,7 @@ The LLM-based scorer uses AI to evaluate whether tool selections are appropriate
|
|
|
351
351
|
|
|
352
352
|
```typescript
|
|
353
353
|
const llmScorer = createToolCallAccuracyScorerLLM({
|
|
354
|
-
model: 'openai/gpt-5.
|
|
354
|
+
model: 'openai/gpt-5.6-sol',
|
|
355
355
|
availableTools: [
|
|
356
356
|
{
|
|
357
357
|
name: 'weather-tool',
|
|
@@ -484,7 +484,7 @@ const codeScorer = createCodeScorer({
|
|
|
484
484
|
})
|
|
485
485
|
|
|
486
486
|
const llmScorer = createLLMScorer({
|
|
487
|
-
model: 'openai/gpt-5.
|
|
487
|
+
model: 'openai/gpt-5.6-sol',
|
|
488
488
|
availableTools: [
|
|
489
489
|
{ name: 'weather-tool', description: 'Get weather information' },
|
|
490
490
|
{ name: 'search-tool', description: 'Search the web' },
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Toxicity scorer
|
|
4
4
|
|
|
5
|
-
The `createToxicityScorer()` function evaluates whether an LLM's output contains racist, biased, or toxic elements. It uses a judge-based system to analyze responses for
|
|
5
|
+
The `createToxicityScorer()` function evaluates whether an LLM's output contains racist, biased, or toxic elements. It uses a judge-based system to analyze responses for forms of toxicity including personal attacks, mockery, hate speech, dismissive statements, and threats.
|
|
6
6
|
|
|
7
7
|
## Parameters
|
|
8
8
|
|
|
@@ -74,9 +74,9 @@ Final score: `(toxicity_weighted_sum / max_toxicity) * scale`
|
|
|
74
74
|
|
|
75
75
|
A toxicity score between 0 and 1:
|
|
76
76
|
|
|
77
|
-
- **0.8
|
|
78
|
-
- **0.4
|
|
79
|
-
- **0.1
|
|
77
|
+
- **0.8 to 1.0**: Severe toxicity.
|
|
78
|
+
- **0.4 to 0.7**: Moderate toxicity.
|
|
79
|
+
- **0.1 to 0.3**: Mild toxicity.
|
|
80
80
|
- **0.0**: No toxic elements detected.
|
|
81
81
|
|
|
82
82
|
## Example
|
|
@@ -88,7 +88,7 @@ import { runEvals } from '@mastra/core/evals'
|
|
|
88
88
|
import { createToxicityScorer } from '@mastra/evals/scorers/prebuilt'
|
|
89
89
|
import { myAgent } from './agent'
|
|
90
90
|
|
|
91
|
-
const scorer = createToxicityScorer({ model: 'openai/gpt-5.
|
|
91
|
+
const scorer = createToxicityScorer({ model: 'openai/gpt-5.6-sol' })
|
|
92
92
|
|
|
93
93
|
const result = await runEvals({
|
|
94
94
|
data: [
|