SSD Nodes Learn Hosting plans →
Hướng dẫn Matt ConnorBởi Matt Connor

Tự host Langfuse để trace AI agent trên VPS

Hướng dẫn tự host Langfuse trên VPS: mức tài nguyên tối thiểu thực tế, pin image tag, cấu hình TLS, retention ClickHouse và backup dùng được.

Vì sao phải trace AI agent

Bạn tự host Langfuse để xem agent thực sự đã làm gì trong một lần chạy. Langfuse là công cụ observability mã nguồn mở cho LLM (large language model). Công cụ này ghi lại mọi prompt, mọi phản hồi của model, mọi lần gọi tool và mọi token, rồi nhóm chúng vào một trace duy nhất để bạn mở và đọc. Chạy Langfuse trên VPS của bạn nghĩa là các prompt đó không rời khỏi server do bạn kiểm soát.

Lý do cần làm việc này rất rõ ràng. Bạn không thể xử lý vấn đề chi phí hoặc chất lượng nếu không nhìn thấy nguyên nhân. Hóa đơn của provider cho biết chi phí vào thứ Ba cao gấp 4 lần thứ Hai. Trace cho biết lần chạy agent nào gây ra việc đó, prompt nào tăng lên 40,000 token và vòng retry nào đã chạy 9 lần trước khi bỏ cuộc. Hóa đơn cho bạn con số. Trace cho bạn đoạn code tạo ra con số đó.

Hướng dẫn này sử dụng 3 thuật ngữ. Trace là một lần chạy end-to-end của agent. Observation là một bước trong lần chạy đó: span dành cho code thông thường, generation dành cho lần gọi model. Score là một con số gắn với trace, do người review hoặc evaluator tự động tạo ra. Langfuse sử dụng OpenTelemetry (OTel), tiêu chuẩn trung lập với vendor dành cho distributed tracing, nên instrumentation bạn đã có có thể trỏ đến Langfuse.

Langfuse self-hosting thực sự chạy những gì

Langfuse v4 không chỉ gồm một container. Nó gồm hai application container và bốn storage service. Trên một VPS đơn, cả sáu thành phần này đều chạy trên máy của bạn.

  • langfuse-web cung cấp web interface và ingestion API.
  • langfuse-worker xử lý queue ở background. Nó phân tích các ingestion batch, tính cost và chạy retention job hằng đêm.
  • Postgres lưu dữ liệu giao dịch như user, organisation, project, API key và prompt.
  • ClickHouse lưu chính trace data, gồm observation và score. Đây là column store được xây dựng cho analytical query, nên dashboard trên hơn một trăm triệu row vẫn trả kết quả nhanh.
  • Redis là queue và cache nằm giữa web và worker.
  • MinIO cung cấp S3 compatible object storage ngay trên máy. Nó lưu mọi raw event nhận vào cùng media mà bạn đính kèm.

Langfuse công bố resource tối thiểu cho từng component mà nó chạy. Biểu đồ hiển thị ba component thực hiện phần xử lý.

Biểu đồLangfuse published minimum resources per component
Dữ liệu đằng sau biểu đồ này
[
  {
    "label": "ClickHouse",
    "cpu_cores": 2,
    "memory_gib": 8
  },
  {
    "label": "Langfuse web",
    "cpu_cores": 2,
    "memory_gib": 4
  },
  {
    "label": "Langfuse worker",
    "cpu_cores": 2,
    "memory_gib": 4
  }
]

Riêng ClickHouse cần 8 GiB memory. Web container và worker mỗi component cần 4 GiB. Đây là các mức tối thiểu được công bố cho 3 component trong biểu đồ. Trang này cũng ghi Postgres cần 4 GiB, Redis hoặc Valkey cần 1.5 GiB và MinIO cần 4 GiB. Vì vậy, mức tối thiểu cho cả sáu component cộng lại là 25.5 GiB. Hướng dẫn Docker Compose của chính project khuyến nghị ít nhất 4 core, 16 GiB memory và khoảng 100 GiB storage cho một máy đơn. Mức này thấp hơn tổng mức tối thiểu của các component, nên hãy xem 16 GiB là mức thấp nhất mà một máy Compose dùng chung cần có, không phải phần headroom.

