langfuse-local-dev-loop

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Langfuse Local Dev Loop

Langfuse本地开发循环

Overview

概述

Set up a fast, iterative local development workflow with Langfuse tracing and debugging.
搭建支持Langfuse追踪与调试的快速迭代本地开发工作流。

Prerequisites

前置条件

  • Completed
    langfuse-install-auth
    setup
  • Node.js 18+ or Python 3.9+
  • Docker (optional, for self-hosted local instance)
  • IDE with TypeScript/Python support
  • 已完成
    langfuse-install-auth
    配置
  • Node.js 18+ 或 Python 3.9+
  • Docker(可选,用于本地自托管实例)
  • 支持TypeScript/Python的IDE

Instructions

操作步骤

Step 1: Configure Development Environment

步骤1:配置开发环境

Create a
.env.local
file for development-specific settings:
bash
undefined
创建用于开发专属设置的
.env.local
文件:
bash
undefined

.env.local

.env.local

LANGFUSE_PUBLIC_KEY=pk-lf-dev-... LANGFUSE_SECRET_KEY=sk-lf-dev-... LANGFUSE_HOST=https://cloud.langfuse.com
LANGFUSE_PUBLIC_KEY=pk-lf-dev-... LANGFUSE_SECRET_KEY=sk-lf-dev-... LANGFUSE_HOST=https://cloud.langfuse.com

Development options

Development options

LANGFUSE_DEBUG=true LANGFUSE_FLUSH_AT=1 # Flush after every event for immediate visibility LANGFUSE_FLUSH_INTERVAL=1000 # Flush every second
undefined
LANGFUSE_DEBUG=true LANGFUSE_FLUSH_AT=1 # Flush after every event for immediate visibility LANGFUSE_FLUSH_INTERVAL=1000 # Flush every second
undefined

Step 2: Create Debug-Enabled Client

步骤2:创建启用调试的客户端

typescript
// src/lib/langfuse.ts
import { Langfuse } from "langfuse";

const isDev = process.env.NODE_ENV !== "production";

export const langfuse = new Langfuse({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,
  baseUrl: process.env.LANGFUSE_HOST,
  // Development settings
  flushAt: isDev ? 1 : 15,
  flushInterval: isDev ? 1000 : 10000,
  // Enable debug logging in dev
  ...(isDev && {
    debug: true,
  }),
});

// Auto-flush on process exit
process.on("beforeExit", async () => {
  await langfuse.shutdownAsync();
});

// Helper to get trace URL immediately
export function logTraceUrl(trace: ReturnType<typeof langfuse.trace>) {
  if (isDev) {
    console.log(`\n🔍 Trace: ${trace.getTraceUrl()}\n`);
  }
}
typescript
// src/lib/langfuse.ts
import { Langfuse } from "langfuse";

const isDev = process.env.NODE_ENV !== "production";

export const langfuse = new Langfuse({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,
  baseUrl: process.env.LANGFUSE_HOST,
  // Development settings
  flushAt: isDev ? 1 : 15,
  flushInterval: isDev ? 1000 : 10000,
  // Enable debug logging in dev
  ...(isDev && {
    debug: true,
  }),
});

// Auto-flush on process exit
process.on("beforeExit", async () => {
  await langfuse.shutdownAsync();
});

// Helper to get trace URL immediately
export function logTraceUrl(trace: ReturnType<typeof langfuse.trace>) {
  if (isDev) {
    console.log(`\n🔍 Trace: ${trace.getTraceUrl()}\n`);
  }
}

Step 3: Set Up Hot Reload Development Script

步骤3:设置热重载开发脚本

json
// package.json
{
  "scripts": {
    "dev": "tsx watch --env-file=.env.local src/index.ts",
    "dev:debug": "DEBUG=langfuse* tsx watch --env-file=.env.local src/index.ts"
  }
}
json
// package.json
{
  "scripts": {
    "dev": "tsx watch --env-file=.env.local src/index.ts",
    "dev:debug": "DEBUG=langfuse* tsx watch --env-file=.env.local src/index.ts"
  }
}

Step 4: Add Development Utilities

步骤4:添加开发工具函数

typescript
// src/lib/dev-utils.ts
import { langfuse, logTraceUrl } from "./langfuse";

// Wrapper that logs trace URLs in dev
export function withTracing<T extends (...args: any[]) => Promise<any>>(
  name: string,
  fn: T
): T {
  return (async (...args: Parameters<T>) => {
    const trace = langfuse.trace({
      name,
      input: args,
      tags: ["dev"],
    });

    logTraceUrl(trace);

    try {
      const result = await fn(...args);
      trace.update({ output: result });
      return result;
    } catch (error) {
      trace.update({
        output: { error: String(error) },
        tags: ["dev", "error"],
      });
      throw error;
    }
  }) as T;
}

// Quick debug trace
export function debugTrace(name: string, data: Record<string, any>) {
  const trace = langfuse.trace({
    name: `debug/${name}`,
    metadata: data,
    tags: ["debug"],
  });
  logTraceUrl(trace);
  return trace;
}
typescript
// src/lib/dev-utils.ts
import { langfuse, logTraceUrl } from "./langfuse";

// Wrapper that logs trace URLs in dev
export function withTracing<T extends (...args: any[]) => Promise<any>>(
  name: string,
  fn: T
): T {
  return (async (...args: Parameters<T>) => {
    const trace = langfuse.trace({
      name,
      input: args,
      tags: ["dev"],
    });

    logTraceUrl(trace);

    try {
      const result = await fn(...args);
      trace.update({ output: result });
      return result;
    } catch (error) {
      trace.update({
        output: { error: String(error) },
        tags: ["dev", "error"],
      });
      throw error;
    }
  }) as T;
}

