通用的 LLM Agent 评测平台:把"这个 Agent 到底好不好"从一句感觉,变成可测量、可校准、可回归的工程问题。
被测 Agent 只需暴露一个 HTTP API——平台把它当黑盒,负责其余的一切:数据集管理、批量实验、trace 采集、分层打分(规则 → 指标 → LLM Judge)、人工标注界面、Judge 校准闭环、回归门禁。
AZORA 是第一个完整接入案例(见 examples/azora/ 与 datasets/)。
Agent 产品的迭代困境:改了 prompt / 换了模型 / 加了工具,你怎么知道变好了还是变坏了?
- 手动试几个 query —— 样本太小,且你只会试自己想得到的
- 直接上 LLM-as-a-Judge —— 未经校准的 judge 只是把"感觉"外包给了另一个模型
- 只看线上指标 —— 滞后、混杂,无法归因到某次改动
这个平台实现的是完整的评测闭环:
trace 采集 → 错误分析(开放编码→taxonomy) → 人工标注(gold) → 分层自动打分
↑ │
└──────────── 回归门禁 ← Judge 校准(TPR/TNR + few-shot) ←────┘
┌─────────────────────────────┐ ┌──────────────────────────┐
│ 被测 Agent(黑盒) │ │ Eval Platform (:8100) │
│ PRODUCT_API_URL (:8001) │◄───────│ │
│ │ HTTP │ runner/ 批量实验执行 │
│ 评测专用隔离实例 │ │ graders/ L0/L1/L2 打分 │
│ (docker-compose.eval.yml, │ │ storage/ SQLite 存储 │
│ 固定资源配额,消除基础设施 │ │ api/ REST + WS │
│ 噪声) │ │ cli.py 实验 CLI │
└─────────────────────────────┘ └────────────┬─────────────┘
│
┌────────────▼─────────────┐
│ 标注前端 (frontend-v2/) │
│ Trace 查看 / Pass-Fail │
│ 标注 / 开放编码 / 实验对比 │
└──────────────────────────┘
便宜、确定性的检查先跑;昂贵、需要判断力的检查后跑。失败在哪一层,就归因到哪一层(graders/failure_funnel.py)。
| 层 | 模块 | 检查内容 | 成本 |
|---|---|---|---|
| L0 | l0_structure.py / l0_constraints.py |
输出结构完整性、硬约束(预算、必备条件)是否满足 | 免费,纯规则 |
| L1 | l1_metrics.py |
可计算指标(数量、覆盖度、来源多样性等) | 免费,纯代码 |
| L2 | l2_judge.py / llm_graders.py |
需要判断力的维度:groundedness、actionability、rubric 合规、trap 检测 | LLM 调用 |
配套:error_taxonomy.py(失效模式分类)、composite.py(加权合成总分)、scoring.py(阈值判定)。
未校准的 judge 不可信任。 平台把校准做成了可重复的工作流:
scripts/sample_for_annotation.py— 分层采样待标注 traceANNOTATION_GUIDE.md+ 标注前端 — 人工标注 gold labels(Pass/Fail 判据显式成文,标注人是人不是模型)scripts/validate_evaluator.py— judge 判定 vs 人工 gold,输出 TPR/TNR 对齐报告scripts/extract_few_shots.py— 从分歧样本提炼 few-shot 示例(calibration/few_shots/)scripts/calibration_loop.py— 注入 few-shots 重跑,迭代直到对齐达标
工程保证:
- Judge 必须强于被测模型(
config.py:GRADING_MODEL 默认取更强模型——弱模型抓不住强模型级别的错误,同级模型会共享盲区) - Judge prompt 版本哈希(
JUDGE_PROMPT_VERSION)——每次实验记录 judge 版本,分数变化可归因:"是 Agent 变了,还是尺子变了?" - 通过阈值由人工标注校准得出,并随标注量增长定期重校准,不拍脑袋
按使用旅程组织。所有命令在仓库根目录执行,评测后端需已启动(见 Quickstart)。
数据集是一个 JSON 文件(真实示例见 datasets/):
{
"name": "My Agent Baseline V1",
"description": "First regression suite for my agent",
"cases": [
{
"key": "noise_cancel_budget",
"query": "best noise cancelling headphones under $400 with 30 hour battery",
"type": "constrained",
"constraints": {"price_max": 400, "must_have": ["noise cancelling", "30+ hour battery"]}
}
]
}key在数据集内唯一;type是你自定义的 case 分类(后续按类型分析);constraints供 L0 约束 grader 消费;有参考答案的 case 可加golden_data- 导入:把文件放进
datasets/后执行python cli.py import --dataset <文件名>(不带.json) - 数据集带版本号:case 变更自动 +1,每次实验记录所用版本,结果可追溯
python cli.py run --dataset "My Agent Baseline V1" --tag v1.0 --trials 2 --concurrency 2
python cli.py list # 历史实验
python cli.py summary --experiment-id 1 # 汇总:分数、通过情况、各 grader 表现
python cli.py regression --latest --threshold 5 # 最近两次对比,掉分超阈值 → exit 1实时进度看 UI 实验页(WebSocket 推送)。每条 trace 记录 prompt 版本、模型、judge prompt 版本哈希——分数变化可归因到"Agent 变了"还是"尺子变了"。
python scripts/sample_for_annotation.py --experiment-id 1 --count 50 # 采样(--seed 可复现)然后在 UI 的 TracePage 逐条判 Pass/Fail、打开放编码(open codes)。判据写在 ANNOTATION_GUIDE.md——换领域先重写它。标注落库到 human_pass / human_scores 字段。
python scripts/calibration_loop.py --create-splits # train/dev/test 划分(一次性)
python scripts/validate_evaluator.py --per-grader # judge vs 人工 gold 对齐报告
python scripts/extract_few_shots.py # 从 train 分歧样本提炼 few-shots
python scripts/calibration_loop.py --run-dev --notes "v2 few-shots" # dev 集重打分
# …迭代到对齐达标后…
python scripts/calibration_loop.py --run-test # test 集一次性终评(防过拟合)
python scripts/calibration_loop.py --history # 校准历史EVAL_DATASET="My Agent Baseline V1" scripts/run_eval.sh regression --threshold 5模式:smoke(2 case 冒烟)/ regression(回归门禁)/ capability(全量 ×N trials)。退出码 0=通过、1=回归、2=平台或被测系统不可达,可直接做流水线门禁。支持消融实验(选择性关闭 Agent 组件,定位能力来源)。
python scripts/export_langfuse.py --days 30 --limit 200 --tag my-agent --grade需要 .env 中的 LangFuse 密钥;--grade 表示导入后立即打分。
| 变量 | 作用 | 默认 |
|---|---|---|
PRODUCT_API_URL |
被测 Agent 的 API 地址 | http://localhost:8001 |
EVAL_API_KEY |
与被测系统的共享密钥 | 空 |
ANTHROPIC_API_KEY |
L2 judge 调用所需 | 空 |
GRADING_MODEL |
judge 模型(必须强于被测模型) | 见 backend/config.py |
JUDGE_ENABLED |
是否启用 L2 judge | 关 |
PASS_THRESHOLD |
通过阈值(应由校准得出,勿拍脑袋) | 60 |
PRODUCT_CODE_PATH |
被测 Agent 源码路径,preset judge 深检用(可选) | 空 |
LANGFUSE_SECRET_KEY / LANGFUSE_PUBLIC_KEY |
生产 trace 导入 | 空 |
EVAL_DATASET |
run_eval.sh 使用的数据集名 |
Legacy Baseline V1 |
EVAL_CORS_ORIGINS |
评测后端 CORS 放行来源 | localhost:5200 |
领域耦合集中在三层,替换它们即可接入新 Agent:
- 端点:让你的 Agent 暴露一个任务 API,设置
PRODUCT_API_URL+EVAL_API_KEY(backend/.env.example) - 数据集:按
datasets/*.json的 schema 编写 cases(key/query/type/constraints,可选golden_data) - 标注指南 + graders:参照
ANNOTATION_GUIDE.md写出你的领域 Pass/Fail 判据;替换/增补 L0 约束检查和 L2 judge 维度
平台层(runner / storage / 标注前端 / 校准脚本 / CLI)与领域无关,无需改动。
前置要求:Python 3.10+(3.11 实测验证)、Node 18+。
1. 启动评测后端(端口 8100)
python3.11 -m venv .venv && source .venv/bin/activate
pip install -r backend/requirements.txt
cd backend
cp .env.example .env # 至少填 PRODUCT_API_URL;要用 L2 judge 再填 ANTHROPIC_API_KEY
python main.py # 起来后 http://localhost:8100/docs 可见全部 API2. 导入示例数据集、跑通 CLI(这一步不需要任何 API key)
python cli.py import --dataset legacy_v1 # 在仓库根目录执行,导入 20 个示例 case
python cli.py list3. 启动标注/实验 UI
cd frontend-v2
npm install && npm run dev # http://localhost:5200,/api 与 /ws 已代理到 81004. 跑一个实验(这一步需要被测 Agent 在线)
python cli.py run --dataset "Legacy Baseline V1" --tag first-run
python cli.py summary --experiment-id 1
python cli.py regression --latest --threshold 5依赖边界:run 需要 PRODUCT_API_URL 指向一个真实运行的被测 Agent;L2 judge 打分需要 ANTHROPIC_API_KEY。两者都没有时,import / list / UI 浏览 / 人工标注仍然全部可用。被测系统的隔离实例部署示例见 examples/azora/docker-compose.eval.yml。
backend/ # FastAPI 评测后端:api/ graders/ runner/ storage/ agent/
frontend/ # 标注与实验 UI(v1,含失效漏斗、分数趋势、实验对比)
frontend-v2/ # 标注与实验 UI(v2,datasets/evaluators/experiments/observation)
calibration/ # Judge 校准 few-shots(groundedness / actionability / rubric / trap)
datasets/ # 数据集(AZORA 案例:deepshop_v1 / legacy_v1)
scripts/ # 采样、标注、校准、回归、LangFuse 导出等工作流脚本
examples/azora/ # 第一个接入案例的部署配置
l2-codex/ # 跨厂商 L2 judge 实验(Codex SDK)
cli.py # 实验 CLI
ANNOTATION_GUIDE.md # 标注指南(AZORA 案例实例,可作为你的领域模板)
- 平台架构与被测系统解耦(HTTP 黑盒),但第一案例是购物研究场景:部分 grader(如
search_quality.py、retrieval_grader.py)和数据集带有该领域印记,接入新领域时按上文三层替换。 - 校准数值(阈值、TPR/TNR)以你自己数据上
validate_evaluator.py的输出为准——不要沿用案例中的数字。 - 生产 trace 导入目前对接 LangFuse(
scripts/export_langfuse.py)。
评测方法论对齐 Hamel Husain 的 evals 体系:错误分析先行、人工 gold 为锚、judge 必须校准、指标服务于迭代而非汇报。
与 openai/evals 定位互补:它是基准 registry + 模板化跑分(YAML 注册 + JSONL 数据 + oaieval CLI),适合横向比较模型能力,其 model-graded judge 为 zero-shot、校准手段只有 meta-eval 一致率(简单 accuracy,无 TPR/TNR、无数据划分);本平台是单一 Agent 产品的迭代评测系统——judge 校准做到 TPR/TNR + train/dev/test 划分 + few-shot 迭代,并自带标注 UI、回归门禁与生产 trace 回流。