Unified Python SDK for chat completions across multiple AI providers
Project description
Rezunate LLM SDK
Unified Python SDK for chat completions, prompt management, and PII guardrails across OpenAI, Anthropic, and Google Gemini. All requests and responses use the OpenAI format, regardless of provider.
Get an API key and learn more at rezunatellm.com.
What's Included
| Feature | Cost | Requires |
|---|---|---|
| Unified chat completions across OpenAI, Anthropic, Google Gemini | Free | Your own provider API key |
| Local regex guardrails (block / flag PII in inputs and outputs) | Free | Nothing — runs client-side |
| Server-side PII detection | Hosted | Rezunate API key |
| Prompt management with versioning | Hosted | Rezunate API key |
You only need a Rezunate API key for the hosted features.
Installation
pip install rezunate-llm-sdk
Quickstart
from rezunate_llm_sdk import ChatCompletionRequest, Gateway, Message
gateway = Gateway(
default_provider="anthropic",
default_api_key="your-provider-api-key",
)
response = gateway.chat_complete(
ChatCompletionRequest(
model="claude-sonnet-4-5",
messages=[Message(role="user", content="Hello!")],
max_tokens=100,
)
)
print(response.choices[0].message.content)
The stateless form is also available when you don't want a long-lived gateway:
from rezunate_llm_sdk import ChatCompletionRequest, Message, chat_complete
response = chat_complete(
provider="openai",
api_key="your-openai-api-key",
request=ChatCompletionRequest(
model="gpt-4o",
messages=[Message(role="user", content="Hello!")],
),
)
Responses always come back in OpenAI format (response.choices[0].message.content, response.usage.total_tokens, etc.) — even for Anthropic and Google.
Providers
The SDK ships with a factory that creates provider instances on demand. You bring your own API key per provider — Rezunate doesn't proxy or charge for these calls.
from rezunate_llm_sdk import get_available_providers, get_provider
# List the providers the SDK supports
print(get_available_providers())
# [Provider.OPENAI, Provider.ANTHROPIC, Provider.GOOGLE]
# Build a provider instance directly (skips the Gateway/chat_complete facade)
provider = get_provider("anthropic", api_key="your-anthropic-key")
response = provider.chat_complete(
ChatCompletionRequest(
model="claude-sonnet-4-5",
messages=[Message(role="user", content="Hi!")],
)
)
You can also switch providers at call time on a single Gateway:
gateway = Gateway()
gateway.chat_complete(req, provider="openai", api_key=openai_key)
gateway.chat_complete(req, provider="anthropic", api_key=anthropic_key)
gateway.chat_complete(req, provider="google", api_key=google_key)
Request Parameters
ChatCompletionRequest follows the OpenAI schema and supports the common knobs:
ChatCompletionRequest(
model="gpt-4o",
messages=[
Message(role="system", content="You are concise."),
Message(role="user", content="Summarize the last commit."),
],
temperature=0.2,
max_tokens=500,
top_p=0.9,
frequency_penalty=0.0,
presence_penalty=0.0,
stop=["END"],
)
Provider-specific arguments (e.g. Google top_k, safety_settings) are accepted as extra fields and forwarded by each provider's transformer.
Tool Calling
Define tools in OpenAI format and the SDK translates them to each provider's native shape (Anthropic tool_use, Google functionCall) and normalizes the response back to OpenAI tool_calls. The same code works across OpenAI, Anthropic, and Google.
from rezunate_llm_sdk import ChatCompletionRequest, Gateway, Message
gateway = Gateway(default_provider="anthropic", default_api_key="your-anthropic-key")
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Look up the current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}
]
messages = [Message(role="user", content="What's the weather in Tokyo?")]
response = gateway.chat_complete(
ChatCompletionRequest(
model="claude-sonnet-4-5",
messages=messages,
tools=tools,
tool_choice="auto", # "auto" | "required" | "none" | {"type": "function", "function": {"name": "get_weather"}}
max_tokens=300,
)
)
choice = response.choices[0]
if choice.finish_reason == "tool_calls":
call = choice.message.tool_calls[0]
print(call.function.name) # "get_weather"
print(call.function.arguments) # '{"city": "Tokyo"}' (a JSON string)
Run the tool, then send the result back as a tool message to get the final answer:
import json
args = json.loads(call.function.arguments)
result = f"Sunny, 22C in {args['city']}" # your real tool goes here
messages += [
Message(role="assistant", tool_calls=choice.message.tool_calls),
Message(role="tool", content=result, tool_call_id=call.id),
# For Google, also set name=call.function.name on the tool message.
]
final = gateway.chat_complete(
ChatCompletionRequest(model="claude-sonnet-4-5", messages=messages, tools=tools, max_tokens=300)
)
print(final.choices[0].message.content)
Local Regex Guardrails (Free)
Define regex patterns in YAML to block, flag, or redact sensitive content (PII or anything custom) in both user inputs and model outputs. Everything is free and runs client-side — no RezunateLLM account needed, no data leaves your machine.
Create a config file:
# guardrails.yaml
guardrails:
- name: block-ssn
pattern: '\b\d{3}-\d{2}-\d{4}\b'
description: "Block Social Security Numbers"
action: block
# Redact PII instead of blocking the whole request/response.
- name: redact-email
pattern: '\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
description: "Redact email addresses"
action: redact
replacement: "[EMAIL]"
- name: flag-credit-card
pattern: '\b(?:\d[ -]*?){13,16}\b'
description: "Flag potential credit card numbers"
action: flag
Each rule needs:
name— identifierpattern— regex to matchdescription— human-readable descriptionaction— one of:block— raisesGuardrailsError, stopping the request (input) or response (output)flag— records a violation and logs it, but lets the content through unchangedredact— replaces every match withreplacement(defaults to[REDACTED]) in both the prompt sent to the provider and the model's response
replacement— text substituted for each match whenaction: redact(optional; defaults to[REDACTED])
Use it in two ways:
Pass it explicitly to a Gateway:
from rezunate_llm_sdk import Gateway, load_guardrails
config = load_guardrails("guardrails.yaml")
gateway = Gateway(
default_provider="anthropic",
default_api_key="your-anthropic-key",
guardrails_config=config,
)
# Both input and output are checked on every chat_complete call.
gateway.chat_complete(request)
Or enable automatic loading via env var:
export GUARDRAILS_FILE_PATH=path/to/guardrails.yaml
When set, the SDK loads the file once and applies the rules on every chat_complete call without explicit wiring.
You can also call the checker directly. check_guardrails returns a (redacted_text, violations) tuple and raises GuardrailsError on a block rule:
from rezunate_llm_sdk import GuardrailsError, check_guardrails, load_guardrails
from rezunate_llm_sdk.models import GuardrailDirection
config = load_guardrails("guardrails.yaml") # with a redact rule for emails
try:
redacted, violations = check_guardrails(
"Email me at alex@example.com", config, GuardrailDirection.OUTPUT
)
print(redacted) # -> "Email me at [EMAIL]" (redact rules applied)
# 'flag' rules show up in `violations`; 'block' rules raise GuardrailsError
except GuardrailsError as e:
print(f"Blocked by rule '{e.rule_name}' on {e.direction.name}")
Hosted Features
These call the Rezunate API and require REZUNATE_LLM_API_KEY (passed to Gateway or set in the env).
Server-side PII Detection (Premium Feature)
Detect PII entities using the workspace guardrail config managed in RezunateLLM. Returns model-detected entities, with labels, scores, and offsets.
gateway = Gateway(REZUNATE_LLM_API_KEY="your-rezunate-api-key")
result = gateway.guardrails.scan("My SSN is 123-45-6789 and my email is alex@example.com.")
for entity in result.entities:
print(f"{entity.label}: {entity.text!r} (score={entity.score:.2f})")
print("action:", result.action) # action taken per workspace config
print("blocked:", result.blocked) # whether the request was blocked
print("text:", result.text) # processed text (e.g. with PII redacted)
Automatic PII guardrails on input and output
Set server_guardrails=True and the Gateway scans every chat_complete call with the hosted PII service, applying the workspace config automatically:
- if the scan blocks the content → raises
ServerGuardrailsError - if the scan redacts it → the content is replaced with the server's redacted text (the prompt before it's sent, or the response after)
- detected entities are logged either way
from rezunate_llm_sdk import Gateway, ServerGuardrailsError
gateway = Gateway(
default_provider="openai",
default_api_key="your-openai-key",
server_guardrails=True, # scan input AND output via hosted PII service
REZUNATE_LLM_API_KEY="your-rezunate-api-key",
)
try:
response = gateway.chat_complete(request)
print(response.choices[0].message.content) # PII redacted by the server
except ServerGuardrailsError as e:
print(f"Blocked on {e.direction.name} — detected {[ent.label for ent in e.entities]}")
Choosing which side to scan. True scans both the prompt (input) and the model response (output). To scan only one side, pass a ServerGuardrailsConfig with directions:
from rezunate_llm_sdk import Gateway, ServerGuardrailsConfig
gateway = Gateway(
default_provider="openai",
default_api_key="your-openai-key",
server_guardrails=ServerGuardrailsConfig(directions=("output",)), # output only
REZUNATE_LLM_API_KEY="your-rezunate-api-key",
)
server_guardrails value |
Scans |
|---|---|
True |
input and output |
ServerGuardrailsConfig(directions=("input",)) |
input only |
ServerGuardrailsConfig(directions=("output",)) |
output only |
False (default) |
nothing |
You can also override it per call: gateway.chat_complete(request, server_guardrails=...). This runs alongside any local regex guardrails.
Prompt Management
Fetch and render prompts stored on Rezunate LLM. Pin to a specific version, or omit version to use the current one. Variables are interpolated into the template before returning.
gateway = Gateway(
default_provider="anthropic",
default_api_key="your-anthropic-api-key",
REZUNATE_LLM_API_KEY="your-rezunate-api-key",
)
system_prompt = gateway.get_prompt(
slug_id="customer-support-greeting",
variables={"name": "Alex", "tier": "premium"},
version=3, # optional — defaults to current version
)
response = gateway.chat_complete(
ChatCompletionRequest(
model="claude-sonnet-4-5",
messages=[
Message(role="system", content=system_prompt),
Message(role="user", content="Where's my order?"),
],
)
)
Environment Variables
| Variable | Purpose |
|---|---|
REZUNATE_LLM_API_KEY |
Rezunate API key — required for hosted features (prompts, server-side scan) |
OPENAI_API_KEY |
OpenAI provider key — used by your application code |
ANTHROPIC_AI_API_KEY |
Anthropic provider key — used by your application code |
GOOGLE_API_KEY |
Google Gemini provider key — used by your application code |
GUARDRAILS_FILE_PATH |
Optional path to a local guardrails YAML config; loaded automatically when set |
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rezunate_llm_sdk-0.1.2.tar.gz.
File metadata
- Download URL: rezunate_llm_sdk-0.1.2.tar.gz
- Upload date:
- Size: 104.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f0f973e4c209790903827615ce0ac5189aa926e452a0021026383c45185cefb2
|
|
| MD5 |
d8be691209a17c9bd50ca2ed0c7d6f55
|
|
| BLAKE2b-256 |
c87cc2b86f84aa0f8047a610d5979bc85598e4c13f83883b2efe5df8f69502e9
|
File details
Details for the file rezunate_llm_sdk-0.1.2-py3-none-any.whl.
File metadata
- Download URL: rezunate_llm_sdk-0.1.2-py3-none-any.whl
- Upload date:
- Size: 45.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bfbfe0c9e48044d3fb09cecc190424adf71c401bb93daf1873b36576af747195
|
|
| MD5 |
187d1d5aead73ce9d1b826cdd04441c8
|
|
| BLAKE2b-256 |
032ad2301cb4116cb27c4cfe9b0b77f3d7cda689ed00337ae0ff57a5678569a4
|