evaluation

package
v1.126.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: Apache-2.0 Imports: 37 Imported by: 0

Documentation

Overview

Package evaluation provides an evaluation framework for testing agents.

Index

Constants

View Source
const DefaultContainerRuntime = "docker"

DefaultContainerRuntime is the container runtime executable used when Config.ContainerRuntime is empty, keeping the historical Docker behavior.

View Source
const MaxTolerance = 1.0

MaxTolerance is the largest accepted --regression-tolerance. A rate cannot move by more than 1.0, so anything above it silently disables the aggregate gate — better rejected at startup than discovered when a regression sails through.

Variables

View Source
var ErrNoBaselineEvals = errors.New("baseline contains no evaluations")

ErrNoBaselineEvals reports a baseline carrying no evaluations. A gate built on one would compare against all-zero metrics and pass unconditionally.

View Source
var ErrNoCurrentEvals = errors.New("run produced no evaluations to compare")

ErrNoCurrentEvals reports a run that produced no evaluations — an --only pattern that matched nothing, for instance. There is nothing to gate on.

View Source
var ErrNothingComparable = errors.New("baseline and run share no metric or evaluation to compare")

ErrNothingComparable reports a baseline and run with no metric and no evaluation in common, so the comparison could only ever pass.

Functions

func GenerateRunName

func GenerateRunName() string

GenerateRunName creates a memorable name for an evaluation run.

func PrintComparison added in v1.126.0

func PrintComparison(out io.Writer, c Comparison)

PrintComparison writes a human-readable comparison.

func Save

func Save(sess *session.Session, filename string) (string, error)

func SaveRunJSON

func SaveRunJSON(run *EvalRun, outputDir string) (string, error)

SaveRunJSON saves the eval run results to a JSON file. This is kept for backward compatibility and debugging purposes.

func SaveRunSessions

func SaveRunSessions(ctx context.Context, run *EvalRun, outputDir string) (string, error)

SaveRunSessions saves all eval sessions to a SQLite database file. The database follows the same schema as the main session store, allowing the sessions to be loaded and inspected using standard session tools.

func SaveRunSessionsJSON

func SaveRunSessionsJSON(run *EvalRun, outputDir string) (string, error)

SaveRunSessionsJSON saves the full evaluation run output to a JSON file. The output includes run metadata (config, summary) and all sessions with their eval criteria and scoring results (pass/fail, judge reasoning, errors).

func SessionFromEvents

func SessionFromEvents(events []map[string]any, title string, questions []string) *session.Session

SessionFromEvents reconstructs a session from raw container output events. This parses the JSON events emitted by docker agent run --exec --json and builds a session with the conversation history.

Types

type Baseline added in v1.126.0

type Baseline struct {
	Name    string
	Summary Summary
	// Passed maps an evaluation's key (see evalKey) to whether it passed.
	Passed map[string]bool
}

Baseline is a previously saved run, reduced to what a regression gate needs.

It is loaded from the JSON the eval command actually writes — a RunOutput from SaveRunSessionsJSON — rather than from EvalRun, which has no producer outside tests and whose Duration field is typed incompatibly.

func LoadBaseline added in v1.126.0

func LoadBaseline(path string) (*Baseline, error)

LoadBaseline reads the run JSON the eval command writes.

A file that parses but carries no evaluations is rejected rather than treated as an empty baseline: every rate would be skipped by the has-flag guards and the gate would report success while every evaluation in the current run failed. A gate must fail closed.

type Comparison added in v1.126.0

type Comparison struct {
	Baseline  Metrics       `json:"baseline"`
	Current   Metrics       `json:"current"`
	Tolerance float64       `json:"tolerance"`
	Deltas    []MetricDelta `json:"deltas"`
	Changes   []EvalChange  `json:"changes"`
	// Regressed is true when any gating metric moved beyond the tolerance, or
	// an evaluation that passed in the baseline now fails.
	Regressed bool `json:"regressed"`
}

Comparison is the result of checking a run against a baseline.

func Compare added in v1.126.0

func Compare(baseline *Baseline, current *EvalRun, tolerance float64) (Comparison, error)

Compare checks current against baseline.

tolerance is the amount an aggregate quality rate may fall (or the failure rate may climb) before it counts as a regression, so judge variance does not fail a build on noise. A tolerance of 0 means any movement in the wrong direction regresses; a negative value is clamped to 0.

