spinny:~/writing $ less rag-langchain-deep-dive.md
12বড় ভাষা মডেল (LLMs) যেমন GPT-4 এবং Claude অসাধারণভাবে শক্তিশালী, কিন্তু তারা একটি মৌলিক সীমাবদ্ধতায় ভোগে: তাদের জ্ঞান প্রশিক্ষণের সময়ে স্থির হয়ে যায়। তারা আপনার অভ্যন্তরীণ নথি, আপনার ডাটাবেস বা রিয়েল-টাইম তথ্য অ্যাক্সেস করতে পারে না। **রিট্রিভাল-অগমেন্টেড জেনারেশন (RAG)** ঠিক এই সমস্যাটি সমাধান করে, LLM-এর জেনারেটিভ ক্ষমতার সাথে বাহ্যিক উৎস থেকে তথ্য পুনরুদ্ধারের ক্ষমতা সংযুক্ত করে।34## সমস্যা: LLM-এর সীমাবদ্ধতা56RAG নিয়ে কথা বলার আগে, আমাদের কেন এটি প্রয়োজন তা বোঝা গুরুত্বপূর্ণ।781. **স্থির জ্ঞান**: একটি LLM শুধুমাত্র সেটাই জানে যা সে প্রশিক্ষণের সময় দেখেছে। আপনি যদি এর কাটঅফের পরে ঘটে যাওয়া কোনো ঘটনা সম্পর্কে জিজ্ঞেস করেন, এটি উত্তর দিতে পারে না।92. **হ্যালুসিনেশন**: যখন একটি LLM উত্তর জানে না, তখন এটি একটি তৈরি করার প্রবণতা রাখে, বিশ্বাসযোগ্য কিন্তু সম্পূর্ণ মিথ্যা তথ্য তৈরি করে।103. **ব্যক্তিগত ডেটায় অ্যাক্সেস নেই**: একটি সাধারণ LLM-এর আপনার কোম্পানির অভ্যন্তরীণ ডকুমেন্টেশন, টিকেট বা কোডবেসে অ্যাক্সেস নেই।1112RAG এই তিনটি সমস্যারই সমাধান করে, কুয়েরির সময় বাহ্যিক উৎস থেকে পুনরুদ্ধার করা **প্রাসঙ্গিক প্রসঙ্গ** মডেলকে প্রদান করে।1314## RAG কী?1516রিট্রিভাল-অগমেন্টেড জেনারেশন হলো একটি আর্কিটেকচার যা একটি বাহ্যিক জ্ঞান ভিত্তি থেকে পুনরুদ্ধার করা তথ্য দিয়ে LLM-এ পাঠানো প্রম্পটকে সমৃদ্ধ করে। মডেলের প্যারামেট্রিক জ্ঞানের উপর সম্পূর্ণভাবে নির্ভর করার পরিবর্তে, RAG প্রথমে প্রাসঙ্গিক তথ্য **অনুসন্ধান** করে এবং তারপর সেটি প্রম্পটে **ইনজেক্ট** করে, মডেলকে সঠিক, ভিত্তিযুক্ত প্রতিক্রিয়া তৈরি করতে সক্ষম করে।1718```mermaid19graph LR20 User["User"] -- "Question" --> Retriever21 Retriever -- "Search relevant\ndocuments" --> VectorStore["Vector Store"]22 VectorStore -- "Relevant\ndocuments" --> Retriever23 Retriever -- "Context + Question" --> LLM24 LLM -- "Grounded\nresponse" --> User25```2627## RAG কীভাবে বিস্তারিতভাবে কাজ করে2829RAG আর্কিটেকচার দুটি প্রধান ধাপ নিয়ে গঠিত: **ইনডেক্সিং** (অফলাইন) এবং **রিট্রিভাল + জেনারেশন** (অনলাইন)।3031### ধাপ ১: ইনডেক্সিং (ডকুমেন্ট ইনজেশন)3233ইনডেক্সিং ধাপ আপনার নথিগুলোকে সেমান্টিক সার্চের জন্য প্রস্তুত করে। এটি চারটি পদক্ষেপ নিয়ে গঠিত।3435```mermaid36graph TD37 A["Documents\n(PDF, HTML, MD, DB)"] --> B["Document Loader"]38 B --> C["Text Splitter"]39 C --> D["Text Chunks"]40 D --> E["Embedding Model"]41 E --> F["Numerical Vectors"]42 F --> G["Vector Store\n(ChromaDB, Pinecone, FAISS)"]43```4445#### ১. ডকুমেন্ট লোডিং4647নথিগুলো যেকোনো উৎস থেকে আসতে পারে: PDF ফাইল, ওয়েব পেজ, ডাটাবেস, Markdown ফাইল, API। **Document Loader** এই নথিগুলো পড়ে এবং কাঠামোবদ্ধ টেক্সটে রূপান্তর করে।4849#### ২. টেক্সট বিভাজন (Chunking)5051LLM-গুলোর সীমিত কনটেক্সট উইন্ডো আছে, এবং নথিগুলো খুব দীর্ঘ হতে পারে। **Text Splitter** নথিগুলোকে *chunks* নামক ছোট খণ্ডে ভাগ করে। Chunking-এর মান অত্যন্ত গুরুত্বপূর্ণ: অত্যন্ত ছোট chunks প্রসঙ্গ হারায়, আবার অত্যন্ত বড় chunks প্রাসঙ্গিকতা কমিয়ে দেয়।5253সবচেয়ে সাধারণ কৌশলগুলো হলো:54- **রিকার্সিভ ক্যারেক্টার স্প্লিটিং**: `\n\n`, `\n`, `. ` এর মতো বিভাজক ব্যবহার করে পুনরাবৃত্তিমূলকভাবে টেক্সট বিভক্ত করে, নথির কাঠামো সম্মান করে।55- **সেমান্টিক স্প্লিটিং**: টেক্সটে প্রাকৃতিক ব্রেকপয়েন্ট খুঁজতে embeddings ব্যবহার করে।56- **Chunk ওভারল্যাপ**: সীমানায় প্রসঙ্গ সংরক্ষণ করতে পরপর chunks-এর মধ্যে ওভারল্যাপ অন্তর্ভুক্ত করে।5758#### ৩. Embedding5960প্রতিটি chunk একটি embedding মডেলের (যেমন OpenAI-এর `text-embedding-3-small`) মাধ্যমে একটি **সংখ্যাসূচক ভেক্টরে** (embedding) রূপান্তরিত হয়। এই ভেক্টরগুলো টেক্সটের সেমান্টিক অর্থ ধারণ করে: একই রকম অর্থযুক্ত বাক্যগুলোর ভেক্টর বহুমাত্রিক স্থানে কাছাকাছি থাকবে।6162#### ৪. Vector Store6364ভেক্টরগুলো একটি **Vector Store**-এ (বা ভেক্টর ডাটাবেস) সংরক্ষিত হয়, যেমন ChromaDB, Pinecone, Weaviate বা FAISS। এই ডাটাবেস **সাদৃশ্য অনুসন্ধানের** জন্য অপ্টিমাইজড: একটি কুয়েরি দেওয়া হলে, এটি সবচেয়ে সাদৃশ্যপূর্ণ ভেক্টর (এবং তাই সবচেয়ে প্রাসঙ্গিক টেক্সট chunks) খুঁজে বের করে।6566### ধাপ ২: রিট্রিভাল + জেনারেশন6768যখন ব্যবহারকারী একটি প্রশ্ন করেন:69701. প্রশ্নটি একই embedding মডেল ব্যবহার করে একটি embedding-এ রূপান্তরিত হয়।712. Vector Store **সাদৃশ্য অনুসন্ধানের** মাধ্যমে সবচেয়ে সাদৃশ্যপূর্ণ chunks খুঁজে বের করে (সাধারণত কোসাইন সাদৃশ্য বা ইউক্লিডীয় দূরত্ব)।723. পুনরুদ্ধার করা chunks প্রসঙ্গ হিসেবে প্রম্পটে ঢোকানো হয়।734. LLM প্রদত্ত প্রসঙ্গের ভিত্তিতে একটি প্রতিক্রিয়া তৈরি করে।7475## LangChain দিয়ে একটি RAG পাইপলাইন তৈরি7677**LangChain** হলো LLM-চালিত অ্যাপ্লিকেশন তৈরির জন্য সবচেয়ে জনপ্রিয় Python (এবং JavaScript) ফ্রেমওয়ার্ক। এটি RAG পাইপলাইনের প্রতিটি উপাদানের জন্য উচ্চ-স্তরের অ্যাবস্ট্রাকশন প্রদান করে।7879### ইনস্টলেশন8081```bash82pip install langchain langchain-openai langchain-community chromadb83```8485### পদক্ষেপ ১: ডকুমেন্ট লোড করুন8687LangChain বিভিন্ন ডেটা সোর্সের জন্য ডজনখানেক Document Loader প্রদান করে।8889```python90from langchain_community.document_loaders import (91 PyPDFLoader,92 WebBaseLoader,93 DirectoryLoader,94 TextLoader,95)9697# Load a PDF98pdf_loader = PyPDFLoader("docs/manual.pdf")99pdf_docs = pdf_loader.load()100101# Load a web page102web_loader = WebBaseLoader("https://docs.example.com/guide")103web_docs = web_loader.load()104105# Load all .md files from a directory106dir_loader = DirectoryLoader("./knowledge_base", glob="**/*.md", loader_cls=TextLoader)107md_docs = dir_loader.load()108109all_docs = pdf_docs + web_docs + md_docs110```111112### পদক্ষেপ ২: ডকুমেন্টগুলোকে Chunks-এ ভাগ করুন113114```python115from langchain.text_splitter import RecursiveCharacterTextSplitter116117text_splitter = RecursiveCharacterTextSplitter(118 chunk_size=1000,119 chunk_overlap=200,120 separators=["\n\n", "\n", ". ", " ", ""],121)122123chunks = text_splitter.split_documents(all_docs)124print(f"Original documents: {len(all_docs)}, Chunks: {len(chunks)}")125```126127`chunk_overlap` প্যারামিটারটি অত্যন্ত গুরুত্বপূর্ণ: এটি পরপর chunks-এর মধ্যে ওভারল্যাপ তৈরি করে যাতে সীমানায় প্রসঙ্গ হারিয়ে না যায়।128129### পদক্ষেপ ৩: Embeddings এবং Vector Store তৈরি করুন130131```python132from langchain_openai import OpenAIEmbeddings133from langchain_community.vectorstores import Chroma134135embedding_model = OpenAIEmbeddings(model="text-embedding-3-small")136137vectorstore = Chroma.from_documents(138 documents=chunks,139 embedding=embedding_model,140 persist_directory="./chroma_db",141)142```143144### পদক্ষেপ ৪: Retriever তৈরি করুন145146Retriever হলো সেই উপাদান যা, একটি কুয়েরি দেওয়া হলে, vector store থেকে সবচেয়ে প্রাসঙ্গিক chunks সংগ্রহ করে।147148```python149retriever = vectorstore.as_retriever(150 search_type="similarity",151 search_kwargs={"k": 4},152)153154relevant_docs = retriever.invoke("How does authentication work?")155for doc in relevant_docs:156 print(doc.page_content[:200])157 print("---")158```159160### পদক্ষেপ ৫: RAG চেইন তৈরি করুন161162এখন একটি LLM এবং একটি প্রম্পট টেমপ্লেটের সাথে সবকিছু একসাথে যুক্ত করা যাক।163164```python165from langchain_openai import ChatOpenAI166from langchain_core.prompts import ChatPromptTemplate167from langchain_core.runnables import RunnablePassthrough168from langchain_core.output_parsers import StrOutputParser169170llm = ChatOpenAI(model="gpt-4o", temperature=0)171172prompt = ChatPromptTemplate.from_template("""173Answer the question based only on the provided context.174If the context does not contain enough information, say you don't know.175176Context:177{context}178179Question: {question}180181Answer:182""")183184def format_docs(docs):185 return "\n\n".join(doc.page_content for doc in docs)186187rag_chain = (188 {"context": retriever | format_docs, "question": RunnablePassthrough()}189 | prompt190 | llm191 | StrOutputParser()192)193194response = rag_chain.invoke("How does authentication work in the system?")195print(response)196```197198## উন্নত RAG কৌশল199200বেসিক পাইপলাইন ভালো কাজ করে, কিন্তু প্রতিক্রিয়ার মান উল্লেখযোগ্যভাবে উন্নত করতে বেশ কিছু কৌশল রয়েছে।201202### মাল্টি-কুয়েরি রিট্রিভাল203204কখনো কখনো ব্যবহারকারীর কুয়েরি অস্পষ্ট হয় বা নথিতে ব্যবহৃত ভাষার সাথে সামঞ্জস্যপূর্ণ নয়। **Multi-Query Retriever** স্বয়ংক্রিয়ভাবে মূল প্রশ্নের বিভিন্ন সংস্করণ তৈরি করে বিভিন্ন দৃষ্টিভঙ্গি ক্যাপচার করতে।205206```python207from langchain.retrievers import MultiQueryRetriever208209multi_retriever = MultiQueryRetriever.from_llm(210 retriever=vectorstore.as_retriever(),211 llm=llm,212)213214docs = multi_retriever.invoke("What are the security best practices?")215```216217### প্রাসঙ্গিক সংকোচন218219একটি chunk-এর সমস্ত বিষয়বস্তু কুয়েরির জন্য প্রাসঙ্গিক নয়। **Contextual Compression Retriever** প্রতিটি পুনরুদ্ধার করা chunk থেকে শুধুমাত্র প্রাসঙ্গিক অংশগুলো বের করতে একটি LLM ব্যবহার করে।220221```python222from langchain.retrievers import ContextualCompressionRetriever223from langchain.retrievers.document_compressors import LLMChainExtractor224225compressor = LLMChainExtractor.from_llm(llm)226compression_retriever = ContextualCompressionRetriever(227 base_compressor=compressor,228 base_retriever=retriever,229)230```231232### হাইব্রিড সার্চ233234সম্পূর্ণ সেমান্টিক সার্চ সবসময় আদর্শ নয়। **হাইব্রিড সার্চ** ভালো ফলাফল অর্জনের জন্য সেমান্টিক সার্চ (embeddings) এর সাথে লেক্সিকাল সার্চ (BM25, কীওয়ার্ড ম্যাচিং) একত্রিত করে।235236```python237from langchain.retrievers import EnsembleRetriever238from langchain_community.retrievers import BM25Retriever239240bm25_retriever = BM25Retriever.from_documents(chunks)241bm25_retriever.k = 4242243semantic_retriever = vectorstore.as_retriever(search_kwargs={"k": 4})244245hybrid_retriever = EnsembleRetriever(246 retrievers=[bm25_retriever, semantic_retriever],247 weights=[0.4, 0.6],248)249```250251### কথোপকথনমূলক RAG (মেমোরি সহ)252253একটি RAG চ্যাটবট তৈরি করতে যা কথোপকথনের প্রসঙ্গ মনে রাখে, কথোপকথনের ইতিহাস বিবেচনায় নিয়ে ব্যবহারকারীর প্রশ্নগুলো পুনর্গঠন করে এমন মেমোরি যোগ করতে হবে।254255```python256from langchain.chains import create_history_aware_retriever257from langchain_core.prompts import MessagesPlaceholder258259contextualize_prompt = ChatPromptTemplate.from_messages([260 ("system", "Given the chat history and the user's latest question, "261 "reformulate the question so it is understandable without the history."),262 MessagesPlaceholder("chat_history"),263 ("human", "{input}"),264])265266history_aware_retriever = create_history_aware_retriever(267 llm, retriever, contextualize_prompt268)269```270271## সর্বোত্তম অনুশীলন2722731. **সঠিক chunk আকার বেছে নিন**: বিভিন্ন আকার নিয়ে পরীক্ষা করুন (৫০০-১৫০০ টোকেন)। সুনির্দিষ্ট উত্তরের জন্য ছোট chunks, বৃহত্তর প্রসঙ্গের জন্য বড় chunks।2742. **ডকুমেন্ট মেটাডেটা ব্যবহার করুন**: chunks-এ মেটাডেটা হিসেবে উৎস, তারিখ এবং বিভাগ যোগ করুন। এটি রিট্রিভালের সময় ফলাফল ফিল্টার করতে দেয়।2753. **গুণমান মূল্যায়ন করুন**: *faithfulness*, *relevancy* এবং *context precision* এর মতো মেট্রিক্স পরিমাপ করতে [RAGAS](https://docs.ragas.io/) এর মতো ফ্রেমওয়ার্ক ব্যবহার করুন।2764. **ডকুমেন্ট আপডেট পরিচালনা করুন**: আপনার ডেটা সোর্সের সাথে vector store সিঙ্ক্রোনাইজড রাখতে একটি পুনরায়-ইনজেশন পাইপলাইন বাস্তবায়ন করুন।2775. **একটি re-ranker যোগ করুন**: প্রাথমিক রিট্রিভালের পরে, প্রকৃত প্রাসঙ্গিকতার ভিত্তিতে ফলাফলগুলো পুনরায় সাজাতে একটি re-ranking মডেল (যেমন Cohere Rerank) ব্যবহার করুন।278279## উপসংহার280281RAG নির্দিষ্ট, আপ-টু-ডেট জ্ঞানে অ্যাক্সেস প্রয়োজন এমন AI অ্যাপ্লিকেশন তৈরির জন্য মানক আর্কিটেকচারে পরিণত হয়েছে। LangChain পাইপলাইনের প্রতিটি উপাদানের জন্য অ্যাবস্ট্রাকশন প্রদান করে বাস্তবায়নকে ব্যাপকভাবে সরল করে।282283**পরবর্তী পদক্ষেপ:**284- **স্থানীয়ভাবে পরীক্ষা করুন**: পাইপলাইনের সাথে পরিচিত হতে ChromaDB এবং কিছু নথি দিয়ে শুরু করুন।285- **LangSmith অন্বেষণ করুন**: প্রোডাকশনে আপনার চেইনগুলো মনিটর এবং ডিবাগ করতে [LangSmith](https://smith.langchain.com/) ব্যবহার করুন।286- **বিভিন্ন embedding মডেল ব্যবহার করে দেখুন**: `text-embedding-3-small`, `text-embedding-3-large` এবং Sentence Transformers এর ওপেন-সোর্স মডেলগুলো তুলনা করুন।287- **ডকুমেন্টেশন দেখুন**: [LangChain ডকুমেন্টেশন](https://python.langchain.com/docs/) একটি চমৎকার এবং ক্রমাগত আপডেটেড রিসোর্স।288
:RAG এবং LangChain: রিট্রিভাল-অগমেন্টেড জেনারেশনের একটি সম্পূর্ণ গাইডlines 1-288 (END) — press q to close