// Quick debug trace
export function debugTrace(name: string, data: Record<string, any>) {
  const trace = langfuse.trace({
    name: `debug/${name}`,
    metadata: data,
    tags: ["debug"],
  });
  logTraceUrl(trace);
  return trace;
}

Local Self-Hosted Instance (Optional)

本地自托管实例(可选)

For completely local development without cloud:
yaml
undefined
如需完全脱离云服务的本地开发:
yaml
undefined

docker-compose.langfuse.yml

docker-compose.langfuse.yml

version: "3.8" services: langfuse: image: langfuse/langfuse:latest ports: - "3000:3000" environment: - DATABASE_URL=postgresql://postgres:postgres@db:5432/langfuse - NEXTAUTH_SECRET=development-secret-change-in-prod - NEXTAUTH_URL=http://localhost:3000 - SALT=development-salt-change-in-prod depends_on: - db
db: image: postgres:15-alpine environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - POSTGRES_DB=langfuse volumes: - langfuse-db:/var/lib/postgresql/data
volumes: langfuse-db:

```bash
version: "3.8" services: langfuse: image: langfuse/langfuse:latest ports: - "3000:3000" environment: - DATABASE_URL=postgresql://postgres:postgres@db:5432/langfuse - NEXTAUTH_SECRET=development-secret-change-in-prod - NEXTAUTH_URL=http://localhost:3000 - SALT=development-salt-change-in-prod depends_on: - db
db: image: postgres:15-alpine environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres - POSTGRES_DB=langfuse volumes: - langfuse-db:/var/lib/postgresql/data
volumes: langfuse-db:

```bash

Start local Langfuse

Start local Langfuse

docker compose -f docker-compose.langfuse.yml up -d
docker compose -f docker-compose.langfuse.yml up -d

Update .env.local

Update .env.local

echo 'LANGFUSE_HOST=http://localhost:3000' >> .env.local
undefined
echo 'LANGFUSE_HOST=http://localhost:3000' >> .env.local
undefined

Output

输出结果

  • Development environment with hot reload
  • Immediate trace visibility (flush after every event)
  • Debug logging enabled
  • Trace URLs printed to console
  • (Optional) Local Langfuse instance
  • 支持热重载的开发环境
  • 即时追踪可见性(每次事件后立即刷新)
  • 已启用调试日志
  • 追踪URL打印至控制台
  • (可选)本地Langfuse实例

Error Handling

错误处理

IssueCauseSolution
Traces delayedBatching enabledSet
flushAt: 1
in dev
No debug outputDebug not enabledSet
LANGFUSE_DEBUG=true
Hot reload failsFile watching issueUse
tsx watch
or
nodemon
Local instance unreachableDocker not runningRun
docker compose up -d
问题原因解决方案
追踪数据延迟启用了批量处理在开发环境中设置
flushAt: 1
无调试输出未启用调试功能设置
LANGFUSE_DEBUG=true
热重载失败文件监听问题使用
tsx watch
nodemon
本地实例无法访问Docker未运行执行
docker compose up -d

Examples

示例

Quick Development Test

快速开发测试

typescript
// src/index.ts
import { langfuse, logTraceUrl } from "./lib/langfuse";
import OpenAI from "openai";
import { observeOpenAI } from "langfuse";

const openai = observeOpenAI(new OpenAI());

async function devTest() {
  const trace = langfuse.trace({
    name: "dev-test",
    tags: ["dev"],
  });

  logTraceUrl(trace);

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

  console.log("Response:", response.choices[0].message.content);
  await langfuse.flushAsync();
}

devTest();
typescript
// src/index.ts
import { langfuse, logTraceUrl } from "./lib/langfuse";
import OpenAI from "openai";
import { observeOpenAI } from "langfuse";

const openai = observeOpenAI(new OpenAI());

async function devTest() {
  const trace = langfuse.trace({
    name: "dev-test",
    tags: ["dev"],
  });

  logTraceUrl(trace);

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

  console.log("Response:", response.choices[0].message.content);
  await langfuse.flushAsync();
}

devTest();

Watch Mode with Live Trace Links

带实时追踪链接的监听模式

bash
undefined
bash
undefined

Terminal output with trace links

Terminal output with trace links

$ pnpm dev
🔄 Watching for changes...
Response: Hello! How can I help you today?
[File changed, reloading...]
Response: I'm doing great, thanks for asking!
undefined
$ pnpm dev
🔄 Watching for changes...
Response: Hello! How can I help you today?
[File changed, reloading...]
Response: I'm doing great, thanks for asking!
undefined

Debug Mode Configuration

调试模式配置

typescript
// Enable verbose SDK debugging
const langfuse = new Langfuse({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,
  debug: true, // Logs all SDK operations
});

// Or use environment variable
// DEBUG=langfuse* pnpm dev
typescript
// Enable verbose SDK debugging
const langfuse = new Langfuse({
  publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
  secretKey: process.env.LANGFUSE_SECRET_KEY!,
  debug: true, // Logs all SDK operations
});

// Or use environment variable
// DEBUG=langfuse* pnpm dev

Resources

参考资源

Next Steps

下一步

For SDK patterns and best practices, see
langfuse-sdk-patterns
.
如需了解SDK模式与最佳实践,请查看
langfuse-sdk-patterns