关于 agent-eval-harness
agent-eval-harness 是面向 TypeScript/JavaScript 项目的命令行工具,用于捕获无头 CLI Agent 的执行轨迹。它输出结构化 JSONL,并提供汇总、评分、校准和运行对比等评估工作流。
主要功能
- 01捕获 Agent 思路、工具和计划轨迹
- 02以 JSONL 保存完整执行记录
- 03支持多次试运行与评分
- 04汇总、校准和验证参考答案
- 05分析测试集覆盖并比较运行结果
适用场景
- 01为 Agent 行为构建回归测试
- 02生成 SFT 或 DPO 训练数据
- 03比较不同模型或配置的 Agent
- 04抽查失败案例并校准评分器
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ youdotcom-oss/ agent-skills --skill agent-eval-harness安装后在 Claude Code 中输入/agent-eval-harness确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/docker-compose.eval.ymlDockerfile.evalreferences/calibration.mdcomparison-graders.mddocker-evals.mdeval-concepts.mdinline-graders.mdoutput-formats.md详细介绍
Agent Eval Harness
用途
用于从无头 CLI Agent 捕获执行轨迹的命令行工具,针对使用 Bun 的 TypeScript/JavaScript 项目进行了优化。
Harness 负责捕获。评分由你完成。
| Harness 提供 | 你提供 |
|---|---|
| 通过无头适配器执行提示词 | 评分逻辑(Braintrust、自定义脚本) |
| 完整捕获执行轨迹(思考、工具、计划) | 通过评分器判定通过/失败 |
| 结构化 JSONL 输出 | LLM-as-judge 提示词 |
| 可复现的执行环境 | CI 集成、黄金文件比较 |
适用于以下场景:
- 为下游评估捕获执行轨迹
- 在完整上下文中生成训练数据(SFT/DPO)
- 为 Agent 行为构建回归测试夹具
- 比较不同配置下的 Agent 响应
安装
# Run without installing (recommended)
bunx @plaited/agent-eval-harness capture prompts.jsonl --schema ./claude.json -o results.jsonl
# Or install as project dependency
bun add @plaited/agent-eval-harness
核心原则:捕获一次,派生多种视图
flowchart LR
Prompts["prompts.jsonl"] --> Capture["capture/trials"]
Schema["headless schema"] --> Capture
Capture --> Results["results.jsonl (full trajectory)"]
Results --> Summarize["summarize"]
Results --> Calibrate["calibrate"]
Results --> Custom["(your tools)"]
Summarize --> Views["summary.jsonl / .md"]
Calibrate --> Report["calibration.md"]
Custom --> Pipeline["any scoring platform"]
**单一输出格式:**完整执行轨迹 JSONL(始终如此)
**没有 --format 标志:**通过单独的命令派生视图
**Schema 导出:**提供 Zod Schema + JSON Schema,适用于各种工具
命令
核心命令
| 命令 | 输入 | 输出 | 用途 |
|---|---|---|---|
capture | prompts.jsonl + schema | results.jsonl | 捕获执行轨迹(完整) |
trials | prompts.jsonl + schema | trials.jsonl | 多次运行 + 可选指标 |
summarize | results.jsonl | summary.jsonl 或 .md | 派生精简视图 |
calibrate | results.jsonl | calibration.md | 抽取失败样本供审查 |
validate-refs | prompts.jsonl | validation.jsonl | 检查参考解答 |
balance | prompts.jsonl | balance.json | 分析测试集覆盖情况 |
schemas | (无) | JSON Schema | 为非 TS 用户导出 Schema |
管道命令(Unix 风格)
| 命令 | 输入 | 输出 | 用途 |
|---|---|---|---|
run | prompts.jsonl + schema | raw.jsonl | 执行提示词,输出原始结果 |
extract | raw.jsonl + schema | extracted.jsonl | 解析执行轨迹 |
grade | extracted.jsonl + grader | graded.jsonl | 应用评分器评分 |
format | results.jsonl | jsonl/markdown/csv | 转换输出格式 |
compare | 多个 results.jsonl | comparison.json | 比较运行结果(汇总报告) |
所有命令都支持使用可选参数 --grader ./grader.ts 进行评分。
Capture 命令
基本用法
bunx @plaited/agent-eval-harness capture <prompts.jsonl> --schema <schema.json> [options]
参数
| 参数/标志 | 描述 | 默认值 |
|---|---|---|
prompts.jsonl | 包含待执行提示词的输入文件 | 必填 |
-s, --schema | 无头适配器 Schema 的路径 | 必填 |
-o, --output | 输出文件/路径 | stdout |
-c, --cwd | Agent 的工作目录 | 当前目录 |
-t, --timeout | 请求超时时间,单位为 ms | 60000 |
-j, --concurrency | 并发工作进程数 | 1 |
--workspace-dir | 用于隔离每个提示词工作区的基目录 | 无 |
--progress | 在 stderr 中显示进度 | false |
--append | 追加到输出文件 | false |
-g, --grader | 评分器模块的路径 | 无 |
--debug | 显示详细的 CLI 输出以供调试 | false |
示例
# Basic capture
bunx @plaited/agent-eval-harness capture prompts.jsonl --schema ./claude.json -o results.jsonl
# Parallel execution (4x faster with 4 workers)
bunx @plaited/agent-eval-harness capture prompts.jsonl --schema ./claude.json -j 4 -o results.jsonl
# With workspace isolation for code generation tasks
bunx @plaited/agent-eval-harness capture prompts.jsonl --schema ./claude.json \
-j 4 --workspace-dir ./workspaces -o results.jsonl
# Using a local adapter script
bunx @plaited/agent-eval-harness capture prompts.jsonl bun ./my-adapter.ts -o results.jsonl
# With grader (adds score to each result)
bunx @plaited/agent-eval-harness capture prompts.jsonl --schema ./claude.json --grader ./grader.ts -o results.jsonl
Trials 命令
对每个提示词运行多次,以进行 pass@k/pass^k 分析。
# Capture only (no grader)
bunx @plaited/agent-eval-harness trials prompts.jsonl --schema ./claude.json -k 5 -o trials.jsonl
# With grader (computes pass@k, pass^k)
bunx @plaited/agent-eval-harness trials prompts.jsonl --schema ./claude.json -k 5 --grader ./grader.ts -o trials.jsonl
# Parallel execution (4 prompts' trials run concurrently)
bunx @plaited/agent-eval-harness trials prompts.jsonl --schema ./claude.json -k 5 -j 4 -o trials.jsonl
# With workspace isolation (each trial gets its own directory)
bunx @plaited/agent-eval-harness trials prompts.jsonl --schema ./claude.json -k 5 -j 4 \
--workspace-dir ./workspaces -o trials.jsonl
并行化说明:
-j/--concurrency会在不同提示词之间并行执行(不会并行执行同一提示词的多次试验)- 每个提示词的 k 次试验仍按顺序运行(聚合所需)
- 对于 151 个提示词,使用
-j 4时会有 4 个提示词同时运行试验 --workspace-dir会为每次试验创建{workspace-dir}/prompt-{id}-trial-{n}/- 进度日志会显示总体完成情况(例如,
12/50 prompts completed)
工作区清理: 完成后目录会保留,以便调试。请手动清理:
# After capture
rm -rf ./workspaces
# In CI (add as post-step)
- run: rm -rf ./workspaces
if: always()
输出
不使用评分器时:
{"id":"search-001","input":"Find the CEO","k":5,"trials":[{"trialNum":1,"output":"...","trajectory":[...],"duration":1234},...]}
使用评分器时:
{"id":"search-001","input":"Find the CEO","k":5,"passRate":0.8,"passAtK":0.99,"passExpK":0.33,"trials":[{"trialNum":1,"output":"...","pass":true,"score":1.0},...]}
Summarize 命令
从完整执行轨迹结果中派生精简视图。
# Summary JSONL (for jq analysis)
bunx @plaited/agent-eval-harness summarize results.jsonl -o summary.jsonl
# Markdown (for LLM-as-judge)
bunx @plaited/agent-eval-harness summarize results.jsonl --markdown -o results.md
Calibrate 命令
抽样检查失败案例,供评分器审核。校准有助于区分Agent 失败(Agent 做错了)和评分器错误(Agent 是正确的,但评分器过于严格)。
# Sample failures for human review
bunx @plaited/agent-eval-harness calibrate results.jsonl --sample 10 -o calibration.md
# Re-score with different grader to compare
bunx @plaited/agent-eval-harness calibrate results.jsonl --grader ./loose-grader.ts --sample 10 -o comparison.md
请参阅 eval-concepts.md,了解校准的重要性。
Validate-Refs 命令
在评估 Agent 之前,检查参考解决方案是否能通过你的评分器。
# Validate reference solutions
bunx @plaited/agent-eval-harness validate-refs prompts.jsonl --grader ./grader.ts -o validation.jsonl
# Check for failures
cat validation.jsonl | jq 'select(.pass == false)'
为什么要使用?
如果参考解决方案未能通过你自己的评分器:
- 任务定义含糊不清
- 评分器过于严格
- 提示有误
请先修复评估,再评估 Agent。
输入格式
提示词必须包含 reference 字段:
{"id":"test-001","input":"Create a button component","hint":"<button>","reference":"export const Button = () => <button>Click</button>"}
输出格式
{"id":"test-001","input":"Create a button component","reference":"export const Button = () => <button>Click</button>","pass":true,"score":1.0,"reasoning":"Contains hint content"}
Balance 命令
分析测试集覆盖范围,确保评估均衡。
# Analyze prompt distribution
bunx @plaited/agent-eval-harness balance prompts.jsonl -o balance.json
# Pretty print
bunx @plaited/agent-eval-harness balance prompts.jsonl | jq .
为什么要使用?
仅包含“让 X 正常工作”的评估会忽略“不要破坏 Y”。均衡性分析会展示:
- 类别分布(来自
metadata.category) - 正向/负向案例比例
- 覆盖缺口
输出格式
{
"totalCases": 50,
"categories": [
{ "name": "ui", "count": 20, "percentage": 40 },
{ "name": "logic", "count": 15, "percentage": 30 },
{ "name": "api", "count": 10, "percentage": 20 },
{ "name": "edge-case", "count": 5, "percentage": 10 }
],
"underrepresented": ["edge-case"],
"suggestions": ["Consider adding more test cases for: edge-case"]
}
均衡的评估设计
同时包含正向和负向案例:
| 类型 | 示例 | 目的 |
|---|---|---|
| 正向 | “添加一个登录按钮” | Agent 应该成功 |
| 负向 | “添加一个按钮,同时不破坏测试” | Agent 不应该破坏现有功能 |
| 边缘案例 | “妥善处理空输入” | Agent 应该具备鲁棒性 |
如需进一步了解均衡测试集,请参阅 eval-concepts.md。
Pipeline 工作流
Pipeline 命令支持 Unix 风格的组合方式,让评估工作流更加灵活。
完整 Pipeline 示例
# Execute → Extract → Grade → Format in one pipeline
cat prompts.jsonl | \
bunx @plaited/agent-eval-harness run -s claude.json | \
bunx @plaited/agent-eval-harness extract -s claude.json | \
bunx @plaited/agent-eval-harness grade -g ./grader.ts | \
bunx @plaited/agent-eval-harness format -f markdown > report.md
Run 命令
执行提示词并输出原始结果。提供三种模式:
# Schema mode (recommended)
bunx @plaited/agent-eval-harness run prompts.jsonl --schema claude.json
# Simple mode: {} placeholder substitution
bunx @plaited/agent-eval-harness run prompts.jsonl --simple "claude -p {} --output-format stream-json"
# Shell mode: $PROMPT environment variable
bunx @plaited/agent-eval-harness run prompts.jsonl --shell 'claude -p "$PROMPT" --output-format stream-json'
⚠️ 安全警告:
--simple和--shell模式会通过 Shell 命令执行提示词。虽然提示词会经过转义,但在这些模式下不要使用不可信的提示词内容。恶意提示词文本可能绕过引号转义并执行任意命令。对于不可信的输入,请使用--schema模式(无头适配器)。
Extract 命令
将原始输出解析为结构化轨迹:
# From file
bunx @plaited/agent-eval-harness extract raw.jsonl --schema claude.json -o extracted.jsonl
# Piped from run
bunx @plaited/agent-eval-harness run prompts.jsonl -s claude.json | \
bunx @plaited/agent-eval-harness extract -s claude.json
Grade 命令
对提取的结果应用评分器:
bunx @plaited/agent-eval-harness grade extracted.jsonl --grader ./grader.ts -o graded.jsonl
Format 命令
将结果转换为不同的输出格式:
# Markdown report
bunx @plaited/agent-eval-harness format results.jsonl --style markdown -o report.md
# CSV for spreadsheets
bunx @plaited/agent-eval-harness format results.jsonl --style csv -o results.csv
# JSONL (pass-through, default)
bunx @plaited/agent-eval-harness format results.jsonl --style jsonl
Compare 命令
比较同一组提示词的多次运行。支持 CaptureResult(单次运行)和 TrialResult(多次运行的可靠性)格式,并可自动检测。
# Default: auto-detect format, weighted strategy, JSON output
bunx @plaited/agent-eval-harness compare run1.jsonl run2.jsonl -o comparison.json
# Statistical significance strategy
bunx @plaited/agent-eval-harness compare run1.jsonl run2.jsonl --strategy statistical -o comparison.json
# Custom weights via environment variables (CaptureResult)
COMPARE_QUALITY=0.7 COMPARE_LATENCY=0.2 COMPARE_RELIABILITY=0.1 \
bunx @plaited/agent-eval-harness compare run1.jsonl run2.jsonl -o comparison.json
# Markdown report format
bunx @plaited/agent-eval-harness compare run1.jsonl run2.jsonl --format markdown -o report.md
# Custom grader (LLM-as-Judge)
bunx @plaited/agent-eval-harness compare run1.jsonl run2.jsonl \
--strategy custom --grader ./my-llm-judge.ts -o comparison.json
# With explicit labels
bunx @plaited/agent-eval-harness compare \
--run "with-mcp:results-mcp.jsonl" \
--run "vanilla:results-vanilla.jsonl" \
-o comparison.json
Compare 的使用场景:
- 同一 Agent 使用不同的 MCP 服务
- 同一 Agent 启用不同的技能
- 同一 Agent 使用不同版本的模型
- 完全不同的 Agent
Trials 比较(pass@k 分析)
比较 TrialResult 文件以分析可靠性:
# Auto-detect trials format
bunx @plaited/agent-eval-harness compare trials1.jsonl trials2.jsonl -o comparison.json
# Explicit format (skip auto-detection)
bunx @plaited/agent-eval-harness compare trials1.jsonl trials2.jsonl --input-format trials -o comparison.json
# Custom weights for trials comparison
COMPARE_CAPABILITY=0.5 COMPARE_RELIABILITY=0.3 COMPARE_CONSISTENCY=0.2 \
bunx @plaited/agent-eval-harness compare trials1.jsonl trials2.jsonl -o comparison.json
Trials 指标:
| 指标 | 说明 | 公式 |
|---|---|---|
| 能力(passAtK) | 在 K 次尝试中至少成功一次 | 1 - (1-p)^k |
| 可靠性(passExpK) | 每次都能稳定成功 | p^k |
| 不稳定性 | 能力与可靠性之间的差距 | passAtK - passExpK |
| 质量(分数) | 汇总各次试验的评分器分数 | avg/median/p25/p75(仅在使用评分器时提供) |
| 性能(延迟) | 汇总各次试验的持续时间 | p50/p90/p99/mean/min/max(始终提供) |
内置比较策略
对于 CaptureResult(单次运行):
| 策略 | 描述 | 环境变量 |
|---|---|---|
weighted(默认) | 质量、延迟、可靠性 | COMPARE_QUALITY、COMPARE_LATENCY、COMPARE_RELIABILITY |
statistical | 使用 Bootstrap 计算置信区间 | COMPARE_BOOTSTRAP_ITERATIONS |
custom | 自定义评分器 | --grader path |
对于 TrialResult(多次运行):
| 策略 | 描述 | 环境变量 |
|---|---|---|
weighted(默认) | 能力、可靠性、一致性 | COMPARE_CAPABILITY、COMPARE_RELIABILITY、COMPARE_CONSISTENCY |
statistical | 使用 Bootstrap 计算 passAtK 置信区间 | COMPARE_BOOTSTRAP_ITERATIONS |
custom | 自定义评分器 | --grader path |
比较报告输出
CaptureResult 格式输出 ComparisonReport:
{
"meta": { "generatedAt": "...", "runs": ["baseline", "variant"], "promptCount": 100 },
"quality": { "baseline": { "avgScore": 0.85, "passRate": 0.82 }, "variant": { ... } },
"performance": { "baseline": { "latency": { "p50": 1200, "p90": 3400 } }, ... },
"reliability": { "baseline": { "type": "run", "toolErrors": 5, "completionRate": 0.99 }, ... },
"headToHead": { "pairwise": [{ "runA": "baseline", "runB": "variant", "aWins": 35, "bWins": 55 }] }
}
使用 --strategy statistical 时,质量和性能指标会包含 95% 置信区间:
{
"quality": {
"baseline": {
"avgScore": 0.85,
"passRate": 0.82,
"confidenceIntervals": {
"avgScore": [0.82, 0.88],
"passRate": [0.79, 0.85]
}
}
},
"performance": {
"baseline": {
"latency": { "p50": 1200, "mean": 1350 },
"confidenceIntervals": {
"latencyMean": [1280, 1420]
}
}
}
}
TrialResult 格式输出 TrialsComparisonReport:
{
"meta": { "generatedAt": "...", "runs": ["claude", "gemini"], "promptCount": 50, "trialsPerPrompt": 5, "inputFormat": "trials" },
"capability": { "claude": { "avgPassAtK": 0.92, "medianPassAtK": 0.95 }, "gemini": { "..." : "..." } },
"reliability": { "claude": { "type": "trial", "avgPassExpK": 0.78, "medianPassExpK": 0.82 }, "gemini": { "..." : "..." } },
"flakiness": { "claude": { "avgFlakiness": 0.14, "flakyPromptCount": 12 }, "gemini": { "..." : "..." } },
"quality": { "claude": { "avgScore": 0.85, "medianScore": 0.90, "p25Score": 0.75, "p75Score": 0.95 }, "gemini": { "..." : "..." } },
"performance": { "claude": { "latency": { "p50": 1200, "p90": 3400, "p99": 5100, "mean": 1500, "min": 800, "max": 5200 }, "totalDuration": 375000 }, "gemini": { "..." : "..." } },
"headToHead": {
"capability": [{ "runA": "claude", "runB": "gemini", "aWins": 28, "bWins": 18, "ties": 4 }],
"reliability": ["..."],
"overall": ["..."]
}
}
注意:
- 只有使用了评分器时才会包含
quality(试验包含score字段) - 始终包含
performance(每次试验都有duration)
使用 --strategy statistical 时,能力、可靠性、质量和性能指标会包含 95% 置信区间:
{
"capability": {
"claude": {
"avgPassAtK": 0.92,
"confidenceIntervals": { "avgPassAtK": [0.88, 0.95] }
}
},
"reliability": {
"claude": {
"type": "trial",
"avgPassExpK": 0.78,
"confidenceIntervals": { "avgPassExpK": [0.72, 0.84] }
}
},
"quality": {
"claude": {
"avgScore": 0.85,
"confidenceIntervals": { "avgScore": [0.82, 0.88] }
}
},
"performance": {
"claude": {
"latency": { "mean": 1500 },
"confidenceIntervals": { "latencyMean": [1380, 1620] }
}
}
}
完整的比较评分器文档(包括 LLM-as-Judge 模式)请参阅 comparison-graders.md。
比较评分器接口
CaptureResult 评分器:
import type { ComparisonGrader } from '@plaited/agent-eval-harness/pipeline'
export const grade: ComparisonGrader = async ({ id, input, hint, runs }) => {
// runs is Record<string, { output, trajectory?, score?, duration?, toolErrors? }>
return {
rankings: [
{ run: 'with-mcp', rank: 1, score: 0.9 },
{ run: 'vanilla', rank: 2, score: 0.7 },
],
reasoning: 'MCP run produced more accurate output'
}
}
TrialResult 评分器:
import type { TrialsComparisonGrader } from '@plaited/agent-eval-harness/pipeline'
export const grade: TrialsComparisonGrader = async ({ id, input, hint, runs }) => {
// runs is Record<string, { passAtK?, passExpK?, k, trials }>
// Each trial in trials has: { duration, score?, pass?, output, trajectory }
return {
rankings: [
{ run: 'claude', rank: 1, score: 0.92 },
{ run: 'gemini', rank: 2, score: 0.85 },
],
reasoning: 'Claude has higher reliability with lower flakiness'
}
}
流水线工作流图
flowchart LR
Prompts["prompts.jsonl"] --> Run["run"]
Schema["headless schema"] --> Run
Run --> Raw["raw.jsonl"]
Raw --> Extract["extract"]
Schema --> Extract
Extract --> Extracted["extracted.jsonl"]
Extracted --> Grade["grade"]
Grader["grader.ts"] --> Grade
Grade --> Graded["graded.jsonl"]
Graded --> Format["format"]
Format --> Output["report.md / .csv / .jsonl"]
Graded --> Compare["compare"]
Results2["other runs..."] --> Compare
CompareGrader["compare-grader.ts"] --> Compare
Compare --> Comparison["comparison.jsonl"]
Schemas 命令
为非 TypeScript 工具导出 JSON schemas。
# List available schemas
bunx @plaited/agent-eval-harness schemas
# Export all schemas as JSON
bunx @plaited/agent-eval-harness schemas --json -o schemas.json
# Export specific schema
bunx @plaited/agent-eval-harness schemas CaptureResult --json
bunx @plaited/agent-eval-harness schemas TrialResult --json
bunx @plaited/agent-eval-harness schemas GraderResult --json
可用的 Schema
| Schema | 描述 |
|---|---|
CaptureResult | 单次捕获输出(id、input、output、trajectory、timing) |
TrialResult | 多次运行试验输出(包含 passAtK、passExpK) |
GraderResult | 评分器返回值(pass、score、reasoning) |
PromptInput | 输入提示词格式 |
TrajectoryStep | trajectory 数组中的单个步骤 |
SummaryResult | 紧凑摘要格式 |
在其他语言中的用法
导出 schema,以便在 Python、Go 等语言中进行验证:
# Export all schemas
bunx @plaited/agent-eval-harness schemas --json -o schemas.json
# Use in Python with jsonschema
python -c "
import json
from jsonschema import validate
with open('schemas.json') as f:
schemas = json.load(f)
with open('results.jsonl') as f:
for line in f:
result = json.loads(line)
validate(result, schemas['CaptureResult'])
print(f'{result[\"id\"]}: valid')
"
评分器接口
评分器为捕获的轨迹提供语义层面的通过/失败评分。该测试框架支持使用任何语言编写的评分器。
基于 Git 的评分(推荐用于编码任务)
评估结果,而非路径。 使用可选的 cwd 参数,通过 git 检测环境变化:
// git-grader.ts
import type { Grader } from '@plaited/agent-eval-harness/schemas'
export const grade: Grader = async ({ output, hint, cwd }) => {
if (!cwd) return { pass: false, score: 0, reasoning: 'No cwd' }
// Detect file changes
const status = await Bun.$`git -C ${cwd} status --porcelain`.text()
const filesCreated = status
.split('\n')
.filter(line => line.startsWith('??'))
.map(line => line.slice(3).trim())
// Verify tests pass
const testResult = await Bun.$`cd ${cwd} && bun test`.nothrow()
return {
pass: filesCreated.length > 0 && testResult.exitCode === 0,
score: testResult.exitCode === 0 ? 1 : 0,
reasoning: `Files: ${filesCreated.join(', ')}. Tests: ${testResult.exitCode === 0 ? 'pass' : 'fail'}`,
outcome: { // Optional: structured data for analysis
filesCreated,
testsPassed: testResult.exitCode === 0,
type: 'file_creation_with_tests'
}
}
}
有关全面的基于 git 的评分模式,请参阅 inline-graders.md。
基于输出的评分(通用)
// my-grader.ts
import type { Grader } from '@plaited/agent-eval-harness/schemas'
export const grade: Grader = async ({ input, output, hint, trajectory }) => {
const pass = output.toLowerCase().includes(hint?.toLowerCase() ?? '')
return {
pass,
score: pass ? 1 : 0,
reasoning: pass ? 'Contains hint content' : 'Missing hint content'
}
}
注意: input 可以是 string(单轮)或 string[](多轮)。hint 字段为评分器提供上下文(由 expected 更名而来)。
Python/可执行文件评分器
任何可执行文件都可以作为评分器,使用 stdin/stdout JSON 协议:
#!/usr/bin/env python3
import json, sys
data = json.load(sys.stdin)
output = data.get("output", "").lower()
hint = (data.get("hint") or "").lower()
pass_result = hint in output if hint else True
print(json.dumps({
"pass": pass_result,
"score": 1.0 if pass_result else 0.0,
"reasoning": "Contains hint" if pass_result else "Missing hint"
}))
chmod +x ./grader.py
bunx @plaited/agent-eval-harness capture prompts.jsonl --schema ./claude.json --grader ./grader.py -o results.jsonl
完整的评分器文档(包括 LLM-as-Judge 模式)请参阅 inline-graders.md。
输入格式
prompts.jsonl 中的每一行:
{"id":"test-001","input":"Create a button","hint":"should contain <button>"}
{"id":"test-002","input":["Create a button","Make it blue"],"metadata":{"category":"ui"}}
| 字段 | 必填 | 描述 |
|---|---|---|
id | 是 | 唯一标识符 |
input | 是 | 单个提示词(string)或对话轮次(string[]) |
hint | 否 | 评分器上下文——需要关注的内容(不是严格匹配) |
reference | 否 | 参考解决方案(用于 validate-refs) |
metadata | 否 | 用于筛选的标签、类别、难度 |
timeout | 否 | 覆盖此提示词的默认超时时间 |
会话行为: 每条 JSONL 记录 = 1 个全新会话
input: string→ 1 个会话,1 条提示词input: string[]→ 1 个会话,N 条提示词(按顺序进行多轮交互)
输出格式
完整轨迹 JSONL(始终输出):
{
"id": "test-001",
"input": "Find the CEO of Anthropic",
"output": "The CEO of Anthropic is Dario Amodei.",
"hint": "should mention Dario Amodei",
"trajectory": [
{"type": "thought", "content": "I'll search for this...", "timestamp": 100},
{"type": "tool_call", "name": "WebSearch", "status": "completed", "input": {...}, "output": {...}, "duration": 500},
{"type": "message", "content": "The CEO of Anthropic is Dario Amodei.", "timestamp": 700}
],
"metadata": {
"category": "search",
"agent": "--schema ./claude.json",
"trajectoryRichness": "full",
"turnCount": 1
},
"timing": {
"start": 1704067200000,
"end": 1704067201234,
"firstResponse": 100,
"sessionCreation": 234,
"total": 1234,
"inputTokens": 150,
"outputTokens": 85
},
"toolErrors": false
}
输出字段
| 字段 | 描述 |
|---|---|
input | 原始提示词(多轮对话时为字符串或 string[]) |
hint | 评分器上下文提示(如果提供) |
metadata.trajectoryRichness | "full" | "messages-only" | "minimal" |
metadata.turnCount | 对话轮数(字符串为 1,数组为 N) |
timing.sessionCreation | 创建会话所需时间(ms) |
timing.total | 总耗时(结束时间 - 开始时间) |
timing.inputTokens | 消耗的输入 token 数(如果适配器提供) |
timing.outputTokens | 生成的输出 token 数(如果适配器提供) |
toolErrors | 是否有工具调用失败 |
注意: toolErrors 用来替代容易产生误导的 status: 'passed'|'failed'。实际的通过/失败结果由你的评分器决定。
架构导出
使用者可以直接导入 Zod 架构:
import { CaptureResultSchema, TrialResultSchema } from '@plaited/agent-eval-harness/schemas'
// Validate external data
const result = CaptureResultSchema.parse(jsonData)
// Generate JSON Schema (Zod 4 native)
import * as z from 'zod'
const jsonSchema = z.toJSONSchema(CaptureResultSchema)
可靠性指标的判别联合类型
可靠性指标包含 type 判别字段,可进行类型安全的解析:
import * as z from 'zod'
import {
ReliabilityMetricsSchema, // type: 'run'
TrialsReliabilityMetricsSchema // type: 'trial'
} from '@plaited/agent-eval-harness/schemas'
// Create a unified schema for both metric types
const UnifiedReliabilitySchema = z.discriminatedUnion('type', [
ReliabilityMetricsSchema,
TrialsReliabilityMetricsSchema,
])
// Type-safe parsing with automatic narrowing
const metrics = UnifiedReliabilitySchema.parse(data)
if (metrics.type === 'run') {
// TypeScript knows: ReliabilityMetrics
console.log(metrics.toolErrors, metrics.completionRate)
} else {
// TypeScript knows: TrialsReliabilityMetrics
console.log(metrics.avgPassExpK, metrics.medianPassExpK)
}
也可以为非 TypeScript 工具导出 JSON 架构:
bunx @plaited/agent-eval-harness schemas --json -o schemas.json
bunx @plaited/agent-eval-harness schemas CaptureResult --json
执行环境
建议: 在 Docker 容器中运行测试框架,以确保执行环境一致且相互隔离。
# Run integration tests via Docker
docker compose -f docker-compose.test.yml run --rm test
# Or with explicit API keys
ANTHROPIC_API_KEY=sk-... GEMINI_API_KEY=... docker compose -f docker-compose.test.yml run --rm test
Docker 要求
| 要求 | 原因 |
|---|---|
| Node.js 24+ | Gemini CLI 使用现代 JS 特性(可选链) |
| 非 root 用户 | Claude CLI 会阻止 root 用户使用 --dangerously-skip-permissions |
| Gemini API 密钥 | 为 Gemini CLI 传入 GEMINI_API_KEY |
请参阅 docker-evals.md,了解完整的 Docker 设置指南、调试技巧和 CI 集成模式。
多轮对话
使用 input: string[] 在单个会话中执行多轮对话:
{"id":"context-001","input":["Remember this number: 42","What number did I ask you to remember?"],"hint":"42"}
{"id":"context-002","input":["My name is Alice","What is my name?"],"hint":"Alice"}
使用无头适配器运行:
# Using Claude Code via headless adapter
bunx @plaited/agent-eval-harness capture multi-turn.jsonl \
bunx @plaited/agent-eval-harness headless --schema ./claude-headless.json \
-o results.jsonl
# Using Gemini CLI via headless adapter
GEMINI_API_KEY=... bunx @plaited/agent-eval-harness capture multi-turn.jsonl \
bunx @plaited/agent-eval-harness headless --schema ./gemini-headless.json \
-o results.jsonl
要点:
- 每条 JSONL 记录 = 一个全新的会话
input: string[]会将连续的轮次发送到同一个会话- 兼容
stream模式(Claude)和iterative模式(Gemini) - 适配器会自动保留上下文
下游集成
测试框架会输出标准 JSONL,可将其传递给任何工具:
# Filter with jq
cat results.jsonl | jq 'select(.metadata.category == "ui")'
# Count tool usage
cat results.jsonl | jq -s 'map(.trajectory | map(select(.type == "tool_call")) | length) | add'
# Summarize for quick analysis
bunx @plaited/agent-eval-harness summarize results.jsonl -o summary.jsonl
# Compare runs with built-in strategies
bunx @plaited/agent-eval-harness compare run1.jsonl run2.jsonl -o comparison.json
快速参考
| 资源 | 描述 |
|---|---|
bunx @plaited/agent-eval-harness | CLI 帮助 |
| output-formats.md | JSONL 架构、命令详情 |
| inline-graders.md | 单输入/输出评分器(TypeScript、Python、shell) |
| comparison-graders.md | 比较策略(加权、统计、LLM 评审) |
| calibration.md | 评分器校准工作流 |
| eval-concepts.md | 评估概念(pass@k、pass^k) |
| docker-evals.md | Docker 设置、调试、CI 集成 |
相关内容
- headless-adapters skill - 面向无头 CLI Agent 的架构驱动适配器