Skip to content

Commit 4cd409e

Browse files
committed
fix(evals): record the config that actually ran and preserve candidate_k when downgrading rerank
1 parent 29f8028 commit 4cd409e

2 files changed

Lines changed: 29 additions & 7 deletions

File tree

app/evals/run.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from app.evals.graders.deterministic import grade_citations, grade_refusal
3535
from app.evals.graders.judges import grade_correctness, grade_faithfulness
3636
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
3838
from app.generation.prompts.registry import all_prompt_ids
3939
from app.observability.cost import UsageMeter
4040

@@ -233,7 +233,25 @@ async def run_eval(
233233
if limit:
234234
questions = questions[:limit]
235235

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+
237255
log.info(
238256
"eval %s (%s) — %s questions %s, space=%s",
239257
config.name,

app/generation/answer.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,15 @@ def resolve_config(name: str | None) -> RetrievalConfig:
9595
not settings.is_serverless and LocalCrossEncoderReranker.available()
9696
):
9797
why = "serverless" if settings.is_serverless else "cross-encoder unavailable"
98-
downgraded = get_config("serverless")
99-
downgraded.name = config.name
100-
downgraded.top_k = config.top_k
101-
downgraded.candidate_k = min(config.candidate_k, downgraded.candidate_k)
102-
downgraded.label = f"{config.label} ({why}: LLM reranker)"
98+
downgraded = config.model_copy(deep=True)
99+
downgraded.rerank = RerankStrategy.LLM
100+
if settings.is_serverless:
101+
# Only the serverless path narrows the candidate set; it is a
102+
# latency budget, not part of what the config means. Applying it to
103+
# a local benchmark run would change retrieval depth as well as the
104+
# reranker, and the comparison would no longer isolate one variable.
105+
downgraded.candidate_k = min(config.candidate_k, get_config("serverless").candidate_k)
106+
downgraded.label = f"{config.label} — LLM reranker ({why})"
103107
log.info("config %s downgraded to the LLM reranker — %s", config.name, why)
104108
return downgraded
105109
return config

0 commit comments

Comments
 (0)