# Opik

> Reference for the Opik SDK — tracing, span types, framework integrations, threads, and the prompt library (Python, TypeScript, REST). Use for "what span types exist", "how do I flush", "track_openai", "add OpikTracer", "version a prompt". To instrument a repo end to end, use the `opik-instrument` skill.

- Skill: `comet-ml/opik` (Agent Skill, multi-file: 11 files)
- Install (CLI): `npx skillmds@latest add comet-ml/opik`
- Raw SKILL.md: https://api.skillmd.com/api/skills/comet-ml/opik/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: comet-ml (https://skillmd.com/u/comet-ml)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/comet-ml/opik

---


# Opik SDK Reference

Opik is an open-source LLM observability platform. This skill is a **reference**
for the SDK. To instrument a codebase step by step (detect frameworks, add
config, emit and verify a trace), use the task-shaped `opik-instrument` skill.

## Core concepts

A trace is one execution path (one request → one response). Spans are the
operations inside it and form a hierarchy.

### Span types — the ONLY valid values

| Type | Use for |
|------|---------|
| `general` | orchestration, agent entry points |
| `llm` | model calls |
| `tool` | tools, retrieval, API / DB calls |
| `guardrail` | safety / validation checks |

Do NOT use `retrieval` or any other value.

## Python — tracing

```python
import opik

@opik.track(name="agent", type="general")
def agent(query: str) -> str:
    return generate(retrieve(query))

@opik.track(type="tool")
def retrieve(query): ...

@opik.track(type="llm")
def generate(ctx): ...

opik.flush_tracker()   # required in scripts
```

## TypeScript — tracing

```typescript
import { Opik } from "opik";
const client = new Opik({ projectName: "my-project" });

const trace = client.trace({ name: "agent", input: { query } });
const span = trace.span({ name: "llm-call", type: "llm" });
span.end({ output });
trace.end({ output });
await client.flush();
```

## Framework integrations

Prefer an integration over manual `@opik.track` — integrations capture tokens,
model, and cost automatically. Patterns (full list in
`references/integrations.md`):

- **wrap-the-client** — `track_openai(OpenAI())`, `track_anthropic(...)`
- **global-enable** — `track_crewai(crew=crew)`
- **callback** — `dspy.configure(callbacks=[OpikCallback()])`
- **tracer** — `OpikTracer()` for LangChain / LangGraph / LlamaIndex
- **agent-specific** — `track_adk_agent_recursive(agent, OpikTracer())`

### LiteLLM inside `@opik.track` (common trap)

If code uses `litellm` **and** you add `@opik.track`, pass `current_span_data`
via metadata on every completion call — otherwise `OpikLogger` emits **orphaned**
top-level traces instead of nesting under your span.

```python
from opik.opik_context import get_current_span_data

@opik.track
def call_llm(messages):
    return litellm.completion(
        model="gpt-4o", messages=messages,
        metadata={"opik": {"current_span_data": get_current_span_data()}},
    )
```

## Threads (conversations)

Group turns with `thread_id` — one turn = one trace, shared `thread_id` = one
thread. Use for chat / multi-turn; skip for single-shot.

```python
@opik.track(entrypoint=True)
def handle(session_id: str, message: str) -> str:
    opik.update_current_trace(thread_id=session_id)
    return reply(message)
```

## Prompt library

Version prompts with `client.get_prompt` / `create_prompt` (chat variants:
`get_chat_prompt` / `create_chat_prompt`). Store model + temperature in the
prompt `metadata` so they version with the text. Call `get_prompt` **inside** a
`@opik.track` function so the version links to the trace.

```python
@opik.track(entrypoint=True)
def run(question: str) -> str:
    p = client.get_prompt(name="system") or client.create_prompt(
        name="system",
        prompt="You help with {{product}}.",
        metadata={"model": "gpt-4o", "temperature": 0.7},
    )
    return llm(p.format(product="Opik"), model=p.metadata["model"])
```

## Searching traces

One filter grammar, OQL, serves both the hosted MCP's `list` tool and the
SDK's `search_traces` / `search_spans` / `search_threads`:

```
<field>[.<key>] <op> <value> [AND ...]
ops: = != > >= < <= contains not_contains starts_with ends_with is_empty is_not_empty in not_in
```

Strings in double quotes, numbers bare, `duration` in **milliseconds**, dates as
ISO-8601 instants with a timezone (`"2026-09-08T10:00:00Z"`). Scores and
dictionaries take a key: `feedback_scores.accuracy < 0.5`,
`metadata.environment = "prod"`. `AND` is the only connector.

```
error_info is_not_empty AND duration > 5000
type = "llm" AND usage.total_tokens > 10000            # spans
feedback_scores.hallucination > 0.5 AND start_time >= "2026-09-08T00:00:00Z"
```

With the MCP connected, prefer `list` — it also sorts (`sort="duration desc"`),
windows (`since="1h"`, `"7d"`), and searches free text (`search="order-42"`):

```
list(entity_type="trace", project_name="<project>", since="1h",
     filters="error_info is_not_empty", sort="duration desc")
```

Trace, span and thread lists add `source = "sdk"` unless you name `source`, so
evaluator, playground and experiment traces stay out of the way. A rejected
filter comes back with what fixes it; `schema("list.trace")` (or `list.span`,
`list.thread`, `list.experiment`) is the full field and operator reference.

Without the MCP, the same string goes to the SDK:

```python
client.search_traces(project_name="<project>", filter_string="error_info is_not_empty")
```

## Anti-patterns

| Anti-pattern | Fix |
|--------------|-----|
| span type `retrieval` / custom | use `tool` (or `general`) |
| `get_prompt` outside `@opik.track` | fetch inside — else no trace link |
| deprecated `opik.Prompt` / `opik.Config` | use `client.get_prompt` / config file |
| `litellm` without `current_span_data` | pass it — else orphaned traces |
| no flush in scripts | `opik.flush_tracker()` / `await client.flush()` |

## References

| Topic | File |
|-------|------|
| Python SDK (async, distributed, context) | `references/tracing-python.md` |
| TypeScript SDK | `references/tracing-typescript.md` |
| REST API | `references/tracing-rest-api.md` |
| All integrations | `references/integrations.md` |
| Core concepts (traces, spans, threads) | `references/observability.md` |
| Best practices (lifecycle, monitoring, anti-patterns) | `references/best-practices.md` |
| Agent architecture, reliability, security | `references/agent-patterns.md` |
| Production monitoring, alerts, guardrails | `references/production.md` |
| Evaluation datasets & test suites (reference) | `references/evaluation-datasets.md`, `references/evaluation-test-suites.md` |

To build and run an evaluation, use the `opik-evaluate` skill. For repo instrumentation and config, use the `opik-instrument` skill.

