Skip to main content

Opik alternative: guardrails, PII and online evaluation

· 17 min read
LLM-ops platform

Opik is Comet's open-source LLM-ops platform, and unlike some competitors we've covered it ships with genuinely no login wall when self-hosted — you docker compose up and you're working inside a real workspace immediately. We built the same prompt — vip-support-triage, a support agent that changes tone for VIP customers and lists their open tickets — on both platforms, then ran the identical sequence on each: create the prompt, version it, send a live call, inspect the trace, build a dataset, run an experiment, and call it from an SDK script.

Same example, both sides

Every paired screenshot below comes from the exact same prompt and the exact same customer message, sent through the exact same downstream model (openai/gpt-4o-mini via OpenRouter) on both platforms. Opik's self-hosted instance had no login screen and no credentials to configure, so this comparison was run as an anonymous local user — exactly what a reader self-hosting it for the first time would see. Where a step is genuinely one-sided — no equivalent screen exists on the other product — we say so instead of padding it out. License, pricing, team structure, and community stats live on the compare page instead of here — they were always tables, and a price change there is one edit instead of three.

At a glance

AspectOpikAcruxCoreWinner
Dataset creationAdd-to-dataset from any trace, inline dataset creationFrom real span-level trace feedbackDepends
Prompt templatingFlat {{variable}} only, but real Diff view + environment labelsReal nunjucks {% if %} / {% for %} logic, real Diff tabAcruxCore
PlaygroundLatency + tokens shown inline, no cost, no cacheCost, cache, latency shown inlineAcruxCore
Tracing depthSpan tree via client-side SDK instrumentationSingle automatic spanDepends
Request-path gatewayNone — ingests a trace after your own callBuilt in — routing, caching, budgetsAcruxCore
Tool catalogNo catalog at all — "Agent playground" needs a live connected processVersioned catalog, real executed calls, analyticsAcruxCore
SDK trace captureWrap a client with track_openai()Automatic side effect of the gateway callAcruxCore
Measured overhead+2 to +22 ms across three 100-round runs+9 to +31 ms across the same three runsOpik, barely
Time-to-first-traceOnly via the SDK path, after wrapping a clientZero code, first callAcruxCore

License, pricing, team structure, security, and community stats: see AcruxCore vs Opik on the compare page.

Full breakdown, screenshots, and the verdict below.

Evaluation & datasets

Opik's "Add to → Dataset" works straight from a trace's detail panel — broader than a span-only restriction we hit on another platform — and creating a brand-new dataset is a one-step inline dialog from that same menu.

Show screenshot: Add to dataset dialog on Opik

Opik's Add to dataset dialog, with a newly-created vip-support-triage-feedback dataset selected and the trace's nested spans, tags, feedback scores, and usage metrics all checked to copy in

AcruxCore's dataset — built from a real feedback row, since the vip-support-triage trace's own single-span feedback wasn't eligible — is one sentence here; see the walkthrough for the screenshot.

Running an experiment against that dataset from the UI goes through "Open in Playground" — the dataset's rows load as bindable variables ({{input.messages.1.content}}-style paths), then Run. Clicking "Run an experiment" directly instead explicitly says "Use this dataset to run an experiment using the Python SDK" — confirming the SDK is the primary path for a scripted experiment, with the Playground as the interactive alternative.

Show screenshot: dataset-bound experiment run in Opik's Playground

Opik's Playground with the dataset loaded, a variant bound to the dataset's message field, and a real experiment result row showing the model's reply next to the dataset's expected output and feedback score

AcruxCore's Run report for that dataset against gpt-4o-mini — a plain, unscored manual run — is one sentence here; see the walkthrough for the screenshot.

FeatureOpikAcruxCore
Dataset creationFrom any trace directly, inline "create new dataset" in the same dialogFrom trace feedback only — and only span-level feedback
ExperimentsInteractive via Playground, or scripted via the Python SDK (UI explicitly defers to it)Version × model sweep with an automatic baseline, run from the UI
Feedback scoresThumbs-up/down "Human review," visible in the dataset row copied overSpan-level feedback, gates dataset eligibility

Prompt authoring & versioning

Opik's Prompt library offers a "text prompt" or a "chat prompt" — both are flat {{variable}} substitution, confirmed hands-on: there is no {% if %} or {% for %} anywhere. We flattened the VIP-branch note and the two-item ticket list into plain text, the same way an earlier comparison had to for Langfuse, keeping only {{company}} and {{customer_message}} as real variables.

