orizu 0.5.21 → 0.5.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -15
- package/dist/cleanup.d.ts +6 -0
- package/dist/cleanup.d.ts.map +1 -0
- package/dist/cleanup.js +27 -0
- package/dist/gepa-engine-dispatch.d.ts.map +1 -1
- package/dist/gepa-engine-dispatch.js +20 -1
- package/dist/gepa-python-paths.d.ts.map +1 -1
- package/dist/gepa-python-paths.js +25 -6
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +37 -15
- package/dist/hosted-commands.d.ts +13 -0
- package/dist/hosted-commands.d.ts.map +1 -0
- package/dist/hosted-commands.js +10 -0
- package/dist/hosted-gepa-cli.d.ts +11 -0
- package/dist/hosted-gepa-cli.d.ts.map +1 -0
- package/dist/hosted-gepa-cli.js +110 -0
- package/dist/hosted-gepa-numeric-values.d.ts +3 -0
- package/dist/hosted-gepa-numeric-values.d.ts.map +1 -0
- package/dist/hosted-gepa-numeric-values.js +49 -0
- package/dist/hosted-provider-settings.d.ts +3 -0
- package/dist/hosted-provider-settings.d.ts.map +1 -0
- package/dist/hosted-provider-settings.js +69 -0
- package/dist/hosted-session-cli.d.ts.map +1 -1
- package/dist/hosted-session-cli.js +6 -1
- package/dist/http.d.ts +1 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +72 -74
- package/dist/instruction-set-loader.d.ts.map +1 -1
- package/dist/instruction-set-loader.js +57 -5
- package/dist/instruction-sets-cli.d.ts +5 -2
- package/dist/instruction-sets-cli.d.ts.map +1 -1
- package/dist/instruction-sets-cli.js +134 -24
- package/dist/optimizations-promote-cli.d.ts +3 -0
- package/dist/optimizations-promote-cli.d.ts.map +1 -1
- package/dist/optimizations-promote-cli.js +75 -7
- package/dist/runner-dir-verify.d.ts.map +1 -1
- package/dist/runner-dir-verify.js +4 -7
- package/dist/skilled-proposer-bake-report.d.ts +2 -0
- package/dist/skilled-proposer-bake-report.d.ts.map +1 -0
- package/dist/skilled-proposer-bake-report.js +1 -0
- package/dist/skilled-proposer-config.d.ts +2 -0
- package/dist/skilled-proposer-config.d.ts.map +1 -0
- package/dist/skilled-proposer-config.js +212 -0
- package/dist/skilled-proposer-launch.d.ts +26 -0
- package/dist/skilled-proposer-launch.d.ts.map +1 -1
- package/dist/skilled-proposer-launch.js +103 -6
- package/package.json +1 -1
- package/scripts/vendor-gepa-python.mjs +81 -12
- package/src/cleanup.ts +37 -0
- package/src/gepa-engine-dispatch.ts +21 -1
- package/src/gepa-python-paths.ts +24 -6
- package/src/help.ts +37 -15
- package/src/hosted-commands.ts +4 -0
- package/src/hosted-gepa-cli.ts +107 -0
- package/src/hosted-gepa-numeric-values.ts +60 -0
- package/src/hosted-provider-settings.ts +69 -0
- package/src/hosted-session-cli.ts +4 -1
- package/src/http.ts +8 -0
- package/src/index.ts +112 -89
- package/src/instruction-set-loader.ts +55 -5
- package/src/instruction-sets-cli.ts +173 -19
- package/src/optimizations-promote-cli.ts +85 -7
- package/src/runner-dir-verify.ts +11 -6
- package/src/skilled-proposer-bake-report.ts +1 -0
- package/src/skilled-proposer-config.ts +191 -0
- package/src/skilled-proposer-launch.ts +96 -7
- package/src/skilled-proposer-venv-manager.mjs +44 -27
- package/vendor/orizu-gepa/src/orizu_gepa_connector/engine.py +36 -3
- package/vendor/orizu-gepa/src/orizu_gepa_connector/instruction_set_loader.py +31 -3
- package/vendor/orizu-gepa/src/orizu_gepa_connector/runtime.py +7 -2
- package/vendor/orizu-gepa/src/orizu_gepa_connector/skilled_proposer_bridge.py +354 -5
- package/vendor/orizu-gepa-python/src/orizu_gepa/cli.py +1 -0
- package/vendor/orizu-gepa-python/src/orizu_gepa/client.py +15 -0
- package/vendor/skills/orizu-cli/SKILL.md +94 -168
- package/vendor/skills/orizu-cli/references/assess-and-plan.md +107 -0
- package/vendor/skills/orizu-cli/references/building-judges.md +442 -180
- package/vendor/skills/orizu-cli/references/cli-reference.md +69 -39
- package/vendor/skills/orizu-cli/references/dataset-design.md +100 -0
- package/vendor/skills/orizu-cli/references/eval-strategy.md +64 -0
- package/vendor/skills/orizu-cli/references/instructions-after-prompts.md +115 -0
- package/vendor/skills/orizu-cli/references/migrate-existing-gepa-setup.md +150 -82
- package/vendor/skills/orizu-cli/references/optimization-reports.md +196 -104
- package/vendor/skills/orizu-cli/references/optimization-with-gepa.md +57 -37
- package/vendor/skills/orizu-cli/references/primer.md +43 -18
- package/vendor/skills/orizu-cli/references/prompt-control-plane.md +199 -131
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
# Optimization With GEPA
|
|
2
2
|
|
|
3
|
-
How to optimize
|
|
3
|
+
How to optimize an instruction-set profile against validated judges and scorers. Prepare the complete instruction-set manifest, follow the [Authority map](../SKILL.md#authority-map) for its mutation, and then run the bundled `orizu optimizations run-gepa` flow. Use this reference for GEPA mechanics, custom optimizer implementations, and optional DSPy context for customers already using DSPy.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Select the profile explicitly with `--instruction-set <slug-or-exact-name> --model-config <identity>`. Those two selectors replace the legacy `--candidate-version-id` path and cannot be combined with it. The connector resolves that model config's production profile, or the set default when the profile has no production version, and optimizes its complete component map. `--component-selector round-robin` is the default and updates one component per round; `--component-selector all` updates every component per round. The runner receives a multi-component candidate as a component map, while a one-component set keeps the existing single-body runner contract. Git-pinned components and malformed component maps are refused before a run starts. Automatic promotion is refused for multi-component sets; write the report, obtain the human promotion decision, and follow the Authority map. Manifest create/push is the pre-run seed path, not a second accepted-candidate materialization; after a run, use the human one-shot or equivalent idempotent two-stage path in step 9.
|
|
6
6
|
|
|
7
7
|
## Inputs
|
|
8
8
|
|
|
9
9
|
You should arrive here with:
|
|
10
|
-
- One or more **validated judges**
|
|
10
|
+
- One or more **validated judges** that clear their agreed judge trust bar (see `building-judges.md`).
|
|
11
11
|
- A **dataset** of inputs to optimize against — usually the same exported labels, plus any harder cases you've added since.
|
|
12
|
-
-
|
|
12
|
+
- An **instruction set** whose selected profile contains the starting component values for the LLM application you want to improve.
|
|
13
13
|
|
|
14
14
|
If you don't have a validated judge, stop. Optimizing against an unvalidated judge means you'll hill-climb on a noisy or biased signal — Goodhart's law in action.
|
|
15
15
|
|
|
16
16
|
## Why GEPA-Style Optimization
|
|
17
17
|
|
|
18
|
-
- **GEPA** is a gradient-free
|
|
18
|
+
- **GEPA** is a gradient-free text optimizer that uses an LLM to propose component edits, scores candidates against your metric, and keeps the best. It is well-suited to instruction optimization where you cannot backpropagate through the model.
|
|
19
19
|
- In Orizu, runners execute candidates, scorers produce metrics/feedback, and optimization events make the loop inspectable and promotable.
|
|
20
20
|
- DSPy is not part of Orizu's bundled optimizer. Treat DSPy examples here as an external integration pattern only.
|
|
21
21
|
|
|
@@ -40,52 +40,72 @@ If you don't have a validated judge, stop. Optimizing against an unvalidated jud
|
|
|
40
40
|
└──────────┬──────────────┘
|
|
41
41
|
▼
|
|
42
42
|
┌─────────────────────────┐
|
|
43
|
-
│ Optimized
|
|
43
|
+
│ Optimized profile │
|
|
44
44
|
│ Compare before/after │
|
|
45
45
|
└─────────────────────────┘
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
## Orizu-tracked optimization
|
|
49
49
|
|
|
50
|
-
Use the
|
|
50
|
+
Use the control plane described in `prompt-control-plane.md` when you want runs, candidates, score charts, Pareto/frontier views, and promotions in Orizu:
|
|
51
51
|
|
|
52
|
-
1.
|
|
53
|
-
2.
|
|
54
|
-
3.
|
|
55
|
-
4.
|
|
56
|
-
5.
|
|
57
|
-
6.
|
|
58
|
-
7.
|
|
52
|
+
1. Create the instruction set from its prepared manifest with `orizu instructions create`, or push a new profile version with `orizu instructions push`, using the executor selected by the Authority map. Keep the set's shape fixed during a run.
|
|
53
|
+
2. Push the candidate runner and, for an LLM evaluator, the judge rubric with `orizu judges push`.
|
|
54
|
+
3. Register a row scorer for reflection. GEPA reflection requires row-level feedback.
|
|
55
|
+
4. Snapshot a dataset version. Create one split set with train, validation, and a reserved final-held-out partition; pass only the train and validation partition names to `run-gepa`. Never pass the final-held-out partition as `--train-split` or `--val-split`; the CLI accepts arbitrary partition names and does not enforce this boundary.
|
|
56
|
+
5. Push the optimizer implementation with `orizu optimizers push ./optimizer --project <team/project> --name <optimizer-name> --json` and retain its returned optimizer version ID.
|
|
57
|
+
6. Use `orizu optimizations run-gepa --optimizer-version-id <optimizer-version-id>` with the set slug and model-config identity. It uses official GEPA by default; `--engine legacy` is a frozen safety hatch while migration parity is proven. Use `orizu optimizations start` plus event logging for a custom optimizer. Candidates are ranked on the partition passed as `--val-split`; use that partition for validation, not Final-held-out.
|
|
58
|
+
7. Use set scorers for selection/tracked reporting when the meaningful metric is batch-level; execute builtin set scorers with `orizu scorers exec` or submit precomputed aggregates with `orizu scores submit --aggregate`.
|
|
59
|
+
8. Write and attach the optimization report by following “How To Build The Report” step 5 in `references/optimization-reports.md`: “Determine whether the current execution surfaces can reproduce the selected system before claiming a Final-held-out comparison.” Its “Flat-row scorer contract,” “Default GEPA scorer contract,” and “Instruction-set execution limits” subsections own the executable boundaries and current gaps.
|
|
60
|
+
9. After the human accepts the report, follow the [Authority map](../SKILL.md#authority-map). Simpler one-shot path: a human curator runs `orizu optimizations promote <run-id> --candidate <id> --label production --project <team/project>`, materializing and labeling once. In the two-stage path for multi-component or deliberately unlabeled materialization, an agent may materialize with `orizu optimizations promote <run-id> --candidate <id> --project <team/project>`. A human curator re-runs that same promotion as `orizu optimizations promote <run-id> --candidate <id> --label production --project <team/project>`. The idempotent finalizer reuses the existing materialized profile version, moves production to it, and creates no duplicate profile version or candidate-promoted event.
|
|
59
61
|
|
|
60
|
-
The bundled Orizu GEPA-style optimizer supports configurable budget, minibatch size (default 3), candidate selection strategy, reflection model/template, reflection provider settings, evaluation caching, and optional auto-promotion.
|
|
62
|
+
The bundled Orizu GEPA-style optimizer supports configurable budget, minibatch size (default 3), candidate selection strategy, reflection model/template, reflection provider settings, evaluation caching, and optional auto-promotion. Use the report-first path: run without auto-promotion, write the report, obtain the human promotion decision, then route the manual promotion command through the Authority map. Only pass `--log-row-snapshots` when raw data in event logs is intentional.
|
|
63
|
+
|
|
64
|
+
Budget behavior:
|
|
65
|
+
- The `auto`, `light`, `medium`, and `heavy` presets are DSPy-style metric-call budgets whose limits scale with the validation-set size.
|
|
66
|
+
- Budgets are checked after in-run seed validation and between completed iterations, never mid-iteration; once an iteration starts, its parent minibatch, child minibatch, and, for an accepted child, full validation complete even if that work overshoots the selected limit.
|
|
61
67
|
|
|
62
68
|
Reflection output contract:
|
|
63
|
-
- The reflective LM
|
|
64
|
-
- The default reflection
|
|
65
|
-
- Put provider-native reasoning controls in `--reflection-provider-settings <json|@file>`, not in
|
|
69
|
+
- The official engine uses the decoded reflective LM response string as the next value of the selected component without trimming; the legacy engine uses `response.strip()`, removing leading and trailing whitespace. With `round-robin`, other component values are read-only context; with `all`, each component is reflected independently and the results form one complete candidate profile.
|
|
70
|
+
- The default reflection template asks for only the complete updated component value. Do not ask the model to wrap the value in markdown fences or tags; instruction components often contain those characters.
|
|
71
|
+
- Put provider-native reasoning controls in `--reflection-provider-settings <json|@file>`, not in an instruction component. For OpenAI reasoning models, use a shape such as `{"reasoning":{"effort":"medium","summary":"auto"}}`. For Anthropic Claude models with thinking controls, use a shape such as `{"thinking":{"type":"adaptive"},"output_config":{"effort":"medium"}}`.
|
|
72
|
+
- Treat scorer feedback as directional signal: with `higher_is_better: true`, describe lower scores as failures or opportunities, not as a numeric loss; omit fields labeled `informational; not scored` from feedback sent to reflection.
|
|
66
73
|
- Reflection max-token limits are explicit. `--reflection-max-tokens <n>` maps to Anthropic `max_tokens` and OpenAI `max_output_tokens`; Anthropic native Messages reflection requires it, while OpenAI may omit it when no cap is desired.
|
|
67
|
-
- Reflection HTTP calls retry transient failures by default (`--reflection-retry-attempts 3`, `--reflection-http-timeout-seconds 180`).
|
|
74
|
+
- Reflection HTTP calls retry transient failures by default (`--reflection-retry-attempts 3`, `--reflection-http-timeout-seconds 180`). Legacy GEPA logs an exhausted retryable reflection failure, charges proposal and iteration budgets, and continues. The official engine increments proposal usage only after successful `on_proposal_end`; skilled-proposer failures re-raise and stop.
|
|
68
75
|
|
|
69
76
|
Full command syntax and event contracts: `prompt-control-plane.md`.
|
|
70
77
|
|
|
78
|
+
For staff-enabled hosted optimization, a human/PAT caller adds `--hosted` and
|
|
79
|
+
uses a named `--budget auto|light|medium|heavy`. Hosted launch does not require
|
|
80
|
+
the local candidate/scorer runner directories or a local log directory, and it
|
|
81
|
+
never sends provider credentials or runner bytes from the customer's machine.
|
|
82
|
+
Numeric budget controls are refused because they cannot be compared honestly
|
|
83
|
+
to the named team ceiling. For response-loss recovery, reuse an explicit
|
|
84
|
+
`--launch-intent-id <uuid>`; a changed project or job specification requires a
|
|
85
|
+
new intent. A hosted agent prepares the command and hands it to a human.
|
|
86
|
+
|
|
71
87
|
## Migrating from the legacy engine (release cli-v0.5.20+)
|
|
72
88
|
|
|
73
89
|
Since release `cli-v0.5.20` (`orizu@0.5.20` on npm), `run-gepa` defaults to the official GEPA engine. The flag surface and validation rules match legacy almost everywhere — a valid legacy command runs unchanged, with two exceptions: the reflection-cap requirement below, and stricter `=`-form parsing (`--flag=` with an empty value, or an `=`-attached value that itself starts with `--`, is refused pre-launch; legacy's argparse accepted both — a scripted `--scorer-candidate-field=$FIELD` with `FIELD` unset now fails with the flag named). What actually differs:
|
|
74
90
|
|
|
75
|
-
- **Validation happens before launch.** Legacy validated flags inside the python process (an argparse exit); the official dispatcher enforces the flag-shape rules below before anything spawns and names the offending flag in the error (the budget-conflict error lists the exclusive set rather than the flags you passed; value errors — e.g. a non-integer or non-positive budget number — are still reported by the engine and name the underlying setting). The rules carried over from legacy: `--budget` / `--candidate-selection-strategy` / `--scorer-input-contract` validate their choices, boolean flags take no value, abbreviated flag spellings are rejected, and budget controls are mutually exclusive — at most one of `--budget`, `--max-metric-calls`, `--max-full-evals`, `--max-iterations`. The official-only `--max-candidate-proposals` joins that exclusion set
|
|
91
|
+
- **Validation happens before launch.** Legacy validated flags inside the python process (an argparse exit); the official dispatcher enforces the flag-shape rules below before anything spawns and names the offending flag in the error (the budget-conflict error lists the exclusive set rather than the flags you passed; value errors — e.g. a non-integer or non-positive budget number — are still reported by the engine and name the underlying setting). The rules carried over from legacy: `--budget` / `--candidate-selection-strategy` / `--scorer-input-contract` validate their choices, boolean flags take no value, abbreviated flag spellings are rejected, and budget controls are mutually exclusive — at most one of `--budget`, `--max-metric-calls`, `--max-full-evals`, `--max-iterations`. The official-only `--max-candidate-proposals` joins that exclusion set. With no budget control, `--budget auto` selects the balanced `medium` preset.
|
|
92
|
+
- **Context and runtime.** Supply `--optimizer-version-id`, `--runner-version-id`, `--candidate-runner-dir`, `--scorer-version-id`, `--scorer-runner-version-id`, `--scorer-runner-dir`, `--dataset-version-id`, `--split-set-id`, `--train-split`, and `--val-split`; use `--python` to select the interpreter and `--json` for structured output.
|
|
93
|
+
- **Search and reproducibility.** Tune `--minibatch-size`, `--candidate-selection-strategy`, `--epsilon`, `--objective`, and `--num-threads`; use `--seed`, `--disable-evaluation-cache`, and optional `--metadata <json>` when reproducibility or run attribution requires them. Automatic row-evaluation concurrency is bounded by the larger of the minibatch and validation workloads, twice the detected CPU count, available memory after its reserve, available file descriptors after headroom, and a configurable ceiling whose default is 64 (`ORIZU_GEPA_AUTO_THREADS_MAX`). An explicit positive thread count bypasses that auto-scaling calculation.
|
|
94
|
+
- **Reflection controls.** Select `--reflection-model` and `--reflection-temperature`; a perfect selected minibatch skips reflection and child creation by default under `--skip-perfect-parent-reflection`, while `--no-skip-perfect-parent-reflection` overrides that behavior.
|
|
95
|
+
- **Promotion flags.** Do not use `--auto-promote` or `--promotion-label` in the report-first workflow: write the report, obtain the human promotion decision, and follow the Authority map.
|
|
76
96
|
- **A reflection cap is required for non-OpenAI reflection models.** `--reflection-max-tokens` is required at launch whenever the reflection model does not start with `openai/` — including the default (`anthropic/claude-opus-4-7`) and bare names like `gpt-4o` — so the run refuses immediately instead of failing every reflection call mid-run.
|
|
77
|
-
- **The skilled proposer is an opt-in proposal path.** Reach for `--candidate-proposer skilled-proposer` when you want to evaluate the upstream proposer's alternative reflection process and can accept its first-use network, CPython, and managed-dependency requirements. Evaluate the shipped empty-skills proposer through the controlled A/B below, and ground quality or generalization claims in that evidence.
|
|
97
|
+
- **The skilled proposer is an opt-in proposal path.** Reach for `--candidate-proposer skilled-proposer` when you want to evaluate the upstream proposer's alternative reflection process and can accept its first-use network, CPython, and managed-dependency requirements. It prepares or reuses a managed Python environment. Its aggregate `--proposal-max-calls` and `--proposal-max-tokens` budgets are independent of metric-call limits and per-response reflection limits. Add `--candidate-proposer-config @file` for explicit skills/guidance; do not combine the selection with `--reflection-prompt-template`. Evaluate the shipped empty-skills proposer or a pinned config through the controlled A/B below, and ground quality or generalization claims in that evidence. Config schema, environment setup, and recovery live in `prompt-control-plane.md` ("Skilled proposer").
|
|
78
98
|
- **Seed preflight: same gate, better evidence.** Both engines refuse a degenerate seed (every valid row pinned to the same bound — the worst score, or uniformly `0.0` under a lower-is-better scorer, where the perfect bound is indistinguishable from a scorer silently zeroing on a mismatched input shape) or an all-errored seed at launch, and both accept `--allow-degenerate-seed` to bypass. The bypass covers *both* refusals — including the broken-scorer one — so a bypassed run can spend budget on a scorer that never works; use it only when a weak seed is expected. New on the official engine: the refusal message carries per-row evidence (row ids, scores, scorer output and errors); `<log-dir>/preflight-refused-<uuid>/preflight.json` (not written under `--no-local-log`) instead stores redacted `{row_id, score, error_class}` entries unless `--log-row-snapshots` is passed — a sibling of the run directories, since no run record exists when a launch is refused.
|
|
79
99
|
- **Metric accounting differs.** Official counts include every evaluated row; legacy excluded some cached work. Do not compare raw metric-call totals across engines (details in ADR-019).
|
|
80
100
|
- **Artifacts.** Both engines write `events.jsonl`, `evaluations.jsonl`, `reflections.jsonl`, and `result.json` locally; `lm_stats.json` (reflection usage) is official-only. Dashboard rendering is identical, and run metadata records `engine: official` or `engine: legacy`.
|
|
81
101
|
|
|
82
|
-
Terminal semantics are unchanged between engines: exhausting any budget control other than `--max-iterations` ends the run `paused` (`pause_reason: budget_exhausted`)
|
|
102
|
+
Terminal semantics are unchanged between engines: exhausting any budget control other than `--max-iterations` ends the run `paused` (`pause_reason: budget_exhausted`), while completing the configured `--max-iterations` is a normal `succeeded` finish. In both cases, keep the report-first path: no auto-promotion; write the report, obtain the human promotion decision, and follow the Authority map for manual promotion. Falling back to `--engine legacy` after a budget-exhausted pause reproduces the same paused outcome; it will not turn the run into a `succeeded` one.
|
|
83
103
|
|
|
84
104
|
**Fallback:** rerun with `--engine legacy` for the previous engine's exact behavior, dropping `--max-candidate-proposals` first if you used it (it is official-only; the CLI refuses it under legacy before launch). Legacy is frozen (no new features) and will be removed at the M3 milestone (ADR-019) — if you fall back because the official engine misbehaved, capture both run ids and report the pair.
|
|
85
105
|
|
|
86
106
|
### Compare the skilled proposer with the default
|
|
87
107
|
|
|
88
|
-
Run two arms with the same
|
|
108
|
+
Run two arms with the same instruction-set profile version, dataset version and split set, candidate and scorer runners, seed, reflection model/settings, thread count, and one shared overall budget such as `--max-candidate-proposals 1`. Keep the default arm unselected; add `--candidate-proposer skilled-proposer`, the same pinned `--candidate-proposer-config @file` when testing configuration, and bounded `--proposal-max-calls` / `--proposal-max-tokens` only to the selected arm. The comparison is ready when both terminal states, retained candidates, scores, proposal evidence, and total run usage are captured. A fixed GEPA seed aligns optimizer sampling but does not make provider or scorer calls deterministic, so treat the pair as process and outcome evidence rather than an intrinsic quality claim.
|
|
89
109
|
|
|
90
110
|
For the selected arm, each provider-bearing proposal call appends `proposal-observability/events.jsonl`. Success records contain `source`, `status`, `attempt`, `correlation_id`, `provider`, `model`, nullable `request_id`, `latency_ms`, `cache_state`, and `usage.{input_tokens,output_tokens,total_tokens}`. Failure records contain `source`, `status`, `attempt`, `correlation_id`, `provider`, `cache_state`, `failure_code`, and optional `usage`; the latest durable failure is also written to `proposal-failures/latest.json` with `source`, `code`, `detail`, and optional `correlation_id`.
|
|
91
111
|
|
|
@@ -93,7 +113,7 @@ With local logging, those paths sit under `<log-dir>/<run-id>/`, and terminal `p
|
|
|
93
113
|
|
|
94
114
|
## Step 1: Wrap your application as an Orizu runner
|
|
95
115
|
|
|
96
|
-
For Orizu-tracked optimization, the candidate runner receives one dataset row and
|
|
116
|
+
For Orizu-tracked optimization, the candidate runner receives one dataset row and the candidate profile through the file contract. A one-component profile is passed as a single body for runner compatibility; a multi-component profile is passed as a complete component map. The scorer runner, by default, receives a GEPA-shaped `row` — `{source_row, candidate_id, candidate_output, candidate_raw_response, candidate_error}` — and returns a score and feedback. See `prompt-control-plane.md` ("Scorer-Runner Input Contracts") for the exact runner I/O shapes.
|
|
97
117
|
|
|
98
118
|
**Contract warning:** the GEPA scorer contract differs from the flat-row score-run contract used by `orizu runners exec --scorer-version`. A judge runner written for flat-row score runs will find no output to judge in the GEPA shape and silently score every candidate 0. Do not hand-write a wrapper runner: pass `--scorer-input-contract flat_row` (plus `--scorer-candidate-field <row-field>` if the judge reads the candidate output from a named row field such as `draft`) and `run-gepa` adapts the payload for you while keeping the registered runner bytes unchanged. `run-gepa` also validates the contract on the seed at launch and refuses a uniformly-worst-scoring seed with a diagnosis instead of burning budget.
|
|
99
119
|
|
|
@@ -132,7 +152,7 @@ class SupportAgent(dspy.Module):
|
|
|
132
152
|
)
|
|
133
153
|
```
|
|
134
154
|
|
|
135
|
-
If your real application is multi-step (retrieval + generation + tool use), build a multi-Module program. GEPA can optimize each
|
|
155
|
+
If your real application is multi-step (retrieval + generation + tool use), build a multi-Module program. GEPA can optimize each module's instructions independently.
|
|
136
156
|
|
|
137
157
|
## Step 2: Register scorers
|
|
138
158
|
|
|
@@ -208,7 +228,7 @@ logs/<optimization_run_id>/
|
|
|
208
228
|
result.json
|
|
209
229
|
```
|
|
210
230
|
|
|
211
|
-
Use this directory as the
|
|
231
|
+
Use this directory as the preferred artifact for coding-agent analysis. It contains the full row inputs, model outputs, scores, feedback, scorer responses, reflection prompts, reflection responses, candidate text, and final result. Override the root with `--log-dir <dir>`; disable persistence with `--no-local-log` only when raw rows/reflection context must not be written to disk.
|
|
212
232
|
|
|
213
233
|
If the local log is missing or the run happened elsewhere, export the server-side archive:
|
|
214
234
|
|
|
@@ -218,7 +238,7 @@ orizu optimizations export <optimization-run-id> --out ./optimization.json
|
|
|
218
238
|
|
|
219
239
|
Export returns one JSON object with raw events plus derived seed-vs-best, Pareto frontier, candidates, score-over-time, iterations, minibatch rows, validation rows, scorer context, prompt versions, and dataset split information. It fetches all optimization events and rehydrates row inputs from dataset artifacts when possible. Server events redact row snapshots and reflection prompts by default, but bundled `run-gepa` includes reflection responses in the event stream.
|
|
220
240
|
|
|
221
|
-
After the run ends, write a markdown report before the context is lost. Use `optimization-reports.md
|
|
241
|
+
After the run ends, write a markdown report before the context is lost. Use the authoritative ordered sections in `optimization-reports.md`: Promotion Decision; Run And Evidence; Candidate Comparison (Validation Data); Optimizer Health; Scenario Classes; What Changed In The Selected Version; Final-held-out Result: Seed vs Selected Candidate; Recommendation And Named Next Moves; Reproducibility; and Report Completeness Checklist.
|
|
222
242
|
|
|
223
243
|
DSPy GEPA example for customers already on DSPy:
|
|
224
244
|
|
|
@@ -247,13 +267,13 @@ optimized_program.save("./optimized_support_agent.json")
|
|
|
247
267
|
|
|
248
268
|
GEPA will:
|
|
249
269
|
1. Run the program on `trainset`, score with `metric`.
|
|
250
|
-
2. Use `reflection_lm` to propose
|
|
251
|
-
3. Score candidate
|
|
270
|
+
2. Use `reflection_lm` to propose instruction edits based on failures.
|
|
271
|
+
3. Score candidate programs on the trainset, keep the best.
|
|
252
272
|
4. Validate on `valset` to avoid overfitting.
|
|
253
273
|
|
|
254
274
|
Orizu's bundled optimizer is intentionally narrower than DSPy GEPA today: text candidates only, local runner/scorer directories, and Orizu event logging built in.
|
|
255
275
|
|
|
256
|
-
## Step 5: Compare before / after on
|
|
276
|
+
## Step 5: Compare before / after on Final-held-out
|
|
257
277
|
|
|
258
278
|
This is the step teams skip and regret.
|
|
259
279
|
|
|
@@ -274,7 +294,7 @@ def evaluate(program, examples) -> dict:
|
|
|
274
294
|
|
|
275
295
|
|
|
276
296
|
# Hold out a fresh set the optimizer never saw.
|
|
277
|
-
held_out = load_examples("./held-out.jsonl")
|
|
297
|
+
held_out = load_examples("./final-held-out.jsonl")
|
|
278
298
|
|
|
279
299
|
before = evaluate(SupportAgent(), held_out)
|
|
280
300
|
after = evaluate(optimized_program, held_out)
|
|
@@ -287,8 +307,8 @@ print(f"After: {after}")
|
|
|
287
307
|
|
|
288
308
|
## Step 6: Ship and feed the loop
|
|
289
309
|
|
|
290
|
-
If the optimized
|
|
291
|
-
-
|
|
310
|
+
If the optimized profile holds up on Final-held-out:
|
|
311
|
+
- Promote the validated profile version to production; never promote one component by itself.
|
|
292
312
|
- Sample new production traces over the next week.
|
|
293
313
|
- Upload them as a new dataset (`primer.md` Step 1).
|
|
294
314
|
- Annotate failures the optimized system *now* exhibits — they'll be different from the ones the previous version had.
|
|
@@ -300,18 +320,18 @@ Each pass through the loop reveals the next layer.
|
|
|
300
320
|
## Common pitfalls
|
|
301
321
|
|
|
302
322
|
- **Optimizing against an unvalidated judge.** You'll improve the metric and degrade the system. Always validate first.
|
|
303
|
-
- **No held-out comparison.** "It's better, look at the metric" without
|
|
323
|
+
- **No Final-held-out comparison.** "It's better, look at the metric" without Final-held-out is meaningless — GEPA will overfit if you let it.
|
|
304
324
|
- **Hiding regressions in the average.** Track per-failure-mode metrics, not just combined.
|
|
305
325
|
- **Over-budgeting GEPA.** Heavy budgets give diminishing returns and burn LM spend. Start with `auto="light"`, scale up only if needed.
|
|
306
326
|
- **Ignoring temperature.** Run optimization with the same LM config (model, temperature) you use in production. Optimizing against gpt-4o at temp=0 doesn't transfer to gpt-4o-mini at temp=0.7.
|
|
307
|
-
- **Recreating Orizu logging by hand for
|
|
327
|
+
- **Recreating Orizu logging by hand for instruction sets.** Use `orizu optimizations run-gepa` unless the optimizer is genuinely custom.
|
|
308
328
|
|
|
309
329
|
## Checklist
|
|
310
330
|
|
|
311
331
|
Before declaring an optimization run successful:
|
|
312
332
|
|
|
313
|
-
- [ ] Each metric is backed by a validated judge (
|
|
314
|
-
- [ ] Train
|
|
333
|
+
- [ ] Each metric is backed by a validated judge that clears its agreed judge trust bar (see `building-judges.md`)
|
|
334
|
+
- [ ] Train and validation partitions plus Final-held-out, which stays genuinely untouched during optimization
|
|
315
335
|
- [ ] Per-metric numbers reviewed (not just combined)
|
|
316
336
|
- [ ] Same LM/temperature in eval as in production
|
|
317
337
|
- [ ] Optimization report written from logs/export and attached with `--report-file` when the run is finished, failed, or cancelled
|
|
@@ -2,19 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
> **Core idea:** You can't improve what you can't measure — but measuring the wrong thing is worse than not measuring at all. This doc walks from raw failure logs to a continuously-running evaluation loop, and shows how Orizu operationalizes each step.
|
|
4
4
|
|
|
5
|
-
The loop
|
|
5
|
+
The operational loop starts at **J3 — Build the dataset** and branches on the
|
|
6
|
+
approved ground-truth source:
|
|
6
7
|
|
|
7
8
|
```
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
approved golden ground truth covers the scenario classes: J3 → J5
|
|
10
|
+
missing ground truth needs human labels: J3 → J4 → J5
|
|
11
|
+
│
|
|
12
|
+
▼
|
|
13
|
+
J6 → new traces → J3
|
|
11
14
|
```
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
In the diagram, **J4 — Ground truth via annotation (conditional)** is taken only
|
|
17
|
+
for missing labels, **J5 — Build & validate judges** consumes the approved
|
|
18
|
+
ground truth, and **J6 — Optimize & promote** feeds new traces into the next J3
|
|
19
|
+
dataset version. Approved golden ground truth therefore goes directly from J3
|
|
20
|
+
to J5 instead of passing through annotation.
|
|
21
|
+
|
|
22
|
+
The CLI covers the full operational loop. Start instruction sets with `orizu instructions`: one instruction set per agent or LLM experience, one profile per model config, and components owned by that profile. Human annotation still happens through apps/tasks when J4 is needed, while judge/scorer logic and optimization execution run locally and report back through the instruction control plane. Follow the applicable branch and require its prior journey step's exit criterion before continuing.
|
|
23
|
+
|
|
24
|
+
An instruction-set manifest carries its `name`, optional `description`, fixed, ordered `shape`, and component values. The set's slug is its stable CLI reference even when its display name changes. Profiles have their own component values; components are never shared between profiles or sets. The set-wide default serves model configs without a production profile version.
|
|
25
|
+
|
|
26
|
+
Start by inspecting the set, then follow the [Authority map](../SKILL.md#authority-map)
|
|
27
|
+
for mutation custody before syncing through the same surface:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
orizu instructions list --project <team>/<project>
|
|
31
|
+
orizu instructions show <slug-or-exact-name> --project <team>/<project>
|
|
32
|
+
orizu instructions create ./orizu.instruction-set.json --project <team>/<project> --model-config <identity>
|
|
33
|
+
orizu instructions push ./orizu.instruction-set.json --project <team>/<project> --set <slug-or-exact-name>
|
|
34
|
+
orizu instructions profiles new <slug-or-exact-name> --project <team>/<project> --model-config <identity>
|
|
35
|
+
orizu instructions sync <slug-or-exact-name> --out ./instructions --project <team>/<project>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Do not create or mutate standalone prompts. If a legacy identifier leads to a prompt read view, use its owner information to find the instruction set and continue with `orizu instructions`.
|
|
14
39
|
|
|
15
40
|
---
|
|
16
41
|
|
|
17
|
-
##
|
|
42
|
+
## Error analysis (before writing any eval)
|
|
18
43
|
|
|
19
44
|
The most common mistake teams make is jumping straight to evals before they understand what's actually failing. Error analysis is the prerequisite.
|
|
20
45
|
|
|
@@ -30,11 +55,11 @@ The most common mistake teams make is jumping straight to evals before they unde
|
|
|
30
55
|
**Decision: should you even write a formal eval for this failure?**
|
|
31
56
|
- If you haven't observed it, no — do error analysis first.
|
|
32
57
|
- If the fix is one-shot and obvious, no — just fix it.
|
|
33
|
-
- If fixing it requires repeated iteration (
|
|
58
|
+
- If fixing it requires repeated iteration (component edits, retries, structural changes), yes — that's where evals shine.
|
|
34
59
|
|
|
35
60
|
---
|
|
36
61
|
|
|
37
|
-
##
|
|
62
|
+
## J3 detail: Upload — gather diverse traces
|
|
38
63
|
|
|
39
64
|
### Why
|
|
40
65
|
|
|
@@ -80,7 +105,7 @@ Full surface: `cli-reference.md`.
|
|
|
80
105
|
|
|
81
106
|
---
|
|
82
107
|
|
|
83
|
-
##
|
|
108
|
+
## Conditional J4 detail: Annotate — binary labels per failure mode
|
|
84
109
|
|
|
85
110
|
### Why
|
|
86
111
|
|
|
@@ -133,14 +158,14 @@ Authoring the labeler app — contract, design principles, and common patterns:
|
|
|
133
158
|
|
|
134
159
|
---
|
|
135
160
|
|
|
136
|
-
##
|
|
161
|
+
## J5 detail: Judge — turn labels into automated evaluators
|
|
137
162
|
|
|
138
163
|
### Why
|
|
139
164
|
|
|
140
165
|
- **Code assertions first.** If a failure is a rule (keyword present, tool called, format valid), write a code check. Fast, free, deterministic.
|
|
141
166
|
- **LLM-as-a-judge for nuanced criteria only.** Powerful but slow and expensive — reserve for failures code can't catch.
|
|
142
167
|
- **Validate every judge against human labels.** A judge that doesn't agree with humans is a misaligned metric.
|
|
143
|
-
- Track **TPR (True Positive Rate)** and **TNR (True Negative Rate)** separately, not accuracy. Accuracy is misleading on imbalanced data.
|
|
168
|
+
- Track **TPR (True Positive Rate)** and **TNR (True Negative Rate)** separately, not accuracy. Accuracy is misleading on imbalanced data. Each judge must clear its agreed judge trust bar (see `building-judges.md`).
|
|
144
169
|
- **A 100% pass rate is a smell** — your evals are saturated. Add harder cases.
|
|
145
170
|
- **Three common eval mistakes:**
|
|
146
171
|
1. Skipping the data — using off-the-shelf metrics ("Helpfulness," "Faithfulness") that don't measure your specific failures.
|
|
@@ -154,19 +179,19 @@ There are three **types** of automated evals:
|
|
|
154
179
|
|
|
155
180
|
### In Orizu
|
|
156
181
|
|
|
157
|
-
This work is still authored by the agent in code, but Orizu
|
|
182
|
+
This work is still authored by the agent in code, but Orizu stores the versioned instruction, evaluator, and score artifacts:
|
|
158
183
|
|
|
159
184
|
1. Export labeled data: `orizu tasks export --task <id> --format jsonl --out labels.jsonl`
|
|
160
185
|
2. For each failure mode, choose code assertion or LLM-judge.
|
|
161
186
|
3. Build the judge.
|
|
162
187
|
4. Validate against the labels (train/dev/test split, TPR/TNR).
|
|
163
|
-
5.
|
|
188
|
+
5. Keep the subject application's instruction material in its instruction set. For an LLM judge, push the judge artifact and runner, register a scorer, then submit score runs for the set's profile versions or optimization candidates.
|
|
164
189
|
|
|
165
|
-
Control-plane commands: `prompt-control-plane.md`. Detailed
|
|
190
|
+
Control-plane commands: `prompt-control-plane.md`. Detailed alignment-first walkthrough — deterministic versus LLM judge choice, binary output contract, judge trust bar agreement, judge-test evidence, and judge optimization: `building-judges.md`.
|
|
166
191
|
|
|
167
192
|
---
|
|
168
193
|
|
|
169
|
-
##
|
|
194
|
+
## J6 detail: Optimize — hill-climb against validated judges
|
|
170
195
|
|
|
171
196
|
### Why
|
|
172
197
|
|
|
@@ -181,8 +206,8 @@ Done locally, reported to Orizu:
|
|
|
181
206
|
1. Package the candidate execution as a runner, or use the customer's existing local app wrapper.
|
|
182
207
|
2. Register validated scorers.
|
|
183
208
|
3. Run the bundled Orizu GEPA-style text optimizer, or a custom optimizer against the scorer set.
|
|
184
|
-
4. Stream optimization events to Orizu, promote accepted candidates, and submit comparable scores.
|
|
185
|
-
5. Diff before/after on the eval suite. Ship if it holds; new traces feed back to
|
|
209
|
+
4. Stream optimization events to Orizu, promote accepted candidates into the target instruction-set profile, and submit comparable scores.
|
|
210
|
+
5. Diff before/after on the eval suite. Ship if it holds; new traces feed back to J3.
|
|
186
211
|
|
|
187
212
|
Control-plane commands: `prompt-control-plane.md`. Detailed walkthrough — GEPA mechanics, optional DSPy context for customers already using it, and before/after comparison: `optimization-with-gepa.md`.
|
|
188
213
|
|
|
@@ -231,7 +256,7 @@ Production Traffic
|
|
|
231
256
|
↓ │
|
|
232
257
|
Build Judge (code-first, LLM-as-judge if needed)
|
|
233
258
|
↓ │
|
|
234
|
-
Validate Judge (
|
|
259
|
+
Validate Judge (agreed trust bar) │
|
|
235
260
|
↓ │
|
|
236
261
|
Optimize (GEPA-style search against scorers) │
|
|
237
262
|
↓ │
|