SSD Nodes Learn 🎉 VPS $4.99/মাস থেকে
নির্দেশিকা Matt Connorদ্বারা Matt Connor · আপডেট করা হয়েছে 2026-08-06

নিজের VPS-এ Langfuse চালিয়ে AI agent trace করুন

নিজের VPS-এ Langfuse চালানোর আগে প্রকৃত resource floor, pinned image tag, TLS, ClickHouse retention, disk ভরে যাওয়ার ঝুঁকি এবং কার্যকর backup জানুন।

একটি AI agent-এর কার্যক্রম trace করবেন কেন

কোনো run-এ আপনার agent আসলে কী করেছে তা দেখতে Langfuse নিজে host করুন। Langfuse হলো open source LLM (large language model) observability tool। এটি প্রতিটি prompt, প্রতিটি model response, প্রতিটি tool call এবং প্রতিটি token record করে। এরপর এগুলোকে একটি trace-এর অধীনে group করে, যা আপনি খুলে পড়তে পারেন। এটি নিজের VPS-এ চালালে ওই prompt-গুলো আপনার নিয়ন্ত্রণাধীন server-এর বাইরে যায় না।

এটি করার কারণ সরল। যে cost problem বা quality problem আপনি দেখতে পান না, তা ঠিক করতে পারবেন না। Provider invoice আপনাকে জানায় যে Tuesday-এর খরচ Monday-এর চেয়ে চার গুণ ছিল। একটি trace জানায় কোন agent run-এর কারণে এটি হয়েছে, কোন prompt 40,000 token-এ বেড়েছে এবং হাল ছাড়ার আগে কোন retry loop নয়বার চলেছে। Invoice শুধু সংখ্যাটি দেয়। Trace সেই code দেখায়, যা সংখ্যাটি তৈরি করেছে।

এই guide জুড়ে তিনটি term ব্যবহার করা হয়েছে। Trace হলো আপনার agent-এর একটি end-to-end run। Observation হলো ওই run-এর ভেতরের একটি ধাপ: সাধারণ code-এর জন্য একটি span এবং model call-এর জন্য একটি generation। Score হলো কোনো trace-এর সঙ্গে যুক্ত একটি সংখ্যা, যা human review বা automated evaluator থেকে আসে। Langfuse OpenTelemetry (OTel) ব্যবহার করে। এটি distributed tracing-এর vendor-neutral standard। তাই আপনার আগে থেকেই থাকা instrumentation Langfuse-এ নির্দেশ করা যায়।

Langfuse self-hosting-এ আসলে কী কী চালাতে হয়

Langfuse v4 কোনো একক container নয়। এতে দুটি application container এবং চারটি storage service থাকে। একটি VPS-এ এই ছয়টিই আপনার server-এ চালাতে হবে।

  • langfuse-web web interface এবং ingestion API পরিবেশন করে।
  • langfuse-worker background-এ queue খালি করে। এটি ingestion batch parse করে, cost হিসাব করে এবং প্রতি রাতে retention job চালায়।
  • Postgres users, organisations, projects, API keys এবং prompts-এর মতো transactional data সংরক্ষণ করে।
  • ClickHouse মূল trace data, অর্থাৎ observations এবং scores, সংরক্ষণ করে। এটি analytical query-এর জন্য তৈরি একটি column store। তাই একশো মিলিয়নের বেশি row-এর dashboard-ও দ্রুত উত্তর দিতে পারে।
  • Redis হলো web এবং worker-এর মাঝের queue ও cache।
  • MinIO server-এ S3 compatible object storage দেয়। এটি প্রতিটি raw incoming event এবং আপনার সংযুক্ত যেকোনো media সংরক্ষণ করে।

Langfuse কাজের জন্য ব্যবহৃত তিনটি component-এর minimum resource প্রকাশ করে।

ChartLangfuse published minimum resources per component
The data behind this chart
[
  {
    "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
  }
]

শুধু ClickHouse-এর জন্যই 8 GiB memory দরকার। web container এবং worker-এর জন্য 4 GiB করে দরকার। এগুলো Langfuse যে 3টি component-এর resource requirement নির্ধারণ করেছে, সেগুলোর প্রকাশিত minimum। এর বাইরে Postgres, Redis এবং MinIO-এর জন্যও memory দরকার। প্রকল্পটির নিজস্ব Docker Compose guide 4 core, 16 GiB memory এবং প্রায় 100 GiB storage-সহ একটি machine সুপারিশ করে। এই হিসাবও অতিরিক্ত resource ধরে নেওয়ার বদলে একই প্রয়োজনীয়তার সঙ্গে মেলে।

