0d3cb498a3
CI / Shell Format Check (push) Has been cancelled
CI / Check Ruby (3.4) (push) Has been cancelled
CI / CI Config (push) Has been cancelled
CI / Test on Node ${{ matrix.node }} and ${{ matrix.os }}${{ matrix.shard && format(' (shard {0}/3)', matrix.shard) || '' }} (push) Has been cancelled
CI / Build on Node ${{ matrix.node }} (push) Has been cancelled
CI / Style Check (push) Has been cancelled
CI / Generate Assets (push) Has been cancelled
CI / Check Python (3.14) (push) Has been cancelled
CI / Check Python (3.9) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Code Scan Action (push) Has been cancelled
CI / Site tests (push) Has been cancelled
CI / webui tests (push) Has been cancelled
CI / Run Integration Tests (push) Has been cancelled
CI / Run Smoke Tests (push) Has been cancelled
CI / Go Tests (push) Has been cancelled
CI / Share Test (push) Has been cancelled
CI / Redteam (Production API) (push) Has been cancelled
CI / Redteam (Staging API) (push) Has been cancelled
CI / GitHub Actions Lint (push) Has been cancelled
CI / Check Ruby (3.0) (push) Has been cancelled
release-please / release-please (push) Has been cancelled
release-please / build (push) Has been cancelled
release-please / publish-npm (push) Has been cancelled
release-please / publish-npm-backfill (push) Has been cancelled
release-please / docker (push) Has been cancelled
release-please / publish-code-scan-action (push) Has been cancelled
release-please / attest-code-scan-action (push) Has been cancelled
Deploy local.promptfoo.app / Deploy to Cloudflare Pages (push) Has been cancelled
Test and Publish Multi-arch Docker Image / test (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-amd64 platform:linux/amd64 runner:ubuntu-latest]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / build-docker-and-push-digests (map[digest-suffix:linux-arm64 platform:linux/arm64 runner:ubuntu-24.04-arm]) (push) Has been cancelled
Test and Publish Multi-arch Docker Image / merge-docker-digests (push) Has been cancelled
Test and Publish Multi-arch Docker Image / Attest Multi-arch Image (push) Has been cancelled
Validate Renovate Config / Validate Renovate Configuration (push) Has been cancelled
239 lines
5.3 KiB
Markdown
239 lines
5.3 KiB
Markdown
# Eval Patterns
|
|
|
|
## Config Structure
|
|
|
|
Use this order so configs stay easy to scan:
|
|
|
|
```yaml
|
|
# yaml-language-server: $schema=https://promptfoo.dev/config-schema.json
|
|
description: Invoice approval regression
|
|
|
|
prompts:
|
|
- file://prompts/main.txt
|
|
|
|
providers:
|
|
- id: file://./provider.mjs
|
|
label: invoice-agent
|
|
|
|
defaultTest:
|
|
assert:
|
|
- type: latency
|
|
threshold: 5000
|
|
|
|
tests:
|
|
- file://tests/*.yaml
|
|
```
|
|
|
|
Use quoted Nunjucks env references:
|
|
|
|
```yaml
|
|
apiKey: '{{env.OPENAI_API_KEY}}'
|
|
baseUrl: '{{env.API_BASE_URL}}'
|
|
```
|
|
|
|
## Minimal Local Provider Eval
|
|
|
|
```yaml
|
|
# yaml-language-server: $schema=https://promptfoo.dev/config-schema.json
|
|
description: Local provider smoke eval
|
|
|
|
prompts:
|
|
- 'Answer {{question}} with the trace id {{trace_id}}.'
|
|
|
|
providers:
|
|
- id: file://./provider.mjs
|
|
label: local-smoke-provider
|
|
|
|
tests:
|
|
- vars:
|
|
question: Say PONG
|
|
trace_id: eval-123
|
|
assert:
|
|
- type: contains
|
|
value: PONG
|
|
- type: regex
|
|
value: trace id eval-123
|
|
```
|
|
|
|
Python local providers use the same `call_api(prompt, options, context)` shape:
|
|
|
|
```yaml
|
|
providers:
|
|
- id: file://./provider.py
|
|
label: local-python-smoke
|
|
config:
|
|
workers: 1
|
|
```
|
|
|
|
If a Python provider imports nearby app modules, anchor `sys.path` to
|
|
`Path(__file__).resolve().parent` before those imports.
|
|
Provider `config` reaches JS wrappers as constructor `options.config` and Python
|
|
wrappers as the `options` argument to `call_api`.
|
|
|
|
## Known Provider Examples
|
|
|
|
Use these when the provider is already known and does not need discovery:
|
|
|
|
```yaml
|
|
providers:
|
|
- openai:chat:gpt-4.1-mini
|
|
- anthropic:messages:claude-sonnet-4-6
|
|
- echo
|
|
```
|
|
|
|
For HTTP APIs, local app code, auth, custom parsing, or redteam targets, switch
|
|
to `promptfoo-provider-setup` before expanding eval assertions.
|
|
|
|
## File-Based Tests
|
|
|
|
```text
|
|
evals/invoice-approval/
|
|
promptfooconfig.yaml
|
|
prompts/main.txt
|
|
tests/happy-path.yaml
|
|
tests/regressions.yaml
|
|
```
|
|
|
|
```yaml
|
|
prompts:
|
|
- file://prompts/main.txt
|
|
|
|
tests:
|
|
- file://tests/*.yaml
|
|
```
|
|
|
|
## Dataset-Backed Tests
|
|
|
|
Use datasets when cases are tabular or generated from source data.
|
|
|
|
```yaml
|
|
tests: file://tests.csv
|
|
```
|
|
|
|
Script-generated tests can keep large suites deterministic:
|
|
|
|
```yaml
|
|
tests: file://generate_tests.py:create_tests
|
|
```
|
|
|
|
Return test cases with `description`, `vars`, and `assert` so generated cases
|
|
look like hand-authored cases in Promptfoo results.
|
|
|
|
## Assertion Scoring Options
|
|
|
|
Use `weight` to make important checks count more, `metric` to name report
|
|
series, and `threshold` according to the assertion type:
|
|
|
|
```yaml
|
|
assert:
|
|
- type: icontains
|
|
value: approved
|
|
weight: 2
|
|
metric: decision_accuracy
|
|
- type: llm-rubric
|
|
value: The answer is accurate and cites the relevant source.
|
|
threshold: 0.8
|
|
- type: latency
|
|
threshold: 5000
|
|
```
|
|
|
|
For model-graded assertions, `threshold` is usually a minimum score from 0 to 1.
|
|
For `cost` and `latency`, it is a maximum allowed value.
|
|
|
|
## Structured JSON Eval
|
|
|
|
```yaml
|
|
tests:
|
|
- vars:
|
|
invoice_id: inv-123
|
|
options:
|
|
transform: JSON.parse(output)
|
|
assert:
|
|
- type: is-json
|
|
- type: javascript
|
|
value: output.invoice_id === 'inv-123' && output.status === 'approved'
|
|
- type: contains-any
|
|
transform: output.reasons
|
|
value:
|
|
- policy-match
|
|
- low-risk
|
|
```
|
|
|
|
If the model wraps JSON in markdown fences, clean it before assertions:
|
|
|
|
````yaml
|
|
options:
|
|
transform: "output.replace(/```json\\n?|```/g, '').trim()"
|
|
````
|
|
|
|
## Local Model-Graded Rubric
|
|
|
|
```yaml
|
|
defaultTest:
|
|
options:
|
|
provider: file://./grader.mjs
|
|
|
|
tests:
|
|
- vars:
|
|
question: Summarize invoice inv-123.
|
|
assert:
|
|
- type: llm-rubric
|
|
value: >-
|
|
The response must mention invoice inv-123, state that it is approved,
|
|
and avoid claiming payment was already sent.
|
|
```
|
|
|
|
The grader provider returns JSON with `pass`, `score`, and `reason`.
|
|
|
|
```js
|
|
export default class DeterministicEvalGrader {
|
|
id() {
|
|
return 'deterministic-eval-grader';
|
|
}
|
|
|
|
async callApi(prompt) {
|
|
const text = String(prompt);
|
|
const pass = text.includes('inv-123') && text.includes('approved');
|
|
return {
|
|
output: JSON.stringify({
|
|
pass,
|
|
score: pass ? 1 : 0,
|
|
reason: pass ? 'Criteria satisfied.' : 'Missing invoice approval details.',
|
|
}),
|
|
};
|
|
}
|
|
}
|
|
```
|
|
|
|
## Faithfulness Rubric
|
|
|
|
```yaml
|
|
assert:
|
|
- type: llm-rubric
|
|
value: |
|
|
The summary only states facts from this source:
|
|
"{{article}}"
|
|
It does not add, infer, or fabricate any claims.
|
|
```
|
|
|
|
Use `context-faithfulness` when the source is already available as context;
|
|
otherwise inline the source in the rubric as shown.
|
|
|
|
## Focused Reruns
|
|
|
|
```bash
|
|
npm run local -- eval -c promptfooconfig.yaml --filter-pattern invoice -o /tmp/invoice.json --no-cache --no-share
|
|
npm run local -- eval -c promptfooconfig.yaml --filter-metadata area=billing -o /tmp/billing.json --no-cache --no-share
|
|
npm run local -- eval -c promptfooconfig.yaml --filter-failing /tmp/eval-results.json -o /tmp/failing.json --no-cache --no-share
|
|
```
|
|
|
|
## CI Gate
|
|
|
|
```bash
|
|
PROMPTFOO_FAILED_TEST_EXIT_CODE=0 npm run local -- eval -c promptfooconfig.yaml -o eval-results.json --no-cache --no-share
|
|
node -e "const s=require('./eval-results.json').results.stats; if (s.errors || s.failures) process.exit(1)"
|
|
```
|
|
|
|
Use the environment override only when the follow-up gate owns the failure
|
|
decision.
|