مجله ایرانیکاسرور آموزش سرور، هاست، وردپرس و شبکه پنل کاربری

ساخت Text-to-SQL فارسی روی VPS؛ پرس‌وجوی هوشمند MySQL و PostgreSQL با زبان طبیعی و هوش مصنوعی

اگر بتوانید به‌جای نوشتن Query پیچیده SQL، سؤال خود را فارسی بپرسید و پاسخ را مستقیماً از دیتابیس بگیرید چه؟ در این آموزش یک سرویس واقعی Text-to-SQL می‌سازیم که روی VPS اجرا می‌شود، سؤال…

✍ Amir Jabbari 📅 9 مهر 1405 ⏱ 20 دقیقه مطالعه 👁 4 بازدید 💬 0 دیدگاه

اگر بتوانید به‌جای نوشتن Query پیچیده SQL، سؤال خود را فارسی بپرسید و پاسخ را مستقیماً از دیتابیس بگیرید چه؟ در این آموزش یک سرویس واقعی Text-to-SQL می‌سازیم که روی VPS اجرا می‌شود، سؤال فارسی کاربر را به SQL تبدیل می‌کند، ساختار دیتابیس را در اختیار مدل قرار می‌دهد، Query را فقط در حالت خواندنی اجرا می‌کند و نتیجه را برمی‌گرداند.

این معماری برای دیتابیس‌های MySQL و PostgreSQL طراحی شده و می‌تواند برای داشبوردهای داخلی، پنل‌های مدیریتی، گزارش‌گیری فروش، تحلیل سفارش‌ها، CRM، سیستم‌های مالی و سرویس‌های SaaS کاربرد داشته باشد. بخش هوش مصنوعی نیز می‌تواند به‌صورت محلی روی همان VPS اجرا شود تا وابستگی به ارسال مستقیم اطلاعات دیتابیس به سرویس‌های ابری کاهش پیدا کند.

📌 در این آموزش دقیقاً چه می‌سازیم؟

🔹 یک API با Python و FastAPI برای دریافت سؤال فارسی

🔹 اتصال امن به MySQL یا PostgreSQL با SQLAlchemy

🔹 استخراج ساختار جدول‌ها و ستون‌ها

🔹 ارسال Schema و سؤال به مدل زبانی محلی

🔹 تبدیل سؤال فارسی به SQL

🔹 جلوگیری از اجرای INSERT، UPDATE، DELETE، DROP و سایر دستورات تغییر‌دهنده

🔹 محدود کردن تعداد رکوردهای خروجی

🔹 نمایش SQL تولیدشده و نتیجه Query

فهرست مطالب

Text-to-SQL فارسی چیست و چرا روی VPS ارزش دارد؟

Text-to-SQL یا NL2SQL به سیستمی گفته می‌شود که یک سؤال انسانی را به دستور SQL تبدیل می‌کند. تفاوت مهم این روش با یک چت‌بات معمولی این است که مدل فقط متن تولید نمی‌کند؛ بلکه باید سؤال را به ساختار واقعی دیتابیس ارتباط دهد.

برای مثال فرض کنید دیتابیس فروشگاه شما جدولی به نام orders دارد و ستون‌های آن شامل id، customer_id، amount و created_at است. کاربر می‌تواند بپرسد:

«مجموع فروش سه ماه گذشته چقدر بوده است؟»

مدل باید تشخیص دهد که برای پاسخ، به ستون مبلغ و تاریخ نیاز دارد و سپس Query مناسب را تولید کند. در یک پیاده‌سازی حرفه‌ای، نباید به مدل اجازه داد هر SQL دلخواهی را اجرا کند. به همین دلیل در این مقاله لایه امنیتی جداگانه‌ای برای Read Only SQL در نظر می‌گیریم.

آیا این موضوع تکراری است؟ تفاوت این آموزش با Text-to-SQLهای معمولی

جست‌وجوی فعلی وب نشان می‌دهد پروژه‌های مختلفی برای NL2SQL وجود دارند؛ از ابزارهای Self-hosted گرفته تا پروژه‌هایی که PostgreSQL و MySQL را پشتیبانی می‌کنند. برای نمونه، پروژه‌هایی مانند NLQueries و چند پیاده‌سازی متن‌باز دیگر از تبدیل زبان طبیعی به SQL استفاده می‌کنند. در برخی از آن‌ها نیز اعتبارسنجی Query، Schema Retrieval و اجرای Read Only دیده می‌شود.

بنابراین صرفاً نوشتن مقاله‌ای با عنوان «تبدیل متن به SQL» ارزش آموزشی زیادی ایجاد نمی‌کند. زاویه این مقاله روی کاربر فارسی‌زبان، نصب واقعی روی VPS، مدل محلی، اتصال هم‌زمان به MySQL/PostgreSQL، کنترل دستورات خطرناک و ساخت API قابل توسعه قرار گرفته است.

