Service policy examples
This feature is in Beta. Account admins can control access to this feature from the account console Previews page. See Manage Databricks previews.
These custom service policy examples cover common governance scenarios for AI model and MCP services. They fall into two kinds of custom policy:
- Deterministic SQL policies: a SQL function that makes an exact, rule-based decision (a tool name, an argument value, a keyword, a length). Use these when the rule is precise and repeatable.
- LLM-as-a-judge policies: a natural-language classifier that an evaluator model applies to the request or response. Use these when the check is semantic (intent, topic, tone) and no exact rule captures it.
For the end-to-end procedure to author and attach a policy, see Create and attach a service policy. For the event fields, the return value, and the supported SQL subset, see Service policy function reference. For the built-in guardrails that cover PII, unsafe content, jailbreak, and hallucination without custom code, see Built-in service policies.
Deterministic SQL policy examples
Each example is a SQL user-defined function (UDF) that you register in Unity Catalog and attach to a service. The policy runs at both evaluation points, so each function branches on event:type::string ('request' for the input phase, ON CALL; 'response' for the output phase, ON RESULT) and returns an explicit ALLOW for every path it doesn't block.
Service policies are fail-closed: a missing field, an unsupported function, or any evaluation error results in DENY. Always cast a VARIANT path before comparing it to a literal (for example, event:type::string = 'request'), and end each function with an explicit ALLOW branch. The policy body supports only a restricted subset of SQL. See Supported SQL.
Block requests that contain specific keywords
This policy blocks requests to a Model Service or Model Provider Service whose message contains any term on a blocklist, such as an internal project codename. It lowercases the message with LOWER so the match is case-insensitive.
CREATE OR REPLACE FUNCTION main.governance.block_codenames(
event VARIANT
)
RETURNS VARIANT
LANGUAGE SQL
RETURN
CASE
WHEN event:type::string = 'request'
AND (
CONTAINS(LOWER(event:context.message::string), 'projectfalcon')
OR CONTAINS(LOWER(event:context.message::string), 'bluewidget')
OR CONTAINS(LOWER(event:context.message::string), 'codename-atlas')
)
THEN to_variant_object(named_struct('result', 'DENY', 'reason', 'Your request references a restricted internal or competitor codename.'))
ELSE to_variant_object(named_struct('result', 'ALLOW', 'reason', ''))
END;
Block requests about restricted topics
This policy blocks requests to a Model Service or Model Provider Service that mention topics the assistant shouldn't engage on, matched by keyword. This is the deterministic form of a topic block. When the topic is nuanced and a keyword list is too blunt, use an LLM-as-a-judge policy instead.
CREATE OR REPLACE FUNCTION main.governance.deny_restricted_topics(
event VARIANT
)
RETURNS VARIANT
LANGUAGE SQL
RETURN
CASE
WHEN event:type::string = 'request'
AND (
CONTAINS(LOWER(event:context.message::string), 'lawsuit')
OR CONTAINS(LOWER(event:context.message::string), 'legal advice')
OR CONTAINS(LOWER(event:context.message::string), 'investment advice')
)
THEN to_variant_object(named_struct('result', 'DENY', 'reason', 'This assistant does not handle legal or investment topics.'))
ELSE to_variant_object(named_struct('result', 'ALLOW', 'reason', ''))
END;
The policy SQL subset matches on substrings with CONTAINS, LIKE, STARTSWITH, and ENDSWITH; regular expressions (regexp_*) aren't supported. Substring matching can't validate a format that depends on structure or a checksum, such as a national ID or an account number. For those checks, use a built-in guardrail where one applies. See Supported SQL.
Limit prompt length
This policy denies requests to a Model Service or Model Provider Service whose message exceeds a character limit. Very long prompts are often pasted dumps or prompt-stuffing attempts, and they raise latency and cost.
CREATE OR REPLACE FUNCTION main.governance.deny_oversized_prompt(
event VARIANT
)
RETURNS VARIANT
LANGUAGE SQL
RETURN
CASE
WHEN event:type::string = 'request'
AND LENGTH(event:context.message::string) > 8000
THEN to_variant_object(named_struct('result', 'DENY', 'reason', 'Your prompt exceeds the 8000-character limit for this service.'))
ELSE to_variant_object(named_struct('result', 'ALLOW', 'reason', ''))
END;
Require approval when an agent acts on behalf of a user
This policy uses the on-behalf-of (OBO) actor context to hold a write action for human approval when an agent, rather than a person, calls a sensitive tool on an MCP Service. The ASK outcome pauses the call until a person approves it.
CREATE OR REPLACE FUNCTION main.governance.ask_when_agent_writes(
event VARIANT
)
RETURNS VARIANT
LANGUAGE SQL
RETURN
CASE
WHEN event:type::string = 'request'
AND event:context.actor.context.is_on_behalf_of::boolean = true
AND event:context.tool.name::string IN ('create_issue', 'push_files', 'merge_pull_request')
THEN to_variant_object(named_struct('result', 'ASK', 'reason', 'An agent is attempting a write action on your behalf. Please confirm.'))
ELSE to_variant_object(named_struct('result', 'ALLOW', 'reason', ''))
END;
For how Databricks delivers the ASK approval prompt to an external agent, see Write a decision policy.
Block responses that expose internal URLs
This policy runs on the output phase (ON RESULT): it inspects the model's response on a Model Service or Model Provider Service and blocks answers that reference an internal-only host. Because it branches on event:type::string = 'response', it evaluates the response rather than the request.
CREATE OR REPLACE FUNCTION main.governance.block_internal_links_in_response(
event VARIANT
)
RETURNS VARIANT
LANGUAGE SQL
RETURN
CASE
WHEN event:type::string = 'response'
AND (
CONTAINS(LOWER(event:context.message::string), 'wiki.internal.example.com')
OR CONTAINS(LOWER(event:context.message::string), 'admin.example.com')
)
THEN to_variant_object(named_struct('result', 'DENY', 'reason', 'The response was blocked because it referenced an internal-only URL.'))
ELSE to_variant_object(named_struct('result', 'ALLOW', 'reason', ''))
END;
Block a tool call by its arguments
This policy inspects a tool's arguments and blocks calls that target a protected resource, while allowing every other call. It applies to an MCP Service. The published deny a GitHub push example blocks a tool by name; this one goes a level deeper and checks an argument value.
CREATE OR REPLACE FUNCTION main.governance.block_protected_repo(
event VARIANT
)
RETURNS VARIANT
LANGUAGE SQL
RETURN
CASE
WHEN event:type::string = 'request'
AND event:context.tool.arguments.repo::string = 'prod-infra'
THEN to_variant_object(named_struct('result', 'DENY', 'reason', 'Actions on the prod-infra repository are not permitted through the agent.'))
ELSE to_variant_object(named_struct('result', 'ALLOW', 'reason', ''))
END;
Restrict a sensitive tool to approved agents
This policy restricts a sensitive write tool on an MCP Service to approved agents. A push_files call made on a user's behalf is allowed only if the acting agent's OAuth client ID (event:context.actor.context.client_id) is on the approved list; everything else is allowed. If the client ID is missing or null, the call is denied too, so the gate stays fail-closed. Calls not made on an agent's behalf fall through to ALLOW, leaving ordinary access governed by grants.
CREATE OR REPLACE FUNCTION main.governance.restrict_push_to_approved_agents(
event VARIANT
)
RETURNS VARIANT
LANGUAGE SQL
RETURN
CASE
WHEN event:type::string = 'request'
AND event:context.tool.name::string = 'push_files'
AND event:context.actor.context.is_on_behalf_of::boolean = true
AND (
event:context.actor.context.client_id IS NULL
OR event:context.actor.context.client_id::string NOT IN ('release-bot', 'ci-deployer')
)
THEN to_variant_object(named_struct('result', 'DENY', 'reason', 'Only approved agents can call the push_files tool on this service.'))
ELSE to_variant_object(named_struct('result', 'ALLOW', 'reason', ''))
END;
To narrow the rule further, combine the agent check with an argument value, such as Block a tool call by its arguments, for example to allow the push only to a specific repository. This example uses the same on-behalf-of actor context as Require approval when an agent acts on behalf of a user, but returns DENY for an unapproved agent instead of ASK.
LLM-as-a-judge policy examples
An LLM-as-a-judge policy uses an evaluator model to classify the request or response against criteria you describe in natural language. Use it for semantic checks that a deterministic rule can't express, such as whether a message is on topic or whether a response stays professional.
To create one, follow the attach a policy procedure, but in Guardrail type select Custom, then set Type to LLM-as-a-judge. Enter your classifier in the Prompt field and select an Evaluator model service (you need CAN QUERY on the model you choose).
You write the classification criteria. Databricks appends a structured output contract to your prompt, so the evaluator returns a JSON decision (a flagged boolean and a confidence score) rather than free text. Don't write ALLOW or DENY in the prompt, and don't specify an output format. When the evaluator flags content, Databricks blocks the interaction. Databricks also wraps the content under evaluation and instructs the evaluator to treat it as untrusted data rather than as instructions to follow.
The examples in this section run on model services and block flagged content. To hold an interaction for human approval instead of blocking it, use the ASK outcome, which applies to MCP services. See Require approval when an agent acts on behalf of a user.
Write effective judge prompts
The prompts on this page are starting points. Adapt each one to your assistant's domain, and test it on realistic in-scope traffic before you rely on it to block.
The following table lists best practices that make a judge prompt more reliable.
Best practice | Description |
|---|---|
State clear FLAG and DO NOT FLAG criteria. | Describe the content to flag, then the content to leave alone. Each example here pairs a "flag if" condition with a "do not flag" boundary; a prompt that lists only what to flag tends to over-flag. |
Give a tie-breaker for boundary cases. | Say how to classify content that sits between the two lists, for example whether an educational or fictional framing exempts otherwise-disallowed detail, so the evaluator doesn't decide those cases inconsistently. |
Describe intent, not just keywords or techniques. | Flag on what a message is trying to do, not on the presence of a word or a technique alone. Role-play or an encoded string isn't a jailbreak by itself; require an attempt to obtain disallowed content. |
Prefer a built-in where one fits, and keep custom criteria focused. | For a risk a built-in guardrail already covers, such as PII, unsafe content, or jailbreak, use the built-in instead of re-describing it in a custom prompt. Layering overlapping policies still works, and some teams do it deliberately, but it adds redundant evaluation and cost and makes it harder to tell which policy blocked a given interaction. |
Roll out in Log mode first, and account for non-determinism. | Attach the policy in Log mode, which records the verdict without blocking, and review its false positives and negatives on realistic in-scope traffic before you switch it to Enforce. Reviewing those verdicts requires inference tables enabled on the service; without them, a Log-mode policy still evaluates but there's nothing you can inspect. The evaluator is a model, so the same input can occasionally get different verdicts, and a prompt that flags borderline content aggressively produces false positives at scale. |
Keep an assistant on topic
This input-phase (ON CALL) policy runs on a Model Service. It flags requests that fall outside the assistant's supported scope, so an assistant built for one purpose isn't used as a general-purpose chatbot.
Prompt:
You are reviewing messages sent to a customer-support assistant that may only help with the company's products, orders, billing, and account support. Flag the message if it asks for something outside that scope, such as general coding help, writing essays, unrelated trivia, or using the assistant as a general-purpose chatbot. Do not flag a genuine product or support question.
Enforce a professional tone
This output-phase (ON RESULT) policy runs on a Model Service. It flags responses that are off-brand or unprofessional, complementing the built-in block_unsafe_content guardrail, which targets harmful content rather than tone.
Prompt:
You are reviewing responses drafted by a public-facing assistant. Flag the response if it is rude, sarcastic, dismissive, condescending, uses profanity, or would embarrass the company if a customer saw it. Do not flag a response that is professional, respectful, and on-brand.
Block regulated advice
This output-phase (ON RESULT) policy runs on a Model Service. It flags responses that give individualized regulated advice, distinguishing them from general, non-advisory information, which a keyword rule can't do reliably.
Prompt:
You are reviewing responses drafted by a financial-services assistant. Flag the response if it provides individualized investment, tax, or legal advice, or a specific recommendation to a person. Do not flag a response that gives only general product information, education, or non-advisory content.
This example blocks flagged responses. Holding an interaction for human approval instead of blocking it uses the ASK outcome, which applies to MCP services, as in Require approval when an agent acts on behalf of a user.
Multi-turn LLM-as-a-judge examples
The LLM-as-a-judge examples above evaluate the latest message on its own. Some risks are only visible across an exchange, when the latest message looks fine but the recent conversation doesn't. A multi-turn LLM-as-a-judge policy gives the evaluator a window of the most recent messages instead of only the latest one.
To enable it, attach the policy as an LLM-as-a-judge policy and set the Conversation window field to the number of recent messages the evaluator should receive, or select Evaluate the entire conversation. Multi-turn evaluation applies to the input (ON CALL) phase on Model Services and Model Provider Services only; it isn't available on the output phase or on MCP Services. Write the prompt to judge the recent messages together, not just the last one.
The Conversation window counts individual messages of any role (system, user, assistant, and tool), not back-and-forth pairs, so a window of 6 covers the last six messages, and a window of 1 is the same as single-message evaluation. For a window larger than one, the evaluator receives the recent messages together with the latest user message from the request, so the current turn is always judged alongside the recent context.
Evaluate the entire conversation sends every message in the current request, not a server-retained session history: Databricks keeps no conversation state between requests. It applies no size limit, so a long conversation can exceed the evaluator model's context window and fail the evaluation, which denies the request, because policies fail closed. A larger window also adds token cost and latency. Prefer a bounded numeric window large enough to capture the pattern you're checking for, and reserve Evaluate the entire conversation for short exchanges.
Multi-turn evaluation is windowed, not stateful. The evaluator sees only the messages present in the current request, and Databricks keeps no state between requests. Within that window, a policy can act on an earlier turn, but it can't use information that has dropped out of the request or maintain a running score across requests. It can't implement session-scoped controls, such as "once this agent reads sensitive data, block its other tools for the rest of the session."
For jailbreak and unsafe-content risks, use the built-in Jailbreak and Unsafe Content guardrails, which you can also run across recent messages by setting a Conversation window. Reserve a custom multi-turn judge for domain-specific policies the built-ins don't cover. See the following sections for examples of domain-specific policies.
Detect a conversation drifting off topic
This input-phase (ON CALL) policy runs on a Model Service or Model Provider Service. It is the multi-turn form of Keep an assistant on topic: it flags a conversation that has moved outside the assistant's supported scope over several turns, even when the latest message alone looks acceptable.
Prompt:
You are reviewing the most recent turns of a conversation with a customer-support assistant that may only help with the company's products, orders, billing, and account support. Flag the conversation if the recent exchange has moved outside that scope, such as into general coding help, essay writing, or unrelated trivia, even when the latest message on its own looks like it could be in scope. Do not flag a conversation that stays within the supported topics.
Flag discussion of a confidential project across turns
This input-phase (ON CALL) policy runs on a Model Service or Model Provider Service. It is the semantic, multi-turn complement to the deterministic keyword codename block: it flags a conversation that is probing for or discussing a confidential internal project, even when the latest message doesn't name it. Adapt the description of what counts as confidential to your organization.
Prompt:
You are reviewing the most recent turns of a conversation with an internal assistant. Flag the conversation if the recent messages are soliciting or discussing details of a confidential, unreleased internal project, such as its roadmap, financials, or codename, even when the latest message alone doesn't name the project. Do not flag general questions about publicly released products or the company's public information.
Flag a request steering toward regulated advice
This input-phase (ON CALL) policy runs on a Model Service or Model Provider Service. It is the request-phase, multi-turn complement to Block regulated advice, which checks a single response: it flags a conversation steering the assistant toward giving individualized regulated advice, so the assistant can redirect before it answers.
Prompt:
You are reviewing the most recent turns of a conversation with a financial-services assistant that may share only general, educational information. Flag the conversation if the recent messages work toward obtaining individualized investment, tax, or legal advice or a specific recommendation for the user's own situation, even when the latest message alone reads as a general question. Do not flag a conversation that stays on general, non-advisory information.