prism-sdk
LLM Observability in 3 lines. Costs, latency, errors and quality — automatically.
pip install useprism
Quick Start
With Anthropic
import anthropic
import prism
# 1. Init
prism.init("prism_your_api_key")
# 2. Wrap your client
client = prism.wrap(anthropic.Anthropic())
# 3. Use exactly as before — everything is traced automatically
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Summarise this contract..."}],
)
With OpenAI
import openai
import prism
prism.init("prism_your_api_key")
client = prism.wrap(openai.OpenAI())
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello!"}],
)
Streaming
# Anthropic — as an iterator
stream = client.messages.create(model="claude-sonnet-4-6", stream=True,
max_tokens=1024, messages=[...])
for event in stream:
...
# Anthropic — as a context manager
with client.messages.stream(model="claude-sonnet-4-6", max_tokens=1024, messages=[...]) as s:
for text in s.text_stream:
print(text, end="")
The trace is recorded when the stream finishes — output tokens are only known at that point. Events pass through untouched.
Streaming with OpenAI: their API only returns usage if you ask for it. Without it,
token counts and cost come back as zero, and the trace is flagged with
metadata.usage_missing so you can tell "it was free" apart from "it could not be
measured":
stream = client.chat.completions.create(
model="gpt-4o", stream=True, messages=[...],
stream_options={"include_usage": True}, # without this, no cost data
)
Async clients
import anthropic, prism
prism.init("prism_your_api_key")
client = prism.wrap(anthropic.AsyncAnthropic())
response = await client.messages.create(model="claude-sonnet-4-6",
max_tokens=1024, messages=[...])
# async streaming
stream = await client.messages.create(stream=True, ...)
async for event in stream:
...
AsyncOpenAI works the same way.
When a call fails
Your exception is re-raised untouched — Prism never swallows errors. The trace is recorded
first, with the provider's status code and the exception type and message under
metadata.error, so a failed call shows why rather than just 500.
try:
client.messages.create(...)
except anthropic.RateLimitError:
... # your handling is unaffected; the trace already recorded 429
With a custom / unsupported client
import prism
from prism.manual import trace
prism.init("prism_your_api_key")
with trace("my-model", endpoint="/api/summarize") as t:
result = my_custom_llm_call(prompt)
t.set_tokens(prompt=500, completion=200)
t.set_response(result.text)
Configuration
prism.init(
api_key="prism_your_api_key",
debug=True, # print logs to stdout
flush_interval=2.0, # seconds between batch flushes
batch_size=20, # traces per batch request
)
What gets tracked automatically
| Field | Description |
|---|---|
model |
Model name (e.g. claude-sonnet-4-6) |
provider |
anthropic / openai / google |
prompt_tokens |
Input tokens used |
completion_tokens |
Output tokens used |
cost_usd |
Calculated cost (server-side) |
latency_ms |
End-to-end response time |
status_code |
200 on success, 4xx/5xx on errors |
prompt_preview |
First 500 chars of the prompt |
response_preview |
First 500 chars of the response |
metadata.error |
On failure: exception type and message |
session_id |
Conversation grouping (if provided) |
prompt_name / prompt_version |
Via extra_headers |
FastAPI integration example
from fastapi import FastAPI, Request
import anthropic
import prism
prism.init("prism_your_api_key")
app = FastAPI()
@app.post("/api/chat")
async def chat(request: Request):
body = await request.json()
# Wrap per-request for endpoint-level tracking
client = prism.wrap(
anthropic.Anthropic(),
endpoint="/api/chat",
)
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": body["message"]}],
)
return {"reply": response.content[0].text}
Overhead
- ~0ms added to your LLM calls (async background thread)
- Traces are batched and sent every 2 seconds
- On shutdown, all pending traces are flushed
License
MIT
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 useprism-0.7.0.tar.gz.
File metadata
- Download URL: useprism-0.7.0.tar.gz
- Upload date:
- Size: 21.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7af3a599f06964874f4d0dcb5d8df81ecfc5a354e316753ec4896cd6b45579e
|
|
| MD5 |
759246d93f9505a7b5547da7e0620bb4
|
|
| BLAKE2b-256 |
bdb9e0da6e4eeb39f6cb7187c5e7902218ebe8e309cf0fa65fd9874851c6453d
|
File details
Details for the file useprism-0.7.0-py3-none-any.whl.
File metadata
- Download URL: useprism-0.7.0-py3-none-any.whl
- Upload date:
- Size: 17.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f1afb4fc4cb95eb7466c15fdb12867992860f4fc151ba3b4fcad2fd5340bd3a
|
|
| MD5 |
aa6a1ef056beea0d79c60458afe70bf0
|
|
| BLAKE2b-256 |
72db0f688f72497a12974d5590495cb7a9fa6448f6aecbfee61310f4363a62d1
|