مبانی و معماری

اتصال RAG به SQL؛ شمارش سفارش‌ها با شاهد قابل بررسی

یک سؤال، دو پشتوانه: محاسبهٔ سفارش‌های معوق از پایگاه داده و توضیح رویه از سند. قرارداد ابزار و خطاهای تعیین‌کننده را با یک مثال دنبال کنیم.

چرتکه‌ای با قاب مسی و مهره‌های سبز جنگلی که با پلی مسی به برگهٔ راهنمای تاشدهٔ عاجی روی میز متصل است

آنچه از این مقاله می‌آموزید

  • شاخص عددی را با تعریف تجاری و پرس‌وجوی بازبینی‌شده محاسبه کنید.
  • شاهد محاسبه و ارجاع سند دو پشتوانهٔ جدا برای یک پاسخ ترکیبی‌اند.
  • تکرار اتصال جدول‌ها، مبلغ نامعلوم، مرز زمان و دامنهٔ شعبه را پیش از تحویل بیازمایید.

مدیر عملیات یک شرکت پخش می‌پرسد: «در شعبهٔ تهران چند سفارش باز از موعد تحویل گذشته‌اند و طبق دستورالعمل، پیگیری آن‌ها از کجا شروع می‌شود؟» نیمهٔ اول سؤال به وضعیت سفارش‌ها در سامانهٔ عملیاتی وابسته است؛ نیمهٔ دوم به متن رویهٔ شرکت. اگر دستیار فقط چند گزارش مشابه را پیدا کند، ممکن است توضیح مناسبی بدهد، اما تعداد را از روی نمونه‌ای ناقص حدس بزند.

این مقاله برای تیم فنی یک شرکت متوسط است که می‌خواهد دستیار دانشی خود را به داده‌های ساختاریافته متصل کند. مسیر پیشنهادی، ترکیب یک پرس‌وجوی محدود و تعریف‌شده با بازیابی سند است: پایگاه داده محاسبه می‌کند و RAG، دستورالعمل مرتبط را با شاهد توضیح می‌دهد. قرارداد ابزار، داده‌ها و پاسخ نمونهٔ زیر کاملاً توضیحی‌اند؛ هیچ‌کدام نتیجهٔ اجرای یک مشتری نیستند.

ابتدا معلوم کنید «سفارش باز» یعنی چه

پیش از اتصال ابزار، یک تعریف تجاری بنویسید. آیا سفارش تأییدشده‌ای که بخشی از آن ارسال شده هنوز باز است؟ سفارش لغوشده چه وضعی دارد؟ «گذشته از موعد» بر اساس تاریخ تعهد اولیه محاسبه می‌شود یا تاریخ اصلاح‌شده؟ بدون پاسخ این پرسش‌ها، دو پرس‌وجوی کاملاً معتبر می‌توانند دو عدد متفاوت تولید کنند.

برای مثال این مقاله، سفارش باز یعنی سفارش تأییدشده با مقدار تحویل‌نشدهٔ مثبت؛ سفارش لغوشده کنار می‌رود. موعد، تاریخ تعهد معتبر ثبت‌شده است و «معوق» یعنی این موعد از زمان مرجع گذشته باشد. این تعریف باید مالک مشخص و نسخه داشته باشد تا تغییر معنای شاخص، پشت یک پاسخ ظاهراً مشابه پنهان نماند.

پژوهش BIRD با شناسهٔ arXiv:2305.03111، علاوه بر ساختار جدول، فهم مقدارهای پایگاه، دانش دامنه و کارایی پرس‌وجو را بررسی می‌کند. بخش شرح داده و شواهد بیرونی آن نشان می‌دهد نگاشت زبان کاربر به معنای مقدارها، مسئله‌ای مستقل است. این پژوهش نخست در ۴ مهٔ ۲۰۲۳ منتشر شده؛ از آن برای توضیح مسئله استفاده می‌کنیم، نه ادعای وضعیت امروز مدل‌ها یا تضمین دقت محصول. ۱

سؤال را به دو خروجی قابل بررسی تبدیل کنید

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

بهتر است تصمیم مسیریابی نیز محدود باشد. پرسش «مراحل پیگیری چیست؟» فقط مسیر سند می‌خواهد؛ «چند سفارش داریم؟» مسیر محاسبه را فعال می‌کند؛ پرسش ترکیبی هر دو را می‌خواهد. اگر شعبه یا بازه روشن نیست، همان مورد را از کاربر بپرسید. انتخاب خودکار همهٔ شعب به‌جای رفع ابهام، معنای سؤال را عوض می‌کند.

