从 v3 开始,Langfuse 自托管是 双进程 + 四存储 的架构,不是一个 docker run 就完事的单体。langfuse-web 提供 UI 与 API(接收 SDK 上报、渲染 Dashboard);langfuse-worker 异步消费队列、把 trace 落库并做聚合。两者共享同一套后端:Postgres 存配置 / 用户 / prompt 等事务性数据,ClickHouse 存海量 trace / observation / score 这类分析型数据,Redis 做队列与缓存,MinIO(或任意 S3 兼容存储)存大体积的事件原始 payload 与多模态文件。理解这套分工,后面的环境变量就不再是黑盒。

选型:Cloud 还是自托管

维度Langfuse Cloud自托管 (Docker)
上手成本注册即用,无需运维需自己部署并维护 4 个存储组件
免费额度Hobby 计划含每月一定额度的免费 unit,单项目,社区支持完全免费(开源核心),成本在你的服务器上
数据驻留 / Region提供 EU / US / HIPAA 等多 region,注册时按域名选择数据 100% 在你自己的基础设施,region 你说了算
合规 (内网 / 私有化)受限于云服务条款可完全内网、满足强合规要求
升级官方自动升级,始终最新需自己拉新镜像、跟版本迁移
适合谁验证想法、中小团队、不想碰运维有合规 / 数据驻留 / 内网要求的团队
口诀要快用 Cloud,要合规自托管:先用 Cloud 跑通价值,确有数据约束再迁自托管。

自托管:完整可运行的 docker-compose.yml

下面这份 docker-compose.yml 包含 v3 自托管所需的全部组件,可在本地 / 单机服务器直接跑起来。先看配置,再逐项解释关键环境变量与密钥。

# docker-compose.yml
# 一份可直接 `docker compose up -d` 的 Langfuse v3 自托管最小完整配置
# 适用于本地验证 / 单机部署;生产环境请把密钥换成强随机值并接入外部托管存储
services:
  # ---------- Langfuse 应用层(双进程)----------
  langfuse-web:
    image: langfuse/langfuse:3            # UI + API 进程
    depends_on:
      postgres: { condition: service_healthy }
      clickhouse: { condition: service_healthy }
      redis: { condition: service_healthy }
      minio: { condition: service_healthy }
    ports:
      - "3000:3000"                       # 浏览器访问 http://localhost:3000
    environment: &langfuse-env             # web 与 worker 共享同一组环境变量
      # --- 事务库:Postgres ---
      DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres
      # --- 分析库:ClickHouse ---
      CLICKHOUSE_URL: http://clickhouse:8123
      CLICKHOUSE_MIGRATION_URL: clickhouse://clickhouse:9000
      CLICKHOUSE_USER: clickhouse
      CLICKHOUSE_PASSWORD: clickhouse
      CLICKHOUSE_CLUSTER_ENABLED: "false"  # 单机部署必须关,否则迁移会找不到集群
      # --- 队列 / 缓存:Redis ---
      REDIS_HOST: redis
      REDIS_PORT: 6379
      REDIS_AUTH: myredissecret
      # --- 对象存储:MinIO(S3 兼容),存事件原始 payload + 多模态文件 ---
      LANGFUSE_S3_EVENT_UPLOAD_BUCKET: langfuse
      LANGFUSE_S3_EVENT_UPLOAD_REGION: auto
      LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT: http://minio:9000
      LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID: minio
      LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY: miniosecret
      LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE: "true"  # MinIO 必须开 path style
      # --- 安全密钥(关键,见下文)---
      NEXTAUTH_URL: http://localhost:3000
      NEXTAUTH_SECRET: CHANGE_ME_openssl_rand_base64_32   # 会话签名,部署后别乱改
      SALT: CHANGE_ME_openssl_rand_base64_32              # API key 哈希盐
      ENCRYPTION_KEY: CHANGE_ME_openssl_rand_hex_32        # 必须是 64 位十六进制(256bit)
    restart: always

  langfuse-worker:
    image: langfuse/langfuse-worker:3       # 异步消费队列、落库与聚合
    depends_on:
      postgres: { condition: service_healthy }
      clickhouse: { condition: service_healthy }
      redis: { condition: service_healthy }
      minio: { condition: service_healthy }
    environment:
      <<: *langfuse-env                     # 复用上面整组环境变量
    restart: always

  # ---------- 后端存储 ----------
  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: postgres
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 10
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: always

  clickhouse:
    image: clickhouse/clickhouse-server:24.3
    environment:
      CLICKHOUSE_USER: clickhouse
      CLICKHOUSE_PASSWORD: clickhouse
    healthcheck:
      test: ["CMD", "wget", "--spider", "-q", "http://localhost:8123/ping"]
      interval: 5s
      timeout: 5s
      retries: 10
    ulimits:                                # ClickHouse 需要更高的文件句柄上限
      nofile: { soft: 262144, hard: 262144 }
    volumes:
      - clickhouse_data:/var/lib/clickhouse
    restart: always

  redis:
    image: redis:7
    command: --requirepass myredissecret    # 与 REDIS_AUTH 保持一致
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "myredissecret", "ping"]
      interval: 5s
      timeout: 5s
      retries: 10
    restart: always

  minio:
    image: minio/minio
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: minio
      MINIO_ROOT_PASSWORD: miniosecret
    healthcheck:
      test: ["CMD", "mc", "ready", "local"]
      interval: 5s
      timeout: 5s
      retries: 10
    ports:
      - "9001:9001"                         # MinIO 控制台,用于建 langfuse bucket
    volumes:
      - minio_data:/data
    restart: always

