paint-brush
RAG Uygulamalarında Hassasiyetin Kilidini Açma: Neo4j ve LangChain ile Bilgi Grafiklerinden Yararlanmaile@neo4j
220 okumalar

RAG Uygulamalarında Hassasiyetin Kilidini Açma: Neo4j ve LangChain ile Bilgi Grafiklerinden Yararlanma

ile Neo4j9m2024/10/21
Read on Terminal Reader

Çok uzun; Okumak

Bu blog yazısı LangChain kullanarak bir bilgi grafiğinin nasıl oluşturulacağını gösteriyor. Kod GitHub'da mevcut. Bir Neo4j örneği ayarlamanız gerekiyor. Bu gösteri için [Elizabeth I'in] Wikipedia sayfasını kullanacağız. Belgeleri Wikipedia'dan almak ve bölmek için [LangChain yükleyicilerini] kullanabiliriz.
featured image - RAG Uygulamalarında Hassasiyetin Kilidini Açma: Neo4j ve LangChain ile Bilgi Grafiklerinden Yararlanma
Neo4j HackerNoon profile picture
0-item
1-item


Grafik alma-artırılmış üretim ( GraphRAG ) ivme kazanıyor ve geleneksel vektör arama alma yöntemlerine güçlü bir ek haline geliyor. Bu yaklaşım, alınan bilgilerin derinliğini ve bağlamsallığını artırmak için verileri düğümler ve ilişkiler olarak düzenleyen grafik veritabanlarının yapılandırılmış doğasından yararlanır.



Bilgi grafiğinin örneği.

Grafikler, heterojen ve birbirine bağlı bilgileri yapılandırılmış bir şekilde temsil etme ve depolamada harikadır, çeşitli veri türleri arasında karmaşık ilişkileri ve nitelikleri zahmetsizce yakalar. Buna karşılık, vektör veritabanları genellikle bu tür yapılandırılmış bilgilerle mücadele eder, çünkü güçleri yüksek boyutlu vektörler aracılığıyla yapılandırılmamış verileri işlemekte yatar. RAG uygulamanızda, yapılandırılmış grafik verilerini yapılandırılmamış metin aracılığıyla vektör aramasıyla birleştirerek her iki dünyanın da en iyisini elde edebilirsiniz. Bu blog yazısında göstereceğimiz şey budur.

Bilgi Grafikleri Harika, Peki Nasıl Oluşturulur?

Bir bilgi grafiği oluşturmak genellikle en zorlu adımdır. Verilerin toplanmasını ve yapılandırılmasını içerir ve bu da hem alan hem de grafik modellemesi hakkında derin bir anlayış gerektirir.


Bu süreci basitleştirmek için LLM'lerle deneyler yaptık. Dil ve bağlam konusunda derin anlayışları sayesinde LLM'ler, bilgi grafiği oluşturma sürecinin önemli kısımlarını otomatikleştirebilir. Bu modeller, metin verilerini analiz ederek varlıkları belirleyebilir, ilişkilerini anlayabilir ve bir grafik yapısında en iyi şekilde nasıl temsil edilebileceklerini önerebilir.


Bu deneyler sonucunda LangChain'e grafik inşa modülünün ilk versiyonunu ekledik; bunu bu blog yazısında göstereceğiz.


Kod GitHub'da mevcut.

Neo4j Ortam Kurulumu

Bir Neo4j örneği kurmanız gerekiyor. Bu blog yazısındaki örnekleri takip edin. En kolay yol, Neo4j veritabanının bulut örneklerini sunan Neo4j Aura'da ücretsiz bir örnek başlatmaktır. Alternatif olarak, Neo4j Masaüstü uygulamasını indirip yerel bir veritabanı örneği oluşturarak Neo4j veritabanının yerel bir örneğini de kurabilirsiniz.


 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()


Ayrıca bu blog yazısında onların modellerini kullanacağımız için bir OpenAI anahtarı da sağlamanız gerekiyor.

Veri Toplama

Bu gösteri için Elizabeth I'in Wikipedia sayfasını kullanacağız. Wikipedia'dan belgeleri sorunsuz bir şekilde almak ve bölmek için LangChain yükleyicilerini kullanabiliriz.


 # 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])


Alınan belgelere dayalı bir grafik oluşturmanın zamanı geldi. Bu amaçla, bir grafik veritabanında bir bilgi grafiği oluşturmayı ve depolamayı önemli ölçüde basitleştiren bir LLMGraphTransformermodule uyguladık.


 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 )


Bilgi grafiği oluşturma zincirinin hangi LLM'yi kullanmasını istediğinizi tanımlayabilirsiniz. Şu anda yalnızca OpenAI ve Mistral'dan gelen fonksiyon çağıran modelleri destekliyoruz. Ancak, gelecekte LLM seçimini genişletmeyi planlıyoruz. Bu örnekte, en son GPT-4'ü kullanıyoruz. Oluşturulan grafiğin kalitesinin kullandığınız modele önemli ölçüde bağlı olduğunu unutmayın. Teoride, her zaman en yetenekli olanı kullanmak istersiniz. LLM grafik dönüştürücüleri, add_graph_documents yöntemi aracılığıyla Neo4j'ye aktarılabilen grafik belgeleri döndürür. baseEntityLabel parametresi ek bir Varlık her düğüme etiket ekleyerek dizinleme ve sorgu performansını geliştirin. include_source parametresi düğümleri kaynak belgelerine bağlayarak veri izlenebilirliğini ve bağlam anlayışını kolaylaştırır.


