@arizeai/openinference-vercel

中文文档
3.3.1发布于 2026/10/24Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 53.8万

OpenInference utilities for ingesting Vercel AI SDK spans

原始使用文档
文档目录8 节
  1. AI SDK Compatibility
  2. Installation
  3. Usage
  4. TypeScript Application
  5. Next.js Application
  6. Decision models
  7. Reparenting orphaned spans
  8. Propagating session and context attributes

OpenInference Vercel

npm version

This package provides utilities to transform Vercel AI SDK OpenTelemetry spans into OpenInference spans for platforms like Arize AX and Phoenix.

Note: This package targets AI SDK v7 telemetry. Use @arizeai/openinference-vercel v2.x for AI SDK v6.

AI SDK Compatibility

AI SDK versionSupport levelNotes
v7.xSupportedUses @ai-sdk/otel OpenTelemetry, which emits gen_ai.* spans by default. Optional supplemental ai.* attributes fill non-GenAI data gaps.
v6.x and olderUnsupportedUse @arizeai/openinference-vercel v2.x. AI SDK v6 used experimental_telemetry and emitted a different span shape.

AI SDK v7 and this package require Node.js 22 or newer and are ESM-only. Configure your application accordingly before upgrading.

Installation

npm install --save @arizeai/openinference-vercel

You will also need OpenTelemetry, ai, @ai-sdk/otel, and the AI SDK provider package you use. The examples below use @ai-sdk/openai.

npm i @arizeai/openinference-vercel ai@^7 @ai-sdk/otel@^1 @ai-sdk/openai@^4 @opentelemetry/api @opentelemetry/exporter-trace-otlp-proto @opentelemetry/resources @opentelemetry/sdk-trace-base @opentelemetry/sdk-trace-node @opentelemetry/semantic-conventions @arizeai/openinference-semantic-conventions

For Next.js applications deployed on Vercel, also install @vercel/otel:

npm i @vercel/otel

Usage

@arizeai/openinference-vercel provides span processors that convert AI SDK v7 telemetry into OpenInference attributes before spans are exported. To get started, add OpenTelemetry to your application and register AI SDK telemetry once at application startup.

For Next.js apps deployed on Vercel, registerOTel from @vercel/otel still registers the OpenTelemetry provider, resource attributes, exporters, and span processors. AI SDK v7's registerTelemetry(new OpenTelemetry(...)) does not replace that setup; it configures the AI SDK's telemetry integration.

To process Vercel AI SDK spans, add OpenInferenceSimpleSpanProcessor or OpenInferenceBatchSpanProcessor to your OpenTelemetry configuration.

[!NOTE] The OpenInferenceSpanProcessor does not handle the exporting of spans by itself, pass it an exporter as a parameter.

TypeScript Application

For a standalone TypeScript or Node.js application exporting to Phoenix, create an instrumentation module and import it before your AI SDK calls run.

// instrumentation.ts
import { SEMRESATTRS_PROJECT_NAME } from "@arizeai/openinference-semantic-conventions";
import {
  enrichSpanWithOpenInference,
  OpenInferenceBatchSpanProcessor,
} from "@arizeai/openinference-vercel";

import { OpenTelemetry } from "@ai-sdk/otel";
import { diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
import { Resource } from "@opentelemetry/resources";
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { registerTelemetry } from "ai";

// For troubleshooting, set the log level to DiagLogLevel.DEBUG.
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO);

const phoenixUrl = process.env["PHOENIX_COLLECTOR_ENDPOINT"] ?? "http://localhost:6006/v1/traces";
const phoenixApiKey = process.env["PHOENIX_API_KEY"];

export const tracerProvider = new NodeTracerProvider({
  resource: new Resource({
    [SEMRESATTRS_PROJECT_NAME]: process.env["PHOENIX_PROJECT_NAME"] ?? "my-typescript-app",
  }),
  spanProcessors: [
    new OpenInferenceBatchSpanProcessor({
      exporter: new OTLPTraceExporter({
        url: phoenixUrl,
        headers: phoenixApiKey
          ? {
              api_key: phoenixApiKey,
              Authorization: `Bearer ${phoenixApiKey}`,
            }
          : undefined,
      }),
    }),
  ],
});

tracerProvider.register();

registerTelemetry(
  new OpenTelemetry({
    enrichSpan: enrichSpanWithOpenInference,
    // Optional, but recommended for fuller OpenInference coverage.
    usage: true,
    providerMetadata: true,
    embedding: true,
    reranking: true,
    experimental_decision: true,
    runtimeContext: true,
    headers: true,
    toolChoice: true,
    schema: true,
  }),
);

Then import the instrumentation module before using the AI SDK.

import "./instrumentation";

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.",
  // Telemetry is enabled by default once OpenTelemetry is registered.
  // Use telemetry for per-call metadata or to opt out with isEnabled: false.
  telemetry: { functionId: "story-agent" },
});

Next.js Application

// instrumentation.ts
import { registerOTel } from "@vercel/otel";
import { registerTelemetry } from "ai";
import { OpenTelemetry } from "@ai-sdk/otel";
import {
  enrichSpanWithOpenInference,
  isOpenInferenceSpan,
  OpenInferenceSimpleSpanProcessor,
} from "@arizeai/openinference-vercel";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
import { SEMRESATTRS_PROJECT_NAME } from "@arizeai/openinference-semantic-conventions";

export function register() {
  const phoenixApiKey = process.env["PHOENIX_API_KEY"];

  registerTelemetry(
    new OpenTelemetry({
      enrichSpan: enrichSpanWithOpenInference,
      // Optional, but recommended for fuller OpenInference coverage.
      usage: true,
      providerMetadata: true,
      embedding: true,
      reranking: true,
      experimental_decision: true,
      runtimeContext: true,
      headers: true,
      toolChoice: true,
      schema: true,
    }),
  );

  registerOTel({
    serviceName: "phoenix-next-app",
    attributes: {
      // This is not required but it will ensure your traces get added to a specific project in Arize Phoenix
      [SEMRESATTRS_PROJECT_NAME]: "your-next-app",
    },
    spanProcessors: [
      new OpenInferenceSimpleSpanProcessor({
        exporter: new OTLPTraceExporter({
          headers: phoenixApiKey
            ? {
                api_key: phoenixApiKey,
                Authorization: `Bearer ${phoenixApiKey}`,
              }
            : undefined,
          url:
            process.env["PHOENIX_COLLECTOR_ENDPOINT"] ?? "https://app.phoenix.arize.com/v1/traces",
        }),
        spanFilter: (span) => {
          // Remove this filter if you want to export non-generative spans too.
          return isOpenInferenceSpan(span);
        },
      }),
    ],
  });
}

Once registerTelemetry(new OpenTelemetry()) is called, AI SDK v7 telemetry is enabled by default. Use telemetry only for metadata such as functionId or to opt out.

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

To disable telemetry for a single call, set telemetry: { isEnabled: false }.

For details on AI SDK v7 telemetry, see the AI SDK telemetry documentation.

Decision models

AI SDK experimental_decide calls require ai 7.0.128 or later and @ai-sdk/otel 1.0.128 or later, with experimental_decision: true set on OpenTelemetry to record the state, questions, and answers.

The SDK emits an outer operation span and a child model-call span, and both carry the same gen_ai.operation.name: "decide", provider, and model attributes. The processor alone cannot tell them apart, so without enrichSpan both spans are exported as DECISION spans that each carry the model identity, and the model call's usage is attributed to a second decision. Pass enrichSpan: enrichSpanWithOpenInference to OpenTelemetry to classify the outer operation as a CHAIN span (with the decision input and output) and the model call as a DECISION span (with decision.model_name, decision.provider, decision.system, and decision.token_count.*).

Decision spans identify the model under decision.* rather than llm.*. To keep downstream GenAI converters from re-labeling the model as an LLM, the processor removes gen_ai.provider.name, gen_ai.request.model, gen_ai.response.model, and gen_ai.usage.* from decision spans after mapping them. Other exporters attached to the same tracer provider see the span after this removal.

The Jev decision example calls TypeSafe's hosted model with @ai-sdk/typesafe-ai and requires TYPESAFE_API_KEY.

For more information on Vercel OpenTelemetry support, see the Vercel OpenTelemetry guide.

Reparenting orphaned spans

When you filter with spanFilter: isOpenInferenceSpan, only AI-related spans are exported. But the highest-level AI span (e.g. ai.generateText, ai.streamText) is frequently parented under a non-AI span — for example the HTTP/server span that Next.js parents everything under. That parent is filtered out, leaving the AI span orphaned: it references a parent that was never exported, so backends may not be able to render the trace correctly.

Set reparentOrphanedSpans: true to detach (re-root) any AI span whose direct parent is a non-AI span, so it becomes a trace root. Multiple sibling AI spans in the same trace are each re-rooted, and AI spans nested under an AI parent keep their place.

new OpenInferenceSimpleSpanProcessor({
  exporter,
  spanFilter: isOpenInferenceSpan,
  reparentOrphanedSpans: true, // default: false
});

The check is stateless — the parent span is read from the start-time context, so no per-trace bookkeeping is kept.

If the re-rooted span is an ai.* framework wrapper that the package doesn't map to a span kind (for example a per-turn span an agent framework emits on top of the AI SDK), it would otherwise be kind-less and dropped by the filter. Such a root is tagged openinference.span.kind = AGENT so it is kept as the trace root. This is matched by shape (an unrecognized AI-like root), not by any specific framework span name.

reparentOrphanedSpans is opt-in (default false). It is intended for use alongside a filter that drops non-AI parent spans — which is exactly the situation that orphans the AI children in the first place: when the filter removes a non-AI parent, every AI span beneath it is left pointing at a parent that was never exported. Reparenting re-roots those children so the trace still renders. (Conversely, without such a filter the non-AI parent is still exported, so there is nothing to orphan, and reparenting would only split an otherwise-intact trace.)

Propagating session and context attributes

The Vercel AI SDK creates its own spans, so — unlike the OpenInference instrumentors, which build spans through an OITracer — this processor does not read the OpenInference context. That means values you set with the @arizeai/openinference-core helpers (setSession, setUser, setMetadata, setTags) never reach the exported AI spans. A session.id set around a call like this would otherwise be lost:

import { context } from "@opentelemetry/api";
import { setSession } from "@arizeai/openinference-core";

context.with(setSession(context.active(), { sessionId }), () =>
  streamText({ model, prompt, experimental_telemetry: { isEnabled: true } }),
);

propagateContextAttributes copies every OpenInference attribute on the start-time context (session.id, user.id, metadata.*, tag.tags, …) directly onto each span at onStart, so traces group into sessions in Arize / Phoenix. It is enabled by default; set it to false to opt out.

new OpenInferenceSimpleSpanProcessor({
  exporter,
  spanFilter: isOpenInferenceSpan,
  reparentOrphanedSpans: true,
  propagateContextAttributes: true, // default: true
});

Because the values are written directly onto the span, they survive both reparentOrphanedSpans re-rooting and export, and spans started in the same context (child model/tool calls) inherit them.

Spans that carry the GenAI gen_ai.conversation.id attribute (for example every span Vercel eve emits) also get session.id from it, with no context setup needed. A session.id propagated from the context takes precedence.

版本与发布记录

@arizeai/openinference-vercel 共发布 59 个版本,首次发布于 2024/08/21;过去 12 个月发布了 36 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
3.3.1latest2026/10/2414 天前
3.3.02026/10/1028 天前
3.2.42026/10/021 个月前
3.2.32026/10/021 个月前
3.2.22026/10/011 个月前
3.2.12026/09/191 个月前

关于 @arizeai/openinference-vercel 的常见问题

@arizeai/openinference-vercel 是什么?

OpenInference utilities for ingesting Vercel AI SDK spans

如何安装 @arizeai/openinference-vercel?

在项目目录运行 npm install @arizeai/openinference-vercel,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:ai(^7.0.0)、@ai-sdk/otel(^1.0.0)、@opentelemetry/api(>=1.7.0 <2.0.0)、@opentelemetry/semantic-conventions(>=1.41.1 <2.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@arizeai/openinference-vercel 支持 TypeScript 吗?

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

@arizeai/openinference-vercel 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@arizeai/openinference-vercel 需要什么版本的 Node.js?

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

@arizeai/openinference-vercel 可以商用吗?

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

@arizeai/openinference-vercel 的下载量有多少?

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

@arizeai/openinference-vercel 还在维护吗?

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