Inferensys

Prompt

Refusal Reason Extraction and Classification Prompt

A practical prompt playbook for using Refusal Reason Extraction and Classification Prompt in production AI workflows.
Operations team reviewing AI workflow automation on laptop, workflow builder visible, casual office setup.
PROMPT PLAYBOOK

When to Use This Prompt

Defines the operational context for the Refusal Reason Extraction and Classification Prompt, including its ideal use cases, prerequisites, and critical limitations.

This prompt is designed for observability pipelines that need to convert unstructured model refusal responses into structured, queryable data. The primary job-to-be-done is post-hoc analysis: you have a log of raw text where a model refused a user request, and you need to classify why it refused, identify the specific policy invoked, assess the model's confidence in the refusal, and determine if the refusal is potentially recoverable. The ideal user is a safety engineer, policy auditor, or product manager who needs to understand refusal trends at scale without manually reading thousands of responses. Required context includes the raw refusal text and the original user request; optional context includes the system prompt, conversation history, and applicable policy documents.

This is not a real-time intervention tool. Do not use this prompt to make live safety decisions or to gate model responses in a production request path. It is an offline ingestion step for analytics, trend analysis, and policy auditing. The prompt assumes the refusal has already occurred and that you are now extracting structured metadata from it. It is also not a substitute for human policy review when dealing with genuinely ambiguous safety boundaries—the recoverability flag is a signal for downstream triage, not an automated override. For high-risk domains, always route flagged cases to human review before taking action on the classification output.

Before implementing this prompt, ensure your observability pipeline can capture the raw model response and the original user request together. The prompt's value depends on having both sides of the interaction. If your logging only captures the refusal text without the triggering request, the classification will be incomplete and the recoverability assessment unreliable. Once you have the structured output, you can ingest it into your analytics database for trend detection, policy gap analysis, and false-positive rate monitoring. The next step is to pair this extraction prompt with a validation schema that rejects malformed classifications before they enter your analytics store.

PRACTICAL GUARDRAILS

Use Case Fit

Where the Refusal Reason Extraction and Classification Prompt delivers value and where it introduces risk.

01

Good Fit: Production Observability Pipelines

Use when: you need to ingest unstructured refusal text from production logs and convert it into structured, queryable records for dashboards and trend analysis. Guardrail: Validate the output against a strict schema before ingestion to prevent downstream analytics corruption.

02

Bad Fit: Real-Time User-Facing Decisions

Avoid when: the classification result is used to immediately override a refusal and respond to a user without human review. Risk: Misclassification of a legitimate safety refusal as a false positive could expose users to harmful content. Guardrail: Always route recoverable: true flags to a human review queue before actioning.

03

Required Inputs: Raw Response and Policy Context

What to watch: The prompt cannot function accurately without the full, unredacted model response and a reference to the active safety policy. Guardrail: If the policy version or raw response is missing, the prompt must return a classification_error status rather than guessing the reason.

04

Operational Risk: Policy Drift and Stale Mappings

What to watch: The classification prompt relies on internal knowledge of policy articles that may change over time. Guardrail: Version-lock the policy reference in the prompt's system context and trigger a mandatory review of the classification logic whenever the source safety policy is updated.

05

Bad Fit: Single-Turn Chatbots Without Logging

Avoid when: you are building a simple chatbot and only need to show a generic error message. Risk: The overhead of structured extraction adds latency and complexity without a consumer for the structured data. Guardrail: Only deploy this prompt when the output is directly consumed by a monitoring or analytics system.

06

Good Fit: Safety Policy Gap Analysis

Use when: safety engineers need to aggregate refusal reasons across thousands of interactions to identify over-refusal patterns or missing policy coverage. Guardrail: Combine the structured reason_code output with user feedback signals to prioritize which policy gaps to fix first.

PROMPT PLAYBOOK

Copy-Ready Prompt Template

A copy-ready prompt template for extracting and classifying refusal reasons from model responses into structured JSON for observability pipelines.

The prompt template below is designed to be dropped directly into your observability or safety logging pipeline. It takes an unstructured model refusal response and a reference safety policy, then outputs a structured JSON object suitable for analytics ingestion. The template uses square-bracket placeholders for all dynamic inputs, making it easy to parameterize in code before sending to the model.

text
You are a safety observability classifier. Your task is to analyze a model's refusal response against a provided safety policy and extract structured refusal data.

## INPUT
Model Refusal Response:
"""
[REFUSAL_RESPONSE_TEXT]
"""

Safety Policy Reference:
"""
[SAFETY_POLICY_TEXT]
"""

## OUTPUT SCHEMA
Return ONLY a valid JSON object with the following fields. Do not include any text outside the JSON.