Oluşturulan grafiği Neo4j Browser’da inceleyebilirsiniz.


Oluşturulan grafiğin bir parçası.


Bu görselin oluşturulan grafiğin sadece bir kısmını temsil ettiğini unutmayın.


RAG için Hibrit Geri Alma

Grafik oluşturma işleminden sonra, RAG uygulamaları için vektör ve anahtar kelime indekslerini grafik alma ile birleştiren hibrit alma yaklaşımını kullanacağız.


Hibrit (vektör + anahtar kelime) ve grafik alma yöntemlerinin birleştirilmesi. Yazarın görseli.


Diyagram, bir kullanıcının bir soru sormasıyla başlayan ve ardından bir RAG alıcısına yönlendirilen bir alma sürecini göstermektedir. Bu alıcı, yapılandırılmamış metin verilerini aramak için anahtar kelime ve vektör aramaları kullanır ve bunları bilgi grafiğinden topladığı bilgilerle birleştirir. Neo4j hem anahtar kelime hem de vektör dizinleri içerdiğinden, üç alma seçeneğini de tek bir veritabanı sistemiyle uygulayabilirsiniz. Bu kaynaklardan toplanan veriler, nihai cevabı oluşturmak ve iletmek için bir LLM'ye beslenir.

Yapılandırılmamış Veri Alıcısı

Belgelere hem anahtar sözcük hem de vektör alma eklemek için Neo4jVector.from_existing_graph yöntemini kullanabilirsiniz. Bu yöntem, Belge etiketli düğümleri hedef alarak karma arama yaklaşımı için anahtar sözcük ve vektör arama dizinlerini yapılandırır. Ayrıca, eksikse metin yerleştirme değerlerini hesaplar.


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


Daha sonra vektör indeksi similarity_search metodu ile çağrılabilir.

Grafik Alıcısı

Öte yandan, bir grafik alma yapılandırması daha karmaşıktır ancak daha fazla özgürlük sunar. Bu örnek, ilgili düğümleri tanımlamak ve doğrudan komşuluklarını döndürmek için tam metin dizini kullanacaktır.


Grafik alıcısı. Yazarın resmi.



Grafik alıcısı girdideki ilgili varlıkları tanımlayarak başlar. Basitleştirmek için, LLM'ye insanları, kuruluşları ve konumları tanımlamasını talimat veriyoruz. Bunu başarmak için, bunu başarmak için yeni eklenen with_structured_output yöntemiyle LCEL'i kullanacağız.


 # 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)


Hadi deneyelim:


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


Harika, artık sorudaki varlıkları tespit edebildiğimize göre, bunları bilgi grafiğine eşlemek için tam metin dizini kullanalım. Öncelikle, burada çok fazla ayrıntıya girmeyeceğimiz, biraz yazım yanlışına izin veren tam metin sorguları üretecek bir tam metin dizini ve bir fonksiyon tanımlamamız gerekiyor.


 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()



Şimdi hepsini bir araya getirelim.


 # 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



structured_retriever fonksiyonu kullanıcı sorusundaki varlıkları tespit ederek başlar. Sonra, tespit edilen varlıklar üzerinde yineleme yapar ve ilgili düğümlerin mahallesini almak için bir Cypher şablonu kullanır. Hadi deneyelim!


 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...


Son kurtarıcı

Başta da belirttiğimiz gibi, LLM'ye aktarılacak son bağlamı oluşturmak için yapılandırılmamış ve grafik alıcılarını birleştireceğiz.


 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 ile çalıştığımız için çıktıları f-stringini kullanarak kolayca birleştirebiliriz.

RAG Zincirini Tanımlamak

RAG'ın geri alma bileşenini başarıyla uyguladık. Sonra, entegre hibrit geri alma aracının sağladığı bağlamdan yararlanarak yanıtı üreten ve RAG zincirinin uygulanmasını tamamlayan bir istem sunuyoruz.


 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() )


Son olarak hibrit RAG uygulamamızı test etmeye başlayabiliriz.


 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.'


Ayrıca, RAG zincirinin takip sorularına izin veren konuşma ayarlarına uyum sağlamasını sağlayan bir sorgu yeniden yazma özelliği de ekledim. Vektör ve anahtar kelime arama yöntemlerini kullandığımızı göz önünde bulundurarak, arama sürecimizi optimize etmek için takip sorularını yeniden yazmalıyız.


 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.'


When was she born? ifadesinin ilk olarak When was Elizabeth I born? şeklinde yeniden yazıldığını görebilirsiniz. Yeniden yazılan sorgu daha sonra ilgili bağlamı almak ve soruyu cevaplamak için kullanıldı.

Bilgi Grafikleri Kolaylaştırıldı

LLMGraphTransformer'ın tanıtımıyla, bilgi grafikleri üretme süreci artık daha akıcı ve daha erişilebilir olmalı ve bu da RAG uygulamalarını bilgi grafiklerinin sağladığı derinlik ve bağlamla geliştirmek isteyen herkes için daha kolay hale getirmelidir. Planladığımız birçok iyileştirme olduğu için bu sadece bir başlangıçtır.


LLM'lerle grafik oluşturma konusunda görüşleriniz, önerileriniz veya sorularınız varsa lütfen bize ulaşmaktan çekinmeyin.


Kod şu adreste mevcuttur: GitHub .