Experiments#
Experiments is a first-class Langfuse feature for evaluating prompts and model configurations against a dataset, entirely within the UI. It sits on top of the existing DatasetRuns Postgres table but layers a dedicated event-driven data model (getExperimentsFromEvents, getExperimentItemsFromEvents, etc.) that provides faster loading and richer filtering than the legacy Dataset Runs view.
The feature lives at:
- Entry page:
web/src/pages/project/[projectId]/experiments.tsx - Results page:
web/src/pages/project/[projectId]/experiments/results.tsx - Feature directory:
web/src/features/experiments/
RBAC scopes:
promptExperiments:CUD— create/trigger experimentspromptExperiments:read— view experiments/results
Data Architecture: Experiments vs. Dataset Runs#
An Experiment is a DatasetRun record in Postgres, but with structured metadata and a dedicated processing pipeline:
| Aspect | Legacy Dataset Runs | Experiments |
|---|---|---|
| UI location | /datasets/[id] runs tab | /experiments (beta toggle) |
| Data backend | Direct Prisma queries | getExperimentsFromEvents (ClickHouse event model) |
| Score display | DatasetRunsTable with chart overlay | ExperimentsTable with score sub-columns |
| RBAC scope | datasets:* | promptExperiments:* |
| Trigger | SDK / API only | UI form OR SDK / API |
| Execution | Any custom pipeline | ExperimentCreateQueue → worker processes prompt+LLM for each dataset item |
On creation, createExperiment in the router does two things:
- Creates a
DatasetRunsrow with experiment metadata (prompt_id,provider,model,model_params,experiment_name,experiment_run_name) stored in themetadatafield. - Enqueues a job on
ExperimentCreateQueue→QueueName.ExperimentCreate. A background worker then iterates dataset items, calls the LLM for each, and writes traces/observations back via the ingestion pipeline.
URL translation between the legacy compare?runs=A&B format and the new experiments/results?baseline=A&c=B format is handled by experimentUrlTranslation.ts.
Creation Workflow#
The entry point is CreateExperimentsForm, which presents two modes:
- Via UI — renders
MultiStepExperimentForm, a 5-step breadcrumb wizard. - Via SDK/API — shows docs links and an optional webhook/remote-trigger configuration (
RemoteExperimentUpsertForm/RemoteExperimentTriggerModal).
The 5-step wizard steps are:
| Step | Component | Key behavior |
|---|---|---|
| 1 – Prompt & Model | PromptModelStep | Select prompt version, provider, model, optional structured output schema |
| 2 – Dataset | DatasetStep | Select dataset (+ optional snapshot version); validateConfig query checks prompt variables against dataset items |
| 3 – Evaluators | EvaluatorsStep | Attach existing or new eval jobs (optional, requires evalJob:read/CUD) |
| 4 – Experiment run details | ExperimentDetailsStep | Name (auto-generated as {prompt}-v{N} on dataset {dataset}) and description |
| 5 – Review | ReviewStep | Summary before final submission |
Form state is managed by react-hook-form with CreateExperimentData Zod schema . The experiment name and runName are auto-generated from the selected prompt/version/dataset . Submission calls api.experiments.createExperiment.useMutation .
CreateExperimentsForm is also embedded in the Prompt detail page (prompt-detail.tsx) so an experiment can be launched directly from a prompt version .
Experiments List & Filtering#
ExperimentsTable at /project/[projectId]/experiments shows all experiments for a project with:
- Columns: name, description, item count, error count, start time, linked dataset (badge), linked prompts (badges), avg latency, total cost, and score sub-columns .
- Score sub-columns come in three flavors rendered via
useScoreColumns: trace-level item scores, observation-level item scores, and experiment-level scores . - Dataset filter: the
experimentDatasetIdfilter option lets users scope the table to a specific dataset. Filter options (including available dataset IDs and score names) are fetched viaexperiments.filterOptions. - Compare action: selecting multiple rows shows a "Compare (N)" button that navigates to
/experiments/results?baseline=<first>&c=<others>. - Row click navigates to the results page with that experiment as baseline .
The page is guarded by a beta toggle (useExperimentAccess + ExperimentsBetaSwitch). Users without the beta enabled see a feature-opt-in screen; disabling the toggle redirects back to /datasets .
Results & Comparison View#
The results page (results.tsx) centers on ExperimentItemsTable, which renders one row per dataset item. Each row stacks the output, scores, latency, and cost from the baseline experiment and any number of comparison experiments side-by-side. Up to 5 color-coded slots are supported (baseline + 4 comparisons).
The router's items procedure fetches per-item data across all selected experiment IDs, supporting:
baseExperimentId/compExperimentIdsfor multi-experiment comparison .filterByExperiment— per-experiment filter arrays, enabling dataset-item-level filtering scoped to a specific run .itemVisibilitytoggle (baseline-onlyvsall) to show only items present in the baseline or all items across all selected experiments .
An ExperimentOverviewPanel sidebar shows aggregate metrics for each selected experiment.
Key files quick reference:
| File | Purpose |
|---|---|
web/src/features/experiments/server/router.ts | tRPC router: createExperiment, all, metrics, items, filterOptions |
web/src/features/experiments/components/CreateExperimentsForm.tsx | Outer form shell (UI vs SDK mode select) |
web/src/features/experiments/components/MultiStepExperimentForm.tsx | 5-step wizard |
web/src/features/experiments/components/table/ExperimentsTable.tsx | List view with filtering and compare action |
web/src/features/experiments/utils/experimentUrlTranslation.ts | URL migration helpers (old → new format) |
web/src/pages/project/[projectId]/experiments.tsx | Page entry point |
web/src/pages/project/[projectId]/experiments/results.tsx | Results/comparison page |