নিজের VPS-এ Langfuse চালিয়ে AI agent trace করুন
নিজের VPS-এ Langfuse চালানোর বাস্তব resource floor, pinned image tag, TLS, disk ভরার আগে ClickHouse retention এবং কার্যকর backup সেটআপ জানুন।
একটি AI agent trace করবেন কেন
আপনার agent আসলে কী করেছে তা একটি run-এ দেখার জন্য আপনি নিজের ব্যবস্থাপনায় Langfuse চালান। Langfuse একটি open source LLM (large language model) observability tool। এটি প্রতিটি prompt, প্রতিটি model response, প্রতিটি tool call এবং প্রতিটি token রেকর্ড করে। এরপর এগুলোকে একটি trace-এর অধীনে group করে, যা আপনি খুলে পড়তে পারেন। নিজের VPS-এ এটি চালালে ওই prompt-গুলো আপনার নিয়ন্ত্রণাধীন server-এর বাইরে যায় না।
এটি করার কারণ সরল। যে cost সমস্যা বা quality সমস্যা আপনি দেখতে পান না, তা ঠিক করতে পারবেন না। 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-এ নির্দেশ করতে পারে।
Self-hosting Langfuse-এ আসলে কী চলে
Langfuse v4 একটি container নয়। এতে দুটি application container এবং চারটি storage service থাকে। একটি VPS-এ সব ছয়টি আপনার মেশিনেই চলে।
langfuse-webweb interface এবং ingestion API সরবরাহ করে।langfuse-workerbackground-এ queue খালি করে। এটি ingestion batch parse করে, cost গণনা করে এবং nightly 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 মেশিনেই S3 compatible object storage সরবরাহ করে। এটি প্রতিটি raw incoming event এবং আপনার সংযুক্ত যেকোনো media সংরক্ষণ করে।
কাজটি সম্পাদনকারী তিনটি component-এর জন্য Langfuse minimum resource প্রকাশ করে।
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 memory প্রয়োজন। এগুলো Langfuse যে 3টি component-এর resource requirement নির্ধারণ করেছে, সেগুলোর প্রকাশিত minimum। এর পাশাপাশি Postgres, Redis এবং MinIO-এরও memory প্রয়োজন। Project-এর নিজস্ব Docker Compose guide 4 core, 16 GiB memory এবং প্রায় 100 GiB storage-সহ একটি machine সুপারিশ করে। এই হিসাবও সেটিই দেখায়; অতিরিক্ত resource ধরা হয়নি।
2 GiB plan-এ এটি চালানোর চেষ্টা করবেন না। ClickHouse start হয় এবং কিছু সময় 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 ধরুন। একই VPS-এ অন্য কিছু চালানোর প্রয়োজন হলে তার resource আলাদাভাবে হিসাব করুন। কারণ self-hosted AFFiNE workspace-এর মতো তুলনামূলকভাবে হালকা stack-এরও নিজস্ব কয়েক GiB memory প্রয়োজন, এবং ClickHouse তার কোনো memory ছেড়ে দেবে না।
Docker Compose দিয়ে Langfuse স্থাপন
Repository clone করুন। Stack, সংযোগ-ব্যবস্থা এবং default environment—সবকিছু এর docker-compose.yml-এ রয়েছে।
git clone https://github.com/langfuse/langfuse.git
cd langfuseওই file-এ যে প্রতিটি value পরিবর্তন করতে হবে, সেটি # CHANGEME দিয়ে চিহ্নিত করা আছে। প্রথমে তিনটি application secret তৈরি করুন।
openssl rand -base64 32 # NEXTAUTH_SECRET
openssl rand -base64 32 # SALT
openssl rand -hex 32 # ENCRYPTION_KEYENCRYPTION_KEY-এর মান 64টি hexadecimal character হিসেবে লেখা 256 bits হতে হবে। openssl rand -hex 32 ঠিক এই format-এই মানটি দেখায়। এটি সংরক্ষিত অবস্থায় থাকা sensitive value encrypt করে; instance-এ রাখা LLM provider key-ও এর অন্তর্ভুক্ত। 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 হিসেবে। একটি value বাদ পড়লে MinIO ওই client-কে SignatureDoesNotMatch দিয়ে প্রত্যাখ্যান করে। এই error worker log-এ দেখা যায়, যদিও web interface তখনও স্বাভাবিক দেখাতে পারে। Tracked compose file-এর বদলে env file-এ এই value রাখা Docker Compose env file এবং secret-এ বর্ণিত পদ্ধতি।
শুরু করার আগে image tag নির্দিষ্ট করুন
সরবরাহ করা file-এ 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 নির্দিষ্ট করুন। Compose এটি সরবরাহ করা file-এর ওপর প্রয়োগ করবে, ফলে পরবর্তী git pull আপনার পরিবর্তনের সঙ্গে সংঘাতে যাবে না।
services:
langfuse-web:
image: docker.io/langfuse/langfuse:4.3.1
langfuse-worker:
image: docker.io/langfuse/langfuse-worker:4.3.1August 2026 অনুযায়ী 4.3.1 ছিল বর্তমান 4.3 release; এর পরে 4.4.0 প্রকাশিত হয়েছে। Project-এর GitHub releases page দেখুন, deployment-এর দিন যে release বর্তমান সেটি pin করুন, এবং পরে version number ইচ্ছাকৃতভাবে পরিবর্তন করুন। সরবরাহ করা file-এ storage image-গুলো ইতিমধ্যে major version-এ pinned: postgres:17, clickhouse-server:25.12 এবং redis:7। এগুলোকেও একইভাবে নির্দিষ্ট করা উচিত। এই নিয়ম শুধু Langfuse-এর জন্য নয়: একটি self-hosted openGym workout tracker এই stack-এর ছোট একটি অংশ চালায়, তবু একটি নির্দিষ্ট git tag ব্যবহার করা উচিত। কারণ start হওয়ার সময় নিজের database migration চালানো যেকোনো software-এর ক্ষেত্রে সাধারণ pull schema change ঘটাতে পারে।
এখন stack চালু করুন।
docker compose up -d
docker compose ps
docker compose logs -f langfuse-workerপ্রথম boot-এ migration চলে। তাই কোনো response পাওয়ার আগে এক বা দুই মিনিট অপেক্ষা করুন। docker compose ps-এ running state-এ ছয়টি service দেখা উচিত। Worker যদি বারবার restart হয়, তার log-এ কারণ থাকবে: CLICKHOUSE_MIGRATION_URL port 9000-এ ClickHouse native protocol ব্যবহার করে, HTTP port 8123 নয়। তাই এটিকে 8123-এ নির্দেশ করলে 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 গ্রহণ চালিয়ে যেতে পারে। Monitor-এ ব্যবহারের জন্য failIfDatabaseUnavailable=true form-টি উপযুক্ত। Database unreachable হলে এটি 503 ফেরত দেয়। Migration শেষ হলে /api/public/ready 200 ফেরত দেয় এবং container traffic গ্রহণ করতে প্রস্তুত থাকে। দুটিই সাধারণ HTTP check। তাই একটি Uptime Kuma status page এগুলো monitor করতে পারে এবং agent-গুলোর আগে stack অচল হওয়ার খবর দিতে পারে।
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 দেখার আগেই এই rule-গুলো প্রয়োগ হয়। তাই ufw deny 3000 ব্যবহার করলেও published port খোলা থাকে। এই সমস্যা এত সাধারণ যে এর জন্য আলাদা guide আছে: কেন Docker-এর published 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-এর পুরো round trip-এ 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 ব্যবহার করে S3 endpoint-এ নির্দেশ করা URL-এর মাধ্যমে আপনার browser-এ সংযুক্ত media পাঠায়। তাই image বা audio-সহ multi-modal trace ব্যবহার করলে loopback-only MinIO-এর কারণে attachment load হবে না। এটিকে proxy করার আগে blob storage configuration page পড়ুন। Presigned URL-এ লেখা endpoint-টি আপনি যে endpoint প্রকাশ করছেন, তার সঙ্গে মিলতে হবে। Plain-text trace এতে প্রভাবিত হয় না।
প্রথমবার visit করলে আপনার account তৈরি করুন। এরপর instance-এর নিয়ন্ত্রণ নিজের কাছে রাখুন। LANGFUSE_ALLOWED_ORGANIZATION_CREATORS-এ নিজের email address দিন, যাতে page-এ পৌঁছানো কোনো অপরিচিত ব্যক্তি আপনার server-এ organisation তৈরি করতে না পারে। আপনি যদি ইতিমধ্যে নিজের identity provider হিসেবে Authentik চালান, Langfuse একটি standard OIDC connection গ্রহণ করে। ফলে account-গুলো আপনার অন্যান্য অ্যাপের সঙ্গে একসঙ্গে তৈরি ও অপসারিত হয়। শুধু এই server জানে এমন password list-এর ওপর নির্ভর করতে হয় না।
আপনার প্রথম 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-এ released হয়েছে। পুরোনো code এবং পুরোনো guide-এ LANGFUSE_HOST ব্যবহার করা হয়। আপনার trace যদি server-এর পরিবর্তে Langfuse Cloud-এ পৌঁছায়, তার কারণ হলো base URL unset আছে; কারণ default URL hosted instance-এ নির্দেশ করে।
pip install langfuse opentelemetry-instrumentation-anthropic anthropicimport 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 তৈরি করে, function-এর argument ও return value capture করে এবং ইতিমধ্যে active থাকা observation-এর অধীনে এটিকে nest করে। AnthropicInstrumentor হলো Anthropic client-এর জন্য OpenTelemetry instrumentation। এটি প্রতিটি messages.create call-কে model name, token usage এবং latency-সহ একটি generation-এ রূপান্তর করে। Call site-এ কোনো পরিবর্তন করতে হয় না।
দুটি কল স্বয়ংক্রিয়ভাবে যাচাই করে। langfuse.auth_check() ভুল key বা ভুল base URL থাকলে False ফেরত দেয়। Dashboard কেন খালি, তা অনুমান করার চেয়ে এটি দ্রুত সমস্যাটি শনাক্ত করে। langfuse.flush() queue-তে থাকা span পাঠানো শেষ না হওয়া পর্যন্ত অপেক্ষা করে। স্বল্পস্থায়ী process-এর জন্য এটি প্রয়োজনীয়, কারণ SDK background-এ batch তৈরি করে এবং সঙ্গে সঙ্গে exit করা script তার unsent batch-ও সঙ্গে নিয়ে শেষ হয়ে যায়। একটি script নয়, পুরো team trace পাঠালে প্রত্যেকের shell-এ সেট না করে সবাই যে gateway ব্যবহার করে, সেখানে ওই তিনটি variable একবার সেট করুন। এভাবেই একটি self-hosted OneCLI harness প্রতিটি সহকর্মীর run-এ instrumentation সক্রিয় রাখে, আর key এক জায়গায় সংরক্ষিত থাকে।
ClickHouse-এর আকার কেন ক্রমাগত বাড়ে?
বেশিরভাগ মানুষ self-host করে এমন ডেটার মধ্যে traces সবচেয়ে দ্রুত বাড়ে। প্রতিটি agent run-এর প্রতিটি ধাপের জন্য একটি করে row লেখা হয়। Input ও output সম্পূর্ণভাবে সংরক্ষণ করা হয়। তাই দীর্ঘ prompt ব্যবহারকারী বেশি কথাবলা agent প্রতিদিন তার পর্যবেক্ষণ করা application-এর চেয়ে অনেক বেশি bytes তৈরি করে। এভাবে চলতে থাকলে ClickHouse disk পূর্ণ করে ফেলে। Disk পূর্ণ হলে ingestion ধীর হয় না; বরং বন্ধ হয়ে যায়।
এখানে দুটি আলাদা জিনিস বাড়ে। এগুলোর জন্য দুটি আলাদা সমাধান প্রয়োজন।
প্রথমটি হলো আপনার নিজস্ব trace data। এর সমাধান হলো retention setting। Web interface-এ project settings খুলে days-এ data retention period নির্ধারণ করুন। Langfuse ন্যূনতম 3 days গ্রহণ করে। এরপর একটি nightly job নির্ধারিত সময়সীমার চেয়ে পুরোনো traces, observations, scores এবং media assets নির্বাচন করে ClickHouse ও blob storage থেকে মুছে দেয়। Bucket-এ jobটির DeleteObject permission প্রয়োজন। Default compose file-এ থাকা MinIO root credentials-এ এই permission আগে থেকেই আছে। Deletion স্থায়ী। তাই দীর্ঘমেয়াদি history প্রয়োজন হলে আগে blob storage export configure করুন। Langfuse-এর নিজস্ব tables-এ হাতে TTL clause লিখবেন না। Retention job-ই ClickHouse ও bucket-কে সমন্বয়ে রাখে। Manual TTL শুধু একটি দিকের data মুছে দেয়।
আপনি বাস্তবে যতদিনের data ব্যবহার করেন, সেই অনুযায়ী সময়সীমা নির্ধারণ করুন। Cost ও quality review সাধারণত কয়েক দিন আগের data-তে হয়, কয়েক মাস আগের data-তে নয়। ছোট team-এর জন্য 30 days দিয়ে শুরু করা যুক্তিসঙ্গত। কোনো সমস্যা হলে শুধু trace খোলেন এমন ক্ষেত্রে 14 days যথেষ্ট।
দ্বিতীয়টি হলো ClickHouse-এর নিজস্ব system log tables। এটি অনেককে অবাক করে, কারণ 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 tables যদি তালিকার উপরের দিকে থাকে, তবে config overlay ব্যবহার করে সেগুলো বন্ধ করুন। কারণ ClickHouse start হওয়ার সময় /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-এ থাকা পুরোনো rows থেকে যাবে। তাই DROP TABLE IF EXISTS system.trace_log ব্যবহার করে এবং অপসারণ করা প্রতিটি table-এর জন্য একই কাজ করে space স্পষ্টভাবে reclaim করুন। Diagnostics রাখতে চাইলে remove="1"-এর পরিবর্তে প্রতিটি table-এ aggressive TTL ব্যবহার করতে পারেন। Langfuse scaling docs-এ এই পদ্ধতিটি বিস্তারিতভাবে দেওয়া আছে।
আরেকটি table সম্পর্কেও জানা দরকার। blob_storage_file_log আপনার bucket-এ upload করা event files-এর হিসাব রাখে। Bucket-এ lifecycle policy সেট করলে table-এও matching TTL দিন, যাতে দুটি একে অপরের সঙ্গে অসামঞ্জস্যপূর্ণ না হয়।
ALTER TABLE blob_storage_file_log MODIFY TTL created_at + INTERVAL 30 DAY DELETE;Data disk-এ একটি সাধারণ df -h alert-ও সেট করুন। Traces সমান হারে বাড়ে না। নতুন agent ship করার দিন এগুলো দ্রুত বাড়তে পারে। Ingestion ব্যর্থ হওয়া যেন তার প্রথম লক্ষণ না হয়।
Postgres এবং ClickHouse-এর ব্যাকআপ নিন
Langfuse-এর ব্যাকআপের 3টি অংশ রয়েছে। Postgres-এ আপনার user, organisation, project এবং API key থাকে। ClickHouse-এ trace থাকে। MinIO-তে raw event থাকে। শুধু Postgres restore করলে history ছাড়া login করার মতো একটি কার্যকর সিস্টেম পাবেন। শুধু ClickHouse restore করলে এমন history পাবেন, যা দেখার জন্য কেউ login করতে পারবে না। এই বিভাজন শুধু Langfuse-এর ক্ষেত্রে নয়। self-hosted Chatwoot support desk-এর ক্ষেত্রেও একই কাঠামো দেখা যায়। সেখানে uploads directory ছাড়া নেওয়া Postgres dump restore করলে conversation ফিরে আসে, কিন্তু সব attachment হারিয়ে যায়।
Postgres একটি সাধারণ pg_dump, এবং Langfuse-এর backup documentation-এ এটিই সুপারিশ করা হয়েছে।
docker compose exec -T postgres pg_dump -U postgres postgres \
| gzip > langfuse-pg-$(date +%F).sql.gzClickHouse-এর ক্ষেত্রে আরও সতর্কতা দরকার। Merge চলার সময় live data directory কপি করলে তা 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 clickhousedocker volume ls যে volume name দেখায়, সেটি ব্যবহার করুন; YAML-এ লেখা নামটি নয়। File-এ langfuse_clickhouse_data ঘোষণা করা আছে, এবং Compose project name-এর সঙ্গে prefix যোগ করে। তাই langfuse নামের directory-তে clone করলে langfuse_langfuse_clickhouse_data তৈরি হয়। এটি ভুল হলে docker run কোনো error না দেখিয়ে একটি নতুন খালি volume তৈরি করে, এবং আপনার archive-এ কিছুই থাকে না।
Web container প্রতিটি incoming event worker process করার আগে bucket-এ লেখে। তাই ClickHouse অল্প সময়ের জন্য বন্ধ থাকলে সাধারণত worker পরে retry করে। কম ব্যস্ত সময়ে কাজটি করুন এবং সময় যতটা সম্ভব কম রাখুন। বেশি ব্যস্ত 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 হারালে বর্তমানে প্রক্রিয়াধীন event হারাবেন, এর বেশি পুরোনো কিছু নয়।
Consistency সংক্রান্ত সীমাবদ্ধতাটি বাস্তব এবং স্পষ্টভাবে উল্লেখ করা দরকার। Postgres এবং ClickHouse আলাদা সময়ে dump করা হয়। তাই restore করার পরে এমন project row থাকতে পারে যার কোনো trace নেই, অথবা এমন trace থাকতে পারে যা আর বিদ্যমান নয় এমন project-এর অন্তর্ভুক্ত। Langfuse এটি সহ্য করতে পারে। তবে দুটি dump কাছাকাছি সময়ে এবং কম traffic-এর সময় নিন। Event bucket-ই আসল safety net, কারণ Langfuse প্রতিটি incoming event process করার আগে সেখানে সংরক্ষণ করে।
কমপক্ষে একবার একটি scratch stack-এ restore করুন। এতে ভুল volume name এখনই ধরা পড়বে, outage চলাকালীন নয়।
প্রথমে যা দেখবেন
প্রথম সপ্তাহে চারটি বিষয় অগ্রাধিকার পাওয়ার মতো।
- প্রতি 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 পুনরায় চেষ্টা করে এবং পরে workaround করতে token খরচ করে।
Retention window নির্ধারণ করুন এবং deploy করার দিনই ঠিক করুন, প্রতি সপ্তাহে একই দিনে কোন dashboard পরীক্ষা করবেন। যে observability tool কেউ খোলে না, সেটি শেষ পর্যন্ত এমন একটি database হয়ে যায় যা disk পূর্ণ করে।
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 process বন্ধ করে দেয়, এবং 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 সবচেয়ে বড় তা দেখতে system.parts-কে table অনুযায়ী group করে query চালান। এরপর /etc/clickhouse-server/config.d/-এর অধীন কোনো file-এ remove="1" entry দিয়ে অপ্রয়োজনীয় table-গুলো disable করুন। ClickHouse restart করুন। ইতিমধ্যে ব্যবহৃত space ফেরত পেতে বিদ্যমান table-গুলো drop করুন।
Langfuse-এ minimum data retention period কত?
3 দিন। Project settings-এ প্রতি project-এর জন্য retention সেট করা যায়। Projects API ব্যবহার করেও এটি সেট করা যায়। Nightly job retention window-এর চেয়ে পুরোনো trace, observation, score এবং media asset ClickHouse ও blob storage—দুই জায়গা থেকেই মুছে দেয়। মুছে ফেলা data পুনরুদ্ধার করা যায় না। তাই ওই সময়সীমার বেশি সময়ের history প্রয়োজন হলে আগে blob storage export কনফিগার করুন।
আমার কি 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_KEY এবং LANGFUSE_BASE_URL-এ আপনার নিজস্ব host সেট করুন। Missing dashboard খোঁজার আগে langfuse.auth_check() দিয়ে নিশ্চিত করুন।