Promptfoopromptfoo 0.123.0 · Node 22.22+ · Python 3
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
25 small wins to finish your pathNext lesson

contains, equals and regex

Every check so far has been contains. There are about sixty assertion types and the useful thing about the first group is that none of them costs anything: they are string comparisons, decided on your machine in no time at all.

Promptfoo calls these deterministic. They always give the same verdict for the same answer, which makes them the right tool whenever the answer has a form you can describe.

yaml
assert:
  - type: contains
    value: 3 March
  - type: icontains
    value: COURIER
  - type: regex
    value: "\d+ March"
  - type: not-contains
    value: cancelled

Four checks on one answer, in a test that asks where order A17 is. contains is case sensitive and icontains is not. regex takes a pattern, so \d+ March accepts any day. not-contains is the negative form, and most types have one: put not- in front and the verdict flips.

Example
promptfoo eval

One row, four checks, one verdict. The row passes because all four passed, and that is the rule everywhere: a test is the unit, an assertion is a vote inside it.

The one that is nearly always wrong

equals demands the exact string. It is the check people reach for first and regret.

yaml
providers:
  - file://support_bot.py
prompts:
  - "{{question}}"
tests:
  - vars:
      question: Where is order A17?
    assert:
      - type: equals
        value: Order A17 shipped on 3 March.
Example
promptfoo eval

The answer was Order A17 shipped on 3 March by courier. and the check wanted it without the last two words. A person reading both would call the answer correct. equals called it a failure, and it was right to, because that is what it was asked.

Use equals when the answer is a label, a code or a number. Use contains and regex when it is a sentence. When the thing you care about cannot be written as either, that is what part 4 is for.

The ones worth remembering

TypePasses whenGood for
containsthe text appearsa fact that must be mentioned
icontainsit appears, ignoring casethe same, when case is noise
regexthe pattern matchesdates, ids, formats
equalsthe whole answer matcheslabels and codes
starts-withthe answer opens with ita required prefix
contains-anyany one of a list appearsseveral acceptable wordings
contains-allevery item of a list appearsa checklist of facts
costthe run cost less than a numbera budget
latencyit answered inside a timea speed limit
latency and cost need real numbers to work on. A Python provider reports neither unless you return latencyMs, tokenUsage or cost from call_api, so both checks are about real providers rather than the one in this course.
Try it yourself
  • Change regex to \d+ April and read the failure reason in the table.
  • Swap contains for contains-all with a list of two facts, one of them missing.
  • Put not- in front of regex and predict the verdict before running.

Slow is fine. Stopping is the only problem.