Loading...

文章背景图

Promptfoo:LLM 应用的提示词评测与红队测试工具|部署与使用全指南

2026-10-27
1
- 字
- 分钟

Promptfoo:LLM 应用的提示词评测与红队测试工具|部署与使用全指南

适用版本段:本文基于 promptfoo npm 最新版 0.125.1(GitHub Release 发布于 2026-10-25)撰写,对应官方文档 "Last updated on Oct 25, 2026"。仓库 promptfoo/promptfoo 约 26.4k star、2.6k fork,main 分支当日仍有提交(2026-10-26),属于高活跃度项目。许可证为 MIT。需注意:README 顶部公告写明 "Promptfoo is now part of OpenAI",但项目仍然开源且保持 MIT 许可。

Promptfoo Web Viewer 评测矩阵

Promptfoo 是一个面向 LLM(Large Language Model)应用的评测(eval)与红队(red team)测试工具:你用一份 promptfooconfig.yaml 描述「提示词 × 模型 × 测试用例 × 断言」,它就把所有组合跑一遍,给出可量化的通过率、分数、成本与延迟,并在本地浏览器里以矩阵形式对比输出。它同时能自动生成上千条对抗性输入,对你的 AI 应用做漏洞扫描(越狱、提示注入、PII 泄露、越权等),产出合规风险报告。核心卖点是:纯本地运行、 prompts 不出机器、可接入 CI/CD 做质量门禁。

Promptfoo 评测矩阵示意

一、项目介绍与适用场景

1.1 它是什么

  • 形态:一个 Node.js CLI(promptfoo)+ 一个本地 Web viewer + 一个可自托管的 Express 服务端(Docker 镜像)。

  • 输入:YAML 配置(prompts / providers / tests / redteam 等)。

  • 输出:终端表格、JSON / YAML / CSV / JSONL / HTML / JUnit XML 报告、Web 可视化矩阵、红队风险报告。

  • 本质:把「改 prompt → 凭感觉上线」变成「改 prompt → 跑回归 → 看指标」的工程化流程。

1.2 技术定位

维度

Promptfoo 的做法

运行时

Node.js ≥ 22.22.0(官方推荐 Node.js 24 LTS)

执行位置

100% 本地执行,调用各家 LLM API;不托管你的 prompts

模型接入

60+ provider(OpenAI / Anthropic / Azure / Google Vertex / AWS Bedrock / Ollama / HTTP / 自定义脚本…)

断言体系

确定性断言(equals / contains / regex / is-json / cost / latency …)+ 模型辅助断言(llm-rubric / similar / factuality / g-eval …)

扩展方式

JS / Python / Ruby 自定义 provider、assertion、extension hook

测试类型

功能评测(eval)+ 安全红队(redteam)+ 代码扫描(code scanning)

CI

GitHub Action promptfoo/promptfoo-action@v1,或命令行 + JUnit/JSON 输出

1.3 适合谁

  • 正在做 RAG、Agent、聊天机器人的应用开发团队:需要在改 prompt / 换模型时防止回归。

  • 平台 / SRE 团队:需要在 CI 里给 LLM 相关改动加质量门禁与成本门禁。

  • 安全团队(AppSec):需要对 AI 应用做 OWASP LLM Top 10、NIST AI RMF、EU AI Act 对齐的漏洞扫描。

  • 模型选型者:同一批测试集,横向对比多家模型的评分 / 延迟 / 成本。

  • 个人开发者:本地 npx promptfoo@latest 一条命令就能跑,无需注册账号。

1.4 不适合的场景

  • 需要多人协作、RBAC、SSO、共享数据库的团队级 SaaS:官方自托管镜像明确写着 "not recommended for production use cases"(SQLite、单副本、无鉴权、无 SSO),这类需求要走 Enterprise 平台。

  • 需要训练 / 微调模型:它只做推理侧的评测与扫描,不做训练。

  • 完全没有 API key 的纯离线场景:大多数断言需要调用 LLM,本地模型(Ollama / llama.cpp / vLLM)可以替代但配置成本更高。

  • 把这个 Docker 镜像当多租户服务对外售卖:自托管版本不具备多租户能力。

二、核心功能逐条拆解

  1. 多提示词 × 多模型矩阵评测:prompts 与 providers 做笛卡尔积,tests 提供变量,一次性跑出完整矩阵;Web viewer 里逐格对比,配合 "Pass / Fail / Score / Comment" 人工标注。

  2. 丰富的断言类型:40+ 确定性断言(equals、contains-any/all、regex、is-json、is-sql、is-xml、latency、cost、perplexity、levenshtein、rouge-n、bleu、meteor、tool-call-f1、trace-* 等)与 16 类模型辅助断言(llm-rubric、similar、classifier、moderation、factuality、g-eval、answer-relevance、context-faithfulness / recall / relevance 等)。

  3. not- 前缀取反:几乎所有断言类型都能加 not- 前缀(如 not-equals、not-regex、not-contains),用来断言"不该出现什么"。

  4. 加权与命名指标:每条 assert 可设 weight,同名 metric 会被聚合;还能用 derivedMetrics 基于命名分数算出 F1、平均值等复合指标。

  5. 断言集(assert-set):把多条断言分组并设 threshold,例如"成本与延迟满足其一即可通过"(threshold 0.5)。

  6. 缓存与并发控制:默认磁盘缓存(~/.promptfoo/cache,TTL 14 天),429 自动指数退避,evaluateOptions.maxConcurrency 默认 4,delay 可限流,--no-cache 可强制穿透。

  7. 红队测试(red teaming):redteam init → run → report 三步走,自动生成数百条对抗输入(jailbreak、prompt injection、PII、BOLA/BFLA、competitors 等 50+ 插件),按严重级别(critical / high / medium / low)生成漏洞报告。

  8. 合规框架映射:redteam.frameworks 可选 owasp:llm、owasp:api、owasp:agentic、nist:ai:measure、mitre:atlas、eu:ai-act、iso:42001、gdpr、dod:ai:ethics,报告里直接呈现对应合规项。

  9. CI/CD 集成:命令行 npx promptfoo@latest eval -o results.junit.xml 输出 JUnit;promptfoo/promptfoo-action@v1 在 PR 里自动对比改动前后的 prompt 并贴评论。

  10. 代码扫描(code scanning):promptfoo code-scans run 对仓库做 LLM 相关安全与合规问题的静态扫描。

  11. Web viewer 交互分析:支持搜索/正则过滤、按 metric 与 metadata 过滤、对比两次 eval(Compare)、导出 CSV/JSON/DPO JSON/Human Eval YAML/Burp payloads。

  12. 结果分享与自托管:promptfoo share 生成分享链接;也可把服务端部署在自己的机器上(ghcr.io/promptfoo/promptfoo),用 sharing.apiBaseUrl 指向它。

红队漏洞报告

三、全套官方链接

四、硬件与环境前置要求

项目

要求

说明

Node.js

≥ 22.22.0,推荐 24 LTS

npm / npx 均要求;CI 里把 Node 设为 24

包管理器

npm(随 Node 自带)

也可用 brew install promptfoo(Mac/Linux)、pip install promptfoo

Python(可选)

3.x

仅当使用 Python provider / Python assertion / Python 扩展 hook 时需要

Ruby(可选)

3.x

仅 Ruby provider / assertion 需要

操作系统

Windows / macOS / Linux