برای طراحی این معماری از الگوی اتصال دیتابیس در SQLAlchemy و API محلی Ollama استفاده می‌کنیم. SQLAlchemy برای URLهای اتصال دیتابیس از ساختاری مانند dialect و driver و host و port استفاده می‌کند و Ollama نیز API محلی برای ارسال پیام به مدل ارائه می‌دهد.

مستندات رسمی SQLAlchemy درباره Engine و Database URL و صفحه رسمی Qwen3 در Ollama منابع اصلی این بخش هستند.

معماری پیشنهادی Text-to-SQL روی VPS

قبل از نصب، بهتر است مسیر داده را مشخص کنیم. معماری ساده و قابل توسعه این پروژه به شکل زیر است:

سؤال فارسی کاربر

↓

FastAPI

↓

Schema دیتابیس + Prompt

↓

LLM محلی با Ollama

↓

اعتبارسنجی SQL

↓

MySQL / PostgreSQL

↓

نتیجه قابل نمایش

برای Text-to-SQL فارسی چه VPSای لازم داریم؟

منابع موردنیاز به مدل انتخابی بستگی دارد. اگر مدل زبانی روی همان VPS اجرا شود، RAM و CPU اهمیت زیادی پیدا می‌کنند. برای مدل‌های بزرگ‌تر نیز GPU می‌تواند زمان پاسخ را کاهش دهد.

سناریو RAM پیشنهادی CPU GPU
آزمایش و مدل کوچک 8GB 4 هسته ضروری نیست
کاربری متوسط 16GB 6 تا 8 هسته اختیاری
مدل بزرگ‌تر و کاربران هم‌زمان 32GB+ 8 هسته+ توصیه می‌شود
سرویس سازمانی با LLM سنگین 64GB+ CPU قدرتمند GPU مناسب

نکته: این اعداد نسخه سخت‌افزاری ثابت و تضمین‌شده برای همه مدل‌ها نیستند. اندازه مدل، quantization، طول Schema، تعداد کاربران و حجم Query روی مصرف منابع تأثیر مستقیم دارند.

انتخاب مدل هوش مصنوعی برای سؤال فارسی

برای این پروژه می‌توان از مدل‌های چندزبانه استفاده کرد. Qwen3 در نسخه‌های مختلف ارائه شده و در صفحه رسمی Ollama اندازه‌های متفاوتی از مدل آن وجود دارد. نسخه‌های کوچک‌تر برای تست مناسب‌تر هستند و مدل‌های بزرگ‌تر منابع بیشتری نیاز دارند.

مدل کاربرد پیشنهادی فشار روی VPS
Qwen3:4b تست، پروژه کوچک و پرسش‌های ساده کمتر
Qwen3:8b استفاده عمومی متوسط
Qwen3:14b Queryهای پیچیده‌تر بالا
Qwen3:30b-a3b سرور قدرتمند و پروژه‌های جدی‌تر زیاد

صفحه رسمی Ollama برای Qwen3، مدل‌هایی از 0.6B تا اندازه‌های بسیار بزرگ‌تر را فهرست می‌کند و Qwen3 را یک خانواده چندزبانه معرفی می‌کند. برای شروع این آموزش از Qwen3:4b استفاده می‌کنیم تا راه‌اندازی روی VPS ساده‌تر باشد. :contentReference[oaicite:0]{index=0}

مرحله اول: آماده‌سازی Ubuntu روی VPS

در این آموزش فرض می‌کنیم سرور با Ubuntu 24.04 یا نسخه‌ای نزدیک به آن در اختیار دارید و از طریق SSH وارد شده‌اید.

ابتدا سیستم را به‌روزرسانی کنید:

sudo apt update && sudo apt upgrade -y
sudo apt install -y python3 python3-venv python3-pip curl git

سپس برای پروژه یک پوشه جدا ایجاد کنید:

sudo mkdir -p /opt/text-to-sql
sudo chown -R $USER:$USER /opt/text-to-sql
cd /opt/text-to-sql

مرحله دوم: نصب Ollama و مدل هوش مصنوعی

Ollama یک API محلی برای اجرای مدل‌های زبانی فراهم می‌کند. در این پروژه، FastAPI به Ollama درخواست می‌فرستد و پاسخ مدل را دریافت می‌کند.

curl -fsSL https://ollama.com/install.sh | sh

بعد از نصب، سرویس را بررسی کنید:

sudo systemctl status ollama

اگر سرویس فعال بود، مدل را دریافت کنید:

ollama pull qwen3:4b

برای تست سریع:

ollama run qwen3:4b

⚠️ نکته امنیتی درباره Ollama

API مدل را بدون دلیل روی اینترنت عمومی قرار ندهید. اگر FastAPI و Ollama روی همان VPS هستند، بهتر است Ollama فقط از localhost قابل دسترسی باشد و API عمومی شما از طریق Nginx، HTTPS و احراز هویت محافظت شود.

مرحله سوم: ساخت محیط Python

cd /opt/text-to-sql

python3 -m venv .venv
source .venv/bin/activate

