Laminar Observability
Laminar Observability
Laminar은 AI 에이전트를 위해 특별히 설계된 오픈소스, Otel 네이티브 관측성 플랫폼이에요.
Laminar의 기능:
이 가이드의 한 버전은 Laminar 문서에서 볼 수 있어요.
출처: 문서
본문
설정
코딩 에이전트를 사용해 Laminar을 설치하거나 수동으로 설치할 수 있어요.
코딩 에이전트로 설정
아래 프롬프트를 복사해 코딩 에이전트에 붙여넣으면 완전히 자동으로 통합돼요.
1. Run `npx lmnr-cli setup` at the project root to get started with Laminar. This command will authenticate the user, save a new project API key to .env, and install the Laminar skill.
2. Instrument this project with Laminar using the installed skill or the docs:
https://laminar.sh/docs/tracing/integrations/vercel-ai-sdk
3. Run a traced path inside your application.
4. Verify instrumentation:
`lmnr-cli sql query "SELECT * FROM traces ORDER BY start_time DESC LIMIT 1" --json`
수동 설정
Laminar을 수동으로 설정하려면 먼저 @lmnr-ai/lmnr 패키지를 설치해요.
npm install @lmnr-ai/lmnr
프로젝트 API 키를 받아 환경에 설정
그런 다음 Laminar에 가입하거나 인스턴스를 셀프호스팅(github)하고 새 프로젝트를 만들어요.
npx lmnr-cli@latest setup을 사용해요. 이 명령은:
- Laminar에 디바이스를 인증하고,
- 새 프로젝트 API 키를 만들어
.env에LMNR_PROJECT_API_KEY로 저장하며, - 코딩 에이전트가 Laminar SDK로 에이전트를 계측하는 데 사용할 Laminar 스킬을 설치해요.
Next.js
트레이싱 초기화
Next.js에서 Laminar 초기화와 AI SDK 텔레메트리 통합은 둘 다 instrumentation.{ts,js}에서 해야 해요:
export async function register() {
// prevent this from running in the edge runtime
if (process.env.NEXT_RUNTIME === 'nodejs') {
const { registerTelemetry } = await import('ai');
const { LaminarAiSdkTelemetry } = await import('@lmnr-ai/lmnr');
registerTelemetry(new LaminarAiSdkTelemetry());
}
}
next.config에 @lmnr-ai/lmnr 추가
next.config.js(.ts / .mjs)에 다음 줄을 추가해요:
const nextConfig = {
serverExternalPackages: ['@lmnr-ai/lmnr'],
};
export default nextConfig;
Laminar은 OpenTelemetry에 의존하는데 OpenTelemetry는 일부 Node.js 특화 기능을 사용하므로, Next.js에 이 사실을 알려야 하기 때문이에요. 자세한 내용은 Next.js 문서에서 확인하세요.
AI SDK 호출 트레이싱
통합이 등록되면 모든 AI SDK 호출에서 텔레메트리가 자동으로 캡처돼요:
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';
const { text } = await generateText({
model: openai('gpt-6-luna'),
prompt: 'What is Laminar flow?',
});
이것은 ai.generateText에 대한 span을 생성해요. Laminar은 다음 정보를 수집하고 표시해요:
- LLM 호출 입력과 출력
- 시작 및 종료 시간
- 기간 / 지연시간
- 사용된 프로바이더와 모델
- 입력 및 출력 토큰
- 입력 및 출력 가격
- 추가 메타데이터와 span 속성
이전 버전의 Next.js
13.4 ≤ Next.js < 15를 사용한다면 실험적 instrumentation 훅도 활성화해야 해요. next.config.js에 다음을 넣어요:
module.exports = {
experimental: {
instrumentationHook: true,
},
};
자세한 내용은 Laminar의 AI SDK 통합 가이드와 Next.js instrumentation 문서를 참고하세요. Next.js의 모든 trace를 활성화하는 방법도 문서에서 배울 수 있어요.
@vercel/otel과 함께 사용
Laminar은 @vercel/otel과 함께 존재하며 AI SDK 호출을 추적할 수 있어요. 기본 Laminar 설정은 다음을 보장해요:
- 일반 Next.js trace는
@vercel/otel을 통해 Vercel로 구성된 텔레메트리 백엔드로 전송되고, - AI SDK 및 기타 LLM 또는 브라우저 에이전트 trace는 Laminar을 통해 전송돼요.
import { registerOTel } from '@vercel/otel';
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
const { registerTelemetry } = await import('ai');
const { initializeLaminarInstrumentations, LaminarAiSdkTelemetry } =
await import('@lmnr-ai/lmnr');
// Next.js telemetry
registerOTel({
serviceName: 'my-service',
instrumentations: initializeLaminarInstrumentations(),
});
// Laminar AI SDK telemetry
registerTelemetry(new LaminarAiSdkTelemetry());
}
}
모든 Next.js trace를 Laminar을 통해 추적할 수 있게 하는 고급 구성은 예시 저장소를 참고하세요.
@sentry/node와 함께 사용
Laminar은 @sentry/node와 함께 존재하며 AI SDK 호출을 추적할 수 있어요. Sentry.init 이후에 Laminar을 초기화해야 해요.
이것은 다음을 보장해요:
- Sentry가 계측하는 모든 것은 Sentry 백엔드로 전송되고,
- AI SDK 및 기타 LLM 또는 브라우저 에이전트 trace는 Laminar을 통해 전송돼요.
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
const { registerTelemetry } = await import('ai');
const Sentry = await import('@sentry/node');
const { LaminarAiSdkTelemetry } = await import('@lmnr-ai/lmnr');
Sentry.init({
dsn: process.env.SENTRY_DSN,
});
// Make sure to initialize Laminar **after** `Sentry.init`
registerTelemetry(new LaminarAiSdkTelemetry());
}
}
Node.js
트레이싱 초기화
그런 다음 애플리케이션에서 트레이싱을 초기화해요:
import { registerTelemetry } from 'ai';
import { LaminarAiSdkTelemetry } from '@lmnr-ai/lmnr';
registerTelemetry(new LaminarAiSdkTelemetry());
이것은 애플리케이션에서 가능한 한 일찍 한 번 해야 하며, 다른 트레이싱 라이브러리(예: @sentry/node)가 초기화된 이후에 해야 해요.
Laminar 문서에서 더 읽어보세요.
AI SDK 호출 트레이싱
통합이 등록되면 모든 AI SDK 호출에서 텔레메트리가 자동으로 캡처돼요:
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';
const { text } = await generateText({
model: openai('gpt-6-luna'),
prompt: 'What is Laminar flow?',
});
이것은 ai.generateText에 대한 span을 생성해요. Laminar은 다음 정보를 수집하고 표시해요:
- LLM 호출 입력과 출력
- 시작 및 종료 시간
- 기간 / 지연시간
- 사용된 프로바이더와 모델
- 입력 및 출력 토큰
- 입력 및 출력 가격
- 추가 메타데이터와 span 속성
@sentry/node와 함께 사용
Laminar은 @sentry/node와 함께 동작해 AI SDK 호출을 추적할 수 있어요. Sentry.init 이후에 Laminar을 초기화해야 해요:
const { LaminarAiSdkTelemetry } = await import('@lmnr-ai/lmnr');
const Sentry = await import('@sentry/node');
const { registerTelemetry } = await import('ai');
Sentry.init({
dsn: process.env.SENTRY_DSN,
});
registerTelemetry(new LaminarAiSdkTelemetry());
이것은 다음을 보장해요:
- Sentry가 계측하는 모든 것은 Sentry 백엔드로 전송되고,
- AI SDK 및 기타 LLM 또는 브라우저 에이전트 trace는 Laminar을 통해 전송돼요.
두 라이브러리는 추가 고급 구성을 허용하지만, 위 기본 설정이 권장돼요.
추가 구성
Laminar 옵션
LaminarAiSdkTelemetry는 Laminar.initialize()에 옵션을 전달할 수 있어요. 셀프호스팅 사용자의 경우,
import { registerTelemetry } from 'ai';
import { LaminarAiSdkTelemetry } from '@lmnr-ai/lmnr';
registerTelemetry(new LaminarAiSdkTelemetry({
laminarOptions: {
projectApiKey: proces...KEY,
baseUrl: "http://localhost",
httpPort: 8000,
grpcPort: 8001,
},
}));
입력 또는 출력 기록 안 함
기본적으로 Laminar 통합은 모든 입력과 출력을 기록하지만, 생성자 옵션에서 이를 비활성화할 수 있어요.
import { registerTelemetry } from 'ai';
import { LaminarAiSdkTelemetry } from '@lmnr-ai/lmnr';
registerTelemetry(new LaminarAiSdkTelemetry({
recordInputs: false, // default true
recordOutputs: false, // default true
}));
모든 에이전트 스텝에 span 추가
AI SDK 텔레메트리 통합은 모든 에이전트 스텝에 대해 스텝 span을 생성해요. 기본적으로 Laminar은 이 span들을 무시해요. 생성자 옵션에서 이를 구성할 수 있어요.
import { registerTelemetry } from 'ai';
import { LaminarAiSdkTelemetry } from '@lmnr-ai/lmnr';
registerTelemetry(new LaminarAiSdkTelemetry({
createStepSpan: true, // default false
}));
span 이름
기본 span 이름을 재정의하려면 telemetry 옵션 안에 functionId를 설정할 수 있어요.
const { text } = await generateText({
model: openai('gpt-6-luna'),
prompt: `Write a poem about Laminar flow.`,
telemetry: {
functionId: 'poem-writer',
},
});
중첩 span
AI SDK 호출뿐 아니라 애플리케이션의 다른 함수도 추적하려면 Laminar의 observe 래퍼를 사용할 수 있어요.
import { observe } from '@lmnr-ai/lmnr';
const result = await observe({ name: 'my-function' }, async () => {
// ... some work
await generateText({
//...
});
// ... some work
});
이것은 "my-function"이라는 이름의 span을 만들고 함수 호출을 추적해요. 그 안에 중첩된 ai.generateText span이 보일 거예요.
observe로 감싼 함수의 입력 인자를 추적하려면 추가 인자로 래퍼에 전달하세요. 함수의 반환값은 래퍼에서 반환되고 span의 출력으로 추적돼요.
const result = await observe(
{ name: 'poem writer' },
async (topic: string, mood: string) => {
const { text } = await generateText({
model: openai('gpt-6-luna'),
prompt: `Write a poem about ${topic} in ${mood} mood.`,
});
return text;
},
'Laminar flow',
'happy',
);
메타데이터
Laminar에서 메타데이터는 trace 수준에 설정돼요. 메타데이터는 키-값 쌍을 포함하며 trace를 필터링하는 데 사용할 수 있어요.
const { text } = await generateText({
model: openai('gpt-6-luna'),
prompt: `Write a poem about Laminar flow.`,
telemetry: {
metadata: {
'my-key': 'my-value',
'another-key': 'another-value',
},
},
});
이것은 Laminar의 메타데이터로 변환되어 trace에 저장돼요.
태그
예약된 메타데이터 키 중 하나는 tags예요. 이를 사용해 span에 태그를 추가할 수 있어요.
태그는 이후 Laminar에서 trace를 필터링하는 데 사용할 수 있어요.
const { text } = await generateText({
model: openai('gpt-6-luna'),
prompt: `Write a poem about Laminar flow.`,
telemetry: {
metadata: {
tags: ['fallback-model', 'api-handler'],
},
},
});
세션 ID와 사용자 ID
Laminar의 trace는 세션 또는 사용자 ID로 그룹화할 수 있어요. 이들도 예약된 메타데이터 키예요.
const { text } = await generateText({
model: openai('gpt-6-luna'),
prompt: `Write a poem about Laminar flow.`,
telemetry: {
metadata: {
sessionId: 'session-123',
userId: 'user-123',
},
},
});
더 알아보기 (Learn more)
- 출처 문서: Laminar Observability