原生依赖(libsql)提供 darwin-arm64、linux-x64-gnu、win32-x64-msvc 等预编译包

CPU / 内存

2 核 / 4 GB 起步

大批量测试建议 8 GB 以上;测试用例与输出很大时需调 NODE_OPTIONS=--max-old-space-size

磁盘

≥ 2 GB 可用

~/.promptfoo 存数据库 promptfoo.db、缓存、日志;缓存默认 14 天 TTL

GPU

不需要

只调用远端 API;若接本地模型(Ollama / vLLM)则由本地模型侧决定

网络

需出网访问 LLM API

企业代理用 HTTPS_PROXY / NO_PROXY,自签 CA 用 PROMPTFOO_CA_CERT_PATH

账号

至少一个 LLM 提供商 API key

如 OPENAI_API_KEY、ANTHROPIC_API_KEY 等

五、多平台部署步骤

5.1 Linux / macOS(npm 全局安装)

# 1. 确认 Node 版本(必须 >= 22.22.0)
node --version

# 2. 如版本过低,用 nvm 升级
nvm install 24
nvm use 24

# 3. 全局安装
npm install -g promptfoo

# 4. 验证
promptfoo --version

# 5. 初始化一个项目(交互式向导,生成 promptfooconfig.yaml)
promptfoo init

# 6. 也可以用官方示例项目
promptfoo init --example getting-started
cd getting-started

# 7. 配置 API key
export OPENAI_API_KEY=sk-abc123

# 8. 跑评测 + 开 Web viewer
promptfoo eval
promptfoo view

5.2 macOS(Homebrew)

brew install promptfoo
promptfoo --version
promptfoo init --example getting-started

5.3 免安装方式(npx,跨平台,CI 首选)

# 不装全局包,直接跑
npx promptfoo@latest init --example getting-started
cd getting-started
export OPENAI_API_KEY=sk-abc123
npx promptfoo@latest eval
npx promptfoo@latest view

5.4 Windows(PowerShell)

# 确认 Node 版本
node --version

# 全局安装
npm install -g promptfoo

# 验证(若仍有残留路径,说明装了多份)
where.exe promptfoo

# 设置 API key(当前会话)
$env:OPENAI_API_KEY = "sk-abc123"

# 跑评测
promptfoo init
promptfoo eval
promptfoo view

Windows 上 Python provider 的检测顺序(官方文档):provider 的 config.pythonExecutable → PROMPTFOO_PYTHON → Windows 智能探测(where python,过滤 Microsoft Store 存根)→ python -c "import sys; print(sys.executable)" → 依次尝试 python / python3 / py -3 / py。装的是 Microsoft Store 版 Python 时建议显式设置:

$env:PROMPTFOO_PYTHON = "C:\Users\YourName\AppData\Local\Microsoft\WindowsApps\python.exe"

5.5 Docker(官方预构建镜像,用于自托管 Web UI 与结果存储)

官方镜像托管在 GitHub Container Registry,镜像名是 ghcr.io/promptfoo/promptfoo。官方文档未使用 Docker Hub 上的同名镜像,请以此为准。

# 1. 拉取(也可固定版本,例如 ghcr.io/promptfoo/promptfoo:0.109.1)
docker pull ghcr.io/promptfoo/promptfoo:latest

# 2. 校验镜像来源(可选)
# gh attestation verify oci://ghcr.io/promptfoo/promptfoo:latest --owner promptfoo

# 3. 启动:务必做卷映射,否则数据丢失
docker run -d \
  --name promptfoo_container \
  -p 3000:3000 \
  -v ./promptfoo_data:/home/promptfoo/.promptfoo \
  -e OPENAI_API_KEY=sk-abc123 \
  ghcr.io/promptfoo/promptfoo:latest

访问 http://localhost:3000 打开 Web UI。

Docker Compose 版本:

# docker-compose.yml
version: '3.8'
services:
  promptfoo_container:
    image: ghcr.io/promptfoo/promptfoo:latest
    ports:
      - '3000:3000'
    volumes:
      - ./promptfoo_data:/home/promptfoo/.promptfoo
    environment:
      - PROMPTFOO_SHARE_CHUNK_SIZE=10
      - OPENAI_API_KEY=your_key_here
mkdir -p ./promptfoo_data
docker compose up -d

让本地 CLI 指向自托管实例:

export PROMPTFOO_REMOTE_API_BASE_URL=http://your-server-address:3000
export PROMPTFOO_REMOTE_APP_BASE_URL=http://your-server-address:3000
promptfoo eval
promptfoo share
# 或一条命令
promptfoo eval --share

也可以写进配置文件(优先级最高):

sharing:
  apiBaseUrl: http://your-server-address:3000
  appBaseUrl: http://your-server-address:3000

自定义配置目录(容器内换路径):

mkdir -p ./my_custom_data
docker run -d --name promptfoo_container -p 3000:3000 \
  -v ./my_custom_data:/app/data \
  -e PROMPTFOO_CONFIG_DIR=/app/data \
  ghcr.io/promptfoo/promptfoo:latest

限制 Web UI 里可用的 provider(成本控制 / 走内部网关): 在 .promptfoo 目录(与 promptfoo.db 同级)放 ui-providers.yaml:

providers:
  - openai:gpt-5.1-mini
  - id: openai:gpt-5.1
    label: GPT-5.1 (Company Approved)
    config:
      temperature: 0.7
      max_tokens: 4096
  - id: 'http://llm-gateway.company.com/v1'
    label: Internal Gateway
    config:
      method: POST
      headers:
        Authorization: 'Bearer {{ env.INTERNAL_API_KEY }}'

5.6 pip / pipx:不是官方主推方式

  • README 提到 pip install promptfoo 也可用,但官方安装文档只列了 npm / npx / brew 三种。

  • 不建议使用 pipx:promptfoo 的核心是 Node 包,通过 pip 安装的本质仍是包装 Node 运行时;自定义 Python provider 只需要系统里有 python3 即可,不需要 pipx。

  • 官方未提供 pipx install promptfoo 的说明,因此本文不给出该命令。

5.7 源码编译(不推荐,仅贡献者需要)

git clone https://github.com/promptfoo/promptfoo.git
cd promptfoo
npm install
npm run build

遇到原生依赖(libsql 等)编译失败时安装构建工具链:

# Ubuntu / Debian
sudo apt-get install build-essential
# macOS
xcode-select --install
# 强制本地编译
npm install --build-from-source

六、配置文件全部参数解释

6.1 顶层参数(Config)

参数

类型

必填

默认值

说明

description

string

否

—

这套测试做什么的描述

tags

Record

否

—

测试套件标签(如 env: production);运行级标签用 promptfoo eval --tag

providers

ProvidersConfig

是(除非有 targets)

—

被测的 LLM API 列表

targets

ProvidersConfig

是(除非有 providers)

—

providers 的别名,红队配置里常用

prompts

string / string[] / Record / Prompt[]

是

—

一条或多条提示词,支持 file:// 路径与 raw 内联

tests

string / (string|TestCase|Generator)[]

否

—

测试文件路径、内联用例或生成器;省略则每个 prompt/provider 组合跑一次空变量

scenarios

(string|Scenario)[]

否

—

场景文件或内联场景定义

defaultTest

file://... / Partial TestCase

否

—

所有测试用例的默认属性

outputPath

string / string[]

