پرامپت‌نویسی برای RAG — از بازیابی تا تولید

قسمت ۷ ۱۸ دقیقه

یه مرور سریع

تو اپیزود قبلی یاد گرفتیم چطور بهترین تکه‌های مرتبط رو با جستجوی برداری، فیلتر Metadata و جستجوی ترکیبی پیدا کنیم. حالا این تکه‌ها رو داریم، ولی یه سؤال مهم مونده: چطور اینا رو به LLM بدیم که بهترین جواب رو تولید کنه؟

اینجاست که پرامپت‌نویسی برای RAG وارد بازی می‌شه. پرامپت خوب فرق بین یه RAG که جواب‌های دقیق و مفید می‌ده و یه RAG که هذیان می‌گه رو مشخص می‌کنه.

ساختار System Prompt برای RAG

System Prompt همون دستورالعملیه که به LLM می‌گی «تو کی هستی و چطور باید جواب بدی». تو RAG، این Prompt باید چند چیز مهم رو مشخص کنه:

system_prompt = """
تو یک دستیار متخصص هستی که فقط بر اساس اطلاعات ارائه‌شده پاسخ می‌دهی.

قوانین:
1. فقط از اطلاعات بخش «زمینه» استفاده کن
2. اگر اطلاعات کافی نیست، صادقانه بگو «اطلاعات کافی برای پاسخ ندارم»
3. هر ادعا را با شماره منبع مشخص کن [1]، [2]، ...
4. از اطلاعات عمومی یا حدس استفاده نکن
5. پاسخ را ساده و قابل فهم بنویس
"""

بذار هر بخش رو باز کنیم.

نقش (Role)

اولین خط مشخص می‌کنه LLM چه نقشی داره. «دستیار متخصص» بهتر از «هوش مصنوعی» هست چون LLM رو تو یه چارچوب مشخص قرار می‌ده. می‌تونی نقش رو خاص‌تر هم کنی: «دستیار متخصص در پشتیبانی فنی محصولات الکترونیکی».

محدودیت‌ها (Constraints)

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

رفتار در نبود اطلاعات

قانون ۲ خیلی مهمه. LLM ذاتاً دوست داره جواب بده — حتی وقتی نمی‌دونه! باید صریحاً بگی «اگه نمی‌دونی، بگو نمی‌دونم». بعداً بیشتر درباره این حرف می‌زنیم.

الگوهای تزریق Context

حالا باید تکه‌های بازیابی‌شده رو تو پرامپت بذاری. چند تا الگوی رایج وجود داره:

الگوی ساده — همه تکه‌ها پشت سر هم

prompt = f"""
زمینه:
{chunk_1}
{chunk_2}
{chunk_3}

سؤال: {user_question}

پاسخ:
"""

ساده‌ست ولی مشکل داره: LLM نمی‌فهمه هر تکه از کجا اومده و مرز بین تکه‌ها کجاست.

الگوی شماره‌دار — با منبع مشخص

prompt = f"""
زمینه:
[منبع 1]: {chunk_1}
[منبع 2]: {chunk_2}
[منبع 3]: {chunk_3}

سؤال: {user_question}

بر اساس منابع بالا پاسخ بده و شماره منبع هر ادعا را مشخص کن.
"""

این خیلی بهتره. LLM می‌تونه تو جوابش بنویسه «طبق [منبع ۱]، …» و کاربر بتونه منبع رو چک کنه.

الگوی ساختاریافته — با Metadata

prompt = f"""
زمینه:
---
منبع: {source_1_title}
تاریخ: {source_1_date}
محتوا: {chunk_1}
---
منبع: {source_2_title}
تاریخ: {source_2_date}
محتوا: {chunk_2}
---

سؤال: {user_question}
"""

این الگو اطلاعات بیشتری به LLM می‌ده. مثلاً اگه دو تا منبع متناقض باشن، LLM می‌تونه بر اساس تاریخ، منبع جدیدتر رو ترجیح بده.

ارجاع به منابع — اعتماد کاربر

یکی از بزرگ‌ترین مزایای RAG نسبت به یه ChatBot ساده اینه که می‌تونی منبع جواب رو نشون بدی. ولی این خودش نیاز به طراحی درست داره.

روش ۱ — Inline Citation

مثل مقالات علمی. تو متن جواب، شماره منبع رو بذار:

«برای حل این مشکل، ابتدا دستگاه را ریستارت کنید [1]. 
اگر مشکل ادامه داشت، تنظیمات شبکه را بررسی کنید [2].»

منابع:
[1] راهنمای عیب‌یابی، صفحه ۱۲
[2] مستندات تنظیمات شبکه، بخش ۳

روش ۲ — Section-level Citation

هر پاراگراف جواب یه منبع داره:

درباره نصب: (منبع: راهنمای نصب v2.1)
مراحل نصب شامل...

درباره پیکربندی: (منبع: مستندات فنی v3.0)
تنظیمات اولیه شامل...

نکته مهم

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

هنر گفتن «نمی‌دونم»

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

چرا اینقدر مهمه؟

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

تکنیک‌های «نمی‌دونم» گفتن

