Skip to main content

evals-write-spec

Write LLM evaluation spec files with datasets, tasks, and evaluators using the @kbn/evals Playwright fixture. Use when authoring new eval specs, adding datasets or evaluators, or debugging evaluation test failures.

Quellinformationen

Repository
elastic/kibana
Letzte Quellaktivität
3. August 2026 um 17:06
Erkannte Sprache von SKILL.md
Englisch
Sterne
21.236
Forks
8.623

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
3 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
evals-write-spec
disable-model-invocation
true
description
Write LLM evaluation spec files with datasets, tasks, and evaluators using the @kbn/evals Playwright fixture. Use when authoring new eval specs, adding datasets or evaluators, or debugging evaluation test failures.
# Write Eval Specs ## Spec File Anatomy Eval specs use the `evaluate` Playwright fixture (not `test`). A spec file follows this structure: ```ts import { evaluate, tags, selectEvaluators, type Example, type TaskOutput } from '@kbn/evals'; evaluate.describe('Suite name', { tag: tags.serverless.observability.complete }, () => { evaluate.beforeAll(async ({ fetch, log }) => { // one-time setup: install docs, create agents, load archives }); evaluate.afterAll(async ({ fetch, log }) => { // teardown: uninstall docs, delete agents, unload archives }); evaluate('test name', async ({ executorClient, connector }) => { await executorClient.runExperiment( { datasets: [dataset], task }, evaluators ); }); }); ``` When a suite has a custom `src/evaluate.ts`, import from there instead of `@kbn/evals`: ```ts import { evaluate } from '../src/evaluate'; ``` ## Tags Every `evaluate.describe` must have a tag. Common choices: | Tag | When to use | |-----|-------------| | `tags.serverless.observability.complete` | Observability domain evals | | `tags.serverless.security.complete` | Security domain evals | | `tags.serverless.search` | Search domain evals | | `tags.stateful.classic` | Stateful-only evals | Import tags from `@kbn/scout` or `@kbn/evals` (re-exported). ## Datasets A dataset is an array of examples with typed `input`, `output` (expected), and optional `metadata`: ```ts type MyExample = Example< { question: string }, { expectedAnswer: string }, { tags?: string[] } >; const dataset = { name: 'my-dataset', description: 'What this dataset tests', examples: [ { input: { question: 'What is 2+2?' }, output: { expectedAnswer: '4' }, metadata: { tags: ['math'] }, }, ], }; ``` Keep datasets focused. For local iteration, use `--grep` to run a subset: ```bash node scripts/evals start --grep "my test name" ``` ## Tasks The `task` function receives an example and returns the output to evaluate: ```ts task: async ({ input }) => { const result = await someKibanaApi(input.question); return { answer: result.content }; } ``` Tasks can use any fixture available in the `evaluate` callback: `fetch`, `inferenceClient`, `connector`, `esClient`, `kbnClient`, or custom fixtures like `chatClient`. ## Evaluators There are two ways to provide evaluators to `runExperiment`: 1. **Inline array** -- pass evaluator objects directly (simple suites) 2. **`selectEvaluators`** -- typed wrapper that enforces `Example`/`TaskOutput` generics ### CODE Evaluators Deterministic, no LLM call. Use for binary checks: ```ts { name: 'NonEmpty', kind: 'CODE', evaluate: async ({ output }) => ({ score: output?.documents?.length > 0 ? 1 : 0, }), } ``` ### LLM-as-Judge Criteria Use `evaluators.criteria(criteriaArray)` for subjective quality checks. The judge LLM scores each criterion: ```ts evaluators.criteria([ 'The response correctly identifies the top users.', 'The response includes risk scores.', ]).evaluate({ input, output, expected, metadata }) ``` ### Correctness Analysis Compares output against expected answer: ```ts evaluators.correctnessAnalysis().evaluate({ input, output, expected, metadata }) ``` ### Groundedness Analysis Checks if output is grounded in provided context: ```ts evaluators.groundednessAnalysis().evaluate({ input, output, expected, metadata }) ``` ### Trace-Based Evaluators Available from `evaluators.traceBasedEvaluators`: - `inputTokens`, `outputTokens`, `cachedTokens` -- token usage - `toolCalls` -- number of tool calls - `latency` -- span latency in seconds These read from the tracing ES cluster and require EDOT to be running. ### RAG Evaluators For retrieval-augmented generation with ground truth: ```ts import { createPrecisionAtKEvaluator, createRecallAtKEvaluator, createF1AtKEvaluator } from '@kbn/evals'; ``` See [evaluator-patterns.md](references/evaluator-patterns.md) for full examples. ## Available Fixtures | Fixture | Scope | Description | |---------|-------|-------------| | `executorClient` | worker | Runs experiments, exports scores to ES | | `inferenceClient` | worker | Inference REST client bound to connector | | `connector` | worker | The model connector being evaluated | | `evaluationConnector` | worker | The judge connector | | `evaluators` | worker | `DefaultEvaluators` (criteria, correctness, groundedness, trace-based) | | `fetch` | worker | `HttpHandler` for Kibana API calls | | `esClient` | worker | Elasticsearch client (Scout cluster) | | `kbnClient` | worker | Kibana client with retries | | `traceEsClient` | worker | ES client for trace queries | | `evaluationsEsClient` | worker | ES client for evaluation score storage | | `log` | worker | `ToolingLog` for structured logging | | `repetitions` | worker | Number of experiment repetitions | | `config` | worker | Scout server config (hosts, auth) | ## The `evaluateDataset` Pattern For suites with many specs that share the same task + evaluator wiring, extract a reusable helper: **`src/evaluate_dataset.ts`:** ```ts import type { DefaultEvaluators, EvalsExecutorClient } from '@kbn/evals'; import type { MyChatClient } from './chat_client'; export type EvaluateDataset = (opts: { dataset: { name: string; description: string; examples: MyExample[] }; }) => Promise<void>; export function createEvaluateDataset({ chatClient, evaluators, executorClient, }: { chatClient: MyChatClient; evaluators: DefaultEvaluators; executorClient: EvalsExecutorClient; }): EvaluateDataset { return async ({ dataset }) => { await executorClient.runExperiment( { datasets: [dataset], task: async ({ input }) => { const response = await chatClient.converse({ messages: [{ message: input.question }] }); return { messages: response.messages, steps: response.steps }; }, }, [myCriteriaEvaluator, myToolCallsEvaluator] ); }; } ``` **In the spec:** ```ts import { evaluate as base } from '../src/evaluate'; import type { EvaluateDataset } from '../src/evaluate_dataset'; import { createEvaluateDataset } from '../src/evaluate_dataset'; const evaluate = base.extend<{ evaluateDataset: EvaluateDataset }, {}>({ evaluateDataset: [ ({ chatClient, evaluators, executorClient }, use) => { use(createEvaluateDataset({ chatClient, evaluators, executorClient })); }, { scope: 'test' }, ], }); evaluate.describe('My suite', { tag: tags.serverless.search }, () => { evaluate('my test', async ({ evaluateDataset }) => { await evaluateDataset({ dataset: { name: '...', description: '...', examples: [...] } }); }); }); ``` ## Setup and Teardown Use `evaluate.beforeAll` / `evaluate.afterAll` for expensive one-time operations: - **Install product docs**: POST to `/internal/product_doc_base/install` - **Create agents/rules**: Use `fetch` or `kbnClient` - **Load ES archives**: Use `esArchiver.load(archivePath)` (requires custom fixture) Always clean up in `afterAll` -- delete agents, uninstall docs, unload archives. ## Running Locally ```bash # Full interactive flow node scripts/evals start # Specify model and judge node scripts/evals start --model <connector-id> --judge <connector-id> # Filter to a specific test node scripts/evals start --grep "my test name" # Run directly (services already running) node scripts/evals run --model <connector-id> --judge <connector-id> ``` ## Common Mistakes - Forgetting the `tag` on `evaluate.describe` -- Scout validates tags at runtime. - Missing `afterAll` cleanup -- leftover agents/docs pollute subsequent runs. - Overly large datasets for local iteration -- use `--grep` to target a single `evaluate()` block. - Importing `evaluate` from `@kbn/evals` when the suite has a custom `src/evaluate.ts` -- you'll miss custom fixtures. - Using `test` instead of `evaluate` -- the `evaluate` fixture provides all the evals-specific wiring. ## References - Evaluator type examples with real code: [references/evaluator-patterns.md](references/evaluator-patterns.md) - Suite scaffolding: use the `evals-create-suite` skill
Auf GitHub ansehen