SSD Nodes Learn 🎉 VPS من $4.99/شهر
الأدلة Matt Connorبقلم Matt Connor · آخر تحديث في 2026-08-07

استضافة Langfuse ذاتيًا لتتبّع وكلاء الذكاء الاصطناعي

شغّل Langfuse على VPS تملكه: تعرّف إلى الحد الأدنى الحقيقي للموارد، وثبّت وسوم الصور، واضبط TLS واحتفاظ ClickHouse والنسخ الاحتياطية قبل امتلاء القرص.

لماذا تراقب وكيلاً للذكاء الاصطناعي أصلاً

تستضيف Langfuse ذاتياً لمعرفة ما نفّذه وكيلك فعلياً أثناء إحدى التشغيلات. Langfuse أداة مفتوحة المصدر لمراقبة LLM (النموذج اللغوي الكبير). تسجّل كل prompt، وكل استجابة من النموذج، وكل استدعاء لأداة، وكل token، ثم تجمعها ضمن trace واحد يمكنك فتحه وقراءته. ويعني تشغيلها على VPS تملكه أن تلك الـprompts لا تغادر خادماً تتحكم فيه.

السبب واضح. لا يمكنك إصلاح مشكلة في التكلفة أو الجودة إذا لم تتمكن من رؤيتها. تُخبرك فاتورة المزوّد بأن تكلفة يوم الثلاثاء كانت أكبر بأربع مرات من تكلفة يوم الاثنين. أما trace فيُخبرك بأي تشغيل للوكيل تسبب في ذلك، وأي prompt نما إلى 40,000 token، وأي حلقة retry تكررت تسع مرات قبل أن تتوقف. تمنحك الفاتورة الرقم، بينما يمنحك trace الشيفرة التي أنتجته.

تُستخدم ثلاثة مصطلحات في هذا الدليل. الـtrace هو تشغيل واحد لوكيلك من البداية إلى النهاية. والـobservation خطوة واحدة داخل ذلك التشغيل: يكون span للشيفرة العادية، وgeneration لاستدعاء نموذج. أما الـscore فهو رقم مرتبط بـtrace، مصدره مراجعة بشرية أو مقيّم آلي. يستخدم Langfuse معيار OpenTelemetry (OTel) المحايد تجاه المورّد لتتبّع الأنظمة الموزعة، لذلك يمكن للتجهيز instrumentation الموجود لديك توجيه البيانات إليه.

ما الذي يشغّله Langfuse عند استضافته ذاتياً فعلياً

لا يتكوّن Langfuse v4 من حاوية واحدة. بل يتكوّن من حاويتَي تطبيق وأربع خدمات تخزين، وجميع هذه المكوّنات الستة تعمل على خادمك عند تشغيلها على VPS واحد.

  • langfuse-web يقدّم واجهة الويب وواجهة ingestion API.
  • langfuse-worker يفرّغ قائمة الانتظار في الخلفية. ويحلّل دفعات ingestion، ويحسب التكلفة، وينفّذ مهمة الاحتفاظ الليلية.
  • يحتفظ Postgres بالبيانات الخاصة بالمعاملات، مثل المستخدمين والمؤسسات والمشاريع ومفاتيح API وprompts.
  • يحتفظ ClickHouse ببيانات trace نفسها، أي observations وscores. وهو مخزن أعمدة مصمم للاستعلامات التحليلية، ولذلك تستجيب لوحة المعلومات بسرعة حتى عند احتوائها على أكثر من مئة مليون صف.
  • يوفّر Redis قائمة الانتظار وذاكرة التخزين المؤقت بين web وworker.
  • يوفّر MinIO تخزين كائنات متوافقاً مع S3 على الخادم. ويحتفظ بكل event خام وارد، إضافة إلى أي وسائط ترفقها.

