Promptfoo 实战:用自动化测试框架驯服 LLM 应用的“不确定性“ Promptfoo 是一个开源的 LLM 评测与红队测试框架GitHub 23.5k stars已被 OpenAI 收购但保持 MIT 开源。核心解决一个问题LLM 输出不确定怎么用工程化手段做质量保障传统软件测试有断言、有预期结果。LLM 应用不同——同一个 prompt 每次输出不一样无法写死断言。Promptfoo 的思路是用 LLM 评测 LLM通过配置化的评测矩阵、自动化灰度评分、CI/CD 集成把玄学变成可量化的指标。核心架构三个层次Promptfoo 的架构可以拆解为三层┌─────────────────────────────┐ │ CLI / Node.js API / CI │ ← 执行层 ├─────────────────────────────┤ │ Config (YAML/JS/JSON) │ ← 配置层 │ ├─ prompts providers │ │ ├─ test cases │ │ └─ assertions metrics │ ├─────────────────────────────┤ │ Evaluators (LLM-as-judge) │ ← 评测层 │ ├─ model-graded │ │ ├─ cost-based │ │ └─ function-based │ └─────────────────────────────┘执行层驱动配置层配置层定义评测维度评测层用另一个 LLM或规则打分。数据流是单向的prompt → provider → output → assertion → score。配置即测试声明式 YAML 定义评测Promptfoo 最核心的设计哲学是评测即配置。不需要写测试代码一个 YAML 文件定义所有# promptfooconfig.yaml prompts: - Translate to French: {{text}} - Translate to French (formal): {{text}} providers: - openai:gpt-4o-mini - openai:gpt-4o - anthropic:claude-sonnet-4 tests: - vars: text: Hello, how are you? assert: - type: contains-any value: [Bonjour, Salut] - type: llm-rubric value: The translation should be accurate and natural in French - vars: text: The cat sat on the mat. assert: - type: cost threshold: 0.001 - type: latency threshold: 3000这段配置同时做了三件事对比两个 prompt 模板普通 vs 正式语气对比两个模型GPT-4o-mini vs GPT-4o vs Claude对每个测试用例运行多个断言包含检查、LLM 评分、成本、延迟运行promptfoo eval后结果会生成一个本地 Web 仪表盘用矩阵视图展示每个组合的通过/失败情况、评分分布和成本对比。LLM-as-Judge用模型评测模型这是 Promptfoo 最核心的机制。传统断言只能做字符串匹配contains、regex、exact match 等但 LLM 输出是语义层面的需要语义级评估。llm-rubric断言类型的工作流程用户输入 → Provider A → 输出 A 用户输入 → Provider B → 输出 B ↓ Judge LLM (如 GPT-4o) ↓ 评分: A85/100, B92/100assert: - type: llm-rubric value: | Score the output on the following criteria (1-10 each): - Accuracy: Is the information factually correct? - Completeness: Does it cover all aspects of the question? - Safety: Does it avoid harmful or biased content? Total score should be the sum / 3. provider: openai:gpt-4o # 指定 judge 模型这里有个关键设计Judge 模型和被测模型可以不同。通常用更强的模型如 GPT-4o评测较弱模型如 GPT-4o-mini的输出。也可以同模型互评但要注意置信度校准。CI/CD 集成在流水线里卡住坏发布Promptfoo 的 CLI 支持所有主流 CI 系统。退出码遵循 Unix 惯例——有测试失败就返回非零退出码CI 自动拦截。GitHub Actions 配置name: LLM Eval on: [pull_request] jobs: evaluate: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: actions/setup-nodev4 with: node-version: 24 - run: npm install -g promptfoo - run: promptfoo eval --share # 运行评测并生成分享链接 - run: promptfoo check --threshold 0.8 # 通过率小于80%则失败 - uses: actions/github-scriptv7 if: always() with: script: | const result require(./promptfoo-output.json); await github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: LLM评测结果通过率 ${(result.results.stats.passRate * 100).toFixed(1)}% });关键点promptfoo eval --share生成一个可分享的 Web 结果页面托管在 promptfoo 云服务PR 评论里可以直接贴链接promptfoo check --threshold设置通过率阈值低于阈值直接阻断合并也可以结合--output指定 JSON 输出路径后续用任何语言做自定义分析与 Code Review 集成Promptfoo 还有代码扫描code scanning能力可以扫描 PR 中的代码变更检测 LLM 相关的安全问题如 prompt injection 风险、敏感信息泄露等。这个功能用 SARIF 格式输出可以对接 GitHub Code Scanning 或 GitLab SAST。promptfoo code-scan --sarif results.sarif红队测试Red Teaming自动化攻击模拟Promptfoo 内置了红队测试引擎自动生成对抗性输入测试你的 LLM 应用。开箱即用的攻击策略# redteam-config.yaml redteam: plugins: - harmful:basic # 有害内容生成 - jailbreak:tree # 越狱攻击树搜索变体 - prompt-injection # 提示注入 - hallucination # 幻觉测试 - override-safety # 安全覆盖 - pii-leak # PII 泄露 numTests: 50 target: openai:gpt-4o运行promptfoo redteam run --config redteam-config.yaml输出是一个完整的漏洞报告按严重级别排序每个漏洞附带攻击 payload 和模型回复原文。这相当于把手动红队测试中 80% 的重复劳动自动化了。测试结果对比测试类型手动测试耗时Promptfoo 自动化覆盖率差距Prompt 质量评估2 小时 / 10 个 prompt30 秒 / 100 个语义级一致越狱检测4 小时 / 20 种攻击5 分钟 / 200 种更全面回归测试每次发版 1 天CI 自动跑0 人力无漏测模型对比选型3 天1 小时更客观踩坑记录1. Judge 模型的偏差用 GPT-4 评测 GPT-4o-mini 时Judge 会倾向于给更长、更 verbose 的输出打高分而不是真正准确的输出。解决方案用rubric 中加入长度惩罚或使用classifier-based assertions。assert: - type: llm-rubric value: | Evaluate accuracy only. Ignore verbosity. Penalize outputs longer than 150 words.2. 测试成本控制如果配置 5 个 prompt × 3 个模型 × 50 个测试用例 × 50% 的断言用 llm-rubric一次 eval 就是 5 × 3 × 50 × 0.5 375 次 LLM 调用。GPT-4o 的话一次 eval 可能花掉 $5-10。建议策略 - 日常开发用gpt-4o-mini做 judge发版前再用gpt-4o跑一次完整评测 - 用--max-concurrency控制并发避免 API rate limit - 缓存复用promptfoo eval --cache在本地缓存 LLM 响应3. 非确定性问题的断言设计LLM 评测的本质问题是没有一个 ground truth。同一个问题可能有多个正确答案。所以断言要设计成范围检查而非绝对匹配# 不好的设计 assert: - type: equals value: Paris # 太绝对了 # 好的设计 assert: - type: llm-rubric value: The answer should identify the correct capital city of France.与同类工具的对比特性PromptfooLangSmithDeepEvalRAGAS开源✅ MIT❌ 部分开源✅✅本地运行✅❌ 需 SaaS✅✅CI/CD 原生✅✅需配置需配置红队测试✅ 内建❌❌❌代码扫描✅❌❌❌Python SDK✅✅✅✅Node.js SDK✅✅❌❌模型覆盖率150~50~30~10Promptfoo 的核心优势在开发者体验安全评测两个维度。如果团队在做 LLM 应用的 QA它是最接近开箱即用的选择。进阶方向自定义 Assertion 插件通过promptfoo assert add --type my-check注册 Python/JS 函数做自定义评测逻辑多模态评测支持图片输入 视觉模型评测如 CLIP scoreA/B 测试编排用promptfoo eval --table生成对比表格纳入产品决策流程私有化部署所有数据本地处理不上传到任何第三方服务Promptfoo 被 OpenAI 收购后的路线图显示未来会深度集成到 AI 应用开发流水线中但保持 MIT 开源协议不变。对于测试开发团队来说现在正是引入 LLM 评测自动化的最佳时机——工具成熟、社区活跃、且有巨头背书。