Self-hosted LLM observability SDK — trace any model call to your own dashboard
Project description
LangProtect Python SDK
Every model call is scanned by Armor for threats and PII, routed to the right provider, and linked to the LangProtect dashboard — all with a single import change.
Install
pip install git+https://github.com/Quokka-Labs-LLP/langprotect-armor-sdk.git#subdirectory=python
Quick Start
import langprotect
langprotect.init(
openai_api_key = "sk-...",
armour_base_url = "https://langprotect-xxx.run.app",
armour_api_key = "your-armour-key",
security_on = True,
)
from langprotect.langfuse.openai import openai
response = openai.chat.completions.create(
model = "gpt-4o-mini",
messages = [{"role": "user", "content": "Hello!"}],
session_id = "sess_001",
user_id = "user_42",
)
print(response.choices[0].message.content)
Configuration
All configuration is passed to langprotect.init() — no .env file required.
import langprotect
langprotect.init(
# LLM provider
openai_api_key = "sk-...",
# Armor security scanning
armour_base_url = "https://langprotect-xxx.run.app",
armour_api_key = "your-armour-key",
security_on = False, # True → sanitize/block unsafe input
# False → scanning disabled entirely
trace_only = False, # True → log only, never enforce
scan_timeout = 60, # Armor HTTP timeout in seconds
# LangProtect dashboard (used by score())
langprotect_host = "http://localhost:8000",
# LiteLLM proxy (optional — enables non-OpenAI models)
litellm_host = "", # e.g. "http://localhost:4000"
)
| Parameter | Default | Description |
|---|---|---|
openai_api_key |
"" |
OpenAI API key |
armour_base_url |
"" |
Armor API base URL |
armour_api_key |
"" |
Armor X-API-Key header |
security_on |
False |
Enforce sanitization / blocking |
trace_only |
False |
Log only — never block or sanitize |
scan_timeout |
60 |
Armor HTTP timeout (seconds) |
langprotect_host |
http://localhost:8000 |
Dashboard URL for score() |
litellm_host |
"" |
LiteLLM proxy URL for non-OpenAI models |
init()must be called beforefrom langprotect.langfuse.openai import openai.
Usage
Chat completions
from langprotect.langfuse.openai import openai
response = openai.chat.completions.create(
model = "gpt-4o",
messages = [{"role": "user", "content": "Explain async/await"}],
session_id = "sess_123",
user_id = "u_42",
metadata = {"turn_number": 1},
)
print(response.choices[0].message.content)
Handling blocked responses
When security_on=True and Armor hard-blocks a request, a BlockedResponse is returned instead of a normal completion. Check for it before reading .choices:
if getattr(response, "blocked", False):
print(response.content) # "This response has been blocked by security policy."
else:
print(response.choices[0].message.content)
Toggling security at runtime
from langprotect.langfuse.openai import set_security
set_security(True) # Armor ON
set_security(False) # Armor OFF
Feedback scoring
from langprotect.langfuse.openai import score
score(trace_id="abc123", value=1, comment="Correct and concise")
score(trace_id="abc123", value=-1)
value is 1 (positive) or -1 (negative). Scores are posted to {langprotect_host}/api/feedback.
Supported call parameters
These are stripped before the OpenAI call and used for metadata only:
| Parameter | Type | Description |
|---|---|---|
session_id |
str |
Groups all turns of a conversation |
user_id |
str |
Identifies the end user |
name |
str |
Trace label |
metadata |
dict |
Any JSON key-value context |
trace_id |
str |
Override the auto-generated UUID |
tags |
list |
Labels for filtering |
Security Scanning
The SDK calls the Armor /v1/scan endpoint on every input and output.
Scan modes
trace_only |
security_on |
Behaviour |
|---|---|---|
True |
any | Log the scan result, always proceed |
False |
False |
Block if input is not safe, no sanitization |
False |
True |
Sanitize if possible, block otherwise |
Anonymization
When Armor returns a sanitized_prompt (PII replaced with tokens like [PERSON_1], [EMAIL_ADDRESS_1]), the SDK:
- Replaces the user message with the sanitized version
- Injects a system prompt hint so the LLM treats tokens as real values
- On the output scan, restores the original values via
sanitized_outputtransparently
The caller always receives the deanonymized response.
Model Routing
The SDK detects the provider from the model name and routes accordingly:
| Model prefix | Provider | Route |
|---|---|---|
gpt-, o1, o3, text-davinci, text-embedding |
OpenAI | Direct to OpenAI API |
claude, anthropic |
Anthropic | Via LiteLLM proxy |
gemini, palm |
Via LiteLLM proxy | |
llama, mistral, mixtral, codellama, phi, qwen |
Ollama | Via LiteLLM proxy |
| anything else | LiteLLM | Via LiteLLM proxy |
Non-OpenAI models require litellm_host to be set.
Starting LiteLLM
litellm --model claude-3-5-sonnet-20241022 --port 4000
Then in init():
langprotect.init(
...
litellm_host = "http://localhost:4000",
)
Adding a new model via config
# litellm_config.yaml
- model_name: phi3
litellm_params:
model: ollama/phi3
api_base: http://localhost:11434
ollama pull phi3
litellm --config litellm_config.yaml --port 4000
Data Flow
Your App
openai.chat.completions.create(model="gpt-4o", messages=[...])
│
▼
langprotect SDK
1. Armor input scan → sanitize / block / log
2. LLM call → OpenAI direct or LiteLLM proxy
3. Armor output scan → deanonymize + eval trigger
│
▼
Response returned to caller
(eval runs as background task on LangProtect backend)
Troubleshooting
ModuleNotFoundError: langprotect
Ensure the SDK is installed in your active virtualenv and init() is called before importing submodules.
Response not deanonymized
Check that security_on=True and ARMOUR_BASE_URL / ARMOUR_API_KEY are set correctly. The Armor output scan must return sanitized_output.
Non-OpenAI model fails
Set litellm_host in init() and ensure the LiteLLM proxy is running with the model configured.
Armor scan times out
Increase scan_timeout in init() (default 60 s). Check that armour_base_url is reachable from your environment.
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 langprotect_armor-0.1.0.tar.gz.
File metadata
- Download URL: langprotect_armor-0.1.0.tar.gz
- Upload date:
- Size: 14.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f183c43d774a8c140dc0b4aa1aeb47a22a271762dc0807cc72ae2470b592834b
|
|
| MD5 |
f04362fd2207857fa4c1e4a2f5862db1
|
|
| BLAKE2b-256 |
f69c868d3a5851c75247efd29bf90efe39980696d43021aaf2234252d2200284
|
File details
Details for the file langprotect_armor-0.1.0-py3-none-any.whl.
File metadata
- Download URL: langprotect_armor-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9bdda8bd727d0ec3afa394e196059a3ac581485ec2f867c30bafb9b8469e99ba
|
|
| MD5 |
b50844a4947ff07deb083851ec4a85e3
|
|
| BLAKE2b-256 |
6857c83fc156188a176e2d45852ed76471030adece136ad2519ef99688a8a7ee
|