paint-brush
RAG ایپلی کیشنز میں درستگی کو غیر مقفل کرنا: Neo4j اور LangChain کے ساتھ نالج گرافس کا استعمالکی طرف سے@neo4j
220 ریڈنگز

RAG ایپلی کیشنز میں درستگی کو غیر مقفل کرنا: Neo4j اور LangChain کے ساتھ نالج گرافس کا استعمال

کی طرف سے Neo4j9m2024/10/21
Read on Terminal Reader

بہت لمبا؛ پڑھنے کے لئے

یہ بلاگ پوسٹ دکھاتی ہے کہ LangChain کا استعمال کرتے ہوئے نالج گراف کیسے بنایا جائے۔ کوڈ GitHub پر دستیاب ہے۔ آپ کو Neo4j مثال قائم کرنے کی ضرورت ہے۔ اس مظاہرے کے لیے، ہم [Elizabeth I’s] Wikipedia صفحہ استعمال کریں گے۔ ویکیپیڈیا سے دستاویزات لانے اور تقسیم کرنے کے لیے ہم [LangChain لوڈرز] کا استعمال کر سکتے ہیں۔
featured image - RAG ایپلی کیشنز میں درستگی کو غیر مقفل کرنا: Neo4j اور LangChain کے ساتھ نالج گرافس کا استعمال
Neo4j HackerNoon profile picture
0-item
1-item


گراف بازیافت بڑھا ہوا جنریشن ( GraphRAG ) رفتار پکڑ رہا ہے اور روایتی ویکٹر تلاش کی بازیافت کے طریقوں میں ایک طاقتور اضافہ بن رہا ہے۔ یہ نقطہ نظر گراف ڈیٹا بیس کی ساختی نوعیت کا فائدہ اٹھاتا ہے، جو ڈیٹا کو نوڈس اور تعلقات کے طور پر منظم کرتے ہیں، تاکہ بازیافت کی گئی معلومات کی گہرائی اور سیاق و سباق کو بڑھایا جا سکے۔



علمی گراف کی مثال۔

گرافس متنوع ڈیٹا کی اقسام میں پیچیدہ تعلقات اور صفات کو آسانی سے گرفت میں لے کر، متنوع اور باہم جڑی ہوئی معلومات کو منظم انداز میں پیش کرنے اور ذخیرہ کرنے میں بہترین ہیں۔ اس کے برعکس، ویکٹر ڈیٹا بیس اکثر ایسی ساختی معلومات کے ساتھ جدوجہد کرتے ہیں، کیونکہ ان کی طاقت اعلیٰ جہتی ویکٹرز کے ذریعے غیر ساختہ ڈیٹا کو سنبھالنے میں مضمر ہے۔ آپ کی RAG ایپلیکیشن میں، آپ دونوں جہانوں میں بہترین حاصل کرنے کے لیے غیر ساختہ متن کے ذریعے ویکٹر کی تلاش کے ساتھ سٹرکچرڈ گراف ڈیٹا کو یکجا کر سکتے ہیں۔ ہم اس بلاگ پوسٹ میں یہی ظاہر کریں گے۔

علم کے گراف بہت اچھے ہیں، لیکن آپ اسے کیسے بنائیں گے؟

علم کا گراف بنانا عام طور پر سب سے مشکل مرحلہ ہوتا ہے۔ اس میں ڈیٹا اکٹھا کرنا اور اس کی تشکیل کرنا شامل ہے، جس کے لیے ڈومین اور گراف ماڈلنگ دونوں کی گہری سمجھ کی ضرورت ہوتی ہے۔


اس عمل کو آسان بنانے کے لیے، ہم LLMs کے ساتھ تجربہ کر رہے ہیں۔ زبان اور سیاق و سباق کی اپنی گہری سمجھ کے ساتھ، LLMs نالج گراف بنانے کے عمل کے اہم حصوں کو خودکار کر سکتے ہیں۔ ٹیکسٹ ڈیٹا کا تجزیہ کرکے، یہ ماڈل اداروں کی شناخت کر سکتے ہیں، ان کے تعلقات کو سمجھ سکتے ہیں، اور تجویز کر سکتے ہیں کہ گراف ڈھانچے میں ان کی بہترین نمائندگی کیسے کی جا سکتی ہے۔