pip install --upgrade pip
pip install fastapi uvicorn sqlalchemy pymysql psycopg[binary] requests sqlparse python-dotenv

در اینجا SQLAlchemy نقش لایه مشترک اتصال به دیتابیس را دارد. برای MySQL از درایور PyMySQL و برای PostgreSQL از psycopg استفاده می‌کنیم.

مرحله چهارم: ساخت کاربر Read Only برای دیتابیس

این مهم‌ترین بخش امنیت پروژه است. حتی اگر Prompt مدل کاملاً دقیق نوشته شده باشد، نباید حساب دیتابیس هوش مصنوعی مجوز تغییر اطلاعات داشته باشد.

ساخت کاربر فقط خواندنی در MySQL

CREATE USER 'ai_reader'@'localhost' IDENTIFIED BY 'CHANGE_THIS_PASSWORD';

GRANT SELECT ON shopdb.* TO 'ai_reader'@'localhost';

FLUSH PRIVILEGES;

به‌جای shopdb نام دیتابیس خود را قرار دهید و رمز قوی انتخاب کنید.

ساخت کاربر Read Only در PostgreSQL

CREATE USER ai_reader WITH PASSWORD 'CHANGE_THIS_PASSWORD';

GRANT CONNECT ON DATABASE shopdb TO ai_reader;

GRANT USAGE ON SCHEMA public TO ai_reader;

GRANT SELECT ON ALL TABLES IN SCHEMA public TO ai_reader;

ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO ai_reader;

⚠️ فقط Prompt کافی نیست

جلوگیری از DELETE و DROP نباید فقط به دستور «SQL مخرب ننویس» در Prompt وابسته باشد. دسترسی دیتابیس، Parser و محدودیت‌های اجرای Query باید هم‌زمان استفاده شوند.

مرحله پنجم: ساخت فایل تنظیمات

یک فایل .env بسازید:

nano /opt/text-to-sql/.env

برای PostgreSQL:

DATABASE_URL=postgresql+psycopg://ai_reader:CHANGE_THIS_PASSWORD@127.0.0.1:5432/shopdb
OLLAMA_URL=http://127.0.0.1:11434/api/chat
OLLAMA_MODEL=qwen3:4b
MAX_ROWS=100

برای MySQL می‌توانید DATABASE_URL را به این شکل تغییر دهید:

DATABASE_URL=mysql+pymysql://ai_reader:CHANGE_THIS_PASSWORD@127.0.0.1:3306/shopdb
OLLAMA_URL=http://127.0.0.1:11434/api/chat
OLLAMA_MODEL=qwen3:4b
MAX_ROWS=100

سرور مناسب برای اجرای Text-to-SQL فارسی

اگر قصد دارید مدل هوش مصنوعی، API و دیتابیس را روی یک سرور اجرا کنید، منابع اختصاصی CPU و RAM اهمیت زیادی پیدا می‌کنند. برای دیتابیس نیز دیسک سریع NVMe می‌تواند زمان اجرای Query و عملیات I/O را بهبود دهد.

ایرانیکاسرور برای پروژه‌هایی مانند API هوش مصنوعی، دیتابیس، سرویس‌های Python و ابزارهای Self-hosted، پلن‌های مختلف سرور مجازی ارائه می‌کند.

📞 تماس با پشتیبانی: 021-91302460 | ایرانیکاسرور

مرحله ششم: استخراج Schema دیتابیس

مدل هوش مصنوعی بدون شناخت جدول‌ها و ستون‌ها نمی‌تواند SQL قابل اعتمادی بسازد. در نسخه اولیه پروژه، Schema را از SQLAlchemy می‌گیریم.

فایل app.py را ایجاد کنید:

nano /opt/text-to-sql/app.py

کد زیر یک API ساده اما قابل توسعه ایجاد می‌کند:

import os
import re
import requests

from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from sqlalchemy import create_engine, inspect, text

load_dotenv()

DATABASE_URL = os.getenv("DATABASE_URL")
OLLAMA_URL = os.getenv("OLLAMA_URL", "http://127.0.0.1:11434/api/chat")
OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "qwen3:4b")
MAX_ROWS = int(os.getenv("MAX_ROWS", "100"))

if not DATABASE_URL:
    raise RuntimeError("DATABASE_URL is not configured")

engine = create_engine(
    DATABASE_URL,
    pool_pre_ping=True
)

app = FastAPI(
    title="Persian Text-to-SQL API",
    version="1.0.0"
)


class Question(BaseModel):
    question: str


def get_schema():
    inspector = inspect(engine)
    output = []

    for table_name in inspector.get_table_names():
        columns = inspector.get_columns(table_name)

        column_text = []
        for column in columns:
            name = column["name"]
            dtype = str(column["type"])
            column_text.append(f"- {name}: {dtype}")

        output.append(
            f"TABLE {table_name}\n" +
            "\n".join(column_text)
        )

    return "\n\n".join(output)