ينشر Langfuse الحد الأدنى من الموارد للمكوّنات الثلاثة التي تنفّذ العمل.

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 من الذاكرة. وتحتاج حاوية web وworker إلى 4 GiB لكل منهما. هذه هي الحدود الدنيا المنشورة للمكوّنات وعددها 3 التي يحدّد Langfuse متطلباتها، بينما لا يزال Postgres وRedis وMinIO يحتاج كل منها إلى ذاكرة إضافية. ويوصي دليل Docker Compose الخاص بالمشروع بآلة تحتوي على 4 أنوية و16 GiB من الذاكرة ونحو 100 GiB من التخزين، وهو ما يتوافق مع هذا الحساب بدلاً من إضافة هامش مبالغ فيه.

لا تحاول تشغيل هذا على خطة بسعة 2 GiB. يبدأ ClickHouse ويقبل عمليات الكتابة لبعض الوقت، ثم يتوقف أثناء عملية دمج في الخلفية، لأن الدمج يحمّل أجزاء كبيرة من الجدول إلى الذاكرة. سترى docker compose ps يعرض حاوية clickhouse بالحالة restarting، وdmesg يتضمن سطراً مثل Out of memory: Killed process 1234 (clickhouse-serv)، وستعيد كل لوحة معلومات في Langfuse الحالة 500. وعند انخفاض الضغط، يرفض ClickHouse الاستعلام بدلاً من ذلك ويسجّل DB::Exception: Memory limit (total) exceeded. تكفي 8 GiB لمطوّر واحد يرسل بضعة آلاف من traces يومياً. أما 16 فهي السعة التي ينبغي التخطيط لها.

نشر Langfuse باستخدام Docker Compose

استنسخ المستودع. توجد الحزمة، والربط بين مكوّناتها، وبيئة التشغيل الافتراضية كلها في docker-compose.yml.

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

كل قيمة يجب تغييرها مميّزة بالعلامة # CHANGEME في ذلك الملف. أنشئ أسرار التطبيقات الثلاثة أولاً.

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

يجب أن تكون ENCRYPTION_KEY بطول 256 بت، مكتوبة على شكل 64 محرفاً سداسياً عشرياً. وهذا بالضبط ما يطبعه openssl rand -hex 32. تُشفّر هذه القيمة البيانات الحساسة أثناء تخزينها، بما في ذلك مفاتيح موفّري LLM التي تحفظها في المثيل. إذا غيّرتها بعد وجود البيانات، فلن تعود تلك الصفوف قابلة لفك التشفير. لذلك تعامل معها كقيمة دائمة منذ أول إقلاع. تُستخدم SALT لتجزئة مفاتيح Langfuse API. لذلك يؤدي تغييرها إلى إبطال كل مفتاح تستخدمه وكلاؤك حالياً.

اضبط بعد ذلك POSTGRES_PASSWORD وCLICKHOUSE_PASSWORD وREDIS_AUTH وMINIO_ROOT_PASSWORD. تظهر كلمة مرور MinIO في أربعة مواضع: مرة بوصفها 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 ذلك العميل بسبب SignatureDoesNotMatch. ويظهر هذا الخطأ في سجل العامل، بينما تبدو واجهة الويب سليمة. إن حفظ هذه القيم في ملف env بدلاً من ملف Compose المتتبَّع هو النمط المشروح في ملفات env والأسرار في Docker Compose.

ثبّت وسوم الصور قبل البدء

يستخدم الملف المرفق langfuse/langfuse:4 وlangfuse/langfuse-worker:4. هذه الوسوم تتغير. يشغّل Langfuse عمليات ترحيل Postgres وClickHouse تلقائياً عند البدء. لذلك يصبح تحديث عادي عبر docker compose pull بعد عدة أشهر عملية ترحيل غير مخطط لها للمخطط، على قاعدة بيانات لم تنشئ لها نسخة احتياطية في ذلك الصباح. ثبّت كليهما على إصدار واحد في docker-compose.override.yml. يدمج Compose هذا الملف فوق الملف المرفق، وبذلك لا يتعارض تحديث لاحق عبر git pull مع تعديلاتك.

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

