Skip to main content
A dataset yields rows; each row is one thing your agent should handle well. Pass anything below to ->dataset(...) in Pest, or return it from a class-based evaluation’s dataset() method.

JSONL — the preferred format

One JSON object per line, streamed lazily (large files never load fully into memory):
evals/support.jsonl
Recognised keys:
hash is identity, not data — a column of that name is not available as meta, and a value that isn’t a 64-character sha256 digest aborts the read. Rename the column if you meant it as your own field.
Malformed lines fail loudly with their line number — no silent row-dropping.

CSV

evals/support.csv
Header row required; prompt and expected columns by default (both configurable via Dataset::fromCsv($path, inputColumn: ..., expectedColumn: ...)); other columns become meta. CSV exists so non-developers can own datasets in a spreadsheet.

Arrays and Eloquent

Inline rows
From your database

Production conversations

The differentiated one — build the dataset from conversations your agent actually had, stored by the Laravel AI SDK’s conversation feature:
Replay real traffic
Each stored conversation becomes a multi-turn row: the latest user turn is the prompt, prior turns replay as context, and the reply your agent actually gave is exposed as $row->expected() — ideal for judging new prompts against real production answers. The standalone Dataset::fromConversations(SupportBot::class) form adds ->latest(), ->take(n), and ->where(...) refinement.

Row identity

Every row gets a content hash over input + messages + expected (not meta). It’s how baseline comparison joins rows across runs — stable across file reordering, unaffected by meta changes, changed only when the row’s actual content changes.