part = 3 / 5

How everyone else models it

Every AI observability product answers the same three questions — what is the unit of record, is the request a real object, and who owns conversation identity — and the answers sort the whole field into two philosophies. Phoenix sits firmly in one of them.

Two philosophies

Telemetry-first products (Phoenix, Datadog LLM Observability, anything OTel-native) start from the wire: flat, immutable spans, emitted by anyone, assembled into structure at read time. The model is whatever survives transport. Application-first products (LangSmith, Langfuse, Braintrust, W&B Weave) start from the developer's program: this function ran with these inputs and returned these outputs. Their SDKs own the write path, so their objects can be richer — mutable while running, nested payloads intact, request and conversation as real records with fields.

Neither side is confused; they optimized for different first questions. Telemetry-first optimizes "will I be able to ingest whatever exists, from anywhere, forever?" Application-first optimizes "will the developer's second-favorite debugging question — what did this request take in and put out? — be answerable by a primary-key lookup?" Everything below is downstream of that fork.

Rosetta stone

The interesting details, per product

LangSmith: the run tree

LangSmith's primitive is the Run: a typed node (llm, chain, tool, retriever…) with first-class inputs and outputs as structured JSON, an error field, and timestamps. A trace is simply the tree under a root run — which means the trace has inputs, outputs, and a status by construction, because the root run is a real record, created at start and patched at end. That create-then-patch protocol is the load-bearing difference from OTel: LangSmith sees runs the moment they begin. Conversations ("threads") are, amusingly, a metadata convention — a session_id/thread_id key on the root run — so their session story is roughly as duct-taped as ours, one level up.

Langfuse: the trace as a real object

Langfuse is the cleanest expression of application-first modeling. The trace is a first-class record with its own input, output, metadata, tags, user_id, and session_id — settable and updatable from application code at any point during execution. Observations (spans, generations, events) hang off it. Sessions are first-class and group traces. Scores attach to traces, observations, or sessions symmetrically — the annotation model Part 4 argues for, shipped. Langfuse also ingests OTLP by mapping it into this model, which is an existence proof that the wire format and the mental model can differ.

Braintrust: spans, but mutable

Braintrust looks OTel-ish — everything is a span, the root span stands in for the trace — but spans are mergeable: log the same span id twice and the fields merge, so you can open a span, stream into it, and close it later, even from a different process. It's a quiet rejection of OTel's one core constraint (immutability) while keeping its shape. The product's center of gravity is evals — datasets, experiments, scorers — with production tracing as the feeder.

W&B Weave: the program is the model

Weave traces calls — decorated function invocations with captured inputs and outputs, linked to versioned code objects ("ops"). It's the most literal "your program, replayed" model, excellent for the single-process notebook-to-app workflow, and the least concerned with distributed transport of anything here.

Datadog LLM Observability: our philosophy, their scale

Datadog models LLM work as typed spans (workflow, agent, llm, tool) with session_id tagging, riding the existing APM pipeline. Telemetry-first, like us. Notable mostly as evidence that the big-infrastructure players landed on the same side of the fork, for the same reasons: they don't control the write path either.

So who has the cleaner mental model?

For the core debugging loop — find the bad request, read its input and output, look inside, mark it — yes, the application-first products are cleaner, and it isn't close. In Langfuse the object the user is thinking about (this request, this conversation) is the object in the database. In Phoenix it's a projection that usually resolves correctly. Users don't see our schema, but they feel its edges: the trace table that can't be tagged, the session that can't be annotated from the UI, the turn whose "annotate" button aims one level down (Part 1).

But the cleanliness is purchased with the write path. LangSmith's live run tree requires create-then-patch through their SDK. Langfuse's updatable trace requires their client and their two-phase writes. Braintrust's merges require their ingestion semantics. Each of those products, when it decided to also accept OTLP, had to build the same read-time reconstruction machinery we run — they just treat it as a compatibility layer instead of the core. The moment you accept arbitrary OTel input (and at this point they all felt compelled to), you inherit the orphan roots, the late spans, the convention-based sessions. The difference is what happens next: they map the mess into a rich model; we present the mess with good typography.

Can we make the transitions?

Mostly yes, because the fix is at the read/ingest boundary, not the wire. Nothing about OTel compliance forbids Phoenix from materializing the objects users think in:

part 3 in one sentence The competitors with cleaner mental models got them by modeling the application rather than the telemetry; Phoenix can adopt nearly all of that model at read time — trace as summary object, session as annotatable object, one root policy — without giving up the OTel write path that is its actual moat.

Competitor descriptions reflect their public data models as of mid-2026; all of these products move quickly, and the point is the philosophy fork, not any vendor's current feature list.