Không nên chạy cấu hình này trên plan 2 GiB. ClickHouse sẽ khởi động và nhận write trong một thời gian, rồi dừng trong lúc background merge chạy, vì merge phải load các part lớn của table vào memory. Bạn sẽ thấy docker compose ps báo container clickhouse ở trạng thái restarting, dmesg chứa một dòng như Out of memory: Killed process 1234 (clickhouse-serv), và mọi Langfuse dashboard đều trả về 500. Khi tải nhẹ hơn, ClickHouse sẽ từ chối query thay vào đó và ghi log DB::Exception: Memory limit (total) exceeded. Hãy lập kế hoạch với 16 GiB. Nếu cùng VPS còn phải chạy việc khác, hãy cộng thêm resource riêng cho phần đó, vì ngay cả stack tương đối nhẹ như một workspace AFFiNE tự host cũng cần vài GiB riêng, còn ClickHouse sẽ không trả lại phần memory nào.

Triển khai Langfuse bằng Docker Compose

Clone repository. Stack, cách kết nối các thành phần và environment mặc định đều nằm trong docker-compose.yml.

git clone https://github.com/langfuse/langfuse.git
cd langfuse

Mọi giá trị bạn phải thay đều được đánh dấu # CHANGEME trong file đó. Trước tiên, hãy tạo 3 application secret.

openssl rand -base64 32   # NEXTAUTH_SECRET
openssl rand -base64 32   # SALT
openssl rand -hex 32      # ENCRYPTION_KEY

ENCRYPTION_KEY phải có độ dài 256 bit và được viết thành 64 ký tự hex. Đây chính xác là định dạng mà openssl rand -hex 32 in ra. Nó mã hóa các giá trị nhạy cảm khi lưu trữ, bao gồm mọi LLM provider key bạn lưu trong instance. Nếu thay đổi sau khi đã có dữ liệu, các bản ghi đó sẽ không thể giải mã. Vì vậy, hãy xem giá trị này là cố định ngay từ lần boot đầu tiên. SALT được dùng để hash Langfuse API key. Thay đổi nó sẽ vô hiệu hóa mọi key mà các agent đang sử dụng.

Tiếp theo, đặt POSTGRES_PASSWORD, CLICKHOUSE_PASSWORD, REDIS_AUTH và MINIO_ROOT_PASSWORD. Mật khẩu MinIO xuất hiện ở 4 vị trí: một lần dưới dạng MINIO_ROOT_PASSWORD, sau đó là LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY, LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY và LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY. Chỉ cần bỏ sót một vị trí là MinIO sẽ từ chối client đó với SignatureDoesNotMatch. Lỗi này xuất hiện trong worker log, trong khi web interface vẫn có vẻ bình thường. Lưu các giá trị này trong env file thay vì compose file được track là cách làm được trình bày trong env file và secret của Docker Compose.

Ghim image tag trước khi bắt đầu

File được cung cấp dùng docker.langfuse.com/langfuse/langfuse:4 và docker.langfuse.com/langfuse/langfuse-worker:4. Các tag này có thể thay đổi. Langfuse tự động chạy migration cho Postgres và ClickHouse khi khởi động. Vì vậy, một docker compose pull thông thường vài tháng sau có thể trở thành migration schema ngoài kế hoạch trên database mà sáng hôm đó bạn chưa backup. Ghim cả 2 image vào một release trong docker-compose.override.yml. Compose sẽ merge file này lên trên file được cung cấp, nên một git pull sau đó sẽ không ghi đè các chỉnh sửa của bạn. Các image tương tự được publish trên Docker Hub; file override bên dưới sẽ pull image từ đó.