در این طراحی، تعداد قطعه‌های بازیابی‌شده هیچ نقشی در شمارش سفارش‌ها ندارد. حتی اگر ده گزارش دربارهٔ سفارش‌های معوق پیدا شود، این ده گزارش فهرست کامل سفارش‌ها نیستند. شاهد عدد، نتیجهٔ محاسبه بر مجموعهٔ تعریف‌شده است؛ شاهد رویه، بند سندی است که کاربر می‌تواند باز کند.

قرارداد ابزار را کوچک و صریح نگه دارید

برای شروع، ابزار مستقلی با نامی مانند overdue_orders_summary تعریف کنید. ورودی آن فقط شعبهٔ مجاز، بازهٔ موعد و شناسهٔ تعریف شاخص است. زمان مرجع را سرویس تعیین و ثبت می‌کند. شناسهٔ سازمان و محدودهٔ دسترسی نیز از نشست احرازشده می‌آیند، نه از متن پیشنهادی مدل.

جدول زیر قرارداد پیشنهادی همین ابزار را نشان می‌دهد؛ این نام‌ها ویژگی آمادهٔ یک محصول خاص نیستند.

جزء قرارداد تصمیم لازم برای مثال شرکت پخش
واحد شمارش هر سفارش یک‌بار، مستقل از تعداد اقلام یا ارسال‌ها
وضعیت‌های پذیرفته تأییدشده و دارای ماندهٔ تحویل؛ حذف لغوشده‌ها
بازهٔ موعد شروع شامل، پایان خارج از بازه، با منطقهٔ زمانی تهران
مبلغ ارزش تحویل‌نشده به ریال، با قاعدهٔ مشخص محاسبه
دامنهٔ دسترسی شعبه‌های مجاز کاربر، با کنترل در سرویس و لایهٔ داده
وضعیت خروجی موفق، نیازمند توضیح، دادهٔ ناکافی یا خطای اجرا

قالب پرس‌وجو را توسعه‌دهنده بازبینی می‌کند و مقدارها جداگانه به آن داده می‌شوند. مرجع PREPARE در PostgreSQL، پارامترهای مقداری با نوع مشخص را توضیح می‌دهد. ۲ در پیشنهاد این مقاله، نام جدول، ستون، ترتیب اتصال و فرمول شاخص جزو قالب ثابت‌اند؛ انتخاب آن‌ها را به متن آزاد مدل نمی‌سپاریم. این محدودیت برای پوشش چند نیاز تکراری شرکت، هزینهٔ بررسی را قابل مدیریت می‌کند.

مثال عددی: پنج سفارش، دو مورد مشمول

فرض کنیم زمان مرجع، ساعت ۹ صبح ۲۹ اکتبر ۲۰۲۶ تهران است و کاربر سفارش‌هایی با موعد از ۲۲ اکتبر تا پایان ۲۸ اکتبر را می‌خواهد. جدول زیر تمام دادهٔ ساختگی این تمرین است. «مانده» ارزش بخش تحویل‌نشده است؛ مبالغ، واحد یکسان دارند و هیچ مبلغی از سند متنی استخراج نشده است.

سفارش شعبه وضعیت در زمان مرجع موعد در اکتبر ۲۰۲۶ مانده، میلیون ریال
۲۰۱ تهران تأییدشده، بدون تحویل ۲۷ ۳۰
۲۰۲ تهران تأییدشده، تحویل جزئی ۲۸ ۲۰
۲۰۳ تهران تحویل کامل ۲۵ ۰
۲۰۴ تهران لغوشده ۲۶ ۱۵
۲۰۵ شیراز تأییدشده، بدون تحویل ۲۷ ۴۰

با تعریف انتخاب‌شده، فقط سفارش‌های ۲۰۱ و ۲۰۲ مشمول‌اند: تعداد ۲ و ماندهٔ مجموع ۵۰ میلیون ریال. سفارش ۲۰۴ با وجود داشتن مانده کنار می‌رود و سفارش ۲۰۵ خارج از دامنهٔ شعبه است. همین توضیح کوتاه، امکان بررسی معنای خروجی را فراهم می‌کند؛ عدد تنها این کار را نمی‌کند.

اکنون فرض کنید سفارش ۲۰۱ دو رکورد ارسال دارد. اتصال مستقیم جدول سفارش به ارسال می‌تواند آن سفارش را در ورودی محاسبه تکرار کند. ابتدا داده را در سطح هر سفارش به یک رکورد برسانید و سپس جمع بزنید. شمارش شناسهٔ یکتا به‌تنهایی، جمع مبلغ تکرارشده را اصلاح نمی‌کند؛ هر دو شاخص باید در سطح درست محاسبه شوند.