2 GiB plan-এ এটি চালানোর চেষ্টা করবেন না। ClickHouse শুরু হয় এবং কিছু সময় write গ্রহণ করে। এরপর background merge চলার সময় বন্ধ হয়ে যায়, কারণ merge একটি table-এর বড় অংশ memory-তে load করে। আপনি docker compose ps-এ clickhouse container-কে restarting হিসেবে দেখতে পাবেন, dmesg-এ Out of memory: Killed process 1234 (clickhouse-serv)-এর মতো একটি line থাকবে এবং Langfuse-এর প্রতিটি dashboard 500 ফেরত দেবে। চাপ কম থাকলে ClickHouse query প্রত্যাখ্যান করে এবং DB::Exception: Memory limit (total) exceeded log করে। প্রতিদিন কয়েক হাজার trace পাঠানো একজন developer-এর জন্য 8 GiB ব্যবহারযোগ্য। তবে পরিকল্পনার সময় 16 GiB ধরে এগোনো উচিত।

Docker Compose দিয়ে Langfuse deploy করুন

রিপোজিটরি clone করুন। Stack, wiring এবং default environment সবই এর docker-compose.yml-এ আছে।

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

এই ফাইলে যে প্রতিটি value পরিবর্তন করতে হবে, তা # CHANGEME দিয়ে চিহ্নিত করা আছে। প্রথমে তিনটি application secret তৈরি করুন।

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

ENCRYPTION_KEY-এর মান 256 bits হতে হবে এবং 64টি hexadecimal character হিসেবে লিখতে হবে। openssl rand -hex 32 ঠিক এই format-ই প্রিন্ট করে। এটি at-rest অবস্থায় থাকা sensitive value, including instance-এ সংরক্ষিত LLM provider key, encrypt করে। Data তৈরি হওয়ার পরে এটি পরিবর্তন করলে ওই row-গুলো আর decrypt করা যাবে না। তাই প্রথম boot থেকেই এটিকে স্থায়ী value হিসেবে বিবেচনা করুন। SALT আপনার Langfuse API key hash করতে ব্যবহৃত হয়। এটি পরিবর্তন করলে agent-গুলো ইতিমধ্যে ব্যবহার করছে এমন প্রতিটি key invalid হয়ে যাবে।

এরপর POSTGRES_PASSWORD, CLICKHOUSE_PASSWORD, REDIS_AUTH এবং MINIO_ROOT_PASSWORD সেট করুন। MinIO password চার জায়গায় থাকে: একবার MINIO_ROOT_PASSWORD হিসেবে, এরপর LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY, LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY এবং LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY হিসেবে। কোনো একটি বাদ পড়লে MinIO ওই client-কে SignatureDoesNotMatch দিয়ে প্রত্যাখ্যান করে। এই error worker log-এ দেখা যায়, যদিও web interface তখনও সুস্থ মনে হয়। Tracked compose file-এ value না রেখে env file-এ রাখার পদ্ধতিটি Docker Compose env file এবং secret-এ ব্যাখ্যা করা হয়েছে।

শুরু করার আগে image tag নির্দিষ্ট করুন

সরবরাহ করা ফাইলে langfuse/langfuse:4 এবং langfuse/langfuse-worker:4 ব্যবহার করা হয়েছে। এই tag পরিবর্তিত হতে পারে। Langfuse start হওয়ার সময় Postgres এবং ClickHouse migration স্বয়ংক্রিয়ভাবে চালায়। তাই কয়েক মাস পরে একটি সাধারণ docker compose pull এমন একটি database-এ অনির্ধারিত schema migration ঘটাতে পারে, যেটির backup আপনি সেদিন সকালে নেননি। একটি docker-compose.override.yml-এ উভয় image-কে একই release-এ pin করুন। Compose এটি সরবরাহ করা ফাইলের ওপর merge করে। ফলে পরবর্তী git pull আপনার edit-এর সঙ্গে সংঘাতে যাবে না।

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

