The detection layer for LLM pipelines — per-step anomaly detection on tokens, latency, and cost
Project description
cernova
Python SDK for Cernova — the detection layer for LLM pipelines.
Automatically captures tokens, latency, and cost for every LLM call, and runs per-step anomaly detection to catch silent regressions before your users notice.
Installation
pip install cernova # core — manual ingest()
pip install cernova[langchain] # + LangChain callback handler (Anthropic, OpenAI, etc.)
LangChain (recommended)
Attach CernovaCallbackHandler to any LangChain LLM — every call is traced automatically:
from cernova import Tracer
from cernova.langchain import CernovaCallbackHandler
from langchain_anthropic import ChatAnthropic
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
tracer = Tracer(api_key="trace_...")
handler = CernovaCallbackHandler(tracer)
llm = ChatAnthropic(model="claude-haiku-4-5-20251001", callbacks=[handler])
chain = ChatPromptTemplate.from_template("Summarize: {text}") | llm | StrOutputParser()
chain.invoke({"text": "..."})
# → shows up in your dashboard automatically
Works with any LangChain-compatible provider: Anthropic, OpenAI, Gemini, Cohere, and more.
Step naming
Pass step_name in config metadata to label steps in the dashboard:
chain.invoke(
{"text": "..."},
config={"metadata": {"step_name": "summarize"}}
)
Without a name, the step is labeled from the serialized model name (e.g. ChatAnthropic).
Multi-step pipelines
Steps inside a single chain.invoke() are automatically grouped into one run in the dashboard. Use RunnableLambda to wrap multi-step workflows:
from langchain_core.runnables import RunnableLambda
from langchain_core.messages import SystemMessage, HumanMessage
def pipeline(inputs, config):
intent = llm.invoke(
[SystemMessage(content="Classify as: billing, technical, general."),
HumanMessage(content=inputs["message"])],
config={**config, "metadata": {"step_name": "classify"}},
)
reply = llm.invoke(
[SystemMessage(content="You are a support agent. Be concise."),
HumanMessage(content=inputs["message"])],
config={**config, "metadata": {"step_name": "generate"}},
)
return reply.content
chain = RunnableLambda(pipeline)
chain.invoke({"message": "..."}, config={"callbacks": [handler]})
# → both steps appear under one run_id in the dashboard
Manual ingest
For models outside LangChain, or to record any custom step:
import time, json
start = time.monotonic()
response = my_model.generate(prompt)
latency = int((time.monotonic() - start) * 1000)
tracer.ingest(
run_id = "my-run-id",
step_name = "generate",
step_index = 0,
model = "my-model",
prompt = json.dumps({"messages": [{"role": "user", "content": prompt}]}),
input_tokens = response.input_tokens,
output_tokens = response.output_tokens,
total_tokens = response.total_tokens,
latency_ms = latency,
cost = 0.001,
status_success= True,
output_code = response.text,
)
ingest() fires in a background thread and never blocks your application.
Configuration
import os
from cernova import Tracer
tracer = Tracer(
api_key = os.environ["CERNOVA_API_KEY"],
api_url = os.environ.get("CERNOVA_API_URL", "https://trace-production-940c.up.railway.app"),
)
For local dev, add to .env:
CERNOVA_API_KEY=trace_...
CERNOVA_API_URL=http://localhost:8000
Links
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 cernova-0.1.1.tar.gz.
File metadata
- Download URL: cernova-0.1.1.tar.gz
- Upload date:
- Size: 7.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29ea60e638b81427d07432c34d33f511081092d966cfb7d9cd957872db5e0638
|
|
| MD5 |
2bb9c6f4c99e99e2ed850f2e2f6b466f
|
|
| BLAKE2b-256 |
8341e111d446632ba2a51c1ea6f249193e3584eca11603b80043fc58b8e0232e
|
File details
Details for the file cernova-0.1.1-py3-none-any.whl.
File metadata
- Download URL: cernova-0.1.1-py3-none-any.whl
- Upload date:
- Size: 8.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76602779a448d38d6d833b3314a1e359f2401ecafd150356d302436e7d38750f
|
|
| MD5 |
8aa80882fb7b0b026691431195767393
|
|
| BLAKE2b-256 |
49b3ac359995f6ffbc3f38ce11f1aa9827a405b312f2d4f3aafb684168183354
|