Графикалык издөө-көбөйтүлгөн муун ( GraphRAG ) күч алып, салттуу вектордук издөө издөө ыкмаларына күчтүү кошумча болуп баратат. Бул ыкма алынган маалыматтын тереңдигин жана контексттүүлүгүн жогорулатуу үчүн маалыматтарды түйүндөр жана мамилелер катары уюштурган графикалык маалымат базаларынын структураланган табиятын колдонот.
Графиктер гетерогендүү жана бири-бири менен байланышкан маалыматты структуралаштырылган түрдө көрсөтүүдө жана сактоодо, ар кандай маалымат түрлөрү боюнча татаал мамилелерди жана атрибуттарды оңой эле тартууда сонун. Ал эми, вектордук маалымат базалары көбүнчө структураланган маалымат менен күрөшүшөт, анткени алардын күчү структураланбаган маалыматтарды жогорку өлчөмдүү векторлор аркылуу иштетүүдө. RAG тиркемеңизде эки дүйнөнүн эң жакшысына жетүү үчүн структураланган график маалыматтарын структураланбаган текст аркылуу вектордук издөө менен айкалыштыра аласыз. Муну биз бул блог постунда көрсөтөбүз.
Билим графигин түзүү, адатта, эң татаал кадам болуп саналат. Ал маалыматтарды чогултууну жана структуралаштырууну камтыйт, бул доменди жана графикти моделдештирүү боюнча терең түшүнүктү талап кылат.
Бул процессти жөнөкөйлөтүү үчүн биз LLM менен эксперимент жүргүзүп жатабыз. Тилди жана контекстти терең түшүнүү менен LLMs билим графигин түзүү процессинин маанилүү бөлүктөрүн автоматташтыра алат. Тексттик маалыматтарды талдоо менен, бул моделдер объекттерди аныктай алат, алардын өз ара мамилелерин түшүнөт жана аларды графикалык структурада кантип эң жакшы чагылдырууну сунуштай алат.
Бул эксперименттердин натыйжасында биз LangChainге график куруу модулунун биринчи версиясын коштук, аны бул блог постунда көрсөтөбүз.
Код GitHub сайтында жеткиликтүү.
Neo4j инстанциясын орнотушуңуз керек. Бул блог постундагы мисалдар менен бирге жүрүңүз. Эң оңой жолу - Neo4j маалымат базасынын булут инстанцияларын сунуш кылган Neo4j Auraда акысыз нусканы баштоо. Же болбосо, Neo4j Desktop тиркемесин жүктөп алып, жергиликтүү маалымат базасынын инстанциясын түзүү менен 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 ачкычын беришиңиз керек, анткени биз бул блог постунда алардын моделдерин колдонобуз.
Бул демонстрация үчүн Элизабет Iнин Wikipedia баракчасын колдонобуз. Биз 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 параметри кошумча дайындайт
Сиз Neo4j Браузеринде түзүлгөн графикти текшере аласыз.
Бул сүрөт түзүлгөн графиктин бир бөлүгүн гана билдирерин эске алыңыз.
График түзүлгөндөн кийин, биз 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ге адамдарды, уюмдарды жана жерлерди аныктоону тапшырабыз. Буга жетүү үчүн биз LCELди жаңы кошулган with_structured_output ыкмасы менен колдонобуз.
# 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
structured_retriever функциясы колдонуучунун суроосунда объекттерди аныктоо менен башталат. Андан кийин, ал табылган объекттерди кайталайт жана тиешелүү түйүндөрдүн айланасын алуу үчүн Cypher үлгүсүн колдонот. Келгиле, аны сынап көрөлү!
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...
Башында айтылгандай, биз LLMге өткөн акыркы контекстти түзүү үчүн структураланбаган жана графикалык ретриверди бириктиребиз.
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-сапты колдонуп жыйынтыктарды бириктире алабыз.
Биз РАГдын издөө компонентин ийгиликтүү ишке ашырдык. Андан кийин, биз 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 тиркемелерин өркүндөтүүнү каалагандар үчүн жеңилдетет. Бул башталышы гана, анткени бизде көптөгөн жакшыртуулар пландаштырылган.
LLMлер менен графиктерди түзүү боюнча түшүнүктөрүңүз, сунуштарыңыз же суроолоруңуз болсо, тартынбаңыз.
Код жеткиликтүү