August 2026 অনুযায়ী Version 4.3.0 ছিল বর্তমান release। Project-এর GitHub releases page পরীক্ষা করে deploy করার দিন যে version বর্তমান, সেটি pin করুন। এরপর version number ইচ্ছাকৃতভাবে পরিবর্তন করুন। সরবরাহ করা ফাইলে storage image-গুলো ইতিমধ্যে major version-এ pinned আছে: postgres:17, clickhouse-server:25.12 এবং redis:7। এগুলোকেও একইভাবে pin করা উচিত।

Stack চালু করুন।

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

প্রথম boot-এ migration চলে। তাই কোনো endpoint response দেওয়ার আগে এক বা দুই মিনিট অপেক্ষা করুন। docker compose ps-এ running state-এ থাকা ছয়টি service দেখা উচিত। Worker যদি বারবার restart হয়, তার log-এ কারণ থাকবে। CLICKHOUSE_MIGRATION_URL port 9000-এ ClickHouse native protocol ব্যবহার করে, HTTP port 8123 নয়। এটিকে 8123-এ point করলে worker ব্যর্থ হয়, যদিও web container তখনও স্বাভাবিক দেখায়।

সার্ভার থেকেই health পরীক্ষা করুন।

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

সাধারণ /api/public/health call শুধু API process চালু আছে কি না তা নিশ্চিত করে। এটি ইচ্ছাকৃতভাবে database পরীক্ষা করে না, যাতে Postgres সাময়িকভাবে অচল হলেও service request পরিবেশন করতে পারে। failIfDatabaseUnavailable=true form-টি monitor-এর জন্য ব্যবহার করা উচিত। Database unreachable হলে এটি 503 ফেরত দেয়। Migration শেষ হলে /api/public/ready 200 ফেরত দেয় এবং container traffic গ্রহণ করতে প্রস্তুত থাকে। দুটিই সাধারণ HTTP check। তাই একটি Uptime Kuma status page এগুলো monitor করে আপনার agent-এর আগে stack down হওয়ার বিষয়টি জানাতে পারে।

TLS সামনে রাখুন এবং অতিরিক্ত port বন্ধ করুন

প্রদত্ত compose file-এ web container-এর জন্য 3000:3000 এবং MinIO-এর জন্য 9090:9000 প্রকাশ করা থাকে। দুটিই সব interface-এ bind করে। কোনো public IP-তে এর অর্থ হলো, কেউ port 3000 scan করলে আপনার sign-up page-এ পৌঁছে যাবে, আর কেউ 9090 scan করলে আপনার raw prompt রাখা bucket-এ সংযোগ করবে।

শুধু firewall rule ব্যবহার করলে এগুলো বন্ধ হয় না। Docker নিজস্ব DNAT rule-গুলো nat table-এ লেখে। ufw-এর filter rule packet দেখার আগেই সেগুলো কার্যকর হয়। তাই ufw deny 3000 প্রকাশিত port খোলা রাখে। এই সমস্যাটি এত সাধারণ যে এর জন্য আলাদা guide আছে: Docker-এর প্রকাশিত port কেন ufw-এর নিয়ম পাশ কাটায়। আপনার override file-এ এগুলো loopback-এ bind করুন।

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

NEXTAUTH_URL-এ scheme-সহ নির্দিষ্ট public address দিতে হবে। কারণ login flow এই মান থেকে callback URL তৈরি করে। HTTPS proxy-এর পেছনে এটিকে http://localhost:3000 রেখে দিলে sign-in-এর পুরো যাত্রায় browser এমন একটি ঠিকানায় পাঠানো হবে, যেখানে সেটি পৌঁছাতে পারবে না।

এখন 127.0.0.1:3000-এর দিকে একটি reverse proxy নির্দেশ করুন এবং certificate সেটির মাধ্যমে পরিচালনা করুন। একই Compose project-এ থাকা Traefik সাধারণত উপযুক্ত পছন্দ। এর routing label-গুলো একটি Traefik reverse proxy-এর পেছনে একাধিক অ্যাপ চালানো অংশে ব্যাখ্যা করা হয়েছে। Langfuse-ই যদি server-এ একমাত্র অ্যাপ হয়, Caddy দুই লাইনে একই কাজ করতে পারে। curl -sI https://langfuse.example.com/api/public/ready দিয়ে যাচাই করুন। এরপর দ্বিতীয় একটি machine থেকে নিশ্চিত করুন যে curl http://YOUR_IP:3000 এখন timeout হচ্ছে।

