promptfoo
An eval and red-team tool. Its openai:chat:<model> provider calls plugboard's Chat Completions.
Connect
promptfooconfig.yaml:
yaml
prompts:
- "{{input}}"
providers:
- id: openai:chat:fast
config:
apiBaseUrl: "{{ env.PLUGBOARD_URL }}"
apiKey: "{{ env.PLUGBOARD_KEY }}"
tools:
- type: function
function:
name: get_weather
description: Current weather for a city.
parameters:
type: object
properties:
city:
type: string
required: [city]
tests:
- vars:
input: "Reply with exactly: pong"
assert:
- type: icontains
value: pong
- vars:
input: "What is the weather in Paris? Use the tool."
assert:
- type: is-valid-openai-tools-call
- type: javascript
value: "Array.isArray(output.tool_calls ?? output) && (output.tool_calls ?? output).length > 0"sh
PLUGBOARD_URL=http://127.0.0.1:4010/v1 PLUGBOARD_KEY=<your key> npx promptfoo@latest eval --no-cacheapiBaseUrl keeps /v1. The model name goes after openai:chat:. The file is in examples/promptfoo/.
What works
Text and tool-call assertions, and several choices per prompt with config.passthrough: { n: 3 } when the server's maxChoices allows it.
Limits
- Model-graded assertions (
llm-rubricand others) call OpenAI by default. Point the grader at plugboard withdefaultTest.options.provider, using the sameapiBaseUrland key. - Put per-test prompts in a variable, as in the config: a per-test
prompt:key is ignored. - Give a reasoning model a
max_tokensbudget (1024 or more) so it has room to answer.