services:
  langfuse-web:
    image: docker.io/langfuse/langfuse:4.72.0
  langfuse-worker:
    image: docker.io/langfuse/langfuse-worker:4.72.0

Version 4.3.1 là bản hiện tại của nhánh 4.3 vào tháng 8 năm 2026. Các release sau đó được phát hành nhanh, và v4.56.0 là bản mới nhất trên GitHub vào ngày 11 tháng 10 năm 2026. File override bên trên dùng v4.72.0, bản mới nhất trên GitHub vào ngày 31 tháng 10 năm 2026. Hãy kiểm tra trang GitHub releases của project, ghim bản hiện tại vào ngày bạn triển khai, rồi chủ động cập nhật con số đó sau này. Một số storage image trong file được cung cấp cũng nên được xử lý tương tự vì tag của chúng cũng thay đổi. postgres:17 (giá trị mặc định của biến POSTGRES_VERSION) và redis:7 đi theo major version. File được cung cấp hiện dùng exact version tag cho docker.io/clickhouse/clickhouse-server, nhờ đó ghim chính xác phiên bản ClickHouse. Quy tắc này không chỉ áp dụng cho Langfuse: trình theo dõi bài tập openGym tự host chỉ chạy một phần của stack này nhưng vẫn cần một git tag cụ thể, vì bất kỳ ứng dụng nào tự migration database khi khởi động đều có thể biến một lần pull thông thường thành thay đổi schema.

Khởi động stack.

docker compose up -d
docker compose ps
docker compose logs -f langfuse-worker

Lần boot đầu tiên sẽ chạy migration, vì vậy hãy chờ 2 hoặc 3 phút trước khi kiểm tra phản hồi. Web container ghi Ready vào log sau khi khởi động xong. docker compose ps phải liệt kê 6 service ở trạng thái running. Nếu một container restart liên tục, log của nó sẽ cho biết nguyên nhân. ClickHouse migration được áp dụng khi web container khởi động. Vì vậy, CLICKHOUSE_MIGRATION_URL sai sẽ xuất hiện trong docker compose logs langfuse-web, không phải trong worker log mà bạn đang tail. Biến đó dùng ClickHouse native protocol trên port 9000, không phải HTTP port 8123. Trỏ biến này vào 8123 sẽ làm web container lỗi khi chạy startup migration. Worker chạy các background migration chậm hơn, nên log của worker là nơi ghi kết quả của các migration đó.

Kiểm tra health ngay trên máy chủ.

curl -s "http://localhost:3000/api/public/health?failIfDatabaseUnavailable=true"
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/api/public/ready

Một lệnh gọi /api/public/health đơn giản chỉ chứng minh API process đang chạy, vì mặc định nó không kiểm tra database. Dạng failIfDatabaseUnavailable=true là endpoint phù hợp để monitor, và nó trả về 503 khi không thể truy cập database. /api/public/ready trả về 200 khi web container sẵn sàng nhận traffic, và trả về 500 sau khi container được yêu cầu shutdown. Cả 2 đều là HTTP check thông thường, nên trang trạng thái Uptime Kuma có thể monitor các endpoint này và báo cho bạn biết stack đã down trước khi agent phát hiện.

Đặt TLS phía trước và đóng các cổng thừa

File compose đi kèm publish 3000:3000 cho web container và 9090:9000 cho MinIO. Cả hai đều bind trên mọi interface. Trên một public IP, điều đó có nghĩa là bất kỳ ai scan cổng 3000 đều truy cập được trang đăng ký, còn bất kỳ ai scan cổng 9090 đều đang truy cập bucket chứa các prompt thô của bạn.

Chỉ thêm firewall rule thì không đóng được các cổng này. Docker tự ghi các DNAT rule vào nat table. Các rule đó được xử lý trước khi packet đi đến filter rule của ufw, nên ufw deny 3000 vẫn để cổng đã publish mở. Tình huống này xảy ra đủ thường xuyên để có hẳn một hướng dẫn riêng: vì sao cổng do Docker publish bypass ufw. Thay vào đó, hãy bind vào loopback trong file override. Dùng !override với Docker Compose 2.24.4 trở lên để thay thế các cổng đã publish; một list thông thường sẽ merge với các binding ban đầu.