ان تجربات کے نتیجے میں، ہم نے گراف کی تعمیر کے ماڈیول کا پہلا ورژن LangChain میں شامل کیا ہے، جسے ہم اس بلاگ پوسٹ میں ظاہر کریں گے۔


کوڈ GitHub پر دستیاب ہے۔

Neo4j ماحولیاتی سیٹ اپ

آپ کو Neo4j مثال قائم کرنے کی ضرورت ہے۔ اس بلاگ پوسٹ میں مثالوں کے ساتھ عمل کریں۔ سب سے آسان طریقہ Neo4j Aura پر ایک مفت مثال شروع کرنا ہے، جو Neo4j ڈیٹا بیس کے کلاؤڈ انسٹینس پیش کرتا ہے۔ متبادل طور پر، آپ Neo4j ڈیسک ٹاپ ایپلیکیشن ڈاؤن لوڈ کرکے اور مقامی ڈیٹا بیس کی مثال بنا کر Neo4j ڈیٹابیس کی مقامی مثال بھی ترتیب دے سکتے ہیں۔


 os.environ["OPENAI_API_KEY"] = "sk-" os.environ["NEO4J_URI"] = "bolt://localhost:7687" os.environ["NEO4J_USERNAME"] = "neo4j" os.environ["NEO4J_PASSWORD"] = "password" graph = Neo4jGraph()


اس کے علاوہ، آپ کو ایک OpenAI کلید فراہم کرنا ضروری ہے، کیونکہ ہم اس بلاگ پوسٹ میں ان کے ماڈل استعمال کریں گے۔

ڈیٹا ادخال

اس مظاہرے کے لیے، ہم الزبتھ اول کا ویکیپیڈیا صفحہ استعمال کریں گے۔ ہم بغیر کسی رکاوٹ کے ویکیپیڈیا سے دستاویزات لانے اور تقسیم کرنے کے لیے LangChain لوڈرز کا استعمال کر سکتے ہیں۔


 # Read the wikipedia article raw_documents = WikipediaLoader(query="Elizabeth I").load() # Define chunking strategy text_splitter = TokenTextSplitter(chunk_size=512, chunk_overlap=24) documents = text_splitter.split_documents(raw_documents[:3])


بازیافت شدہ دستاویزات کی بنیاد پر گراف بنانے کا وقت آگیا ہے۔ اس مقصد کے لیے، ہم نے ایک LLMGraphTransformermodule نافذ کیا ہے جو گراف ڈیٹا بیس میں علمی گراف کی تعمیر اور ذخیرہ کرنے کو نمایاں طور پر آسان بناتا ہے۔


 llm=ChatOpenAI(temperature=0, model_name="gpt-4-0125-preview") llm_transformer = LLMGraphTransformer(llm=llm) # Extract graph data graph_documents = llm_transformer.convert_to_graph_documents(documents) # Store to neo4j graph.add_graph_documents( graph_documents, baseEntityLabel=True, include_source=True )


آپ اس بات کی وضاحت کر سکتے ہیں کہ آپ کس LLM کو نالج گراف جنریشن چین استعمال کرنا چاہتے ہیں۔ فی الحال، ہم OpenAI اور Mistral سے صرف فنکشن کالنگ ماڈلز کو سپورٹ کرتے ہیں۔ تاہم، ہم مستقبل میں LLM انتخاب کو بڑھانے کا ارادہ رکھتے ہیں۔ اس مثال میں، ہم جدید ترین GPT-4 استعمال کر رہے ہیں۔ نوٹ کریں کہ تیار کردہ گراف کا معیار نمایاں طور پر اس ماڈل پر منحصر ہے جسے آپ استعمال کر رہے ہیں۔ نظریہ میں، آپ ہمیشہ سب سے زیادہ قابل استعمال کرنا چاہتے ہیں۔ LLM گراف ٹرانسفارمرز گراف دستاویزات واپس کرتے ہیں، جنہیں add_graph_documents طریقہ کے ذریعے Neo4j میں درآمد کیا جا سکتا ہے۔ baseEntityLabel پیرامیٹر ایک اضافی تفویض کرتا ہے۔ ہستی ہر نوڈ پر لیبل، اشاریہ سازی اور استفسار کی کارکردگی کو بڑھانا۔ Include_source پیرامیٹر نوڈس کو ان کی ابتدائی دستاویزات سے جوڑتا ہے، ڈیٹا کو ٹریس ایبلٹی اور سیاق و سباق کو سمجھنے میں سہولت فراہم کرتا ہے۔


