Ollama: نشر المشروع وتحسينه: نظام خدمة العملاء الذكي

النشر والتحسين هو حفل تخرج SupportBot — من التطوير إلى الإنتاج، من الوظيفي إلى المتميز.

⚠️ ملاحظة: قبل النشر، أكمل قائمة فحص الأمان — ① الطلبات بدون API Key تُرجع 401؛ ② الطلبات المحدودة المعدل تُرجع 429؛ ③ المنفذ 11434 غير متاح خارجيًا؛ ④ شهادة SSL صالحة وHTTPS مفروض؛ ⑤ تصفية المدخلات/المخرجات تعمل. إعدادات الأمان "تبدو صحيحة" ≠ "تعمل فعليًا" — اختبر كل عنصر بـ curl.

📋 المتطلبات المسبقة: يجب أن تتقن أولاً ما يلي

1. ما ستتعلمه


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) بنية الإنتاج

100%
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 يمكن استرجاعها من النسخ الاحتياطي.

📖 ملخص


📝 تمارين

  1. أساسي (⭐): انشر نسخة SupportBot مصغّرة باستخدام Docker Compose (Ollama + FastAPI)، وتحقق أن نقطة /health تُرجع OK.
  2. متوسط (⭐⭐): شغّل نص قياس الأداء، سجّل زمن الانتقال P95 والإنتاجية ومعدل الخطأ، وقارنها بالأهداف. إذا لم تتحقق الأهداف، عدّل OLLAMA_NUM_PARALLEL أو num_ctx وأعد الاختبار.
  3. متقدم (⭐⭐⭐): أكمل نشر SupportBot الكامل للإنتاج — بما في ذلك إعدادات أمان Nginx + مراقبة Prometheus/Grafana + قواعد التنبيه + دليل العمليات — ونفذ التحقق الكامل لقائمة فحص الإطلاق.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%