Skip to main content

evaLLM

evaLLM is a lightweight QA framework for evaluating LLM outputs with composable, schema-validated metrics.

It is designed for two workflows:

  • batch evaluation through a CLI
  • embeddable evaluation pipelines through a Python API

Quick links

Installation

Install from PyPI

pip install evallm-qa

Install optional extras

Use this if you want encoding-based metrics (for example count_encodings):

pip install "evallm-qa[hf-tokenizers]"

Install from source (secondary option)

Use this if you want to work from a local checkout:

git clone https://github.com/psandhaas/evaLLM.git
cd evaLLM
pip install .

Source install with extras:

pip install .[hf-tokenizers]

What evaLLM evaluates

Current built-in metrics include:

  • CountsMetric: character, token, or model-encoding counts
  • JsonFormatMetric: field-level JSON format validation against a JSON Schema

Results are emitted per input record as JSON objects, which makes them easy to pipe, persist, and analyze downstream.

Library structure

evaLLM follows a layered architecture to keep concerns separated:

  • evallm.application
    • orchestration layer
    • DTOs (EvaluationRequest, MetricSpec, dataset specs)
    • request resolution and evaluator execution
  • evallm.metrics
    • base metric interface (BaseMetric[T])
    • built-in metrics and registration catalog
    • metric composition (CompositeMetric)
  • evallm.readers
    • dataset access layer (currently JSONL reader)
  • evallm.cli
    • Typer-based command-line interface

Further details on architectural choices can be found in the documentation.

Composite metrics

evaLLM intentionally models multi-metric evaluation using the Composite design pattern.

Composite is a good fit because each metric is an independent computation over the same input text, and the framework must aggregate all metric outputs into one result object. This creates a tree-shaped execution model:

  • a parent metric container evaluates children
  • each child contributes a namespaced result
  • multiple instances of the same metric class can coexist with different configs

This gives you two concrete benefits:

  • as a user you can rely on the fact that calling evalute(text) does exactly that; your input is evaluated against however many metrics, with whichever configuration you chose, and
  • as a developer you only need to implement evaluate(text), without having to consider how or when your metric is called.

Core concepts

Evaluation request

An evaluation is defined by:

  • one dataset spec (dataset)
  • one or more metric specs (metrics)

Metric spec

Each metric spec supports:

  • name: registered metric identifier
  • config (optional): runtime metric config
  • result_key (optional): output field name override

Dataset support

Current support:

  • JSONL datasets (JsonlDatasetSpec)

Each JSONL record must contain a text field and can optionally provide a stable record id field.

Extend BaseReader and BaseDatasetSpec for further formats.

Python API examples

1) Build and run an evaluation with helper presets

from evallm.application import (
    JsonlEvaluationBuilder,
    count_characters,
    count_tokens,
    json_format,
)

builder = JsonlEvaluationBuilder(
    "./data/dataset.jsonl",
    text_key="text",
    record_id_key="id",
)

builder.use(count_characters(result_key="chars"))
builder.use(count_tokens(segmentation="wordpunct", result_key="tokens_wordpunct"))
builder.use(
    json_format(
        {
            "type": "object",
            "properties": {
                "answer": {"type": "string"},
                "confidence": {"type": "number", "minimum": 0.0, "maximum": 1.0},
            },
            "required": ["answer"],
        },
        result_key="format_ok",
    )
)

for result in builder.run():
    print(result.model_dump())

2) Build a request explicitly

from evallm.application import EvaluationRequest

request = EvaluationRequest.create(
    obj={
        "dataset": {
            "input_file": "./data/dataset.jsonl",
            "text_key": "text",
            "record_id_key": "id",
        },
        "metrics": [
            {"name": "CountsMetric", "result_key": "chars"},
            {
                "name": "CountsMetric",
                "config": {"segments": "tokens", "segmentation": "whitespace"},
                "result_key": "tokens",
            },
        ],
    }
)

CLI examples

Evaluate via flags

evallm run \
    --input-file ./data/dataset.jsonl \
    --text-key text \
    --record-id-key id \
    --metric CountsMetric

Evaluate via config file

evallm run --config ./run.yaml

Discover available metrics and presets

evallm metrics list
evallm metrics info CountsMetric --format yaml
evallm metrics presets

Write JSONL results to a file

evallm run \
    -f ./data/dataset.jsonl \
    -t text \
    -i id \
    -m CountsMetric \
    --output ./results.jsonl

Config file reference

evallm run expects two top-level sections:

  1. dataset
  2. metrics

Minimal YAML example:

dataset:
    input_file: ./data/dataset.jsonl
    text_key: text
    record_id_key: id

metrics:
    - name: CountsMetric
        result_key: chars

    - name: CountsMetric
        config:
            segments: tokens
            segmentation: whitespace
        result_key: tokens

    - name: JsonFormatMetric
        config:
            expected_schema:
                type: object
                properties:
                    answer:
                        type: string
                    confidence:
                        type: number
                        minimum: 0.0
                        maximum: 1.0
                required:
                    - answer
            check_formats: true
        result_key: structured_output

Important merge rule:

  • if --config and inline flags are both provided, inline dataset flags override config fields
  • if any --metric flags are provided, they replace config.metrics

Extending evaLLM with custom metrics

Implement BaseMetric[T] and register with @register_metric.

from evallm.metrics.base import BaseMetric
from evallm.metrics.registry import register_metric


@register_metric(name="token_lengths")
class TokenLengthsMetric(BaseMetric[list[int]]):
    def evaluate(self, text: str) -> dict[str, list[int]]:
        if text.strip() == "":
            return self.result([])
        return self.result([len(tok) for tok in text.split()])

Development

Run tests:

uv run pytest

Without uv:

python -m pytest

Run docs locally:

uv run mkdocs serve

Without uv:

mkdocs serve

If you want to use uv, installation instructions are available at https://docs.astral.sh/uv/getting-started/installation/.

Metadata

Release files for evallm-qa 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for evallm-qa 0.1.1
File Size Uploaded Provenance
evallm_qa-0.1.1.tar.gz 60.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for evallm-qa 0.1.1
File Interpreter ABI Platform
evallm_qa-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 131.0 kB

Release files / evallm_qa-0.1.1.tar.gz

Download URL evallm_qa-0.1.1.tar.gz
Size 60.6 kB
Tags Source
SHA-256 checksum
How to use checksums
16d220654e5d6bc223fa12030e190f1b959092f7e842d72dc6750e3d91acbcfd
BLAKE2b-256 checksum
How to use checksums
6ef0d03158cdabb3ee68979e39215cb84371f2452fc771b2daab717b82b861c5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / evallm_qa-0.1.1-py3-none-any.whl

Download URL evallm_qa-0.1.1-py3-none-any.whl
Size 70.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ea2a106ac12fce26ce74d30be6ede34528c0b9c79fd79b2a830825848cf79b2f
BLAKE2b-256 checksum
How to use checksums
225646e827b8d59372fde64128d0991b5e5e6f374bbc2ea61a0192ba49c5d745
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.7 {"installer":{"name":"uv","version":"0.10.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for evallm-qa 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page