كان الإصدار 4.3.1 هو إصدار 4.3 الحالي في أغسطس 2026، وقد صدر الإصدار 4.4.0 منذ ذلك الحين. تحقّق من صفحة إصدارات المشروع على GitHub، وثبّت الإصدار الحالي في يوم النشر، ثم غيّر هذا الرقم عمداً لاحقاً. صور التخزين في الملف المرفق مثبتة بالفعل على الإصدارات الرئيسية، وهي postgres:17 وclickhouse-server:25.12 وredis:7. ويجب التعامل معها بالطريقة نفسها.

شغّل الحزمة.

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

يشغّل الإقلاع الأول عمليات الترحيل. لذلك انتظر دقيقة أو دقيقتين قبل اختبار الاستجابة. يجب أن يعرض docker compose ps ست خدمات بالحالة running. إذا أعاد العامل التشغيل في حلقة، فسيوضح سجله السبب: يستخدم CLICKHOUSE_MIGRATION_URL البروتوكول الأصلي لـClickHouse على المنفذ 9000، وليس منفذ HTTP 8123. ويؤدي توجيهه إلى 8123 إلى فشل العامل، بينما تظل حاوية الويب تبدو سليمة.

تحقّق من الصحة من الخادم نفسه.

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 العادي فقط أن عملية API تعمل، لأنه يتجاوز قاعدة البيانات عمداً حتى تستمر الخدمة في تقديم الطلبات عند تعثر Postgres مؤقتاً. أما صيغة failIfDatabaseUnavailable=true فهي المناسبة لربط أداة مراقبة بها، وتعيد 503 عندما يتعذر الوصول إلى قاعدة البيانات. تعيد /api/public/ready الرمز 200 بعد اكتمال عمليات الترحيل، وعندها تقبل الحاوية حركة الشبكة. كلا الاختبارين عاديان عبر HTTP، لذلك يمكن لـصفحة حالة Uptime Kuma مراقبتهما وإبلاغك بتوقف الحزمة قبل أن يكتشف وكلاؤك ذلك.

ضع TLS أمام الخدمة وأغلق المنافذ الإضافية

ينشر ملف Compose المرفق 3000:3000 لحاوية الويب و9090:9000 لـMinIO. ويرتبط كلاهما بكل الواجهات. على عنوان IP عام، يعني ذلك أن أي شخص يفحص المنفذ 3000 يصل إلى صفحة التسجيل، وأي شخص يفحص 9090 يتصل بالحاوية التي تحتوي على مطالباتك الأولية.

لا تكفي قاعدة جدار ناري وحدها لإغلاقهما. يكتب Docker قواعد DNAT الخاصة به في جدول nat، وتُقيَّم هذه القواعد قبل أن ترى قواعد filter في ufw الحزمة، لذلك تترك ufw deny 3000 المنفذ المنشور مفتوحاً. تتكرر هذه الحالة كثيراً لدرجة وجود دليل مستقل لها: لماذا تتجاوز المنافذ التي ينشرها Docker جدار ufw. اربط المنفذين بواجهة loopback في ملف override بدلاً من ذلك.

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 العنوان العام الدقيق، بما في ذلك المخطط، لأن مسار تسجيل الدخول ينشئ عنوان URL لإعادة الاتصال من هذه القيمة. إذا تركتها http://localhost:3000 خلف وكيل HTTPS، فسترسل دورة تسجيل الدخول المتصفح إلى عنوان لا يمكنه الوصول إليه.

وجّه الآن reverse proxy إلى 127.0.0.1:3000 ودعه يتولى الشهادة. يُعد Traefik في مشروع Compose نفسه الخيار المعتاد، كما أن تسميات التوجيه هي نفسها المشروحة في تشغيل عدة تطبيقات خلف reverse proxy واحد باستخدام Traefik. ينفّذ Caddy المهمة نفسها في سطرين إذا كان Langfuse هو التطبيق الوحيد على الخادم. تحقّق باستخدام curl -sI https://langfuse.example.com/api/public/ready، ثم تأكد من جهاز آخر من أن curl http://YOUR_IP:3000 ينتهي الآن بمهلة.