否

—

输出文件路径;不设则输出到终端 / Web viewer

sharing

boolean / object

否

—

结果分享;对象形式支持 apiBaseUrl、appBaseUrl

nunjucksFilters

Record

否

—

Nunjucks 过滤器名 → 文件路径

basePath

string

否

配置文件所在目录

本地文件引用的基准目录

env

Record

否

—

本次运行注入的环境变量,覆盖已有环境变量

derivedMetrics

DerivedMetric[]

否

—

eval 结束后基于命名分数计算的派生指标

extensions

string[]

否

—

扩展 hook 文件(beforeAll / afterAll / beforeEach / afterEach,.py 或 .js)

metadata

Record

否

—

随 eval 配置一起存储的任意元数据

redteam

RedteamConfig

否

—

红队配置

writeLatestResults

boolean

否

—

把最新结果写入 promptfoo 存储,便于 Web UI 查看

tracing

TracingConfig

否

—

OpenTelemetry 追踪配置

commandLineOptions

CommandLineOptions

否

—

命令行选项的默认值

6.2 evaluateOptions

参数

类型

默认值

说明

maxConcurrency

number

4

最大并发请求数

repeat

number

1

每条用例重复运行次数;不同 repeat 索引使用独立缓存命名空间

delay

number

0

每次 API 调用后等待的毫秒数

showProgressBar

boolean

—

是否显示进度条

cache

boolean

true

是否使用磁盘缓存

timeoutMs

number

0(不限)

单条用例 / 单次 provider 调用的超时

maxEvalTimeMs

number

0(不限)

整个 eval 的总时长上限,超出后剩余用例标记为 error

对应环境变量:PROMPTFOO_EVAL_TIMEOUT_MS、PROMPTFOO_MAX_EVAL_TIME_MS。

6.3 Test Case(测试用例)

参数

类型

说明

description

string

用例描述;仅含非空 description 的行会按默认配置运行

vars

Record / string / string[]

注入提示词的变量;字符串/数组时从文件加载

provider

string / ProviderOptions / ApiProvider

覆盖该用例使用的 provider

providers

string[]

过滤该用例跑哪些 provider,支持标签、ID 与通配符(如 openai:*)

prompts

string[]

过滤该用例跑哪些 prompt,支持通配符(如 Math:*)

providerOutput

string / Record

预置输出,跳过实际调用直接跑断言

assert

(Assertion | AssertionSet)[]

断言列表

assertScoringFunction

file:// js/py 路径或函数

自定义评分函数,合并命名断言分数

threshold

number

综合分数低于该值则判定失败

metadata

Record

附加元数据,便于过滤与分组

options.transformVars

string / function

变量注入前的转换(js/py 文件或函数)

options.transform

string / function

对 LLM 输出做转换后再断言

options.postprocess

string / function

已废弃,等价于 options.transform

options.prefix / options.suffix

string

追加到提示词前 / 后的文本

options.provider

ProviderOptions / ApiProvider

model-graded 断言使用的打分模型

options.rubricPrompt

string / string[] / ChatMessage[]

自定义 model-graded 的评分提示词

options.factuality

object

factuality 断言的权重(subset / superset / agree / disagree / differButFactual)

options.disableVarExpansion

boolean

为 true 时 vars 里的数组不展开成多条用例

options.disableConversationVar

boolean

不包含隐式 _conversation 变量

options.disableDefaultAsserts

boolean

不继承 defaultTest.assert(其他 defaultTest 属性仍生效)

options.runSerially

boolean

该用例串行执行,忽略全局并发

options.storeOutputAs

string

把输出存成变量供后续用例使用(多轮对话)

options.<provider-specific>

any

透传给 provider 的字段,如 response_format、responseSchema、temperature

6.4 Assertion(断言)

参数

类型

必填

说明

type

string

是

断言类型,支持 not- 前缀取反

value

string / string[] / number / object / function

否

期望值

config

Record

否

传给断言或断言值函数的额外配置

threshold

number

否

阈值(similar / cost / javascript / python 等类型用)

weight

number

否(默认 1)

相对权重,最终分数为加权平均

provider

string / ProviderOptions

否

similar / llm-rubric / model-graded-* 需要的 LLM provider

rubricPrompt

string / string[] / ChatMessage[]

否

覆盖 model-graded 的评分标准

metric

string

否

命名指标,同名 metric 会聚合

transform

string / function

否

断言前对输出做转换

contextTransform

string / function

否

把 provider 归一化输出转成上下文,供上下文类断言使用

6.5 Assertion Set

参数

类型

必填

说明

type

assert-set

是

标记为断言集

assert

Assertion[]

是

集合内的断言

threshold

number

否

集合所需的通过分数(如 4 条等权断言中要过 1 条,填 0.25)

weight

number

否

集合相对其他断言的权重

metric

string

否

集合的命名指标

config

Record

否

集合内每条断言共享的配置

6.6 commandLineOptions(写入 YAML 的命令行默认值)

分类

参数

类型

说明

基础

config

string[]

配置文件路径

基础

envPath

string | string[]

.env 文件路径,后写的覆盖先写的

输入

prompts

string[]

prompt 文件路径

输入

providers

string[]

provider 标识符

输入

tests / vars / assertions / modelOutputs

string

对应输入文件路径

提示词

promptPrefix / promptSuffix

string

前缀 / 后缀

提示词

generateSuggestions

boolean

生成新 prompt 并追加

提示词

suggestionsCount

integer

生成数量,默认 1,最大 50(等价 CLI --suggest-prompts <n>)

执行

maxConcurrency / repeat / delay

number

并发数 / 重复次数 / 间隔毫秒

执行

grader

string

model-graded 使用的 provider

执行

var

object

以键值对设置测试变量

执行

tags

object

默认 eval 标签,--tag 会覆盖同键

过滤

filterPattern

string

按 description 正则过滤

过滤

filterPrompts / filterProviders / filterTargets

string

按 prompt / provider 的 id 或 label 正则过滤

过滤

filterFirstN / filterRange / filterSample / filterSampleSeed

number / string

前 N 条 / start:end 区间 / 随机 N 条 / 随机种子

过滤

filterMetadata

string | string[]

key=value 元数据过滤,多个之间为 AND

过滤

filterErrorsOnly / filterFailing / filterFailingOnly

string

只跑上次出错 / 失败 / 仅断言失败的用例

输出

output

string[]

输出路径(csv/txt/json/jsonl/yaml/yml/html/xml/junit.xml)

输出

table / tableCellMaxLength / progressBar / verbose

boolean / number

终端表格与日志相关

输出

share / noShare

boolean

是否生成分享链接

缓存

cache / write

boolean

是否用缓存(默认 true)/ 是否写结果(默认 true)

其他

watch / retryErrors / extension

boolean / string[]

监听改动 / 重试错误 / 扩展 hook

6.7 断言类型全表(官方 Assertions & Metrics)

确定性断言(Deterministic eval metrics)

类型

通过条件

equals

输出完全匹配

contains / icontains

输出包含指定子串(后者忽略大小写)

regex

输出匹配正则

starts-with

输出以指定字符串开头

contains-any / contains-all

包含列表中任意一个 / 全部子串

icontains-any / icontains-all

同上,忽略大小写

is-json / contains-json

是合法 JSON / 含合法 JSON(可选 JSON Schema 校验)

is-html / contains-html