MinIO সম্পর্কে একটি গুরুত্বপূর্ণ বিষয় আছে। Langfuse presigned URL-এর মাধ্যমে browser-এ সংযুক্ত media পাঠায় এবং সেই URL-এ ওই S3 endpoint নির্দেশ করা থাকে। তাই image বা audio-সহ multi-modal trace ব্যবহার করলে loopback-only MinIO-এর কারণে attachment লোড হবে না। MinIO proxy করার আগে blob storage configuration page পড়ুন। কারণ presigned URL-এ লেখা endpoint-টি আপনি যে endpoint প্রকাশ করছেন, তার সঙ্গে মিলতে হবে। Plain-text trace এতে প্রভাবিত হবে না।

প্রথমবার visit করার সময় account তৈরি করুন। এরপর instance-এর নিয়ন্ত্রণ নিজের কাছে রাখুন। LANGFUSE_ALLOWED_ORGANIZATION_CREATORS-এ নিজের email address সেট করুন, যাতে page-এ পৌঁছানো কোনো অপরিচিত ব্যক্তি আপনার server-এ organisation তৈরি করতে না পারে।

আপনার প্রথম trace পাঠান

Web interface-এ একটি project তৈরি করুন এবং project settings থেকে এর public ও secret key কপি করুন। Python SDK তিনটি environment variable পড়ে।

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

LANGFUSE_BASE_URL হলো SDK v4-এর variable name, যা March 2026-এ release করা হয়েছিল। পুরোনো code ও পুরোনো guide-এ LANGFUSE_HOST ব্যবহার করা হয়। আপনার trace যদি নিজের server-এর বদলে Langfuse Cloud-এ পৌঁছায়, তার কারণ হলো base URL unset। কারণ default URL hosted instance-এ নির্দেশ করে।

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()

@observe decorator function-এর চারপাশে একটি observation তৈরি করে, এর argument ও return value capture করে এবং ইতিমধ্যে active থাকা observation-এর অধীনে এটিকে nest করে। AnthropicInstrumentor হলো Anthropic client-এর জন্য OpenTelemetry instrumentation। এটি প্রতিটি messages.create call-কে model name, token usage ও latency-সহ একটি generation-এ রূপান্তর করে। Call site-এ কোনো পরিবর্তন করতে হয় না।

দুটি call স্বয়ংক্রিয়ভাবে পরীক্ষা চালায়। ভুল key বা ভুল base URL থাকলে langfuse.auth_check() False ফেরত দেয়। Dashboard খালি কেন তা অনুমান করার চেয়ে এটি দ্রুত সমস্যা শনাক্ত করে। langfuse.flush() queued span পাঠানো শেষ না হওয়া পর্যন্ত অপেক্ষা করে। অল্প সময় চলা process-এর জন্য এটি প্রয়োজনীয়, কারণ SDK background-এ batch তৈরি করে এবং কোনো script সঙ্গে সঙ্গে exit করলে unsent batch-ও তার সঙ্গে হারিয়ে যায়।

ClickHouse-এর আকার ক্রমাগত বাড়ে কেন?

বেশিরভাগ মানুষ self-host করে এমন ডেটার মধ্যে trace-ই সবচেয়ে দ্রুত বাড়ে। প্রতিটি agent run-এ প্রতি ধাপের জন্য একটি করে row লেখা হয়। Input ও output সম্পূর্ণভাবে সংরক্ষণ করা হয়। তাই দীর্ঘ prompt-সহ বেশি কথোপকথনকারী agent প্রতিদিন তার পর্যবেক্ষণ করা application-এর চেয়ে অনেক বেশি byte তৈরি করতে পারে। কোনো নিয়ন্ত্রণ না থাকলে ClickHouse disk পূর্ণ করে ফেলে। Disk পূর্ণ হলে ingestion ধীর হয় না; বরং বন্ধ হয়ে যায়।

এখানে দুটি পৃথক জিনিস বাড়ে। তাই সমাধানও দুটি পৃথক।

