Skip to main content
Version: 1.66

Apply guardrails with the Python client

Use the Deeploy Python client to discover Workspace guardrails, check payloads manually, and enforce guardrails automatically on requests made through OpenAI-compatible clients and supported AI libraries.

Install the guardrails package​

Install the guardrails extra when you install the Deeploy Python package. The extra includes the dependencies required for guardrail evaluation and request interception.

pip install "deeploy[guardrails]"

If you already installed deeploy, install or upgrade the extra with the same command.

Configure authentication​

You need the following values to connect to a Workspace:

  • Your Deeploy host URL.
  • Your Workspace ID.
  • Either access and secret keys or OAuth client credentials.
  • An OpenAI-compatible provider URL, API key, and model when you send requests to a provider.

Store these values in environment variables rather than placing credentials directly in your notebook or application. The following example loads them from a local env_guardrail file. If you only use guard.check() or local regex guardrails, you don't need to configure a provider.

import os
from pathlib import Path

from dotenv import load_dotenv

ENV_FILE = Path.cwd() / "env_guardrail"
if not ENV_FILE.is_file():
raise FileNotFoundError(
f"Create {ENV_FILE} from env_guardrail.example and fill in the values."
)
load_dotenv(ENV_FILE)

DEEPLOY_BASE_URL = os.environ["DEEPLOY_BASE_URL"]
WORKSPACE_ID = os.environ["DEEPLOY_WORKSPACE_ID"]
DEEPLOY_CLIENT_ID = os.environ["DEEPLOY_CLIENT_ID"]
DEEPLOY_CLIENT_SECRET = os.environ["DEEPLOY_CLIENT_SECRET"]

PROVIDER_BASE_URL = os.environ["OPENAI_BASE_URL"]
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
MODEL = os.environ["OPENAI_MODEL"]

For access-key authentication, initialize the client with access_key and secret_key instead of OAuth client credentials. See Authentication for the available Deeploy authentication methods.

Connect to the GuardrailService​

Create a Deeploy Client and retrieve its GuardrailService. The service uses your Workspace credentials to list and evaluate the guardrails configured in that Workspace.

The service supports two failure modes for deployment-backed guardrails:

  • fail_mode="open" (default): if a guardrail deployment cannot be reached, rejects authentication, or another interception error occurs, the provider request or response is forwarded and the failure is logged.
  • fail_mode="closed": the guardrail failure is raised and the unguarded provider request or response is not allowed to continue.

Use fail_mode="closed" when guardrail enforcement is mandatory:

from deeploy.guardrails import GuardrailService

guard = GuardrailService(
host=DEEPLOY_BASE_URL,
workspace_id=WORKSPACE_ID,
client_id=DEEPLOY_CLIENT_ID,
client_secret=DEEPLOY_CLIENT_SECRET,
fail_mode="closed",
)

Use fail_mode="open" when guardrails should be best-effort and provider availability should take priority.

from deeploy.client import Client

client = Client(
host=DEEPLOY_BASE_URL,
workspace_id=WORKSPACE_ID,
oauth_client_id=DEEPLOY_CLIENT_ID,
oauth_client_secret=DEEPLOY_CLIENT_SECRET,
)

guard = client.get_guardrail_service()

You can also initialize GuardrailService directly when you don't need the rest of the client:

from deeploy.guardrails import GuardrailService

guard = GuardrailService(
host=DEEPLOY_BASE_URL,
workspace_id=WORKSPACE_ID,
client_id=DEEPLOY_CLIENT_ID,
client_secret=DEEPLOY_CLIENT_SECRET,
)

Discover Workspace guardrails​

Call get_guardrails() to retrieve the guardrails configured in the Workspace. Each returned guardrail includes its name, type, action, direction, and deployment details when applicable.

guardrails = guard.get_guardrails()

