28. 案例研究(二):代码 Agent 的三层评估落地
如果只读一节:代码 Agent 的评估 = 自动层(HumanEval+ / LiveCodeBench 跑分)+ 业务层(接受率、修改距离、自建 SWE-bench 风格内测集)+ 人工层(每周 rubric 抽检)。三层各答一个问题:能不能做题、有没有人用、用着舒不舒服。基准知识在 第 11 章,本章讲三层怎么在一个真实团队里落地。
前置知识:第 11 章(代码基准)、第 20 章(mini evaluator 与沙箱)、第 6 章(人类评估与 Kappa)、第 25 章(CI 门禁)。本章代码全部为 TypeScript。
28.1 本章目标与读者
读完后你能:
- 为一个代码补全 / 代码生成产品搭起三层评估,知道每层的触发时机与成本量级
- 从自家仓库挑出 30 个已修复 Issue,造一个 SWE-bench 风格的内测集,并用 golden patch 验证它不是"评分抽签"
- 设计接受率与修改距离的埋点,避开让指标失真的四个埋点坑
场景设定(合成案例):一个 SaaS 团队在做 VS Code 插件形态的 AI 代码助手,能力包括行内补全、函数生成、Bug 修复建议。团队目标写的是"帮前端工程师提效 30%"——这句话不可测,本章第一件事就是把它拆成三层可测的指标。基准本身的原理(HumanEval 为什么饱和、LiveCodeBench 怎么防污染、SWE-bench 的口径战争)全部在第 11 章,本章只做"怎么跑、怎么用"。
28.2 概念引入:三层评估 = 单测、埋点、代码评审
前端类比:给代码 Agent 建评估 ≈ 评估一个"自动重构机器人"——第一层像单元测试(跑得过就是跑得过),第二层像产品埋点(功能被点开了多少次、点开后有没有改),第三层像代码评审(评审员按 checklist 打分)。三层缺一:只有第一层是"会做题不会干活",只有第二层是"有人用但不知道为什么好",只有第三层是"主观印象没有规模"。
先定义被测物。与第 27 章同理,评估瞄准的是事件流,不是模型输出本身:
// code-agent/types.ts —— 建议生命周期事件契约(无需联网)
// 每一次"插件给出建议"都会产生一条 suggestion 事件,之后跟随一条结果事件
export interface SuggestionEvent {
id: string;
ts: number;
userId: string; // 脱敏后的设备标识
kind: "inline" | "function" | "fix"; // 补全 / 函数生成 / Bug 修复
language: "ts" | "tsx" | "js" | "python";
model: string; // 被测模型版本
promptVersion: string; // 提示词版本——三层归因的关键字段
latencyMs: number;
shown: boolean; // 是否真正展示给用户(防止把未展示算进分母)
}
export type SuggestionOutcome =
| { id: string; action: "accepted"; editedLines: number; finalCode: string }
| { id: string; action: "rejected" }
| { id: string; action: "ignored"; dwellMs: number } // 展示后未交互
| { id: string; action: "expired" }; // 用户已输入,建议作废expired 和 ignored 这两个状态是后面所有指标不出错的前提——漏掉它们,接受率的分母就错了。
28.3 三层评估的蓝图
| 层 | 回答的问题 | 数据 | 频率 | 成本量级 | 决策联动 |
|---|---|---|---|---|---|
| 自动层 | 模型能不能做题 | HumanEval+ / LiveCodeBench / 自建 TS 集 | 每次模型或 prompt 变更 | 数美元/次 | PR 门禁(硬) |
| 业务层 | 功能有没有人用、用得顺不顺 | 生产埋点 + 自建内测集 | 每周汇总 | 近零(埋点)+ 内测集数美元 | 周报(软) |
| 人工层 | 代码质量与风格是否可接受 | 50 条/周人工 rubric 抽检 | 每周 | 约 1 小时×3 人 | 月度校准与改进项 |
flowchart LR
PR["模型/prompt 变更 PR"] --> AUTO["自动层<br/>HumanEval+ / LiveCodeBench / TS 自建集<br/>硬门禁"]
AUTO -->|"过"| REL["发布到灰度通道"]
REL --> PROD["生产使用"]
PROD --> BIZ["业务层<br/>接受率 / 修改距离 / 内测集"]
PROD --> HUMAN["人工层<br/>每周 50 条 rubric 抽检"]
BIZ --> WK["周报:三层读数并排"]
HUMAN --> WK
WK -->|"改进项"| PR
三层的关系不是"从上到下越来越重要",而是各自回答一个别的层答不了的问题。下面按落地顺序展开。
28.4 自动层:HumanEval+ 与 LiveCodeBench
28.4.1 选集与分工
自动层的选集直接引用第 11 章的结论:
| 集 | 用途 | 注意事项 |
|---|---|---|
| HumanEval+(arXiv:2305.01210) | 冒烟与回归,每题约 80 倍测试密度 | 头部模型已 90%+(来源:第 11 章 11.3 节),只降不升说明它在退场 |
| LiveCodeBench(arXiv:2403.07974) | 防污染的能力探针 | 各家选窗不同,分数不可跨报告横比;自己跑要固定窗口并记录 |
| 自建 TS/React 集(200 题) | 与业务语言对齐 | 公开集几乎全是 Python——前端团队必须自建这一档 |
自建集的题目结构复用第 11 章 11.11 节的最小评估器:题面 + 测试 + 入口函数名,评分是"沙箱里跑测试"。执行验证的关键工程件是超时与隔离——模型生成的代码必须当作不可信输入处理:
// code-agent/run-suite.ts —— 沙箱执行生成的 TS 代码(本地运行;测试样本需自备)
// 运行:npx tsx code-agent/run-suite.ts data/ts-tasks.jsonl
import { spawnSync } from "node:child_process";
import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { readFileSync } from "node:fs";
interface TsTask { id: string; prompt: string; test: string; category: string; }
export function runOne(task: TsTask, completion: string): { pass: boolean; reason: string } {
const dir = mkdtempSync(join(tmpdir(), "code-eval-"));
try {
// 生成的代码 + 测试写进独立临时目录:互相不可见,跑完即删
writeFileSync(join(dir, "solution.ts"), `${task.prompt}\n${completion}\n${task.test}\n`);
const r = spawnSync("npx", ["tsx", join(dir, "solution.ts")], {
cwd: dir,
timeout: 10_000, // 必须有超时:死循环是模型的高频失败模式
stdio: "pipe",
env: { ...process.env, NODE_OPTIONS: "--no-experimental-strip-types" },
});
// 退出码 0 且 stderr 无未捕获异常 → 通过;其余一律按失败并保留原因
const clean = r.status === 0 && !/Unhandled error|AssertionError/.test(r.stderr.toString());
return { pass: clean, reason: clean ? "ok" : r.stderr.toString().slice(0, 300) };
} finally {
rmSync(dir, { recursive: true, force: true });
}
}
const tasks: TsTask[] = readFileSync(process.argv[2] ?? "data/ts-tasks.jsonl", "utf-8")
.trim().split("\n").map(JSON.parse);
let pass = 0;
for (const t of tasks) {
const completion = await solve(t); // solve:调用被测模型,见第 20 章 17.3
const r = runOne(t, completion);
if (r.pass) pass++;
else console.error(`FAIL ${t.id} [${t.category}] ${r.reason.split("\n")[0]}`);
}
console.log(`pass_rate=${(pass / tasks.length).toFixed(3)} n=${tasks.length}`);
// 期望输出示例:pass_rate=0.875 n=200三个工程纪律:并发要有界(第 20 章 17.5 的 mapPool,无限 Promise.all 会触发限流并静默丢样本);温度固定为 0(否则两次 run 的差异无法归因);失败样本的 stderr 前 300 字符必须落盘——它是下一轮改进的全部线索。
28.4.2 自动层的门槛语义
自动层是硬门禁(第 25 章 24.3),但阈值要按"集"分:自建 200 题上 pass 率不许低于上版 3 个百分点;HumanEval+ 只做"不许大幅倒退"的底线检查(它已饱和,区分度不足);LiveCodeBench 固定时间窗,只跟自己历史比。
28.5 业务层(一):接受率与修改距离的埋点
28.5.1 指标定义
| 指标 | 定义 | 评分方式 | 目标 | 数据来源 |
|---|---|---|---|---|
| 展示接受率 | accepted /(accepted + rejected) | 事件计数(确定性) | 建立自家基线,逐版 +3pp | IDE 埋点 |
| 一次通过率 | accepted 且 editedLines = 0 的比例 | 事件计数 | 趋势上升 | IDE 埋点 |
| 修改距离 | 接受后用户手改的行数 / 建议行数 | diff 统计(确定性) | 中位数 ≤ 5 行 | IDE + git |
| 回归引入率 | 采纳的 fix 建议合并后导致测试回退 | 事后 CI 数据回查 | 趋近 0 | 仓库 CI |
两个刻意的定义选择,直接决定指标能不能被信任:
第一,分母不含 ignored 和 expired。 "展示了但没交互"既不是接受也不是拒绝——把它算进分母会人为压低接受率,把它剔除又可能掩盖"建议太差没人理"。行业通行做法是单列观察,不进主指标("代码助手用户接受率"的行业统一基准值未能查证——各家产品口径不一,第 3 章 4.6.2 有同样声明;可依赖的只有自家基线的相对变化)。
第二,修改距离按行数 diff 而不是字符编辑距离。 前端类比:Prettier 重排了 import 顺序的"大编辑距离"没有信息量,改错变量名的"小编辑距离"才是灾难。按行 diff 让指标对"无意义格式差异"不敏感:
// code-agent/biz-metrics.ts —— 从事件日志聚合业务层指标(本地运行,无需联网)
// 运行:npx tsx code-agent/biz-metrics.ts data/events.jsonl
import { readFileSync } from "node:fs";
type Event = import("./types.ts").SuggestionEvent | import("./types.ts").SuggestionOutcome;
const lines = readFileSync(process.argv[2] ?? "data/events.jsonl", "utf-8").trim().split("\n");
const events: Event[] = lines.map(JSON.parse);
const shown = new Map(events.filter(e => "kind" in e && e.shown).map(e => [e.id, e]));
const outcomes = events.filter(e => "action" in e && shown.has(e.id));
const accepted = outcomes.filter(o => o.action === "accepted");
const rejected = outcomes.filter(o => o.action === "rejected");
const ignored = outcomes.filter(o => o.action === "ignored");
const acceptance = accepted.length / Math.max(accepted.length + rejected.length, 1);
const perfect = accepted.filter(o => o.editedLines === 0).length / Math.max(accepted.length, 1);
const ignoreRate = ignored.length / shown.size;
console.log({
acceptanceRate: acceptance.toFixed(3), // 展示接受率
perfectAcceptRate: perfect.toFixed(3), // 零修改直接接受
ignoreRate: ignoreRate.toFixed(3), // 展示后无交互(单列观察,不进主指标)
n: accepted.length + rejected.length,
});
// 期望输出示例:{ acceptanceRate: '0.371', perfectAcceptRate: '0.588', ignoreRate: '0.212', n: 8620 }28.5.2 埋点的四个坑
- 漏掉
expired:用户继续打字时建议作废,不记录就会把"手速快的用户"算成"全部拒绝",接受率被系统性压低。 - 按用户求平均而不是按建议求和:10 个重度用户和 1 个轻度用户的平均使用量会扭曲周报;分母永远是建议次数。
- 混淆相关性 causality:接受率高的团队可能只是 prompt 版本新,也可能是他们项目简单——归因时必须带
promptVersion与项目维度切片。 - 拿接受率当唯一 KPI 考核:接受率可以被"保守建议"刷高(只建议最安全的补全),必须与修改距离、人工层评分并列看。
28.5.3 业务效果怎么锚:引用研究的口径
"提效 30%"这类目标需要一个外部参照系。常被引用的一手证据是 GitHub 的随机对照实验(来源:Peng, Kalliamvakou, Cihon, Demirer,arXiv:2302.06590,Microsoft Research / GitHub):8 个开发者实现同一个 JavaScript HTTP 服务器,使用 AI 结对编程的实验组完成速度快 55.8%(95% 置信区间约 21%–89%,实验组约 71 分钟 vs 对照组约 161 分钟)。引用时必须带三个限定:样本量小(n=8 的实验)、任务单一(单文件新写,不含仓库内改造)、测的是速度而不是质量。同团队的问卷研究(来源:github.blog 2022《Research: quantifying GitHub Copilot's impact on developer productivity and happiness》)报告了主观感受维度,属于调查数据,不能与 RCT 混用。把 55.8% 直接换算成自己产品的"提效 30%"承诺是不成立的——正确的用法是:把 RCT 的测量思想(同任务、对照组、计时)搬进你的内测集,让业务层也有自己的对照实验。
28.6 业务层(二):SWE-bench 风格内测集(从自家仓库挑 30 个已修复 Issue)
28.6.1 构建流程
公开 SWE-bench 测的是"陌生开源仓库的 Issue",你的产品实际工作在"用户自己的仓库"里。内测集就是把 SWE-bench 的构造方法搬到自家代码库(合成案例:一个 3 年历史的 monorepo):
1. 筛选:近 12 个月已合并的 bugfix PR,过滤条件——
· 带有可复现的测试改动(test patch 存在)
· 改动 ≤ 5 个源文件(排除大规模重构)
· 模块分布覆盖 P0 路径(结算、登录、权限),不是只挑好修的
2. 固化:每个 Issue 记录 base_commit / issue 正文 / golden patch / test patch
3. 脱敏:业务字段改名、删除内网地址——内测集会进 CI 日志
4. 版本:swe-cases v1.0 锁定(30 例),改动永远新建版本30 例的构成建议(合成案例的配比,按业务权重而非难度分布):核心业务逻辑 12、纯工具函数 6、状态管理 6、构建/配置 3、跨模块联动 3。
28.6.2 Harness 与 golden patch 自检
每个案例的评估循环:checkout 到 base_commit → 把 Issue 正文喂给 Agent → Agent 产出 patch → 应用 test patch → 跑测试。构建完先跑一次"标准答案考试":把 golden patch 喂进 harness,它必须得满分;打上反向 patch(把修复改回错误版本)必须得零分——这是第 20 章 17.7.2 的 harness 自检,也是 ABC 论文对 SWE-bench Verified"测试用例不足"批评(第 11 章 7.5.7)的工程对策:测试套件本身要审计,否则评分是抽签(来源:Establishing Best Practices for Building Rigorous Agentic Benchmarks,arXiv:2507.02825)。
// code-agent/swe-case.ts —— 内测集单例执行(需本机 git 与 node;Agent 调用需联网)
// 运行:npx tsx code-agent/swe-case.ts swe-cases/issue-0142.json
import { spawnSync } from "node:child_process";
import { readFileSync, writeFileSync, mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
interface SweCase {
id: string; repoUrl: string; baseCommit: string;
issueText: string; goldenPatch: string; testPatch: string; testCmd: string;
}
function sh(cmd: string, cwd: string, timeoutMs = 300_000) {
return spawnSync("bash", ["-c", cmd], { cwd, timeout: timeoutMs, stdio: "pipe" });
}
export async function runSweCase(c: SweCase, producePatch: (issue: string, cwd: string) => Promise<string>) {
const dir = mkdtempSync(join(tmpdir(), "swe-"));
try {
// 1. 固定到 Issue 发生前的提交,保证起点一致
sh(`git clone --quiet ${c.repoUrl} . && git checkout --quiet ${c.baseCommit}`, dir);
// 2. Agent 只拿到 Issue 正文与工作目录,产出 unified diff
const patch = await producePatch(c.issueText, dir);
writeFileSync(join(dir, "model.patch"), patch);
if (sh("git apply --whitespace=nowarn model.patch", dir).status !== 0)
return { id: c.id, pass: false, reason: "patch 不适用" };
// 3. 测试补丁单独打:Agent 看不到测试内容,防止"对着测试写代码"
writeFileSync(join(dir, "test.patch"), c.testPatch);
sh("git apply test.patch", dir);
// 4. 唯一裁判是仓库自己的测试
const r = sh(c.testCmd, dir);
return { id: c.id, pass: r.status === 0, reason: r.status === 0 ? "ok" : "tests failed" };
} finally {
rmSync(dir, { recursive: true, force: true });
}
}
// 自检入口:golden patch 必须满分(放进 CI,断言失败即整个内测集不可信)
const c: SweCase = JSON.parse(readFileSync(process.argv[2]!, "utf-8"));
const verdict = await runSweCase(c, async () => c.goldenPatch);
console.log(verdict.pass ? "harness 自检通过" : "harness 有缺陷:golden patch 未通过");
process.exitCode = verdict.pass ? 0 : 1;沙箱安全提醒:Agent 产出的 patch 会真实进入你的文件系统并被执行。内测集执行必须在隔离环境(容器或一次性虚拟机)里跑,绝不在开发机直接执行——这是第 14 章 10.6"Agent 评估需要沙箱"的落地底线。
28.7 人工层:每周 50 条的 rubric 抽检
28.7.1 Rubric
四个维度,每维 1-5 分,评分定义写死到可以跨人复现(第 6 章 19.3 的评估员一致性原则):
| 维度 | 5 分 | 3 分 | 1 分 |
|---|---|---|---|
| 正确性 | 可直接合并,测试全绿 | 能跑但有 1 处逻辑错误需手改 | 编译不过或方向性错误 |
| 风格一致 | 与文件现有约定(命名/导入/类型风格)一致 | 需小幅调整 | 引入全新风格,评审必然打回 |
| 可维护性 | 命名自解释、复杂度与问题匹配 | 可读但要停下来推敲 | 深嵌套/超长函数 |
| 安全性 | 输入校验、无密钥硬编码、无注入面 | 有轻微隐患 | 引入明显漏洞(XSS/注入/密钥泄漏) |
28.7.2 流程与一致性
每周从埋点日志分层抽样 50 条(按 kind × language 分层,不是随机——否则补全类会淹没 fix 类),3 名工程师独立打分,全程盲评(看不到彼此分数、看不到是哪个模型版本)。一致性用 Cohen's Kappa(第 6 章 19.3),判读沿用第 7 章门槛:与人工共识一致率 ≥ 80%,Kappa ≥ 0.7;低于 0.4 说明 rubric 有歧义,先改 rubric 再评下一批。
// code-agent/agreement.ts —— 评分员一致性(本地运行,无需联网)
// 运行:npx tsx code-agent/agreement.ts data/weekly-ratings.json
import { readFileSync } from "node:fs";
// ratings: [{ id, rater: "a"|"b"|"c", scores: { correctness, style, maintainability, security } }]
const ratings: Array<{ id: string; rater: string; scores: Record<string, number> }> =
JSON.parse(readFileSync(process.argv[2]!, "utf-8"));
export function cohensKappa(a: number[], b: number[]): number {
const cats = [...new Set([...a, ...b])];
const n = a.length;
const po = a.filter((v, i) => v === b[i]).length / n; // 观察一致率
const pe = cats.reduce((s, c) =>
s + (a.filter(v => v === c).length / n) * (b.filter(v => v === c).length / n), 0);
return (po - pe) / (1 - pe); // 校正随机一致
}
const ids = [...new Set(ratings.map(r => r.id))];
for (const dim of ["correctness", "style", "maintainability", "security"] as const) {
const pair = ids.filter(id => ratings.filter(r => r.id === id).length >= 2)
.map(id => ratings.filter(r => r.id === id).slice(0, 2).map(r => r.scores[dim]));
const [a, b] = [pair.map(p => p[0]), pair.map(p => p[1])];
console.log(`${dim}: kappa=${cohensKappa(a, b).toFixed(2)} n=${a.length}`);
}
// 期望输出示例:correctness: kappa=0.74 n=50 (低于 0.4 的维度先修 rubric)人工层的产出不是分数,是改进项:每条 ≤3 分的样本都要归类("上下文不够""格式不符约定""过度设计"),归入下一轮 prompt 或检索策略的 backlog——这正是第 6 章"人工评估校准自动评估"的循环。
28.8 把三层读数并排放
周报的固定格式是三层并排,防止任何一层单维优化(合成数据示例):
| 周 | 自动层 TS 集 | 内测集 30 例 | 展示接受率 | 零修改接受 | 人工层均分 | 备注 |
|---|---|---|---|---|---|---|
| W32 | 0.875 | 0.70(21/30) | 0.371 | 0.588 | 3.4 | 上线 prompt v7 |
| W33 | 0.878 | 0.77(23/30) | 0.402 | 0.601 | 3.6 | v7 在 fix 类提升明显 |
| W34 | 0.881 | 0.73(22/30) | 0.398 | 0.545 | 3.3 | v8 回退:可维护性降分 |
W34 的读数值得注意:自动层满分、接受率持平,但人工层"可维护性"掉了——只有三层并排才能看到这类回归,单一指标会宣布"v8 没问题"。
28.9 实战与陷阱
陷阱 1:拿公开榜分数当产品承诺。 "我们 SWE-bench Verified 通过率 60%"与"能修你们仓库的 bug"之间隔着仓库差异、脚手架差异与子集裁剪(第 11 章 7.5 的口径战争)。公开榜用来缩圈选模型,内测集 30 例用来做决定。
陷阱 2:内测集的测试套件没审计。 某些案例的测试太弱,错误 patch 也能让 FAIL_TO_PASS 转绿。golden patch 自检 + 反向 patch 自检是构建时的必做项,不是可选项。
陷阱 3:接受率被产品机制扭曲。 建议 UI 改版(比如把建议字体调大)会让接受率跳升 5 个百分点,而模型没变。业务层指标的一切结论都必须对照"同 UI、同 prompt 版本"的切片。
陷阱 4:Agent 在评估机上直接执行生成代码。 补全建议在沙箱里跑是对的,但 SWE-bench 风格的 patch 执行经常被"为了省事"直接跑在开发机上——patch 里可以有任何 shell 命令。容器隔离不可省。
陷阱 5:人工层只打总分不归类。 "平均 3.4 分"没有行动价值;按维度 + 按失败模式归类的人工层,才能给下一轮迭代开出具体的工单。
28.10 验收自测
- 选择:三层评估中"能不能做题"由哪层回答?
- A. 人工层 rubric
- B. 自动层(HumanEval+ / LiveCodeBench / 自建集)
- C. 业务层接受率
- D. 内测集 golden patch
- 选择:展示接受率的正确分母是?
- A. 全部产生的建议
- B. accepted + rejected + ignored + expired
- C. accepted + rejected(真正展示且被用户决策的建议)
- D. 仅 accepted
- 选择:内测集构建完成后,第一件事是?
- A. 跑最新的旗舰模型看分数
- B. 用 golden patch 验证 harness 能判满分、反向 patch 能判零分
- C. 把它接入 PR 门禁
- D. 扩充到 100 例
- 简答:为什么引用 GitHub RCT 的"快 55.8%"时必须带置信区间和任务限定?
- 简答:W34 的例子中,为什么"自动层分数上升 + 人工层可维护性下降"只能被三层并排发现?单看任何一层会得出什么错误结论?
- 实操:从你团队最近的 10 个已合并 bugfix PR 里挑 3 个满足 28.6.1 筛选条件的,手写
SweCaseJSON(issue 正文 + golden patch + test patch),跑通 golden patch 自检;故意把 testCmd 写错,确认自检会红。
28.11 本章 Cheat Sheet
| 概念 | 一句话 | 详见 |
|---|---|---|
| 三层分工 | 自动=能做题 / 业务=有人用 / 人工=用着舒服 | §28.3 |
| 自动层选集 | HumanEval+ 回归 + LiveCodeBench 防污染 + TS 自建 200 题 | §28.4 |
| 沙箱执行 | 超时 + 独立临时目录 + 失败样本 stderr 落盘 | §28.4.1 |
| 接受率口径 | 分母 = accepted + rejected;ignored/expired 单列观察 | §28.5.1 |
| 修改距离 | 按行 diff,中位数 ≤ 5 行;字符编辑距离无信息量 | §28.5.1 |
| 内测集 | 30 例已修复 Issue,模块分布按业务权重 | §28.6.1 |
| golden patch 自检 | 标准答案必须满分、反向 patch 必须零分,否则评分是抽签 | §28.6.2 |
| 人工层 | 每周 50 条分层抽样 + 3 人盲评 + Kappa ≥ 0.7 | §28.7 |
| 三层并排周报 | 防单维优化;归因必带 promptVersion | §28.8 |
28.12 5 个常见错误
- 只看公开榜——SWE-bench Verified 60% 不等于能修你的 bug;子集相似度比总分重要(第 11 章 7.5)。
- 自动层当唯一门禁——HumanEval+ 已饱和,90%+ 区间的波动多数是噪声;精细回归交给内测集与人工层。
- 埋点漏状态——
expired/ignored缺失会让接受率系统性失真,指标失去信任后就再也回不来了。 - 人工评估不设维度——只给 1-5 总分没有行动价值;维度化 + 失败模式归类才有工单。
- 评估完不复盘——每次 run 的失败样本不写 lessons learned,同样的坑每季度踩一遍;周报里的"备注"列就是为复盘准备的。
28.13 延伸阅读
⭐⭐⭐(官方一手)
- SWE-bench / 评测 harness 文档 — 内测集构造方法的公开参照
- LiveCodeBench(arXiv:2403.07974) — 时间窗防污染协议
- The Impact of AI on Developer Productivity(arXiv:2302.06590) — Microsoft Research / GitHub RCT 原文
⭐⭐(方法论)
- EvalPlus / HumanEval+(arXiv:2305.01210) — 测试密度决定评分上限
- Agentic Benchmark Checklist(arXiv:2507.02825) — 代码基准有效性审计
- Research: quantifying GitHub Copilot's impact(github.blog) — 主观感受维度的调查口径
⭐
- Inspect AI — 沙箱化 Agent 评估的现成框架(Python)
- agentevals — 轨迹与工具调用判分的 TS 工具