zcbot/evaluation/runner.py

104 lines
3.0 KiB
Python

"""顺序执行评测任务。
第一版刻意不并发:避免压测与质量评测混在一起,也降低误连环境时的影响面。
"""
from __future__ import annotations
import datetime as dt
import uuid
from dataclasses import dataclass
from typing import Callable, Optional
from .client import ZcbotClient
from .models import (
CaseResult,
EvalCase,
EvalSuite,
RepetitionResult,
RunObservation,
safe_case_slug,
)
from .scoring import score_observation
@dataclass(frozen=True)
class RunSettings:
repetitions: Optional[int] = None
timeout_s: float = 900.0
ProgressCallback = Callable[[str], None]
def run_suite(
suite: EvalSuite,
client: ZcbotClient,
*,
settings: RunSettings,
progress: ProgressCallback = lambda _message: None,
) -> list[CaseResult]:
stamp = (
dt.datetime.now().strftime("%Y%m%d-%H%M%S")
+ "-"
+ uuid.uuid4().hex[:8]
)
results: list[CaseResult] = []
for case in suite.cases:
repetitions = (
settings.repetitions
if settings.repetitions is not None
else case.repetitions or suite.default_repetitions
)
run_results: list[RepetitionResult] = []
for index in range(1, repetitions + 1):
slug = safe_case_slug(case.id)
working_dir = f"eval-{slug}-{stamp}-{index}"
task_name = f"eval-{slug}-{index}"
progress(f"[INFO] {case.id} repetition {index}/{repetitions}")
task = client.create_task(
name=task_name,
working_dir=working_dir,
skill=case.skill,
model_profile=case.model_profile,
)
task_id = str(task["task_id"])
try:
observation = client.run_prompt(
task_id=task_id,
prompt=case.prompt,
working_dir=working_dir,
timeout_s=case.timeout_s or settings.timeout_s,
)
except Exception as exc:
observation = RunObservation(
run_status="error",
run_error=f"{type(exc).__name__}: {exc}",
task_id=task_id,
working_dir=working_dir,
)
score, assertions = score_observation(
case.assertions, observation
)
run_results.append(
RepetitionResult(
index=index,
observation=observation,
assertions=assertions,
score=score,
)
)
case_score = sum(item.score for item in run_results) / len(run_results)
passed = [
item.score >= suite.pass_threshold for item in run_results
]
results.append(
CaseResult(
case=case,
repetitions=run_results,
score=case_score,
pass_at_1=passed[0],
pass_all=all(passed),
)
)
return results