|
30 | 30 |
|
31 | 31 |
|
32 | 32 | class ExecutionConfig(EvalBaseModel): |
33 | | - """How a later phase obtains an optimization candidate.""" |
| 33 | + """Pipeline execution mode and deterministic candidate scenario.""" |
34 | 34 |
|
35 | | - mode: Literal["fake", "real", "trace"] = "fake" |
36 | | - fake_candidate_scenario: Literal["improve", "no_improvement", "overfit"] = "improve" |
37 | | - use_fake_judge: bool = False |
| 35 | + mode: Literal["offline", "real", "trace"] = "offline" |
| 36 | + candidate_scenario: Literal["improve", "no_improvement", "overfit"] = "improve" |
| 37 | + |
| 38 | + @model_validator(mode="before") |
| 39 | + @classmethod |
| 40 | + def _reject_removed_execution_options(cls, value: object) -> object: |
| 41 | + if not isinstance(value, dict): |
| 42 | + return value |
| 43 | + if value.get("mode") == "fake": |
| 44 | + raise ValueError("execution.mode='fake' was renamed to 'offline'") |
| 45 | + if "use_fake_judge" in value: |
| 46 | + raise ValueError( |
| 47 | + "execution.use_fake_judge was removed; configure evaluation " |
| 48 | + "metrics or rubric explicitly in optimizer.json" |
| 49 | + ) |
| 50 | + if "fake_candidate_scenario" in value: |
| 51 | + raise ValueError( |
| 52 | + "execution.fake_candidate_scenario was renamed to " |
| 53 | + "execution.candidate_scenario" |
| 54 | + ) |
| 55 | + return value |
38 | 56 |
|
39 | 57 |
|
40 | 58 | class InputPathsConfig(EvalBaseModel): |
@@ -72,6 +90,37 @@ def _require_non_empty_relative_path(cls, value: str) -> str: |
72 | 90 | return value |
73 | 91 |
|
74 | 92 |
|
| 93 | +class TraceCandidateInputsConfig(EvalBaseModel): |
| 94 | + """一个 Trace 候选版本的评测集和 Prompt 快照路径。""" |
| 95 | + |
| 96 | + train_evalset: str |
| 97 | + validation_evalset: str |
| 98 | + prompts: list[PromptFieldConfig] = Field(min_length=1) |
| 99 | + |
| 100 | + @field_validator("train_evalset", "validation_evalset") |
| 101 | + @classmethod |
| 102 | + def _require_relative_trace_path(cls, value: str) -> str: |
| 103 | + if not value.strip() or Path(value).is_absolute(): |
| 104 | + raise ValueError("trace evalset path must be a non-empty relative path") |
| 105 | + return value |
| 106 | + |
| 107 | + |
| 108 | +class TraceInputsConfig(EvalBaseModel): |
| 109 | + """三个确定性候选场景的 Trace 输入。""" |
| 110 | + |
| 111 | + candidates: dict[ |
| 112 | + Literal["improve", "no_improvement", "overfit"], |
| 113 | + TraceCandidateInputsConfig, |
| 114 | + ] |
| 115 | + |
| 116 | + @model_validator(mode="after") |
| 117 | + def _require_all_scenarios(self) -> "TraceInputsConfig": |
| 118 | + required = {"improve", "no_improvement", "overfit"} |
| 119 | + if set(self.candidates) != required: |
| 120 | + raise ValueError("trace_inputs must define improve, no_improvement, and overfit") |
| 121 | + return self |
| 122 | + |
| 123 | + |
75 | 124 | class RunConfig(EvalBaseModel): |
76 | 125 | """Reproducibility and workspace location settings.""" |
77 | 126 |
|
@@ -186,12 +235,31 @@ class PipelineConfig(EvalBaseModel): |
186 | 235 | reporting: ReportingConfig = Field(default_factory=ReportingConfig) |
187 | 236 | artifacts: ArtifactConfig = Field(default_factory=ArtifactConfig) |
188 | 237 | writeback: WritebackConfig = Field(default_factory=WritebackConfig) |
| 238 | + trace_inputs: Optional[TraceInputsConfig] = None |
189 | 239 |
|
190 | 240 | @model_validator(mode="after") |
191 | 241 | def _require_unique_prompt_names(self) -> "PipelineConfig": |
192 | 242 | names = [prompt.name for prompt in self.prompts] |
193 | 243 | if len(names) != len(set(names)): |
194 | 244 | raise ValueError("prompts must not contain duplicate field names") |
| 245 | + if self.execution.mode == "trace": |
| 246 | + if self.trace_inputs is None: |
| 247 | + raise ValueError("trace mode requires trace_inputs") |
| 248 | + if self.writeback.enabled: |
| 249 | + raise ValueError("trace mode does not allow source Prompt writeback") |
| 250 | + expected = set(names) |
| 251 | + for scenario, inputs in self.trace_inputs.candidates.items(): |
| 252 | + candidate_names = [prompt.name for prompt in inputs.prompts] |
| 253 | + if len(candidate_names) != len(set(candidate_names)): |
| 254 | + raise ValueError( |
| 255 | + f"trace candidate {scenario} has duplicate prompt names" |
| 256 | + ) |
| 257 | + if set(candidate_names) != expected: |
| 258 | + raise ValueError( |
| 259 | + f"trace candidate {scenario} prompt fields must match baseline" |
| 260 | + ) |
| 261 | + elif self.trace_inputs is not None: |
| 262 | + raise ValueError("trace_inputs is only allowed in trace mode") |
195 | 263 | return self |
196 | 264 |
|
197 | 265 |
|
|
0 commit comments