Skip to main content

Output Controls

Bias Monitor

bias-monitor sends a narrow set of HR answers to a person for review: answers to hiring, promotion, or performance review questions that mention a protected attribute or an age. It matches fixed words. It is not a fairness classifier.

The score is either 0.0 or 0.95, not a probability of bias. Substring matching also causes false positives: "manager" contains "age".

Set up the review workflow first. A review decision does not replay the original request.

Configuration​

Apply this to a test agent with the config-first workflow, and watch what it matches on real HR text before customers use it.

policy-config.yaml
pack:
  name: bias-monitor-example
  version: 1.0.0
  enabled: true
policies:
  chain:
    - bias-monitor
policy:
  bias-monitor:
    threshold: 0.85

Verify the threshold​

With threshold: 0.85, controlled provider responses give these results:

Request mentionsAnswer containsResult
performance reviewgenderEscalated with bias.detected
performance reviewmanagerAlso escalated, a false positive of the age substring
Summarize this recipeNo listed term or age phraseAllowed with bias.clean

An escalated caller receives no answer. Find the escalation in Inbox and read the nested bias result.

Fields​

FieldTypeDefaultDescription
thresholdnumber0.85The control acts when the score is at or above this value
actionstringescalateescalate or block. Needs gateway 0.1.26 or later.

Lint rejects the removed field protected_characteristics. Gateway 0.1.25 and earlier also reject action and always escalate.

How it works​

  1. The gateway lowercases the joined request messages and the response.
  2. A request that contains hire, promotion, or performance review is an HR request.
  3. The control looks for race, gender, religion, disability, or age in the response, and for age phrases such as over 40 or younger than 25.
  4. An HR request with either kind of match scores 0.95. Everything else scores 0.0.
  5. A score at or above threshold escalates with bias.detected. With action: block, it blocks with bias.detected and creates no escalation. Otherwise the answer is allowed with bias.clean.

The details contain action, score, threshold, is_hr_context, mentions_protected_characteristic, and has_age_reference.

Phase and verdicts​

ItemValue
Phaseoutput
Request familiesChat Completions, Completions, Responses, Messages
Verdictsallow, escalate, block
Reason codesbias.detected, bias.clean

Limits and failure behavior​

  • Substring matching flags ordinary HR words, such as manager.
  • Only the five terms and the age phrases count.
  • Because the only non-zero score is 0.95, any threshold up to 0.95 escalates every HR match, and a higher threshold never escalates.
  • With gateway 0.1.26 or later, bias-monitor examines streamed Chat Completions, Responses, and Messages output. When the chain has bias-monitor, the gateway holds all streamed output until the stream ends. If the score reaches the threshold, the stream stops with an escalation and the client gets no output text. With action: block, the stream stops with the error event "Streaming response blocked by policy: bias.detected" and the verdict BLOCK. Otherwise, the gateway sends all the output when the stream ends. A client that measures first-token latency sees the complete output at one time. See Output escalations in a stream.
  • An escalation returns HTTP 200 with content: null, finish_reason: content_filter, and a verdictan object with verdict ESCALATE and the escalation ID. The caller gets no model text.
  • A block of a buffered response returns the block error of the route, for example HTTP 400 with content_policy_violation on Chat Completions. The decision has the verdict block and no escalation.
  • A when condition does not limit this control. Use routes to apply it to some requests only.

Next steps​