در دنیای مدلهای زبانی بزرگ، یکی از چالشهای اصلی، حفظ دقت و بهروز بودن پاسخهاست. مدلهای ازپیشآموزشدیده اگرچه قدرتمندند اما دانش آنها محدود به دادههایی است که پیشتر آموزش دیدهاند. این یعنی نمیتوانند بهتنهایی به اطلاعات جدید یا دادههای خاص هر سازمان دسترسی پیدا کنند. در چنین شرایطی، رویکردی به نام پیادهسازی RAG بهعنوان راهحل هوشمندانهای مطرح شده است.
RAG ترکیبی از دو دنیای متفاوت است: بازیابی اطلاعات (Retrieval) و تولید متن (Generation). نتیجه، خروجیهایی دقیقتر، مرتبطتر و قابل اعتمادتر است. در این مقاله از بلاگ آسا، بهصورت گامبهگام با نحوهی پیادهسازی RAG آشنا میشوید؛ از درک اجزای اصلی آن گرفته تا ایجاد یک نمونه عملی با ابزارهای متنباز. همچنین به چالشها، محدودیتها و مسیرهای بهبود سیستمهای RAG نیز خواهیم پرداخت تا دیدی کامل از ساختار و کاربرد آن پیدا کنید.
تعریف RAG
برای پیادهسازی RAG، درک چند مولفه کلیدی ضروری است: Embedding، پایگاه برداری، بازیابی دادهها و ترکیب با مدل زبانی. هرکدام نقشی حیاتی در دقت و عملکرد سیستم دارند.
- Embedding (تعبیهسازی)
در امبدینگ، متون به بردارهای عددی تبدیل میشوند تا معنا و مفهوم آنها قابل مقایسه شود.
جملات مشابه در فضای برداری به هم نزدیکاند و این ویژگی پایهای برای درک معنایی است.
ابزارهایی مانند OpenAI Embeddings یا Sentence Transformers برای این کار استفاده میشوند.
- پایگاه برداری (Vector Database)
بردارها در پایگاه دادهای مخصوص ذخیره میشوند که امکان جستوجوی معنایی را فراهم میکند.
پایگاههایی مثل Pinecone، Weaviate و FAISS متداولترین گزینهها هستند.
- بازیابی (Retrieval)
در پاسخ به پرسش کاربر، سیستم نزدیکترین بردارها را از نظر معنا پیدا میکند (مثلا با Cosine Similarity).
این مرحله تعیین میکند چه دانشی برای تولید پاسخ به مدل تزریق شود.
- ترکیب با مدل زبانی
در نهایت، دادههای بازیابیشده به مدل زبانی مانند GPT یا Llama داده میشود تا پاسخ نهایی تولید شود.
این ترکیب باعث میشود خروجی RAG هم دقیقتر باشد، هم بهروزتر از مدلهای صرفا زبانی.
پیادهسازی RAG از صفر تا اجرا

