মূল নথি (HTML, PDF, Markdown, ইত্যাদি) থেকে পাঠ্য বের করা।
নথির কাঠামো এবং শব্দার্থবিদ্যার উপর ভিত্তি করে পাঠ্যকে নির্দিষ্ট আকারে ভাগ করা।
একটি ভেক্টর ডাটাবেসে খণ্ডগুলিকে সঞ্চয় করা খণ্ডের একটি এমবেডিং দ্বারা চাবি করা।
উত্তর তৈরি করার সময় একটি প্রসঙ্গ হিসাবে ব্যবহারের জন্য একটি প্রশ্নের সাথে প্রাসঙ্গিক অংশগুলি পুনরুদ্ধার করা।
যাইহোক, ভেক্টর সাদৃশ্যের উপর ভিত্তি করে RAG এর কিছু দুর্বলতা রয়েছে। যেহেতু এটি প্রশ্নের অনুরূপ তথ্যের উপর ফোকাস করে, তাই একাধিক বিষয় এবং/অথবা একাধিক হপস-এর প্রয়োজন এমন প্রশ্নের উত্তর দেওয়া কঠিন। উপরন্তু, এটি পুনরুদ্ধার করা অংশের সংখ্যা সীমিত করে।
প্রতিটি খণ্ড একটি স্বতন্ত্র উৎস থেকে আসে, তাই যেখানে একাধিক জায়গায় একই ধরনের তথ্য বিদ্যমান থাকে, সেক্ষেত্রে তথ্যের একাধিক কপি পুনরুদ্ধার করা (এবং সম্ভবত অন্যান্য তথ্য হারিয়ে যাওয়া) বা আরও কিছু পাওয়ার জন্য শুধুমাত্র একটি কপি বেছে নেওয়ার প্রয়োজন হয়। বিভিন্ন খণ্ড, যা পরে অন্যান্য উত্সের সূক্ষ্মতা মিস করে।
সাদৃশ্য-ভিত্তিক পদ্ধতির তুলনায় এই পদ্ধতির বেশ কয়েকটি সুবিধা রয়েছে:
অনেক তথ্য একক উত্স থেকে বের করা যেতে পারে এবং জ্ঞান গ্রাফের মধ্যে বিভিন্ন সত্তার সাথে যুক্ত হতে পারে। এটি অপ্রাসঙ্গিক তথ্য সহ সমগ্র অংশের পরিবর্তে একটি প্রদত্ত উত্স থেকে প্রাসঙ্গিক তথ্য পুনরুদ্ধারের অনুমতি দেয়।
যদি একাধিক উত্স একই জিনিস বলে তবে তারা একই নোড বা প্রান্ত তৈরি করে। এগুলিকে স্বতন্ত্র তথ্য হিসাবে বিবেচনা করার পরিবর্তে (এবং একাধিক অনুলিপি পুনরুদ্ধার করা), এগুলিকে একই নোড বা প্রান্ত হিসাবে বিবেচনা করা যেতে পারে এবং শুধুমাত্র একবার পুনরুদ্ধার করা যেতে পারে। এটি বিভিন্ন ধরণের তথ্য পুনরুদ্ধার করতে সক্ষম করে এবং/অথবা শুধুমাত্র একাধিক সূত্রে প্রদর্শিত তথ্যের উপর ফোকাস করে।
গ্রাফটি একাধিক ধাপের মধ্য দিয়ে অতিক্রম করা যেতে পারে - শুধুমাত্র প্রশ্নে থাকা সত্তার সাথে সরাসরি সম্পর্কিত তথ্য পুনরুদ্ধার করা নয়, 2 বা 3 ধাপ দূরে থাকা জিনিসগুলিকেও ফিরিয়ে আনা। একটি প্রচলিত RAG পদ্ধতিতে, এর জন্য একাধিক রাউন্ড ক্যোয়ারী করতে হবে।
RAG-এর জন্য নলেজ গ্রাফ ব্যবহার করার সুবিধার পাশাপাশি, এলএলএমগুলি জ্ঞানের গ্রাফ তৈরি করাও সহজ করেছে। জ্ঞানের গ্রাফটি যত্ন সহকারে তৈরি করার জন্য বিষয় বিশেষজ্ঞদের প্রয়োজনের পরিবর্তে, নথি থেকে তথ্য বের করতে একটি LLM এবং একটি প্রম্পট ব্যবহার করা যেতে পারে।
এই পোস্টটি ব্যবহার করে, RAG-এর জন্য জ্ঞান গ্রাফের ব্যবহার অন্বেষণ করে
তারপরে আমরা প্রশ্ন থেকে সত্তা বের করার জন্য এবং প্রাসঙ্গিক সাব-গ্রাফগুলি পুনরুদ্ধার করার জন্য LangChain runnables তৈরি করব। আমরা দেখব যে জ্ঞান গ্রাফ ব্যবহার করে RAG বাস্তবায়নের জন্য প্রয়োজনীয় ক্রিয়াকলাপগুলির জন্য গ্রাফ ডেটাবেস বা গ্রাফ ক্যোয়ারী ভাষার প্রয়োজন হয় না, আপনি ইতিমধ্যে ব্যবহার করছেন এমন একটি সাধারণ ডেটা স্টোর ব্যবহার করে পদ্ধতিটি প্রয়োগ করার অনুমতি দেয়।
পূর্বে উল্লিখিত হিসাবে, একটি জ্ঞান গ্রাফ নোড হিসাবে স্বতন্ত্র সত্তা প্রতিনিধিত্ব করে। উদাহরণস্বরূপ, একটি নোড "মারি কুরি" ব্যক্তিকে বা "ফরাসি" ভাষাকে প্রতিনিধিত্ব করতে পারে। LangChain-এ, প্রতিটি নোডের একটি নাম এবং একটি প্রকার রয়েছে। একটি নোডকে স্বতন্ত্রভাবে চিহ্নিত করার সময় আমরা উভয়ই বিবেচনা করব, "ফরাসি" ভাষাকে "ফরাসি" জাতীয়তা থেকে আলাদা করতে।
সত্তাগুলির মধ্যে সম্পর্কগুলি গ্রাফের প্রান্তগুলির সাথে মিলে যায়৷ প্রতিটি প্রান্তে উৎস অন্তর্ভুক্ত থাকে (উদাহরণস্বরূপ, ম্যারি কুরি ব্যক্তি), লক্ষ্য (নোবেল পুরস্কার পুরস্কার), এবং একটি প্রকার, যেটি নির্দেশ করে কিভাবে উৎসটি লক্ষ্যের সাথে সম্পর্কিত (উদাহরণস্বরূপ, "জয়")।
ল্যাংচেইন ব্যবহার করে মেরি কুরি সম্পর্কে একটি অনুচ্ছেদ থেকে নেওয়া একটি উদাহরণ জ্ঞান গ্রাফ নীচে দেখানো হয়েছে:
আপনার লক্ষ্যগুলির উপর নির্ভর করে, আপনি নোড এবং প্রান্তগুলিতে বৈশিষ্ট্য যুক্ত করতে বেছে নিতে পারেন। উদাহরণস্বরূপ, আপনি কখন নোবেল পুরস্কার জিতেছিলেন এবং বিভাগটি সনাক্ত করতে একটি সম্পত্তি ব্যবহার করতে পারেন। পুনরুদ্ধারের সময় গ্রাফটি অতিক্রম করার সময় প্রান্ত এবং নোডগুলি ফিল্টার করতে এগুলি কার্যকর হতে পারে।
জ্ঞান গ্রাফ সমন্বিত সত্তা এবং সম্পর্কগুলি বিদ্যমান পরিচিত-ভাল ডেটা উত্স থেকে সরাসরি তৈরি বা আমদানি করা যেতে পারে। আপনি যখন জ্ঞানটি যত্ন সহকারে কিউরেট করতে চান তখন এটি দরকারী, তবে এটি নতুন তথ্য দ্রুত অন্তর্ভুক্ত করা বা প্রচুর পরিমাণে তথ্য পরিচালনা করা কঠিন করে তোলে।
সৌভাগ্যবশত, LLMগুলি বিষয়বস্তু থেকে তথ্য বের করা সহজ করে, তাই আমরা জ্ঞানের গ্রাফ বের করার জন্য সেগুলি ব্যবহার করতে পারি।
নীচে, আমি ব্যবহার
ল্যাংচেইন অন্যান্য বিকল্পগুলিকে সমর্থন করে যেমন
from langchain_experimental.graph_transformers import LLMGraphTransformer from langchain_openai import ChatOpenAI from langchain_core.documents import Document # Prompt used by LLMGraphTransformer is tuned for Gpt4. llm = ChatOpenAI(temperature=0, model_name="gpt-4") llm_transformer = LLMGraphTransformer(llm=llm) text = """ Marie Curie, was a Polish and naturalised-French physicist and chemist who conducted pioneering research on radioactivity. She was the first woman to win a Nobel Prize, the first person to win a Nobel Prize twice, and the only person to win a Nobel Prize in two scientific fields. Her husband, Pierre Curie, was a co-winner of her first Nobel Prize, making them the first-ever married couple to win the Nobel Prize and launching the Curie family legacy of five Nobel Prizes. She was, in 1906, the first woman to become a professor at the University of Paris. """ documents = [Document(page_content=text)] graph_documents = llm_transformer.convert_to_graph_documents(documents) print(f"Nodes:{graph_documents[0].nodes}") print(f"Relationships:{graph_documents[0].relationships}")
এটি দেখায় কিভাবে LangChain এর LLMGraphTransformer
ব্যবহার করে একটি জ্ঞান গ্রাফ বের করতে হয়। আপনি চাক্ষুষ পরিদর্শনের জন্য একটি LangChain GraphDocument
রেন্ডার করতে সংগ্রহস্থলে পাওয়া render_graph_document
ব্যবহার করতে পারেন।
ভবিষ্যতের পোস্টে, আমরা আলোচনা করব কিভাবে আপনি জ্ঞানের গ্রাফটিকে সম্পূর্ণরূপে পরীক্ষা করতে পারেন এবং সেইসাথে প্রতিটি নথি থেকে নেওয়া সাব-গ্রাফ এবং কীভাবে আপনি স্বয়ংক্রিয় নিষ্কাশনকে উন্নত করতে প্রম্পট ইঞ্জিনিয়ারিং এবং নলেজ ইঞ্জিনিয়ারিং প্রয়োগ করতে পারেন।
নলেজ গ্রাফ ব্যবহার করে প্রশ্নের উত্তর দেওয়ার জন্য বেশ কিছু ধাপ প্রয়োজন। আমরা প্রথমে শনাক্ত করি যে আমাদের জ্ঞান গ্রাফের ট্রাভার্সাল কোথা থেকে শুরু করতে হবে। এই উদাহরণের জন্য, আমি প্রশ্ন থেকে সত্তা বের করার জন্য একটি LLM-কে অনুরোধ করব। তারপর, সেই প্রারম্ভিক বিন্দুগুলির একটি নির্দিষ্ট দূরত্বের মধ্যে সমস্ত সম্পর্ক পুনরুদ্ধার করতে জ্ঞানের গ্রাফটি অতিক্রম করা হয়। ডিফল্ট ট্রাভার্সাল গভীরতা হল 3। পুনরুদ্ধার করা সম্পর্ক এবং আসল প্রশ্নটি এলএলএম-এর প্রশ্নের উত্তর দেওয়ার জন্য একটি প্রম্পট এবং প্রসঙ্গ তৈরি করতে ব্যবহৃত হয়।
জ্ঞান গ্রাফের নিষ্কাশনের মতো, একটি প্রশ্নে সত্তাগুলিকে নিষ্কাশন করা একটি বিশেষ মডেল বা একটি নির্দিষ্ট প্রম্পট সহ একটি এলএলএম ব্যবহার করে করা যেতে পারে। সরলতার জন্য, আমরা নিম্নলিখিত প্রম্পট সহ একটি LLM ব্যবহার করব যাতে এক্সট্রাক্ট করার ফর্ম্যাট সম্পর্কে প্রশ্ন এবং তথ্য উভয়ই অন্তর্ভুক্ত থাকে। সঠিক কাঠামো পেতে আমরা নাম এবং টাইপ সহ একটি পাইডান্টিক মডেল ব্যবহার করি।
QUERY_ENTITY_EXTRACT_PROMPT = ( "A question is provided below. Given the question, extract up to 5 " "entity names and types from the text. Focus on extracting the key entities " "that we can use to best lookup answers to the question. Avoid stopwords.\n" "---------------------\n" "{question}\n" "---------------------\n" "{format_instructions}\n" ) def extract_entities(llm): prompt = ChatPromptTemplate.from_messages([keyword_extraction_prompt]) class SimpleNode(BaseModel): """Represents a node in a graph with associated properties.""" id: str = Field(description="Name or human-readable unique identifier.") type: str = optional_enum_field(node_types, description="The type or label of the node.") class SimpleNodeList(BaseModel): """Represents a list of simple nodes.""" nodes: List[SimpleNode] output_parser = JsonOutputParser(pydantic_object=SimpleNodeList) return ( RunnablePassthrough.assign( format_instructions=lambda _: output_parser.get_format_instructions(), ) | ChatPromptTemplate.from_messages([QUERY_ENTITY_EXTRACT_PROMPT]) | llm | output_parser | RunnableLambda( lambda node_list: [(n["id"], n["type"]) for n in node_list["nodes"]]) )
উপরের উদাহরণটি চালালে আমরা দেখতে পাই যে সত্তাগুলি বের করা হয়েছে:
# Example showing extracted entities (nodes) extract_entities(llm).invoke({ "question": "Who is Marie Curie?"}) # Output: [Marie Curie(Person)]
অবশ্যই, একটি LangChain Runnable একটি প্রশ্ন থেকে সত্তা বের করতে একটি চেইনে ব্যবহার করা যেতে পারে।
ভবিষ্যতে, আমরা সত্তা নিষ্কাশন উন্নত করার উপায়গুলি নিয়ে আলোচনা করব, যেমন নোডের বৈশিষ্ট্যগুলি বিবেচনা করা বা ভেক্টর এমবেডিং ব্যবহার করা এবং প্রাসঙ্গিক প্রারম্ভিক পয়েন্টগুলি সনাক্ত করতে মিল অনুসন্ধান করা। এই প্রথম পোস্টটিকে সহজ রাখার জন্য, আমরা উপরের প্রম্পটের সাথে লেগে থাকব, এবং knowledge-subgraph
পুনরুদ্ধার করার জন্য নলেজ গ্রাফটি অতিক্রম করার দিকে অগ্রসর হব এবং প্রম্পটে প্রসঙ্গ হিসাবে এটি অন্তর্ভুক্ত করব।
পূর্ববর্তী চেইন আমাদের প্রশ্নে নোড দেয়। প্রাসঙ্গিক জ্ঞান ট্রিপল পুনরুদ্ধার করতে আমরা সেই সত্তা এবং গ্রাফ স্টোর ব্যবহার করতে পারি। RAG-এর মতো, আমরা সেগুলিকে প্রসঙ্গের অংশ হিসাবে প্রম্পটে ড্রপ করি এবং উত্তর তৈরি করি।
def _combine_relations(relations): return "\n".join(map(repr, relations)) ANSWER_PROMPT = ( "The original question is given below." "This question has been used to retrieve information from a knowledge graph." "The matching triples are shown below." "Use the information in the triples to answer the original question.\n\n" "Original Question: {question}\n\n" "Knowledge Graph Triples:\n{context}\n\n" "Response:" ) chain = ( { "question": RunnablePassthrough() } # extract_entities is provided by the Cassandra knowledge graph library # and extracts entitise as shown above. | RunnablePassthrough.assign(entities = extract_entities(llm)) | RunnablePassthrough.assign( # graph_store.as_runnable() is provided by the CassandraGraphStore # and takes one or more entities and retrieves the relevant sub-graph(s). triples = itemgetter("entities") | graph_store.as_runnable()) | RunnablePassthrough.assign( context = itemgetter("triples") | RunnableLambda(_combine_relations)) | ChatPromptTemplate.from_messages([ANSWER_PROMPT]) | llm )
উপরের চেইনটি একটি প্রশ্নের উত্তর দেওয়ার জন্য কার্যকর করা যেতে পারে। উদাহরণ স্বরূপ:
chain.invoke("Who is Marie Curie?") # Output AIMessage( content="Marie Curie is a Polish and French chemist, physicist, and professor who " "researched radioactivity. She was married to Pierre Curie and has worked at " "the University of Paris. She is also a recipient of the Nobel Prize.", response_metadata={ 'token_usage': {'completion_tokens': 47, 'prompt_tokens': 213, 'total_tokens': 260}, 'model_name': 'gpt-4', ... } )
যদিও জ্ঞানের গ্রাফ সঞ্চয় করার জন্য একটি গ্রাফ ডিবি ব্যবহার করা স্বজ্ঞাত মনে হতে পারে, এটি আসলে প্রয়োজনীয় নয়। কয়েকটি নোডের চারপাশে সাব-নলেজ গ্রাফ পুনরুদ্ধার করা একটি সাধারণ গ্রাফ ট্রাভার্সাল, যখন গ্রাফ ডিবিগুলি বৈশিষ্ট্যগুলির নির্দিষ্ট ক্রম সহ পাথগুলি অনুসন্ধান করার জন্য আরও জটিল প্রশ্নের জন্য ডিজাইন করা হয়েছে। আরও, ট্র্যাভার্সাল প্রায়শই কেবল 2 বা 3 এর গভীরতায় থাকে, যেহেতু নোডগুলি আরও দূরে সরানো হয় সেগুলি খুব দ্রুত প্রশ্নের সাথে অপ্রাসঙ্গিক হয়ে যায়। এটিকে কয়েকটি রাউন্ডের সাধারণ প্রশ্নের (প্রতিটি ধাপের জন্য একটি) বা একটি SQL যোগদান হিসাবে প্রকাশ করা যেতে পারে।
একটি পৃথক গ্রাফ ডাটাবেসের প্রয়োজনীয়তা দূর করা জ্ঞান গ্রাফ ব্যবহার করা সহজ করে তোলে। উপরন্তু, Astra DB বা Apache Cassandra ব্যবহার করে একই জায়গায় সংরক্ষিত গ্রাফ এবং অন্যান্য ডেটা উভয়ের জন্য লেনদেন সংক্রান্ত লেখা সহজ করে এবং সম্ভবত আরও ভালোভাবে স্কেল করা যায়। সেই ওভারহেডটি তখনই সার্থক হবে যদি আপনি গ্রেমলিন বা সাইফার বা অনুরূপ কিছু ব্যবহার করে গ্রাফ প্রশ্ন তৈরি এবং চালানোর পরিকল্পনা করেন।
কিন্তু এটি সাব-নলেজ গ্রাফ পুনরুদ্ধারের জন্য সহজভাবে ওভারকিল, এবং এটি অন্যান্য অনেক সমস্যার জন্য দরজা খুলে দেয়, যেমন কর্মক্ষমতার দিক থেকে রেইল বন্ধ হয়ে যাওয়া প্রশ্নগুলি।
এই ট্রাভার্সালটি পাইথনে প্রয়োগ করা সহজ। সিকিউএল এবং ক্যাসান্দ্রা ড্রাইভার ব্যবহার করে এটি (সিঙ্ক্রোনাস এবং অ্যাসিঙ্ক্রোনাস উভয়ভাবেই) বাস্তবায়নের সম্পূর্ণ কোড পাওয়া যাবে
def fetch_relation(tg: asyncio.TaskGroup, depth: int, source: Node) -> AsyncPagedQuery: paged_query = AsyncPagedQuery( depth, session.execute_async(query, (source.name, source.type)) ) return tg.create_task(paged_query.next()) results = set() async with asyncio.TaskGroup() as tg: if isinstance(start, Node): start = [start] discovered = {t: 0 for t in start} pending = {fetch_relation(tg, 1, source) for source in start} while pending: done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED) for future in done: depth, relations, more = future.result() for relation in relations: results.add(relation) # Schedule the future for more results from the same query. if more is not None: pending.add(tg.create_task(more.next())) # Schedule futures for the next step. if depth < steps: # We've found a path of length `depth` to each of the targets. # We need to update `discovered` to include the shortest path. # And build `to_visit` to be all of the targets for which this is # the new shortest path. to_visit = set() for r in relations: previous = discovered.get(r.target, steps + 1) if depth < previous: discovered[r.target] = depth to_visit.add(r.target) for source in to_visit: pending.add(fetch_relation(tg, depth + 1, source)) return results
এই নিবন্ধটি দেখিয়েছে কিভাবে জ্ঞানের গ্রাফ নিষ্কাশন এবং পুনরুদ্ধার প্রশ্ন উত্তরের জন্য তৈরি এবং ব্যবহার করতে হয়। মূল টেকঅ্যাওয়ে হল আজ এটি করার জন্য আপনার গ্রেমলিন বা সাইফারের মতো গ্রাফ ক্যোয়ারী ভাষা সহ একটি গ্রাফ ডাটাবেসের প্রয়োজন নেই। Astra এর মতো একটি দুর্দান্ত ডাটাবেস যা দক্ষতার সাথে সমান্তরালভাবে অনেকগুলি প্রশ্ন পরিচালনা করে তা ইতিমধ্যেই এটি পরিচালনা করতে পারে।
আসলে, আপনি একটি নির্দিষ্ট প্রশ্নের উত্তর দেওয়ার জন্য প্রয়োজনীয় সাব-নলেজ গ্রাফ পুনরুদ্ধার করতে প্রশ্নের একটি সাধারণ ক্রম লিখতে পারেন। এটি আপনার আর্কিটেকচারকে সহজ রাখে (কোনও যোগ নির্ভরতা নেই) এবং আপনাকে অনুমতি দেয়
আমরা Cassandra এবং Astra DB-এর জন্য GraphRAG প্যাটার্নগুলি বাস্তবায়ন করতে এই একই ধারণাগুলি ব্যবহার করেছি। আমরা তাদের LangChain-এ অবদান রাখতে যাচ্ছি এবং ভবিষ্যতে LLM-এর সাথে জ্ঞানের গ্রাফ ব্যবহারে অন্যান্য উন্নতি আনতে কাজ করব!
বেন চেম্বার্স, ডেটাস্ট্যাক্স দ্বারা