@arizeai/phoenix-otel

中文文档
2.3.0发布于 2026/10/22Apache-2.0TypeScriptESM + CJS构建来源已验证近 30 天下载 29.4万

Phoenix OpenTelemetry tracing SDK for Node.js — register tracing, manual span helpers, and context attributes for LLM observability

原始使用文档
文档目录28 节
  1. Features
  2. Installation
  3. Quick Start
  4. Basic Usage
  5. Production Setup
  6. Configuration
  7. Environment Variables
  8. Configuration Options
  9. Custom Span Processors
  10. Usage Examples
  11. With the Vercel AI SDK (v7+)
  12. With Auto-Instrumentation
  13. With OpenAI (ESM)
  14. Tracing Helpers
  15. Custom Input And Output Processing
  16. Context Attributes
  17. Decorators
  18. Attribute Helper APIs
  19. Trace Config And Redaction
  20. Raw OpenTelemetry Spans
  21. Utility Helpers
  22. Development vs Production
  23. Custom Headers
  24. Non-Global Provider
  25. Docs And Source Code In node_modules
  26. Coding Agent Skill
  27. Documentation
  28. Community

Arize Phoenix logo
@arizeai/phoenix-otel

NPM Version Documentation

A lightweight wrapper around OpenTelemetry for Node.js applications that simplifies sending traces to Arize Phoenix. @arizeai/phoenix-otel handles provider registration and OTLP export, then re-exports the full @arizeai/openinference-core helper surface from the same package path so you can register tracing and author manual spans from one import.

Note: This package is under active development and APIs may change.

Features

  • Simple Setup - One-line configuration with sensible defaults
  • Environment Variables - Automatic configuration from environment variables
  • Batch Processing - Built-in batch span processing for production use
  • OpenInference Helpers Included - Re-exports withSpan, the span-kind wrappers (traceChain, traceAgent, traceTool, traceLLM, traceRetriever, traceReranker, traceEmbedding, traceGuardrail, traceEvaluator, tracePrompt), observe, context setters, attribute builders, OITracer, and utility helpers
  • Provider-Swap Safe Wrappers - The re-exported OpenInference helpers resolve the default tracer when the wrapped function executes, so module-scoped wrappers continue following global provider changes
  • Agent-Friendly Local Docs - Ships curated docs and source in node_modules/@arizeai/phoenix-otel/

Installation

npm install @arizeai/phoenix-otel

Requires Node.js 18 or newer. Both ESM and CommonJS entry points are provided.

Quick Start

Basic Usage

The simplest way to get started is to use register() together with the built-in tracing helpers:

import { register, traceChain } from "@arizeai/phoenix-otel";

const provider = register({
  projectName: "my-app",
});

const answerQuestion = traceChain(
  async (question: string) => `Handled: ${question}`,
  { name: "answer-question" }
);

await answerQuestion("What is Phoenix?");
await provider.shutdown();

register() sets up the Phoenix exporter. The tracing helpers come from @arizeai/openinference-core, re-exported through @arizeai/phoenix-otel.

Production Setup

For production use with a remote Phoenix instance:

import { register } from "@arizeai/phoenix-otel";

register({
  projectName: "my-app",
  url: "https://your-phoenix-instance.com",
  apiKey: process.env.PHOENIX_API_KEY,
});

Configuration

Environment Variables

The register function automatically reads from environment variables:

# For local Phoenix server (default)
export PHOENIX_COLLECTOR_ENDPOINT="http://localhost:6006"

# For a remote Phoenix instance
export PHOENIX_COLLECTOR_ENDPOINT="https://your-phoenix-instance.com"
export PHOENIX_API_KEY="your-api-key"

When a setting is not provided by argument or environment variable, register also looks for a .env.phoenix file in the current working directory — walking up toward the filesystem root and stopping at the first match — and reads PHOENIX_-prefixed keys from it (dotenv format). Environment variables always take precedence over the file; set PHOENIX_DISCOVER_CONFIG=false to disable discovery entirely.

PHOENIX_API_KEY and PHOENIX_CLIENT_HEADERS are resolved as one credential group. Explicit Authorization headers are preserved case-insensitively. If an explicit or process credential is paired with PHOENIX_COLLECTOR_ENDPOINT from the file, the exporter warns once and continues without logging credential values.

Configuration Options

The register function accepts the following parameters:

ParameterTypeDefaultDescription
projectNamestring"default"The project name for organizing traces in Phoenix
urlstring"http://localhost:6006"The URL to your Phoenix instance
apiKeystringundefinedAPI key for Phoenix authentication
headersRecord<string, string>{}Custom headers for OTLP requests
batchbooleantrueUse batch span processing (recommended for production)
instrumentationsInstrumentation[]undefinedArray of OpenTelemetry instrumentations to register
globalbooleantrueRegister the tracer provider globally
diagLogLevelDiagLogLevelundefinedDiagnostic logging level for debugging

Custom Span Processors

register() also accepts spanProcessors, which replaces the default Phoenix exporter setup. For these setups the package root re-exports OTLPTraceExporter, and the ESM-only @arizeai/phoenix-otel/vercel subpath re-exports @arizeai/openinference-vercel (OpenInferenceSimpleSpanProcessor, OpenInferenceBatchSpanProcessor, isOpenInferenceSpan, and types) — no need to install the underlying packages:

import {
  ensureCollectorEndpoint,
  OTLPTraceExporter,
  register,
} from "@arizeai/phoenix-otel";
import {
  isOpenInferenceSpan,
  OpenInferenceSimpleSpanProcessor,
} from "@arizeai/phoenix-otel/vercel";

register({
  projectName: "my-agent",
  spanProcessors: [
    new OpenInferenceSimpleSpanProcessor({
      exporter: new OTLPTraceExporter({
        url: ensureCollectorEndpoint("http://localhost:6006"),
      }),
      // Export only AI spans, re-rooting any left orphaned by the filter
      spanFilter: isOpenInferenceSpan,
      reparentOrphanedSpans: true,
    }),
  ],
});

Usage Examples

With the Vercel AI SDK (v7+)

AI SDK v7 telemetry registration is process-global, so applications configure it explicitly. Install ai and @ai-sdk/otel, then register the integration alongside the Phoenix provider. Request-header capture is disabled below because headers can contain authorization tokens and cookies.

// instrumentation.ts
import { OpenTelemetry } from "@ai-sdk/otel";
import { registerTelemetry } from "ai";
import { register } from "@arizeai/phoenix-otel";

const provider = register({
  projectName: "my-ai-app",
});

registerTelemetry(
  new OpenTelemetry({
    tracer: provider.getTracer("@arizeai/phoenix-otel/ai-sdk"),
    headers: false,
  })
);
// main.ts
import "./instrumentation.ts";
import { openai } from "@ai-sdk/openai";
import { generateText } from "ai";

const result = await generateText({
  model: openai("gpt-4o-mini"),
  prompt: "Write a short story about a cat.",
});

Note: AI SDK v6 and older emit a different span shape that is not supported by the bundled span processors. Use @arizeai/phoenix-otel 1.x (with @arizeai/openinference-vercel 2.x) for AI SDK v6.

With Auto-Instrumentation

Automatically instrument common libraries (works best with CommonJS):

import { register } from "@arizeai/phoenix-otel";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";

register({
  projectName: "my-express-app",
  instrumentations: [new HttpInstrumentation(), new ExpressInstrumentation()],
});

Note: Auto-instrumentation via the instrumentations parameter works best with CommonJS projects. ESM projects require manual instrumentation.

With OpenAI (ESM)

For ESM projects, manually instrument libraries:

// instrumentation.ts
import { register, registerInstrumentations } from "@arizeai/phoenix-otel";
import OpenAI from "openai";
import { OpenAIInstrumentation } from "@arizeai/openinference-instrumentation-openai";

register({
  projectName: "openai-app",
});

// Manual instrumentation for ESM
const instrumentation = new OpenAIInstrumentation();
instrumentation.manuallyInstrument(OpenAI);

registerInstrumentations({
  instrumentations: [instrumentation],
});
// main.ts
import "./instrumentation.ts";
import OpenAI from "openai";

const openai = new OpenAI();

const response = await openai.chat.completions.create({
  model: "gpt-4o",
  messages: [{ role: "user", content: "Hello!" }],
});

Tracing Helpers

The package includes withSpan plus span-kind shorthands — traceChain, traceAgent, and traceTool — for wrapping functions with OpenInference spans. Each helper automatically records inputs, outputs, errors, and span kind.

import {
  register,
  traceAgent,
  traceChain,
  traceTool,
  withSpan,
} from "@arizeai/phoenix-otel";

register({ projectName: "my-app" });

// traceTool — for tool calls and API lookups
const searchDocs = traceTool(
  async (query: string) => {
    const response = await fetch(`/api/search?q=${query}`);
    return response.json();
  },
  { name: "search-docs" }
);

// traceChain — for pipeline steps and orchestration
const summarize = traceChain(
  async (text: string) => `Summary of ${text.length} chars`,
  { name: "summarize" }
);

// traceAgent — for autonomous agent entry points
const supportAgent = traceAgent(
  async (question: string) => {
    const docs = await searchDocs(question);
    return summarize(JSON.stringify(docs));
  },
  { name: "support-agent" }
);

// withSpan — general purpose, specify kind explicitly
const retrieveDocs = withSpan(
  async (query: string) =>
    fetch(`/api/search?q=${query}`).then((r) => r.json()),
  { name: "retrieve-docs", kind: "RETRIEVER" }
);

These helpers resolve the default tracer when the wrapped function runs, so traced functions defined at module scope keep following global provider changes.

Additional Span-Kind Wrappers

The full set of OpenInference span kinds is covered by matching wrappers, each a shorthand for withSpan(fn, { ...options, kind }). They accept the same options as traceChain/traceAgent/traceTool (everything except kind, which is pre-set). These wrappers are marked @experimental in @arizeai/openinference-core.

WrapperSpan kindUse it for
traceLLMLLMLanguage-model invocations — chat/text completions and other inference calls
traceRetrieverRETRIEVERFetching documents from a knowledge base, vector store, or search index (RAG)
traceRerankerRERANKERReordering or scoring candidate documents by relevance
traceEmbeddingEMBEDDINGConverting text or data into vector representations
traceGuardrailGUARDRAILSafety, validation, or policy checks (moderation, PII, compliance)
traceEvaluatorEVALUATORScoring output quality — relevance, correctness, or LLM-as-a-judge
tracePromptPROMPTConstructing, rendering, or templating a prompt before a model call
import {
  traceEmbedding,
  traceEvaluator,
  traceGuardrail,
  traceLLM,
  tracePrompt,
  traceReranker,
  traceRetriever,
} from "@arizeai/phoenix-otel";

const retrieveDocuments = traceRetriever(
  async (query: string) => vectorStore.similaritySearch(query, 5),
  { name: "vector-search" }
);

const evaluateAnswer = traceEvaluator(
  async (question: string, answer: string) => judge.score({ question, answer }),
  { name: "answer-evaluation" }
);

Custom Input And Output Processing

Use processInput and processOutput when you want richer OpenInference attributes than the default JSON-serialized input.value and output.value.

import {
  OpenInferenceSpanKind,
  getInputAttributes,
  getRetrieverAttributes,
  withSpan,
} from "@arizeai/phoenix-otel";

const retrieveDocs = withSpan(
  async (query: string) => [`Doc A for ${query}`, `Doc B for ${query}`],
  {
    name: "retrieve-docs",
    kind: OpenInferenceSpanKind.RETRIEVER,
    processInput: (query) => getInputAttributes(query),
    processOutput: (documents) =>
      getRetrieverAttributes({
        documents: documents.map((content, index) => ({
          id: `doc-${index}`,
          content,
        })),
      }),
  }
);

Context Attributes

Propagate session IDs, user IDs, metadata, and tags to all child spans using context setters:

import {
  context,
  register,
  setMetadata,
  setSession,
  setUser,
  traceChain,
} from "@arizeai/phoenix-otel";

register({ projectName: "my-app" });

const handleQuery = traceChain(async (query: string) => `Handled: ${query}`, {
  name: "handle-query",
});

// All spans inside context.with() inherit session, user, and metadata
await context.with(
  setMetadata(
    setUser(setSession(context.active(), { sessionId: "sess-123" }), {
      userId: "user-456",
    }),
    { environment: "production" }
  ),
  () => handleQuery("Hello")
);

Available setters: setSession, setUser, setMetadata, setTags, setAttributes, setPromptTemplate.

If you create spans manually with a plain OpenTelemetry tracer, copy the propagated context attributes onto the span explicitly:

import {
  context,
  getAttributesFromContext,
  register,
  trace,
} from "@arizeai/phoenix-otel";

register({ projectName: "my-app" });

const tracer = trace.getTracer("manual-tracer");
const span = tracer.startSpan("manual-span");
span.setAttributes(getAttributesFromContext(context.active()));
span.end();

Decorators

observe wraps class methods with tracing while preserving method this context. Use TypeScript 5+ standard decorators.

import { OpenInferenceSpanKind, observe } from "@arizeai/phoenix-otel";

class ChatService {
  @observe({ kind: OpenInferenceSpanKind.CHAIN })
  async runWorkflow(message: string) {
    return `processed: ${message}`;
  }

  @observe({ name: "llm-call", kind: OpenInferenceSpanKind.LLM })
  async callModel(prompt: string) {
    return `model output for: ${prompt}`;
  }
}

Attribute Helper APIs

Use the attribute helpers when you want to build OpenInference-compatible span attributes directly:

import { getLLMAttributes, trace } from "@arizeai/phoenix-otel";

const tracer = trace.getTracer("llm-service");

tracer.startActiveSpan("llm-inference", (span) => {
  span.setAttributes(
    getLLMAttributes({
      provider: "openai",
      modelName: "gpt-4o-mini",
      inputMessages: [{ role: "user", content: "What is Phoenix?" }],
      outputMessages: [{ role: "assistant", content: "Phoenix is..." }],
      tokenCount: { prompt: 12, completion: 44, total: 56 },
      invocationParameters: { temperature: 0.2 },
    })
  );
  span.end();
});

Available helpers include:

  • getLLMAttributes
  • getEmbeddingAttributes
  • getRetrieverAttributes
  • getToolAttributes
  • getMetadataAttributes
  • getInputAttributes / getOutputAttributes
  • defaultProcessInput / defaultProcessOutput

Trace Config And Redaction

OITracer wraps an OpenTelemetry tracer and can redact or drop sensitive OpenInference attributes before spans are written:

import {
  OITracer,
  OpenInferenceSpanKind,
  trace,
  withSpan,
} from "@arizeai/phoenix-otel";

const tracer = new OITracer({
  tracer: trace.getTracer("my-service"),
  traceConfig: {
    hideInputs: true,
    hideOutputText: true,
    hideEmbeddingVectors: true,
    hideLLMTools: true,
    base64ImageMaxLength: 8_000,
  },
});

const safeLLMCall = withSpan(
  async (prompt: string) => `model response for ${prompt}`,
  {
    tracer,
    kind: OpenInferenceSpanKind.LLM,
    name: "safe-llm-call",
  }
);

Supported environment variables include:

  • OPENINFERENCE_HIDE_INPUTS
  • OPENINFERENCE_HIDE_OUTPUTS
  • OPENINFERENCE_HIDE_INPUT_MESSAGES
  • OPENINFERENCE_HIDE_OUTPUT_MESSAGES
  • OPENINFERENCE_HIDE_INPUT_IMAGES
  • OPENINFERENCE_HIDE_INPUT_TEXT
  • OPENINFERENCE_HIDE_OUTPUT_TEXT
  • OPENINFERENCE_HIDE_EMBEDDING_VECTORS
  • OPENINFERENCE_BASE64_IMAGE_MAX_LENGTH
  • OPENINFERENCE_HIDE_PROMPTS
  • OPENINFERENCE_HIDE_LLM_TOOLS

Raw OpenTelemetry Spans

For full control over attributes and timing, use the OpenTelemetry API directly:

import { register, trace, SpanStatusCode } from "@arizeai/phoenix-otel";

register({ projectName: "my-app" });

const tracer = trace.getTracer("my-service");

async function processOrder(orderId: string) {
  return tracer.startActiveSpan("process-order", async (span) => {
    try {
      span.setAttribute("order.id", orderId);
      const result = await fetchOrderDetails(orderId);
      span.setAttribute("order.status", result.status);
      return result;
    } catch (error) {
      span.recordException(error as Error);
      span.setStatus({ code: SpanStatusCode.ERROR });
      throw error;
    } finally {
      span.end();
    }
  });
}

Utility Helpers

The package also re-exports small utilities from @arizeai/openinference-core:

  • withSafety({ fn, onError? }) wraps a function and returns null on error
  • safelyJSONStringify(value) and safelyJSONParse(value) guard JSON operations

Development vs Production

Development (with debug logging):

import { DiagLogLevel, register } from "@arizeai/phoenix-otel";

register({
  projectName: "my-app-dev",
  url: "http://localhost:6006",
  batch: false, // Immediate span delivery for faster feedback
  diagLogLevel: DiagLogLevel.DEBUG,
});

Production (optimized for performance):

import { register } from "@arizeai/phoenix-otel";

register({
  projectName: "my-app-prod",
  url: "https://your-phoenix-instance.com",
  apiKey: process.env.PHOENIX_API_KEY,
  batch: true, // Batch processing for better performance
});

Custom Headers

Add custom headers to OTLP requests:

import { register } from "@arizeai/phoenix-otel";

register({
  projectName: "my-app",
  url: "https://your-phoenix-instance.com",
  headers: {
    "X-Custom-Header": "custom-value",
    "X-Environment": process.env.NODE_ENV || "development",
  },
});

Non-Global Provider

Use the provider explicitly without registering globally:

import { register } from "@arizeai/phoenix-otel";

const provider = register({
  projectName: "my-app",
  global: false,
});

// Use the provider explicitly
const tracer = provider.getTracer("my-tracer");

Docs And Source Code In node_modules

After install, a coding agent can inspect the exact versioned docs and implementation that shipped with the package:

node_modules/@arizeai/phoenix-otel/docs/
node_modules/@arizeai/phoenix-otel/src/

Because @arizeai/phoenix-otel re-exports @arizeai/openinference-core, the dependency docs are also useful local references:

node_modules/@arizeai/openinference-core/docs/
node_modules/@arizeai/openinference-core/src/

Coding Agent Skill

The Phoenix repo includes a phoenix-tracing skill that teaches coding agents (Claude Code, Cursor, etc.) how to instrument LLM applications with OpenInference tracing. Install it with:

npx skills add Arize-ai/phoenix --skill phoenix-tracing

Tracing helpers:

import {
  observe,
  traceAgent,
  traceChain,
  traceEmbedding,
  traceEvaluator,
  traceGuardrail,
  traceLLM,
  tracePrompt,
  traceReranker,
  traceRetriever,
  traceTool,
  withSpan,
} from "@arizeai/phoenix-otel";

Context attribute setters:

import {
  setAttributes,
  setMetadata,
  setPromptTemplate,
  setSession,
  setTags,
  setUser,
} from "@arizeai/phoenix-otel";

Attribute builders for rich span data:

import {
  defaultProcessInput,
  defaultProcessOutput,
  getEmbeddingAttributes,
  getLLMAttributes,
  getRetrieverAttributes,
  getToolAttributes,
} from "@arizeai/phoenix-otel";

Redaction and utility helpers:

import {
  OITracer,
  safelyJSONParse,
  safelyJSONStringify,
  withSafety,
} from "@arizeai/phoenix-otel";

The tracing helper wrappers resolve the default tracer when they run. That keeps spans attached to the current provider in experiments and in any workflow that swaps providers during process lifetime.

Documentation

Community

Join our community to connect with thousands of AI builders:

版本与发布记录

@arizeai/phoenix-otel 共发布 21 个版本,首次发布于 2025/10/24;过去 12 个月发布了 16 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.3.0latest2026/10/2217 天前
2.2.02026/08/082 个月前
2.1.02026/07/223 个月前
2.0.02026/07/223 个月前
1.2.02026/07/153 个月前
1.1.12026/07/113 个月前

关于 @arizeai/phoenix-otel 的常见问题

@arizeai/phoenix-otel 是什么?

Phoenix OpenTelemetry tracing SDK for Node.js — register tracing, manual span helpers, and context attributes for LLM observability

如何安装 @arizeai/phoenix-otel?

在项目目录运行 npm install @arizeai/phoenix-otel,或使用 pnpm add / yarn add / bun add。

@arizeai/phoenix-otel 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@arizeai/phoenix-otel 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@arizeai/phoenix-otel 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@arizeai/phoenix-otel 可以商用吗?

@arizeai/phoenix-otel 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@arizeai/phoenix-otel 的下载量有多少?

根据 npm 官方下载统计,@arizeai/phoenix-otel 在 2026/10/07 – 2026/11/05 这 30 天内被下载 294,247 次,日均约 9,808 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@arizeai/phoenix-otel 还在维护吗?

最新版本 2.3.0 发布于 2026/10/22(17 天前);至今共发布 21 个版本,其中过去 12 个月发布了 16 个;首次发布于 2025/10/24。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。