services:
  langfuse-web:
    ports: !override
      - "127.0.0.1:3000:3000"
    environment:
      NEXTAUTH_URL: https://langfuse.example.com
  minio:
    ports: !override
      - "127.0.0.1:9090:9000"
      - "127.0.0.1:9091:9001"

NEXTAUTH_URL phải là public address chính xác, bao gồm cả scheme, vì login flow tạo callback URL từ giá trị này. Nếu để là http://localhost:3000 phía sau HTTPS proxy, round trip đăng nhập sẽ đưa browser đến một địa chỉ mà nó không thể truy cập.

Bây giờ trỏ reverse proxy đến 127.0.0.1:3000 và để proxy quản lý certificate. Nếu dùng Traefik trong cùng Compose project, hãy route đến langfuse-web:3000 qua Compose network bằng các label được trình bày trong chạy nhiều ứng dụng phía sau một Traefik reverse proxy. Nếu Langfuse là ứng dụng duy nhất trên máy, Caddy thực hiện việc này chỉ với hai dòng. Xác minh bằng curl -sI https://langfuse.example.com/api/public/ready, sau đó dùng máy thứ hai để xác nhận rằng curl http://YOUR_IP:3000 không thể kết nối.

Có một điểm cần lưu ý về MinIO. Langfuse cấp presigned URL trỏ đến S3 endpoint đó cho cả SDK upload media và browser tải media. Vì vậy, nếu bạn dùng trace đa phương thức có image hoặc audio, MinIO chỉ bind trên loopback sẽ khiến attachment không upload được từ máy khác và không load được trong browser. Hãy đọc trang cấu hình blob storage trước khi proxy MinIO, vì endpoint được ghi trong presigned URL, LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT, phải khớp với endpoint bạn publish. Trace dạng plain text không bị ảnh hưởng.

Hãy tạo account trong lần truy cập đầu tiên, sau đó giữ instance chỉ thuộc quyền của bạn. Đặt AUTH_DISABLE_SIGNUP=true sau khi account đã tồn tại để người lạ truy cập trang không thể đăng ký. Langfuse cũng có LANGFUSE_ALLOWED_ORGANIZATION_CREATORS để giới hạn những ai được tạo organisation, nhưng đây là tính năng của Enterprise Edition và chỉ có hiệu lực khi có license key. Nếu bạn đã chạy Authentik làm identity provider của riêng mình, Langfuse hỗ trợ kết nối OIDC tiêu chuẩn. Khi đó account được tạo và xóa cùng các app khác, thay vì nằm trong một danh sách password chỉ instance này biết.

Gửi trace đầu tiên của bạn

Tạo một project trong web interface rồi sao chép public key và secret key từ phần cài đặt của project. Python SDK đọc 3 biến môi trường.

export LANGFUSE_PUBLIC_KEY="pk-lf-..."
export LANGFUSE_SECRET_KEY="sk-lf-..."
export LANGFUSE_BASE_URL="https://langfuse.example.com"

LANGFUSE_BASE_URL là tên biến trong SDK v4, được release vào tháng 3 năm 2026. Code cũ và các guide cũ dùng LANGFUSE_HOST. Nếu trace được gửi đến Langfuse Cloud thay vì server của bạn, nguyên nhân là base URL chưa được set, vì giá trị mặc định trỏ đến instance được host sẵn.

Python SDK v5 hiện tại yêu cầu Python 3.11 trở lên và Langfuse v4.59.0 self-hosted trở lên. Server đã pin ở trên đáp ứng các yêu cầu này.

pip install langfuse opentelemetry-instrumentation-anthropic anthropic
import os
from anthropic import Anthropic
from langfuse import get_client, observe
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor

AnthropicInstrumentor().instrument()
langfuse = get_client()
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

@observe(as_type="tool")
def lookup_order(order_id: str) -> str:
    return f"order {order_id}: shipped"

@observe()
def handle_request(question: str) -> str:
    context = lookup_order("A-1042")
    message = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=512,
        messages=[{"role": "user", "content": f"{context}\n\n{question}"}],
    )
    return message.content[0].text

if __name__ == "__main__":
    assert langfuse.auth_check()
    print(handle_request("Where is my order?"))
    langfuse.flush()

Decorator @observe mở một observation quanh function, thu thập các argument và giá trị trả về của function, rồi lồng observation đó dưới observation đang active. AnthropicInstrumentor là phần instrumentation của OpenTelemetry cho Anthropic client. Nó biến mỗi lần gọi messages.create thành một generation chứa tên model, lượng token đã dùng và latency, mà không cần thay đổi code tại vị trí gọi.

Hai lệnh gọi này thực hiện bước kiểm tra thay cho bạn. langfuse.auth_check() trả về False nếu key không hợp lệ hoặc base URL sai. Cách này nhanh hơn việc phải đoán tại sao dashboard trống. langfuse.flush() chặn cho đến khi các span đang xếp hàng được gửi đi. Lệnh này cần thiết với các process chạy trong thời gian ngắn, vì SDK gửi theo batch ở background và một script thoát ngay sẽ kết thúc cùng batch chưa được gửi. Nếu cả team gửi trace thay vì chỉ một script, hãy set 3 biến này một lần trong gateway mà các agent đã đi qua, thay vì set trong shell của từng người. Đây là cách một harness OneCLI self-hosted giữ instrumentation cho các lần chạy của mọi thành viên mà vẫn tập trung key ở một nơi.

Vì sao ClickHouse cứ tiếp tục tăng dung lượng?

Trace là loại dữ liệu tăng nhanh nhất mà nhiều người từng tự host. Mỗi lần agent chạy sẽ ghi một dòng cho mỗi bước. Input và output được lưu đầy đủ, nên agent có nhiều tương tác và prompt dài có thể tạo ra nhiều byte mỗi ngày hơn cả ứng dụng mà nó đang giám sát. Nếu không xử lý, ClickHouse sẽ làm đầy disk. Khi disk đầy, ingestion sẽ dừng thay vì chỉ chậm lại.

Ở đây có 2 loại dữ liệu tăng riêng biệt, và cần 2 cách xử lý riêng.

Loại thứ nhất là dữ liệu trace của chính bạn. Cách xử lý là cấu hình retention. Trên instance tự host, retention dữ liệu là tính năng của Enterprise Edition và cần license key. Nếu không có license key, Langfuse giữ trace, observation, score và media vô thời hạn. Bạn phải tính dung lượng disk cho trường hợp này và dựa vào disk alert ở cuối section này. Khi có license, project owner và admin mở project settings rồi đặt thời hạn retention dữ liệu theo số ngày. Langfuse chấp nhận tối thiểu 3 ngày. Mỗi đêm, một job sẽ chọn các trace, observation, score và media asset cũ hơn khoảng thời gian này rồi xóa chúng khỏi ClickHouse và blob storage, ngoại trừ media gắn với các dataset item đã lưu. Job cần quyền DeleteObject trên bucket. Các MinIO root credential trong file compose mặc định đã có quyền này. Xóa là thao tác không thể hoàn tác, nên hãy cấu hình blob storage export trước nếu cần lưu lịch sử dài hạn. Không tự viết các mệnh đề TTL trên table riêng của Langfuse. Retention job giúp ClickHouse và bucket luôn đồng bộ, còn TTL thủ công chỉ xóa dữ liệu ở một phía.