print(f"Discovered {len(guardrails)} guardrail(s):")
for guardrail in guardrails:
print(
f"- {guardrail.name} ({guardrail.id}): "
f"type={guardrail.guardrail_type.value}, "
f"action={guardrail.action.value}, "
f"input={guardrail.apply_to_input}, "
f"output={guardrail.apply_to_output}"
)

if not guardrails:
raise RuntimeError("No guardrails were returned for this Workspace.")

You can pass the complete list to the service or select a subset for a specific request.

Evaluate a payload manually​

Use guard.check() when you want to evaluate a payload without making a provider request. The method returns the processed payload when the check succeeds. A masking guardrail can return a modified payload, while a blocking guardrail raises GuardrailBlocked.

from deeploy.guardrails import GuardrailBlocked

input_payload = {
"model": MODEL,
"messages": [
{"role": "user", "content": "Give me a sample email address?"}
],
}

try:
checked_payload = guard.check(input_payload, guardrails)
print("Manual check passed:", checked_payload)
except GuardrailBlocked as exc:
print("Manual check blocked the payload:", exc.reason)

Use manual checks for validation, tests, or workflows where you build the provider request yourself.

Enforce guardrails on provider requests​

Use guard.install() as a context manager to intercept matching HTTP requests. The guardrails apply for the duration of the context and are removed when the context exits.

The following example protects an OpenAI-compatible chat completion request:

from openai import OpenAI

client = OpenAI(api_key=OPENAI_API_KEY, base_url=PROVIDER_BASE_URL)

with guard.install(guardrails):
response = client.chat.completions.create(
model=MODEL,
messages=input_payload["messages"],
stream=False,
)

print(response.choices[0].message.content)

To intercept a provider endpoint that is not covered by the default patterns, provide url_pattern as a regular expression matching the full request URL.

with guard.install(guardrails, url_pattern=r"/chat/completions"):
response = client.chat.completions.create(
model=MODEL,
messages=input_payload["messages"],
stream=False,
)

url_pattern is a regular expression searched against the full request URL. It adds a custom match to the built-in patterns; it does not replace or restrict them. For example, the following also matches /chat/completions, even though the custom pattern itself targets /my-provider/guarded:

with guard.install(guardrails, url_pattern=r"/my-provider/guarded"):
response = client.post(
"https://provider.example.com/my-provider/guarded",
json=input_payload,
)

Omit url_pattern to use only the built-in provider endpoint patterns. Because it is a regular expression, escape special characters and anchor the expression when a precise URL match is required.

By default, interception covers these endpoint patterns:

  • /chat/completions
  • /completions
  • /v1/messages
  • /v1/responses

A guardrail can flag, mask, or block content depending on its configured action. Catch GuardrailBlocked around manual checks when you need to handle a blocked request explicitly. For intercepted requests, the service returns the guardrail response or refusal according to the configured action.

Add local regex guardrails​

Regex guardrails configured in your Workspace are synchronized to the Python client and executed locally. You can also add local regex guardrails with ManualGuardrail.make_regex() when you need an additional application-specific rule that isn't configured in the Workspace.

The following example creates additional flag, mask, and block rules:

from deeploy.enums import GuardrailAction
from deeploy.guardrails import GuardrailBlocked, ManualGuardrail

regex_flag = ManualGuardrail.make_regex(
regex=r"\b\d{16}\b",
action=GuardrailAction.FLAG,
name="manual-card-flag",
)
regex_mask = ManualGuardrail.make_regex(
regex=r"abc@\w+\.com",
action=GuardrailAction.MASK_CONTENT,
replacement="[EMAIL REDACTED]",
name="manual-email-mask",
)
regex_block = ManualGuardrail.make_regex(
regex=r"\b\d{3}-\d{2}-\d{4}\b",
action=GuardrailAction.BLOCK,
name="manual-ssn-block",
)

print(guard.check("My card is 4111111111111111", regex_flag))
print(guard.check("reach me at [email protected] please", regex_mask))

try:
guard.check("My SSN is 123-45-6789.", regex_block)
except GuardrailBlocked as exc:
print("Blocked:", exc.reason)