def clean_sql(sql):
    sql = sql.strip()

    if sql.startswith("```"):
        sql = re.sub(r"^```[a-zA-Z]*", "", sql)
        sql = re.sub(r"```$", "", sql).strip()

    return sql.strip()


def validate_sql(sql):
    normalized = sql.strip().lower()

    if not normalized.startswith("select"):
        raise HTTPException(
            status_code=400,
            detail="Only SELECT queries are allowed."
        )

    blocked = [
        "insert ",
        "update ",
        "delete ",
        "drop ",
        "alter ",
        "truncate ",
        "create ",
        "grant ",
        "revoke ",
        "replace ",
        "merge "
    ]

    for keyword in blocked:
        if keyword in normalized:
            raise HTTPException(
                status_code=400,
                detail="Unsafe SQL detected."
            )

    if ";" in normalized.rstrip(";"):
        raise HTTPException(
            status_code=400,
            detail="Multiple SQL statements are not allowed."
        )

    return True


def ask_model(question, schema):
    system_prompt = """
You are a SQL generation assistant.

The user asks questions in Persian.

Your task:
1. Understand the Persian question.
2. Use ONLY tables and columns present in the provided schema.
3. Generate exactly ONE SQL SELECT query.
4. Never generate INSERT, UPDATE, DELETE, DROP, ALTER,
   CREATE, TRUNCATE, GRANT or REVOKE.
5. Do not invent tables or columns.
6. Return ONLY SQL.
7. Do not use Markdown fences.
8. Limit the result to a reasonable number of rows when possible.
"""

    user_prompt = f"""
DATABASE SCHEMA:

{schema}

USER QUESTION:

{question}

Generate the SQL SELECT query now.
"""

    response = requests.post(
        OLLAMA_URL,
        json={
            "model": OLLAMA_MODEL,
            "stream": False,
            "messages": [
                {
                    "role": "system",
                    "content": system_prompt
                },
                {
                    "role": "user",
                    "content": user_prompt
                }
            ]
        },
        timeout=120
    )

    response.raise_for_status()

    data = response.json()

    return data["message"]["content"]


@app.get("/health")
def health():
    return {
        "status": "ok",
        "model": OLLAMA_MODEL
    }


@app.get("/schema")
def schema():
    return {
        "schema": get_schema()
    }


@app.post("/ask")
def ask(question: Question):

    if not question.question.strip():
        raise HTTPException(
            status_code=400,
            detail="Question cannot be empty."
        )

    schema_text = get_schema()

    sql = ask_model(
        question.question,
        schema_text
    )

    sql = clean_sql(sql)

    validate_sql(sql)

    with engine.connect() as connection:

        result = connection.execute(
            text(sql)
        )

        rows = result.fetchmany(MAX_ROWS)

        data = [
            dict(row._mapping)
            for row in rows
        ]

    return {
        "question": question.question,
        "sql": sql,
        "rows": data,
        "row_count": len(data)
    }

این کد چگونه سؤال فارسی را به SQL تبدیل می‌کند؟

فرآیند اصلی پروژه ساده است اما چند مرحله مهم دارد:

🔹 کاربر سؤال فارسی را به API ارسال می‌کند.

🔹 برنامه Schema واقعی دیتابیس را می‌خواند.

🔹 Schema همراه با سؤال به مدل ارسال می‌شود.

🔹 مدل فقط یک Query از نوع SELECT تولید می‌کند.

🔹 Query قبل از اجرا بررسی می‌شود.

🔹 Query توسط کاربر Read Only اجرا می‌شود.

🔹 تعداد رکوردهای برگشتی محدود می‌شود.

🔹 SQL و نتیجه برای مصرف‌کننده API ارسال می‌شود.

مرحله هفتم: اجرای Text-to-SQL API

cd /opt/text-to-sql
source .venv/bin/activate

uvicorn app:app --host 127.0.0.1 --port 8000

اگر برنامه بدون خطا اجرا شود، API روی پورت 8000 در دسترس محلی خواهد بود.

برای بررسی سلامت سرویس:

curl http://127.0.0.1:8000/health

پاسخ نمونه:

{
  "status": "ok",
  "model": "qwen3:4b"
}

مرحله هشتم: ارسال اولین سؤال فارسی

اکنون می‌توانیم با curl یک سؤال فارسی به API بفرستیم:

curl -X POST http://127.0.0.1:8000/ask \
-H "Content-Type: application/json" \
-d '{"question":"مجموع فروش سفارش‌های سه ماه گذشته چقدر بوده است؟"}'

اگر Schema شامل جدول سفارش‌ها و ستون‌های مناسب باشد، مدل باید Query متناسب با همان ساختار تولید کند.

📌 نکته مهم درباره دقت

مدل هوش مصنوعی نمی‌تواند ساختار دیتابیس را حدس بزند و همیشه Query صحیح تولید کند. هرچه نام جدول‌ها، روابط، ستون‌ها و توضیحات تجاری دقیق‌تر باشند، احتمال تولید SQL مناسب بیشتر می‌شود. برای سیستم‌های حساس، Query تولیدشده باید قبل از استفاده عملی اعتبارسنجی شود.