هناك ملاحظة مهمة بشأن MinIO. يقدّم Langfuse الوسائط المرفقة إلى متصفحك عبر عناوين URL موقّعة مسبقاً تشير إلى نقطة نهاية S3 تلك. لذلك، إذا استخدمت traces متعددة الوسائط تحتوي على صور أو صوت، فلن تُحمَّل هذه المرفقات إذا كان MinIO متاحاً عبر loopback فقط. اقرأ صفحة إعداد تخزين الكائنات قبل وضعه خلف proxy، لأن نقطة النهاية المكتوبة في عنوان URL الموقّع مسبقاً يجب أن تطابق العنوان الذي تنشره. لا تتأثر traces النصية العادية.

أنشئ حسابك عند الزيارة الأولى، ثم حافظ على ملكيتك للمثيل. اضبط LANGFUSE_ALLOWED_ORGANIZATION_CREATORS على عنوان بريدك الإلكتروني، حتى لا يتمكن شخص غريب يصل إلى الصفحة من إنشاء مؤسسة على خادمك.

أرسل أول trace لك

أنشئ مشروعاً في واجهة الويب، ثم انسخ المفاتيح العامة والسرية من إعدادات المشروع. يقرأ Python SDK ثلاثة متغيرات بيئية.

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، الذي صدر في March 2026. تستخدم الشيفرة القديمة والأدلة القديمة LANGFUSE_HOST. إذا وصلت traces إلى Langfuse Cloud بدلاً من خادمك، فسبب ذلك أن عنوان URL الأساسي غير مضبوط، لأن القيمة الافتراضية تشير إلى النسخة المستضافة.

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 observation حول الدالة، وتلتقط وسائطها وقيمة الإرجاع، وتضعها ضمن observation النشطة، إن وُجدت. أما AnthropicInstrumentor فهي آلية OpenTelemetry لعميل Anthropic، وتحول كل استدعاء messages.create إلى generation يتضمن اسم النموذج، واستخدام الرموز، وزمن الاستجابة، من دون أي تغيير في موضع الاستدعاء.

تنفّذ استدعاءان عملية التحقق نيابةً عنك. يعيد langfuse.auth_check() القيمة False عند استخدام مفاتيح غير صحيحة أو عنوان URL أساس خاطئ، وهذا أسرع من البحث عن سبب فراغ لوحة المعلومات. أما langfuse.flush() فينتظر حتى تُرسل spans الموضوعة في قائمة الانتظار. تحتاج العمليات القصيرة إلى ذلك، لأن SDK يجمعها في الخلفية، والبرنامج النصي الذي ينتهي فوراً يغلق معه الحزمة التي لم تُرسل.

لماذا يواصل ClickHouse النمو؟

تُعدّ بيانات التتبّع الأسرع نمواً بين البيانات التي يستضيفها معظم المستخدمين بأنفسهم. يكتب كل تشغيل لوكيل صفاً واحداً لكل خطوة، وتُخزَّن المدخلات والمخرجات كاملةً، لذلك ينتج الوكيل كثير الرسائل ذي المطالبات الطويلة بايتات يومية أكثر بكثير من التطبيق الذي يراقبه. إذا تُرك ClickHouse دون ضبط، فسيمتلئ القرص، وعند امتلائه يتوقف إدخال البيانات بدلاً من أن يتباطأ.

ينمو هنا شيئان منفصلان، ويحتاج كل منهما إلى إصلاح مستقل.

الأول هو بيانات التتبّع الخاصة بك، وإعداد الاحتفاظ هو الحل. افتح إعدادات المشروع في واجهة الويب وحدد مدة الاحتفاظ بالبيانات بالأيام. يقبل Langfuse مدة لا تقل عن 3 أيام. تحدد مهمة ليلية عمليات التتبّع والملاحظات والتقييمات وموارد الوسائط الأقدم من هذه المدة، ثم تحذفها من ClickHouse ومن تخزين الكائنات. تحتاج المهمة إلى صلاحية DeleteObject على الحاوية، وتملك بيانات اعتماد MinIO الخاصة بـroot في ملف compose الافتراضي هذه الصلاحية مسبقاً. الحذف نهائي، لذلك اضبط تصدير تخزين الكائنات أولاً إذا كنت تحتاج إلى الاحتفاظ بسجل طويل الأمد. لا تكتب عبارات TTL يدوياً على جداول Langfuse نفسها: فمهمة الاحتفاظ هي التي تُبقي ClickHouse والحاوية متزامنين، بينما تحذف TTL اليدوية البيانات من أحد الجانبين فقط.

