Output Controls
Healthcare Compliance
healthcare-compliance checks model answers for medical phrases. It blocks an answer that contains a phrase you list, such as "stop taking", and puts a disclaimer in front of an answer that looks like medical advice.
It does not check that clinical information is correct, and it does not make you compliant with a regulation. fda_class only selects a built-in disclaimer. It does not classify or approve your product. The control runs only with stream: false.
Configuration
Save this as policy-config.yaml and apply it to a test agent with the config-first workflow.
pack:
name: healthcare-compliance-example
version: 1.0.0
enabled: true
policies:
chain:
- healthcare-compliance
policy:
healthcare-compliance:
blocked_patterns:
- diagnose you with
- prescribe
- stop taking
- surgery is necessary
required_disclaimers:
- This is not medical advice.
- Consult a licensed clinician for diagnosis or treatment decisions.
fda_class: IIVerify the result
Use controlled provider responses, because model answers vary:
| Provider response | Result |
|---|---|
I cannot prescribe medication. | Blocked with healthcare.blocked. The phrase matches even in a refusal. |
The treaty was signed. | Disclaimer added with healthcare.disclaimer_injected, because treat matches |
Hello. | Returned unchanged with healthcare.clean |
Compare the client response with the nested result in the runtime event, and tune the phrases with test data from your application before rollout.
Fields
| Field | Type | Default | Description |
|---|---|---|---|
blocked_patterns | list of strings | [] | Literal substrings that block the answer. Case does not matter. Not regular expressions. |
required_disclaimers | list of strings | [] | Lines joined with line breaks and put before an answer that looks like medical advice. Empty uses the built-in disclaimer of fda_class. |
fda_class | string | II | I, II, or III. Selects the built-in disclaimer and appears in the details. Adds no block rules. |
fda_class | Built-in disclaimer |
|---|---|
I | General health information only; not medical advice. |
II | This is not medical advice. Consult a licensed clinician. |
III | This is not medical advice and must not be used for diagnosis or treatment decisions. Consult a licensed clinician. |
How it works
- The gateway takes the text of the complete model response.
- The control lowercases it and looks for each
blocked_patternsentry. The first match blocks withhealthcare.blockedand records it inmatched_pattern. - Otherwise, the text counts as medical advice if it contains
diagnose,diagnosis,treat,treatment,prescribe,prescription,dosage,dose,start taking,stop taking,contraindication, orside effects, ortakewithmgorml, or a dose phrase such astake 500 mgorincrease 200 mcg. - Advice that does not start with the disclaimer gets it, with two line breaks, and
healthcare.disclaimer_injected. - Advice that already starts with it gets
healthcare.disclaimer_present. - Anything else is returned with
healthcare.clean.
The details contain fda_class, looks_like_medical_advice, and disclaimer_injected, or for a block, blocked: true, matched_pattern, and fda_class.
Phase and verdicts
| Item | Value |
|---|---|
| Phase | output |
| Request families | Chat Completions, Completions, Responses, Messages |
| Verdicts | allow, block |
| Reason codes | healthcare.clean, healthcare.disclaimer_present, healthcare.disclaimer_injected, healthcare.blocked |
Examples
Block prescribing language with your own disclaimer:
policy:
healthcare-compliance:
blocked_patterns:
- prescribe
- increase the dose
- stop taking
required_disclaimers:
- This is not medical advice.Use the class III disclaimer:
policy:
healthcare-compliance:
blocked_patterns:
- diagnose you with
- this is cancer
fda_class: IIILimits and failure behavior
- A block returns HTTP
400with error codecontent_policy_violation. The client gets no text. - The advice check matches substrings:
treatmatchestreatyandretreat, anddosematchesendorse. - Only
blocked_patternsblocks. The advice check andfda_classonly add disclaimers. blocked_patternsalso matches in longer words and in quoted or negated text:prescribematchesI cannot prescribe medication.- The control compares the start of the answer, after leading spaces, with your full disclaimer. An answer that starts with a different disclaimer still gets yours.
- Lint accepts only
I,II, orIIIforfda_class. The runtime accepts any string and uses the classIIdisclaimer for an unknown value. - With
stream: true, the gateway buffers the response but does not run the control. - A
whencondition does not limit this control. Use routes.
Next steps
- HIPAA PHI Detector: health information in requests.
- Financial Compliance: the same pattern for investment advice.
- Investigate a Blocked Request: trace a
healthcare.blockeddecision.