Create and attach a service policy
This feature is in Beta. Account admins can control access to this feature from the account console Previews page. See Manage Databricks previews.
For an overview of service policies, see Service policies for AI securables.
You create a service policy and attach it to an MCP Service, Model Service, or Model Provider Service through the Unity Gateway UI. The policy governs each interaction at two evaluation points:
- The input phase (ON CALL) before Databricks invokes the service.
- The output phase (ON RESULT) after the service responds.
Choose a policy type
Policy type | Use it for | What you provide |
|---|---|---|
Common risks, such as unsafe content, jailbreak attempts, hallucinations, and sensitive data. | Nothing. You select the guardrail and attach it. | |
Semantic rules that you can describe in plain language, such as keeping an assistant on topic. | A prompt that describes what to flag. | |
Deterministic rules, such as checks on tool names, tool arguments, or the caller's identity, and holding a call for human approval ( | A SQL user-defined function (UDF) registered in Unity Catalog. | |
Enforcing the decisions of a third-party guardrail vendor that you already use. | A Unity Catalog HTTP connection to the vendor's endpoint. |
Start with a built-in guardrail when one covers your risk. For a rule that no built-in covers, use a custom LLM-as-a-judge policy, or a SQL function when the rule must be deterministic or depends on who is calling.
You can attach more than one policy to a service. Each attachment has a priority (rank), and a DENY at one rank stops evaluation of all later ranks. On the input phase, ranks are evaluated in ascending order (lowest first). On the output phase, they're evaluated in the reverse order. Policies at the same rank can all run even after one of them denies. See Order of evaluation.
Prerequisites
- An account administrator must enable the beta for your account from the Previews page in the account console.
- To attach any policy to a service:
MANAGEon the target service securable. - For a built-in guardrail or a custom LLM-as-a-judge policy with an evaluator other than the default:
EXECUTEon the evaluator model service you choose, plusUSE CATALOGandUSE SCHEMAon its catalog and schema. See Grant access to a model service. - For a custom SQL policy:
CREATE FUNCTIONprivilege on the target schema to create the policy function, andEXECUTEon the policy function to attach it. - For an external service policy:
USE CONNECTIONon the Unity Catalog HTTP connection. See Before you begin.
If a label differs from these steps, follow the in-product labels. A policy applies to all account users on the service, so leave Applied to set to All account users.
Attach a built-in policy
Databricks provides built-in service policies under the system.ai namespace, such as system.ai.block_unsafe_content to block unsafe or harmful content. They cover common risks without any code. For the full list of built-in policies, and a note on how they appear in Unity Catalog, see Built-in service policies.
The following steps attach the Unsafe Content guardrail to a service:
- In the workspace sidebar, click AI Gateway.
- Select the service to govern: a model service on the Models tab, a model provider service on the Providers tab, or an MCP service on the MCPs tab.
- Open the Policies tab, then click New policy.
- Enter a Name for the policy, such as
block_unsafe_content. - In Guardrail type, select a built-in guardrail, such as Unsafe Content or Jailbreak.
- Set the Rank to control evaluation order. The lowest rank runs first on the request and last on the response.
- Under Phase, select where the policy runs: Input guardrails (ON CALL, before the service is invoked), Output guardrails (ON RESULT, after it responds), or both. Some built-in guardrails run in only one phase, such as jailbreak detection on input and hallucination detection on output.
- (Optional) On a model service or model provider service, set the Conversation window: how many recent conversation turns the judge evaluates on the request. It defaults to 10 turns. Set it to 1 to judge only the latest message, or select Evaluate the entire conversation.
- (Optional) Expand Advanced options. The Evaluator model service that runs the check (the LLM judge) is preselected. To use a different one, select it here. You need
EXECUTEon the model service you choose, plusUSE CATALOGandUSE SCHEMAon its catalog and schema. To record verdicts without blocking, set Mode to Log. - Click Create policy.
The policy appears on the service's Policies tab. Allow a short time for it to propagate before you test.
Built-in guardrails don't take any policy-specific configuration. You set only the standard Phase, Rank, Evaluator model service, and Mode fields. The deterministic Sensitive Data Detection guardrail is the exception: it also takes classification tags and an action. See Detect sensitive data with a service policy.
Create an LLM-as-a-judge policy
A custom LLM-as-a-judge policy uses an evaluator model to classify a 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. You write the criteria as a prompt, not as code.
The following steps attach a policy that keeps a support assistant on topic:
-
In the workspace sidebar, click AI Gateway.
-
Select the service to govern: a model service on the Models tab, a model provider service on the Providers tab, or an MCP service on the MCPs tab.
-
Open the Policies tab, then click New policy.
-
Enter a Name for the policy, such as
keep_on_topic. -
In Guardrail type, select Custom.
-
Set the Rank to control evaluation order. The lowest rank runs first on the request and last on the response.
-
Under Implementation, select LLM-as-a-judge.
-
Under Phase, select where the policy runs: Input guardrails (ON CALL, before the service is invoked), Output guardrails (ON RESULT, after it responds), or both. An on-topic check like this one runs on the input.
-
Select an Evaluator model service. You need
EXECUTEon the model service you choose, plusUSE CATALOGandUSE SCHEMAon its catalog and schema. -
In Prompt, describe what the evaluator should flag and what it should leave alone. For example:
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.
Don't write
ALLOWorDENYin the prompt, and don't specify an output format. Databricks appends a structured output contract to your prompt, so the evaluator returns a JSON verdict. When the evaluator flags the content, Databricks blocks the interaction. -
(Optional) On a model service or model provider service, set the Conversation window: how many recent conversation turns the judge evaluates on the request. It defaults to 10 turns. Set it to 1 to judge only the latest message, or select Evaluate the entire conversation. The window applies to input evaluation only.
-
(Optional) Expand Advanced options and set Mode to Log to record verdicts without blocking while you tune the prompt.
-
Click Create policy.
The policy appears on the service's Policies tab. Allow a short time for it to propagate before you test.
The evaluator is a model, so its verdicts are non-deterministic. Databricks recommends starting in Log mode and reviewing the would-be verdicts in the unified trace table. See Non-determinism and dry-run testing. For more prompts, best practices for writing them, and multi-turn examples, see LLM-as-a-judge policy examples.
Create a SQL policy
A custom SQL policy is a SQL function that returns a decision. Use it when the rule must be deterministic, when it depends on a tool's name or arguments or on who is calling, or when it must hold a call for human approval (ASK).
Step 1: Write the policy function
A service policy function is a SQL UDF registered in Unity Catalog. It takes a single VARIANT parameter, event (the interaction data and context), and returns a VARIANT result:
CREATE OR REPLACE FUNCTION <catalog>.<schema>.<function_name>(
event VARIANT
)
RETURNS VARIANT
LANGUAGE SQL
RETURN <expression>;
The function runs at both evaluation points; branch on event:type::string ('request' for the input phase, 'response' for the output phase) to act on a single phase. For the full event fields, the return value, and the supported SQL subset, see Service policy function reference.
The function returns a decision: a VARIANT with a result field of ALLOW, DENY, or ASK and an optional reason. Build the result with named_struct and wrap it in to_variant_object so the function returns a VARIANT, keeping result and reason as top-level fields.
The result value determines what happens (it is case-insensitive):
ALLOW: the interaction proceeds.DENY: Databricks blocks the interaction. Instead of an error, the caller receives a successful (HTTP 200) response whose assistant turn reports the block, with thereasonin a top-leveldatabricks_service_policyobject.ASK: on an MCP Service, the request pauses for user approval before the tool runs. If a custom SQL or Python policy returnsASKfor a Model Service or Model Provider Service, Databricks blocks the request or response because these services cannot ask the user for approval.
Example: deny a GitHub push when an agent acts on a user's behalf
To remove a tool for every caller, use tool selection instead of a service policy. A service policy is useful when the decision depends on who is calling. This policy lets people call the push_files tool directly, but denies it when an agent or app calls it on a user's behalf (on-behalf-of, or OBO), as reported by event:context.actor.context.is_on_behalf_of:
CREATE OR REPLACE FUNCTION main.governance.block_agent_github_push(
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
THEN to_variant_object(named_struct('result', 'DENY', 'reason', 'Agents cannot push to GitHub on behalf of a user. Push the change yourself.'))
ELSE to_variant_object(named_struct('result', 'ALLOW', 'reason', ''))
END;
To allow specific agents instead of blocking all of them, check the agent's OAuth client ID. See Restrict a sensitive tool to approved agents. For the full list of actor fields, see Service policy function reference.
Example: require human approval before a destructive tool runs
This policy pauses any call to the delete_repository tool for human approval and allows all other interactions.
CREATE OR REPLACE FUNCTION main.governance.ask_before_repo_delete(
event VARIANT
)
RETURNS VARIANT
LANGUAGE SQL
RETURN
CASE
WHEN event:context.tool.name::string = 'delete_repository'
THEN to_variant_object(named_struct('result', 'ASK', 'reason', 'Deleting a repository requires human approval.'))
ELSE to_variant_object(named_struct('result', 'ALLOW', 'reason', ''))
END;
When this policy returns ASK, Databricks pauses the call for human approval before it runs.
For external agents calling MCP Services, Databricks delivers the approval decision using MCP URL-mode elicitation: the user opens the provided URL to approve or decline the call. The external agent must retry the call after approval. To use ASK with an external agent, the agent's MCP client must support MCP protocol version 2025-11-25 or later.
For MCP Services, approving a tool call caches the approval for one hour, so an identical call isn't prompted again within that window.
ASK approval is available only for MCP Services during the input phase. If a custom SQL or Python policy returns ASK for a Model Service or Model Provider Service, Databricks blocks the request or response because these services cannot ask the user for approval.
For more custom policies, including tool allowlists, keyword and topic blocks, prompt-length limits, and response checks, see Service policy examples.
Step 2: Attach the function to a service
- In the workspace sidebar, click AI Gateway.
- Select the service to govern: a model service on the Models tab, a model provider service on the Providers tab, or an MCP service on the MCPs tab.
- Open the Policies tab, then click New policy.
- Enter a Name for the policy.
- In Guardrail type, select Custom.
- Set the Rank to control evaluation order. The lowest rank runs first on the request and last on the response.
- Under Implementation, select Custom function, then click Select function and select the SQL function you wrote in Step 1.
- Click Create policy.
A custom SQL function has no Phase setting: it runs at both phases, so branch on event:type in the function body to scope its behavior (see Step 1). The policy appears on the service's Policies tab. Allow a short time for it to propagate before you test.
Attach an external service policy
An external service policy sends the content under evaluation to a third-party guardrail vendor and enforces the vendor's ALLOW or DENY verdict. To use one, open the service's Policies tab and click New policy, then choose External in Guardrail type and select or create the Unity Catalog HTTP connection to your vendor's endpoint. Set the Phase, Rank, optional Policy configuration, and Mode as for any policy.
You need MANAGE on the target service and USE CONNECTION on the connection. You don't need a policy function. For the full setup, including the connection fields, the content sent to the vendor, and fail-closed behavior, see Enforce a partner guardrail with an external service policy.
Verify the policy
After you attach a policy, verify that it is active and producing the expected outcomes.
After you attach or change a policy, allow a short time for the change to take effect before you test. Policy changes typically take a minute or two to propagate.
Confirm attachment
In the Unity Gateway, open the target service and view its attached policies. The policy you created appears in the list.
Observe policy outcomes
You can confirm a policy is taking effect:
- From the caller: when the policy returns
DENY, the caller receives a successful (HTTP 200) response rather than an error. The assistant turn reports that the content was blocked, and a top-leveldatabricks_service_policyobject carries thereasonyou specified.ASKpauses the call for human approval. - In the unified trace table: the unified trace table records every request across your Unity Gateway services, with one
policy_evaluatedevent for each policy and phase that ran, including the action it took. See Policy evaluation events. - In system tables: model and MCP activity is recorded in the usage tables, and, for a service with an inference table, full request and response payloads in its inference table.
Debug and audit a policy decision
When a policy blocks an interaction, the block reason in the databricks_service_policy object names the policy and gives a short explanation. See Observe policy outcomes.
To find which policies ran on a request and what each decided, start with the unified trace table. A metastore admin sets it up one time for all Unity Gateway services, and each request's span carries a policy_evaluated event for every policy and phase that ran, with the policy's name, type, and action. For a policy in Log mode, the event also records the would-be verdict in policy.dry_run_action and policy.dry_run_reason. See Policy evaluation events.
The trace records each LLM-as-a-judge policy's action, but not the evaluator's reasoning. To see the full reasoning behind a built-in or custom LLM-as-a-judge decision, including the evaluator's confidence and the exact content it judged, review the evaluator model service's inference table.
An LLM-as-a-judge policy runs its prompt on a separate evaluator model service (the judge). The judge's verdict isn't recorded in the protected service's inference table, which logs only the protected service's own request and response. The judge's input and verdict are captured only when an inference table is enabled on the evaluator model service.
Capture the evaluator's verdicts
Enable an inference table on the model service that runs the check. You have two options:
- Enable an inference table directly on the evaluator the guardrail already uses. The default evaluator is a
system.aimodel service, and you can enable an inference table on it. - Under Advanced options when you attach the policy, point the guardrail at an evaluator model service you own (it doesn't have to be a
system.aimodel), then enable an inference table on that service.
To enable an inference table, see Log requests and responses to inference tables. Turn it on before the interactions you want to audit: only evaluations that run after logging is enabled are captured, and rows can take a few minutes to appear.
Read a verdict
Each evaluation writes one row per policy per phase to the evaluator's inference table:
requestis the assembled judge prompt: the policy's criteria, the JSON output contract, and the content under evaluation wrapped in<ContentToEvaluate>markers. For a multi-turn (conversation-window) input policy, the evaluated content is the recent turns plus the latest input; otherwise it's the single message.responseis the evaluator's raw completion. The verdict is the assistant message content: a JSON object withflagged,confidence, and, whenflaggedistrue,reason.destination_nameidentifies the evaluator, andrequest_idties the evaluation to the interaction that triggered it.
To find the evaluations where the judge flagged content, filter the evaluator's inference table on the verdict:
SELECT
event_time,
request_id,
get_json_object(response, '$.choices[0].message.content') AS verdict,
request
FROM <catalog>.<schema>.<evaluator_inference_table>
WHERE get_json_object(response, '$.choices[0].message.content') ILIKE '%"flagged":true%'
ORDER BY event_time DESC;
The verdict column shows the evaluator's decision, such as {"flagged":true,"confidence":0.87,"reason":"..."}. A reason appears only when flagged is true. A flagged verdict is the judge's decision, not proof the interaction was blocked. In Log mode, a would-be DENY is recorded here but not enforced, and the table doesn't record the mode, so confirm an actual block from the caller's databricks_service_policy response (see Observe policy outcomes). To trace one specific interaction instead, filter by its request_id.
Audit blocks from the evaluator's inference table, not the protected service's. When an input-phase policy denies a request, Databricks doesn't invoke the underlying service, so a blocked interaction may not produce a row in the protected service's inference table. Sourcing request IDs from the protected table therefore misses blocked interactions; filter the evaluator's table on the verdict instead.
Narrow to one interaction in a large table
The evaluator's inference table has no policy-name column, and the id in the response body (chatcmpl-...) isn't the request_id. Narrow to the interaction you're debugging with these filters, and bound the scan by time:
request_id(most precise): every evaluation for one interaction shares it. Capture it from the call'sdatabricks-request-idresponse header, then filterWHERE request_id = '<id>'. This works for a block. Confirm that the header value matches the column, because the response body'sidfield is a different value.- Request content: the judge's
requestholds the evaluated content, so a distinctive string in your prompt pins the interaction down, for examplerequest ILIKE '%<your marker>%'. - Time:
event_time >= current_timestamp() - INTERVAL 30 MINUTESlimits the scan.
To tell which policy produced a row, read its request. The system message is that policy's criteria, so you can filter and identify the policy. For example request ILIKE '%<distinctive phrase from the policy prompt>%'. The reason in the verdict usually restates the trigger.
SELECT event_time, request_id, invocation_id,
get_json_object(response, '$.choices[0].message.content') AS verdict,
request
FROM <catalog>.<schema>.<evaluator_inference_table>
WHERE event_time >= current_timestamp() - INTERVAL 30 MINUTES
AND request ILIKE '%<your marker or prompt text>%'
AND get_json_object(response, '$.choices[0].message.content') ILIKE '%"flagged":true%'
ORDER BY event_time DESC;
Non-determinism and dry-run testing
The evaluator is a model, so its verdicts are non-deterministic: the same input can return different verdicts across runs, and the variation is larger across different evaluator models or when request routing spans model versions. The reason is short free text, not structured per-entity data, and it can quote the flagged content. For a repeatable, deterministic check, use the built-in Sensitive Data Detection policy or a custom SQL policy instead of an LLM judge.
Databricks recommends attaching an LLM-as-a-judge policy in Log mode first, which records the verdict without blocking. Review the would-be verdicts in the unified trace table, and enable an inference table on the evaluator if you also need its confidence and the content it judged. Inspect the verdicts on real traffic, refine the prompt and rank, then switch the policy to Enforce. Sensitive Data Detection runs in enforce mode only.
Access rights
The steps above require the following privileges:
Step | Required access |
|---|---|
Attach the guardrail |
|
Select a non-default evaluator |
|
Enable an inference table on the evaluator | Permission to manage the evaluator model service (for example, you created it), plus |
Read the evaluator's inference table |
|
Limitations
The following limitations apply:
- Transformation: Service policies return a decision (ALLOW, DENY, or ASK) and don't transform request or response content.
- Policy language: Custom policy functions support only
LANGUAGE SQL. - Attachment scope: Policy attachment is UI-only and scoped to an individual service, and the policy applies to all account users. Attaching policies at the catalog or schema level, attribute-based access control (ABAC) conditions, and custom principals are not available.