چرا فقط فرستادن Schema کامل برای پروژه‌های بزرگ کافی نیست؟

در یک دیتابیس کوچک ممکن است Schema فقط چند جدول داشته باشد. اما در یک سیستم سازمانی ممکن است صدها جدول و هزاران ستون وجود داشته باشد. ارسال کل Schema به مدل باعث افزایش حجم Prompt و احتمال انتخاب جدول اشتباه می‌شود.

در نسخه حرفه‌ای‌تر بهتر است معماری را به سمت Schema Retrieval ببرید. یعنی ابتدا بر اساس سؤال کاربر، جدول‌ها و ستون‌های مرتبط انتخاب شوند و سپس فقط همان بخش از Schema در اختیار مدل قرار گیرد.

برای نمونه، اگر کاربر درباره «فروش ماه گذشته» سؤال کند، سیستم می‌تواند ابتدا جدول‌های مرتبط با سفارش، مشتری، پرداخت و تاریخ را پیدا کند و فقط همان اطلاعات را به LLM بدهد.

افزودن توضیحات فارسی برای جدول‌ها و ستون‌ها

یکی از مشکلات مهم Text-to-SQL این است که نام‌های فنی همیشه معنی تجاری واضحی ندارند. مثلاً مدل ممکن است از نام gmv متوجه مفهوم کسب‌وکار نشود.

می‌توانید یک لایه Metadata برای جدول‌ها ایجاد کنید:

TABLE orders
DESCRIPTION: سفارش‌های ثبت‌شده فروشگاه

COLUMN amount
DESCRIPTION: مبلغ نهایی سفارش به تومان

COLUMN created_at
DESCRIPTION: تاریخ ثبت سفارش

COLUMN status
DESCRIPTION: وضعیت سفارش مانند paid، pending یا cancelled

این روش باعث می‌شود مدل به‌جای تکیه بر نام خام ستون‌ها، از توضیح معنایی آن‌ها نیز استفاده کند.

امنیت Text-to-SQL؛ خطر اصلی کجاست؟

Text-to-SQL مستقیماً با دیتابیس سروکار دارد. بنابراین نباید آن را مانند یک چت‌بات معمولی در نظر گرفت. چند لایه امنیتی باید هم‌زمان وجود داشته باشد.

🔹 کاربر دیتابیس مخصوص AI باید Read Only باشد.

🔹 Query باید قبل از اجرا Parse و بررسی شود.

🔹 اجرای چند Statement در یک درخواست ممنوع شود.

🔹 LIMIT برای Queryهای خروجی‌محور در نظر گرفته شود.

🔹 Timeout برای Queryهای سنگین تنظیم شود.

🔹 API عمومی بدون Authentication منتشر نشود.

🔹 رمز دیتابیس داخل کد قرار نگیرد.

🔹 لاگ‌ها نباید رمز عبور یا اطلاعات حساس Query را ثبت کنند.

⚠️ اجرای SQL تولیدشده توسط LLM را بدون لایه امنیتی انجام ندهید

حتی اگر مدل را مجبور کرده‌اید فقط SELECT تولید کند، یک لایه اعتبارسنجی مستقل و یک حساب دیتابیس محدودشده ضروری است. Prompt به‌تنهایی یک مرز امنیتی محسوب نمی‌شود.

کنترل Queryهای سنگین و جلوگیری از فشار به دیتابیس

ممکن است کاربر سؤالی بپرسد که Query بسیار سنگینی ایجاد کند. برای مثال محاسبه روی میلیون‌ها رکورد یا JOIN چند جدول بزرگ می‌تواند منابع دیتابیس را مصرف کند.

🔹 زمان اجرای Query را محدود کنید.

🔹 تعداد رکورد خروجی را محدود کنید.

🔹 روی ستون‌های پرتکرار Index مناسب داشته باشید.

🔹 Queryهای پرهزینه را در محیط آزمایشی بررسی کنید.

🔹 برای کاربران مختلف سقف مصرف تعریف کنید.

تفاوت Text-to-SQL با داشبوردهای سنتی

ویژگی داشبورد سنتی Text-to-SQL
ساخت گزارش از قبل طراحی می‌شود بر اساس سؤال تولید می‌شود
انعطاف‌پذیری محدود به ویجت‌ها بیشتر
نیاز به SQL اغلب در مرحله ساخت برای کاربر نهایی ضروری نیست
ریسک خطا بیشتر قابل کنترل نیازمند اعتبارسنجی LLM و SQL

Text-to-SQL فارسی برای چه کسب‌وکارهایی مناسب است؟

این معماری فقط برای برنامه‌نویس‌ها نیست. اگر دیتابیس ساختاریافته داشته باشید، می‌توان آن را به ابزار گزارش‌گیری داخلی تبدیل کرد.

