Skip to Content
DocsTracingDecorators

Decorators

Two decorators are available: @observe for tracing-only instrumentation, and @endpoint for functions that Rhesis can invoke from the platform (remote testing) while still emitting traces.

Observe vs endpoint

@observe follows the same mental model as typical observability tools (OpenTelemetry, Langfuse, and similar): the function runs inside your normal application context—database handles, auth, config, and dependency injection are already in place when your code calls the function. The decorator records spans; it does not change who triggers execution or supply missing infrastructure.

@endpoint does two things:

  1. Observability — Like @observe, execution is traced (unless you turn tracing off). When your app calls the function locally, it behaves like other instrumented code.
  2. Remote invocation from Rhesis — The function is registered with Rhesis so the platform can call it over the connector (WebSocket): for example when you start a test run from Rhesis and the runner needs to execute your LLM path in your environment. That path is not an HTTP request to your server—you are not required to expose a public URL—Rhesis triggers the decorated function directly from the product.

So observability-only frameworks never have to “create” your dependencies: they observe code that is already running in a full stack. Remote runs from Rhesis do not have FastAPI’s Depends(), Flask’s g, or an incoming request. Parameters your business logic needs (sessions, tenant DB, user) must still exist at invocation time. For that, use bind on @endpoint so infrastructure is injected while only the business arguments stay in the remote signature. See Parameter Binding.

When to use which

SituationDecorator
Helpers, retrieval, LLM wrappers: trace only, always called from your app@observe (or @observe.* helpers)
Entry points Rhesis should list and run from test runs / the platform, with tracing@endpoint

You can compose them: an @endpoint handler often calls @observe-decorated helpers internally.

@endpoint

Functions decorated with @endpoint are registered for remote testing and are automatically traced by default. Use this for the code paths you want Rhesis to trigger from the platform (for example ad-hoc runs and automated test suites), not only for passive observation.

app.py
from rhesis.sdk import endpoint

@endpoint()
def chat(input: str, session_id: str = None) -> dict:
    # Automatically traced + registered for remote testing
    return {"output": process_message(input), "session_id": session_id}

See the Connector documentation for full details on @endpoint.

Disabling Tracing

To register for remote testing without tracing:

app.py
@endpoint(observe=False)
def no_trace_endpoint(x: int) -> int:
    return x * 2

@observe

Use @observe for functions that only need tracing: they are not registered as remotely invocable SDK endpoints. Typical examples are internal helpers, retrieval, and LLM calls your application orchestrates itself.

app.py
from rhesis.sdk import observe

@observe()
def internal_helper(data: str) -> str:
    return data.upper()

Convenience Decorators

Pre-configured decorators for common AI operations, organized by category.

AI Model Operations

@observe.llm()

For language model calls.

app.py
@observe.llm(provider="openai", model="gpt-4")
def generate(prompt: str) -> str:
    return openai.chat.completions.create(...)
ParameterRequiredDescription
providerYesProvider name (openai, anthropic, google)
modelYesModel name (gpt-4, claude-3-opus)

@observe.embedding()

For embedding generation.

app.py
@observe.embedding(model="text-embedding-ada-002", dimensions=1536)
def embed_texts(texts: list) -> list:
    return embedding_model.encode(texts)
ParameterRequiredDescription
modelYesEmbedding model name
dimensionsNoVector dimensions

Tool & Retrieval

@observe.tool()

For tool/function execution.

app.py
@observe.tool(name="weather_api", tool_type="http")
def get_weather(city: str) -> dict:
    return requests.get(f"api/{city}").json()
ParameterRequiredDescription
nameYesTool name
tool_typeYesType (http, function, database)

@observe.retrieval()

For vector search and knowledge base queries.

app.py
@observe.retrieval(backend="pinecone", top_k=5)
def search_docs(query: str) -> list:
    return vector_db.search(query, k=5)
ParameterRequiredDescription
backendYesBackend name (pinecone, weaviate, chroma)
top_kNoNumber of results

@observe.rerank()

For reranking search results.

app.py
@observe.rerank(model="rerank-v1", top_n=10)
def rerank_documents(query: str, docs: list) -> list:
    return reranker.rerank(query, docs, top_n=10)
ParameterRequiredDescription
modelYesReranker model name
top_nNoNumber of results to return

Quality & Safety

@observe.evaluation()

For response evaluation and scoring.

app.py
@observe.evaluation(metric="relevance", evaluator="gpt-4")
def evaluate_relevance(query: str, response: str) -> float:
    return evaluator.score_relevance(query, response)
ParameterRequiredDescription
metricYesMetric name (relevance, faithfulness)
evaluatorYesEvaluator model/service

@observe.guardrail()

For content safety and moderation.

app.py
@observe.guardrail(guardrail_type="content_safety", provider="openai")
def check_content_safety(text: str) -> bool:
    return safety_checker.is_safe(text)
ParameterRequiredDescription
guardrail_typeYesType (content_safety, pii_detection, toxicity)
providerYesProvider name

Data Processing

@observe.transform()

For data transformation and preprocessing.

app.py
@observe.transform(transform_type="text", operation="clean")
def preprocess_text(text: str) -> str:
    return clean_and_normalize(text)
ParameterRequiredDescription
transform_typeYesType (text, image, audio)
operationYesOperation (clean, normalize, tokenize)

Comparison

Feature@observe@endpoint
Traces executionYesYes (default; can disable)
Registered for Rhesis to invoke (e.g. test runs from the platform)NoYes
Needs bind for infra when invoked remotelyN/AOften (see binding)
Use caseHelpers, instrumented stackCallable entry points for tests and connector

Usage Pattern

app.py
from rhesis.sdk import endpoint, observe

# Public API - remote testing + automatic tracing
@endpoint()
def chat(input: str) -> dict:
    context = build_context(input)
    response = generate_response(input, context)
    return {"output": response}

# Internal helper - tracing only
@observe()
def build_context(message: str) -> list:
    return search_docs(message)

# LLM call - convenience decorator
@observe.llm(provider="openai", model="gpt-4")
def generate_response(message: str, context: list) -> str:
    return llm.generate(message, context=context)

# Retrieval - convenience decorator
@observe.retrieval(backend="pinecone", top_k=5)
def search_docs(query: str) -> list:
    return vector_db.search(query)

Next: Learn about custom spans for advanced attribute configuration.