The tolerance governs aggregate rates ONLY. An evaluation that passed in the baseline and now fails gates regardless of tolerance — that transition is the exact signal this check exists to catch, and absorbing it would defeat the point. Consequently a large tolerance still cannot hide an outright breakage.

Note the corollary: adding a new FAILING evaluation lowers the aggregate rate and therefore gates, even though no existing evaluation regressed. That is intended — a suite that got worse should say so — but it means "add a known- failing eval as a TODO" needs an explicit tolerance bump or a fix.

Cost is reported but never gates: a cost increase is not a quality regression, and gating on it would make the check fire on provider price changes.

A metric absent from either run is skipped rather than treated as 0 — adding the first size expectation to a suite must not look like a regression. If that leaves nothing to gate on and no evaluation in common, an error is returned: a comparison that can only ever pass is worse than no comparison.

type Config

type Config struct {
	AgentFilename    string   // Path to the agent configuration file
	EvalsDir         string   // Directory containing evaluation files
	JudgeModel       string   // Model for relevance checking (format: provider/model, optional)
	Concurrency      int      // Number of concurrent runs (0 = number of CPUs)
	TTYFd            int      // File descriptor for terminal size queries (e.g., int(os.Stdout.Fd()))
	Only             []string // Only run evaluations matching these patterns
	BaseImage        string   // Custom base image for running evaluations
	KeepContainers   bool     // If true, don't remove containers after evaluation (skip --rm)
	EnvVars          []string // Environment variables to pass: KEY (value from env) or KEY=VALUE (explicit)
	Repeat           int      // Number of times to repeat each evaluation (default 1)
	ContainerRuntime string   // Docker-compatible container runtime executable (default "docker")
}

Config holds configuration for evaluation runs.

type EvalChange added in v1.126.0

type EvalChange struct {
	Eval string `json:"eval"`
	// Was and Now are "pass", "fail", or "absent".
	Was       string `json:"was"`
	Now       string `json:"now"`
	Regressed bool   `json:"regressed"`
}

EvalChange records one evaluation's pass/fail transition between runs.

type EvalRun

type EvalRun struct {
	Name      string        `json:"name"`
	Timestamp time.Time     `json:"timestamp"`
	Duration  time.Duration `json:"duration"`
	Config    Config        `json:"-"` // Used to build RunOutput, not serialized directly
	Results   []Result      `json:"results"`
	Summary   Summary       `json:"summary"`
}

EvalRun contains the results and metadata for an evaluation run.

func Evaluate

func Evaluate(ctx context.Context, ttyOut, out io.Writer, isTTY bool, runName string, runConfig *config.RuntimeConfig, cfg Config) (*EvalRun, error)