volumes:
  postgres_data:
  clickhouse_data:
  minio_data:
# 生成三把密钥(把输出分别填进 docker-compose.yml)
openssl rand -base64 32   # -> NEXTAUTH_SECRET
openssl rand -base64 32   # -> SALT
openssl rand -hex 32      # -> ENCRYPTION_KEY  (64 hex chars = 256-bit,长度错会启动失败)

# 启动全部组件
docker compose up -d

# 跟踪 web 进程日志,等到出现 "Ready" / 监听 3000 即可访问
docker compose logs -f langfuse-web

# 浏览器打开 http://localhost:3000 注册第一个账号(自托管首个用户即管理员)
# 别忘了去 http://localhost:9001 用 minio/miniosecret 登录,新建名为 langfuse 的 bucket

拿到三把钥匙:PUBLIC_KEY / SECRET_KEY / HOST

  1. 登录 Langfuse(Cloud 用 cloud.langfuse.com / us.cloud.langfuse.com;自托管用你的 http://localhost:3000)。
  2. 创建一个 Organization,再在其下创建一个 Project —— 所有 trace 都归属到某个 project。
  3. 进入该 Project 的 Settings → API Keys 页面,点击 Create new API keys。
  4. 页面会一次性展示 Public Key(pk-lf-...)和 Secret Key(sk-lf-...),Secret Key 只显示这一次,立刻复制保存。
  5. 确认 Host:Cloud EU 为 https://cloud.langfuse.com,Cloud US 为 https://us.cloud.langfuse.com,自托管填你自己的地址(如 http://localhost:3000)。

pip 安装与 .env 配置,跑通验证

# 安装 Python SDK(v3,对应自托管 v3 / 当前 Cloud)
pip install langfuse

# 如果你要用 OpenAI 直替式集成(后续章节会讲),顺手装上 openai
pip install openai

# 在项目根目录创建 .env —— SDK 默认会从环境变量读取这三把钥匙
cat > .env <<'EOF'
LANGFUSE_PUBLIC_KEY=pk-lf-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
LANGFUSE_SECRET_KEY=sk-lf-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# Cloud EU: https://cloud.langfuse.com  | Cloud US: https://us.cloud.langfuse.com
# 自托管: http://localhost:3000
LANGFUSE_HOST=http://localhost:3000
EOF
# verify_setup.py —— 验证安装与连通性的最小可运行示例
# 运行前先:pip install langfuse python-dotenv,并填好 .env
from dotenv import load_dotenv
load_dotenv()  # 把 .env 注入环境变量;之后 get_client() 会自动读取

from langfuse import get_client

# get_client() 从环境变量读取 LANGFUSE_PUBLIC_KEY / SECRET_KEY / HOST
# 返回进程内单例客户端,无需手动传 key
langfuse = get_client()

# 1) 鉴权与连通性自检:凭证或 HOST 错误时返回 False
assert langfuse.auth_check(), "鉴权失败:检查 PUBLIC/SECRET KEY 与 HOST 是否正确"
print("auth_check 通过,凭证与 HOST 配置正确")

# 2) 用上下文管理器创建第一条 span,验证能真正写入一条 trace
with langfuse.start_as_current_span(name="setup-verification") as span:
    # update_trace 给整条 trace 打上元信息,便于在 UI 里检索
    span.update_trace(
        input={"task": "verify installation"},
        output={"status": "ok"},
        tags=["setup", "smoke-test"],
    )
    print("已创建 trace:", langfuse.get_current_trace_id())

# 3) SDK 异步批量上报,进程退出前务必 flush,否则数据可能丢
langfuse.flush()
print("已 flush,去 Langfuse UI 的 Tracing 页面应能看到 setup-verification")
推荐做法
  • openssl rand 生成 NEXTAUTH_SECRET / SALT / ENCRYPTION_KEY,并妥善备份
  • 把 LANGFUSE_SECRET_KEY 放进 .env 并将 .env 加入 .gitignore
  • 接入第一天就定好 region / HOST,避免后期数据分裂
  • 短脚本结尾调用 langfuse.flush() 或用 with 上下文确保上报
  • 自托管启动后先去 MinIO 控制台手动建好 langfuse bucket
不推荐
  • 不要把 sk-lf- 开头的 Secret Key 提交进 Git 或塞进前端代码
  • 不要部署后修改 NEXTAUTH_SECRET / ENCRYPTION_KEY(会让会话失效、加密字段不可解)
  • 不要给 ENCRYPTION_KEY 用非 64 位十六进制的随机串(会直接启动失败)
  • 不要在单机部署里开启 CLICKHOUSE_CLUSTER_ENABLED
  • 不要只起 langfuse-web 而漏掉 langfuse-worker(trace 会进不了库)
常见误区
  • 漏建 MinIO bucket → worker 报 NoSuchBucket,trace 写不进去
  • REDIS_AUTH 与 redis 容器的 requirepass 不一致 → web/worker 连不上队列
  • 脚本没 flush → 代码无报错但 UI 看不到 trace

运行 verify_setup.py,auth_check 返回 True,且能在 Langfuse UI 的 Tracing 列表看到 setup-verification 这条 trace。


环境已就绪、第一条 trace 也跑通了。下一章我们拆开 Langfuse 的数据模型,把 Trace / Span / Generation 三个核心对象讲透——这是后面所有 tracing、prompt 管理、评估能力的地基。