Python SDK
Complete guide to the ModelRed Python SDK — installation, configuration, and usage patterns.
Introduction
The ModelRed Python SDK provides both synchronous and asynchronous clients for integrating LLM security assessments into your workflow. Built with automatic retries, comprehensive error handling, and type hints for the best developer experience.
Installation
Install via pip or uv:
pip install modelreduv add modelredThe SDK requires Python 3.8 or higher and depends on httpx for HTTP communication.
Client Initialization
Synchronous Client
from modelred import ModelRed
client = ModelRed(
api_key="mr_...",
timeout=20.0,
max_retries=3,
)Asynchronous Client
from modelred import AsyncModelRed
async with AsyncModelRed(api_key="mr_...") as client:
# Use client here
passConfiguration Options
| Prop | Type | Default |
|---|---|---|
api_key? | string | - |
timeout? | float | 20.0 |
max_retries? | int | 3 |
transport? | httpx.BaseTransport | None | - |
extra_headers? | dict[str, str] | None | - |
Context Manager Pattern
Both clients support context managers for automatic resource cleanup:
with ModelRed(api_key="mr_...") as client:
models = client.list_models()
# client.close() called automatically async with AsyncModelRed(api_key="mr_...") as client:
models = await client.list_models()
# await client.aclose() called automaticallyManual Cleanup
If not using context managers, remember to close the client:
client = ModelRed(api_key="mr_...")
try:
# Use client
models = client.list_models()
finally:
client.close() client = AsyncModelRed(api_key="mr_...")
try:
# Use client
models = await client.list_models()
finally:
await client.aclose()Retries & Backoff
The SDK automatically retries requests for transient failures:
Retryable Errors
429 — Rate limited (exponential backoff with jitter)
502, 503, 504 — Server errors
Transport errors — Network issues, connection failures
Backoff Formula
delay = random.uniform(0, min(8.0, 0.5 * 2^attempt))
Base: 0.5s, Cap: 8s
Configure retry behavior:
# Default: 3 retries with 0.5s base, 8s cap
client = ModelRed(api_key="mr_...", max_retries=3)
# Disable retries
client = ModelRed(api_key="mr_...", max_retries=0)
# Aggressive retries
client = ModelRed(api_key="mr_...", max_retries=5)Automatic Retries: The SDK handles rate limits and transient errors automatically. You typically won't see 429 or 5xx errors unless retries are exhausted.
Base URL
The SDK is configured to use https://www.app.modelred.ai as the base URL. This is fixed and cannot be changed in the current version.
User Agent
All requests include a user agent header identifying the SDK version:
modelred-python-sdk/0.1.39Type Hints
The SDK is fully typed and includes type hints for all public methods. Use static type checkers like mypy or pyright for enhanced development experience:
from modelred import ModelRed
from typing import Dict, Any
client: ModelRed = ModelRed(api_key="mr_...")
assessment: Dict[str, Any] = client.get_assessment("assessment_id")API Key Requirements
Your API key must:
- Start with
mr_ - Be valid and active in your ModelRed organization
- Have appropriate permissions for the operations you're performing
The SDK validates the key format on initialization:
# Raises ValueError
client = ModelRed(api_key="invalid_key")
# Raises ValueError
client = ModelRed(api_key="")Thread Safety
The synchronous client uses httpx's Client, which maintains a connection pool but is not thread-safe by default. For concurrent requests:
from modelred import ModelRed
import threading
client = ModelRed(api_key="mr_...")
# NOT RECOMMENDED: Shared client across threads
def worker():
models = client.list_models()
threads = [threading.Thread(target=worker) for _ in range(5)]
for t in threads:
t.start()
for t in threads:
t.join()client per thread def worker(): client = ModelRed(api_key="mr_...") models =
client.list_models() client.close() threads = [threading.Thread(target=worker)
for _ in range(5)] for t in threads: t.start() for t in threads: t.join() ```
</Tab>
<Tab value="Async">
```python
import asyncio
from modelred import AsyncModelRed
async def worker(client: AsyncModelRed):
models = await client.list_models()
async def main():
async with AsyncModelRed(api_key="mr_...") as client:
await asyncio.gather(*[worker(client) for _ in range(5)])
asyncio.run(main())Complete Examples
Synchronous Workflow
from modelred import ModelRed
import os
# Initialize client
client = ModelRed(
api_key=os.environ["MODELRED_API_KEY"],
timeout=30.0,
max_retries=3,
)
try:
# List models
models = client.list_models(provider="openai", status="active")
print(f"Found {len(models['data'])} models")
# Get probe packs
owned = client.list_owned_probes(category="injection", page_size=5)
# Create assessment
if models["data"] and owned["data"]:
assessment = client.create_assessment_by_id(
model_id=models["data"][0]["id"],
probe_pack_ids=[owned["data"][0]["id"]],
detector_provider="openai",
detector_api_key=os.environ["OPENAI_API_KEY"],
detector_model="gpt-4o-mini",
)
print(f"Assessment created: {assessment['id']}")
finally:
client.close()Asynchronous Workflow
import asyncio
from modelred import AsyncModelRed
import os
async def main():
async with AsyncModelRed(
api_key=os.environ["MODELRED_API_KEY"],
timeout=30.0,
max_retries=3,
) as client:
# List models
models = await client.list_models(provider="anthropic", status="active")
print(f"Found {len(models['data'])} models")
# Get probe packs
imported = await client.list_imported_probes(category="jailbreak", page_size=5)
# Create assessment
if models["data"] and imported["data"]:
assessment = await client.create_assessment_by_id(
model_id=models["data"][0]["id"],
probe_pack_ids=[imported["data"][0]["id"]],
detector_provider="anthropic",
detector_api_key=os.environ["ANTHROPIC_API_KEY"],
detector_model="claude-3-5-sonnet-20241022",
)
print(f"Assessment created: {assessment['id']}")
asyncio.run(main())Environment Configuration
Use environment variables for sensitive configuration:
import os
from modelred import ModelRed
from dotenv import load_dotenv
# Load from .env file
load_dotenv()
# Create client from environment
client = ModelRed(
api_key=os.environ["MODELRED_API_KEY"],
timeout=float(os.environ.get("MODELRED_TIMEOUT", "20.0")),
max_retries=int(os.environ.get("MODELRED_MAX_RETRIES", "3")),
)Example .env file:
MODELRED_API_KEY=mr_your_key_here
MODELRED_TIMEOUT=30.0
MODELRED_MAX_RETRIES=5
OPENAI_API_KEY=sk_your_openai_key
ANTHROPIC_API_KEY=sk-ant_your_anthropic_keySecurity: Never commit .env files to version control. Add .env to your
.gitignore file.
Custom Transport
Configure custom HTTP transport for proxies or testing:
import httpx
from modelred import ModelRed
# Corporate proxy
transport = httpx.HTTPTransport(
proxy="http://proxy.company.com:8080"
)
client = ModelRed(
api_key="mr_...",
transport=transport,
)Custom Headers
Add custom headers to all requests:
from modelred import ModelRed
client = ModelRed(
api_key="mr_...",
extra_headers={
"X-Custom-Header": "value",
"X-Request-ID": "unique-id",
},
)Error Handling
The SDK provides comprehensive error types:
from modelred import (
ModelRedError, # Base exception
APIError, # HTTP/API errors
Unauthorized, # 401
Forbidden, # 403
NotFound, # 404
ValidationFailed, # 400, 422
RateLimited, # 429
ServerError, # 5xx
)
try:
assessment = client.get_assessment("assessment_id")
except NotFound as e:
print(f"Assessment not found: {e.message}")
except APIError as e:
print(f"API error {e.status}: {e.message}")See the Error Handling guide for comprehensive error management.
Best Practices
Security
Never hardcode API keys. Use environment variables or secrets managers for production deployments.
Performance
Reuse client instances to benefit from connection pooling. Use async client for concurrent operations.
Resource Management
Always use context managers or ensure manual cleanup with close() or aclose().
# ✅ Good: Reuse client
client = ModelRed(api_key=os.environ["MODELRED_API_KEY"])
def get_models():
return client.list_models()
def create_assessment():
return client.create_assessment_by_id(...)
# ❌ Bad: Creates new client each time
def get_models():
client = ModelRed(api_key=os.environ["MODELRED_API_KEY"])
return client.list_models()Next Steps
Now that you understand client configuration, explore specific operations:
- Create and manage assessments
- Work with probe packs
- List and filter models
- Handle errors gracefully
- Implement pagination