Evaluate runs evaluations with a specified run name. ttyOut is used for progress bar rendering (should be the console/TTY). out is used for results and status messages (can be tee'd to a log file).

type InputSession

type InputSession struct {
	*session.Session

	SourcePath  string // Path to the source eval file (not serialized)
	RepeatIndex int    // Repeat iteration (1-based); 0 means no repeat
}

InputSession wraps a session with its source path for evaluation loading.

type Judge

type Judge struct {
	// contains filtered or unexported fields
}

Judge runs LLM-as-a-judge relevance checks concurrently.

func NewJudge

func NewJudge(model provider.Provider, concurrency int) *Judge

NewJudge creates a new Judge that runs relevance checks with the given concurrency. Concurrency defaults to 1 if n < 1.

func (*Judge) CheckRelevance

func (j *Judge) CheckRelevance(ctx context.Context, response string, criteria []string) (results []RelevanceResult, err error)

CheckRelevance runs all relevance checks concurrently with the configured concurrency. It returns a result for every criterion (both passed and failed, each with a reason from the judge model), and an error if any check encountered an error (e.g. judge model misconfiguration). Errors cause a hard failure so that configuration issues are surfaced immediately rather than silently producing zero-relevance results.

func (*Judge) Validate added in v1.32.4

func (j *Judge) Validate(ctx context.Context) error

Validate performs an end-to-end check of the judge model by sending a trivial relevance prompt and verifying the response is valid structured JSON. This catches configuration errors (bad API key, unsupported model, missing structured-output support, etc.) before running any evaluations, allowing the framework to fail fast.

type MetricDelta added in v1.126.0

type MetricDelta struct {
	Name      string  `json:"name"`
	Baseline  float64 `json:"baseline"`
	Current   float64 `json:"current"`
	Delta     float64 `json:"delta"`
	Regressed bool    `json:"regressed"`
	// Informational marks a metric that is reported but never gates, so a
	// reviewer can see it moved without the build failing over it.
	Informational bool `json:"informational,omitempty"`
}

MetricDelta is one metric's movement between two runs. Higher is better for quality rates and worse for FailureRate, so Regressed — not the sign of Delta — is what a gate reads.

type Metrics added in v1.126.0

type Metrics struct {
	TotalEvals  int     `json:"total_evals"`
	FailedEvals int     `json:"failed_evals"`
	FailureRate float64 `json:"failure_rate"`

	SizePassRate float64 `json:"size_pass_rate"`
	HasSizes     bool    `json:"has_sizes"`

	ToolsF1Mean float64 `json:"tools_f1_mean"`
	HasTools    bool    `json:"has_tools"`

	RelevanceRate float64 `json:"relevance_rate"`
	HasRelevance  bool    `json:"has_relevance"`

	TotalCost float64 `json:"total_cost"`
}

Metrics is the comparable shape of an evaluation run: the rates a regression gate can be built on, derived from the same Summary the run prints.

Rates are 0 when their denominator is 0, and the corresponding Has… flag says whether the rate means anything. Without that distinction "no size expectations declared" and "every size expectation failed" would both read as 0.0 and a gate could not tell them apart.

func MetricsOf added in v1.126.0

func MetricsOf(run *EvalRun) Metrics

MetricsOf derives Metrics from a run's results.

type RelevanceResult

type RelevanceResult struct {
	Criterion string `json:"criterion"`
	Passed    bool   `json:"passed"`
	Reason    string `json:"reason"`
}

RelevanceResult contains the result of a single relevance check.

type Result

type Result struct {
	InputPath         string            `json:"input_path"`
	Title             string            `json:"title"`
	Question          string            `json:"question"`
	Response          string            `json:"response"`
	Cost              float64           `json:"cost"`
	OutputTokens      int64             `json:"output_tokens"`
	Size              string            `json:"size"`
	SizeExpected      string            `json:"size_expected"`
	ToolCallsScore    float64           `json:"tool_calls_score"`
	ToolCallsExpected float64           `json:"tool_calls_score_expected"`
	RelevancePassed   float64           `json:"relevance"`
	RelevanceExpected float64           `json:"relevance_expected"`
	RelevanceResults  []RelevanceResult `json:"relevance_results,omitempty"`
	Error             string            `json:"error,omitempty"`
	RawOutput         []map[string]any  `json:"raw_output,omitempty"`
	Session           *session.Session  `json:"-"` // Full session for database storage (not in JSON)
}

Result contains the evaluation results for a single test case.

type RunOutput added in v1.42.0

type RunOutput struct {
	Name      string             `json:"name"`
	Timestamp time.Time          `json:"timestamp"`
	Duration  string             `json:"duration"`
	Config    RunOutputConfig    `json:"config"`
	Summary   Summary            `json:"summary"`
	Sessions  []*session.Session `json:"sessions"`
}

RunOutput is the top-level structure for the evaluation run JSON output.

type RunOutputConfig added in v1.42.0

type RunOutputConfig struct {
	Agent            string `json:"agent"`
	JudgeModel       string `json:"judge_model,omitempty"`
	Concurrency      int    `json:"concurrency"`
	EvalsDir         string `json:"evals_dir"`
	BaseImage        string `json:"base_image,omitempty"`
	ContainerRuntime string `json:"container_runtime,omitempty"`
}

RunOutputConfig captures the evaluation run configuration.

type Runner

type Runner struct {
	Config
	// contains filtered or unexported fields
}

Runner runs evaluations against an agent.

func (*Runner) Run

func (r *Runner) Run(ctx context.Context, ttyOut, out io.Writer, isTTY bool) ([]Result, error)

Run executes all evaluations concurrently and returns results. ttyOut is used for progress bar rendering (should be the console/TTY). out is used for results and status messages (can be tee'd to a log file).

type Summary

type Summary struct {
	TotalEvals      int     `json:"total_evals"`
	FailedEvals     int     `json:"failed_evals"`
	TotalCost       float64 `json:"total_cost"`
	SizesPassed     int     `json:"sizes_passed"`
	SizesTotal      int     `json:"sizes_total"`
	ToolsF1Sum      float64 `json:"tools_f1_sum"`
	ToolsCount      int     `json:"tools_count"`
	RelevancePassed float64 `json:"relevance_passed"`
	RelevanceTotal  float64 `json:"relevance_total"`
}

Summary contains aggregate statistics across all evaluations.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL