Vercel AI SDK로 트레이싱하기
Vercel AI SDK로 트레이싱하기 (Legacy)
OpenTelemetry(OTEL)를 사용해 Vercel AI SDK 실행을 LangSmith로 트레이싱하는 방법을 알려드릴게요.
경고: 이 페이지는 AI SDK 실행을 트레이싱하는 이전 방식을 문서화합니다. OTEL 설정이 필요 없는 더 간단하고 일반적인 방법은 새 가이드를 참고하세요.
참고: JavaScript의 많은 인기 있는 OpenTelemetry 구현은 현재 실험적이며, 특히 LangSmith를 다른 프로바이더와 함께 계측할 때 프로덕션에서 불규칙하게 동작할 수 있습니다. AI SDK 5를 사용한다면 AI SDK 실행을 트레이싱하는 권장 접근 방식을 사용하는 것을 강력히 권장합니다.
출처: 문서
본문
0. 설치
Vercel AI SDK와 필요한 OTEL 패키지를 설치합니다. 아래 코드 스니펫에서는 OpenAI 통합을 사용하지만, 그들의 다른 옵션도 사용할 수 있습니다.
npm install ai @ai-sdk/openai zod
yarn add ai @ai-sdk/openai zod
pnpm add ai @ai-sdk/openai zod
npm install @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-proto @opentelemetry/context-async-hooks
yarn add @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-proto @opentelemetry/context-async-hooks
pnpm add @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-proto @opentelemetry/context-async-hooks
1. 환경 구성하기
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY=<your-api-key>
export LANGSMITH_OTEL_ENABLED=true
# This example uses OpenAI, but you can use any LLM provider of choice
export OPENAI_API_KEY=<your-openai-api-key>
2. 트레이스 기록하기
Node.js
트레이싱을 시작하려면 코드 시작 부분에서 initializeOTEL 메서드를 import하고 호출해야 합니다:
import { initializeOTEL } from "langsmith/experimental/otel/setup";
const { DEFAULT_LANGSMITH_SPAN_PROCESSOR } = initializeOTEL();
그런 다음 트레이싱하려는 AI SDK 호출에 experimental_telemetry 인자를 추가합니다.
정보: 남은 트레이스를 LangSmith로 플러시하려면 애플리케이션이 종료되기 전에
await DEFAULT_LANGSMITH_SPAN_PROCESSOR.shutdown();을 호출하는 것을 잊지 마세요.
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
let result;
try {
result = await generateText({
model: openai("gpt-5.4-nano"),
prompt: "Write a vegetarian lasagna recipe for 4 people.",
experimental_telemetry: {
isEnabled: true,
},
});
} finally {
await DEFAULT_LANGSMITH_SPAN_PROCESSOR.shutdown();
}
LangSmith 대시보드에서 이런 트레이스를 볼 수 있습니다.
도구 호출이 있는 실행도 트레이싱할 수 있습니다:
import { generateText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
await generateText({
model: openai("gpt-5.4-nano"),
messages: [
{
role: "user",
content: "What are my orders and where are they? My user ID is 123",
},
],
tools: {
listOrders: tool({
description: "list all orders",
parameters: z.object({ userId: z.string() }),
execute: async ({ userId }) =>
`User ${userId} has the following orders: 1`,
}),
viewTrackingInformation: tool({
description: "view tracking information for a specific order",
parameters: z.object({ orderId: z.string() }),
execute: async ({ orderId }) =>
`Here is the tracking information for ${orderId}`,
}),
},
experimental_telemetry: {
isEnabled: true,
},
maxSteps: 10,
});
결과는 이런 트레이스입니다.
traceable 사용
AI SDK 도구 호출 주변이나 내부에 traceable 호출을 래핑할 수 있습니다. 그렇게 하려면 각 traceable에 전달하는 LangSmith client 인스턴스를 초기화한 다음, 모든 트레이스가 플러시되도록 client.awaitPendingTraceBatches();를 호출할 것을 권장합니다. 이렇게 하면 DEFAULT_LANGSMITH_SPAN_PROCESSOR에서 shutdown()이나 forceFlush()를 수동으로 호출할 필요가 없습니다. 예:
import { initializeOTEL } from "langsmith/experimental/otel/setup";
initializeOTEL();
import { Client } from "langsmith";
import { traceable } from "langsmith/traceable";
import { generateText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
const client = new Client();
const wrappedText = traceable(
async (content: string) => {
const { text } = await generateText({
model: openai("gpt-5.4-nano"),
messages: [{ role: "user", content }],
tools: {
listOrders: tool({
description: "list all orders",
parameters: z.object({ userId: z.string() }),
execute: async ({ userId }) => {
const getOrderNumber = traceable(
async () => {
return "1234";
},
{ name: "getOrderNumber" }
);
const orderNumber = await getOrderNumber();
return `User ${userId} has the following order: ${orderNumber}`;
},
}),
},
experimental_telemetry: {
isEnabled: true,
},
maxSteps: 10,
});
return { text };
},
{ name: "parentTraceable", client }
);
let result;
try {
result = await wrappedText("What are my orders?");
} finally {
await client.awaitPendingTraceBatches();
}
결과 트레이스는 이렇게 보입니다.
Next.js
먼저 @vercel/otel 패키지를 설치합니다:
npm install @vercel/otel
yarn add @vercel/otel
pnpm add @vercel/otel
그런 다음 루트 디렉터리에 instrumentation.ts 파일을 설정합니다. initializeOTEL을 호출하고 결과 DEFAULT_LANGSMITH_SPAN_PROCESSOR를 registerOTEL(...) 호출의 spanProcessors 필드로 전달합니다. 대략 이렇게:
import { registerOTel } from "@vercel/otel";
import { initializeOTEL } from "langsmith/experimental/otel/setup";
const { DEFAULT_LANGSMITH_SPAN_PROCESSOR } = initializeOTEL({});
export function register() {
registerOTel({
serviceName: "your-project-name",
spanProcessors: [DEFAULT_LANGSMITH_SPAN_PROCESSOR],
});
}
마지막으로 API 라우트에서도 initializeOTEL을 호출하고 AI SDK 호출에 experimental_telemetry 필드를 추가합니다:
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { initializeOTEL } from "langsmith/experimental/otel/setup";
initializeOTEL();
export async function GET() {
const { text } = await generateText({
model: openai("gpt-5.4-nano"),
messages: [{ role: "user", content: "Why is the sky blue?" }],
experimental_telemetry: {
isEnabled: true,
},
});
return new Response(text);
}
더 세밀한 제어를 위해 코드의 일부를 traceable로 래핑할 수도 있습니다.
Sentry
Sentry를 사용한다면 아래 예제처럼 LangSmith 트레이스 exporter를 Sentry의 기본 OpenTelemetry 계측에 연결할 수 있습니다.
경고: 작성 시점에 Sentry는 OTEL v1 패키지만 지원합니다. LangSmith는 v1과 v2를 모두 지원하지만, 계측이 동작하도록 반드시 OTEL v1 패키지를 설치해야 합니다.
npm install @opentelemetry/[email protected] @opentelemetry/[email protected] @opentelemetry/[email protected]yarn add @opentelemetry/[email protected] @opentelemetry/[email protected] @opentelemetry/[email protected]pnpm add @opentelemetry/[email protected] @opentelemetry/[email protected] @opentelemetry/[email protected]
import { initializeOTEL } from "langsmith/experimental/otel/setup";
import { LangSmithOTLPTraceExporter } from "langsmith/experimental/otel/exporter";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { traceable } from "langsmith/traceable";
import { generateText, tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
import * as Sentry from "@sentry/node";
import { Client } from "langsmith";
const exporter = new LangSmithOTLPTraceExporter();
const spanProcessor = new BatchSpanProcessor(exporter);
const sentry = Sentry.init({
dsn: "...",
tracesSampleRate: 1.0,
openTelemetrySpanProcessors: [spanProcessor],
});
initializeOTEL({
globalTracerProvider: sentry?.traceProvider,
});
const wrappedText = traceable(
async (content: string) => {
const { text } = await generateText({
model: openai("gpt-5.4-nano"),
messages: [{ role: "user", content }],
experimental_telemetry: {
isEnabled: true,
},
maxSteps: 10,
});
return { text };
},
{ name: "parentTraceable" }
);
let result;
try {
result = await wrappedText("What color is the sky?");
} finally {
await sentry?.traceProvider?.shutdown();
}
기타 메타데이터 추가하기
LangSmith UI에서 조직화·필터링에 도움이 되도록 트레이스에 기타 메타데이터를 추가할 수 있습니다:
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
await generateText({
model: openai("gpt-5.4-nano"),
prompt: "Write a vegetarian lasagna recipe for 4 people.",
experimental_telemetry: {
isEnabled: true,
metadata: { userId: "123", language: "english" },
},
});
메타데이터는 LangSmith 대시보드에 표시되며 특정 트레이스를 필터링·검색하는 데 사용할 수 있습니다. AI SDK는 내부 하위 span에도 메타데이터를 전파한다는 점을 유의하세요.
실행 이름 커스터마이즈
experimental_telemetry에 ls_run_name이라는 메타데이터 키를 전달해 실행 이름을 커스터마이즈할 수 있습니다.
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
await generateText({
model: openai("gpt-5.4-mini"),
prompt: "Write a vegetarian lasagna recipe for 4 people.",
experimental_telemetry: {
isEnabled: true,
metadata: {
ls_run_name: "my-custom-run-name",
},
},
});
더 알아보기
- 새 가이드 — OTEL 설정이 필요 없는 권장 방식.