প্রথমটি আপনার নিজস্ব trace data। এর সমাধান হলো retention setting। Web interface-এ project settings খুলে দিনের হিসাবে data retention period সেট করুন। Langfuse-এ সর্বনিম্ন 3 দিন নির্ধারণ করা যায়। এরপর একটি nightly job নির্ধারিত সময়সীমার চেয়ে পুরোনো trace, observation, score এবং media asset নির্বাচন করে ClickHouse ও blob storage থেকে মুছে দেয়। Bucket-এ job-টির DeleteObject permission প্রয়োজন। Default compose file-এ থাকা MinIO root credentials-এ এই permission আগে থেকেই আছে। মুছে ফেলা স্থায়ী। তাই দীর্ঘমেয়াদি history প্রয়োজন হলে আগে blob storage export configure করুন। Langfuse-এর নিজস্ব table-এ হাতে TTL clause লিখবেন না। Retention job-ই ClickHouse ও bucket-কে সামঞ্জস্যপূর্ণ রাখে। Manual TTL শুধু এক পাশ মুছে দেয়।

আপনি বাস্তবে যে সময়সীমা ব্যবহার করেন, সেটিই নির্বাচন করুন। Cost ও quality review সাধারণত কয়েক দিন আগের data-তে হয়, কয়েক মাস আগের data-তে নয়। ছোট দলের জন্য 30 দিন দিয়ে শুরু করা যুক্তিসঙ্গত। কোনো সমস্যা হলে তবেই trace খুললে 14 দিন যথেষ্ট।

দ্বিতীয়টি ClickHouse-এর নিজস্ব system log table। Retention configure করার পরেও disk-এর আকার বাড়তে থাকায় এই বিষয়টি অনেককে অবাক করে। ClickHouse নিজের diagnostics-এর জন্য trace_log, text_log, opentelemetry_span_log, metric_log এবং asynchronous_metric_log লেখে। এগুলোতে কোনো TTL থাকে না। Langfuse কখনো এগুলো পড়ে না। তাই আগে খুঁজে বের করুন disk-এর স্থান আসলে কোথায় ব্যবহার হয়েছে।

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
)

docker compose exec clickhouse clickhouse-client --password "$CLICKHOUSE_PASSWORD" দিয়ে এটি চালান। System table-গুলো তালিকার উপরের দিকে থাকলে config overlay দিয়ে সেগুলো বন্ধ করুন। কারণ ClickHouse চালু হওয়ার সময় /etc/clickhouse-server/config.d/-এর প্রতিটি file main config-এর ওপর merge করে।

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

এটি mount করে ClickHouse restart করুন।

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

এতে নতুন write বন্ধ হবে। Disk-এ আগে থেকে থাকা row থেকে যাবে। তাই DROP TABLE IF EXISTS system.trace_log ব্যবহার করে এবং অপসারণ করা প্রতিটি table-এর জন্য একইভাবে space পুনরুদ্ধার করুন। Diagnostics রাখতে চাইলে remove="1"-এর পরিবর্তে প্রতিটি table-এ aggressive TTL দেওয়া যায়। Langfuse scaling docs-এ এর বিস্তারিত নির্দেশনা আছে।

আরেকটি table সম্পর্কে জানা দরকার। blob_storage_file_log আপনার bucket-এ upload করা event file track করে। Bucket-এ lifecycle policy সেট করলে table-এও একই ধরনের TTL দিন, যাতে দুটি একে অপরের থেকে বিচ্ছিন্ন না হয়।

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

Data disk-এ একটি সাধারণ df -h alert-ও সেট করুন। Trace ধীরে ধীরে সমান হারে বাড়ে না। নতুন agent ship করার দিনেই এর আকার বেড়ে যেতে পারে। সেই বৃদ্ধির প্রথম লক্ষণ ingestion ব্যর্থ হওয়া উচিত নয়।

Postgres এবং ClickHouse-এর ব্যাকআপ

একটি Langfuse ব্যাকআপের তিনটি অংশ আছে। Postgres-এ আপনার user, organisation, project এবং API key থাকে। ClickHouse-এ trace থাকে। MinIO-তে raw event থাকে। শুধু Postgres restore করলে history ছাড়া একটি কার্যকর login পাবেন। শুধু ClickHouse restore করলে এমন history পাবেন, যা দেখার জন্য কেউ login করতে পারবে না।

Postgres একটি সাধারণ pg_dump, যা Langfuse-এর backup documentation-এ সুপারিশ করা হয়েছে।

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

ClickHouse-এর ক্ষেত্রে বেশি সতর্কতা দরকার, কারণ merge চলার সময় live data directory copy করলে সেটি consistent backup হয় না। একটি server-এ সহজ পদ্ধতি হলো container বন্ধ করে volume archive করা।

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