是合法 HTML / 含 HTML

is-sql / contains-sql

是合法非空 SQL / 含合法 SQL

is-xml / contains-xml

是合法 XML / 含 XML 片段

is-refusal

provider 报告拒绝,或输出表现为拒绝

javascript / python / ruby

自定义脚本函数校验输出

webhook

调用 webhook,返回 pass 布尔与 0~1 的 score

rouge-l / rouge-n / rouge-s

ROUGE 分数 ≥ threshold(默认 0.75)

bleu / gleu

BLEU / GLEU ≥ threshold(默认 0.5)

levenshtein

编辑距离低于阈值

meteor

METEOR ≥ threshold(默认 0.5,需 natural 包)

latency

延迟低于阈值(毫秒)

perplexity / perplexity-score

困惑度低于阈值 / 归一化困惑度

cost

成本低于阈值,或记为 0 权重的命名指标

is-valid-function-call / is-valid-openai-function-call

函数调用符合 JSON Schema

is-valid-openai-tools-call

所有 tool call 符合 tools JSON Schema

tool-call-f1

tool 名称达到 F1 阈值

trace-span-count / trace-span-duration / trace-error-spans

OpenTelemetry span 数量 / 时长 / 错误率校验

skill-used

provider 的 skill 元数据包含预期 skill

trajectory:tool-used / trajectory:tool-args-match / trajectory:tool-sequence / trajectory:step-count

Agent 轨迹中的工具调用校验

guardrails

评估 target 的归一化输入 / 输出护栏信号

模型辅助断言(Model-assisted eval metrics)

类型

方法

similar

嵌入 + 余弦相似度高于阈值

classifier

把输出送进分类器

moderation

按安全策略检查输出,并记录 provider 上报的用量

llm-rubric

用兼容模型按评分标准给文本 / 图像 / 音频打分

g-eval

基于 G-Eval 框架的思维链式自定义标准评估

answer-relevance

输出与原始问题相关(默认阈值 0.5)

context-faithfulness

输出使用了给定上下文(默认 0.5)

context-recall

ground truth 出现在上下文中(默认 0.5)

context-relevance

上下文与问题相关(默认 0.5)

conversation-relevance

多轮对话中回复始终相关

trajectory:goal-success

LLM judge 判断 traced agent 是否达成目标

factuality / model-graded-factuality

输出是否遵循给定事实(OpenAI eval 的 Factuality 方法)

model-graded-closedqa

输出是否符合给定标准(OpenAI eval 的 Closed QA 方法)

pi

用专用模型评估标准的替代打分方式

select-best

比较同一用例的多个输出并挑出最好的

max-score

选取其他断言聚合分最高的输出

提示:每种类型都能加 not- 前缀取反,例如 not-equals、not-regex、not-javascript。

6.8 Provider 配置

Provider 语法有三种写法:

# 1) 简单字符串
providers:
  - openai:gpt-5
  - anthropic:messages:claude-opus-5

# 2) 对象 + config
providers:
  - id: openai:gpt-5
    label: gpt-5-prod
    config:
      max_completion_tokens: 150
      temperature: 0.7

# 3) 引用外部文件
providers:
  - file://provider.yaml      # 单个 provider 对象
  - file://providers.yaml     # provider 数组

ProviderOptions 字段:id、label、config(含 cost / inputCost / outputCost 价格覆盖)、prompts(该 provider 跑哪些 prompt)、transform、delay、env(provider 级环境覆盖)、inputs(红队多输入定义)。

常用 config 选项:temperature、max_tokens、max_completion_tokens(OpenAI 推理模型用)、top_p、frequency_penalty、presence_penalty、stop、apiKey。

环境变量解析优先级:provider env → eval env → --env-file → shell 变量;显式写在 provider config 里的值优先级最高。

常用 provider 与 ID 示例(官方 Providers 表节选)

Provider

说明

示例 ID

OpenAI

GPT 系列

openai:gpt-6-luna / openai:gpt-6-sol

Anthropic

Claude 系列

anthropic:messages:claude-opus-5-5

Azure OpenAI

Azure 托管 OpenAI

azure:chat:my-deployment-name

Google AI Studio

Gemini 系列

google:gemini-3.8-flash

Google Vertex AI

GCP 上的模型

vertex:gemini-3.8-flash

AWS Bedrock

AWS 托管多厂商模型

bedrock:us.anthropic.claude-opus-5

AWS Bedrock Agents

Bedrock Agent

bedrock-agent:YOUR_AGENT_ID

Amazon SageMaker

SageMaker 端点

sagemaker:custom:my-endpoint-name

Ollama

本地模型

ollama:chat:llama3.3

vLLM

本地 OpenAI 兼容服务

openai:chat:<served-model-name> + apiBaseUrl

llama.cpp

本地

llama:7b

HTTP / HTTPS

任意 HTTP 端点

https://api.example.com/v1/chat/completions

WebSocket

WS 端点

ws://example.com/ws

自定义 JS

JS 文件

file://path/to/custom_provider.js

自定义 Python

Python 文件

file://path/to/custom_provider.py

自定义 Ruby

Ruby 文件

file://path/to/custom_provider.rb

Shell 命令

可执行脚本

exec: python chain.py

LiteLLM

400+ 模型统一接口

litellm:gpt-5

OpenRouter

多厂商统一 API

openrouter:openai/gpt-5.6-sol

Groq / Cerebras / Together / Fireworks

高性能推理

groq:openai/gpt-oss-120b 等

DeepSeek / Mistral / Cohere / Moonshot

各家厂商

见官方文档

6.9 带注释的完整配置示例

# yaml-language-server: $schema=https://promptfoo.dev/config-schema.json
# ---------- 基础元信息 ----------
description: '中文客服机器人提示词回归测试'
tags:
  env: production
  application: support-bot

# ---------- 被测目标 ----------
providers:
  - id: openai:gpt-5-mini
    label: gpt-5-mini
    config:
      temperature: 0
      max_completion_tokens: 512
  - id: anthropic:messages:claude-sonnet-4-5-20250929
    label: claude-sonnet
  - id: ollama:chat:llama3.3
    label: local-llama
    delay: 200              # 本地模型限速
  # 自定义 HTTP 端点
  - id: https://api.example.com/v1/chat/completions
    label: internal-gateway
    config:
      method: POST
      headers:
        Authorization: 'Bearer {{ env.INTERNAL_API_KEY }}'
  # 自定义 Python provider
  - id: file://./providers/my_provider.py:call_api
    label: my-python-agent

# ---------- 提示词 ----------
prompts:
  - '你是 {{company}} 的客服助手,请用中文回答:{{question}}'
  - file://prompts/v2.txt

# ---------- 默认测试属性 ----------
defaultTest:
  options:
    provider:
      text:
        id: openai:gpt-5-mini       # model-graded 断言用的打分模型
    transform: 'output.trim()'      # 输出先 trim 再断言
  assert:
    - type: latency
      threshold: 5000
    - type: cost
      threshold: 0.02

