|
34 | 34 | from app.evals.graders.deterministic import grade_citations, grade_refusal |
35 | 35 | from app.evals.graders.judges import grade_correctness, grade_faithfulness |
36 | 36 | from app.evals.graders.retrieval import grade_retrieval |
37 | | -from app.generation.answer import QueryRequestSpec, answer_once |
| 37 | +from app.generation.answer import QueryRequestSpec, answer_once, resolve_config |
38 | 38 | from app.generation.prompts.registry import all_prompt_ids |
39 | 39 | from app.observability.cost import UsageMeter |
40 | 40 |
|
@@ -233,7 +233,25 @@ async def run_eval( |
233 | 233 | if limit: |
234 | 234 | questions = questions[:limit] |
235 | 235 |
|
236 | | - config = get_config(config_name) |
| 236 | + # Record the config that will actually run, not the one requested. |
| 237 | + # |
| 238 | + # resolve_config() substitutes the LLM reranker when a cross-encoder cannot |
| 239 | + # load. Storing the requested config here would file the run under |
| 240 | + # "cross-encoder rerank" while an LLM scorer produced every number — the |
| 241 | + # published table would then attribute results to a component that never |
| 242 | + # executed, which is the precise failure this project exists to argue |
| 243 | + # against. |
| 244 | + requested = get_config(config_name) |
| 245 | + config = resolve_config(config_name) |
| 246 | + if config.rerank is not requested.rerank: |
| 247 | + log.warning( |
| 248 | + "config %s requested rerank=%s but will run rerank=%s — the run is " |
| 249 | + "recorded under what actually executes", |
| 250 | + config_name, |
| 251 | + requested.rerank.value, |
| 252 | + config.rerank.value, |
| 253 | + ) |
| 254 | + |
237 | 255 | log.info( |
238 | 256 | "eval %s (%s) — %s questions %s, space=%s", |
239 | 257 | config.name, |
|
0 commit comments