docker volume ls যে volume name দেখায়, সেটি ব্যবহার করুন; YAML-এ লেখা নামটি নয়। File-এ langfuse_clickhouse_data ঘোষণা করা আছে, এবং Compose project name দিয়ে সেটির prefix যোগ করে। তাই langfuse নামের directory-তে clone করলে langfuse_langfuse_clickhouse_data তৈরি হয়। নামটি ভুল হলে docker run কোনো error না দেখিয়ে একটি নতুন empty volume তৈরি করে, এবং আপনার archive-এ কিছুই থাকবে না।

Worker কোনো incoming event process করার আগে web container সেটিকে bucket-এ লেখে। তাই অল্প সময়ের জন্য ClickHouse বন্ধ করলে সাধারণত worker পরে retry করে। কম traffic-এর সময় এটি করুন এবং সময় কম রাখুন। বেশি ব্যস্ত instance-এর ক্ষেত্রে ClickHouse-এর নিজস্ব BACKUP DATABASE default TO S3(...) statement server বন্ধ না করেই একটি consistent backup লেখে। MinIO হলো তৃতীয় অংশ, এবং mc mirror অথবা off-box bucket-এ MinIO replication এটি সুরক্ষিত রাখে। আপনি যে backup-ই তৈরি করুন, সেটি server-এর বাইরে রাখুন। VPS-এ encrypted restic backup-এর উদ্দেশ্য এটাই।

Redis-এর backup দরকার নেই। এতে queue এবং cache থাকে। তাই Redis হারালে বর্তমানে processing-এ থাকা event-গুলো হারাবেন, পুরোনো কোনো data নয়।

Consistency-এর সীমাবদ্ধতাটি বাস্তব এবং স্পষ্টভাবে উল্লেখ করা দরকার। Postgres এবং ClickHouse ভিন্ন সময়ে dump করা হয়। তাই restore-এর পরে কোনো project row-এর সঙ্গে trace নাও থাকতে পারে, অথবা এমন trace থাকতে পারে যার project আর নেই। Langfuse এটি সহ্য করতে পারে। তবু দুটি dump কাছাকাছি সময়ে এবং কম traffic-এর সময় নিন। Event bucket-ই প্রকৃত safety net, কারণ Langfuse processing-এর আগে প্রতিটি incoming event সেখানে সংরক্ষণ করে।

অন্তত একবার একটি scratch stack-এ restore করুন। এতে outage-এর সময় নয়, এখনই ভুল volume name-এর মতো সমস্যা ধরা পড়বে।

প্রথমে যা দেখবেন

প্রথম সপ্তাহে চারটি বিষয় অবশ্যই পর্যবেক্ষণ করুন।

  • প্রতি trace-এর খরচ। Langfuse model name এবং token usage থেকে খরচ হিসাব করে। তাই trace-গুলো খরচ অনুযায়ী সাজিয়ে সবচেয়ে ব্যয়বহুল trace শুরু থেকে শেষ পর্যন্ত পড়ুন। সাধারণত কারণটি হয় বড় হয়ে যাওয়া prompt: পুরো document context-এ paste করা হয়েছে, অথবা এমন conversation history রাখা হয়েছে যা কেউ trim করে না। এটি দেখতে পারলে AI agent-এর খরচ নিয়ন্ত্রণ করা অনুমানের বিষয় না থেকে engineering task হয়ে ওঠে।
  • Input এবং output অনুযায়ী token usage-এর বিভাজন। Input token বেশি এবং সস্তা, output token কম এবং ব্যয়বহুল, আর cached input আরও সস্তা। একই হিসাব Claude Code-এর token usage কীভাবে গণনা করা হয়-এ বিশদে ব্যাখ্যা করা হয়েছে। আপনি নিজে তৈরি করা যেকোনো agent-এর ক্ষেত্রেও এটি প্রযোজ্য।
  • Latency percentile। Median প্রকৃত সমস্যা আড়াল করে। Timeout সাধারণত p95 এবং p99-এ দেখা যায়। Agent loop-এর ভিতরে p95-এ ধীর একটি tool call-এর প্রভাব iteration-এর সংখ্যা অনুযায়ী বহুগুণ হয়।
  • ব্যর্থ tool call। level ERROR অনুযায়ী observation filter করুন। কোনো tool 5% সময় ব্যর্থ হলে aggregate success rate-এ তা চোখে পড়ে না। কিন্তু trace-এ এটি স্পষ্ট দেখা যায়, কারণ সেখানে model-কে retry করতে এবং পরে workaround করতে অতিরিক্ত token ব্যবহার করতে দেখবেন।