اختر المدة وفقاً لاستخدامك الفعلي. تحدث مراجعة التكلفة والجودة على بيانات عمرها أيام، لا أشهر. تُعد مدة 30 يوماً بداية مناسبة لفريق صغير، وتكفي مدة 14 يوماً إذا كنت تفتح التتبّع فقط عند حدوث عطل.

الثاني هو جداول سجلات النظام الخاصة بـClickHouse، وهذا يفاجئ المستخدمين لأن القرص يواصل الامتلاء بعد ضبط الاحتفاظ. يكتب ClickHouse الجداول trace_log وtext_log وopentelemetry_span_log وmetric_log وasynchronous_metric_log لتشخيصاته الخاصة، ولا تتضمن هذه الجداول TTL افتراضياً، كما أن Langfuse لا يقرأها مطلقاً. اعرف أولاً أين استُخدمت مساحة القرص فعلياً.

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". إذا كانت جداول النظام قريبة من أعلى القائمة، فأوقفها باستخدام طبقة إعدادات، لأن ClickHouse يدمج كل ملف في /etc/clickhouse-server/config.d/ فوق إعداداته الرئيسية عند بدء التشغيل.

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

ثبّت الملف ثم أعد تشغيل ClickHouse.

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

يوقف ذلك عمليات الكتابة الجديدة. تبقى الصفوف الموجودة على القرص، لذلك استعد المساحة صراحةً باستخدام DROP TABLE IF EXISTS system.trace_log، وطبّق الأمر نفسه على كل جدول حذفته. إذا كنت تفضل الاحتفاظ ببيانات التشخيص، فاستخدم TTL صارمة على كل جدول بدلاً من remove="1"؛ وتشرح وثائق Langfuse الخاصة بالتوسّع هذا الإعداد بالتفصيل.

هناك جدول آخر تجدر معرفته. يتتبّع blob_storage_file_log ملفات الأحداث المرفوعة إلى حاويتك. إذا ضبطت أيضاً سياسة دورة حياة على الحاوية، فعيّن للجدول TTL مطابقة حتى لا ينفصل سلوكهما بمرور الوقت.

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

ضع أيضاً تنبيهاً عادياً باستخدام df -h على قرص البيانات. لا تنمو بيانات التتبّع بوتيرة ثابتة. بل تنمو في اليوم الذي تطلق فيه وكيلاً جديداً، ويجب ألا تكون أول إشارة إلى ذلك هي فشل إدخال البيانات.

النسخ الاحتياطي لـPostgres وClickHouse

يتكوّن النسخ الاحتياطي لـLangfuse من ثلاثة أجزاء. يحتفظ Postgres بالمستخدمين والمؤسسات والمشروعات ومفاتيح API. ويحتفظ ClickHouse بآثار التتبّع. ويحتفظ MinIO بالأحداث الخام. إذا استعدت Postgres فقط، فستحصل على تسجيل دخول يعمل من دون سجل سابق. وإذا استعدت ClickHouse فقط، فستحصل على سجل لا يستطيع أحد تسجيل الدخول لعرضه.

Postgres عبارة عن pg_dump عادي، وهو الأسلوب الذي توصي به مستندات النسخ الاحتياطي لـLangfuse.

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

يتطلب ClickHouse عناية أكبر، لأن نسخ دليل بيانات حي أثناء تشغيل عمليات الدمج لا ينتج نسخة احتياطية متسقة. الأسلوب البسيط على خادم واحد هو إيقاف الحاوية وأرشفة الـ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

