| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- """agent_eval 框架单测:用 mock 跑/收产物/judge,验证行为回归评估逻辑(可进 CI)。
- 真实 LLM 评估由 evals/run_evals.py 手动/nightly 触发(花钱、要 key),不在默认门禁。
- """
- from __future__ import annotations
- from agentpaas.engine.agent_eval import EvalTask, run_eval_task, summarize
- from agentpaas.engine.pipeline import JudgeResult
- def _judge(score):
- return lambda req: JudgeResult(score=score, passed=score >= req.threshold,
- reasons=["mock"], raw="", usage={})
- def _run(output="done", steps=10, cost=0.1, ws="/ws"):
- return lambda task: {"output": output, "steps": steps, "cost_usd": cost, "workspace_path": ws}
- def test_all_good_passes():
- task = EvalTask(id="t1", input="x", must_produce=["report.md"], rubric="好不好", threshold=0.6)
- r = run_eval_task(task, run_fn=_run(),
- collect_artifacts_fn=lambda ws: {"report.md": "完整内容"},
- judge_fn=_judge(0.8))
- assert r.files_ok and r.judge_passed and r.passed
- assert r.judge_score == 0.8 and r.steps == 10
- def test_missing_file_fails():
- task = EvalTask(id="t2", must_produce=["paper.pdf", "report.md"], rubric="", threshold=0.6)
- r = run_eval_task(task, run_fn=_run(),
- collect_artifacts_fn=lambda ws: {"report.md": "x"},
- judge_fn=_judge(1.0))
- assert not r.files_ok
- assert r.missing_files == ["paper.pdf"]
- assert not r.passed
- def test_judge_below_threshold_fails():
- task = EvalTask(id="t3", must_produce=[], rubric="质量", threshold=0.7)
- r = run_eval_task(task, run_fn=_run(),
- collect_artifacts_fn=lambda ws: {"a.md": "敷衍"},
- judge_fn=_judge(0.4))
- assert not r.judge_passed and not r.passed
- def test_error_output_fails():
- task = EvalTask(id="t4", rubric="", must_produce=[])
- r = run_eval_task(task, run_fn=_run(output="[DASHSCOPE_ERROR] boom"),
- collect_artifacts_fn=lambda ws: {},
- judge_fn=_judge(1.0))
- assert r.error and not r.passed
- def test_run_exception_captured():
- def boom(task):
- raise RuntimeError("run crashed")
- task = EvalTask(id="t5")
- r = run_eval_task(task, run_fn=boom,
- collect_artifacts_fn=lambda ws: {}, judge_fn=_judge(1.0))
- assert "run crashed" in r.error and not r.passed
- def test_no_rubric_skips_judge():
- task = EvalTask(id="t6", must_produce=["x.md"], rubric="")
- r = run_eval_task(task, run_fn=_run(),
- collect_artifacts_fn=lambda ws: {"x.md": "ok"},
- judge_fn=lambda req: (_ for _ in ()).throw(AssertionError("不该调 judge")))
- assert r.judge_passed and r.passed # 无 rubric → 不调 judge,judge_passed 默认 True
- def test_summarize():
- task = EvalTask(id="a", must_produce=["r.md"], rubric="", )
- good = run_eval_task(task, run_fn=_run(steps=5, cost=0.2),
- collect_artifacts_fn=lambda ws: {"r.md": "x"}, judge_fn=_judge(1))
- bad = run_eval_task(EvalTask(id="b", must_produce=["miss.pdf"]),
- run_fn=_run(steps=9, cost=0.3),
- collect_artifacts_fn=lambda ws: {}, judge_fn=_judge(1))
- s = summarize([good, bad])
- assert s["total"] == 2 and s["passed"] == 1 and s["pass_rate"] == 0.5
- assert s["failures"] == ["b"]
- assert s["total_cost_usd"] == 0.5
|