بیایید یک سیستم سادهی RAG بسازیم که اطلاعات را از یک دیتاست از پیش تعیینشده بازیابی کرده و بر اساس دانشی که از آن بهدست میآورد، پاسخ تولید کند.
گام اول: مرحلهی ایندکسسازی (Indexing Phase)
اولین گام در ساخت سیستم RAG، ایندکسسازی دادهها است.
در این مرحله، دیتاست (یا مجموعه اسناد) به بخشهای کوچکتر (chunk) تقسیم میشود و برای هر بخش، یک بردار عددی محاسبه میکنیم که بعدا بتوان بهصورت کارآمد در زمان تولید پاسخ از آن جستوجو کرد.
اندازهی هر بخش به نوع داده و کاربرد بستگی دارد:
- در سیستم بازیابی اسناد، هر بخش میتواند یک پاراگراف یا جمله باشد.
- در سیستم مکالمهای، هر بخش میتواند یک نوبت گفتگو (dialogue turn) باشد.
پس از ایندکسسازی، هر بخش به همراه بردار امبدینگ آن در پایگاه داده برداری ذخیره میشود. نمونهای ساده از ساختار پایگاه داده پس از ایندکسسازی بهصورت زیر است:
| Chunk | Embedding Vector |
| ایتالیا و فرانسه بیش از ۴۰٪ کل شراب جهان را تولید میکنند. | [0.1, 0.04, -0.34, 0.21, …] |
| تاج محل در هند کاملاً از سنگ مرمر ساخته شده است. | [-0.12, 0.03, 0.9, -0.1, …] |
| ۹۰٪ از آب شیرین جهان در قطب جنوب قرار دارد. | [-0.02, 0.6, -0.54, 0.03, …] |
این بردارها برای بازیابی اطلاعات مرتبط با هر پرسوجو (query) استفاده میشوند.
میتوان آن را شبیه به دستور WHERE در SQL در نظر گرفت، با این تفاوت که بهجای جستوجوی دقیق متنی، جستوجو بر اساس شباهت معنایی بین بردارها انجام میشود.
برای اندازهگیری میزان شباهت میان دو بردار، میتوان از cosine similarity، فاصلهی اقلیدسی (Euclidean distance) یا معیارهای مشابه استفاده کرد.
در این مثال، از cosine similarity استفاده میکنیم.
فرمول cosine similarity بین دو بردار A و B به صورت زیر است:
\( ;similarity\left(A,B\right)=\frac{A.B}{\left\|A\right\|\times\left\|B\right\|}\)
اگر با فرمول بالا آشنا نیستید نگران نباشید — در بخش بعدی پیادهسازی آن را خواهیم دید.
گام دوم: مرحلهی بازیابی (Retrieval Phase)
در این مرحله، زمانی که کاربر یک پرسش (Query) میفرستد، ابتدا آن را به بردار تبدیل میکنیم و سپس با بردارهای موجود در پایگاه داده مقایسه میکنیم تا نزدیکترین بخشها (chunks) را بیابیم.
پایگاه داده در پاسخ، چند بخش برتر (top N) را که بیشترین شباهت را با پرسش دارند بازمیگرداند. این بخشها در مرحلهی بعد به چتبات داده میشوند تا پاسخ نهایی تولید شود.
گام سوم: کدنویسی RAG
در این مثال، یک پیادهسازی ساده از RAG را با Python انجام میدهیم.
برای اجرای مدلها از ابزار خط فرمان Ollama استفاده میکنیم.
این ابزار به شما اجازه میدهد مدلهای Hugging Face را مستقیما روی کامپیوترتان اجرا کنید، بدون نیاز به سرور یا فضای ابری.
مدلها
- مدل امبدینگ: hf.co/CompendiumLabs/bge-base-en-v1.5-gguf
- مدل زبانی: hf.co/bartowski/Llama-3.2-1B-Instruct-GGUF
دیتاست
در این مثال از مجموعهای از facts مربوط به گربهها استفاده میشود. هر جمله در این دیتاست، یک بخش (chunk) در مرحلهی ایندکس است.
گام چهارم: نصب و آمادهسازی
ابتدا Ollama را از سایت رسمی نصب کنید:
سپس در ترمینال دستور زیر را برای دانلود مدلها اجرا کنید:
|
1 2 |
ollama pull hf.co/CompendiumLabs/bge–base–en–v1.5–gguf ollama pull hf.co/bartowski/Llama–3.2–1B–Instruct–GGUF |
در صورتی که پیام success مشاهده کردید، مدلها با موفقیت دانلود شدهاند.
حالا برای استفاده از Ollama در پایتون، پکیج مربوطه را نصب کنید:
|
1 |
pip install ollama |
گام پنجم: بارگذاری دیتاست
|
1 2 3 4 |
dataset = [] with open(‘cat-facts.txt’, ‘r’) as file: dataset = file.readlines() print(f‘Loaded {len(dataset)} entries |
گام ششم: پیادهسازی پایگاه دادهی برداری
در این بخش، با استفاده از مدل امبدینگ، هر بخش را به بردار عددی تبدیل کرده و درون یک لیست ذخیره میکنیم.
|
1 2 3 4 5 6 7 8 9 10 |
import ollama EMBEDDING_MODEL = ‘hf.co/CompendiumLabs/bge-base-en-v1.5-gguf’ LANGUAGE_MODEL = ‘hf.co/bartowski/Llama-3.2-1B-Instruct-GGUF’ VECTOR_DB = [] def add_chunk_to_database(chunk): embedding = ollama.embed(model=EMBEDDING_MODEL, input=chunk)[’embeddings’][0] VECTOR_DB.append((chunk, embedding)) |
سپس دادهها را ایندکس میکنیم:
|
1 2 3 |
for i, chunk in enumerate(dataset): add_chunk_to_database(chunk) print(f‘Added chunk {i+1}/{len(dataset)} to the database’) |
گام هفتم: تابع بازیابی (Retrieval Function)
ابتدا تابع محاسبهی cosine similarity را مینویسیم:
|
1 2 3 4 5 |
def cosine_similarity(a, b): dot_product = sum([x * y for x, y in zip(a, b)]) norm_a = sum([x ** 2 for x in a]) ** 0.5 norm_b = sum([x ** 2 for x in b]) ** 0.5 return dot_product / (norm_a * norm_b) |
سپس تابع بازیابی:
|
1 2 3 4 5 6 7 8 |
def retrieve(query, top_n=3): query_embedding = ollama.embed(model=EMBEDDING_MODEL, input=query)[’embeddings’][0] similarities = [] for chunk, embedding in VECTOR_DB: similarity = cosine_similarity(query_embedding, embedding) similarities.append((chunk, similarity)) similarities.sort(key=lambda x: x[1], reverse=True) return similarities[:top_n] |
گام هشتم: مرحلهی تولید پاسخ (Generation Phase)
در این مرحله، چتبات با استفاده از بخشهای بازیابیشده پاسخ تولید میکند.
پرامپت به شکل زیر ساخته میشود:
|
1 2 3 4 5 6 7 |
input_query = input(‘Ask me a question: ‘) retrieved_knowledge = retrieve(input_query) instruction_prompt = f”‘You are a helpful chatbot. Use only the following pieces of context to answer the question. Don’t make up any new information: {‘\n’.join([f‘ – {chunk}’ for chunk, similarity in retrieved_knowledge])} ”‘ |
و سپس پاسخ مدل تولید میشود:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
stream = ollama.chat( model=LANGUAGE_MODEL, messages=[ {‘role’: ‘system’, ‘content’: instruction_prompt}, {‘role’: ‘user’, ‘content’: input_query}, ], stream=True, ) print(‘Chatbot response:’) for chunk in stream: print(chunk[‘message’][‘content’], end=”, flush=True) |
گام نهم: اجرای نهایی
کد را در فایلی با نام demo.py ذخیره کرده و اجرا کنید:
|
1 |
python demo.py |
حالا میتوانید از چتبات سوال بپرسید و پاسخهایی دریافت کنید که بر اساس دادههای بازیابیشده از دیتاست تولید شدهاند.
نقاط قابل بهبود
پیادهسازی فعلی ساده است، اما محدودیتهایی دارد:
۱. اگر پرسش شامل چند موضوع باشد، ممکن است پاسخ دقیق نباشد.
- راهکار: استفاده از query rewriting یا چندین query برای پوشش بیشتر
۲. نتایج بر اساس شباهت کسینی مرتب میشوند، که همیشه بهترین نتیجه را نمیدهد.
- راهکار: استفاده از مدلهای reranking برای مرتبسازی مجدد
۳. پایگاه داده در حافظه نگهداری میشود، پس برای دادههای بزرگ مقیاسپذیر نیست.
- راهکار: استفاده از Qdrant یا Pinecone
۴. هر جمله بهعنوان یک chunk در نظر گرفته شده است.
- راهکار: استفاده از تقسیمبندی هوشمندتر و پیشپردازش دادهها
۵. مدل زبانی استفادهشده تنها ۱ میلیارد پارامتر دارد.
- راهکار: برای کاربردهای پیچیدهتر، میتوان از مدلهای بزرگتر بهره برد
چالشها و محدودیتهای پیاده کردن RAG

در پیادهسازی یک سیستم RAG، هرچند مزایای زیادی از جمله دسترسی به دانش خارجی و افزایش دقت پاسخها وجود دارد، با چالشها و محدودیتهای خاصی نیز مواجه هستیم. این چالشها از محدودیتهای مقیاسپذیری و حجم داده گرفته تا کیفیت بازیابی و کنترل خطاهای مدل متغیر هستند و توجه دقیق به آنها برای طراحی یک سیستم موثر و پایدار ضروری است.
۱. مقیاسپذیری
- وقتی حجم دادهها زیاد میشود، نگهداری و جستجوی سریع در پایگاه برداری حافظهای دشوار میشود.
- نیاز به پایگاههای برداری تخصصی و بهینه (مثل Qdrant یا Pinecone) برای پروژههای واقعی.
۲. کیفیت بازیابی و رتبهبندی
- embedding ساده همیشه نتایج دقیق نمیدهد.
- بدون رنکینگ مناسب، مدل ممکن است اطلاعات غیرمرتبط یا کماهمیت را برگرداند.
۳. مدیریت حجم زیاد داده
- chunking نامناسب یا طول زیاد متن باعث کاهش کیفیت بازیابی میشود.
- انتخاب اندازه مناسب chunk و استراتژی تقسیم متن اهمیت بالایی دارد.
۴. هزینه محاسبات embedding و بازیابی
- ساخت embedding برای تعداد زیادی متن هزینهی محاسباتی بالایی دارد.
- بازیابی مشابهت و محاسبه فاصله بین بردارها نیز با افزایش دادهها سنگین میشود.
۵. کنترل Hallucinations و تولید اشتباه
- حتی با دادههای بازیابیشده، مدل تولیدی ممکن است اطلاعات نادرست بسازد.
- ترکیب دادههای بازیابیشده با کنترلهای مدل یا re-ranking ضروری است.
۶. پیچیدگی یکپارچهسازی
- اتصال embedding، پایگاه برداری، بازیابی و مدل تولیدی بهصورت یک جریان روان چالشبرانگیز است.
- خطاها در هر مرحله میتوانند کیفیت پاسخ نهایی را شدیدا کاهش دهند.
روشهای پیشرفته انجام RAG
با گذر از پیادهسازی پایه، برای افزایش دقت، سرعت و کارایی سیستم RAG میتوان از روشهای پیشرفته و بهبودهای عملی استفاده کرد. این تکنیکها به مدیریت بهتر دادهها، کاهش هزینه محاسباتی و کنترل خطاهای تولید کمک میکنند و سیستم را برای استفاده در پروژههای واقعی آماده میسازند.
- استفاده از پایگاههای برداری واقعی: به جای پایگاه حافظهای ساده، از پایگاههایی مانند Qdrant و Pinecone برای ذخیره و جستجوی سریع بردارها استفاده میشود.
- مدلهای رنکینگ (Reranker): برای بهبود کیفیت نتایج بازیابی، میتوان از مدلهای رنکینگ استفاده کرد که اسناد مرتبطتر را در اولویت قرار میدهند.
- تقسیمبندی هوشمند متن: ترکیب n-gram و sliding window باعث میشود chunkها با دقت بیشتری تولید شوند و اطلاعات از دست نرود.
- روشهای ترکیبی: ترکیب RAG با روشهای دیگر مانند Hybrid RAG یا Graph RAG به افزایش دقت و پوشش دانش کمک میکند.
- Caching و Prefetching: ذخیره نتایج بازیابی متداول و پیشخوانی دادهها باعث کاهش زمان پاسخ و بار محاسباتی میشود.
- بهینهسازی embedding: انتخاب مدل embedding مناسب و فشردهسازی بردارها، هم سرعت و هم دقت بازیابی را بهبود میدهد.
نمونه واقعی از پیاده سازی RAG
برای درک عملکرد RAG و تاثیر بهبودهای پیشرفته، فرض کنید یک مجموعه داده متوسط شامل ۵۰۰ سند متنی داریم. ابتدا نسخه ساده سیستم پیادهسازی میشود: متون به chunk تقسیم میشوند، embedding ساخته میشود و بازیابی بر اساس تشابه برداری انجام میگیرد. سپس نسخه بهبود یافته با تکنیکهای پیشرفته مانند پایگاه برداری واقعی (Qdrant/Pinecone)، رنکینگ و تقسیمبندی هوشمند متن اجرا میشود.
با سنجش دو معیار اصلی:
- دقت بازیابی: چند درصد از پاسخهای برگردانده شده واقعا مرتبط با پرسش هستند
- زمان پاسخدهی: مدت زمان لازم برای بازیابی و تولید پاسخ
میتوان تفاوت را مشاهده کرد. برای مثال:
| نسخه | دقت بازیابی | زمان پاسخ |
| ساده | 65٪ | 1.2 ثانیه |
| بهبود یافته | 85٪ | 0.8 ثانیه |
این جدول به شکل ملموس نشان میدهد که بهبودها چگونه هم کیفیت پاسخها را افزایش میدهند و هم سرعت سیستم را بهبود میبخشند. میتوانیم یک نمونه کد پایتون ساده آماده کنیم که نشان دهد چطور میتوان یک نسخه ساده و یک نسخه بهبود یافته RAG را روی یک مجموعه داده کوچک شبیهسازی کرد و دقت و زمان پاسخ را مقایسه کرد.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
import time from sklearn.metrics.pairwise import cosine_similarity from sentence_transformers import SentenceTransformer import numpy as np # مجموعه داده نمونه (۵ سند کوچک) documents = [ “RAG combines retrieval and generation in language models.”, “Vector databases store embeddings for fast search.”, “Chunking text properly improves retrieval quality.”, “Reranking helps prioritize relevant documents.”, “Caching and prefetching reduce response time.” ] queries = [ “How can retrieval improve language models?”, “What reduces response time in RAG?” ] # مدل embedding model = SentenceTransformer(‘all-MiniLM-L6-v2’) # — نسخه ساده — start_simple = time.time() doc_embeddings = model.encode(documents) results_simple = [] for query in queries: q_emb = model.encode([query]) sims = cosine_similarity(q_emb, doc_embeddings)[0] top_idx = np.argmax(sims) results_simple.append((documents[top_idx], sims[top_idx])) end_simple = time.time() # — نسخه بهبود یافته — # فرض کنید بهبودها شامل رنکینگ ساده + caching است start_adv = time.time() # embedding ها cache شده (فرضی) cached_embeddings = doc_embeddings results_adv = [] for query in queries: q_emb = model.encode([query]) sims = cosine_similarity(q_emb, cached_embeddings)[0] # فرض رنکینگ: top 2 رو بررسی کن top2_idx = sims.argsort()[–2:][::–1] results_adv.append([(documents[i], sims[i]) for i in top2_idx]) end_adv = time.time() # نمایش نتایج print(“=== نسخه ساده ===”) for q, (doc, sim) in zip(queries, results_simple): print(f“Query: {q}\nTop Doc: {doc}\nSimilarity: {sim:.2f}\n”) print(f“زمان پاسخ: {end_simple – start_simple:.2f} ثانیه\n”) print(“=== نسخه بهبود یافته ===”) for q, docs in zip(queries, results_adv): print(f“Query: {q}”) for doc, sim in docs: print(f” Doc: {doc}, Similarity: {sim:.2f}”) print(f“زمان پاسخ: {end_adv – start_adv:.2f} ثانیه”) |
راهنمای استقرار RAG

پس از پیادهسازی و بهبود سیستم RAG، مرحله مهم بعدی استقرار در محیط واقعی و حفظ عملکرد پایدار است. برای این منظور باید به چند نکته کلیدی توجه کرد:
۱. زیرساخت پیشنهادی
- استفاده از پایگاههای برداری مقیاسپذیر مانند Qdrant یا Pinecone برای ذخیره و جستجوی embeddings.
- اجرای مدل تولیدی و بخش بازیابی روی سرورهای با GPU یا CPU مناسب بسته به حجم داده و نیاز پاسخ سریع.
- طراحی معماری modular برای جداسازی بخشهای بازیابی، رنکینگ و تولید متن، تا نگهداری و بهروزرسانی آسان باشد.
۲. مانیتورینگ و بهروزرسانی
- پایش زمان پاسخدهی و کیفیت بازیابی بهصورت مداوم برای شناسایی افت عملکرد.
- بهروزرسانی embeddingها و مدلهای رنکینگ با دادههای جدید برای حفظ دقت.
- ثبت لاگها و خطاها جهت تحلیل و بهینهسازی سیستم در آینده.
۳. معیارهای ارزیابی
- دقت بازیابی (Precision/Recall): درصد پاسخهای مرتبط و کامل.
- زمان پاسخدهی: مدت زمان لازم برای بازیابی و تولید پاسخ.
- حجم داده و مصرف منابع: میزان حافظه و توان محاسباتی استفاده شده.
۴. نکات امنیتی و حفظ حریم خصوصی
- رمزنگاری دادهها در انتقال و ذخیرهسازی (SSL/TLS، encryption).
- کنترل دسترسی و احراز هویت کاربران برای جلوگیری از دسترسی غیرمجاز.
- رعایت قوانین حریم خصوصی و حذف دادههای حساس یا شخصی قبل از ساخت embedding.
نتیجهگیری
پیادهسازی RAG نشان میدهد که ترکیب بازیابی دانش و تولید متن، توانایی چشمگیری در بهبود دقت و گستره پاسخهای مدلهای زبانی فراهم میکند. با اجرای قدمبهقدم سیستم، از ایندکسسازی و ساخت embedding تا بازیابی و تولید پاسخ، میتوان به یک سیستم پایه دست یافت اما مواجهه با چالشهایی مانند مقیاسپذیری، کیفیت بازیابی و کنترل خطا ضروری است.
بهرهگیری از بهبودهای پیشرفته مانند پایگاههای برداری واقعی، رنکینگ، تقسیمبندی هوشمند متن و روشهای ترکیبی، علاوهبر افزایش دقت، زمان پاسخ را کاهش میدهد و تجربه عملی ملموسی ارائه میکند. در نهایت، رعایت اصول استقرار، مانیتورینگ و امنیت دادهها باعث میشود سیستم RAG نه تنها کارآمد، بلکه پایدار و قابل اعتماد در پروژههای واقعی باشد.
منابع
سوالات متداول
مدل embedding برای تبدیل متن به بردار
پایگاه داده برداری برای ذخیره و جستجوی بردارها
الگوریتم بازیابی و متریک مشابهت
مدل تولید متن برای ترکیب پاسخها با دانش بازیابیشده
مقیاسپذیری و مدیریت حجم زیاد داده
کیفیت بازیابی و رتبهبندی نتایج
هزینه محاسباتی embedding و بازیابی
کنترل خطاها و تولید اطلاعات نادرست (هالوسینیشن)
استفاده از پایگاههای برداری واقعی (مثل Qdrant و Pinecone)
اعمال مدلهای رنکینگ (Reranker)
تقسیمبندی هوشمند متن و روشهای ترکیبی (Hybrid یا Graph RAG)
caching و prefetching برای کاهش زمان پاسخ




دیدگاهتان را بنویسید