# ---------- 测试用例 ----------
tests:
  - description: '标准问候'
    vars:
      company: 示例科技
      question: 你好
    assert:
      - type: contains
        value: '你好'
      - type: llm-rubric
        value: '回复应当礼貌、简洁,且使用中文'
        metric: Politeness
        weight: 2
      - type: not-contains
        value: '抱歉,我不能'

  - description: '退款政策问询'
    vars:
      company: 示例科技
      question: 你们支持 7 天无理由退款吗?
    assert:
      - type: assert-set
        threshold: 0.5                # 两条里过一条即可
        assert:
          - type: cost
            threshold: 0.005
          - type: latency
            threshold: 2000
      - type: similar
        value: '支持 7 天无理由退款'
        threshold: 0.8

  - description: '结构化输出校验'
    vars:
      company: 示例科技
      question: 查询订单 12345
    options:
      response_format: file://./schemas/order-response.json   # 透传给 provider
    assert:
      - type: is-json
      - type: javascript
        value: 'output.orderId === "12345"'

# ---------- 运行参数 ----------
evaluateOptions:
  maxConcurrency: 4
  repeat: 1
  delay: 0
  cache: true
  timeoutMs: 30000
  maxEvalTimeMs: 600000

# ---------- 命令行默认值 ----------
commandLineOptions:
  envPath:
    - .env
    - .env.local
  grader: openai:gpt-5-mini
  table: true
  tableCellMaxLength: 100

# ---------- 输出 ----------
outputPath:
  - results.json
  - report.html
  - results.junit.xml

# ---------- 本次运行的环境变量 ----------
env:
  PROMPTFOO_EVAL_TIMEOUT_MS: 30000
  PROMPTFOO_MAX_EVAL_TIME_MS: 300000

# ---------- 派生指标 ----------
derivedMetrics:
  - name: 'quality'
    value: '(helpfulness + accuracy) / 2'

七、启动、后台常驻、开机自启、改端口

7.1 两类"启动"要分清

场景

命令

说明

跑一次评测(批处理)

promptfoo eval

跑完即退出,不需要常驻

看结果(Web viewer)

promptfoo view -p 15500

前台长驻 HTTP 服务,Ctrl+C 停止

红队配置向导

promptfoo redteam setup -p 15500

默认端口 15500

红队报告

promptfoo redteam report -p 15500

默认端口 15500

自托管服务端(Docker)

docker run -d ... -p 3000:3000 ghcr.io/promptfoo/promptfoo:latest

容器默认端口 3000

7.2 修改端口

# Web viewer 换端口
promptfoo view -p 15500
promptfoo view -p 8080 -y          # -y 自动打开浏览器
promptfoo view -p 8080 -n          # -n 不打开浏览器

# 红队报告换端口
promptfoo redteam report -p 8080

# 自托管容器换端口(改 host 侧映射,容器内仍是 3000)
docker run -d -p 8080:3000 \
  -v ./promptfoo_data:/home/promptfoo/.promptfoo \
  ghcr.io/promptfoo/promptfoo:latest

若使用了 PROMPTFOO_CONFIG_DIR 改过输出目录,需要显式指定目录:promptfoo view [directory]。

7.3 Linux 后台常驻(systemd)

自托管服务端建议直接让 Docker 托管(restart: unless-stopped)。如果确实要用 systemd 包一层:

# /etc/systemd/system/promptfoo.service
[Unit]
Description=Promptfoo self-hosted server
After=docker.service
Requires=docker.service