Chọn khoảng thời gian dựa trên cách bạn thực tế sử dụng dữ liệu. Việc đánh giá cost và quality thường dùng dữ liệu vài ngày trước, không phải dữ liệu vài tháng trước. 30 ngày là mốc khởi đầu hợp lý cho team nhỏ. 14 ngày là đủ nếu bạn chỉ mở trace khi có lỗi.

Loại thứ hai là các system log table của ClickHouse. Điều này thường khiến nhiều người bất ngờ, vì disk vẫn tiếp tục tăng sau khi đã cấu hình retention. ClickHouse ghi trace_log, text_log, opentelemetry_span_log, metric_log, asynchronous_metric_log và latency_log để phục vụ chẩn đoán của chính nó. Các table này không có TTL mặc định và Langfuse không bao giờ đọc chúng. Trước tiên, hãy xác định chính xác disk đã được dùng vào đâu.

SELECT table, formatReadableSize(size) AS size, rows FROM (
    SELECT table, database, sum(bytes) AS size, sum(rows) AS rows
    FROM system.parts
    WHERE active
    GROUP BY table, database
    ORDER BY size DESC
)

Chạy lệnh đó với docker compose exec clickhouse clickhouse-client --password "$CLICKHOUSE_PASSWORD". Nếu các system table nằm gần đầu danh sách, hãy tắt chúng bằng config overlay, vì ClickHouse sẽ merge mọi file trong /etc/clickhouse-server/config.d/ lên config chính khi khởi động.

<clickhouse>
    <trace_log remove="1"/>
    <text_log remove="1"/>
    <opentelemetry_span_log remove="1"/>
    <asynchronous_metric_log remove="1"/>
    <metric_log remove="1"/>
    <latency_log remove="1"/>
</clickhouse>

Mount file đó rồi restart ClickHouse.

services:
  clickhouse:
    volumes:
      - ./clickhouse-config.d/system-logs.xml:/etc/clickhouse-server/config.d/system-logs.xml:ro

Cách này ngăn các lần ghi mới. Các row đã có trên disk vẫn còn, nên hãy reclaim dung lượng rõ ràng bằng DROP TABLE IF EXISTS system.trace_log và thực hiện tương tự cho từng table đã xóa. Nếu muốn giữ lại dữ liệu chẩn đoán, bạn có thể dùng TTL tích cực trên từng table thay cho remove="1". Langfuse scaling docs có hướng dẫn cụ thể cho cách này. Các chỉ thị TTL đó chỉ có hiệu lực khi system table được tạo lần đầu. Vì vậy, trên một installation hiện có, cùng tài liệu đó cũng hướng dẫn cách retrofit các table.

Có thêm một table đáng biết. blob_storage_file_log theo dõi các event file được upload lên bucket. Nếu bạn cũng đặt lifecycle policy trên bucket, hãy đặt TTL tương ứng cho table để 2 bên không bị lệch dữ liệu.

ALTER TABLE blob_storage_file_log MODIFY TTL created_at + INTERVAL 30 DAY DELETE;

Đồng thời, hãy đặt alert df -h cho data disk. Trace không tăng đều. Dung lượng có thể tăng mạnh vào ngày bạn release một agent mới. Dấu hiệu đầu tiên của việc đó không nên là ingestion bị fail.

Sao lưu Postgres và ClickHouse

Một bản sao lưu Langfuse có ba phần. Postgres lưu người dùng, tổ chức, project và API key. ClickHouse lưu trace. MinIO lưu event thô. Chỉ restore Postgres thì bạn có thể đăng nhập nhưng không có lịch sử. Chỉ restore ClickHouse thì bạn có lịch sử nhưng không ai đăng nhập để xem được. Cách phân tách này không riêng gì Langfuse; một help desk Chatwoot tự host cũng có cấu trúc tương tự. Nếu dump Postgres nhưng không sao lưu thư mục uploads, các conversation được restore sẽ mất toàn bộ file đính kèm.

Postgres là một pg_dump đơn giản. Đây cũng là cách các tài liệu backup của Langfuse dùng cho cài đặt Docker.