Show screenshots: prompt editor and versions on both platforms

Opik's New chat prompt dialog for the recreated vip-support-triage prompt, showing flat {{company}} and {{customer_message}} variable substitution with no conditional syntax available Opik's prompt detail page for v1, with Use, Deploy to, and Edit controls above the rendered system and user messages AcruxCore's Diff tab showing a real unified diff between prompt version 2 and version 3

AcruxCore's own prompt editor — real nunjucks conditionals and loops rendering VIP status and the ticket list inline — is one sentence here; see the walkthrough for the picture.

Unlike a competitor we compared earlier that had no diff feature at all, Opik does have a real version comparison — we edited the prompt to create v2 and used its "Diff" button:

Show screenshot: version diff panel on Opik

Opik's Compare v1 to v2 panel, showing the old system message in red strikethrough on the left and the new message in green on the right, side by side

It also has an environment-labelling control ("Deploy to") that tags a specific version as production, staging, or development — functionally close to Acrux Core's aliases, just without the runtime "fetch by alias" SDK call:

Show screenshot: Deploy to / environment labels on Opik

Opik's Deploy to menu, with v2 now tagged production via a green badge next to the version number

FeatureOpikAcruxCore
Conditional templatingFlat {{variable}} only — verified hands-on, no {% if %}/{% for %}Real nunjucks {% if %}/{% for %}, rendered server-side
Version comparisonReal "Diff" view, whole-message red/green (not word-level)Standing Diff tab, unified word-level diff between any two versions
Live/staging labels"Deploy to" tags a version production/staging/developmentproduction / staging aliases your app fetches at runtime

Sending a live call

Opik's Prompt playground accepts OpenRouter directly as a named provider — paste a key, search any OpenRouter-routed model by name. Both playgrounds produced the identical VIP reply from the identical inputs.

Show screenshots: Playground run on both platforms

Opik's Prompt playground with the recreated prompt loaded, openai/gpt-4o-mini selected via OpenRouter, and Output A showing the real completion with 1.9s latency and 163 tokens AcruxCore Playground's Stored-prompt tab, showing the same completion plus a Gateway Telemetry panel with provider, cost, cache status, and latency

FeatureOpikAcruxCore
PlaygroundRuns against any OpenRouter-routed model, shows latency + tokens inline, no costRuns against a stored prompt reference, shows cost/cache/latency inline
Requires a real keyYesYes

Tracing & observability

Confirmed hands-on: running the prompt from Opik's Playground left the project's Logs tab at "No traces yet" — the Playground alone does not trace, the same finding as an earlier comparison. A real trace only appeared after calling the SDK-wrapped client, producing a two-level span tree: an outer chat_completion_create trace wrapping an inner LLM span with model, provider, tokens, and cost.

Show screenshots: trace detail on both platforms

Opik's trace detail: a two-node span tree (outer trace + inner LLM span), 2.6s latency, <$0.01 cost, 138 total tokens, full system/user/assistant messages shown AcruxCore's trace detail: one LLM span with model, provider, tokens, cost, and latency, linked back to the exact gateway request and prompt version

FeatureOpikAcruxCore
Trace shapeSpan tree (outer trace + inner LLM span)Single span per gateway call
How it's producedClient-side track_openai() wrapperAutomatic — a side effect of the gateway call
Playground produces a traceNo — confirmed, Logs stayed empty after a Playground runYes — every Playground run is traced

Where the platform sits — in the request path, or beside it

AcruxCore's gateway sits in the request path: every call is routed through it, so BYOK provider selection, caching, budgets, and virtual keys all apply before the provider is ever called, and the trace is a side effect of that same hop. Opik sits beside the request path too — like the other observability-first platforms we've compared, it ingests a trace after your own client made the call, so there's nothing to route, cache, or budget against on its side.

FeatureOpikAcruxCore
Where it sitsBeside the request path — call providers yourself, trace is reported afterIn the request path — every call routes through it
BYOK, caching, budgets, virtual keysNot applicable — no request path to apply them toBuilt in, applied before the provider call

How tools are handled — schema registry, or execution

Opik has no tool catalog concept at all. Its closest surface, "Agent playground," is not a schema-definition UI — it's a live-connection debugger: you add @opik.track(entrypoint=True) to a running agent's own code and run a connector command in your terminal, and Opik waits for that process to connect.