آپ Neo4j براؤزر میں تیار کردہ گراف کا معائنہ کر سکتے ہیں۔


تیار کردہ گراف کا حصہ۔


نوٹ کریں کہ یہ تصویر تیار کردہ گراف کے صرف ایک حصے کی نمائندگی کرتی ہے۔


RAG کے لیے ہائبرڈ بازیافت

گراف جنریشن کے بعد، ہم ایک ہائبرڈ بازیافت کا طریقہ استعمال کریں گے جو RAG ایپلی کیشنز کے لیے گراف کی بازیافت کے ساتھ ویکٹر اور کلیدی الفاظ کے اشاریہ جات کو یکجا کرتا ہے۔


ہائبرڈ (ویکٹر + کلیدی لفظ) اور گراف کی بازیافت کے طریقوں کو یکجا کرنا۔ تصویر بذریعہ مصنف۔


خاکہ بازیافت کے عمل کی وضاحت کرتا ہے جس کا آغاز ایک صارف کے سوال کے ساتھ ہوتا ہے، جسے پھر RAG بازیافت کرنے والے کو بھیج دیا جاتا ہے۔ یہ ریٹریور غیر ساختہ ٹیکسٹ ڈیٹا کے ذریعے تلاش کرنے کے لیے کلیدی الفاظ اور ویکٹر کی تلاش کا استعمال کرتا ہے اور اسے معلومات کے گراف سے جمع کردہ معلومات کے ساتھ جوڑتا ہے۔ چونکہ Neo4j میں کلیدی الفاظ اور ویکٹر انڈیکس دونوں شامل ہیں، اس لیے آپ ایک ہی ڈیٹا بیس سسٹم کے ساتھ بازیافت کے تینوں اختیارات کو نافذ کر سکتے ہیں۔ ان ذرائع سے جمع کردہ ڈیٹا کو حتمی جواب تیار کرنے اور فراہم کرنے کے لیے LLM میں فیڈ کیا جاتا ہے۔

غیر ساختہ ڈیٹا ریٹریور

آپ دستاویزات میں مطلوبہ الفاظ اور ویکٹر کی بازیافت دونوں کو شامل کرنے کے لیے Neo4jVector.from_existing_graph طریقہ استعمال کر سکتے ہیں۔ یہ طریقہ مطلوبہ الفاظ اور ویکٹر کی تلاش کے اشاریہ جات کو ہائبرڈ تلاش کے نقطہ نظر کے لیے ترتیب دیتا ہے، دستاویز کے لیبل والے نوڈس کو نشانہ بناتا ہے۔ مزید برآں، یہ ٹیکسٹ ایمبیڈنگ اقدار کا حساب لگاتا ہے اگر وہ غائب ہیں۔


 vector_index = Neo4jVector.from_existing_graph( OpenAIEmbeddings(), search_type="hybrid", node_label="Document", text_node_properties=["text"], embedding_node_property="embedding" )


اس کے بعد ویکٹر انڈیکس کو مماثلت_تلاش کے طریقہ سے بلایا جا سکتا ہے۔

گراف ریٹریور

دوسری طرف، گراف کی بازیافت کو ترتیب دینا زیادہ شامل ہے لیکن زیادہ آزادی فراہم کرتا ہے۔ یہ مثال متعلقہ نوڈس کی شناخت کرنے اور ان کے براہ راست پڑوس کو واپس کرنے کے لیے ایک مکمل ٹیکسٹ انڈیکس کا استعمال کرے گی۔


گراف بازیافت کرنے والا۔ تصویر بذریعہ مصنف۔



