paint-brush
A RAG fejlesztése tudásgráfokkal: A Llama 3.1, az NVIDIA NIM és a LangChain integrálása a dinamikus AI-hozáltal@neo4j
Új történelem

A RAG fejlesztése tudásgráfokkal: A Llama 3.1, az NVIDIA NIM és a LangChain integrálása a dinamikus AI-hoz

által Neo4j9m2024/10/22
Read on Terminal Reader

Túl hosszú; Olvasni

Ez a cikk bemutatja a Llama 3.1, az NVIDIA NIM és a LangChain használatát tudásgráf-alapú ügynök létrehozására a lekérdezéssel kiegészített generáláshoz (RAG), kihasználva a strukturált adatokat és a dinamikus lekérdezések generálását az információ-visszakeresés és a válaszadás pontosságának javítása érdekében.
featured image - A RAG fejlesztése tudásgráfokkal: A Llama 3.1, az NVIDIA NIM és a LangChain integrálása a dinamikus AI-hoz
Neo4j HackerNoon profile picture
0-item
1-item



Míg a legtöbb ember a strukturálatlan szövegek, például a vállalati dokumentumok vagy dokumentációk helyett a visszakereséssel bővített generálásra (RAG) összpontosít, én eléggé hűvös vagyok a visszakereső rendszerekkel szemben a strukturált információkkal, különösen a tudásgrafikonokkal szemben. Nagy izgalom volt a GraphRAG, különösen a Microsoft implementációja kapcsán. Megvalósításukban azonban a bemeneti adat strukturálatlan szöveg, dokumentum formájában, amelyet egy nagy nyelvi modell (LLM) segítségével tudásgráfrá alakítanak át.


Ebben a blogbejegyzésben bemutatjuk, hogyan lehet retrievert megvalósítani egy tudásgrafikonon, amely az FDA Adverse Event Reporting System (FAERS) strukturált információit tartalmazza, és amely információkat nyújt a kábítószer-mellékhatásokról. Ha valaha is foglalkozott a tudásgráfokkal és a visszakereséssel, az első gondolata az lehet, hogy egy LLM segítségével adatbázislekérdezéseket generál, hogy egy adott kérdés megválaszolásához releváns információkat kérjen le egy tudásgráfról. Az adatbázis-lekérdezések létrehozása LLM-ekkel azonban még mindig fejlődik, és még nem biztos, hogy a legkonzisztensebb vagy legrobusztusabb megoldást kínálja. Tehát mik az életképes alternatívák jelenleg?


Véleményem szerint a jelenlegi legjobb megoldás a dinamikus lekérdezésgenerálás. Ahelyett, hogy teljes egészében egy LLM-re támaszkodna a teljes lekérdezés generálására, ez a módszer egy logikai réteget alkalmaz, amely determinisztikusan generál egy adatbázis-lekérdezést előre meghatározott bemeneti paraméterekből. Ez a megoldás egy függvényhívás támogatással rendelkező LLM segítségével valósítható meg. A függvényhívási szolgáltatás használatának előnye abban rejlik, hogy egy LLM-nek meg lehet határozni, hogyan készítse elő a függvény strukturált bemenetét. Ez a megközelítés biztosítja, hogy a lekérdezésgenerálási folyamat ellenőrizhető és konzisztens legyen, miközben lehetővé teszi a felhasználói beviteli rugalmasságot.


Dinamikus lekérdezésgenerálási folyamat —Kép a szerzőtől


A kép azt a folyamatot szemlélteti, amely során megértik a felhasználó kérdését, hogy konkrét információkat nyerjenek ki. Az áramlás három fő lépésből áll:


  1. Egy felhasználó kérdést tesz fel a Lyrica gyógyszer gyakori mellékhatásairól 35 év alattiaknál.


  2. Az LLM dönti el, hogy melyik függvényt hívja meg, és a szükséges paramétereket. Ebben a példában a mellékhatások nevű függvényt választotta olyan paraméterekkel, mint a Lyrica gyógyszer és a maximális életkor 35 év.


  3. Az azonosított függvény és paraméterek egy adatbázis-lekérdezés (Cypher) utasítás determinisztikus és dinamikus generálására szolgálnak a releváns információk lekéréséhez.


A funkcióhívás-támogatás létfontosságú a fejlett LLM-használati esetekben, például lehetővé teszi az LLM-ek számára, hogy több visszakeresőt használjanak a felhasználói szándék alapján, vagy több ügynököt tartalmazó folyamatokat építsenek ki. Írtam néhány cikket kereskedelmi LLM-ek használatával, natív funkcióhívási támogatással. Azonban a nemrég kiadott Llama-3.1-et fogjuk használni, amely egy kiváló nyílt forráskódú LLM natív függvényhívási támogatással.


A kód elérhető a GitHubon .

A Tudásgráf beállítása

A Neo4j-t, amely egy natív gráf adatbázis, fogjuk használni a nemkívánatos események információinak tárolására. Ezt a linket követve beállíthat egy ingyenes felhő Sandbox projektet, amely előre feltöltött FAERS-szel érkezik.