استخدم اسم الـvolume الذي يطبعه docker volume ls، وليس الاسم المكتوب في YAML. يعرّف الملف langfuse_clickhouse_data، ويضيف Compose اسم المشروع إلى الاسم، لذلك ينتج النسخ في دليل اسمه langfuse القيمة langfuse_langfuse_clickhouse_data. إذا أخطأت في ذلك، ينشئ docker run volume جديداً فارغاً من دون إصدار تحذير، وستحتوي أرشيفيتك على لا شيء.

تكتب حاوية الويب كل حدث وارد إلى الـbucket قبل أن يعالجه العامل، لذلك يعني إيقاف ClickHouse لفترة قصيرة غالباً أن العامل سيعيد المحاولة بعد ذلك. نفّذ العملية خلال ساعة هادئة واجعلها قصيرة. بالنسبة إلى مثيل أكثر نشاطاً، تكتب عبارة BACKUP DATABASE default TO S3(...) الخاصة بـClickHouse نسخة احتياطية متسقة من دون إيقاف الخادم. ويشكّل MinIO الجزء الثالث، ويغطيه mc mirror أو النسخ المتماثل في MinIO إلى bucket خارج الخادم. أياً كان ما تنشئه، انقله خارج الخادم؛ فهذا هو الغرض من نسخ restic الاحتياطية المشفّرة على VPS.

لا يحتاج Redis إلى نسخة احتياطية. فهو يحتفظ بقائمة الانتظار وذاكرة التخزين المؤقت، ولذلك لا يسبب فقدانه سوى فقدان الأحداث الموجودة قيد المعالجة حالياً، وليس أي أحداث أقدم.

ملاحظة الاتساق هذه حقيقية ومن المهم توضيحها. تُفرَّغ Postgres وClickHouse في لحظتين مختلفتين، لذلك قد تؤدي الاستعادة إلى وجود صف مشروع من دون آثار تتبّع، أو آثار تتبّع لمشروع لم يعد موجوداً. يتعامل Langfuse مع ذلك، لكن خذ النسختين في وقتين متقاربين وخلال فترة منخفضة الحركة. ويُعدّ event bucket شبكة الأمان الفعلية، لأن Langfuse يحفظ كل حدث وارد فيه قبل معالجته.

استعد إلى stack تجريبي مرة واحدة على الأقل. بهذه الطريقة تكتشف خطأ اسم الـvolume الآن، بدلاً من اكتشافه أثناء انقطاع الخدمة.

ما الذي ينبغي فحصه أولاً

هناك أربعة أمور تستحق المتابعة خلال الأسبوع الأول.

  • التكلفة لكل trace. يحسب Langfuse التكلفة من اسم النموذج واستخدام الرموز، لذا رتّب traces حسب التكلفة واقرأ أغلاها من البداية إلى النهاية. غالباً ما تكون الإجابة prompt تضخّم حجمه: مستند كامل أُلصق في السياق، أو سجل محادثة لا يختصره أحد. عندما تتمكن من رؤيته، يصبح التحكم في تكلفة وكيل AI عليك مهمة هندسية بدلاً من التخمين.
  • تقسيم استخدام الرموز حسب الإدخال والإخراج. تكون رموز الإدخال كثيرة ورخيصة، بينما تكون رموز الإخراج قليلة ومكلفة، وتكون تكلفة الإدخال المخزّن مؤقتاً أقل من ذلك أيضاً. يشرح كيفية احتساب استخدام الرموز في Claude Code تفاصيل المحاسبة نفسها، وينطبق ذلك على أي وكيل تكتبه بنفسك.
  • النسب المئوية لزمن الاستجابة. يخفي الوسيط المشكلة. تقع حالات انتهاء المهلة عند p95 وp99، وداخل حلقة الوكيل، تتضاعف آثار استدعاء أداة بطيء عند p95 بحسب عدد التكرارات.
  • استدعاءات الأدوات الفاشلة. رشّح observations حسب المستوى ERROR. تكون الأداة التي تفشل بنسبة 5% غير ظاهرة في معدل النجاح الإجمالي، لكنها واضحة جداً في traces، حيث تراقب النموذج وهو يعيد المحاولة ثم يستهلك الرموز للالتفاف على المشكلة.