گراف کی بازیافت ان پٹ میں متعلقہ اداروں کی شناخت سے شروع ہوتی ہے۔ سادگی کے لیے، ہم LLM کو لوگوں، تنظیموں اور مقامات کی شناخت کرنے کی ہدایت کرتے ہیں۔ اسے حاصل کرنے کے لیے، ہم اسے حاصل کرنے کے لیے نئے شامل کیے گئے with_structured_output طریقہ کے ساتھ LCEL استعمال کریں گے۔


 # Extract entities from text class Entities(BaseModel): """Identifying information about entities.""" names: List[str] = Field( ..., description="All the person, organization, or business entities that " "appear in the text", ) prompt = ChatPromptTemplate.from_messages( [ ( "system", "You are extracting organization and person entities from the text.", ), ( "human", "Use the given format to extract information from the following " "input: {question}", ), ] ) entity_chain = prompt | llm.with_structured_output(Entities)


آئیے اس کی جانچ کریں:


 entity_chain.invoke({"question": "Where was Amelia Earhart born?"}).names # ['Amelia Earhart']


بہت اچھا، اب جب کہ ہم سوال میں موجود ہستیوں کا پتہ لگا سکتے ہیں، آئیے علمی گراف پر نقشہ بنانے کے لیے ایک مکمل متن کا انڈیکس استعمال کریں۔ سب سے پہلے، ہمیں ایک مکمل ٹیکسٹ انڈیکس اور ایک فنکشن کی وضاحت کرنے کی ضرورت ہے جو مکمل متن کے سوالات پیدا کرے گا جو تھوڑا سا غلط ہجے کی اجازت دیتا ہے، جس کی ہم یہاں زیادہ تفصیل میں نہیں جائیں گے۔


 graph.query( "CREATE FULLTEXT INDEX entity IF NOT EXISTS FOR (e:__Entity__) ON EACH [e.id]") def generate_full_text_query(input: str) -> str: """ Generate a full-text search query for a given input string. This function constructs a query string suitable for a full-text search. It processes the input string by splitting it into words and appending a similarity threshold (~2 changed characters) to each word, then combines them using the AND operator. Useful for mapping entities from user questions to database values, and allows for some misspelings. """ full_text_query = "" words = [el for el in remove_lucene_chars(input).split() if el] for word in words[:-1]: full_text_query += f" {word}~2 AND" full_text_query += f" {words[-1]}~2" return full_text_query.strip()



آئیے اب یہ سب ایک ساتھ رکھیں۔


 # Fulltext index query def structured_retriever(question: str) -> str: """ Collects the neighborhood of entities mentioned in the question """ result = "" entities = entity_chain.invoke({"question": question}) for entity in entities.names: response = graph.query( """CALL db.index.fulltext.queryNodes('entity', $query, {limit:2}) YIELD node,score CALL { MATCH (node)-[r:!MENTIONS]->(neighbor) RETURN node.id + ' - ' + type(r) + ' -> ' + neighbor.id AS output UNION MATCH (node)<-[r:!MENTIONS]-(neighbor) RETURN neighbor.id + ' - ' + type(r) + ' -> ' + node.id AS output } RETURN output LIMIT 50 """, {"query": generate_full_text_query(entity)}, ) result += "\n".join([el['output'] for el in response]) return result



اسٹرکچرڈ_ریٹریور فنکشن صارف کے سوال میں موجود اداروں کا پتہ لگانے سے شروع ہوتا ہے۔ اگلا، یہ پتہ چلنے والے اداروں پر اعادہ کرتا ہے اور متعلقہ نوڈس کے پڑوس کو بازیافت کرنے کے لیے سائفر ٹیمپلیٹ کا استعمال کرتا ہے۔ آئیے اس کی جانچ کریں!


 print(structured_retriever("Who is Elizabeth I?")) # Elizabeth I - BORN_ON -> 7 September 1533 # Elizabeth I - DIED_ON -> 24 March 1603 # Elizabeth I - TITLE_HELD_FROM -> Queen Of England And Ireland # Elizabeth I - TITLE_HELD_UNTIL -> 17 November 1558 # Elizabeth I - MEMBER_OF -> House Of Tudor # Elizabeth I - CHILD_OF -> Henry Viii # and more...


حتمی بازیافت کرنے والا