A példányosított adatbázispéldánynak van egy gráfja a következő sémával.


A nemkívánatos események diagramjának sémája  – „A szerző képe


A séma középpontjában a Case csomópont áll, amely összekapcsolja a gyógyszerbiztonsági jelentés különböző aspektusait, beleértve az érintett gyógyszereket, a tapasztalt reakciókat, az eredményeket és az előírt terápiákat. Mindegyik gyógyszert az jellemzi, hogy elsődleges, másodlagos, kísérő vagy kölcsönhatásban lévő gyógyszer. Az esetek a gyártóra, a beteg korcsoportjára és a jelentés forrására vonatkozó információkhoz is kapcsolódnak. Ez a séma lehetővé teszi a kábítószerek közötti kapcsolatok, reakcióik és kimenetelek strukturált nyomon követését és elemzését.


Kezdjük azzal, hogy kapcsolatot hozunk létre az adatbázissal egy Neo4jGraph objektum példányosításával:


 os.environ["NEO4J_URI"] = "bolt://18.206.157.187:7687" os.environ["NEO4J_USERNAME"] = "neo4j" os.environ["NEO4J_PASSWORD"] = "elevation-reservist-thousands" graph = Neo4jGraph(refresh_schema=False)


Az LLM-környezet beállítása

Számos lehetőség kínálkozik a nyílt forráskódú LLM-ek, például a Llama-3.1 fogadására. Az NVIDIA API katalógusát fogjuk használni, amely NVIDIA NIM következtetési mikroszolgáltatásokat biztosít, és támogatja a Llama 3.1 modellek függvényhívását. Amikor létrehozol egy fiókot, 1000 tokent kapsz, ami több mint elég a követéshez. Létre kell hoznia egy API-kulcsot, és át kell másolnia a jegyzetfüzetbe:


 os.environ["NVIDIA_API_KEY"] = "nvapi-" llm = ChatNVIDIA(model="meta/llama-3.1-70b-instruct")


A láma-3.1–70b-t fogjuk használni, mert a 8b verziónak van némi akadozása az opcionális paraméterekkel a függvénydefiníciókban.


Az NVIDIA NIM mikroszolgáltatásokban az a szép, hogy ha biztonsági vagy egyéb aggályai vannak, könnyedén tárolhatja őket helyben , így könnyen cserélhető, és csak egy URL-paramétert kell hozzáadnia az LLM-konfigurációhoz:


 # connect to an local NIM running at localhost:8000, # specifying a specific model llm = ChatNVIDIA( base_url="http://localhost:8000/v1", model="meta/llama-3.1-70b-instruct" )

Eszköz meghatározása

Egyetlen eszközt konfigurálunk négy választható paraméterrel. Ezeken a paramétereken alapuló megfelelő Cypher utasítást készítünk, hogy lekérjük a tudásgráfból a releváns információkat. Eszközünk képes lesz azonosítani a leggyakoribb mellékhatásokat a bevitt gyógyszer, az életkor és a gyógyszergyártó alapján.


 @tool def get_side_effects( drug: Optional[str] = Field( description="disease mentioned in the question. Return None if no mentioned." ), min_age: Optional[int] = Field( description="Minimum age of the patient. Return None if no mentioned." ), max_age: Optional[int] = Field( description="Maximum age of the patient. Return None if no mentioned." ), manufacturer: Optional[str] = Field( description="manufacturer of the drug. Return None if no mentioned." ), ): """Useful for when you need to find common side effects.""" params = {} filters = [] side_effects_base_query = """ MATCH (c:Case)-[:HAS_REACTION]->(r:Reaction), (c)-[:IS_PRIMARY_SUSPECT]->(d:Drug) """ if drug and isinstance(drug, str): candidate_drugs = [el["candidate"] for el in get_candidates(drug, "drug")] if not candidate_drugs: return "The mentioned drug was not found" filters.append("d.name IN $drugs") params["drugs"] = candidate_drugs if min_age and isinstance(min_age, int): filters.append("c.age > $min_age ") params["min_age"] = min_age if max_age and isinstance(max_age, int): filters.append("c.age < $max_age ") params["max_age"] = max_age if manufacturer and isinstance(manufacturer, str): candidate_manufacturers = [ el["candidate"] for el in get_candidates(manufacturer, "manufacturer") ] if not candidate_manufacturers: return "The mentioned manufacturer was not found" filters.append( "EXISTS {(c)<-[:REGISTERED]-(:Manufacturer {manufacturerName: $manufacturer})}" ) params["manufacturer"] = candidate_manufacturers[0] if filters: side_effects_base_query += " WHERE " side_effects_base_query += " AND ".join(filters) side_effects_base_query += """ RETURN d.name AS drug, r.description AS side_effect, count(*) AS count ORDER BY count DESC LIMIT 10 """ print(f"Using parameters: {params}") data = graph.query(side_effects_base_query, params=params) return data


