Security: deep /api/health (DB+MinIO probes, 503 on failure) + /api/live; rate-limited public forms with honeypots; real client IP behind Traefik (--proxy-headers); TipTap URL sanitization on write (nh3); non-root containers + slim .dockerignore; prod MinIO console bound to 127.0.0.1; HSTS/nosniff on TLS routers; JWT 8h; no default credentials in code. Reliability: Alembic migrations (create_all baseline); graceful shutdown (exec uvicorn); hardened backups (checksums, sanity check, freshness gauge, optional rclone off-site) + restore.sh + hourly db-backup sidecar (ops profile); stack.sh ops tooling (deploy/logs/health/backup/restore/monitoring); .gitattributes LF for shell scripts. Orchestration: json-file log rotation, pinned images, per-service memory limits, edge/internal networks, Traefik ping/accesslog/metrics + flood limiter, conditional minio-setup, pgvector db image, one-shot db-init (umami + aramesh_chatbot databases). Chatbot: unified from site-chatbot branch (RAG + pgvector, SSE, ChatWidget). Monitoring: Prometheus/Alertmanager/Loki/Promtail/Grafana + cAdvisor, node/postgres/blackbox exporters, provisioned dashboards and 10 alert rules; alerts delivered to Bale (tapi.bale.ai — Telegram-compatible). Analytics: Umami on shared Postgres, build-time tracker injection, custom events (contact/newsletter/phone/chat/lang) via frontend/src/analytics.ts. Hygiene: CSV export for contact messages and subscribers; upload image optimization (Pillow); CI script + GitHub-compatible workflow; audit.sh; gen-env.sh for strong credentials.
8.7 KiB
دستیار هوشمند سایت (چتبات)
سرویس گفتگوی محتوای سایت «گروه ساختمانی آرامش» — بازدیدکننده به فارسی سؤال میپرسد و دستیار فقط از روی محتوای خود سایت (مقالهها، پروژهها، خدمات، سؤالات متداول، اطلاعات تماس و…) پاسخ میدهد؛ اگر پاسخ در محتوا نباشد، بهجای ساخت جواب، صادقانه اعلام میکند.
این سرویس پورت خط لولهٔ پروژهٔ llm-srerver-chatbot (نسخه v13) با چهار تغییر اصلی برای این سایت است:
- پایگاه sparse بهجای SPLADE از BM25 استفاده میکند — SPLADE انگلیسیمحور است و روی فارسی عملاً بیفایده؛ BM25 با نرمالسازی فارسی (ی/ک عربی، اعراب، ارقام، نیمفاصله) جایگزین شده است.
- ذخیرهساز برداری pgvector است، نه FAISS — بردارها در یک دیتابیس جدا (
aramesh_chatbot) روی همان نمونه Postgres نگهداری میشوند؛ همگامسازی افزایشی است (فقط سطرهای جدید/تغییریافته امبد میشوند)، بکاپگیری با خود دیتابیس است و فایل ایندکس جدا وجود ندارد. - تأخیر کمتر — مسیریابی
alphaبا LLM و گسترش چندپرسشی (multi-query) بهصورت پیشفرض خاموشاند (با متغیر محیطی قابل فعالسازی)؛ بازنویسی پرسش فقط وقتی تاریخچه گفتگو وجود دارد اجرا میشود. - استریم واقعی توکنبهتوکن با
astream_eventsبهجای دیف پیامهای کامل.
خط لوله هر پیام
پرسش کاربر
│
├─[اگر تاریخچه هست] بازنویسی پرسش با LLM (حل ضمیرها و اشارهها: «اون دومی» → موضوع واقعی)
│
├─ بازیابی ترکیبی: pgvector (معنایی، کسینوسی روی HNSW — MiniLM چندزبانه)
│ + BM25 (کلیدواژه، متن نرمالشده فارسی)
│ نمرهها min-max → ترکیب α×معنایی + (1-α)×کلیدواژه
│
├─ برش خوشهای (K-Means K=2 + silhouette ≥ 0.55) — مرز طبیعی کیفیت
│
├─ ریرنک با BAAI/bge-reranker-v2-m3 → نگهداشتن ۳ سند برتر
│
└─ تولید پاسخ فارسی با LLM (قواعد تکیه بر داده + معرفی صفحه مرتبط + پیام جایگزین مشخص)
ایندکس از محتوای PostgreSQL سایت ساخته میشود (articles منتشرشده، projects، services،
faqs، brand، offices، investment_models، process_steps، why_us، team،
testimonials، timeline، story). متنهای بلند به قطعات ~۷۰۰ نویسهای همپوشان برش میخورند.
- ایندکس برداری در pgvector: جدول
chatbot_chunksدر دیتابیس اختصاصیaramesh_chatbot(روی همان نمونه Postgres) با ستونembedding vector(384)و ایندکس HNSW کسینوسی؛ هر قطعهdoc_idپایدار وcontent_hashدارد و همگامسازی فقط سطرهای جدید/تغییریافته را امبد میکند. دیتابیس و جدول در شروع سرویس خودکار ساخته میشوند. - بازسازی خودکار: یک حلقهٔ پسزمینه هر
INDEX_REFRESH_SECONDSثانیه محتوا را چک میکند و اگر ادمین چیزی را در پنل عوض کرده باشد، فقط تغییرات همگام میشود (امبد اجباری همه:POST /chat/reindex). - ماندگاری گفتگو: در حافظهٔ همان پروسه (MemorySaver لنگگراف) — با ریاستارت پاک میشود.
متغیرهای محیطی (در .env ریشه پروژه)
| متغیر | پیشفرض | توضیح |
|---|---|---|
LLM_BASE_URL |
خالی | اجباری — نشانی سرویس LLM سازگار با OpenAI. بدون آن چتبات بالا میآید ولی پاسخ نمیدهد |
LLM_API_KEY |
خالی | کلید API (برای سرور داخلی not-needed بگذارید) |
LLM_MODEL |
openai/gpt-oss-120b |
نام مدل |
CHAT_REINDEX_TOKEN |
خالی | توکن POST /chat/reindex — اگر خالی باشد آن مسیر ۴۰۳ میدهد |
CHATBOT_DB_NAME |
aramesh_chatbot |
نام دیتابیس اختصاصی چتبات روی همان نمونه Postgres (بردارها اینجا میروند) |
EMBEDDING_DIM |
384 |
بعد بردار مدل امبدینگ — با تعویض مدل امبدینگ باید هماهنگ شود |
RERANKER_ENABLED |
true |
روی سرور کمرم (زیر ~۴GB) false بگذارید |
ALPHA_DENSE |
0.5 |
وزن جستوجوی معنایی در ترکیب نمرهها (۰ تا ۱) |
BEST_OF_K |
3 |
تعداد سند نهایی که به LLM میرود |
INDEX_REFRESH_SECONDS |
600 |
بازسازی خودکار ایندکس پس از تغییر محتوا (۰ = خاموش) |
RATE_LIMIT_MESSAGES / RATE_LIMIT_WINDOW |
20 / 300 |
سقف پیام هر IP در پنجره زمانی (ثانیه) |
DATABASE_URL در داکر از docker-compose.yml تزریق میشود — دیتابیس سایت فقط خوانده
میشود و نوشتن (بردارها) فقط در دیتابیس جدا aramesh_chatbot انجام میگیرد.
پیشنیاز pgvector
سرویس db استک از ایمیج pgvector/pgvector:pg17 استفاده میکند (همان postgres:17 +
افزونهٔ vector). اگر Postgres سایت روی نمونهٔ دیگری است، باید افزونهٔ pgvector روی آن
فعال باشد؛ در غیر این صورت شروع چتبات با خطای واضح متوقف میشود.
مسیرها
| مسیر | توضیح |
|---|---|
GET /chat/stream?message=…&thread_id=… |
استریم SSE توکنبهتوکن پاسخ ({"content": …} و در پایان {"done": true}) |
GET /chat/suggestions |
۴ پیشنهاد پرسش (کش ۱۰ دقیقه؛ جایگزین: خود سؤالات متداول) |
GET /chat/eval?message=… |
مخصوص ارزیابی RAGAS — پاسخ + اسناد بازیابیشده با thread تازه |
GET /chat/healthz |
وضعیت ایندکس/LLM/تعداد اسناد |
POST /chat/reindex |
بازسازی اجباری ایندکس (هدر X-Reindex-Token) |
مسیرهای GET /chat/{scope}/stream|eval|suggestions هم برای سازگاری با اسکریپت
eval_ragas.py قدیمی موجود است — کافی است --url را به نشانی این سرویس بدهید.
اجرا
با داکر (بخشی از استک اصلی است — docker compose up -d --build):
# در .env ریشه:
LLM_BASE_URL=http://172.16.22.21:4460/v1 # یا هر سرویس سازگار با OpenAI
LLM_API_KEY=not-needed
اولین بوت مدلها را دانلود میکند (~۱.۵GB: امبدینگ + ریرنکر) و در والیوم
chatbot_cache کش میشود؛ بوتهای بعدی چند ثانیه طول میکشد.
اجرای محلی بدون داکر:
cd chatbot
python -m venv .venv && source .venv/bin/activate # ویندوز: .venv\Scripts\activate
pip install -r requirements.txt
export DATABASE_URL="postgresql+psycopg://aramesh:PASS@localhost:5432/arameshplaza"
export LLM_BASE_URL="http://…" LLM_MODEL="openai/gpt-oss-120b"
uvicorn chatbot.app:api --port 8000 # از ریشه پوشه والد
منابع مورد نیاز
- رم: با ریرنکر ~۴GB (مدل ۵۶۸M پارامتری روی CPU)؛ بدون ریرنکر ~۲GB
- CPU: امبدینگ و ریرنک روی CPU اجرا میشوند؛ GPU لازم نیست
- شبکه: دسترسی به PostgreSQL و به نشانی
LLM_BASE_URL
نکات امنیتی
- دیتابیس سایت فقط خواندن؛ نوشتن فقط در دیتابیس اختصاصی
aramesh_chatbotانجام میشود - محدودسازی نرخ per-IP فعال است (پیشفرض ۲۰ پیام در ۵ دقیقه)
- CORS باز است ولی کوکی/اعتبارنامهای رد و بدل نمیشود؛ در تولید همهچیز هممبدأ (پشت Traefik) است