{
  "refusal_detected": boolean,
  "refusal_reason": string (direct quote or tight paraphrase from the response explaining why the request was refused),
  "reason_code": string (classify into one of: "POLICY_VIOLATION", "CAPABILITY_GAP", "LEGAL_RESTRICTION", "SAFETY_BOUNDARY", "AMBIGUOUS_REQUEST", "OTHER"),
  "policy_reference": string (the specific policy clause, section, or principle cited, or null if none cited),
  "confidence": number (0.0 to 1.0 indicating how clearly the refusal maps to a policy reason),
  "recoverable": boolean (true if the request could likely be fulfilled with rephrasing or additional context, false if the refusal appears definitive),
  "recovery_suggestion": string (if recoverable, a brief suggestion for how the user could rephrase; otherwise null),
  "analysis_notes": string (brief analyst note on any ambiguity, policy interpretation edge cases, or notable patterns)
}

## CONSTRAINTS
- If the response does not contain a refusal, set refusal_detected to false and leave other fields null.
- Do not invent policy citations. Only reference policy text actually provided.
- For ambiguous cases, set confidence below 0.7 and explain the ambiguity in analysis_notes.
- Never classify a legitimate safety refusal as recoverable if recovery would circumvent the policy.

To adapt this template, replace [REFUSAL_RESPONSE_TEXT] with the raw model output you want to classify, and [SAFETY_POLICY_TEXT] with the relevant policy document or excerpt. For production use, validate the output JSON against the schema before ingestion. If the model returns malformed JSON, implement a retry with stricter format instructions or fall back to a repair prompt. For high-stakes safety observability, always sample and manually review classifications to calibrate confidence thresholds and catch systematic misclassifications.

IMPLEMENTATION TABLE

Prompt Variables

Required inputs for the Refusal Reason Extraction and Classification Prompt. Each placeholder must be populated before the prompt is sent. Validation notes describe how to verify the input is well-formed before execution.

PlaceholderPurposeExampleValidation Notes

[MODEL_RESPONSE]

The full unstructured text response from the model that may contain a refusal

I'm sorry, I can't help with that request because it violates our safety policy regarding harmful content.

Non-empty string required. Must be the raw model output, not a pre-processed or truncated version. Minimum 1 character, maximum 8192 tokens.

[POLICY_DOCUMENT]

The safety policy text against which the refusal should be classified

Safety Policy v2.3: Do not generate content that promotes violence, illegal activities, or hate speech. Do not provide instructions for creating weapons or harmful substances.

Non-empty string required. Must contain explicit policy categories or rules. If policy is versioned, include version identifier in the text.

[POLICY_VERSION]

Version identifier for the policy document used, for audit trail and downstream analytics

v2.3

String required. Must match a known policy version in the policy registry. Null not allowed. Format: v[MAJOR].[MINOR] or equivalent versioning scheme.

[REQUEST_CONTEXT]

The original user request that triggered the model response, for intent comparison

Can you tell me how to make a smoke bomb?

Non-empty string required. Must be the exact user input, not a paraphrase. If multi-turn conversation, include the specific turn that triggered the refusal.

[CONVERSATION_HISTORY]

Prior turns in the conversation for context when refusal may depend on earlier exchanges

[{"role": "user", "content": "I'm working on a chemistry project"}, {"role": "assistant", "content": "I'd be happy to help with your chemistry project. What specific topic are you studying?"}]

JSON array of message objects with role and content fields. Null allowed if single-turn interaction. Max 10 prior turns to avoid context pollution.

[CLASSIFICATION_TAXONOMY]

The set of valid refusal reason codes and their definitions for structured output

["SAFETY_VIOLATION", "POLICY_AMBIGUITY", "CAPABILITY_GAP", "OVER_REFUSAL", "LEGITIMATE_REFUSAL"]

Non-empty array of strings required. Each code must have a definition in accompanying documentation. Codes must be mutually exclusive. Validate against taxonomy registry before use.

[CONFIDENCE_THRESHOLD]

Minimum confidence score required for automatic classification before escalation to human review

0.85

Float between 0.0 and 1.0. Default 0.85 if not specified. Values below 0.7 risk high false-positive rates in classification. Must be configurable per deployment environment.

[OUTPUT_SCHEMA_VERSION]

Schema version for the structured output format, enabling downstream parser compatibility

1.2.0

String required. Must match a known schema version in the output schema registry. Used by downstream ingestion to select the correct parser. Format: semantic versioning.

PROMPT PLAYBOOK

Implementation Harness Notes

How to wire the Refusal Reason Extraction and Classification Prompt into an observability pipeline with validation, retries, and structured logging.