You can use the same guardrail with a provider client:

with guard.install([regex_mask]):
response = client.chat.completions.create(
model=MODEL,
messages=[
{
"role": "user",
"content": "My support email is [email protected]. Please say it back verbatim.",
}
],
stream=False,
)

print(response.choices[0].message.content)

Use a Deployment as a guardrail​

A Deployment-backed guardrail sends the request to a dedicated guardrail Deployment. The Deployment must return a JSON object containing a Boolean guardrail_triggered property. For masking behavior, it can also return the transformed request body. See Using a deployment as a guardrail for the response schema and masking examples.

Use ManualGuardrail.make_deployment_guardrail() when you want to configure one Deployment-backed guardrail directly instead of discovering it from the Workspace.

from deeploy.enums import GuardrailAction, GuardrailEndpointType
from deeploy.guardrails import ManualGuardrail

manual_guardrail = ManualGuardrail.make_deployment_guardrail(
deployment_id="r715707e-5d1f-4caa-8180-0958c240c1f3",
deployment_token=os.environ.get("DEEPLOY_DEPLOYMENT_TOKEN", ""),
endpoint_type=GuardrailEndpointType.PREDICT,
action=GuardrailAction.BLOCK,
apply_to_input=True,
apply_to_output=False,
name="deployment-guardrail",
)

with guard.install([manual_guardrail]):
response = client.chat.completions.create(
model=MODEL,
messages=input_payload["messages"],
stream=False,
)

An empty deployment_token makes the service use the Workspace authentication configured on GuardrailService. Provide a deployment token when the application should authenticate specifically to that Deployment.

The Deployment response must include a Boolean guardrail_triggered value. If it is missing or is not a Boolean, the SDK logs a warning and treats the deployment guardrail as not triggered. It does not raise a schema-validation error for this response shape.

Integrate with AI libraries​

Install the library you want to use, then wrap the model call with guard.install().

LangChain​

The following example uses ChatOpenAI with an OpenAI-compatible provider:

from langchain_openai import ChatOpenAI

langchain_model = ChatOpenAI(
model=MODEL,
api_key=OPENAI_API_KEY,
base_url=PROVIDER_BASE_URL,
)

with guard.install(guardrails):
response = langchain_model.invoke(input_text)

print(response.content)

LangGraph​

Create the graph normally and install guardrails around the graph invocation:

with guard.install(guardrails):
graph_result = graph.invoke(
{"messages": [{"role": "user", "content": input_text}]}
)

print(graph_result["messages"][-1].content)

smolagents​

Pass a list of messages to OpenAIModel.generate() and scope the request with url_pattern:

from smolagents import OpenAIModel

smol_model = OpenAIModel(
model_id=MODEL,
api_base=PROVIDER_BASE_URL,
api_key=OPENAI_API_KEY,
)

with guard.install(guardrails):
response = smol_model.generate(
[{"role": "user", "content": input_text}]
)

print(response.content)

Nest temporary guardrail scopes​

Guardrail installations can be nested. A temporary inner scope replaces the active rules while it runs, then restores the outer rules when it exits. This lets you define process-wide rules and apply additional rules for a specific operation.

from deeploy.enums import GuardrailAction
from deeploy.guardrails import ManualGuardrail

rule_a = ManualGuardrail.make_regex(
regex=r"alpha",
action=GuardrailAction.BLOCK,
name="scope-a-alpha",
)
rule_b = ManualGuardrail.make_regex(
regex=r"beta",
action=GuardrailAction.BLOCK,
name="scope-b-beta",
)

try:
guard.install([rule_a])
with guard.install([rule_b]):
# Requests in this scope use rule_b.
pass
# Requests here use rule_a again.
finally:
guard.uninstall()

Call uninstall() when you install a process-wide guardrail scope without a with statement. Prefer the context-manager form for temporary scopes so cleanup happens automatically.