spark agent evals 基线(P1-6)¶
目标:让「agent 改对了没有」从主观感觉变成可回归数字。有 eval 才有迭代依据; 国产模型差距也用 eval 量化,而不是凭印象。
1. 现状:接入方案探测结论(2026-10 实测)¶
| 候选 | 实测结果 | 结论 |
|---|---|---|
deepeval==4.2.8 |
全新 venv uv pip install deepeval==4.2.8 成功,import deepeval 正常(直接依赖 31 个,新增 grpcio/aiohttp/posthog 等闭包约 50MB) |
不接入 CI。原因:①其评判层(GEval 等 LLM-as-judge)必须调 LLM API,mock 模式 CI 里无 key 无法生效;②SWE-bench 风格「检出仓库跑 FAIL_TO_PASS pytest」它本身不提供,仍需手写;③每次 CI 装 50MB 闭包对 mock 零收益。留作文档化的可选 LLM-judge 路径。 |
promptfoo(npm) |
同为 LLM-judge 工具,依赖 Node 环境 + 模型 key | 同上,收益在真实模型对比阶段再引入。 |
| 自研轻量 harness(本项交付) | 纯标准库 + MockProvider,fixture 驱动,全离线 | 采用。harness 真实跑 AgentLoop,判定方式对齐 SWE-bench(pytest 验证)与 τ-bench(工具轨迹合规)。 |
降级是诚实的:真实数据集求解(clone astropy/django at base_commit 跑 FAIL_TO_PASS)需要 Docker/重型 Python 环境,不属于 CI 范畴,写在 §5 手动路径。
2. 数据集与下载情况(如实记录)¶
| 数据源 | 可达性 | 下载情况 |
|---|---|---|
HuggingFace princeton-nlp/SWE-bench_Lite(test split,300 实例) |
匿名可达(HTTP 200;datasets-server first-rows 返回 JSON) |
已拉取 8 行(4 astropy + 4 django),落盘 src/spark/evals/data/swe_lite_real_subset.json(约 93KB,含 problem_statement、FAIL_TO_PASS、gold patch 参考)。 |
sierra-research/tau-bench / tau2-bench-* |
匿名 401 gated,未拉取 | τ-bench 场景以其轨迹判定范式手写为 fixtures(tau-toy-order-refund、tau-toy-shipment-lookup);拿到 HF token 后可按 §4 扩展。 |
3. 场景子集¶
| suite | 场景数 | 判定方式 |
|---|---|---|
swe-lite-style |
2(toy 仓库修 bug) | harness 真实跑 pytest(对齐 FAIL_TO_PASS)+ 文件内容检查 |
tau-bench-style |
2(客服工具轨迹) | 工具调用序列顺序/参数 + 最终文本包含 |
swe-lite-real |
8(真实 SWE-bench Lite 行) | ingest smoke:真实 problem_statement 能被 harness 消费、loop 能跑完;不求解 issue |
4. 运行方式¶
本地(开发机,秒级)¶
pip install -e ".[dev]"
# 全量(内置 4 + 真实子集 8 smoke)
python -m spark.evals
# 只跑某一类
python -m spark.evals --suite swe-lite-style
python -m spark.evals --suite tau-bench-style
python -m spark.evals --id swe-toy-calc-add
# 报告落盘
python -m spark.evals --json evals-report.json
# 手动刷新真实子集(需联网,约 10 行/次)
python -m spark.evals --refresh-real
退出码:全部通过 = 0;任一失败 = 1(CI 据此变红)。
CI¶
.github/workflows/evals.yml:push/PR 时跑 python -m spark.evals --json
evals-report.json,失败即红;报告作为 artifact 留存 14 天。CI 全程 mock,
不联网、不烧 token,分钟内完成。
5. 如何扩展场景¶
在 src/spark/evals/scenarios.py 追加 Scenario:
setup_files:预先铺进临时 workdir 的文件(带 bug 的源码/测试/数据)。script:MockProvider 逐轮剧本(text / tool_call)——离线复现「agent 会怎么干」。judges:判定器,全部通过才算 pass:run_command({python}占位 = 当前解释器):跑 pytest / 任意命令,对齐 SWE-bench 验证;tool_sequence:工具调用序列(顺序 + 参数包含),对齐 τ-bench;file_contains/file_equals/files_exist;final_text_contains;statement_min_chars:真实数据集行的 ingest smoke。
真实 τ-bench 数据:拿到 HF token 后,参照 download_real.py 的写法从
datasets-server.huggingface.co 拉行 JSON 落盘即可(无需 parquet 依赖)。
6. 国产模型差距量化用法(路线)¶
当前 harness 的 script 是 MockProvider 剧本——它回归的是 harness + AgentLoop
行为正确性,不是模型能力。要量化国产模型差距:
- 在 CI 之外建手动目标:把
MockProvider换成真实 provider(DeepSeek-V3.2 / Qwen3-Coder / GLM-4.5 / Kimi K2,走现有openai_compat.py); - 同一批场景(尤其
swe-lite-style的 toy 修复任务)跑 N 个模型, 记录每 suite 通过率; - 需要 LLM-judge 时再引入
deepeval(已验证可装),把 GEval 接到 OpenAI 兼容端点; - 报告形态已就绪:
evals-report.json的 per-scenario pass/fail 可直接 做模型间横向对比表。
诚实边界:本仓库当前 没有 跑过任何真实模型的通过率数字——那是下一步 手动目标的事,不在 CI 内自动发生。