دستیار هوشمند سایت (چتبات)
سرویس گفتگوی محتوای سایت «گروه ساختمانی آرامش» — بازدیدکننده به فارسی سؤال میپرسد و دستیار فقط از روی محتوای خود سایت (مقالهها، پروژهها، خدمات، سؤالات متداول، اطلاعات تماس و…) پاسخ میدهد؛ اگر پاسخ در محتوا نباشد، بهجای ساخت جواب، صادقانه اعلام میکند.
این سرویس پورت خط لولهٔ پروژهٔ 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، و متنهای مدیریت محتوا: stats، hero، page_heroes، section_headings،
footer، before_after). سطرهای جایگاهخالی (متن زیر ~۳۰ نویسه) ایندکس نمیشوند.
متنهای بلند به قطعات ~۷۰۰ نویسهای همپوشان برش میخورند.
- ایندکس برداری در pgvector: جدول
chatbot_chunksدر دیتابیس اختصاصیaramesh_chatbot(روی همان نمونه Postgres) با ستونembedding vector(384)و ایندکس HNSW کسینوسی؛ هر قطعهdoc_idپایدار (شامل url:type:url-key:occ:chunk) وcontent_hashدارد و همگامسازی فقط سطرهای جدید/تغییریافته را امبد میکند. دیتابیس و جدول در شروع سرویس خودکار ساخته میشوند. - تیتر در متن قطعه: در سندهای تکقطعهای که تیترشان در متن نیست (مثلاً نام پروژه)، تیتر به ابتدای متن میچسبد تا BM25 و جستوجوی معنایی پیدایش کنند.
- بازسازی خودکار: یک حلقهٔ پسزمینه هر
INDEX_REFRESH_SECONDSثانیه محتوا را چک میکند و اگر ادمین چیزی را در پنل عوض کرده باشد، فقط تغییرات همگام میشود (امبد اجباری همه:POST /chat/reindex). - ماندگاری گفتگو: در حافظهٔ همان پروسه (MemorySaver لنگگراف) — با ریاستارت پاک میشود.
- گزارش گفتگوها: هر پاسخ (بههمراه تعداد سند بازیابیشده، تشخیص «پاسخی نبود» و تأخیر)
در جدول
chat_logsهمان دیتابیس ذخیره میشود تا پرسشهای بیپاسخ — یعنی شکافهای دانش — قابل کشف باشند؛GET /chat/statsجمعبندی میدهد.
متغیرهای محیطی (در .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, "fallback": true |
GET /chat/suggestions |
۴ پیشنهاد پرسش (کش ۱۰ دقیقه؛ جایگزین: خود سؤالات متداول) |
GET /chat/eval?message=… |
مخصوص ارزیابی — پاسخ + اسناد بازیابیشده با thread تازه |
GET /chat/stats |
آمار گفتگوها (کل، ۷ روز اخیر، نرخ پیام جایگزین)؛ فهرست پرسشهای بیپاسخ اخیر فقط با هدر X-Reindex-Token |
GET /chat/healthz |
وضعیت ایندکس/LLM/تعداد اسناد |
POST /chat/reindex |
بازسازی اجباری ایندکس (هدر X-Reindex-Token) |
مسیرهای GET /chat/{scope}/stream|eval|suggestions هم برای سازگاری با اسکریپت
eval_ragas.py قدیمی موجود است — کافی است --url را به نشانی این سرویس بدهید.
ارزیابی
مجموعه طلایی eval_set.json (پرسشهای واقعی از محتوای دیتابیس + یک کنترل مثبت برای
«نباید قیمت بسازد») با eval_run.py اجرا میشود — داخل کانتینر:
docker exec aramesh-site-chatbot-1 python /srv/chatbot/eval_run.py --out /tmp/report.md
docker exec aramesh-site-chatbot-1 cat /tmp/report.md
خروجی: وضعیت هر پرسش (pass / miss / manual / fallback-expected / unexpected-fallback)،
منابع بازیابیشده و زمان پاسخ — برای سنجش اثر تغییرات دانش و کشف پسرفتها.
اجرا
با داکر (بخشی از استک اصلی است — 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) است