۱. آستانه شباهت: اگه بهترین نتیجه جستجو هم امتیاز پایینی داره، قبل از اینکه به LLM بفرستی، خودت بگو «اطلاعاتی در این مورد نداریم».

۲. دستور صریح در Prompt:

اگر اطلاعات ارائه‌شده در بخش «زمینه» برای پاسخ‌دادن کافی نیست، 
دقیقاً بنویس: «متأسفانه اطلاعات کافی برای پاسخ به این سؤال در اختیار ندارم.»
هرگز از دانش عمومی خودت استفاده نکن.

۳. پاسخ جزئی: گاهی بخشی از جواب تو داده‌هاته. به LLM بگو می‌تونه بخش معلوم رو جواب بده و برای بخش نامعلوم صادق باشه:

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

Few-shot Examples — یاد دادن با مثال

یکی از قوی‌ترین تکنیک‌ها اینه که به LLM چند مثال بدی از جواب‌هایی که انتظار داری:

system_prompt = """
مثال ۱:
زمینه: [محصول X از سال 1402 عرضه شده و دارای گارانتی ۲ ساله است.]
سؤال: گارانتی محصول X چقدره؟
پاسخ: طبق اطلاعات موجود [1]، محصول X دارای گارانتی ۲ ساله است.

مثال ۲:
زمینه: [محصول Y دارای صفحه نمایش ۶.۵ اینچی است.]
سؤال: قیمت محصول Y چقدره؟
پاسخ: متأسفانه اطلاعات قیمت محصول Y در منابع موجود یافت نشد.

حالا با همین سبک پاسخ بده:
"""

Few-shot Examples سه تا کار مهم انجام می‌دن:

  • سبک و لحن جواب رو مشخص می‌کنن
  • نشون می‌دن چطور Citation بذاره
  • نشون می‌دن چطور «نمی‌دونم» بگه

Prompt Template — قالب آماده

تو عمل، معمولاً یه قالب (Template) درست می‌کنی و هر بار متغیرها رو جایگزین می‌کنی:

from string import Template

RAG_TEMPLATE = Template("""
تو یک دستیار متخصص $domain هستی.

زمینه:
$context

سؤال کاربر: $question

دستورالعمل:
- فقط از اطلاعات بخش «زمینه» استفاده کن
- هر ادعا را با شماره منبع مشخص کن
- اگر اطلاعات کافی نیست، صادقانه بگو
- پاسخ را به فارسی و ساده بنویس

پاسخ:
""")

# استفاده
prompt = RAG_TEMPLATE.substitute(
    domain="پشتیبانی فنی",
    context=formatted_chunks,
    question=user_query
)

نکته: از کتابخونه‌هایی مثل LangChain یا LlamaIndex هم می‌تونی استفاده کنی که Prompt Template های آماده و قابل تنظیم دارن.

اشتباهات رایج در پرامپت‌نویسی RAG

۱. Context خیلی زیاد

اگه ۲۰ تکه متن رو بریزی تو پرامپت، LLM گیج می‌شه و ممکنه اطلاعات مهم رو از دست بده. این رو بهش می‌گن Lost in the Middle — LLM معمولاً اول و آخر Context رو بهتر می‌فهمه.

راه‌حل: تکه‌های مهم‌تر رو اول بذار. تعداد تکه‌ها رو محدود کن (معمولاً ۳ تا ۷ تکه کافیه).

۲. Context خیلی کم

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

۳. دستورالعمل مبهم

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

۴. نادیده گرفتن زبان

اگه داده‌هات فارسیه ولی Prompt انگلیسیه، LLM ممکنه جواب انگلیسی بده. صریحاً زبان جواب رو مشخص کن.

یه Prompt کامل و آماده

بذار یه Prompt کامل نشونت بدم که همه اصول رو رعایت کرده:

"""
تو یک دستیار هوشمند هستی که به سؤالات کاربران بر اساس مستندات پاسخ می‌دهی.

## قوانین الزامی
1. فقط و فقط از اطلاعات بخش «زمینه» پاسخ بده
2. هر ادعا را با شماره منبع مرتبط مشخص کن: [1]، [2]، ...
3. اگر اطلاعات کافی نیست: «اطلاعات کافی برای پاسخ در مستندات موجود نیست»
4. اگر فقط بخشی قابل پاسخ است، همان بخش را جواب بده
5. پاسخ را به فارسی، ساده و خلاصه بنویس
6. از حدس، تخمین، یا دانش عمومی استفاده نکن

## زمینه
[1] عنوان: {title_1}
محتوا: {content_1}

[2] عنوان: {title_2}
محتوا: {content_2}

[3] عنوان: {title_3}
محتوا: {content_3}

## سؤال
{user_question}

## پاسخ
"""

جمع‌بندی

تو این اپیزود یاد گرفتی که:

  • System Prompt خوب برای RAG چه ویژگی‌هایی داره
  • چند الگوی مختلف برای تزریق Context وجود داره
  • چطور به LLM یاد بدی Citation بذاره
  • چطور «نمی‌دونم» گفتن رو تقویت کنی
  • Few-shot Examples چقدر مؤثرن
  • اشتباهات رایج چیا هستن و چطور ازشون دوری کنی

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

نظرات

هنوز نظری ثبت نشده. اولین نفر باشید!

نظر خود را بنویسید