[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/docker start -a promptfoo_container
ExecStop=/usr/bin/docker stop -t 10 promptfoo_container

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now promptfoo
sudo systemctl status promptfoo

Compose 版本更简洁:

# /etc/systemd/system/promptfoo-compose.service
[Unit]
Description=Promptfoo compose stack
After=docker.service
Requires=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/promptfoo
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=multi-user.target

7.4 Supervisor(备选)

[program:promptfoo]
command=/usr/bin/docker start -a promptfoo_container
autostart=true
autorestart=true
stderr_logfile=/var/log/promptfoo.err.log
stdout_logfile=/var/log/promptfoo.out.log

7.5 Windows 计划任务 / NSSM

Promptfoo 的 eval 是批处理任务,Windows 下用「任务计划程序」定时跑即可:

# 创建一个每周一 09:00 跑评测的计划任务
$action  = New-ScheduledTaskAction -Execute "npx" -Argument "promptfoo@latest eval -c C:\evals\promptfooconfig.yaml -o C:\evals\results.json"
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At 9am
Register-ScheduledTask -TaskName "Promptfoo Weekly Eval" -Action $action -Trigger $trigger -Description "Weekly LLM eval"

如需把 Web viewer 做成 Windows 服务,可用 NSSM:

nssm install promptfoo-view "C:\Program Files\nodejs\node.exe"
nssm set promptfoo-view AppParameters "C:\Users\me\AppData\Roaming\npm\node_modules\promptfoo\dist\src\main.js view -p 15500 -n"
nssm start promptfoo-view

7.6 Docker Compose 自启

Compose 文件里加 restart: unless-stopped(官方示例已包含),然后:

docker compose up -d          # 会随 docker daemon 重启而自动拉起
docker compose logs -f promptfoo_container

7.7 反向代理示例(Nginx)

server {
    listen 80;
    server_name promptfoo.internal.example.com;

    location / {
        proxy_pass         http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header   Host              $host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        # Web UI 用到 SSE / WebSocket 长连接
        proxy_set_header   Upgrade           $http_upgrade;
        proxy_set_header   Connection        "upgrade";
        proxy_read_timeout 3600s;
    }
}

⚠️ 官方明确说明自托管版本没有内置鉴权与 SSO,放到公司内网时必须由反向代理或网关提供认证,不要直接暴露到公网。

八、功能实操教程

8.1 场景一:从零跑通第一个 eval

mkdir my-evals && cd my-evals
npx promptfoo@latest init --example getting-started
cd getting-started
export OPENAI_API_KEY=sk-abc123
npx promptfoo@latest eval
npx promptfoo@latest view

生成的 promptfooconfig.yaml 形如:

prompts:
  - 'Convert the following English text to {{language}}: {{input}}'
providers:
  - openai:gpt-6-sol
  - openai:gpt-6-luna
tests:
  - vars:
      language: French
      input: Hello world
    assert:
      - type: contains
        value: 'Bonjour le monde'
  - vars:
      language: Spanish
      input: Where is the library?
    assert:
      - type: icontains
        value: 'Dónde está la biblioteca'

终端输出是一张矩阵表,Web viewer 里可以逐格查看完整输出、prompt、变量与打分理由。

Promptfoo Web Viewer 评测矩阵

8.2 场景二:横向对比多家模型(含本地模型)

providers:
  - openai:gpt-5-mini
  - anthropic:messages:claude-sonnet-4-5-20250929
  - vertex:gemini-3.8-flash
  - bedrock:us.anthropic.claude-opus-5
  - ollama:chat:llama3.3
prompts:
  - '用一句话解释 {{concept}}'
tests:
  - vars: { concept: '向量数据库' }
    assert:
      - type: llm-rubric
        value: '解释必须准确、不超过 50 字、且用中文'
        metric: Accuracy
      - type: cost
        threshold: 0.01
      - type: latency
        threshold: 8000

设置各家 key:

export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-ant-...
export GOOGLE_API_KEY=...       # Google AI Studio
# Vertex / Bedrock 走各自云凭证,见官方 provider 文档

只跑某几家:

promptfoo eval --filter-providers 'openai.*'
promptfoo eval --filter-providers 'ollama.*'

8.3 场景三:自定义 HTTP / Python provider

HTTP 端点(打你自己的服务):

providers:
  - id: https://myapp.internal/generate
    label: my-app
    config:
      method: POST
      headers:
        'Content-Type': 'application/json'
        Authorization: 'Bearer {{ env.MYAPP_TOKEN }}'
      body:
        message: '{{prompt}}'
      responseParser: 'json.choices[0].message.content'

Python provider(my_provider.py):

def call_api(prompt, options, context):
    # context["vars"] 可拿到测试用例变量
    return {
        "output": f"echo: {prompt}",
        "tokenUsage": {"total": 10, "prompt": 5, "completion": 5},
    }
providers:
  - id: file://./my_provider.py:call_api

调试 Python provider:

LOG_LEVEL=debug npx promptfoo eval
# 或
npx promptfoo eval --verbose
# 启用 pdb 断点
export PROMPTFOO_PYTHON_DEBUG_ENABLED=true

8.4 场景四:RAG 质量评估(上下文类断言)

prompts:
  - |
    仅根据以下上下文回答问题,若上下文没有答案请回答"不知道"。
    上下文:{{context}}
    问题:{{question}}
providers: [openai:gpt-5-mini]
tests:
  - vars:
      context: '公司成立于 2019 年,总部位于杭州。'
      question: '公司总部在哪里?'
    assert:
      - type: context-faithfulness      # 答案必须来自上下文
        threshold: 0.6
      - type: context-relevance
        threshold: 0.5
      - type: answer-relevance
        threshold: 0.5
      - type: factuality
        value: '公司总部位于杭州'

需要自定义上下文来源时用 contextTransform(把 RAG 检索结果转成 context)。

8.5 场景五:缓存管理与"改了 prompt 没生效"

# 查看是否被缓存命中(输出里会有 cached 标记)
promptfoo eval

# 强制穿透缓存
promptfoo eval --no-cache

# 清空缓存
promptfoo cache clear
rm -rf ~/.promptfoo/cache

# 自定义缓存位置与类型
export PROMPTFOO_CACHE_TYPE=disk
export PROMPTFOO_CACHE_PATH=/data/promptfoo/cache
export PROMPTFOO_CACHE_TTL=604800        # 单位秒,默认 14 天
export PROMPTFOO_CACHE_ENABLED=false     # 全局关闭

缓存关键行为(官方 Caching 文档):

  • 缓存键包含 provider 标识 + 请求内容摘要 + provider 配置 + 上下文变量。

  • 错误响应不缓存,便于重试;空响应不缓存。

  • --repeat > 1 时每个 repeat 索引使用独立缓存命名空间。

  • 429 响应自动指数退避;HTTP 500 可通过 PROMPTFOO_RETRY_5XX=true 重试。

  • 缓存不随"修改 prompt 文件的时间戳"失效 —— 它看的是内容摘要。若你改了 prompt 但结果没变,检查是否改的是未被 include 的文件,或直接用 --no-cache。

8.6 场景六:红队测试全流程

# 方式 A:Web 向导(默认 15500 端口)
npx promptfoo@latest redteam setup

# 方式 B:命令行初始化,不打开浏览器
npx promptfoo@latest redteam init --no-gui

# 生成对抗用例并立即执行
npx promptfoo@latest redteam run

# 查看报告
npx promptfoo@latest redteam report -p 15500

redteam run = redteam generate + redteam eval,生成的用例默认写到 redteam.yaml。

典型红队配置:

targets:
  - id: openai:gpt-5
    label: customer-service-agent

redteam:
  numTests: 10
  purpose: |
    应用是一个电商客服机器人,帮助用户查询订单、申请退款。
    用户是已登录的普通用户,不能查看他人订单,不能执行管理员操作。
  plugins:
    - id: 'harmful:hate'
      numTests: 8
      severity: 'critical'
    - id: 'pii'
      severity: 'high'
    - id: 'bola'
    - id: 'bfla'
    - id: 'prompt-injection'
  strategies:
    - 'basic'
    - id: 'jailbreak'
      config:
        plugins:
          - 'harmful:hate'
  frameworks:
    - owasp:llm
    - nist:ai:measure
  language: Chinese
  maxConcurrency: 4
  delay: 0

攻击 HTTP 端点:

targets:
  - id: https
    label: 'travel-agent'
    config:
      url: 'https://example.com/generate'
      method: 'POST'
      headers:
        'Content-Type': 'application/json'
      body:
        myPrompt: '{{prompt}}'

命令参数速查:

命令

关键参数

redteam init

[directory]、--no-gui

redteam setup

[configDirectory]、-p/--port(默认 15500)

redteam run

-c(默认 promptfooconfig.yaml)、-o(默认 redteam.yaml)、-d、--tag、--no-cache、-j、--delay、--remote、--force、--strict、--filter-providers、-t

redteam generate

--purpose、--injectVar(默认 prompt)、--plugins、--strategies、-n、--language、-w、--burp-escape-json

redteam eval

同 eval,但默认加载 redteam.yaml

redteam report

[directory]、-p/--port(默认 15500)

redteam plugins

--ids-only、--default

红队风险报告

8.7 场景七:CI 集成(GitHub Action + 命令行质量门禁)

GitHub Action(官方 promptfoo/promptfoo-action@v1):

name: 'Prompt Evaluation'

on:
  pull_request:
    paths:
      - 'prompts/**'

jobs:
  evaluate:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '24'

      - name: Set up promptfoo cache
        uses: actions/cache@v4
        with:
          path: ~/.cache/promptfoo
          key: ${{ runner.os }}-promptfoo-v1
          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 }}
          prompts: 'prompts/**/*.json'
          config: 'prompts/promptfooconfig.yaml'
          cache-path: ~/.cache/promptfoo

Action 参数:github-token(必填)、prompts(必填)、config(必填)、openai-api-key、cache-path。Action 依赖环境变量 PROMPTFOO_CONFIG_DIR 与 PROMPTFOO_CACHE_PATH。要求 runner 上 Node.js ≥ 22.22.0,推荐 24。

命令行 + JUnit(通用 CI):

# 生成 JUnit XML,交给 CI 的测试报告面板
npx promptfoo@latest eval -c promptfooconfig.yaml -o results.junit.xml

# 同时产出多种格式
npx promptfoo@latest eval -o results.json -o report.html -o results.junit.xml

# 红队扫描
npx promptfoo@latest redteam run

# 附加流水线上下文标签
npx promptfoo@latest eval --tag ci.run-id="$CI_PIPELINE_ID" --tag git.sha="$CI_COMMIT_SHA"

JUnit 结构要点:每个 prompt/provider 对一个 testsuite,每条 eval 结果一个 testcase,断言失败为 failure,provider / 运行时错误为 error。

退出码与质量门禁:

  • 至少 1 条用例失败,或通过率低于 PROMPTFOO_PASS_RATE_THRESHOLD → 退出码 100。

  • 其他错误 → 退出码 1。

  • 失败退出码可用 PROMPTFOO_FAILED_TEST_EXIT_CODE 覆盖。

export PROMPTFOO_PASS_RATE_THRESHOLD=0.9
npx promptfoo@latest eval -o results.json || echo "质量门禁未通过"

# 用 jq 自己算通过率
PASS_RATE=$(jq '.results.stats.successes / (.results.stats.successes + .results.stats.failures) * 100' results.json)

CI 里缓存 npx 下载:

- uses: actions/setup-node@v4
  with:
    node-version: '24'
    cache: 'npm'
    cache-dependency-path: '**/.github/workflows/*.yml'
- run: npx promptfoo@latest redteam run -c config.yaml -o output.json

8.8 场景八:代码扫描(code scanning)

npx promptfoo@latest code-scans run [repo-path]

扫描结果用于在 PR 里标注 LLM 相关的安全与合规问题。

Code scanning 示例

九、全套报错故障排查

#

现象

原因

解决

1

ERROR: Cannot find module '@libsql/darwin-arm64'

平台原生绑定缺失或 npm 跳过了可选依赖

项目内 npm install;仍不行用 npm install --include=optional;全局装用 npm install -g promptfoo@latest;npx 用 npm cache npx ls → npm cache npx rm <key> → npx -y promptfoo@latest

2

Node 版本相关报错 / 命令直接不启动

Node < 22.22.0

nvm install 24 && nvm use 24,CI 里把 Node 设为 24

3

OpenAI API key is not set

没设 OPENAI_API_KEY,或用了需要 LLM 的断言(similar / llm-rubric / moderation)却没配 grader

export OPENAI_API_KEY=...;或在 provider config.apiKey 写死;或按官方说明覆盖 grader(见下条)

4

没用 OpenAI 却提示要 OpenAI key

使用了 model-graded 断言,默认 grader 是 OpenAI

在 defaultTest.options.provider 指定 text 与 embedding 的 provider(如 Azure)

5

429 Rate limit

并发过高 / provider 配额不足

降 evaluateOptions.maxConcurrency(默认 4)、加 delay;429 已有自动指数退避;必要时 --retry-errors

6

HTTP 500 反复失败

默认不重试 5xx

export PROMPTFOO_RETRY_5XX=true

7

EADDRINUSE: address already in use :::15500

15500 端口被占用(另一个 view / redteam report 进程)

promptfoo view -p 16000;或 lsof -i :15500 / netstat -ano \| findstr :15500 杀掉占用进程

8

JavaScript heap out of memory

用例或输出太大

不用 --no-write;加 --no-table;输出改用 --output results.jsonl(分批写入);或 NODE_OPTIONS="--max-old-space-size=8192" npx promptfoo eval

9

内存仍不足

结果里携带了大量大字段

PROMPTFOO_STRIP_PROMPT_TEXT=true、PROMPTFOO_STRIP_RESPONSE_OUTPUT=true、PROMPTFOO_STRIP_TEST_VARS=true、PROMPTFOO_STRIP_GRADING_RESULT=true、PROMPTFOO_STRIP_METADATA=true

10

Python files require a function name

file://xxx.py 未指定函数名

写成 file://./tools.py:get_tools;JS 同理 file://./tools.js:getTools

11

spawn py -3 ENOENT / Python 3 not found

找不到 Python

export PROMPTFOO_PYTHON=/usr/local/bin/python3(Windows 写 python.exe 全路径),或在 provider 里配 config.pythonExecutable

12

eval 卡住不结束

provider 无响应 / 没设超时

PROMPTFOO_EVAL_TIMEOUT_MS=30000、PROMPTFOO_MAX_EVAL_TIME_MS=300000,或写进 evaluateOptions.timeoutMs / maxEvalTimeMs

13

企业网络下连不上 LLM API

代理 / 自签 CA

export HTTPS_PROXY=http://proxy.company.com:8080、NO_PROXY=localhost,127.0.0.1、PROMPTFOO_CA_CERT_PATH=/path/to/ca-bundle.crt;用 promptfoo debug 验证

14

原生模块编译失败

缺少 C/C++ 工具链

Ubuntu sudo apt-get install build-essential;macOS xcode-select --install;Windows 装 VS Build Tools;再 npm rebuild

15

模板里出现 [object Object]

对象被转成字符串

默认已自动 JSON 序列化;需要 {{ product.name }} 这种属性访问时设 PROMPTFOO_DISABLE_OBJECT_STRINGIFY=true

16

改了 prompt 结果不变

命中磁盘缓存

promptfoo eval --no-cache 或 promptfoo cache clear;注意 repeat>1 时每个索引有独立缓存命名空间

17

自托管实例报 "Job not found"

跑了多个副本,SQLite 无法共享

官方自托管不支持水平扩展,只能单副本;多团队场景改用 Enterprise

18

Docker 容器重启后历史 eval 全没了

没做卷映射

必须 -v <host>:/home/promptfoo/.promptfoo;大媒体文件还会落在 .../blobs,也要一起持久化(或用 PROMPTFOO_INLINE_MEDIA=true 改回内联)

19

promptfoo share 分享链接指向 localhost:3000

预构建镜像里的静态变量被内联

官方说明:预构建镜像下 share 可能开箱即用不了;显式设 PROMPTFOO_REMOTE_API_BASE_URL / PROMPTFOO_REMOTE_APP_BASE_URL 或在 config 里写 sharing.apiBaseUrl

20

分享大 eval 超时 / 失败

分片太大

容器设 PROMPTFOO_SHARE_CHUNK_SIZE=10

21

找不到日志

不知道日志位置

默认在 ~/.promptfoo/logs;promptfoo logs --list / promptfoo logs -n 50 / promptfoo logs -f;改目录用 PROMPTFOO_LOG_DIR;打包给支持团队用 promptfoo export logs

22

需要看 SQL / 数据库层面问题

—

PROMPTFOO_ENABLE_DATABASE_LOGS=true + LOG_LEVEL=debug,跑完 unset

23

-v 没打开 debug 日志

eval 里 -v 是 --vars 的缩写

用 --verbose 或 LOG_LEVEL=debug

24

红队运行中要临时看详细日志

—

交互式终端里按 v 键实时开关 debug(CI / 管道输出里不可用)

25

Web viewer 打开空白 / 数据不对

用了自定义输出目录

promptfoo view <directory> 显式指定目录

26

CI 里 eval 明明失败了但流水线绿

没处理退出码

失败退出码是 100(不是 1);脚本里要判断非 0,或设 PROMPTFOO_FAILED_TEST_EXIT_CODE

十、升级、回滚与卸载

10.1 查看版本

promptfoo --version
npx promptfoo@latest --version
npm view promptfoo version      # 查看 npm 上的最新版

10.2 升级

# npm 全局
npm install -g promptfoo@latest

# 项目依赖
npm install promptfoo@latest --save

# brew
brew upgrade promptfoo

# npx(天然总是最新)
npx promptfoo@latest eval

官方要求:升级前先确认 Node ≥ 22.22.0(推荐 24 LTS),切换运行时后用 node --version 验证再装/升 promptfoo。

10.3 回滚到指定版本

# 全局回滚
npm install -g promptfoo@0.125.0

# 项目内回滚
npm install promptfoo@0.125.0 --save-dev

# npx 指定版本
npx promptfoo@0.125.0 eval

# Docker 固定版本
docker pull ghcr.io/promptfoo/promptfoo:0.109.1
docker run -d -p 3000:3000 \
  -v ./promptfoo_data:/home/promptfoo/.promptfoo \
  ghcr.io/promptfoo/promptfoo:0.109.1

10.4 Docker 升级

docker compose pull
docker compose up -d
docker image prune -f        # 清理旧镜像

10.5 完整卸载

# 1. 卸载包(如果你用多种方式装过,每种都要卸一遍)
npm uninstall -g promptfoo
npm uninstall promptfoo            # 项目依赖
brew uninstall promptfoo           # 若用 brew 装过