در PostgreSQL، count(*) تعداد ردیف‌های ورودی را می‌شمارد، ولی count(column) فقط مقدارهای غیرتهی را می‌شمارد. همچنین sum روی ورودی بدون ردیف، مقدار NULL می‌دهد. ۳ بنابراین ابزار باید میان نبود سفارش مشمول، مبلغ نامعلوم و شکست دریافت داده تفاوت بگذارد. تبدیل همهٔ این وضعیت‌ها به صفر، گزارش مدیریتی گمراه‌کننده می‌سازد.

نتیجهٔ عددی را با بند رویه پیوند دهید

در ادامهٔ همین تمرین، فرض کنیم یک رویهٔ ساختگی می‌گوید: «سفارش معوق ابتدا توسط هماهنگ‌کنندهٔ شعبه بررسی شود؛ نبود موجودی به برنامه‌ریزی تأمین ارجاع شود.» بازیابی باید نسخهٔ معتبر همین رویه و بند مربوط را برگرداند. خروجی مناسب می‌تواند عدد و زمان مرجع را در یک بخش و مراحل پیگیری را همراه شناسهٔ سند در بخش بعد نشان دهد.

اما از وجود دو سفارش معوق نمی‌توان نتیجه گرفت که علت هر دو، نبود موجودی است. بند رویه مسیر رسیدگی را تعیین می‌کند؛ علت تأخیر هر سفارش به دادهٔ جداگانه نیاز دارد. اگر دلیل در ابزار فعلی نیست، پاسخ باید همین کمبود را بیان کند. این تمایز از تبدیل یک دستورالعمل شرطی به توضیح قطعیِ علت جلوگیری می‌کند.

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

دسترسی را پیش از محاسبه محدود کنید

اگر مدیر شعبه فقط تهران را می‌بیند، ابزار باید روی همان دامنه محاسبه کند. محاسبهٔ کل شرکت و پنهان‌کردن فهرست سفارش‌ها کافی نیست؛ عدد مجموع هم اطلاعات دارد. مسیر مشاهدهٔ جزئیات نیز باید همان محدودیت را رعایت کند تا کلیک روی نتیجه، دامنهٔ تازه‌ای باز نکند.

در PostgreSQL، سیاست سطح ردیف می‌تواند ردیف‌های قابل مشاهده را محدود کند؛ اما مالک جدول معمولاً و نقش‌های دارای BYPASSRLS از آن عبور می‌کنند. ۴ نقش اجرای ابزار را با همین ملاحظات بازبینی کنید. اگر از نما یا تابع واسط استفاده می‌کنید، صرف وجود سیاست روی جدول را گواه رفتار نهایی ابزار ندانید؛ آزمون باید با نقش واقعی اجرا انجام شود.

برای این دامنه، اتصال خواندنی با مجوز محدود و قالب‌های تأییدشده پیشنهاد می‌شود. حالت READ ONLY در PostgreSQL بسیاری از فرمان‌های تغییر دادهٔ غیرموقت را منع می‌کند، اما محدودیت کامل همهٔ اثرهای جانبی نیست. ۵ کنترل مجوز و سطح ابزار باید مستقل باقی بماند؛ برچسب خواندنی جای بازبینی مسیر اجرا را نمی‌گیرد.

«الان» و «در آن تاریخ» دو قرارداد متفاوت‌اند

دو پرس‌وجوی جدا برای تعداد و مبلغ ممکن است میان دو تغییر سفارش اجرا شوند. برای خروجی مشترک، هر دو شاخص را در یک دستور محاسبه کنید یا در صورت نیاز، خواندن‌ها را در نمای تراکنشی سازگار انجام دهید. مستندات PostgreSQL تفاوت دید هر دستور در READ COMMITTED و دید پایدارتر تراکنش در REPEATABLE READ را بیان می‌کند. ۵

ثبت ساعت اجرا به‌تنهایی امکان پاسخ‌گویی تاریخی نمی‌سازد. اگر کاربر فردا بپرسد «دیروز ساعت ۹ چند سفارش باز بود؟»، جدولِ فقط وضعیت فعلی شاید آن پاسخ را نداشته باشد. چنین نیازی به تاریخچهٔ تغییرات یا تصویری نگهداری‌شده از داده احتیاج دارد. ابزار فعلی را صریحاً برای وضعیت قابل مشاهده هنگام اجرا تعریف کنید و درخواست تاریخیِ پشتیبانی‌نشده را نپذیرید.

