پیش از نوشتن حتی یک خط کد، باید درک درستی از پاترن معماری RAG داشته باشیم. سیستم RAG به طور کلی به دو فاز اصلی تقسیم میشود:
فاز آمادهسازی داده (Ingestion Pipeline): اسناد خام (PDF، متن، کدهای منبع) خرد شده (Chunking)، به بردارهای عددی (Embeddings) تبدیل شده و در یک پایگاه داده برداری (Vector Database) ذخیره میشوند.
فاز استنباط و پاسخدهی (Inference Pipeline): هنگامی که کاربر سؤالی میپرسد، ابتدا پرسش به بردار تبدیل شده، مرتبطترین اسناد از پایگاه داده بازیابی میشوند و سپس به همراه پرسش اصلی به عنوان Context به LLM تزریق میشوند تا پاسخ دقیق و مبتنی بر مستندات تولید شود.
[User Query]
│
▼
[Embedding Model] ──> [Vector DB Search] ──> [Top-K Relevant Chunks]
│
▼
[LLM (e.g., OpenAI/Llama)] <── [Prompt + Context + Query] ──┘
│
▼
[Accurate Response to User]
برای اینکه بتوانیم در ۳۰ دقیقه پروژه را به سرانجام برسانیم، از پشته نرمافزاری زیر استفاده میکنیم:
زبان برنامهنویسی: Python 3.10+
کتابخانه ارکستراسیون: LangChain یا LlamaIndex (در این مقاله رویکرد ماژولار مبتنی بر کدنویسی تمیز با کتابخانههای سبک است).
پایگاه داده برداری: ChromaDB (سبک، محلی و بدون نیاز به سرور جداگانه).
مدل Embedding و LLM: مدلهای OpenAI (مانند text-embedding-3-small و gpt-4o-mini) برای سرعت و کیفیت بالا.
نصب کتابخانههای مورد نیاز
ترمینال خود را باز کرده و دستور زیر را اجرا کنید:
pip install langchain langchain-openai chromadb sentence-transformers pypdf python-dotenv
پروژه را در یک ساختار ماژولار و تمیز پیادهسازی میکنیم. فایل اصلی را با نام rag_chatbot.py ایجاد کنید.
گام اول: پیکربندی و اتصال به API
ابتدا کلیدهای امنیتی و تنظیمات اولیه را بارگذاری میکنیم:
import os
from dotenv import load_dotenv
load_dotenv()
# تنظیم کلید API (میتوانید در فایل .env قرار دهید)
# os.environ["OPENAI_API_KEY"] = "your-api-key-here"
گام دوم: ایندکسسازی و مدیریت اسناد (Ingestion)
در این بخش، مستندات محلی (مثلاً فایلهای PDF یا متنی) را خوانده و پس از خرد کردن (Chunking)، آنها را برداری و در ChromaDB ذخیره میکنیم.
from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
def initialize_vector_db(docs_path: str, persist_dir: str = "./chroma_db"):
"""اسناد را بارگذاری کرده و پایگاه داده برداری را میسازد."""
print("[*] در حال بارگذاری اسناد...")
loader = DirectoryLoader(docs_path, glob="**/*.pdf", loader_cls=PyPDFLoader)
documents = loader.load()
# خرد کردن متن به تکههای مناسب (Chunking Strategy)
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
length_function=len,
)
chunks = text_splitter.split_documents(documents)
print(
f"[*] تعداد {len.documents if 'documents' in locals() else len(chunks)}"
f" تکه متن استخراج شد."
)
# ساخت Embeddings و ذخیرهسازی در Vector DB
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = Chroma.from_documents(
documents=chunks, embedding=embeddings, persist_directory=persist_dir
)
print("[✓] پایگاه داده برداری با موفقیت آماده شد.")
return vector_store
گام سوم: راهاندازی موتور جستجو و تولید پاسخ (Retrieval & Generation)
اکنون منطق اصلی چتبات را پیادهسازی میکنیم که شامل جستجوی معنایی (Semantic Search) و ارسال کانتکست به مدل زبانی است.
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
def create_rag_chatbot(vector_store):
# تعریف پرامپت مهندسیشده برای جلوگیری از توهم (Hallucination)
system_prompt = (
"شما یک دستیار هوشمند و متخصص هستید."
"برای پاسخ به سوالات، فقط و فقط از اطلاعات بازیابی شده زیر استفاده کنید."
"اگر جواب را در متن نیافتید، با ادب بگویید که اطلاعاتی در دست ندارید."
"\n\n"
"{context}"
)
prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
("human", "{input}"),
])
# مدل زبانی LLM
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.2)
# ساخت زنجیرههای RAG
question_answer_chain = create_stuff_documents_chain(llm, prompt)
retriever = vector_store.as_retriever(
search_type="similarity", search_kwargs={"k": 3}
)
rag_chain = create_retrieval_chain(retriever, question_answer_chain)
return rag_chain
گام چهارم: اجرای حلقه تعاملی (CLI Chat Loop)
حالا میتوانیم برنامه را به صورت تعاملی در ترمینال اجرا کنیم:
if __name__ == "__main__":
# مسیر پوشه حاوی اسناد (PDFها)
DOCS_DIR = "./data"
if not os.path.exists(DOCS_DIR):
os.makedirs(DOCS_DIR)
print(
f"پوشه {DOCS_DIR} ایجاد شد. لطفاً چند فایل PDF در آن قرار دهید و دوباره"
" تلاش کنید."
)
exit(1)
# آمادهسازی پایگاه داده و چتبات
vector_store = initialize_vector_db(DOCS_DIR)
chatbot_chain = create_rag_chatbot(vector_store)
print(
"\n--- چتبات RAG آماده است! (برای خروج 'exit' یا 'quit' را تایپ کنید)"
" ---"
)
while True:
query = input("\nکاربر: ")
if query.lower() in ["exit", "quit"]:
print("خداحافظ!")
break
if not query.strip():
continue
# اجرای پرسوجو
response = chatbot_chain.invoke({"input": query})
print(f"\nچتبات: {response['answer']}")
پیادهسازی بالا در ۳۰ دقیقه انجام میشود، اما برای تبدیل آن به یک محصول نرمافزاری مقیاسپذیر و قابل اتکا در سطح سازمانی، رعایت نکات زیر الزامی است:
بهینهسازی Chunking Strategy: خرد کردن ساده متن بر اساس کاراکتر ممکن است وسط یک جمله یا پاراگراف مهم انجام شود. استفاده از روشهای ساختاریافته (مثل Semantic Chunking یا تفکیک بر اساس عناوین Markdown/PDF) کیفیت بازیابی را به شدت بالا میبرد.
مکانیزم Hybrid Search: ترکیب جستجوی معنایی (Vector Search) با جستجوی سنتی کلیدواژهای (Keyword Search مانند BM25) دقت یافتن اسناد مرتبط را بهبود میدهد.
مدیریت حافظه مکالمه (Conversational Memory): چتبات بالا به صورت پرسش و پاسخ مستقل (Stateless) کار میکند. برای داشتن یک گفتگوی پیوسته، باید تاریخچه گفتگو (Chat History) را به زنجیره RAG اضافه کنید تا مدل ارجاعات ضمایر (مثل «آن چطور کار میکند؟») را درک کند.
Caching: استفاده از سیستمهای کشینگ برای پاسخهای تکراری باعث کاهش هزینههای API و افزایش سرعت پاسخدهی میشود.
همانطور که دیدید، با استفاده از ابزارهای مدرن مهندسی نرمافزار و فریمورکهای استاندارد، ساخت یک پروتوتایپ کاملاً کاربردی و هوشمند از چتبات RAG در کمتر از ۳۰ دقیقه کاملاً امکانپذیر است. این معماری به شما اجازه میدهد دادههای محرمانه یا اختصاصی خود را بدون نیاز به آموزش مجدد مدلهای گرانقیمت، به دامنهی دانش LLM اضافه کنید.
0 نظر
هنوز نظری برای این مقاله ثبت نشده است.