حدّد مدة الاحتفاظ بالسجلات، واختر dashboard ستراجعه أسبوعياً في اليوم نفسه الذي تنفّذ فيه النشر. أداة observability لا يفتحها أحد هي قاعدة بيانات تملأ القرص.

FAQ

ما مقدار الذاكرة التي يحتاج إليها Langfuse المستضاف ذاتياً؟

خطّط لاستخدام 4 أنوية CPU و16 GiB من الذاكرة، وهو ما يوصي به دليل Langfuse Docker Compose لجهاز افتراضي واحد، إضافةً إلى نحو 100 GiB من مساحة التخزين. الحد الأدنى المنشور لمكوّن ClickHouse هو 8 GiB، ولكل من حاويتي الويب والعامل 4 GiB، كما يحتاج Postgres وRedis وMinIO إلى ذاكرة إضافية. تكفي 8 GiB لتشغيل نسخة لمطوّر واحد. أما 2 GiB فلا تكفي: إذ يقتل kernel عملية ClickHouse أثناء عمليات الدمج في الخلفية، ويعرض dmesg القيمة Out of memory: Killed process.

لماذا يمتلئ قرص ClickHouse باستمرار بعد ضبط مدة الاحتفاظ بالبيانات؟

يغطي إعداد الاحتفاظ بيانات Langfuse الخاصة فقط. يكتب ClickHouse بشكل منفصل جداول التشخيص trace_log وtext_log وopentelemetry_span_log وmetric_log وasynchronous_metric_log، ولا تحتوي هذه الجداول على TTL. نفّذ الاستعلام system.parts مع التجميع حسب الجدول لمعرفة الجدول الأكبر، ثم عطّل الجداول غير المستخدمة بإضافة إدخال remove="1" إلى ملف ضمن /etc/clickhouse-server/config.d/، وأعد تشغيل ClickHouse، واحذف الجداول الموجودة لتحرير المساحة المستخدمة مسبقاً.

ما الحد الأدنى لمدة الاحتفاظ بالبيانات في Langfuse؟

3 أيام. تُضبط مدة الاحتفاظ لكل مشروع من إعدادات المشروع أو عبر projects API، وتحذف مهمة ليلية الآثار والملاحظات والتقييمات وملفات الوسائط الأقدم من هذه المدة من ClickHouse وتخزين الكائنات. لا يمكن التراجع عن الحذف، لذلك اضبط تصدير تخزين الكائنات أولاً إذا كنت تحتاج إلى الاحتفاظ بالسجل لمدة تتجاوز هذه المدة.

هل يجب أن أنشئ نسخة احتياطية من Postgres وClickHouse معاً؟

نعم، لأن كلّاً منهما يخزّن بيانات مختلفة. يخزّن Postgres المستخدمين والمؤسسات والمشاريع ومفاتيح API، بينما يخزّن ClickHouse بيانات الآثار نفسها. تمنحك استعادة Postgres وحده نسخة يمكنك تسجيل الدخول إليها، لكنها ستكون خالية من البيانات. أنشئ نسخة احتياطية من حاوية MinIO أيضاً، لأنها تحتوي على الأحداث الخام التي يحفظها Langfuse عند وصولها، وهي أقرب ما يكون إلى مصدر الحقيقة في هذه البنية.

هل يمكنني توجيه إعداد OpenTelemetry موجود إلى Langfuse المستضاف ذاتياً؟

نعم. يعتمد Langfuse v4 وحزم SDK الخاصة به للإصدار v4 على OpenTelemetry، وتُصدّر أدوات Anthropic وOpenAI الخاصة بـ OTel البيانات إليه مباشرةً. في Python، شغّل pip install langfuse opentelemetry-instrumentation-anthropic، واستدعِ AnthropicInstrumentor().instrument() مرة واحدة عند بدء التشغيل، واضبط LANGFUSE_PUBLIC_KEY وLANGFUSE_SECRET_KEY وLANGFUSE_BASE_URL على المضيف الخاص بك. تأكد باستخدام langfuse.auth_check() قبل البحث عن لوحة معلومات مفقودة.