ClickHouse HOLs
GitHub

Langfuse on ClickHouse, without Langfuse


Langfuse (open-source LLM observability) keeps its OLTP state in Postgres, but every observation and score lands in ClickHouse. This lab loads a snapshot of that ClickHouse database into a plain ClickHouse server and runs the ClickHouse SQL from the langfuse-hols workshop on it. You need one container. Langfuse, Postgres and Python are not needed.

Verified end to end on 2026-10-06 against ClickHouse 26.8.18.2: tools/hol run passes all four SQL files. The snapshot itself comes from Langfuse 4.52.0, SDK 4.17.0 and ClickHouse 26.8.18.2.

What is in the snapshot

00-data.sql recreates Langfuse's ClickHouse database default:

It is generated by export_snapshot.py from one run of the langfuse-hols v4 track at commit c7901ec:

Table Rows What it holds
events_full 424 One wide row per observation: 240 SPAN, 104 GENERATION, 80 EVALUATOR. 101 of them are trace root rows (is_app_root)
events_core 424 The same rows with input, output and metadata truncated. In Langfuse events_core_mv fills it; the snapshot loads its rows directly and creates the MV last
scores 212 Every quality signal. All of them have source = 'API' (see Limits)
blob_storage_file_log, schema_migrations 212, 100 Langfuse bookkeeping
traces, observations 0 v3 tables: still created by the migrations, but v4 no longer writes to them. 01-explore.sql shows this
dataset_run_items_rmt, observations_batch_staging, observations_pid_tid_sorting 0 Empty in this run

A round trip proves the copy is exact. 00-data.sql was loaded into a fresh clickhouse/clickhouse-server:26.8.18.2, and all 14 objects matched the source on count() and sum(cityHash64(toString(tuple(*)))). As a negative check, a deliberately modified copy showed DIFF, and reloading the file restored the match.

Files

File What it does
00-data.sql Generated snapshot: DDL, raw rows, materialized views created last (1.5 MB)
01-explore.sql Langfuse's tables, engines and sort keys; a trace as its root row (langfuse-ee/03)
02-analytics.sql Cost, latency, tokens and quality as plain ClickHouse SQL (langfuse-ee/04)
03-scores.sql Scores joined to their traces' root rows (langfuse-eval/07)
export_snapshot.py Regenerates 00-data.sql from a running langfuse-hols v4 stack

The three SQL files are copies of the langfuse-hols files at c7901ec. Only their run instructions changed.

Run

tools/hol run usecase/langfuse-on-clickhouse

That starts a throwaway clickhouse/clickhouse-server:26.8.18.2 and runs 00…03 in order. Add --keep to leave it up and query it yourself:

docker exec -it hol-usecase-langfuse-on-clickhouse clickhouse-client

Limits

Regenerate the snapshot

  1. Bring up the langfuse-hols v4 stack. Host ports 8123 and 9000 must be free, so stop a ClickStack or any other local ClickHouse first.
  2. Run the seed commands listed in the header of 00-data.sql, with ANTHROPIC_API_KEY empty.
  3. Run the regenerate command from the same header, then tools/hol run again.

The generator writes byte-identical output for the same data and --date.

Related


Langfuse(오픈소스 LLM 관측 도구)는 OLTP 상태를 Postgres에 두지만, 모든 observation과 score는 ClickHouse에 쌓입니다. 이 실습은 그 ClickHouse 데이터베이스의 스냅샷을 일반 ClickHouse 서버에 올리고, langfuse-hols 워크숍의 ClickHouse SQL을 그 위에서 실행합니다. 컨테이너 하나만 있으면 됩니다. Langfuse, Postgres, Python은 필요 없습니다.

2026-10-06 ClickHouse 26.8.18.2에서 end-to-end 검증: tools/hol run이 SQL 파일 네 개를 모두 통과합니다. 스냅샷 자체는 Langfuse 4.52.0, SDK 4.17.0, ClickHouse 26.8.18.2에서 만들었습니다.

스냅샷에 든 것

00-data.sql은 Langfuse의 ClickHouse 데이터베이스 default를 다시 만듭니다.

이 파일은 export_snapshot.py가 langfuse-hols v4 트랙(커밋 c7901ec)을 한 번 실행한 결과에서 생성했습니다.

테이블 행 내용
events_full 424 observation 하나당 넓은 행 하나: SPAN 240, GENERATION 104, EVALUATOR 80. 그중 101개가 trace의 root 행(is_app_root)
events_core 424 같은 행에서 input, output, metadata를 잘라 낸 사본. Langfuse에서는 events_core_mv가 채우지만, 스냅샷은 행을 직접 넣고 MV는 마지막에 만듦
scores 212 모든 품질 신호. 전부 source = 'API' (한계 참고)
blob_storage_file_log, schema_migrations 212, 100 Langfuse 내부 기록
traces, observations 0 v3 테이블. 마이그레이션이 여전히 만들지만 v4는 쓰지 않음. 01-explore.sql이 이를 보여 줌
dataset_run_items_rmt, observations_batch_staging, observations_pid_tid_sorting 0 이번 실행에서는 비어 있음

사본이 원본과 똑같다는 것은 왕복 검증으로 확인했습니다. 새 clickhouse/clickhouse-server:26.8.18.2에 00-data.sql을 올리자, 14개 객체 모두 count()와 sum(cityHash64(toString(tuple(*))))가 원본과 일치했습니다. 반대 확인으로 일부러 고친 사본은 DIFF가 나왔고, 파일을 다시 올리자 다시 일치했습니다.

파일

파일 하는 일
00-data.sql 생성된 스냅샷: DDL, 원본 행, 마지막에 만드는 materialized view (1.5 MB)
01-explore.sql Langfuse의 테이블, 엔진, 정렬 키. trace가 곧 root 행이라는 것 (langfuse-ee/03)
02-analytics.sql 비용, 지연, 토큰, 품질을 일반 ClickHouse SQL로 (langfuse-ee/04)
03-scores.sql score를 해당 trace의 root 행과 조인 (langfuse-eval/07)
export_snapshot.py 실행 중인 langfuse-hols v4 스택에서 00-data.sql을 다시 생성

SQL 파일 세 개는 langfuse-hols c7901ec의 파일을 그대로 복사했고, 실행 안내만 바꿨습니다.

실행

tools/hol run usecase/langfuse-on-clickhouse

임시 clickhouse/clickhouse-server:26.8.18.2를 띄우고 00…03을 순서대로 실행합니다. --keep을 붙이면 컨테이너가 남아 직접 쿼리할 수 있습니다.

docker exec -it hol-usecase-langfuse-on-clickhouse clickhouse-client

한계

스냅샷 다시 만들기

  1. langfuse-hols v4 스택을 띄웁니다. 호스트 포트 8123과 9000이 비어 있어야 하므로, ClickStack 같은 다른 로컬 ClickHouse가 떠 있으면 먼저 멈춥니다.
  2. 00-data.sql 머리말에 적힌 시드 명령을 ANTHROPIC_API_KEY를 비운 채 실행합니다.
  3. 같은 머리말의 재생성 명령을 실행한 뒤 tools/hol run을 다시 돌립니다.

데이터와 --date가 같으면 생성기는 바이트 단위로 같은 파일을 씁니다.

관련 저장소

Open this lab on GitHub →GitHub에서 이 실습 열기 →