Retention window নির্ধারণ করুন এবং deploy করার দিনই ঠিক করুন, প্রতি সপ্তাহে একই দিনে কোন dashboard পরীক্ষা করবেন। কেউ খোলে না এমন observability tool শেষ পর্যন্ত disk ভরিয়ে ফেলা একটি database-এ পরিণত হয়।

FAQ

একটি self-hosted Langfuse-এর কত memory প্রয়োজন?

4 CPU core এবং 16 GiB memory-এর পরিকল্পনা করুন। একটি virtual machine-এর জন্য Langfuse Docker Compose guide-এ এটিই সুপারিশ করা হয়েছে। এর সঙ্গে প্রায় 100 GiB storage রাখুন। প্রকাশিত component minimum অনুযায়ী ClickHouse-এর জন্য 8 GiB এবং web ও worker container-এর প্রতিটির জন্য 4 GiB প্রয়োজন। এর অতিরিক্ত Postgres, Redis এবং MinIO-এরও memory প্রয়োজন। 8 GiB-তে একজন developer-এর instance চালানো যায়। 2 GiB যথেষ্ট নয়। Background merge চলার সময় kernel ClickHouse-কে kill করে, এবং dmesg Out of memory: Killed process দেখায়।

Data retention সেট করার পরও ClickHouse-এর disk কেন পূর্ণ হতে থাকে?

Retention setting শুধু Langfuse-এর নিজস্ব data-তে প্রযোজ্য। ClickHouse আলাদাভাবে trace_log, text_log, opentelemetry_span_log, metric_log এবং asynchronous_metric_log diagnostic table-এ data লেখে। এগুলোর সঙ্গে কোনো TTL দেওয়া থাকে না। কোন table সবচেয়ে বড় তা দেখতে table অনুযায়ী group করে system.parts query করুন। এরপর /etc/clickhouse-server/config.d/-এর অধীনে কোনো file-এ remove="1" entry দিয়ে অব্যবহৃত table-গুলো disable করুন। তারপর ClickHouse restart করুন এবং ইতিমধ্যে ব্যবহৃত space ফেরত পেতে বিদ্যমান table-গুলো drop করুন।

Langfuse-এ সর্বনিম্ন data retention period কত?

3 দিন। Project settings-এ প্রতি project-এর জন্য retention সেট করা যায়। Projects API দিয়েও এটি সেট করা যায়। একটি nightly job নির্ধারিত সময়সীমার চেয়ে পুরোনো trace, observation, score এবং media asset ClickHouse ও blob storage উভয় স্থান থেকেই মুছে দেয়। মুছে ফেলা পূর্বাবস্থায় ফেরানো যায় না। তাই ওই সময়সীমার বাইরের history প্রয়োজন হলে আগে একটি blob storage export configure করুন।

Postgres এবং ClickHouse—দুটিরই কি backup নিতে হবে?

হ্যাঁ, কারণ দুটিতে আলাদা data থাকে। Postgres-এ user, organisation, project এবং API key থাকে। ClickHouse-এ trace data নিজেই থাকে। শুধু Postgres restore করলে এমন একটি instance পাবেন, যাতে login করা যায় কিন্তু কোনো data থাকে না। MinIO bucket-এরও backup নিন। এতে Langfuse arrival-এর সময় persist করা raw event থাকে, যা এই stack-এ source of truth-এর সবচেয়ে কাছাকাছি।

বিদ্যমান OpenTelemetry setup কি self-hosted Langfuse-এ পাঠানো যায়?

হ্যাঁ। Langfuse v4 এবং এর v4 SDK OpenTelemetry-এর ওপর তৈরি। Anthropic ও OpenAI OTel instrumentation সরাসরি এতে export করতে পারে। Python-এ pip install langfuse opentelemetry-instrumentation-anthropic চালান, startup-এর সময় একবার AnthropicInstrumentor().instrument() call করুন, এবং LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEYLANGFUSE_BASE_URL-এ নিজের host সেট করুন। Missing dashboard খোঁজার আগে langfuse.auth_check() দিয়ে নিশ্চিত করুন।