docker compose exec -T postgres pg_dump -U postgres postgres \
  | gzip > langfuse-pg-$(date +%F).sql.gz

ClickHouse cần cẩn thận hơn, vì copy một data directory đang có merge chạy sẽ không tạo ra bản sao lưu nhất quán. Cách đơn giản trên một máy là stop container rồi archive volume.

docker compose stop clickhouse
docker volume ls | grep clickhouse
docker run --rm -v langfuse_langfuse_clickhouse_data:/data -v "$PWD":/backup alpine \
  tar czf /backup/langfuse-ch-$(date +%F).tar.gz -C /data .
docker compose start clickhouse

Dùng tên volume mà docker volume ls hiển thị, không dùng tên được viết trong YAML. File khai báo langfuse_clickhouse_data, còn Compose thêm project name vào trước tên đó. Vì vậy, một bản clone trong thư mục tên langfuse sẽ tạo ra langfuse_langfuse_clickhouse_data. Nếu dùng sai tên, docker run sẽ tạo volume mới, rỗng mà không báo lỗi, và archive của bạn sẽ không có dữ liệu.

Langfuse upload dữ liệu event thô lên bucket trong mỗi ingestion request, rồi đọc lại dữ liệu đó để retry các ingestion job bị lỗi. Vì vậy, việc stop ClickHouse trong thời gian ngắn chủ yếu khiến worker retry sau đó. Hãy thực hiện vào giờ ít tải và giữ thời gian stop ngắn. Với instance bận hơn, statement BACKUP DATABASE default TO S3(...) của ClickHouse sẽ ghi một bản sao lưu nhất quán mà không cần stop server. MinIO là phần thứ ba; mc mirror hoặc cơ chế replication của MinIO đến bucket bên ngoài server sẽ xử lý phần này. Dù tạo bản sao lưu theo cách nào, hãy đưa nó ra khỏi server. Đây là mục đích của backup restic được mã hóa trên VPS.

Redis lưu queue và cache. Mất Redis sẽ loại bỏ các job đang chờ, ngay cả khi file event thô vẫn còn trong bucket.

Cần nói rõ về vấn đề nhất quán này. Postgres và ClickHouse được dump tại các thời điểm khác nhau, nên khi restore có thể xảy ra tình trạng một project có row nhưng không có trace, hoặc có trace thuộc về một project đã không còn tồn tại. Langfuse chịu được tình trạng này, nhưng hãy tạo hai bản dump gần nhau và trong thời điểm ít traffic. Event bucket mới là lớp an toàn thực sự, vì Langfuse upload dữ liệu event thô vào đó trong mỗi ingestion request.

Hãy restore vào một scratch stack ít nhất một lần. Đây là cách phát hiện tên volume bị sai ngay bây giờ, thay vì trong lúc xảy ra outage.

Điều cần xem trước tiên

Bốn mục này nên được thiết lập ngay trong tuần đầu tiên.

  • Chi phí trên mỗi trace. Langfuse tính chi phí dựa trên tên model và lượng token đã sử dụng, vì vậy hãy sắp xếp các trace theo chi phí rồi đọc từ đầu đến cuối trace tốn kém nhất. Nguyên nhân thường là prompt đã phình to: toàn bộ tài liệu bị dán vào context hoặc lịch sử hội thoại không được cắt bớt. Khi đã nhìn thấy nguyên nhân, kiểm soát chi phí của AI agent trở thành một công việc kỹ thuật thay vì phỏng đoán.
  • Lượng token tách theo input và output. Input token thường nhiều và rẻ, output token ít hơn nhưng đắt hơn, còn input được cache thì rẻ hơn nữa. Cách tính tương tự được trình bày trong cách tính lượng token của Claude Code, và áp dụng cho mọi agent do bạn tự viết.
  • Các percentile của latency. Median che khuất vấn đề. p95 và p99 là nơi các timeout xảy ra, và trong một vòng lặp agent, một tool call chậm ở p95 sẽ bị nhân lên theo số lần lặp.
  • Các tool call thất bại. Lọc các observation theo level ERROR. Một tool thất bại 5% số lần sẽ khó thấy trong tỷ lệ thành công tổng thể, nhưng rất rõ trong trace, nơi bạn có thể theo dõi model retry rồi tiêu tốn token để xử lý vòng.

