Ollama: نشر المشروع وتحسينه: نظام خدمة العملاء الذكي
النشر والتحسين هو حفل تخرج SupportBot — من التطوير إلى الإنتاج، من الوظيفي إلى المتميز.
⚠️ ملاحظة: قبل النشر، أكمل قائمة فحص الأمان — ① الطلبات بدون API Key تُرجع 401؛ ② الطلبات المحدودة المعدل تُرجع 429؛ ③ المنفذ 11434 غير متاح خارجيًا؛ ④ شهادة SSL صالحة وHTTPS مفروض؛ ⑤ تصفية المدخلات/المخرجات تعمل. إعدادات الأمان "تبدو صحيحة" ≠ "تعمل فعليًا" — اختبر كل عنصر بـ
curl.
📋 المتطلبات المسبقة: يجب أن تتقن أولاً ما يلي
1. ما ستتعلمه
- إعدادات Docker Compose للإنتاج: Ollama + FastAPI + Chroma + Nginx
- قياس الأداء: TTFT / رموز/ثانية / تحسين السعة المتزامنة
- تعزيز الأمان: مصادقة API Key، تحديد المعدل، تصفية المخرجات
- دمج المراقبة: جمع مقاييس Prometheus + لوحات Grafana
- قائمة فحص الإطلاق ودليل العمليات
2. خلفية المشروع
💡 نصيحة: أفضل ممارسة لإدارة متغيرات بيئة الإنتاج — جميع المفاتيح والإعدادات الحساسة يجب حقنها عبر ملفات
.env أو مدير الأسرار، ولا يجب ترميزها أبدًا في الكود أو ملفات Docker Compose. أضف .env إلى .gitignore؛ قدّم فقط قالب .env.example في المستودع.
(1) قضايا رئيسية قبل النشر
SupportBot الخاص بأليس مطور لكنه يواجه تحديات النشر:
| القضية | المخاطرة | الحل |
|---|---|---|
| نشر آلي واحد، بلا تكرار | انقطاع الخدمة | Docker Compose متعدد الخدمات |
| بلا مصادقة، API مكشوف | ثغرة أمنية | Nginx + API Key |
| نقاط عمياء في المراقبة | اكتشاف بطيء للأعطال | Prometheus + Grafana |
| أداء غير مُتحقق | زمن انتقال يتجاوز الهدف | قياس الأداء + الضبط |
| بلا وثائق عمليات | تعافٍ بطيء من الأعطال | دليل العمليات |
3. إعدادات Docker Compose للإنتاج
⚠️ تحذير: في الإنتاج،
OLLAMA_HOST=0.0.0.0 لـ Ollama آمن فقط ضمن شبكة Docker الداخلية؛ المنفذ 11434 يجب ألا يُعرّض مباشرة للإنترنت العامة. Nginx هو نقطة الدخول الخارجية الوحيدة ويجب تكوينه بمصادقة API Key وHTTPS.
(1) بنية الإنتاج
flowchart TD
A[الإنترنت<br/>:443] --> B[Nginx<br/>SSL + مصادقة + تحديد معدل]
B --> C[FastAPI SupportBot<br/>:8000]
C --> D[Ollama<br/>:11434<br/>تسريع GPU]
C --> E[Chroma<br/>:8001<br/>مخزن متجهي]
F[Prometheus<br/>:9090] --> G[جميع الخدمات<br/>جمع المقاييس]
G --> H[Grafana<br/>:3001<br/>لوحات المراقبة]
(2) قائمة الخدمات
| الخدمة | الصورة | المنفذ | الموارد | الثبات |
|---|---|---|---|---|
| nginx | nginx:alpine | 80/443 | 1 vCPU، 512 ميجابايت | ملفات الإعدادات |
| supportbot | مخصصة | 8000 | 2 vCPU، 4 جيجابايت | — |
| ollama | ollama/ollama | 11434 | 8 vCPU، 16 جيجابايت، 1x GPU | ollama_data |
| chroma | chromadb/chroma | 8001 | 2 vCPU، 4 جيجابايت | chroma_data |
| prometheus | prom/prometheus | 9090 | 1 vCPU، 2 جيجابايت | prometheus_data |
| grafana | grafana/grafana | 3001 | 1 vCPU، 1 جيجابايت | grafana_data |
(1) ▶ مثال: Docker Compose للإنتاج
YAML
# docker-compose.prod.yml
version: "3.8"
services:
nginx:
image: nginx:alpine
container_name: supportbot-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/ssl/certs:ro
depends_on:
supportbot:
condition: service_healthy
restart: unless-stopped
supportbot:
build:
context: ./app
dockerfile: Dockerfile
container_name: supportbot-api
ports:
- "8000:8000"
environment:
- OLLAMA_HOST=http://ollama:11434
- CHROMA_HOST=http://chroma:8000
- API_KEY=${SUPPORTBOT_API_KEY}
- CHAT_MODEL=qwen2.5
- CLASSIFIER_MODEL=llama3.2:3b
- EMBED_MODEL=nomic-embed-text
depends_on:
ollama:
condition: service_healthy
chroma:
condition: service_started
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 15s
timeout: 5s
retries: 3
restart: unless-stopped
ollama:
image: ollama/ollama
container_name: supportbot-ollama
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
environment:
- OLLAMA_HOST=0.0.0.0:11434
- OLLAMA_NUM_PARALLEL=4
- OLLAMA_KEEP_ALIVE=30m
- OLLAMA_MAX_LOADED_MODELS=2
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:11434/api/tags"]
interval: 30s
timeout: 10s
retries: 5
restart: unless-stopped
chroma:
image: chromadb/chroma
container_name: supportbot-chroma
ports:
- "8001:8000"
volumes:
- chroma_data:/chroma/chroma
environment:
- ANONYMIZED_TELEMETRY=FALSE
restart: unless-stopped
prometheus:
image: prom/prometheus
container_name: supportbot-prometheus
ports:
- "9090:9090"
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
restart: unless-stopped
grafana:
image: grafana/grafana
container_name: supportbot-grafana
ports:
- "3001:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
depends_on: [prometheus]
restart: unless-stopped
volumes:
ollama_data:
chroma_data:
prometheus_data:
grafana_data:
⚠️ تحذير أمني: كلمة مرور المشرف الافتراضية في Grafana هي
admin — يجب تغييرها فورًا بعد أول تسجيل دخول! في الإنتاج، حدد كلمة مرور قوية عبر متغير البيئة GRAFANA_PASSWORD، مثلاً: GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}، واضبط قيمة كلمة مرور مولّدة عشوائيًا في ملف .env.
الإخراج:
TEXT
Docker Compose production deployment successful, all services healthy
(2) ▶ مثال: إعدادات Nginx للإنتاج
NGINX
# nginx/nginx.conf
worker_processes auto;
events {
worker_connections 1024;
}
http {
# Rate limiting zone
limit_req_zone $binary_remote_addr zone=api:10m rate=60r/m;
upstream supportbot {
server supportbot:8000;
}
# Redirect HTTP to HTTPS
server {
listen 80;
return 301 https://$host$request_uri;
}
# HTTPS server
server {
listen 443 ssl;
server_name ai.globalshop.example.com;
ssl_certificate /etc/ssl/certs/server.crt;
ssl_certificate_key /etc/ssl/certs/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
# SupportBot API
location /v1/ {
limit_req zone=api burst=20 nodelay;
# API Key authentication
if ($http_x_api_key = "") {
return 401 '{"error": "API key required"}';
}
proxy_pass http://supportbot;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
}
# Health check (no auth)
location /health {
proxy_pass http://supportbot/health;
}
}
}
الإخراج:
TEXT
// Execution successful
4. قياس الأداء والتحسين
💡 نصيحة: دائمًا "سخّن" قبل قياس الأداء — أرسل 1-2 طلب لتحميل النموذج على GPU. الطلب الأول يشمل وقت تحميل النموذج (بدء تشغيل بارد 5-30 ثانية)؛ الطلبات اللاحقة تعكس زمن انتقال الاستنتاج الفعلي.
OLLAMA_KEEP_ALIVE يتحكم في وقت بقاء النموذج.
(1) أهداف الأداء الرئيسية
| المقياس | الهدف | طريقة الاختبار |
|---|---|---|
| TTFT | < 500 مللي ثانية | قياس زمن انتظار أول رمز |
| زمن الانتقال P95 | < 3 ثوانٍ | 100 طلب، خذ P95 |
| الإنتاجية | > 20 QPS | اختبار متزامن |
| معدل الحل التلقائي | > 80% | تقييم 100 سؤال حقيقي |
(3) ▶ مثال: نص قياس الأداء
PYTHON
# benchmark.py
import asyncio
import aiohttp
import time
import json
import statistics
import os
API_URL = "http://localhost:8000/v1/chat"
API_KEY = os.environ.get("SUPPORTBOT_API_KEY", "your-api-key-here")
TEST_QUESTIONS = [
"What is the return policy?",
"How long does shipping take?",
"Combien coûte la livraison?",
"I received a damaged item, what do I do?",
"Compare the wireless headphones models",
"Where is order #88765?",
"What is the return policy?",
"My product broke after 2 weeks, I want a refund!",
"Do you ship to Germany?",
"What is the warranty for electronics?",
]
async def single_request(session: aiohttp.ClientSession, question: str) -> dict:
start = time.time()
try:
async with session.post(
API_URL,
json={"message": question},
headers={"X-Api-Key": API_KEY},
timeout=aiohttp.ClientTimeout(total=30)
) as response:
data = await response.json()
elapsed = time.time() - start
return {
"question": question[:40],
"latency_s": round(elapsed, 2),
"intent": data.get("intent", "?"),
"handler": data.get("handler", "?"),
"language": data.get("language", "?"),
"status": "success" if response.status == 200 else "error"
}
except Exception as e:
return {"question": question[:40], "latency_s": round(time.time() - start, 2),
"status": "error", "error": str(e)}
async def run_benchmark(concurrency: int = 1, total_requests: int = 50) -> dict:
async with aiohttp.ClientSession() as session:
# Warm up
await single_request(session, "Hello")
# Run benchmark
start = time.time()
tasks = []
for i in range(total_requests):
q = TEST_QUESTIONS[i % len(TEST_QUESTIONS)]
tasks.append(single_request(session, q))
if len(tasks) >= concurrency:
results = await asyncio.gather(*tasks)
tasks = []
if tasks:
results += await asyncio.gather(*tasks)
total_time = time.time() - start
latencies = [r["latency_s"] for r in results if r["status"] == "success"]
errors = sum(1 for r in results if r["status"] == "error")
return {
"concurrency": concurrency,
"total_requests": total_requests,
"total_time_s": round(total_time, 1),
"errors": errors,
"error_rate": round(errors / total_requests * 100, 1),
"avg_latency_s": round(statistics.mean(latencies), 2) if latencies else 0,
"p50_latency_s": round(statistics.median(latencies), 2) if latencies else 0,
"p95_latency_s": round(sorted(latencies)[int(len(latencies) * 0.95)], 2) if latencies else 0,
"max_latency_s": round(max(latencies), 2) if latencies else 0,
"throughput_rps": round(total_requests / total_time, 1)
}
if __name__ == "__main__":
print("=== SupportBot Benchmark ===")
for c in [1, 4, 8]:
result = asyncio.run(run_benchmark(concurrency=c, total_requests=20))
print(f"\nConcurrency {c}:")
for k, v in result.items():
print(f" {k}: {v}")
الإخراج:
TEXT
=== SupportBot Benchmark ===
5. تعزيز الأمان
⚠️ تحذير: قبل الإطلاق، تحقق من كل عنصر أمني بشكل فردي — الطلبات بدون API Key يجب أن تُرجع 401، الطلبات المحدودة المعدل يجب أن تُرجع 429، المنفذ 11434 يجب ألا يكون متاحًا خارجيًا. إعدادات الأمان "تبدو صحيحة" ≠ "تعمل فعليًا" — اختبر بـ
curl.
(1) قائمة فحص الأمان
| عنصر الفحص | الإعداد | الحالة |
|---|---|---|
| مصادقة API Key | تحقق Nginx X-Api-Key | ✅ |
| تشفير HTTPS | إعدادات Nginx SSL | ✅ |
| تحديد المعدل | 60 طلب/دقيقة/IP | ✅ |
| تصفية المدخلات | اكتشاف حقن الموجهات | ✅ |
| تصفية المخرجات | تصفية المحتوى الحساس | ✅ |
| تنقية البيانات | إزالة تلقائية لـ PII | ✅ |
| Ollama في شبكة داخلية | ربط 127.0.0.1 | ✅ |
(4) ▶ مثال: وسيط أمان متكامل
PYTHON
# security.py - FastAPI security middleware
from fastapi import Request, HTTPException
from fastapi.responses import JSONResponse
import re
import time
from collections import defaultdict
class SecurityMiddleware:
def __init__(self, api_key: str, rate_limit: int = 60):
self.api_key = api_key
self.rate_limit = rate_limit
self.request_counts: dict = defaultdict(list)
self.injection_patterns = [
r"ignore\s+(previous|all)\s+instructions",
r"you\s+are\s+now\s+DAN",
r"show\s+(me\s+)?(your\s+)?system\s+prompt",
r"reveal\s+(your|the)\s+(initial|system)",
]
self.output_patterns = [
r"system\s*prompt[:\s]",
r"RETURN_POLICY_INTERNAL",
r"INTERNAL_PRICING",
]
def check_api_key(self, request: Request) -> bool:
key = request.headers.get("X-Api-Key", "")
return key == self.api_key
def check_rate_limit(self, client_ip: str) -> bool:
now = time.time()
self.request_counts[client_ip] = [
t for t in self.request_counts[client_ip]
if now - t < 60
]
if len(self.request_counts[client_ip]) >= self.rate_limit:
return False
self.request_counts[client_ip].append(now)
return True
def check_input(self, text: str) -> tuple[bool, str]:
for pattern in self.injection_patterns:
if re.search(pattern, text, re.IGNORECASE):
return False, "Potential prompt injection detected"
return True, ""
def check_output(self, text: str) -> tuple[bool, str]:
for pattern in self.output_patterns:
if re.search(pattern, text, re.IGNORECASE):
return False, "Sensitive content in response filtered"
return True, ""
def sanitize_pii(self, text: str) -> str:
text = re.sub(r"[\w.-]+@[\w.-]+\.\w+", "[EMAIL_REDACTED]", text)
text = re.sub(r"\b\d{3}[-.]?\d{3}[-.]?\d{4}\b", "[PHONE_REDACTED]", text)
text = re.sub(r"\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b", "[CC_REDACTED]", text)
return text
الإخراج:
TEXT
# Function defined successfully
6. دمج المراقبة
ℹ️ معلومة: مراقبة GPU يُوصى بها باستخدام DCGM Exporter (رسمي من NVIDIA)، الذي يمكنه جمع مقاييس استخدام GPU، واستخدام VRAM، ودرجة الحرارة، واستهلاك الطاقة. بالدمج مع قالب GPU Dashboard في Grafana، يمكنك بناء لوحة تصور بسرعة لاكتشاف مخاطر OOM والارتفاع الحراري مسبقًا.
(1) مقاييس لوحة Grafana
| اللوحة | المقياس | الوحدة | التنبيه |
|---|---|---|---|
| زمن انتقال الطلبات | supportbot_request_duration_seconds | ثانية | P95 > 3 ثوانٍ |
| معدل الطلبات | supportbot_requests_total | طلب/دقيقة | < 5 طلب/دقيقة |
| معدل الخطأ | supportbot_errors_total | % | > 5% |
| استخدام GPU | DCGM_FI_DEV_GPU_UTIL | % | > 95% |
| استخدام VRAM | DCGM_FI_DEV_FB_USED | ميجابايت | > 95% |
| توزيع النوايا | supportbot_intent_count | عدد | — |
(5) ▶ مثال: إعدادات Prometheus
YAML
# monitoring/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: "supportbot"
static_configs:
- targets: ["supportbot:8000"]
metrics_path: /metrics
- job_name: "ollama"
static_configs:
- targets: ["ollama:11434"]
metrics_path: /metrics
scheme: http
- job_name: "node"
static_configs:
- targets: ["node-exporter:9100"]
rule_files:
- "alert_rules.yml"
# alert_rules.yml
groups:
- name: supportbot_alerts
rules:
- alert: HighLatency
expr: histogram_quantile(0.95, rate(supportbot_request_duration_seconds_bucket[5m])) > 3
for: 5m
labels:
severity: warning
annotations:
summary: "SupportBot P95 latency above 3s"
- alert: ServiceDown
expr: up{job="supportbot"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "SupportBot service is down"
- alert: HighErrorRate
expr: rate(supportbot_errors_total[5m]) / rate(supportbot_requests_total[5m]) > 0.05
for: 3m
labels:
severity: warning
annotations:
summary: "SupportBot error rate above 5%"
الإخراج:
TEXT
# Prometheus configuration loaded successfully
# Target status: 3 scrape targets all UP
# supportbot (UP) | ollama (UP) | node-exporter (UP)
7. مثال شامل: قائمة فحص الإطلاق ودليل العمليات
💡 نصيحة: قيمة دليل العمليات تظهر عند حدوث الأعطال. أجرِ "تمرين حريق" ربع سنوي — أوقف خدمة عمدًا واتبع الدليل للاسترجاع، متحققًا من دقة الوثائق وقابليتها للتشغيل، ومحدّثًا الخطوات القديمة.
PYTHON
# ============================================
# Comprehensive: Production deployment checklist
# Final verification before going live
# ============================================
PRODUCTION_CHECKLIST = {
"infrastructure": {
"items": [
"Docker Compose services all running (6/6)",
"Ollama health check passing",
"Chroma health check passing",
"FastAPI health check passing",
"Nginx SSL certificate valid (not expired)",
"GPU acceleration verified (nvidia-smi inside container)",
],
"commands": [
"docker compose ps",
"curl -f http://localhost:11434/api/tags",
"curl -f http://localhost:8001/api/v1/heartbeat",
"curl -f http://localhost:8000/health",
"curl -f https://ai.globalshop.example.com/health",
]
},
"models": {
"items": [
"qwen2.5:7b pulled and verified",
"llama3.2:3b pulled and verified",
"nomic-embed-text pulled and verified",
"supportbot Modelfile created and tested",
],
"commands": [
"docker exec supportbot-ollama ollama list",
"docker exec supportbot-ollama ollama run supportbot 'Hello'",
]
},
"security": {
"items": [
"API Key authentication working (unauthorized request returns 401)",
"Rate limiting working (burst above limit returns 429)",
"Input injection filter tested",
"Output content filter tested",
"PII sanitization verified",
"Ollama not accessible from internet (port 11434 blocked)",
]
},
"performance": {
"items": [
"Single request latency < 3s (P95)",
"Concurrent 4 requests latency < 5s (P95)",
"Throughput > 10 QPS",
"RAG retrieval relevant (top-3 precision > 80%)",
"Intent classification accuracy > 85%",
]
},
"monitoring": {
"items": [
"Prometheus scraping all services",
"Grafana dashboards created and visible",
"Alert rules configured and tested",
"Log aggregation working",
]
},
"disaster_recovery": {
"items": [
"All configs in Git repository",
"Chroma data backup scheduled (daily)",
"Model files backed up on NFS/S3",
"Recovery procedure documented and tested",
]
}
}
def generate_runbook() -> str:
"""Generate operations runbook."""
runbook = [
"# SupportBot Operations Runbook\n",
"## Service Overview",
"- SupportBot API: https://ai.globalshop.example.com/v1/chat",
"- Health Check: https://ai.globalshop.example.com/health",
"- Grafana: http://localhost:3001 ⚠️ Change default admin password immediately!",
"- Prometheus: http://localhost:9090\n",
"## Common Operations\n",
"### Restart a Service",
"```bash",
"docker compose restart supportbot # Restart API",
"docker compose restart ollama # Restart Ollama",
"```\n",
"### Pull New Model",
"```bash",
"docker exec supportbot-ollama ollama pull model_name",
"```\n",
"### Rebuild Knowledge Base",
"```bash",
"docker exec supportbot-api python indexer.py /app/product_docs",
"```\n",
"### Check Logs",
"```bash",
"docker compose logs -f supportbot # API logs",
"docker compose logs -f ollama # Ollama logs",
"```\n",
"### Emergency: Service Down",
"1. Check: `docker compose ps`",
"2. Restart: `docker compose restart <service>`",
"3. Verify: `curl https://ai.globalshop.example.com/health`",
"4. If Ollama OOM: restart with `OLLAMA_NUM_PARALLEL=2`",
"5. Escalate: notify ops team\n",
"## Performance Baseline",
"| Metric | Target | Current |",
"|:-------|:-------|:--------|",
"| P95 Latency | < 3s | _fill after benchmark_ |",
"| Throughput | > 10 QPS | _fill after benchmark_ |",
"| Error Rate | < 1% | _fill after benchmark_ |",
"| GPU Util | < 85% | _fill after benchmark_ |",
]
return "\n".join(runbook)
# Generate and save
if __name__ == "__main__":
print(generate_runbook())
with open("RUNBOOK.md", "w") as f:
f.write(generate_runbook())
print("\nRunbook saved: RUNBOOK.md")
❓ أسئلة شائعة
س كم يستغرق أول تشغيل بعد النشر؟
ج سحب النموذج يستغرق حوالي 10-30 دقيقة (حسب سرعة الشبكة وحجم النموذج). إعادة التشغيل اللاحقة تستغرق حوالي 30 ثانية (النماذج مخزنة مؤقتًا في Volume). اسحب النماذج مسبقًا.
س كيف أحصل على شهادات SSL للإنتاج؟
ج استخدم certbot لشهادات Let's Encrypt المجانية، أو Caddy لـ HTTPS التلقائي. الشهادات الموقعة ذاتيًا تعمل للشبكات الداخلية.
س كيف أتحقق أن إعدادات الأمان تعمل فعليًا؟
ج 1) الطلبات بدون API Key يجب أن تُرجع 401؛ 2) الطلبات المحدودة المعدل يجب أن تُرجع 429؛ 3) المنفذ 11434 يجب ألا يكون متاحًا خارجيًا؛ 4) هجمات الحقن يجب أن تُحظر. اختبر كل عنصر.
س كم يستغرق تكوين لوحات المراقبة؟
ج اللوحات الأساسية حوالي ساعة واحدة (استورد قالب Node Exporter + لوحة Ollama مخصصة). قواعد التنبيه حوالي 30 دقيقة. الإجمالي حوالي ساعتين.
س كيف أحسّن SupportBot باستمرار بعد الإطلاق؟
ج 1) حلل السجلات للإجابات منخفضة الجودة؛ 2) أضف وثائق لقاعدة المعرفة؛ 3) حسّن تصنيف النوايا؛ 4) وسّع أمثلة MESSAGE في Modelfile؛ 5) أعد تشغيل قياسات الأداء دوريًا.
س كيف أعود لإصدار سابق؟
ج Git checkout لملفات الإعدادات → docker compose down → docker compose up -d. بيانات النماذج في Volumes غير متأثرة. بيانات Chroma يمكن استرجاعها من النسخ الاحتياطي.
📖 ملخص
- إعدادات Docker Compose للإنتاج تشمل 6 خدمات: Nginx + FastAPI + Ollama + Chroma + Prometheus + Grafana
- أهداف الأداء: P95 < 3 ثوانٍ، إنتاجية > 10 QPS، معدل حل تلقائي > 80%
- تعزيز الأمان: API Key + HTTPS + تحديد معدل + تصفية مدخلات/مخرجات + تنقية بيانات
- دمج المراقبة: جمع Prometheus + تصور Grafana + تنبيهات Alertmanager
- قائمة فحص الإطلاق تغطي 6 مجالات: البنية التحتية، النماذج، الأمان، الأداء، المراقبة، التعافي من الكوارث
- دليل العمليات يشمل العمليات اليومية، استكشاف الأخطاء، خطوط أساس الأداء، وإجراءات الطوارئ
📝 تمارين
- أساسي (⭐): انشر نسخة SupportBot مصغّرة باستخدام Docker Compose (Ollama + FastAPI)، وتحقق أن نقطة /health تُرجع OK.
- متوسط (⭐⭐): شغّل نص قياس الأداء، سجّل زمن الانتقال P95 والإنتاجية ومعدل الخطأ، وقارنها بالأهداف. إذا لم تتحقق الأهداف، عدّل OLLAMA_NUM_PARALLEL أو num_ctx وأعد الاختبار.
- متقدم (⭐⭐⭐): أكمل نشر SupportBot الكامل للإنتاج — بما في ذلك إعدادات أمان Nginx + مراقبة Prometheus/Grafana + قواعد التنبيه + دليل العمليات — ونفذ التحقق الكامل لقائمة فحص الإطلاق.