A get_side_effectsfüggvény arra szolgál, hogy meghatározott keresési feltételek segítségével lekérje a gyógyszerek gyakori mellékhatásait egy tudásgráfról. Elfogadja a gyógyszernév, a beteg korosztálya és a gyógyszergyártó opcionális paramétereit a keresés testreszabásához. Minden paraméterhez tartozik egy leírás, amelyet az LLM-nek továbbítanak a függvényleírással együtt, lehetővé téve az LLM számára, hogy megértse a használatukat. A függvény ezután létrehoz egy dinamikus Cypher-lekérdezést a megadott bemenetek alapján, végrehajtja ezt a lekérdezést a tudásgráfon, és visszaadja az eredményül kapott mellékhatásadatokat.


Teszteljük a függvényt:


 get_side_effects("lyrica") # Using parameters: {'drugs': ['LYRICA', 'LYRICA CR']} # [{'drug': 'LYRICA', 'side_effect': 'Pain', 'count': 32}, # {'drug': 'LYRICA', 'side_effect': 'Fall', 'count': 21}, # {'drug': 'LYRICA', 'side_effect': 'Intentional product use issue', 'count': 20}, # {'drug': 'LYRICA', 'side_effect': 'Insomnia', 'count': 19}, # ...


Eszközünk először leképezte a kérdésben említett Lyrica gyógyszert a „['LYRICA', 'LYRICA CR']” értékekre a tudásgráfban, majd végrehajtott egy megfelelő Cypher utasítást, hogy megtalálja a leggyakoribb mellékhatásokat.

Grafikon alapú LLM-ügynök

Már csak egy LLM-ügynök konfigurálása maradt hátra, amely a meghatározott eszköz segítségével válaszolhat a gyógyszer mellékhatásaira vonatkozó kérdésekre.


Ügynöki adatfolyam — Szerző által készített kép


A kép egy felhasználót ábrázol, aki interakcióba lép egy Llama 3.1 ügynökkel, hogy érdeklődjön a gyógyszer mellékhatásairól. Az ügynök hozzáfér egy mellékhatás-eszközhöz, amely információkat kér le egy tudásgráfról, hogy a felhasználó rendelkezésére álljon a releváns adatoknak.


Kezdjük a prompt sablon meghatározásával:


 prompt = ChatPromptTemplate.from_messages( [ ( "system", "You are a helpful assistant that finds information about common side effects. " "If tools require follow up questions, " "make sure to ask the user for clarification. Make sure to include any " "available options that need to be clarified in the follow up questions " "Do only the things the user specifically requested. ", ), MessagesPlaceholder(variable_name="chat_history"), ("user", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ] )


A prompt sablon tartalmazza a rendszerüzenetet, az opcionális csevegési előzményeket és a felhasználói bevitelt. Az agent_scratchpad az LLM számára van fenntartva, mivel néha több lépésre van szüksége a kérdés megválaszolásához, például végrehajtani és lekérni az információkat az eszközökből.


A LangChain könyvtár egyszerűvé teszi az eszközök hozzáadását az LLM-hez a bind_tools metódussal:


 tools = [get_side_effects] llm_with_tools = llm.bind_tools(tools=tools) agent = ( { "input": lambda x: x["input"], "chat_history": lambda x: _format_chat_history(x["chat_history"]) if x.get("chat_history") else [], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] ), } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser() ) agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True).with_types( input_type=AgentInput, output_type=Output )


Az ügynök átalakításokon és kezelőkön keresztül dolgozza fel a bemenetet, amelyek formázzák a csevegési előzményeket, alkalmazzák az LLM-et a kötött eszközökkel, és elemzik a kimenetet. Végül az ügynök egy végrehajtóval van beállítva, amely kezeli a végrehajtási folyamatot, meghatározza a bemeneti és kimeneti típusokat, és tartalmazza a részletes naplózási beállításokat a végrehajtás során.


Teszteljük az ügynököt:


 agent_executor.invoke( { "input": "What are the most common side effects when using lyrica for people below 35 years old?" } )


Eredmények:


Ügynök végrehajtása — A szerző képe


Az LLM megállapította, hogy a get_side_effects függvényt kell használnia megfelelő argumentumokkal. A függvény ezután dinamikusan generál egy Cypher utasítást, lekéri a vonatkozó információkat, és visszaküldi az LLM-nek a végső válasz generálásához.

Összegzés

A függvényhívási képességek hatékonyan kiegészítik az olyan nyílt forráskódú modelleket, mint a Llama 3.1, lehetővé téve a külső adatforrásokkal és eszközökkel való strukturáltabb és szabályozottabb interakciókat. A strukturálatlan dokumentumok lekérdezésén túl a gráfalapú ügynökök izgalmas lehetőségeket kínálnak a tudásgráfokkal és strukturált adatokkal való interakcióhoz. Az ilyen modellek egyszerű üzemeltetése olyan platformokon, mint az NVIDIA NIM mikroszolgáltatások, egyre könnyebben hozzáférhetővé teszi őket.


Mint mindig, a kód elérhető a GitHubon .


Ha többet szeretne megtudni erről a témáról, csatlakozzon hozzánk november 7-én a NODES 2024-en, amely az intelligens alkalmazásokról, tudásgrafikonokról és mesterséges intelligenciáról szóló ingyenes virtuális fejlesztői konferenciánk. Regisztráljon most!