夜雨聆风学习资料网

ARTICLE · 1163341

你的 Claude Code 插件到底有用没用?跑套考卷就见分晓

你的 Claude Code 插件到底有用没用?跑套考卷就见分晓

我这人有个毛病:看到好用的 Claude Code 插件就想装。装到十几个之后,问题来了——到底哪个真在干活,哪个只是躺在那儿占上下文?

以前我全靠感觉。直到前几天翻官方文档,发现 Claude Code 悄悄加了条命令:claude plugin eval。说白了,就是给你的插件出一套考卷,让它自己答题,然后打分。

但最狠的还不是打分,是它还会把插件拿掉再考一遍。装上有多少分,拿掉有多少分,两个一减,插件到底贡献了多少,一目了然。

它到底在考什么

一套"考卷"就放在插件目录里的 evals/ 文件夹。每道题叫一个 case:一段真人会敲的 prompt,加上一条或多条 grader(判卷规则)。

判卷规则有六种:

  • regex:回复里有没有匹配某个正则;
  • tool_used:有没有调用某个工具(比如你的 skill);
  • tool_order:调用的先后顺序对不对;
  • file_exists:有没有生成某个文件;
  • llm:让第二个模型当判卷老师,按你写的 PASS/FAIL 规则投票;
  • baseline:跟一份参考答卷比。

每道题默认跑 3 遍。为啥?模型有随机性,跑一次说明不了问题,取 3 次平均才稳。

小知识:regex、tool_used、tool_order、file_exists 这四种是读运行记录直接算的,不花钱;只有 llm 和 baseline 会真的叫模型来打分,会烧 token。

杀手锏是那个 Δ(增量)

很多人第一次看结果,盯着分数高就高兴。可分数高不代表插件有用——说不定 Claude 本来就会。

Claude Code 早就想到这层了。同一道题它跑两个"组":with 组装着你的插件跑,without 组什么插件都不装再跑一遍。最后给你一张这样的表:

CASE        WITH  W/OUT  Δ      RUNS  COSTfirst-case  1.00  0.33   +0.67  6     $0.41

WITH 是装着插件的分,W/OUT 是裸跑的分,Δ 就是两者之差。举个例子你就懂了:

你写了个"自动写提交信息"的 skill,装上考 1.00 分,很爽。但如果裸跑也有 1.00,那说明 Claude 自己就会写提交信息,你这个插件根本没加分。Δ≈0,等于白装。

真正的价值在 Δ 上:Δ 是正的,才是你实打实赚到的;Δ 是负的,更得警惕——插件可能在帮倒忙。

上手:先让 Claude 帮你出题

自己写题目挺费劲,官方留了条捷径:

# 在插件根目录执行。它会开个交互会话,读你的插件、反问你想考什么,# 然后自己出题、自己设计判分、自己写文件,还会先试跑一遍确认题目合理claude plugin eval init

等它说题目准备好了,/exit 退出就行。不想交互,就用 --bare 拿空白模板自己填:

claude plugin eval init --bare first-case

手写一道题,其实就两个文件

想彻底搞清楚结构,还是自己写一道最直观。题目长这样:

---max_turns: 10allowed_tools: [Read, Glob, Grep, Skill]---帮我给这次改动写一条提交信息:我把 getUser 改名成了 fetchUser,并更新了三处调用点。

前面那几行 allowed_tools 很关键:每道题都在一个空目录里裸跑,不给工具它啥也干不了。Read、Grep、Skill 这些只读工具列上就自动授权;但 Bash、Write、Edit 得另外用 --allow-tools 显式开。

判卷规则一个文件一条。先来一条"内容对不对",交给模型老师判:

---type: llm---PASS:提交信息一句话说清了改名这件事,符合 Conventional Commits 风格。FAIL:只重复了代码动作、没写意图,或者格式完全跑偏。

再来一条"活儿是不是我的 skill 干的":

---type: tool_usedtool: Skillinput_match: '"skill"\s*:\s*"(?:[\w-]+:)?your-skill-name"'---

这招特别好用:哪怕答案写对了,如果根本没触发你的 skill,这条照样挂。答案对,不代表插件起了作用。

写完两条,回到插件根目录:

claude plugin eval .

读结果时,我踩过的几个坑

坑一:tool_used: Skill 显示 fail,可总分还是 1.00。 别慌,这是设计如此。在"裸跑"那组里没有插件,这条永远不可能过。要是把它算进分数,without 组会被硬压到 0,Δ 就假高。所以两臂对比时这类 grader 会被排除计分,只当个"指示灯"看。

坑二:Δ 是负的,先怀疑判卷老师。llm grader 是模型在打分,它可能因为你描述的格式跟答案的实际格式对不上,就把对的判成错的。先换 --judge-model sonnet 重跑,再把 rubrics 写具体些。

坑三:想检查文件内容,结果 files 给的是文件名列表。target: files 只给文件路径清单,不是内容。要判内容,得写 { source: file, path: 你的路径 }。另外 file_exists 只认"这次跑新生成的文件",脚手架建的和只被改过的都不算。

坑四:明明全过了,命令却退出码 1。--threshold 默认是 1.0,也就是要求满分。有一道题低于满分就退 1。CI 里一般设个 0.8 更合理。

坑五:git 太老直接罢工。 跑之前会查 git 版本,低于 2.31 直接停。因为老 git 读不了"关掉仓库 hooks"的那套配置,官方宁可停,也不愿让那些程序在考试里乱跑。

进阶:把它堵在 CI 门口

真正让我觉得这东西值得写的,是它能当 CI 门禁。你改插件、或者新模型上线,都可能悄悄把效果搞崩,跑一遍就知道:

claude plugin eval . \  --trust-plugin \  --json results.json \  --threshold 0.8 \  --model claude-sonnet-5 \  --judge-model claude-haiku-4-5 \  --no-publish \  --max-cost-usd 20

几个参数解释下:

  • --trust-plugin:CI 里没人点确认,必须手动声明信任,否则会被拒;
  • --model 和 --judge-model:两个都钉死。不然模型一升级,你分不清是插件退步还是模型变了;
  • --max-cost-usd:花到上限就停,跑了多少算多少。此时退出码给 2,表示"没跑完",这种半截数据别拿来做趋势。

退出码也好懂:0 全过,1 有题不达标或有题加载失败,2 是撞了成本上限或凭证被拒。

还有个小甜点:evals/mocks/ 能给 MCP 工具造假数据。你的 skill 要调某个 MCP 服务,不用真连,写个 markdown 描述它该返回啥就行,判卷时还能顺带检查 Claude 传进去的参数对不对。

我的建议

插件生态越大,越需要这种"体检"。我现在养成个习惯——每写完一个新 skill,先给它出三道题:一道考"该触发时触发没",一道考"结果对不对",一道考兜底(不该触发时别乱触发)。

一圈跑下来,几十美分的成本,换来的是"这东西到底有没有用"的确定答案。

毕竟插件这东西,装的时候爽。可它到底是真帮你省了事,还是只让你觉得省了事,得用数据说话。

相关学习资料