🔹 فروشگاه‌های اینترنتی برای پرسش درباره سفارش و فروش

🔹 CRM برای بررسی مشتریان و فعالیت‌ها

🔹 سیستم‌های حسابداری برای گزارش‌های مدیریتی

🔹 SaaSها برای ساخت Data Assistant

🔹 شرکت‌ها برای پرسش سریع از دیتابیس داخلی

🔹 تیم‌های فنی برای ساخت پنل Analytics مبتنی بر زبان طبیعی

ساخت رابط کاربری فارسی برای Text-to-SQL

پس از آماده‌شدن API، می‌توانید یک Frontend ساده بسازید که کاربر سؤال خود را وارد کند و سه بخش نمایش دهد: سؤال، SQL تولیدشده و نتیجه.

📌 پیشنهاد برای رابط کاربری

🔹 یک کادر برای سؤال فارسی

🔹 انتخاب دیتابیس MySQL یا PostgreSQL

🔹 نمایش SQL تولیدشده برای بررسی کاربر فنی

🔹 نمایش جدول نتیجه

🔹 امکان کپی Query

🔹 نمایش زمان اجرای Query

رفع خطای رایج: مدل جدول اشتباه انتخاب می‌کند

اگر مدل مرتباً جدول اشتباه انتخاب می‌کند، معمولاً مشکل فقط خود مدل نیست. Schema ممکن است اطلاعات کافی درباره روابط جداول نداشته باشد.

🔹 نام جدول‌ها را واضح‌تر کنید.

🔹 توضیح فارسی برای جدول‌ها اضافه کنید.

🔹 Foreign Keyها را در Schema به مدل نشان دهید.

🔹 چند Query نمونه و معتبر به عنوان Example Query ذخیره کنید.

🔹 جدول‌های غیرضروری را از Context حذف کنید.

رفع خطای تولید SQL نامعتبر

گاهی مدل نام ستونی را تولید می‌کند که وجود ندارد یا از Syntax مربوط به دیتابیس دیگری استفاده می‌کند. این مشکل در پروژه‌های چنددیتابیسی بیشتر دیده می‌شود.

راه‌حل مناسب این است که Dialect دیتابیس را صریحاً در Prompt اعلام کنید:

DATABASE DIALECT: PostgreSQL

Generate SQL compatible with PostgreSQL.

Do not use MySQL-specific functions.

برای MySQL نیز مقدار Dialect را متناسب با همان دیتابیس تغییر دهید.

رفع مشکل اطلاعات اشتباه در پاسخ مدل

یک Text-to-SQL خوب باید تا جای ممکن پاسخ خود را از نتیجه واقعی Query استخراج کند. مدل نباید عددی را که در دیتابیس وجود ندارد حدس بزند.

به همین دلیل معماری بهتر این است که مدل مسئول تولید Query باشد و برنامه مسئول اجرای Query و نمایش نتیجه واقعی. اگر می‌خواهید یک توضیح فارسی درباره نتیجه نیز تولید شود، بهتر است نتیجه واقعی Query دوباره به مدل داده شود تا متن توضیحی تولید کند.

چطور Text-to-SQL را برای فارسی دقیق‌تر کنیم؟

🔹 Prompt را کاملاً فارسی و شفاف بنویسید.

🔹 نام ستون‌های مهم را همراه با توضیح تجاری ارائه کنید.

🔹 روابط جدول‌ها را به مدل نشان دهید.

🔹 نمونه سؤال فارسی و SQL صحیح ذخیره کنید.

🔹 اصطلاحات سازمان را در Metadata ثبت کنید.

🔹 برای تاریخ، واحد پول و وضعیت سفارش قوانین مشخص بنویسید.

🔹 Queryهای تولیدشده را ارزیابی و خطاهای پرتکرار را ثبت کنید.

📌 یک نکته مهم درباره زبان فارسی

«فروش این ماه»، «فروش ۳۰ روز اخیر»، «ماه گذشته» و «سه ماه قبل» ممکن است از نظر کسب‌وکار تعریف متفاوتی داشته باشند. بهتر است این قوانین در Metadata پروژه مشخص شوند تا مدل مجبور به حدس‌زدن نباشد.

ساخت سرویس دائمی با Systemd

برای محیط واقعی بهتر است FastAPI را با یک سرویس Systemd اجرا کنید تا بعد از Restart سرور، برنامه دوباره بالا بیاید.

sudo nano /etc/systemd/system/text-to-sql.service

محتوای فایل:

[Unit]
Description=Persian Text to SQL API
After=network.target

[Service]
User=root
WorkingDirectory=/opt/text-to-sql
EnvironmentFile=/opt/text-to-sql/.env
ExecStart=/opt/text-to-sql/.venv/bin/uvicorn app:app --host 127.0.0.1 --port 8000
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

⚠️ برای محیط Production بهتر است سرویس را با یک کاربر لینوکسی اختصاصی و غیر Root اجرا کنید. استفاده از Root در این مثال صرفاً برای کوتاه نگه‌داشتن آموزش است.