Show screenshots: Agent playground on Opik, tool analytics on AcruxCore

Opik's Agent playground showing Disconnected status and setup instructions to add @opik.track(entrypoint=True) to a running agent and run a connection command in the terminal AcruxCore's Tool analytics page — call volume, error rate, and P50/P95 latency per tool, aggregated from traced executions

With nothing connected, the page just sits at "Disconnected" showing setup copy — this is weaker than even the placeholder "Create LLM Tool" schema dialog a prior comparison found on another platform, since that at least produced a stored, reusable JSON Schema object from the UI with zero code. AcruxCore's Tools page — a dozen real, versioned tools — is one sentence here; see the walkthrough for the screenshot.

FeatureOpikAcruxCore
Tool catalogNone — no schema object, no list view, no per-tool pagePersistent, versioned catalog with its own page
Agent visibilityRequires a live process connected via code + terminal commandReal, gateway-executed calls, traced automatically
Tool analyticsNot availableCalls, error rate, and latency per tool

SDK & developer experience

Opik wraps a client you already own; the trace only appears once that wrapped client makes a call. AcruxCore's SDK has dedicated surfaces — hub.prompts.render() then hub.gateway.chat() — and the trace is automatic.

op_trace_run.py
client = track_openai(
OpenAI(api_key=OPENROUTER_KEY, base_url="https://openrouter.ai/api/v1"),
project_name="Default Project",
)
response = client.chat.completions.create(
model="openai/gpt-4o-mini", temperature=0, max_tokens=256,
messages=[{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": USER_MESSAGE}],
)
acx_sdk_run.py
rendered = await hub.prompts.render("vip-support-triage", "production", VARIABLES)
result = await hub.gateway.chat(
rendered.model, rendered.messages,
temperature=0, max_tokens=256,
prompt_version_id=rendered.version_id,
)

Both produced a real trace within seconds of the call returning:

Show screenshot: SDK-produced trace on Opik

Opik's trace for the script-generated call: 138 total tokens, <$0.01 cost, 2.6s latency, model and provider metadata visible on the span

Full scripts: op_trace_run.py and acx_sdk_run.py.

AcruxCore's SDK-produced trace is one sentence here; see the walkthrough for the screenshot.

FeatureOpikAcruxCore
SDK modelWrap your own client (track_openai(OpenAI(...)))Dedicated hub.prompts / hub.gateway surface
Getting a traceAutomatic once the wrapped client is calledAutomatic side effect of hub.gateway.chat()

Latency overhead — measured

We timed the identical call three ways, interleaved in rotating order over 100 rounds so a network blip hits all three equally: a raw direct call to the provider (baseline), the same call wrapped in Opik's track_openai() client, and the same call through AcruxCore's gateway. Every leg ends at gpt-4o-mini on api.openai.com with the same key and body, and the script refuses to start unless the gateway model resolves to a native OpenAI credential — so all three provably share one upstream. This measures two different kinds of overhead — Opik's is client-side instrumentation cost, AcruxCore's is an extra network hop that buys routing and caching — not a rigged head-to-head.

One run is not a result: the median gap moves enough between runs that a single number would mislead. So it ran three times.

RunDirect-call medianOpik gapAcruxCore gap
1617 ms+22 ms, CI [+7, +47]+22 ms, CI [+10, +42]
2625 ms+2 ms, CI [−13, +18]+9 ms, CI [−6, +27]
3612 ms+4 ms, CI [−15, +26]+31 ms, CI [+5, +45]

Opik's overhead lands between +2 ms and +22 ms, AcruxCore's between +9 ms and +31 ms. Opik's was never the higher of the two, though the two were identical in the first run. In two of the three runs both confidence intervals cross zero, so neither path is reliably distinguishable from calling the provider directly at this sample size.

Full script: latency_bench.py.

For a broader run — six platforms in one interleaved benchmark, the stored-prompt fetch timed alongside the completion, and four independent runs to check how stable the numbers are — see full-cycle latency across six LLM-ops platforms.

Friction hit during this run

Real friction hit while doing this comparison, not a symmetric wish list.

Opik

  • 👍 No login wall at all on self-host — straight into a working project.
  • 👍 OpenRouter is a first-class named provider in the Playground, no custom-base-URL workaround needed.
  • 👍 "Add to dataset" works directly from any trace, with inline "create new dataset" in the same dialog.
  • 👎 The Prompt playground doesn't produce a trace — only a wrapped SDK call does.
  • 👎 Running an experiment from a dataset explicitly defers to the SDK; the UI-only path is the Playground, not a real batch experiment runner.
  • 👎 The Agent playground requires editing your own agent's code and running a terminal connector command just to see it — no schema-only path at all.

AcruxCore

  • 👍 Nothing to instrument — hub.gateway.chat() (or the Playground) writes the trace as a side effect, no wrapper client.
  • 👍 Nunjucks conditionals and loops are real template logic, not something you flatten by hand first.
  • 👎 A model with no registered per-1M rate shows a blank cost instead of $0 or an estimate, until you register one.

Time-to-first-trace: AcruxCore gets there on the first call with zero tracing-specific code. Opik gets there too, but only through the SDK path, after wrapping a client.

What Opik does that AcruxCore doesn't

Sourced from Opik's own dashboard and docs, not from this post's earlier aspects — those carry the same bias any of our own feature list would.

Guardrails — a Topic guardrail and a PII guardrail, configurable per project. Opik's "Set a guardrail" panel lets you enable a topic-restriction check (with a sensitivity slider and a comma-separated restricted-topics list) and a PII check that flags specific categories — credit card number, phone number, email, and more — each with its own sensitivity threshold, plus a ready-to-run Python snippet using opik.guardrails. AcruxCore has no equivalent: nothing inspects a call's input or output for restricted topics or personal data before or after it reaches the model.

Show screenshot: guardrails panel on Opik

Opik's "Set a guardrail" panel: Topic guardrail and PII guardrail toggles with sensitivity sliders, a restricted personal data checklist (credit card number, phone number checked), and a Python code sample using opik.guardrails

Test suites — a dedicated pre-deployment regression object. Distinct from Experiments: import test cases from a CSV or JSON file, or define them in the SDK, each with an expected output and a scoring method, framed by Opik itself as regression testing rather than dataset-driven experimentation.

Show screenshot: Test suites on Opik

Opik's empty Test suites page, offering Upload a file (CSV/JSON) or Use SDK as the two ways to define test cases with expected outputs and scoring

AcruxCore has no equivalent to guardrails or a separate pre-deployment test-suite object. It does have its own rule-based online evaluation — a judge (built-in or your own prompt) scoring every matching live trace as it lands, not just a dataset run on demand.

Is AcruxCore an Opik alternative?

For the day-to-day loop of running a prompt in production, yes. For pre-deployment testing, not yet.

Opik has no tool catalog at all, its experiments default to the SDK rather than the UI, and its Playground produces no trace — only a wrapped SDK call does, which makes for a genuinely confusing first hour if you are evaluating it by clicking around.

Two things you would lose are real, and we will not talk around them: Opik's Topic and PII guardrails, configurable per project, and its Test suites — a dedicated pre-deployment regression object that nothing else in this series has an equivalent of. If either is the reason you run Opik, we are not a replacement for it.

Verdict

OpikAcruxCore
Strongest atGuardrails and PII detection, dedicated test suites, self-host with zero setup friction, real diff/deploy on promptsA request-path gateway with routing, caching, and budgets on every call; tools that actually execute and get measured; datasets built from real feedback; rule-based online evaluation with a real judge model and custom judge prompts
Weakest atNo tool catalog at all; experiments default to the SDK, not the UI; Playground doesn't produce a traceNo guardrails, no dedicated test-suite object
Pick it ifYou want guardrails and regression test suites layered onto a client you already ownYou want the provider call itself — gateway, tools, feedback-driven datasets, and online scoring rules — traced for free, with nothing bolted on after the fact

Opik's guardrails and test suites (What Opik does that AcruxCore doesn't above) are real, and neither is something AcruxCore has an answer for today. But on the loop that runs a production LLM app day to day, this comparison landed on AcruxCore's side: Opik has no tool catalog at all (How tools are handled above), and its Playground doesn't produce a trace, only a wrapped SDK call does (Tracing & observability above). AcruxCore's gateway, tool catalog, and feedback-driven datasets stay in one integrated flow. See the full picture, including license, pricing, and team structure, on the compare page.

Want to run this yourself? The Quickstart gets you from sign-up to a traced, gateway-routed call in about ten minutes.