جیسا کہ شروع میں ذکر کیا گیا ہے، ہم ایل ایل ایم کو دیے گئے حتمی سیاق و سباق کو تخلیق کرنے کے لیے غیر ساختہ اور گراف بازیافت کو یکجا کریں گے۔


 def retriever(question: str): print(f"Search query: {question}") structured_data = structured_retriever(question) unstructured_data = [el.page_content for el in vector_index.similarity_search(question)] final_data = f"""Structured data: {structured_data} Unstructured data: {"#Document ". join(unstructured_data)} """ return final_data


جیسا کہ ہم Python کے ساتھ کام کر رہے ہیں، ہم صرف f-string کا استعمال کرتے ہوئے آؤٹ پٹ کو جوڑ سکتے ہیں۔

آر اے جی چین کی وضاحت کرنا

ہم نے RAG کے بازیافت جزو کو کامیابی کے ساتھ نافذ کیا ہے۔ اگلا، ہم ایک پرامپٹ متعارف کراتے ہیں جو RAG چین کے نفاذ کو مکمل کرتے ہوئے، ردعمل پیدا کرنے کے لیے مربوط ہائبرڈ ریٹریور کے فراہم کردہ سیاق و سباق کا فائدہ اٹھاتا ہے۔


 template = """Answer the question based only on the following context: {context} Question: {question} """ prompt = ChatPromptTemplate.from_template(template) chain = ( RunnableParallel( { "context": _search_query | retriever, "question": RunnablePassthrough(), } ) | prompt | llm | StrOutputParser() )


آخر میں، ہم آگے بڑھ سکتے ہیں اور اپنے ہائبرڈ RAG کے نفاذ کی جانچ کر سکتے ہیں۔


 chain.invoke({"question": "Which house did Elizabeth I belong to?"}) # Search query: Which house did Elizabeth I belong to? # 'Elizabeth I belonged to the House of Tudor.'


میں نے ایک سوال کو دوبارہ لکھنے کی خصوصیت بھی شامل کی ہے، جس سے RAG چین کو بات چیت کی ترتیبات کے مطابق ڈھالنے کے قابل بنایا گیا ہے جو فالو اپ سوالات کی اجازت دیتی ہیں۔ یہ دیکھتے ہوئے کہ ہم ویکٹر اور مطلوبہ الفاظ کی تلاش کے طریقے استعمال کرتے ہیں، ہمیں اپنے تلاش کے عمل کو بہتر بنانے کے لیے فالو اپ سوالات کو دوبارہ لکھنا چاہیے۔


 chain.invoke( { "question": "When was she born?", "chat_history": [("Which house did Elizabeth I belong to?", "House Of Tudor")], } ) # Search query: When was Elizabeth I born? # 'Elizabeth I was born on 7 September 1533.'


آپ دیکھ سکتے ہیں کہ وہ کب پیدا ہوئی؟ پہلی بار دوبارہ لکھا گیا الزبتھ I کب پیدا ہوئی؟ . پھر سے لکھی گئی استفسار کو متعلقہ سیاق و سباق کی بازیافت اور سوال کا جواب دینے کے لیے استعمال کیا گیا۔

علم کے گراف کو آسان بنا دیا گیا ہے۔

LLMGraphTransformer کے متعارف ہونے کے ساتھ، نالج گرافس تیار کرنے کا عمل اب ہموار اور زیادہ قابل رسائی ہونا چاہیے، جس سے ہر اس شخص کے لیے آسان ہو جائے گا جو اپنی RAG ایپلی کیشنز کو اس گہرائی اور سیاق و سباق کے ساتھ بڑھانا چاہتے ہیں جو علمی گراف فراہم کرتے ہیں۔ یہ صرف ایک آغاز ہے کیونکہ ہمارے پاس بہت ساری بہتری کی منصوبہ بندی ہے۔


اگر آپ کے پاس LLMs کے ساتھ ہمارے تخلیق کرنے والے گراف کے بارے میں بصیرت، تجاویز یا سوالات ہیں، تو براہ کرم رابطہ کرنے میں ہچکچاہٹ محسوس نہ کریں۔


کوڈ پر دستیاب ہے۔ گٹ ہب .