This prompt is designed to be a post-processing step in an observability pipeline, not a real-time user-facing component. After a model generates a refusal response, that raw text is routed to this prompt for structured extraction. The output is a machine-readable classification record that downstream analytics systems can ingest. The primary integration point is a logging middleware or a message queue consumer that receives model responses, detects refusals (either via a lightweight classifier or a keyword heuristic), and then invokes this prompt to produce the structured record. Do not use this prompt on non-refusal responses; it will hallucinate refusal reasons where none exist.

The implementation harness should enforce a strict schema contract before the classification record enters your analytics store. Wrap the LLM call in a validation layer that checks: (1) the reason_code matches your internal taxonomy enum, (2) the confidence field is a float between 0.0 and 1.0, (3) the recoverable field is a boolean, and (4) the policy_reference field is not null when the refusal is policy-based. If validation fails, implement a single retry with the validation error message appended to the prompt as additional context. If the retry also fails, log the raw refusal text and the failed parse attempt to a dead-letter queue for manual review. For high-volume production systems, consider using a cheaper, faster model (like a fine-tuned small classifier) for the initial refusal detection step, reserving this prompt for the detailed extraction on detected refusals only.

Logging is critical for this workflow. Every invocation should produce an audit record containing: the original model response, the extracted classification, the model used for extraction, the latency, and the validation status. This audit trail enables offline analysis of refusal patterns, false-positive rate monitoring, and policy gap detection. When deploying this prompt, start with a shadow mode that logs classifications without blocking or altering the user experience. After validating accuracy against a human-labeled sample of at least 200 refusal responses, promote the pipeline to active use. Avoid wiring this prompt directly into a synchronous user-facing code path; the extraction latency will degrade the user experience, and a failed extraction should never block a response from being delivered.

IMPLEMENTATION TABLE

Expected Output Contract

Defines the exact fields, types, and validation rules for the structured refusal record. Use this contract to build downstream ingestion, analytics, and alerting pipelines that consume the prompt's output.

Field or ElementType or FormatRequiredValidation Rule

refusal_id

string (UUID v4)

Must be a valid UUID v4 generated by the system, not the model. Reject if missing or malformed.

original_request

string

Must be a non-empty string. Truncate to 4096 characters. Reject if null or empty.

refusal_reason_code

string (enum)

Must match one of the predefined reason codes: [POLICY_VIOLATION], [CAPABILITY_GAP], [SAFETY_BOUNDARY], [AMBIGUOUS_INTENT], [LEGAL_RESTRICTION], [OTHER]. Reject on mismatch.

policy_reference

string | null

If provided, must match the pattern 'POL-[0-9]{3}' (e.g., POL-042). Null allowed when reason_code is [CAPABILITY_GAP] or [OTHER].

confidence_score

number (float 0.0-1.0)

Must be a float between 0.0 and 1.0 inclusive. Reject if out of range, non-numeric, or missing.

is_recoverable

boolean

Must be true or false. Reject if string, null, or integer.

recovery_strategy

string (enum) | null

Required if is_recoverable is true. Must be one of: [CONTEXT_REFRAME], [PARTIAL_FULFILLMENT], [EXPLICIT_PERMISSION], [CLARIFICATION_QUESTION], [ESCALATE_TO_HUMAN]. Null allowed if is_recoverable is false.

extracted_at

string (ISO 8601 datetime UTC)

Must be a valid ISO 8601 datetime string ending in 'Z'. Reject if unparseable or missing timezone.

PRACTICAL GUARDRAILS

Common Failure Modes

What breaks first when extracting and classifying refusal reasons, and how to guard against it in production observability pipelines.

01

Model Classifies a Legitimate Refusal as a False Positive

What to watch: The extraction prompt misinterprets a correct safety refusal as an error, flagging it for recovery when the model was right to refuse. This inflates false-positive metrics and can lead to unsafe policy relaxation. Guardrail: Include few-shot examples of correct refusals with their policy citations. Add a validation step that cross-references the extracted reason code against the original request's risk profile before flagging for recovery.

02

Unstructured Refusal Text Produces Unparseable JSON

What to watch: The model's refusal response is a long, empathetic paragraph with no clear structure. The extraction prompt fails to map this to the required schema, returning null fields or malformed JSON that breaks the analytics pipeline. Guardrail: Implement a two-pass approach. First, classify whether the response is a refusal. Second, extract structured fields. Add a schema validator in the harness that rejects records with missing required fields and triggers a retry with stricter formatting instructions.

03

Recoverability Flag Is Overly Optimistic

What to watch: The prompt marks refusals as 'recoverable' when the underlying policy is absolute (e.g., illegal content, self-harm). This creates false work for recovery pipelines and can lead to dangerous retry attempts. Guardrail: Maintain a hardcoded list of non-recoverable reason codes in the application layer. Override the model's recoverability flag if the extracted reason code matches a non-recoverable category, regardless of the model's confidence.

04

Policy Reference Is Hallucinated or Vague