# 2. 验证没有残留
which -a promptfoo                 # Mac / Linux
where.exe promptfoo                # Windows
# 项目局部安装(node_modules/.bin/promptfoo)不会被上面命令发现,需删项目依赖

# 3.(可选)删除配置、历史与缓存 —— 会永久删除 eval 历史、数据库与缓存
rm -rf ~/.promptfoo                # Mac / Linux
rmdir /s %USERPROFILE%\.promptfoo  # Windows CMD

# 4. 若自定义过路径,也一并清理
#    PROMPTFOO_CONFIG_DIR / PROMPTFOO_CACHE_PATH / PROMPTFOO_LOG_DIR

# 5. Docker 清理
docker stop promptfoo_container && docker rm promptfoo_container
docker rmi ghcr.io/promptfoo/promptfoo:latest
docker volume rm promptfoo_data    # 谨慎:会删除所有 eval 数据

十一、商用许可与合规风险提示

11.1 License

  • MIT(GitHub License 徽标与 npm 包元数据均为 MIT)。

  • 义务:保留版权与许可声明;无 copyleft 传染性,可自由商用、修改、再分发。

  • README 公告:Promptfoo 已加入 OpenAI,但依旧开源、依旧 MIT。

  • 注意区分:开源 CLI / 自托管镜像(MIT) 与 Promptfoo Enterprise / Cloud 平台 是不同产品,后者涉及商业协议与付费。

11.2 商标与品牌

  • "Promptfoo" 名称与 logo 归项目方所有。MIT 只授予代码使用权,不含商标授权;对外宣传时不要暗示官方背书。

11.3 API 费用与额度

  • Promptfoo 本身免费,但每次 eval 都会真实调用 LLM API 并产生费用。

  • 红队扫描会生成数百到数千条对抗输入,官方提示"单次红队从几分钱到数百美元不等",务必先设 numTests、maxConcurrency、delay 与 provider 侧配额上限。

  • 用缓存、--filter-sample、按 --filter-range 分片跑,可显著省钱。

  • cost 断言 + derivedMetrics 可把成本纳入门禁。

11.4 数据隐私与出网

  • 默认本地执行,prompts 不出机器;但你调用的 LLM provider 会收到你的 prompt 与测试数据。若数据敏感:

  • 只使用本地模型(Ollama / vLLM / llama.cpp)或私有化部署;

  • 对测试数据脱敏;

  • 通过内部网关 provider 统一出口与审计。

  • Web viewer / 自托管服务端默认没有任何鉴权:不要直接暴露公网,必须置于 VPN / 反向代理认证之后。

  • 自托管 SQLite 数据库 promptfoo.db 里存有所有 prompt、输出与变量,属于敏感资产,要控制文件权限与备份加密。

  • promptfoo share 会把结果上传到分享目标(默认官方云,可指向自托管实例);使用 --show-auth 会带上认证信息,公开分享前要确认。

11.5 生产环境风险

  • 自托管镜像官方明确 "not recommended for production use cases"(SQLite、单副本、无 RBAC、无 SSO、无水平扩展、多副本会 "Job not found")。生产协作需求请评估 Enterprise。

  • 红队扫描会生成有害 / 有毒 / 攻击性输入,官方在文档里加了 danger 警告;只在测试环境对自有系统执行,并保留授权记录。

  • CI 中把 prompt 改动与模型改动都纳入回归;建议同时设通过率门禁与成本 / 延迟门禁,避免"指标变好但成本翻十倍"。

附录:命令速查

# ===== 安装与版本 =====
npm install -g promptfoo
brew install promptfoo
npx promptfoo@latest --version
promptfoo --version

# ===== 初始化 =====
promptfoo init
promptfoo init --example getting-started
promptfoo init --no-interactive

# ===== 评测 =====
promptfoo eval
promptfoo eval -c path/to/promptfooconfig.yaml
promptfoo eval -o results.json -o report.html -o results.junit.xml
promptfoo eval --no-cache
promptfoo eval -j 8                       # maxConcurrency
promptfoo eval --repeat 3
promptfoo eval --delay 500
promptfoo eval --filter-pattern 'auth.*'
promptfoo eval --filter-providers 'openai.*'
promptfoo eval --filter-range 0:100
promptfoo eval --filter-sample 50 --filter-sample-seed 42
promptfoo eval --filter-failing results.json
promptfoo eval --retry-errors
promptfoo eval --resume
promptfoo eval --tag env=ci --tag run-id=$CI_RUN_ID
promptfoo eval --share / --no-share
promptfoo eval -w                         # watch 模式,改动即重跑
promptfoo optimize                        # 提示词自动优化

# ===== 查看与分享 =====
promptfoo view
promptfoo view -p 15500 -y
promptfoo share
promptfoo share --show-auth
promptfoo list evals / prompts / datasets
promptfoo show <id>
promptfoo delete <id>
promptfoo export eval <evalId>
promptfoo export logs

# ===== 缓存 =====
promptfoo cache clear
rm -rf ~/.promptfoo/cache

# ===== 日志 =====
promptfoo logs
promptfoo logs -n 50
promptfoo logs -f
promptfoo logs --list
promptfoo logs --type error
promptfoo logs --grep "openai"
promptfoo debug

# ===== 红队 =====
promptfoo redteam setup                   # 默认端口 15500
promptfoo redteam init --no-gui
promptfoo redteam run
promptfoo redteam run --tag ci.run-id=$CI_RUN_ID
promptfoo redteam generate --purpose '...' --injectVar message
promptfoo redteam eval
promptfoo redteam report -p 8080
promptfoo redteam plugins --default
promptfoo redteam discover -c promptfooconfig.yaml
promptfoo code-scans run

# ===== 账号 =====
promptfoo auth login -k <API_KEY>
promptfoo auth whoami
promptfoo auth logout
promptfoo config set email you@example.com

# ===== 常用环境变量 =====
export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-ant-...
export PROMPTFOO_CONFIG_DIR=/data/promptfoo        # 配置与数据库目录
export PROMPTFOO_CACHE_PATH=/data/promptfoo/cache  # 缓存目录
export PROMPTFOO_LOG_DIR=/data/promptfoo/logs      # 日志目录
export PROMPTFOO_CACHE_ENABLED=true
export PROMPTFOO_CACHE_TYPE=disk                   # disk | memory
export PROMPTFOO_CACHE_TTL=1209600                 # 秒,默认 14 天
export PROMPTFOO_RETRY_5XX=true
export PROMPTFOO_EVAL_TIMEOUT_MS=30000
export PROMPTFOO_MAX_EVAL_TIME_MS=300000
export PROMPTFOO_PASS_RATE_THRESHOLD=0.9
export PROMPTFOO_FAILED_TEST_EXIT_CODE=101
export PROMPTFOO_REMOTE_API_BASE_URL=http://host:3000
export PROMPTFOO_REMOTE_APP_BASE_URL=http://host:3000
export PROMPTFOO_CA_CERT_PATH=/path/to/ca-bundle.crt
export PROMPTFOO_PYTHON=/usr/local/bin/python3
export HTTPS_PROXY=http://proxy.company.com:8080
export NO_PROXY=localhost,127.0.0.1
export NODE_OPTIONS="--max-old-space-size=8192"

评论交流

文章目录