sudo systemctl daemon-reload
sudo systemctl enable text-to-sql
sudo systemctl start text-to-sql

sudo systemctl status text-to-sql

قرار دادن API پشت Nginx و HTTPS

برای استفاده واقعی بهتر است API مستقیماً روی اینترنت منتشر نشود. Nginx می‌تواند به عنوان Reverse Proxy جلوی FastAPI قرار بگیرد و HTTPS نیز برای ارتباط امن استفاده شود.

در این مرحله می‌توانید دامنه‌ای مانند sql.example.com را به VPS متصل کنید و درخواست‌ها را به پورت 8000 منتقل کنید.

همچنین Authentication را فراموش نکنید. یک API عمومی که اجازه می‌دهد هر فرد Query روی دیتابیس اجرا کند، حتی اگر Read Only باشد، می‌تواند از نظر مصرف منابع و افشای داده مشکل‌ساز شود.

اگر VPS برای مدل محلی کافی نبود چه کنیم؟

در صورتی که مدل انتخابی RAM زیادی مصرف کند یا زمان پاسخ CPU برای پروژه مناسب نباشد، چند راه دارید:

🔹 استفاده از مدل کوچک‌تر و Quantized

🔹 انتقال مدل به سرور GPU

🔹 جدا کردن دیتابیس و LLM روی دو سرور

🔹 استفاده از API یک سرویس مدل ابری

🔹 استفاده از چند Worker برای API در صورت نیاز

سرور مناسب برای هوش مصنوعی و دیتابیس را از ابتدا درست انتخاب کنید

Text-to-SQL زمانی جذاب می‌شود که API، مدل، دیتابیس و لایه امنیتی بدون گلوگاه منابع کنار هم قرار بگیرند. اگر مدل محلی اجرا می‌کنید، RAM و CPU مهم هستند؛ اگر مدل بزرگ‌تر یا کاربران هم‌زمان دارید، سرور GPU می‌تواند گزینه مناسب‌تری باشد.

برای پروژه‌هایی که به منابع اختصاصی، دیسک سریع و دسترسی پایدار نیاز دارند، مشخصات VPS را بر اساس مدل AI و حجم دیتابیس انتخاب کنید.

📞 تماس با پشتیبانی: 021-91302460 | ایرانیکاسرور

اگر نصب یا اتصال دیتابیس با مشکل مواجه شد چه کنیم؟

🛠 نیاز به کانفیگ یا رفع مشکل سرور دارید؟

اگر در نصب Python، Ollama، اتصال MySQL یا PostgreSQL، تنظیم Firewall، Reverse Proxy، HTTPS یا اجرای سرویس Text-to-SQL روی VPS مشکل دارید، می‌توانید از خدمات کانفیگ و رفع مشکل ایرانیکاسرور استفاده کنید.

هدف این است که به‌جای آزمون و خطای طولانی، مشکل سرویس، شبکه یا تنظیمات سرور مرحله‌به‌مرحله بررسی شود.

📞 تماس با پشتیبانی: 021-91302460 | ایرانیکاسرور

ارتباط این آموزش با سایر پروژه‌های هوش مصنوعی روی VPS

Text-to-SQL را می‌توان یک جزء از یک سیستم بزرگ‌تر Data Assistant در نظر گرفت. برای مثال یک سرویس کامل می‌تواند هم‌زمان به دیتابیس، فایل‌های CSV، Excel، PDF و APIهای داخلی دسترسی داشته باشد.

در چنین معماری، Text-to-SQL برای داده‌های ساختاریافته استفاده می‌شود، در حالی که RAG و Document Intelligence برای داده‌های متنی و اسناد کاربرد دارند. این تفکیک باعث می‌شود هر نوع داده با روش مناسب پردازش شود.

📌 مسیر توسعه پیشنهادی

🔹 مرحله اول: Text-to-SQL برای MySQL و PostgreSQL

🔹 مرحله دوم: Schema Retrieval

🔹 مرحله سوم: ثبت Queryهای موفق

🔹 مرحله چهارم: افزودن داشبورد فارسی

🔹 مرحله پنجم: اضافه‌کردن RAG برای مستندات

🔹 مرحله ششم: اتصال به سیستم‌های داخلی و APIها

پرسش‌های متداول Text-to-SQL فارسی

آیا می‌توان با زبان فارسی از MySQL سؤال پرسید؟

بله. مدل زبانی می‌تواند سؤال فارسی را دریافت کند و بر اساس Schema دیتابیس SQL تولید کند. دقت نتیجه به مدل، Prompt، ساختار Schema و توضیحات معنایی دیتابیس بستگی دارد.

آیا Text-to-SQL روی PostgreSQL هم کار می‌کند؟

بله. در این معماری SQLAlchemy امکان اتصال به PostgreSQL را فراهم می‌کند و می‌توان Dialect مربوط به PostgreSQL را در Prompt مشخص کرد.

