从 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
- 登录 Langfuse(Cloud 用 cloud.langfuse.com / us.cloud.langfuse.com;自托管用你的 http://localhost:3000)。
- 创建一个 Organization,再在其下创建一个 Project —— 所有 trace 都归属到某个 project。
- 进入该 Project 的 Settings → API Keys 页面,点击 Create new API keys。
- 页面会一次性展示 Public Key(
pk-lf-...)和 Secret Key(sk-lf-...),Secret Key 只显示这一次,立刻复制保存。 - 确认 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 管理、评估能力的地基。