اگر ابزار به نسخهٔ گزارش‌گیری متصل است، زمان آخرین به‌روزرسانی آن را نیز نمایش دهید. ساعت تولید پاسخ و تازگی داده دو چیز متفاوت‌اند. نتیجه‌ای که همین لحظه محاسبه شده، ممکن است بر دادهٔ قدیمی‌تر تکیه داشته باشد؛ تصمیم دربارهٔ پذیرش این فاصله با مالک فرایند است.

پیش از تحویل، خطاهای تعیین‌کننده را تمرین کنید

برای پایلوت، همین پنج سفارش را به مجموعه‌ای کوچک با خروجی مرجع تبدیل کنید و هر بار فقط یک ویژگی را تغییر دهید. هدف، اثبات رفتار قرارداد است؛ دقت روی یک جدول ساده، پوشش همهٔ پرسش‌های شرکت را ثابت نمی‌کند.

  1. برای یک سفارش، چند قلم و چند ارسال بسازید؛ تعداد و مبلغ نباید به‌علت اتصال جدول‌ها افزایش یابند.
  2. وضعیت را لغوشده کنید و موعدی دقیقاً روی مرز پایان بگذارید؛ نتیجه باید با تعریف شاخص و بازه سازگار بماند.
  3. با حساب شعبهٔ دیگر همان درخواست را اجرا کنید؛ هم مجموع و هم جزئیات باید به دامنهٔ مجاز محدود باشند.
  4. ورودی بدون سفارش، مبلغ نامعلوم و خطای اتصال را جدا بسازید؛ پیام هرکدام باید وضعیت واقعی را بیان کند.
  5. رویهٔ مرتبط را از مجموعه بردارید؛ عدد می‌تواند باقی بماند، اما دستورالعمل نباید ساخته شود.

سقف زمان اجرا و تعداد فراخوانی را نیز در سرویس قرار دهید. مستندات statement_timeout، قطع دستور طولانی را توضیح می‌دهد. ۶ اگر محاسبه قطع شد، وضعیت خطا برگردانید؛ مدل نباید خروجی ناقص یا عدد اجرای قبلی را نتیجهٔ تازه معرفی کند. رفتار در خطا، بخشی از معیار تحویل ابزار است.

دامنهٔ آغاز را با یک تصمیم تجاری ببندید

برای این شرکت، نقطهٔ شروع می‌تواند فقط «خلاصهٔ سفارش‌های معوق هر شعبه و رویهٔ پیگیری» باشد. خروجی تحویل شامل تعریف مصوب شاخص، قالب بازبینی‌شده، رسید محاسبه، ارجاع بند و نتیجهٔ آزمون‌های بالا است. اگر نیاز فقط دیدن یک عدد ثابت در گزارش روزانه باشد، داشبورد موجود شاید مسیر ساده‌تری باشد؛ ارزش دستیار در پاسخ به پرسش ترکیبی و توضیح قابل پیگیری سنجیده می‌شود.

این طراحی، تحلیل آزاد همهٔ جدول‌ها یا تشخیص خودکار علت تأخیر را پوشش نمی‌دهد. گسترش به شاخص بعدی زمانی توجیه دارد که تعریف تجاری، منبع محاسبه و شاهد توضیح آن نیز روشن شده باشد. به این ترتیب، هر قابلیت تازه با یک قرارداد قابل بررسی وارد دستیار می‌شود و کاربر می‌داند عدد از کجا آمده و متن، کدام تصمیم را پشتیبانی می‌کند.

منابع و مطالعهٔ بیشتر

  1. Can LLM Already Serve as A Database Interface? A BIg Bench for Large-Scale Database Grounded Text-to-SQLs
  2. PREPARE — PostgreSQL 18
  3. 9.21. Aggregate Functions — PostgreSQL 18
  4. 5.9. Row Security Policies — PostgreSQL 18
  5. SET TRANSACTION — PostgreSQL 18
  6. 19.11. Client Connection Defaults — PostgreSQL 18

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

گفت‌وگو دربارهٔ این موضوع در تلگرام@polyaim

ادامهٔ مسیر یادگیری

همهٔ مقاله‌ها

از مسئلهٔ خودتان شروع کنیم

چند سؤال واقعی، بهتر از یک فهرست بلندِ قابلیت‌هاست.

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

پیام در تلگرام