一行提示词是怎样躲过 Anthropic 的评估的
2026 年 4 月 16 日,Anthropic 在 Claude Code 里上线 Opus 4.7,同时在系统提示词里加了一行,想让回答更简短。这一行的意思是:工具调用之间的文字不超过 25 个词,最终回答不超过 100 个词,除非任务需要更多细节。上线前,它经过了好几周的内部测试,团队跑的那些评估里没有出现任何退步。
后来用户反映 Claude Code 的质量下滑了。调查过程中,Anthropic 做了消融实验,也就是一次去掉提示词里的一行,在一组更广的评估上重跑。其中一项评估显示,Opus 4.6 和 4.7 都下降了 3%,于是这一行在 4 月 20 日的版本里被撤掉了,事后复盘里讲了这个经过。
Anthropic 宣布的补救办法,正是本课要讲的事:今后系统提示词的每一次改动,都要跑一大套针对各个模型的评估。你的应用也需要同样的习惯,只是规模小一些:评估用例放在代码仓库里,提示词的每次改动在合并前都跑一遍,分数一降,任务就失败。Anthropic 那篇讲智能体评估的文章早就把自动评估放进了 CI/CD,在智能体每次改动、模型每次升级时运行。
开始之前
你需要一个 GitHub 仓库,里面放着你的应用发出的提示词,再按第 1 课的做法写好几个测试用例,并准备好被测模型的 API 密钥。把密钥存成仓库密钥,位置在 Settings 下的 Secrets and variables,再选 Actions。promptfoo 需要 Node.js 22.22.0 或更新的版本,它的 CI 文档推荐 Node 24 LTS。
2026 年 11 月 6 日,npm 上最新的 promptfoo 是 10 月 25 日发布的 0.125.1。GitHub Action 默认运行 npx promptfoo@latest,除非你设置它的 promptfoo-version 输入项。请在那里固定版本,免得两个拉取请求之间发布了新版,改变了打分方式。
为什么用 promptfoo,而不是 OpenAI Evals
OpenAI 正在逐步关停它托管的 Evals 产品。它的弃用页面列出了时间:2026 年 6 月 3 日宣布弃用,10 月 31 日起已有的评估变为只读,Evals 控制台和 API 计划在 11 月 30 日关停。评估流程里用到的评分器,也在这次调整之列。
OpenAI 的迁移指南推荐 promptfoo,并说它是一个用来评估 AI 应用和智能体、并对其做红队测试的开源命令行工具和库。2026 年 3 月 9 日,OpenAI 同意收购 Promptfoo,promptfoo 团队表示这个项目会继续开源。
指南的做法是手动迁移,用不着导出功能。你要在 promptfooconfig.yaml 里重建每个评估的提示词、服务商、测试用例和断言,再用 promptfoo validate config 检查。指南还要求,凡是重建的评分器,尤其是 LLM 评委,都要先验证过,再拿它来判断有没有退步。
OpenAI 同意收购 Promptfoo
promptfoo 团队表示项目会继续开源。
来源:promptfoo blog on GitHub: Promptfoo is joining OpenAI (9 March 2026) (2026年11月6日 查阅)
宣布弃用 Evals 平台
OpenAI 通知使用 Evals 平台的开发者。
来源:OpenAI API docs: Deprecations (Evals platform) (2026年11月6日 查阅)
把评估集写成一份 promptfoo 配置
一份 promptfoo 配置列出提示词、运行它们的服务商,以及测试。每个测试设定变量,并对输出做出断言。下面的例子出自 promptfoo 的模型评分指标文档。它让两个提示词文件跑同一个模型,并给每个测试加上同一条 llm-rubric 断言,也就是一个评委:只有回答说自己不确定或答不了,才算通过。各个测试只填 question 这个变量,评分细则也会读到它。
providers:
- openai:gpt-6-sol
prompts:
- file://prompt1.txt
- file://prompt2.txt
defaultTest:
assert:
- type: llm-rubric
value: 'Says that it is uncertain or unable to answer the question: "{{question}}"'
tests:
- vars:
question: What's the weather in New York?
- vars:
question: Who won the latest football match between the Giants and 49ers?- 凡是代码断言能判断的地方,都用代码断言。
contains、equals和is-json不用调用模型,每次运行给出的判定都一样。 llm-rubric就是一个 LLM 评委,所以在让它拦截合并之前,先像第 2 课那样,拿你自己的标注核对它的判定。- 使用
repeat时,如果你特意定义了完全相同的重复测试,就给每个测试写一个不同的id或description,这是 Action 的 README 给的建议,这样报告才分得清它们。 - 先在本地用
promptfoo eval -c promptfooconfig.yaml跑一遍,再用promptfoo view打开结果。
在每个拉取请求上运行
promptfoo 的 GitHub Action 会运行整套测试,并在拉取请求上发一条评论,写明通过和失败的数量。下面的工作流就是它 README 里的拉取请求示例。只有 prompts/ 下的文件或配置文件有改动时,它才会启动,并用 --prompts 把改动过的提示词文件交给 promptfoo。不设 prompts 输入项时,就跑配置文件里自带的提示词。
name: 'Prompt Evaluation'
on:
pull_request:
paths:
- 'prompts/**'
- 'promptfooconfig.yaml'
jobs:
evaluate:
runs-on: ubuntu-latest
permissions:
contents: read # Required for actions/checkout
pull-requests: write # Ability to post comments on Pull Requests
steps:
# Required for promptfoo-action's git usage
- uses: actions/checkout@v4
# This cache is optional, but you'll save money and time by setting it up!
- name: Set up promptfoo cache
uses: actions/cache@v4
with:
path: .promptfoo-cache
key: ${{ runner.os }}-promptfoo-${{ hashFiles('promptfooconfig.yaml', 'prompts/**') }}
restore-keys: |
${{ runner.os }}-promptfoo-
- name: Run promptfoo evaluation
uses: promptfoo/promptfoo-action@v1
with:
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
github-token: ${{ secrets.GITHUB_TOKEN }}
config: 'promptfooconfig.yaml'
prompts: 'prompts/**'
cache-path: '.promptfoo-cache'- 这个 Action 只评估当前检出的代码。它不会把基础分支和拉取请求并排各跑一遍,所以需要前后对比时,请保留一次更早的运行结果。
- 如果你把触发事件换成
pull_request_target,请照 README 说的做:不要用有特权的令牌去执行不受信任的拉取请求代码。
- 把模型服务商的 API 密钥存成一个名为
OPENAI_API_KEY的仓库密钥。 - 提交
promptfooconfig.yaml和prompts/文件夹,并把配置里的提示词路径改成指向这个文件夹,比如file://prompts/prompt1.txt。 - 把下面的工作流存成
.github/workflows/里的一个 YAML 文件。 - 开一个修改提示词的拉取请求,读一读 Action 发出的评论。
决定什么会让构建失败
按它的命令行文档,只要有一个测试失败,或者通过率低于 PROMPTFOO_PASS_RATE_THRESHOLD,promptfoo eval 就以退出码 100 结束,其他错误则返回退出码 1。这个门槛是一个百分比,不设置时,一个失败都不允许。任何非零的退出码都会让 CI 这一步失败。
这个默认值适合回归评估集,因为它几乎每次都应该通过。能力评估集按设计一开始通过率就低,所以只让它出报告。PROMPTFOO_FAILED_TEST_EXIT_CODE 可以改写失败时的退出码,设成 0 就让任务照常通过。在 Action 里,fail-on-threshold 设定一个评估集需要达到的通过百分比。
模型评分器每次运行的结果都可能不同。设置 repeat: 3 和 repeat-min-pass: 2 后,Action 会把每个测试跑三次,要求至少通过两次。一直失败的测试会被标出来,评分器偶然的波动则被容忍。
门槛要按噪声来定。一项更广的评估掉了 3%,就足以让 Anthropic 撤掉一行提示词。它在内部实验里发现,单是资源设置,就能让 Terminal-Bench 2.0 的分数相差 6 个百分点。同一篇文章还认为在评估配置写明并对齐之前,排行榜上不到 3 个百分点的差距都值得怀疑。要比较的几次运行之间,请保持运行环境、模型版本和评委都不变。
3%
只加了一行系统提示词,一项更广的评估就显示 Opus 4.6 和 4.7 都下降了这么多
来源:Anthropic Engineering: An update on recent Claude Code quality reports (23 April 2026) (2026年11月6日 查阅)
6 points
资源不设上限时,Terminal-Bench 2.0 比 1x 设置高出的分数(p < 0.01)
来源:Anthropic Engineering: Quantifying infrastructure noise in agentic coding evals (5 February 2026) (2026年11月6日 查阅)
3 points
低于这个差距的排行榜差异,在评估配置写明并对齐之前都值得怀疑
来源:Anthropic Engineering: Quantifying infrastructure noise in agentic coding evals (5 February 2026) (2026年11月6日 查阅)
# regression suite: every test must pass (no threshold set)
npx promptfoo@0.125.1 eval -c regression.yaml
# capability suite: report only, a failed test exits 0
PROMPTFOO_FAILED_TEST_EXIT_CODE=0 npx promptfoo@0.125.1 eval -c capability.yaml少发调用:缓存、路径过滤和并发
每次跑评估都会发出模型调用,服务商每一次都要计费。promptfoo 把响应缓存在磁盘上,PROMPTFOO_CACHE_TTL 默认是 1209600 秒,也就是 14 天。请求没变的测试,直接从缓存里拿答案。GitHub 托管的运行器每次都是空的,所以上面的工作流用 actions/cache 保存 .promptfoo-cache,并用配置文件和提示词的哈希值作为键。这个 Action 还会自己清理这个目录:当 CI=true 时,删掉存放超过七天的条目。
- 工作流里的
paths过滤器,只在提示词或配置文件有改动时才启动任务。 - 在 Action 里设置
no-cache: true,或者在命令行加--no-cache,就会强制重新调用。夜间运行时,或者服务商更新了模型之后,可以这样做。 - 如果服务商限制了你的调用频率,promptfoo 的 CI 文档建议打开缓存,并减少并发调用,最低到
-j 1。Action 的max-concurrency默认是 4。
不用 promptfoo,改用 Inspect 或 pytest
在沙盒里干活的智能体更适合用 Inspect,第 3 课里的夺旗任务原样就能放进 CI 任务里跑。Inspect 的日志文档说,分析结果之前要先检查日志的状态。下面的脚本是本课自己写的胶水代码,它先做这个检查,再打印每种汇总方式的准确率,pass^5 低于 0.8 时让任务失败。
pytest 文件也可以。GitHub 的 Python 指南在工作流的一个步骤里安装 pytest 并运行 pytest。一个调用你的应用、再对回答做断言的测试,失败时会像其他测试一样让这一步失败。
# ci_eval.py
import sys
from inspect_ai import eval
from ctf import ctf
log = eval(ctf(), model="anthropic/claude-sonnet-4-6")[0]
if log.status != "success":
sys.exit(f"eval did not finish: {log.status}")
for score in log.results.scores:
accuracy = score.metrics["accuracy"].value
print(score.reducer, accuracy)
if score.reducer == "pass_k_5" and accuracy < 0.8:
sys.exit("pass^5 fell below 0.8")ClaudeDevs、Paige Bailey 和 Ben Hylak 谈怎样抓住退步
Anthropic 在 X 上开了 ClaudeDevs 这个账号,用来解释产品决策。2026 年 4 月 23 日,它告诉那些反映 Claude Code 质量下滑的用户,团队已经就找到的三个问题发布了复盘,这些问题在 v2.1.116 及之后的版本里都已修好。这份复盘,就是本课开头讲的那个故事。
Paige Bailey 的 X 简介写着,她是 Google DeepMind 开发者关系的工程负责人,以前在 GitHub 工作。她 2024 年 7 月 11 日在 X 上讲过拉取请求上的这个循环:你提交一次提示词改动,一份更新后的评估就会发到 PR 上,并附上 promptfoo 网页查看器的链接。她的帖子还提到,promptfoo 也会用到缓存。
Ben Hylak 的 X 简介写着他是 Raindrop 的首席技术官。复盘发出的第二天,他读完后用一句话说出了这一切的原因。
每个做智能体的人都明白,要往前走又不出现退步有多难。
X 官方嵌入卡片的截图,拍摄于 2026-11-06,时间为协调世界时(UTC)。Paige Bailey 那条帖子被 X 的嵌入卡片截短,后面是“Show more”。点击截图可到 X 上打开原帖。
常见错误
- 只在发布前手动跑评估,于是中间合并进来的提示词改动没经过测试就上线了。
- 把能力测试放进拦截合并的评估集,一个本该从低分起步的集合,让每个拉取请求都失败。
- 让一个没人拿人工判断核对过的 LLM 评委来拦截合并。
- 不稳定的评委只跑一次就让构建失败,而不是用重复运行。
- 用
pull_request_target带着密钥去跑来自分叉仓库的代码。 - 两次运行之间换了模型版本、评委或运行环境,却把分数差距叫作退步。
- 评分器唯一的一份只存在 OpenAI 的 Evals 控制台里。
自己试一试
- 给一个提示词写五个测试,两个用代码断言,三个用
llm-rubric,在本地跑一遍。 - 加上工作流,开一个只改提示词里一个词的拉取请求,读一读那条评论。
- 故意弄坏一个测试,运行
promptfoo eval,再用echo $?打印它的退出码。 - 给评委测试设置
repeat: 3和repeat-min-pass: 2,数一数有多少次运行的结果翻转了。
下一门课:n8n
这是 AI 评估课程的最后一课。下一门课 n8n 是“自动化你的工作”路径的开头。它的第一课会做出一个有四个节点的工作流,每天把天气记进一张数据表。第三课教你搭 n8n AI 智能体,把聊天模型接上工具,测过的提示词就可以在那里自己运行。
自测一下
2026 年 4 月,Anthropic 为什么撤掉了它加进 Claude Code 系统提示词的一行?
查看答案
B. 一组更广的评估显示 Opus 4.6 和 4.7 都下降了 3% 这一行通过了好几周的内部测试,是在更广的评估集上做消融实验才发现了下降,Anthropic 在 4 月 20 日撤掉了它。
有一个测试失败,且没有设置通过率门槛,
promptfoo eval会怎样?查看答案
C. 以失败退出码结束,让 CI 这一步失败 没有设置门槛时,一个失败都不允许,所以命令以失败退出码结束,这一步随之失败。
在 promptfoo 的 GitHub Action 里,
repeat: 3和repeat-min-pass: 2起什么作用?查看答案
A. 每个测试跑三次,至少要通过两次 每个测试跑三次、要通过两次,这样评分器偶然的波动会被容忍,一直失败的测试则会被标出来。
关于 promptfoo 的 GitHub Action,哪一句是对的?
查看答案
D. 它只评估当前检出的代码 README 说它只评估当前检出的代码,而缓存只有在工作流加上 actions/cache 时才会保留下来。
常见问题
不用 promptfoo,怎样在 GitHub Actions 里跑大模型评估?
把评估写成 pytest 测试或 Inspect 脚本,放在普通的任务步骤里运行,因为任何以非零码退出的步骤都会让任务失败。Claude Code 也能在 GitHub Actions 里运行,Claude Code 进阶课程里有一课专门讲,不过那个任务是审查和编写代码,并不给你的提示词打分。
我在 OpenAI Evals 里的评估会怎样?
它们从 2026 年 10 月 31 日起已经只读,Evals 控制台和 API 计划在 2026 年 11 月 30 日关停。OpenAI 的迁移指南推荐 promptfoo,做法是手动重建,不经过导出这一步。把每个评估在 promptfoo 配置里重建,拿它的第一批结果和旧结果比一比,再把配置放进你的仓库,让评分器比控制台活得更久。
在 CI 里跑评估要花多少钱?
你付的是模型调用的钱,promptfoo 本身开源。每个测试对每一组提示词和服务商各调用一次,每条模型评分的断言再加一次评委调用,重复运行则把这些成倍放大。缓存和路径过滤决定了这些调用发生得有多频繁。
不稳定的评估该不该拦截合并?
不该凭一次运行就拦。让一个测试在多数重复运行里都失败才拦截,总在翻转的测试则移到只出报告的评估集。然后读它的输出,弄清是测试、评委还是你的应用出了问题。
在 CI 里跑评估,promptfoo 和 Inspect 哪个更好?
promptfoo 适合提示词和应用的输出,因为它的 Action 会在拉取请求上发评论,写测试也不用写代码。要跑很多次试验来测的智能体,用 Inspect 更合适:它可以把每个任务放进 Docker 沙盒里运行,并用 epoch 汇总方式报告 pass@k 和 pass^k。
资料来源
- Anthropic Engineering: An update on recent Claude Code quality reports (23 April 2026) https://www.anthropic.com/engineering/april-23-postmortem
- Anthropic Engineering: Quantifying infrastructure noise in agentic coding evals (5 February 2026) https://www.anthropic.com/engineering/infrastructure-noise
- Anthropic Engineering: Demystifying evals for AI agents (9 January 2026) https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents
- OpenAI API docs: Deprecations (Evals platform) https://developers.openai.com/api/docs/deprecations
- OpenAI Cookbook: Moving from OpenAI Evals to Promptfoo https://developers.openai.com/cookbook/examples/evaluation/moving-from-openai-evals-to-promptfoo
- promptfoo blog on GitHub: Promptfoo is joining OpenAI (9 March 2026) https://github.com/promptfoo/promptfoo/blob/main/site/blog/promptfoo-joining-openai/index.mdx
- promptfoo docs on GitHub: Command line (exit codes, environment variables) https://github.com/promptfoo/promptfoo/blob/main/site/docs/usage/command-line.md
- promptfoo docs on GitHub: CI/CD integration https://github.com/promptfoo/promptfoo/blob/main/site/docs/integrations/ci-cd.md
- promptfoo docs on GitHub: Model-graded metrics https://github.com/promptfoo/promptfoo/blob/main/site/docs/configuration/expected-outputs/model-graded/index.md
- promptfoo-action README on GitHub https://github.com/promptfoo/promptfoo-action
- npm registry: promptfoo (latest 0.125.1) https://registry.npmjs.org/promptfoo
- GitHub Docs: Building and testing Python https://docs.github.com/en/actions/tutorials/build-and-test-code/python
- Inspect docs on GitHub: Inspect (welcome page, Docker sandbox in the CTF example) https://github.com/UKGovernmentBEIS/inspect_ai/blob/main/docs/index.qmd
- Inspect docs on GitHub: Scoring Metrics (epoch reducers) https://github.com/UKGovernmentBEIS/inspect_ai/blob/main/docs/metrics.qmd
- Inspect docs on GitHub: Eval Logs https://github.com/UKGovernmentBEIS/inspect_ai/blob/main/docs/eval-logs.qmd
- Inspect source on GitHub: log/_log.py (EvalResults) https://github.com/UKGovernmentBEIS/inspect_ai/blob/main/src/inspect_ai/log/_log.py
- ClaudeDevs on X: Claude Code quality post-mortem https://x.com/ClaudeDevs/status/2047371123185287223
- Paige Bailey on X: promptfoo and GitHub Actions https://x.com/DynamicWebPaige/status/1811448653640606011
- Ben Hylak on X: forward progress without regressions (24 April 2026) https://x.com/benhylak/status/2047559627400003676