What to watch: The model cites a policy section like 'Section 4.2' that doesn't exist in your actual safety policy document, or returns a generic label like 'content policy' with no actionable specificity. Guardrail: Constrain the output to an enum of known policy IDs from your actual policy registry. Use a post-extraction check that validates the returned policy reference against the registry and flags mismatches for human review.

05

Confidence Score Doesn't Correlate with Accuracy

What to watch: The model returns high confidence for incorrect classifications, especially on ambiguous or edge-case refusals. Teams relying on the confidence score to auto-route tickets will send misclassified items to the wrong queue. Guardrail: Calibrate the confidence score by running a golden dataset of 200+ labeled refusals through the prompt. Set a threshold based on observed precision/recall, not the raw score. Route low-confidence and ambiguous cases to a human review queue.

06

Prompt Drift After Safety Policy Update

What to watch: Your safety team updates the policy document, adding new refusal categories and deprecating old ones. The extraction prompt, still referencing the old taxonomy, begins misclassifying new refusal types or using deprecated reason codes. Guardrail: Version-lock the prompt to a specific policy document version. Implement a regression test suite that runs after every policy update, checking that new refusal categories are correctly extracted and old codes are no longer produced.

IMPLEMENTATION TABLE

Evaluation Rubric

Use this rubric to test the quality of the refusal reason extraction and classification prompt before shipping. Each criterion targets a specific failure mode in production observability pipelines.

CriterionPass StandardFailure SignalTest Method

Schema Compliance

Output is valid JSON matching the [OUTPUT_SCHEMA] with all required fields present

JSON parse error or missing required field such as refusal_code or confidence_score

Schema validator: parse output and validate against the defined JSON Schema

Refusal Code Accuracy

refusal_code matches the actual refusal category from a pre-labeled test set with >= 90% accuracy

refusal_code is 'other' for a known category or misclassifies a policy violation as a capability refusal

Run against 50 pre-labeled refusal responses and measure exact-match accuracy per code

Confidence Score Calibration

confidence_score is >= 0.8 for unambiguous refusals and <= 0.5 for ambiguous or borderline cases

confidence_score is 0.95 for a vague refusal or 0.3 for a clear policy citation

Compare confidence_score distribution against human-labeled certainty ratings on 30 samples

Policy Reference Grounding

policy_reference field contains a specific policy ID or section when the refusal cites a policy, else null

policy_reference is populated with a hallucinated policy ID or is null when the model explicitly cited a policy

Cross-check policy_reference against the original refusal text for citation presence and accuracy

Recoverability Flag Correctness

recoverable is true when the refusal suggests an alternative or asks for clarification, false when it is a hard block

recoverable is false for a refusal that offered a safe alternative or true for a permanent policy block

Run against 20 refusals with known recoverability labels and measure binary classification accuracy

Null Handling for Missing Fields

Optional fields such as policy_reference or suggested_alternative are null when no evidence exists in the refusal text

Optional fields contain empty strings, 'N/A', or hallucinated values when the source refusal had no such content

Inspect outputs for 10 refusals with known missing information and verify null vs. fabricated content

Original Text Fidelity

original_refusal_text field is an exact substring match from the model response with no modification

original_refusal_text is paraphrased, truncated, or contains added text not present in the source

String-exact match check between the extracted field and the source refusal response

Classification Consistency

Same refusal text produces the same refusal_code and recoverable value across 5 repeated runs

refusal_code flips between 'policy_violation' and 'capability_gap' across runs for the same input

Run the same 10 refusal samples 5 times each and measure output stability with temperature=0

ADAPTATION OPTIONS

Adapt This Prompt

How to adapt

Use the base prompt with a single model call and minimal post-processing. Replace the strict JSON schema enforcement with a looser structured output request. Log raw outputs for manual review.

Prompt modification:

  • Remove [OUTPUT_SCHEMA] validation block
  • Replace with: Return your analysis as JSON with these keys: refusal_detected, reason_code, policy_reference, confidence, recoverable
  • Add: If you cannot determine a field, use null.

Watch for

  • Inconsistent reason codes across runs
  • Missing policy_reference when refusal is implicit
  • Confidence scores that are always 0.9 without calibration
  • Free-text fields that break downstream ingestion
Prasad Kumkar

About the author

Prasad Kumkar

CEO & MD, Inference Systems

Prasad Kumkar is the CEO & MD of Inference Systems and writes about AI systems architecture, LLM infrastructure, model serving, evaluation, and production deployment. Over 5+ years, he has worked across computer vision models, L5 autonomous vehicle systems, and LLM research, with a focus on taking complex AI ideas into real-world engineering systems.

His work and writing cover AI systems, large language models, AI agents, multimodal systems, autonomous systems, inference optimization, RAG, evaluation, and production AI engineering.