Documentation
¶
Overview ¶
Package evalgo is a small, native-Go LLM evaluation framework.
Philosophy (vs. Python's DeepEval/RAGAS): extend Go's strengths — concurrency, determinism, zero-cost heuristics, and `go test` — instead of importing a heavy framework. Metrics split into two families:
- Deterministic (code-based): JSON/regex/contains/exact — fast, free, no LLM.
- Semantic (LLM-as-a-judge): rubric, faithfulness, answer relevancy, context precision — capture intent via a Judge.
The core package has zero third-party dependencies (stdlib only). The agent-go judge adapter lives in the sibling package ./llmjudge so library users who only want deterministic metrics pay no dependency cost.
Example ¶
Example shows Eval-Go used as a library: build a Suite of deterministic metrics over an in-memory golden set and inspect the aggregated report. (Semantic metrics additionally take a judge — see package llmjudge.)
package main
import (
"context"
"fmt"
evalgo "github.com/liliang-cn/eval-go"
)
func main() {
suite := evalgo.Suite{
Metrics: []evalgo.Metric{
evalgo.ValidJSON(),
evalgo.JSONHasFields("name", "age"),
},
Samples: []evalgo.Sample{
{Name: "ok", Output: `{"name":"Jane","age":30}`},
{Name: "missing-age", Output: `{"name":"Jane"}`},
},
}
report := suite.Run(context.Background())
for _, ms := range report.Summary() {
fmt.Printf("%s: %d/%d passed\n", ms.Metric, ms.Passed, ms.Total)
}
fmt.Println("failed:", report.Failed())
}
Output: json_has_fields: 1/2 passed valid_json: 2/2 passed failed: true
Index ¶
- Variables
- func AttackKinds() []string
- func EstimateTokens(s string) int
- func RegisteredMetrics() []string
- func RunT(t *testing.T, s Suite)
- type AlignmentReport
- type AlignmentResult
- type AttackKind
- type Bench
- type ChangeStatus
- type Comparison
- type ComparisonReport
- type DAGNode
- type Diff
- type Disagreement
- type ExecTarget
- type ExecTargetSpec
- type JudgeFunc
- type Meter
- type Metric
- func AnswerRelevancy(judge JudgeFunc, passThreshold float64) Metric
- func ArgumentCorrectness(judge JudgeFunc, passThreshold float64) Metric
- func AttackResistance(judge JudgeFunc, passThreshold float64) Metric
- func Bias(judge JudgeFunc, passThreshold float64) Metric
- func BuildMetrics(names []string, spec MetricSpec) ([]Metric, error)
- func CitationPresent() Metric
- func Contains(substr string) Metric
- func ContextualPrecision(judge JudgeFunc, passThreshold float64) Metric
- func ContextualRecall(judge JudgeFunc, passThreshold float64) Metric
- func ContextualRelevancy(judge JudgeFunc, passThreshold float64) Metric
- func ConversationCompleteness(judge JudgeFunc, passThreshold float64) Metric
- func ConversationRelevancy(judge JudgeFunc, passThreshold float64) Metric
- func DAG(judge JudgeFunc, name string, passThreshold float64, root DAGNode) Metric
- func ExactMatch() Metric
- func Faithfulness(judge JudgeFunc) Metric
- func ForbidsRegex(pattern string) Metric
- func Hallucination(judge JudgeFunc, passThreshold float64) Metric
- func JSONHasFields(fields ...string) Metric
- func KnowledgeRetention(judge JudgeFunc, passThreshold float64) Metric
- func MatchesRegex(pattern string) Metric
- func NonEmpty() Metric
- func PIILeakage(judge JudgeFunc) Metric
- func PlanAdherence(judge JudgeFunc, passThreshold float64) Metric
- func PlanQuality(judge JudgeFunc, passThreshold float64) Metric
- func RefusalPresent() Metric
- func RoleAdherence(judge JudgeFunc, passThreshold float64) Metric
- func RubricJudge(judge JudgeFunc, passThreshold float64) Metric
- func StepEfficiency(judge JudgeFunc, passThreshold float64) Metric
- func Summarization(judge JudgeFunc, passThreshold float64) Metric
- func TaskCompletion(judge JudgeFunc, passThreshold float64) Metric
- func ToolCorrectness() Metric
- func Toxicity(judge JudgeFunc, passThreshold float64) Metric
- func ValidJSON() Metric
- type MetricFunc
- type MetricSpec
- type MetricSummary
- type NamedTarget
- type RedTeam
- type Report
- type Result
- type RunOutput
- type Runner
- type Sample
- type SampleReport
- type ScoreDelta
- type Suite
- type Synthesizer
- type Target
- type TargetFunc
- type TargetReport
- type Task
- type ToolCall
- type Turn
- type Usage
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var AllAttackKinds = []AttackKind{PromptInjection, Jailbreak, PIIExtraction, HarmfulRequest}
AllAttackKinds is the default set probed when none is specified.
var ErrNoLabels = errors.New("no samples carry a label for this metric")
ErrNoLabels is returned by AlignMetric when no sample in the set carries a human label for the metric — so the caller can skip it cleanly.
Functions ¶
func AttackKinds ¶ added in v0.2.0
func AttackKinds() []string
AttackKinds returns the known attack-kind names, for CLI help and validation.
func EstimateTokens ¶ added in v0.2.0
EstimateTokens approximates BPE token count as ~4 characters per token — a rough, model-agnostic heuristic (no tokenizer dependency, keeps the core stdlib-only). Use it for relative comparison and ballpark cost, not billing.
func RegisteredMetrics ¶
func RegisteredMetrics() []string
RegisteredMetrics returns the metric names known to BuildMetrics, sorted.
func RunT ¶
RunT drives a Suite through Go's native test runner: one subtest per sample, executed with t.Parallel() so hundreds of rows evaluate concurrently. Failed metrics become t.Error, so `go test` exit codes and CI reporting work for free.
func TestRAG(t *testing.T) {
if os.Getenv("RUN_EVALS") != "true" { t.Skip("set RUN_EVALS=true") }
evalgo.RunT(t, suite)
}
Types ¶
type AlignmentReport ¶ added in v0.3.0
type AlignmentReport []AlignmentResult
AlignmentReport is the alignment of several metrics, ready to write or gate.
func (AlignmentReport) Failing ¶ added in v0.3.0
func (a AlignmentReport) Failing(minKappa, minF1 float64) []string
Failing returns the metrics whose Kappa < minKappa or F1 < minF1. A floor of 0 disables that check. Use as the CI gate on judge quality.
func (AlignmentReport) WriteConsole ¶ added in v0.3.0
func (a AlignmentReport) WriteConsole(w io.Writer, maxDisagreements int)
WriteConsole emits a human-readable per-metric agreement summary, with up to maxDisagreements example mismatches per metric (0 = none).
type AlignmentResult ¶ added in v0.3.0
type AlignmentResult struct {
Metric string `json:"metric"`
N int `json:"n"` // labeled samples successfully scored
Errored int `json:"errored"` // labeled samples the judge errored on (excluded from N)
// binary agreement — confusion matrix
TP int `json:"tp"`
FP int `json:"fp"`
TN int `json:"tn"`
FN int `json:"fn"`
Accuracy float64 `json:"accuracy"`
Precision float64 `json:"precision"`
Recall float64 `json:"recall"`
F1 float64 `json:"f1"`
Kappa float64 `json:"kappa"` // Cohen's kappa (chance-corrected agreement)
// continuous agreement (judge.Score vs human score)
Pearson float64 `json:"pearson"`
Spearman float64 `json:"spearman"`
MAE float64 `json:"mae"`
RMSE float64 `json:"rmse"`
// BestThreshold is the pass-threshold on judge.Score that best matches the
// human binary labels — use it to re-calibrate the metric's threshold.
BestThreshold float64 `json:"best_threshold"`
Disagreements []Disagreement `json:"disagreements,omitempty"`
}
AlignmentResult reports how well a metric's judge agrees with human labels on the labeled subset. Binary stats compare judge.Passed against (label >= 0.5); continuous stats compare judge.Score against the raw label.
func AlignMetric ¶ added in v0.3.0
func AlignMetric(ctx context.Context, samples []Sample, metric Metric, labelKey string) (AlignmentResult, error)
AlignMetric runs metric over the samples that carry a human label under labelKey (Sample.Labels[labelKey]) and measures judge-vs-human agreement. labelKey is the name the user labels by — typically the same name used to request the metric (the CLI `-m` name), which can differ from metric.Name(). It reuses Suite.Run, so the same bounded concurrency and rate-limited judge apply; it only post-processes the produced Results against the labels. Returns ErrNoLabels when the set has no labeled samples for labelKey.
type AttackKind ¶ added in v0.2.0
type AttackKind string
AttackKind is a category of adversarial probe.
const ( PromptInjection AttackKind = "prompt_injection" // override the system's instructions Jailbreak AttackKind = "jailbreak" // roleplay / persona escapes PIIExtraction AttackKind = "pii_extraction" // coax out secrets or personal data HarmfulRequest AttackKind = "harmful_request" // requests a safe system must refuse )
type Bench ¶ added in v0.4.0
type Bench struct {
Target Target
Tasks []Task
Metrics []Metric
Concurrency int
Timeout time.Duration
OnResult func(task Task, s Sample, err error)
}
Bench is the end-to-end agent-eval entrypoint: run every Task through Target to produce Samples, then score them with Metrics. Returns the scored Report and the Samples (so you can persist or inspect the raw runs).
Example ¶
ExampleBench shows the end-to-end agent-eval flow: define Tasks, plug an agent in as a Target, and let Bench run + score it. Here the Target is an in-process stub and the metrics are deterministic (no LLM judge) so the output is stable.
package main
import (
"context"
"fmt"
evalgo "github.com/liliang-cn/eval-go"
)
func main() {
// The system under test: any func that runs a Task and reports the run.
agent := evalgo.TargetFunc(func(_ context.Context, t evalgo.Task) (evalgo.RunOutput, error) {
return evalgo.RunOutput{
Output: "handled " + t.Name,
ToolCalls: []evalgo.ToolCall{{Name: "write_file"}},
}, nil
})
bench := evalgo.Bench{
Target: agent,
Tasks: []evalgo.Task{
{Name: "task-a", Input: "do A", ExpectedTools: []string{"write_file"}},
},
Metrics: []evalgo.Metric{evalgo.NonEmpty(), evalgo.ToolCorrectness()},
}
report, samples := bench.Run(context.Background())
fmt.Println("ran samples:", len(samples))
for _, sr := range report.Samples {
fmt.Printf("%s passed=%v\n", sr.Sample, sr.Passed)
}
}
Output: ran samples: 1 task-a passed=true
type ChangeStatus ¶ added in v0.2.0
type ChangeStatus string
ChangeStatus classifies one metric result's movement between two reports.
const ( Regressed ChangeStatus = "regressed" // was passing, now failing Fixed ChangeStatus = "fixed" // was failing, now passing Declined ChangeStatus = "declined" // same pass state, lower score Improved ChangeStatus = "improved" // same pass state, higher score Unchanged ChangeStatus = "unchanged" Added ChangeStatus = "added" // present only in the new report Removed ChangeStatus = "removed" // present only in the old report )
type Comparison ¶ added in v0.4.0
type Comparison struct {
Targets []NamedTarget
Tasks []Task
Metrics []Metric
Gate []string // metric names that must pass for a cell to PASS; empty = all metrics
Concurrency int
Timeout time.Duration
OnResult func(target string, task Task, s Sample, err error)
}
Comparison runs every Task through every Target and scores each run, so agents can be compared on identical tasks. Targets run sequentially (one agent at a time); a target's tasks run with Concurrency.
func (Comparison) Run ¶ added in v0.4.0
func (c Comparison) Run(ctx context.Context) ComparisonReport
Run executes the comparison and returns the full report.
type ComparisonReport ¶ added in v0.4.0
type ComparisonReport struct {
Targets []TargetReport `json:"targets"`
Gate []string `json:"gate,omitempty"`
}
ComparisonReport holds every agent's results plus the gate used to derive PASS/FAIL, and can render a task x agent grid.
func (ComparisonReport) Grid ¶ added in v0.4.0
func (cr ComparisonReport) Grid() map[string]map[string]bool
Grid returns passed[taskName][targetName] derived from the gate.
func (ComparisonReport) RenderGrid ¶ added in v0.4.0
func (cr ComparisonReport) RenderGrid(w io.Writer)
RenderGrid writes a task x agent PASS/FAIL table to w.
type DAGNode ¶ added in v0.2.0
type DAGNode interface {
// contains filtered or unexported methods
}
DAGNode is one node in a DAG metric's decision tree.
func Branch ¶ added in v0.2.0
Branch asks the judge to answer question with exactly one of the choice labels and routes to that child. If the answer matches no label, it routes to fallback; a nil fallback with no match scores 0.
type Diff ¶ added in v0.2.0
type Diff []ScoreDelta
Diff is the full comparison of two reports.
func DiffReports ¶ added in v0.2.0
DiffReports compares old vs new by (sample, metric).
func (Diff) Regressions ¶ added in v0.2.0
Regressions counts results that started passing and now fail.
func (Diff) WriteConsole ¶ added in v0.2.0
WriteConsole prints the diff, regressions first, ending with a verdict.
type Disagreement ¶ added in v0.3.0
type Disagreement struct {
Sample string `json:"sample"`
Human float64 `json:"human"` // human gold score 0..1
JudgeScore float64 `json:"judge_score"` // the judge's raw score 0..1
JudgePassed bool `json:"judge_passed"` // the judge's pass verdict
Reason string `json:"reason,omitempty"`
}
Disagreement is one labeled sample where the judge and the human disagreed (on the pass/fail boundary), surfaced for inspection.
type ExecTarget ¶ added in v0.4.0
type ExecTarget struct {
Command []string // argv, e.g. ["python", "runner.py"] or ["./agent"]
Dir string // working directory (optional)
Env map[string]string // extra environment (e.g. API keys); merged over os.Environ
}
ExecTarget drives an agent that runs as a subprocess — so eval-go can evaluate an agent written in any language. The Task is passed both as JSON on stdin and as EVAL_* environment variables; the program prints a JSON RunOutput (or a bare Sample, or a one-element array of either) to stdout.
Environment passed to the program:
EVAL_NAME, EVAL_INPUT, EVAL_RUBRIC, EVAL_EXPECTED, EVAL_EXPECTED_TOOLS (CSV), EVAL_CONTEXT (JSON array), EVAL_FILES (JSON object of seed fixtures)
type ExecTargetSpec ¶ added in v0.4.0
type ExecTargetSpec struct {
Name string `json:"name"`
Command []string `json:"command"`
Dir string `json:"dir,omitempty"`
Env map[string]string `json:"env,omitempty"`
}
ExecTargetSpec is the JSON-config form of an ExecTarget, so the agents under comparison can be declared in a file rather than in Go.
type JudgeFunc ¶
JudgeFunc executes one LLM-as-a-judge call: given a prompt, return raw text (expected to contain JSON). Wrap with RateLimit to pace provider QPS. Build one from agent-go via the sibling package ./llmjudge.
func Cache ¶ added in v0.2.0
Cache wraps a JudgeFunc so identical prompts are served from an on-disk cache instead of re-calling (and re-billing) the provider. Responses are keyed by a SHA-256 of the prompt and persisted as files under dir, so they survive across runs — a re-run of an unchanged dataset spends no tokens. Concurrency-safe.
Only successful responses are cached; errors always re-call. An empty dir disables caching (returns the judge unchanged), mirroring RateLimit.
Cache and RateLimit compose; wrap with Cache outermost so cache hits skip the rate limiter entirely: RateLimit(Cache(judge, dir), rps, burst) caches, then paces only the misses — or Cache(RateLimit(judge,...), dir) to pace nothing on a hit. The CLI uses the latter.
func RateLimit ¶
RateLimit wraps a JudgeFunc with a lazy token-bucket limiter so concurrent samples don't trigger 429 Too Many Requests from the judge provider.
rps is tokens refilled per second; burst is the bucket capacity. Production code may prefer golang.org/x/time/rate; this is an equivalent, dependency-free implementation kept in-tree to honor the framework's stdlib-only core.
type Meter ¶ added in v0.2.0
type Meter struct {
// contains filtered or unexported fields
}
Meter wraps a JudgeFunc to record usage — call count, (estimated) tokens, cumulative judge time, and optional cost — so a CI run can report what an evaluation spent. Concurrency-safe.
Wrap the Meter INSIDE the cache so cache hits aren't billed:
judge = RateLimit(judge, rps, burst) judge = meter.Wrap(judge) // counts only real provider calls judge = Cache(judge, dir) // a hit returns before reaching the meter
Token counts are heuristic (see EstimateTokens), not a provider tokenizer — good for relative comparison and rough cost, not billing-exact.
func NewMeter ¶ added in v0.2.0
NewMeter creates a Meter. costInPerM / costOutPerM are USD per 1,000,000 prompt / completion tokens; pass 0 to omit cost from the report.
type Metric ¶
Metric scores a single sample. Deterministic metrics ignore ctx; semantic metrics use it for the judge call (cancellation / deadlines).
func AnswerRelevancy ¶
AnswerRelevancy measures how much of Output actually addresses Input: extract the answer's statements, classify each as relevant to the question. Score = relevant statements / total. Catches rambling / off-topic answers.
func ArgumentCorrectness ¶ added in v0.2.0
ArgumentCorrectness asks the judge, for EACH recorded tool call, whether the arguments are correct and sufficient to accomplish the INPUT task. Score = correct calls / total. Catches right-tool-wrong-arguments failures.
func AttackResistance ¶ added in v0.2.0
AttackResistance is the headline red-team metric: given the adversarial Input and the system's Output, judge whether the system RESISTED — refused, deflected, or otherwise stayed safe — rather than complying with the attack. Pass = resisted. An empty Output is treated as a (degenerate) refusal.
func Bias ¶ added in v0.2.0
Bias decomposes Output into statements and flags any that carry bias (gender, political, racial, etc.). We score the UNBIASED fraction so higher is better: score = unbiased statements / total.
func BuildMetrics ¶
func BuildMetrics(names []string, spec MetricSpec) ([]Metric, error)
BuildMetrics resolves metric names into Metrics. It errors on an unknown name, or on a semantic metric requested without a judge — so misconfiguration fails fast instead of silently skipping evaluation.
func CitationPresent ¶
func CitationPresent() Metric
CitationPresent passes when Output contains at least one [SOURCE]-style citation — a deterministic proxy for grounded, attributable RAG answers.
func ContextualPrecision ¶
ContextualPrecision measures retrieval quality: of the Context chunks supplied, how many are actually relevant to the Input. Score = relevant chunks / total. Low precision means the retriever is surfacing noise.
func ContextualRecall ¶ added in v0.2.0
ContextualRecall measures whether the retrieved Context contains everything the reference answer needs: decompose Expected into statements, then check each can be attributed to the retrieval context. Score = attributable statements / total. Low recall means the retriever missed information the answer depends on.
func ContextualRelevancy ¶ added in v0.2.0
ContextualRelevancy measures retrieval noise: of the statements present in the retrieved Context, how many are relevant to the Input. Score = relevant statements / total. Low relevancy means the context is padded with off-topic material.
func ConversationCompleteness ¶ added in v0.2.0
ConversationCompleteness judges whether the assistant fulfilled all of the user's intentions and requests across the whole conversation.
func ConversationRelevancy ¶ added in v0.2.0
ConversationRelevancy asks the judge, for EACH assistant message, whether it is relevant given the conversation so far. Score = relevant / total.
func DAG ¶ added in v0.2.0
DAG builds a metric from a decision tree of judge questions instead of one vague 0-1 score. Each interior node asks the judge a categorical question about the Sample and routes to a child by the answer; each leaf assigns a concrete score. This makes complex pass/fail logic deterministic and explainable — the judge only makes small, local decisions (the DeepEval "DAG metric" idea).
root := YesNo("Is the OUTPUT valid JSON?",
YesNo("Does it contain a 'name' field?", Leaf(1, "ok"), Leaf(0.5, "missing name")),
Leaf(0, "not JSON"))
m := DAG(judge, "json_shape", 0.99, root)
passThreshold is the minimum leaf score (0..1) required to pass.
func ExactMatch ¶
func ExactMatch() Metric
ExactMatch passes when trimmed Output equals trimmed Expected.
func Faithfulness ¶
Faithfulness measures how grounded Output is in Context: extract the claims the answer makes, then check each against the retrieval context. Score = non-contradicted claims / total claims. Catches hallucination.
func ForbidsRegex ¶
ForbidsRegex passes when Output does NOT match the pattern — a safety boundary (no secrets, no banned phrases, no leaked PII).
func Hallucination ¶ added in v0.2.0
Hallucination treats Context as trusted source facts and checks that Output does not contradict them. We invert the usual sense so higher = MORE factually consistent, matching the rest of the framework (higher is always better).
func JSONHasFields ¶
JSONHasFields passes when Output is a JSON object containing all given keys.
func KnowledgeRetention ¶ added in v0.2.0
KnowledgeRetention judges whether the assistant RETAINED information the user already provided earlier. A low score means it asked again for facts already given, or forgot or contradicted earlier context.
func MatchesRegex ¶
MatchesRegex passes when Output matches the pattern (e.g. a required format).
func PIILeakage ¶ added in v0.2.0
PIILeakage is a single-judgment check: does Output leak personally identifiable information (names tied to data, emails, phone numbers, SSNs, credit cards, addresses)? Passes when the text is clean.
func PlanAdherence ¶ added in v0.2.0
PlanAdherence judges whether the agent's actual Trajectory followed its own Plan. Needs both a plan and a trajectory; skipped (pass) otherwise.
func PlanQuality ¶ added in v0.2.0
PlanQuality judges the agent's stated Plan for the INPUT: is it logical, complete, and efficient? Skipped (pass) when the sample carries no plan.
func RefusalPresent ¶ added in v0.2.0
func RefusalPresent() Metric
RefusalPresent is a deterministic proxy for attack resistance: the Output contains refusal/deflection language. Free and offline — a cheap first gate before spending a judge call on attack_resistance.
func RoleAdherence ¶ added in v0.2.0
RoleAdherence judges whether the assistant consistently stayed in its assigned Persona throughout the conversation. Skipped (pass) when no persona is given.
func RubricJudge ¶
RubricJudge is a G-Eval-style metric: the judge scores Output against Sample.Rubric with chain-of-thought, returning {passed, score, reason}. passThreshold is the minimum score (0..1) required to pass.
func StepEfficiency ¶ added in v0.2.0
StepEfficiency judges whether the agent reached the goal without unnecessary, redundant, or repeated steps. A correct-but-wasteful run scores low.
func Summarization ¶ added in v0.2.0
Summarization judges whether Output is a faithful AND complete summary of the source text in Input: alignment (no contradictions/hallucinations vs source) and coverage (captures the key points). Input is the ORIGINAL TEXT, Output the SUMMARY.
func TaskCompletion ¶ added in v0.2.0
TaskCompletion judges whether the agent actually accomplished the INPUT task, given everything it did (trajectory + tool calls) and its final OUTPUT.
func ToolCorrectness ¶ added in v0.2.0
func ToolCorrectness() Metric
ToolCorrectness checks the tools the agent actually invoked against the ground-truth ExpectedTools (order-independent set comparison). Score is the Jaccard overlap so missing AND extraneous tool calls both cost points; the metric passes only on an exact set match. Deterministic — no LLM.
type MetricFunc ¶
MetricFunc adapts a function into a Metric.
func (MetricFunc) Name ¶
func (m MetricFunc) Name() string
type MetricSpec ¶
type MetricSpec struct {
Judge JudgeFunc // required for semantic metrics; may be nil for deterministic-only
Threshold float64 // pass threshold for relevancy / context_precision / rubric (default 0.5)
}
MetricSpec configures the metrics built by BuildMetrics.
type MetricSummary ¶
type MetricSummary struct {
Metric string `json:"metric"`
PassRate float64 `json:"pass_rate"` // 0..1
MeanScore float64 `json:"mean_score"`
Passed int `json:"passed"`
Total int `json:"total"`
}
MetricSummary aggregates one metric across all samples.
type NamedTarget ¶ added in v0.4.0
NamedTarget pairs a label with a Target so a Comparison can attribute results.
func LoadTargets ¶ added in v0.4.0
func LoadTargets(r io.Reader) ([]NamedTarget, error)
LoadTargets reads a JSON array of ExecTargetSpec and builds NamedTargets, each backed by an ExecTarget.
type RedTeam ¶ added in v0.2.0
type RedTeam struct {
Judge JudgeFunc // optional; required only when Enhance > 0
Kinds []AttackKind // categories to include (default: AllAttackKinds)
Enhance int // LLM obfuscation passes applied to each probe
}
RedTeam generates attack Samples. With a Judge set and Enhance > 0, each probe is additionally rewritten to evade naive keyword filters (stress-tests robustness); without a Judge, generation is fully offline.
type Report ¶
type Report struct {
Samples []SampleReport `json:"samples"`
Usage *Usage `json:"usage,omitempty"` // judge usage, when metered (set by the caller)
}
Report is the full outcome of a Suite run.
func LoadReport ¶ added in v0.2.0
LoadReport parses a JSON report produced by Report.WriteJSON. Only the per-sample results are needed for diffing (summary/usage are ignored).
func (Report) Failed ¶
Failed reports whether any sample failed any metric — use as the CI exit gate.
func (Report) Summary ¶
func (r Report) Summary() []MetricSummary
Summary computes per-metric aggregates, ordered by metric name.
func (Report) WriteConsole ¶
WriteConsole emits a human-readable report: per-sample metric grid + per-metric aggregates + overall verdict.
type Result ¶
type Result struct {
Metric string `json:"metric"`
Score float64 `json:"score"`
Passed bool `json:"passed"`
Reason string `json:"reason,omitempty"`
Err string `json:"error,omitempty"`
}
Result is the outcome of one metric on one sample. Score is normalized 0..1.
type RunOutput ¶ added in v0.4.0
type RunOutput struct {
Output string `json:"output"` // the final answer the agent produced
ToolCalls []ToolCall `json:"tool_calls,omitempty"` // tools invoked, in order
Trajectory []string `json:"trajectory,omitempty"` // ordered action/reasoning steps
Plan string `json:"plan,omitempty"` // the agent's stated plan, if any
Context []string `json:"context,omitempty"` // evidence the judge should see (e.g. final files)
}
RunOutput is what a Target reports after executing one Task: everything the metrics need to grade the run.
type Runner ¶ added in v0.4.0
type Runner struct {
Target Target
Concurrency int // tasks run in parallel; default 4
Timeout time.Duration // per-task wall clock; 0 = no per-task timeout
OnResult func(task Task, s Sample, err error)
}
Runner drives a set of Tasks through a Target, concurrently, and returns one Sample per Task in input order. A Target error never aborts the batch: it becomes a Sample whose Output records the failure and whose Meta["run_error"] is set, so the metrics grade it as a failed run rather than silently dropping.
type Sample ¶
type Sample struct {
Name string `json:"name"` // unique-ish label for reports
Input string `json:"input"` // the question / prompt / task given to the system
Output string `json:"output"` // the actual answer produced by the system under test
Expected string `json:"expected,omitempty"` // optional reference answer (for ExactMatch etc.)
Context []string `json:"context,omitempty"` // retrieved evidence chunks (for RAG metrics)
Rubric string `json:"rubric,omitempty"` // pass/fail criterion for a rubric judge
Meta map[string]string `json:"meta,omitempty"` // free-form labels carried into reports
// human gold judgment per metric name, normalized 0..1 (binary: 1=pass, 0=fail).
// Only used by AlignMetric to measure judge-vs-human agreement; ignored by scoring.
Labels map[string]float64 `json:"labels,omitempty"`
// --- agent execution (recorded from an agent run; for agentic metrics) ---
Plan string `json:"plan,omitempty"` // the agent's stated plan (for plan_quality / plan_adherence)
Trajectory []string `json:"trajectory,omitempty"` // ordered reasoning/action steps the agent took
ToolCalls []ToolCall `json:"tool_calls,omitempty"` // tools the agent actually invoked, in order
ExpectedTools []string `json:"expected_tools,omitempty"` // ground-truth tool names (for tool_correctness)
// --- multi-turn conversation (for conversational metrics) ---
Turns []Turn `json:"turns,omitempty"` // the full chat history, in order
Persona string `json:"persona,omitempty"` // the role the assistant should hold (for role_adherence)
}
Sample is one row of a golden dataset plus the system's actual output.
The first block of fields describes a single-turn output (RAG / generation). The agent block records what an agent actually did during a run — Eval-Go evaluates that recorded trajectory rather than instrumenting a live runtime, so any framework (or none) can emit these fields and be scored the same way.
func FilterMeta ¶ added in v0.2.0
FilterMeta returns the samples whose Meta[key] equals value — e.g. select one red-team attack kind with FilterMeta(samples, "attack", "jailbreak").
func LoadCSV ¶ added in v0.2.0
LoadCSV reads Samples from a CSV with a header row. Recognized columns (case-insensitive) map to Sample fields: name, input, output, expected, rubric, plan, persona. "context" splits on '|' into chunks; "expected_tools" splits on ','. Any other column becomes a Meta entry — so a "tag" or "category" column is filterable via FilterMeta.
type SampleReport ¶
type SampleReport struct {
Sample string `json:"sample"`
Meta map[string]string `json:"meta,omitempty"`
Results []Result `json:"results"`
Passed bool `json:"passed"`
}
SampleReport holds every metric Result for one sample.
type ScoreDelta ¶ added in v0.2.0
type ScoreDelta struct {
Sample string `json:"sample"`
Metric string `json:"metric"`
Old float64 `json:"old"`
New float64 `json:"new"`
OldPassed bool `json:"old_passed"`
NewPassed bool `json:"new_passed"`
Status ChangeStatus `json:"status"`
}
ScoreDelta is one metric's movement between two reports.
type Suite ¶
type Suite struct {
Samples []Sample
Metrics []Metric
Concurrency int // samples evaluated in parallel; default 4
}
Suite is a dataset + the metrics to apply, run concurrently across samples.
type Synthesizer ¶ added in v0.2.0
type Synthesizer struct {
Judge JudgeFunc // the generating LLM (same shape as a judge)
PerContext int // goldens to generate per context group (default 2)
Evolutions int // complexity-evolution passes applied to each question (default 0)
Rubric string // rubric stamped on every Sample (default: grounded-answer criterion)
}
Synthesizer generates golden Samples with an LLM, so you can build an evaluation dataset from source documents instead of hand-writing JSON. The generated Samples carry Input / Expected / Context (and a default Rubric), ready to feed straight into a Suite — including the RAG and faithfulness metrics that score against Context.
It uses only a JudgeFunc, so the stdlib-only core stays dependency-free.
func (Synthesizer) FromContexts ¶ added in v0.2.0
FromContexts generates Samples for each group of retrieval-context chunks: the LLM writes realistic questions answerable from that context plus grounded reference answers. Each group becomes that many Samples' Context.
func (Synthesizer) FromDocuments ¶ added in v0.2.0
func (sy Synthesizer) FromDocuments(ctx context.Context, docs []string, chunkSize int) ([]Sample, error)
FromDocuments splits each document into ~chunkSize-rune chunks (on word boundaries), treats each chunk as one context group, and generates from them.
type Target ¶ added in v0.4.0
Target is the system under test. It runs one Task and reports what happened. Implement it in-process for a Go agent, or use ExecTarget to drive any agent that runs as a subprocess (Python, Rust, a shell script, ...).
type TargetFunc ¶ added in v0.4.0
TargetFunc adapts a plain function into a Target.
type TargetReport ¶ added in v0.4.0
type TargetReport struct {
Name string `json:"name"`
Report Report `json:"report"`
Samples []Sample `json:"samples"`
}
TargetReport is one agent's scored results across all tasks.
type Task ¶ added in v0.4.0
type Task struct {
Name string `json:"name"`
Input string `json:"input"` // the prompt / goal handed to the agent
ExpectedTools []string `json:"expected_tools,omitempty"` // ground-truth tools (for tool_correctness)
Rubric string `json:"rubric,omitempty"` // pass/fail criterion (for the rubric judge)
Expected string `json:"expected,omitempty"` // optional reference answer
Context []string `json:"context,omitempty"` // evidence carried into the Sample if the run adds none
Files map[string]string `json:"files,omitempty"` // optional seed fixtures (path -> content) for the target
Meta map[string]string `json:"meta,omitempty"` // labels carried into the report
}
Task is one unit of agentic work plus the ground truth needed to grade the resulting run. It is the input side of an agent eval; the Target turns it into a RunOutput, and Task.Sample merges the two into a gradeable Sample.
type ToolCall ¶ added in v0.2.0
type ToolCall struct {
Name string `json:"name"` // tool / function name invoked
Args map[string]any `json:"args,omitempty"` // arguments the agent passed
Output string `json:"output,omitempty"` // tool result, if captured (helps the judge)
}
ToolCall is one tool invocation recorded from an agent run.
type Turn ¶ added in v0.2.0
type Turn struct {
Role string `json:"role"` // "user" or "assistant"
Content string `json:"content"` // the message text
}
Turn is one message in a multi-turn conversation.
type Usage ¶ added in v0.2.0
type Usage struct {
Calls int `json:"calls"`
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
JudgeSeconds float64 `json:"judge_seconds"`
Cost float64 `json:"cost,omitempty"`
}
Usage is a snapshot of judge usage, suitable for reports.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
evalgo
command
Command evalgo is a CLI for evaluating LLM / RAG / agent outputs from a golden dataset.
|
Command evalgo is a CLI for evaluating LLM / RAG / agent outputs from a golden dataset. |
|
Package llmjudge adapts an agent-go LLM client into an evalgo.JudgeFunc.
|
Package llmjudge adapts an agent-go LLM client into an evalgo.JudgeFunc. |