Hãy đặt retention window và chọn dashboard mà bạn sẽ kiểm tra hằng tuần vào cùng ngày bạn deploy. Một công cụ observability không ai mở sẽ trở thành database làm đầy disk.

FAQ

Langfuse tự host cần bao nhiêu memory?

Dự trù 4 CPU core và 16 GiB memory. Đây là mức mà hướng dẫn Langfuse Docker Compose khuyến nghị cho một virtual machine, cùng khoảng 100 GiB storage. Mức tối thiểu được công bố cho ClickHouse là 8 GiB, còn web container và worker container cần 4 GiB mỗi container. Trang này cũng ghi 4 GiB cho Postgres, 1.5 GiB cho Redis và 4 GiB cho MinIO. Như vậy, cả sáu thành phần cần tổng cộng 25.5 GiB, cao hơn mức 16 GiB được khuyến nghị cho Compose.

Vì sao disk ClickHouse vẫn đầy sau khi tôi đặt data retention?

Thiết lập retention chỉ áp dụng cho dữ liệu của Langfuse. ClickHouse vẫn ghi riêng các bảng chẩn đoán trace_log, text_log, opentelemetry_span_log, metric_log, asynchronous_metric_log và latency_log. Các bảng này không có TTL mặc định. Chạy truy vấn system.parts và nhóm theo bảng để xem bảng nào lớn nhất. Sau đó, tắt các bảng không dùng bằng một mục remove="1" trong file bên dưới /etc/clickhouse-server/config.d/, restart ClickHouse và xóa các bảng hiện có để thu hồi dung lượng đã sử dụng.

Thời gian lưu dữ liệu tối thiểu trong Langfuse là bao lâu?

Ba ngày. Retention được đặt theo từng project trong phần cài đặt project hoặc thông qua Organization Management API. Một job chạy hằng đêm sẽ xóa trace, observation, score và media asset cũ hơn khoảng thời gian này khỏi cả ClickHouse và blob storage, ngoại trừ media liên kết với các dataset item đã lưu. Trên instance tự host, đây là tính năng Enterprise Edition và cần license key. Nếu không có license key, dữ liệu sẽ được giữ vô thời hạn. Không thể hoàn tác thao tác xóa. Vì vậy, hãy cấu hình blob storage export trước nếu bạn cần giữ lịch sử lâu hơn khoảng thời gian này.

Tôi có phải backup cả Postgres và ClickHouse không?

Có, vì hai hệ thống này lưu các loại dữ liệu khác nhau. Postgres lưu user, organisation, project và API key. ClickHouse lưu chính dữ liệu trace. Nếu chỉ restore Postgres, bạn sẽ có một instance có thể đăng nhập nhưng không có dữ liệu bên trong. Hãy backup cả bucket MinIO, vì bucket này chứa các event thô mà Langfuse lưu ngay khi nhận được. Đây là thành phần gần với source of truth nhất trong stack.

Tôi có thể trỏ setup OpenTelemetry hiện có vào Langfuse tự host không?

Có. Langfuse v4 và các SDK hiện tại của Langfuse được xây dựng trên OpenTelemetry. Các instrumentation OTel cho Anthropic và OpenAI có thể export trực tiếp vào Langfuse. Trong Python, chạy pip install langfuse opentelemetry-instrumentation-anthropic, gọi AnthropicInstrumentor().instrument() một lần khi startup, rồi đặt LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY và LANGFUSE_BASE_URL trỏ đến host của bạn. Xác nhận bằng langfuse.auth_check() trước khi tìm nguyên nhân do thiếu dashboard.

Bài viết này có hữu ích không?