آیا اجرای Text-to-SQL روی VPS بدون GPU ممکن است؟

بله. مدل‌های کوچک‌تر را می‌توان روی CPU اجرا کرد، اما زمان پاسخ به مدل، حجم آن، تعداد کاربران و منابع سرور بستگی دارد. برای مدل‌های بزرگ‌تر استفاده از GPU می‌تواند مناسب‌تر باشد.

آیا می‌توان مدل را کاملاً روی سرور اجرا کرد؟

بله. با استفاده از یک Runtime محلی مانند Ollama می‌توان مدل را روی همان سرور اجرا کرد. در این حالت مدیریت منابع، امنیت سرور و فضای ذخیره‌سازی اهمیت بیشتری پیدا می‌کند.

آیا می‌توان به مدل اجازه اجرای INSERT و DELETE داد؟

از نظر فنی ممکن است، اما برای Data Assistant عمومی توصیه نمی‌شود. معماری امن‌تر استفاده از کاربر Read Only و محدودکردن Queryها به SELECT است.

چرا مدل گاهی SQL اشتباه تولید می‌کند؟

مدل زبانی Schema را تفسیر می‌کند و تضمین ذاتی برای درستی Query ندارد. نام‌گذاری نامناسب، Schema بزرگ، روابط نامشخص و Prompt ضعیف می‌توانند باعث خطا شوند. اعتبارسنجی SQL و نمایش Query تولیدشده برای کاربران فنی اهمیت زیادی دارد.

برای Text-to-SQL فارسی چه منابع سروری لازم است؟

منابع ثابت و یکسانی برای همه مدل‌ها وجود ندارد. مدل انتخابی، اندازه Quantization، طول Context، حجم Schema، تعداد کاربران و اینکه مدل روی CPU یا GPU اجرا شود، همگی روی منابع موردنیاز تأثیر دارند.

جمع‌بندی؛ ساخت Data Assistant فارسی از دیتابیس

✅ Text-to-SQL فارسی فقط یک Prompt ساده نیست

یک پیاده‌سازی قابل استفاده باید چند بخش را کنار هم قرار دهد: مدل زبانی، Schema دیتابیس، Prompt دقیق، لایه اعتبارسنجی SQL، حساب Read Only، محدودیت تعداد رکورد، کنترل زمان اجرا و API امن.

با این معماری می‌توانید از MySQL یا PostgreSQL با زبان فارسی سؤال بپرسید و به‌جای ساخت دستی Queryهای متعدد، یک رابط طبیعی برای گزارش‌گیری ایجاد کنید.

اگر پروژه کوچک باشد، یک VPS مناسب و مدل سبک می‌تواند نقطه شروع خوبی باشد. برای مدل‌های بزرگ‌تر، کاربران هم‌زمان و تحلیل‌های پیچیده‌تر، باید منابع RAM، CPU، NVMe و در صورت نیاز GPU را متناسب با بار واقعی انتخاب کنید.

شروع پروژه Text-to-SQL روی VPS

اگر قصد دارید این پروژه را از حالت آزمایشی به یک سرویس واقعی تبدیل کنید، اولین قدم انتخاب منابع مناسب برای مدل AI، API و دیتابیس است. برای دیتابیس‌های سنگین نیز بهتر است از ابتدا ظرفیت دیسک و I/O را در نظر بگیرید.

📞 تماس با پشتیبانی: 021-91302460 | ایرانیکاسرور

منابع رسمی برای ادامه کار

Qwen3 در Ollama — مشاهده مدل‌ها و روش اجرای آن‌ها

SQLAlchemy Engine Documentation — تنظیم اتصال به دیتابیس‌ها

مستندات رسمی MySQL — مرجع دستورات و مدیریت MySQL

مستندات رسمی PostgreSQL — مرجع PostgreSQL

این آموزش برایت مفید بود؟ می‌توانی لینک آن را ذخیره یا برای دیگران ارسال کنی.

Amir Jabbari

نویسنده مجله ایرانیکاسرور؛ منتشرکننده آموزش‌ها و راهنماهای کاربردی در حوزه هاست، سرور، وردپرس و شبکه.

برای اجرای آموزش به زیرساخت نیاز داری؟

سرویس مرتبط را ببین؛ معرفی خدمات در این بخش کوتاه نگه داشته شده تا تمرکز اصلی صفحه روی آموزش باقی بماند.

ایرانیکاسرور
گفت‌وگو درباره آموزش

دیدگاه‌ها

0 دیدگاه برای این مطلب ثبت شده است.

هنوز دیدگاهی ثبت نشده است؛ اگر سؤال یا تجربه‌ای درباره این آموزش داری، همین‌جا بنویس. پاسخ‌های مدیریت و کاربران به‌صورت مشخص از هم تفکیک می‌شوند.

دیدگاه یا سؤال خود را بنویسید

ایمیل شما منتشر نمی‌شود. فیلدهای ضروری مشخص شده‌اند.