Promptfoo 是一个专为提示词工程而设计的开源测试与评估工具,它允许你:
- 配置多个提示词
- 配置多个模型
- 批量测试多个输入
- 使用人类打分或自动化机制评估输出质量
Promptfoo 的核心功能:
- 多提示词对比:比较多个提示词在相同输入下的输出质量
- 多模型对比:比较 GPT-4、Claude、Gemini、LLaMA 等模型对同一提示词的输出差异
- 批量输入测试:用多个输入样例评估提示词的稳定性
- 手动或自动评分:支持人工打分、关键词匹配、甚至调用 LLM 对输出进行自评
- 报告输出与分析:自动生成 Markdown、HTML、JSON 格式的测试报告
- 命令行 & Web UI:提供 CLI 工具,也支持运行
promptfoo web启动可视化评测界面 - CI 集成:可集成至 GitHub Actions、CI/CD 流程,做提示词的“自动回归测试”
模板示例一#
npx promptfoo init会默认生成一个 promptfooconfig.yaml 模板,内容如下:
# 对本次 prompt 评估做一个简单的描述,比如你要测试什么内容、比较哪些提示词或模型。description: 'My eval'
# 定义两个提示词模板,它们都包含变量 {{topic}}# promptfoo 会自动将每个变量替换为 tests 中定义的具体值prompts: - 'Write a tweet about {{topic}}' - 'Write a concise, funny tweet about {{topic}}'
# 指定调用的模型提供者,支持多个。providers: - 'openai:gpt-4o-mini' - 'openai:gpt-4o'
# 定义每一组测试输入(变量)tests: - vars: topic: bananas
- vars: topic: avocado toast assert: - type: icontains value: avocado
- type: javascript value: 1 / (output.length + 1)
- vars: topic: new york city assert: - type: llm-rubric value: ensure that the output is funnyassertions 类型速览
| 类型 | 描述 |
|---|---|
equals | 严格等于某个期望值 |
icontains | 忽略大小写包含 |
regex | 匹配正则表达式 |
javascript | 使用 JS 表达式动态打分 |
llm-rubric | 通过 LLM 自动判分(更智能) |
1 / (output.length + 1)output.length 表示模型输出内容的字符数。加 1 是为了避免除以 0。整个式子是:输出越长,分数越低;输出越短,分数越高。
| 输出内容 | output.length | 分数 (1 / (len + 1)) |
|---|---|---|
| “Hello” | 5 | 1 / 6 ≈ 0.166 |
| ”Hello, how are you today?“ | 24 | 1 / 25 ≈ 0.04 |
这个规则鼓励模型输出简洁的结果。
进行评分
promptfoo eval在线模型配置Key
- OpenAI(GPT-3.5 / GPT-4 / GPT-4o)
providers: - id: openai:gpt-4o config: apiKey: $OPENAI_API_KEY- Anthropic(Claude 系列)
providers: - id: anthropic:claude-3-opus config: apiKey: $ANTHROPIC_API_KEY- Cohere
providers: - id: cohere:command-r config: apiKey: $COHERE_API_KEYpromptfoo 会自动从 .env 文件中读取变量,例如:
OPENAI_API_KEY=sk-xxx...ANTHROPIC_API_KEY=sk-ant-xxx...确保你运行 promptfoo 命令时,处于 .env 文件所在目录下(或将它放在项目根目录)。
模板示例二#
下面是另外一份提示词模板示例:
prompts: - id: basic-summary label: '基础总结' raw: '请用一句话总结下面这段话:{{input}}'
- id: formal-summary label: '正式语气总结' raw: '请用正式、简洁的语气总结以下内容:{{input}}'
providers: - id: ollama:llama3 - id: ollama:gemma3
tests: - vars: input: '小明今天早上迟到了,因为他错过了地铁。' - vars: input: '天气预报说今天有雨,所以我们取消了郊游计划。' - vars: input: '这家咖啡馆的氛围很好,适合工作和学习。'
eval: automatic: - type: keyword-match criteria: - '总结' - '简洁'这份配置文件大致分为四大部分:
prompts: # 提示词设计providers: # 模型提供方设置tests: # 输入样本eval: # 自动评分方式提示词设计
prompts: - id: basic-summary label: '基础总结' raw: '请用一句话总结下面这段话:{{input}}'
- id: formal-summary label: '正式语气总结' raw: '请用正式、简洁的语气总结以下内容:{{input}}'说明如下:
| 字段 | 说明 |
|---|---|
id | 每个提示词的唯一标识符(用于结果记录/引用) |
label | 提示词在结果中显示的中文/人类可读名 |
raw | 实际传递给模型的提示词模板,支持变量(如 {{input}}) |
在上面的提示词中,我们设置了两个不同风格的提示词(一个通用、一个正式),Promptfoo 会分别用这两个提示词+输入变量进行测试,形成组合。{{input}} 是变量占位符,会从 tests 中填入。
模型提供方设置
providers: - id: ollama:llama3 - id: ollama:gemma3说明如下:
| 字段 | 说明 |
|---|---|
id | 指定要调用的模型(格式为 平台:模型名) |
我们测试的本地模型有 llama3 和 gemma3,通过 Ollama 调用。Promptfoo 会用所有的 prompt × 所有的 model 做笛卡尔积组合进行测试。
输入样本
tests: - vars: input: '小明今天早上迟到了,因为他错过了地铁。' - vars: input: '天气预报说今天有雨,所以我们取消了郊游计划。' - vars: input: '这家咖啡馆的氛围很好,适合工作和学习。'说明如下:
| 字段 | 说明 |
|---|---|
vars | 输入变量定义(对应 prompt 中的 {{input}}) |
input | 实际输入内容,会被插入到 prompt 中的位置 |
每条样本会作为一次完整测试输入,和每一个 prompt 和模型组合配对,例如有 3 个 input × 2 个 prompt × 2 个模型 = 12 次测试运行。
自动评分方式
eval: automatic: - type: keyword-match criteria: - '总结' - '简洁'说明如下:
| 字段 | 说明 |
|---|---|
type | 自动评分的方式,这里使用的是 keyword-match |
criteria | 模型输出中必须包含的关键词,如果包含则判定“命中” |
Promptfoo 会在每一组结果中查找是否出现了这些关键词。若命中多项,得分越高,可用于粗略判断“是否按照我们要求的格式说话”。也可以使用:
regex-match:用正则表达式匹配输出结构llm-rubric:用 LLM 来评价另一个 LLM 输出质量。
这里说一下 llm-rubric,你可以把它理解为模型自己给自己打分(就像一个助教评分学生作业)。提前设计一个评分规则,然后让 GPT 或 Claude 这样的模型代替人类来打分。Rubric 原意就是“评分标准”,在 Promptfoo 中,它就是你写的一段评分说明或标准句子,告诉评分模型:
- 你想根据什么标准打分?
- 满分是多少?
- 评分输出格式是什么?
例如:
eval: automatic: - type: llm-rubric rubric: | 评分标准: 如果输出内容准确、表达清晰且逻辑合理,得5分; 如果有小问题但大体合理,得3分; 如果严重偏题或错误,得1分; 请只输出一个整数分数,不加解释。Promptfoo 会把你的提示输出 + 输入内容 + rubric 一起打包发给 GPT 模型,然后它会输出类似:
4你可以指定评分的模型使用哪一个:
eval: automatic: - type: llm-rubric rubric: '...' provider: openai:gpt-4如果你没指定,Promptfoo 默认使用你在 providers 中定义的第一个模型。
总结:llm-rubric 是用一个 LLM 来给另一个 LLM 的输出打分的机制。你只需要写一段评分标准,它就能自动判分,不需要你一个一个手动看结果。
模板示例三#
prompts: - id: good-job-title label: '好提示词:具体要求 + 输出格式' raw: | 请根据以下岗位信息,撰写一句吸引人的招聘广告标题: - 以年轻人喜欢的口吻 - 控制在15个字以内 - 用一句话概括岗位亮点 岗位信息: {{input}}
- id: bad-job-title label: '坏提示词:无要求,模糊指令' raw: | 写一句话。
providers: - id: ollama:llama3
tests: - vars: input: '我们是一家AI初创公司,正在招聘前端开发,技术栈为Vue和TypeScript,提供远程办公和股票期权。' - vars: input: '本公司招聘客服专员,工作环境轻松,带薪培训,有下午茶。' - vars: input: '招聘Python数据工程师,参与大模型推理平台建设,年薪40万起。'
eval: automatic: - type: llm-rubric rubric: | 请从以下维度为这个输出打分(1~5分): - 是否突出岗位亮点(2分) - 是否语言吸引人(2分) - 是否符合短标题要求(1分) 请仅返回一个整数分数(1~5分)。可视化输出:
promptfoo view