aidoc.uz

2-qism · Agentlar va bilim izlash·07-bob

Bilim grafikasi va GraphRAG

Ma'lumotni bog'langan tarmoq sifatida saqlash. LLM bilan graf qurish, Neo4j va Cypher, GraphRAG va graf ustida fikrlash — ishlaydigan kod bilan.

Ikki bob davomida RAG bilan ishladik. Uning butun mantiqi bitta g'oyaga tayanadi: matnni bo'laklarga bo'lib, vektorga aylantirish.

Lekin bir savol turi bor, unga vektor RAG hech qachon yaxshi javob bera olmaydi:

"A dori B kasallikni C oqsil orqali qanday davolaydi?"

Bu savolga javob berish uchun bir necha faktni zanjirga ulash kerak. Vektor qidiruvi bo'lak topadi, lekin bo'laklar orasidagi bog'lanishni ko'rmaydi.

Talaba tashbehi#

Kitobni o'qib, hamma joyini bo'yab chiqqan odamni ko'rgansiz. Natija ma'lum:

Hamma narsani chizib chiqish — hech narsani chizmaslik bilan barobar.

Yaxshi talaba boshqacha qiladi — sxema chizadi. Asosiy tushunchalar va ular orasidagi bog'lanishlar. Ixcham, aniq, ortiqchasiz.

Mana shu sxema — bu graf. Va agar unda haqiqiy dunyo ob'ektlari va ular orasidagi ma'noli munosabatlar bo'lsa — bu bilim grafikasi.

Uchlik — grafning atomi#

Bilim grafikasidagi har bir fakt uchlik (triplet) shaklida saqlanadi:

(bosh, munosabat, quyruq)
(Napoleon, tug'ilgan, Ayachcho)
(aspirin, davolaydi, bosh_og'rig'i)
(Anvar, ishlaydi, Mediline)
JADVAL
ism | shahar | kasb Anvar | Toshkent | shifokor
→ uchliklar
(Anvar, yashaydi, Toshkent) (Anvar, kasbi, shifokor)
GRAF
tugunlar bog'langan tarmoq
Jadval va graf — bir xil ma'lumotning ikki ko'rinishi

Grafning uch afzalligi:

1
Bo'sh katak muammosi yo'q
Jadvalda ma'lumot bo'lmasa NULL qoladi. Grafda esa shunchaki qirra chizilmaydi. Turli xil ob'ektlar turli xususiyatlarga ega bo'lishi mumkin.
2
Birlashtirish oson
Ikki jadvalni birlashtirish azob — qaysi ustunni qaysi ustunga, dublikatlar nima bo'ladi. Ikki grafni birlashtirish — uchliklarni bir joyga qo'yish, xolos.
3
Har qanday ma'lumot mos keladi
JSON, XML, CSV, daraxt, ijtimoiy tarmoq — hammasi grafga tushadi. Rekursiv va tsiklik tuzilmalarni ham tabiiy ifodalaydi.

Ontologiya: qoidalar qatlami#

Oddiy graf va bilim grafikasining farqi shundaki, ikkinchisida ma'no oshkor yozilgan — shuning uchun undan xulosa chiqarish mumkin.

Ontologiya — bu grafga qoidalar qo'shadi: munosabat tranzitivmi, simmetrikmi, qanday xususiyatlar bor.


Grafni LLM bilan qurish#

Graf qurishning eng qiyin qismi — matndan ob'ektlar va munosabatlarni ajratib olish. Ilgari bu qo'lda yorliqlangan ma'lumot va oylab ish talab qilar edi. LLM buni tubdan o'zgartirdi.

Ikki vazifa#

"Anvar Toshkentdagi Mediline klinikasida ishlaydi"
xom matn
NER — ob'ektlarni topish
Anvar [ODAM], Toshkent [SHAHAR], Mediline [TASHKILOT]
RE — munosabatlarni topish
(Anvar)-[ISHLAYDI]→(Mediline)-[JOYLASHGAN]→(Toshkent)
NER va RE: matndan grafga

LLM bilan uchlik chiqarish#

import anthropic
import json
 
client = anthropic.Anthropic()
 
 
def uchliklarni_chiqar(matn: str) -> list[dict]:
    """Matndan (bosh, munosabat, quyruq) uchliklarini ajratadi."""
    prompt = f"""Quyidagi matndan bilim grafikasi uchun uchliklar ajrating.
 
Har bir uchlik: bosh ob'ekt, munosabat, quyruq ob'ekt.
Odamning kasbini, joyni, tashkilotni alohida ob'ekt sifatida ajrating.
Faqat matnda AYTILGAN faktlarni oling — to'qib chiqarmang.
 
Natijani QAT'IY quyidagi JSON formatida bering:
[
  {{"bosh": "...", "munosabat": "...", "quyruq": "...",
    "bosh_turi": "ODAM|SHAHAR|TASHKILOT|KASB|...",
    "quyruq_turi": "..."}}
]
 
Matn:
{matn}"""
 
    javob = client.messages.create(
        model="claude-opus-5",
        max_tokens=2048,
        messages=[{"role": "user", "content": prompt}],
    )
 
    matn_javob = "".join(b.text for b in javob.content if b.type == "text")
 
    # JSON qismini ajratib olamiz
    boshi = matn_javob.find("[")
    oxiri = matn_javob.rfind("]") + 1
    return json.loads(matn_javob[boshi:oxiri])
 
 
matn = """Salvatore Raieli — italyan olimi. U sun'iy intellekt bo'yicha
tadqiqotchi va Milanda ishlaydi. U mashina o'rganish sohasida mutaxassis."""
 
for u in uchliklarni_chiqar(matn):
    print(f"({u['bosh']}) --[{u['munosabat']}]--> ({u['quyruq']})")
(Salvatore Raieli) --[millati]--> (italyan)
(Salvatore Raieli) --[kasbi]--> (tadqiqotchi)
(Salvatore Raieli) --[ishlaydi]--> (Milan)
(Salvatore Raieli) --[mutaxassislik]--> (mashina o'rganish)

Ma'no noaniqligini hal qilish#

LLM'ning kuchli tomoni — kontekstni tushunishi:

# "Apple" — meva, kompaniya yoki xonanda (Fiona Apple)?
matnlar = [
    "Apple yangi iPhone chiqardi",           # kompaniya
    "Har kuni bitta apple yeyish foydali",   # meva
]
 
for m in matnlar:
    uchliklar = uchliklarni_chiqar(m)
    print(m, "", uchliklar)
# Model kontekstdan to'g'ri turni aniqlaydi

Neo4j va Cypher#

Grafni saqlash uchun graf bazasi kerak. Neo4j — eng mashhuri.

  1. Neo4j'ni ishga tushirish

    Eng oson yo'l — Docker:

    terminal
    docker run -d --name neo4j -p 7474:7474 -p 7687:7687 -e NEO4J_AUTH=neo4j/parol123 neo4j:5

    Brauzerda http://localhost:7474 ochilib, grafni ko'rish mumkin.

  2. Python'dan ulanish

    terminal
    pip install neo4j
    from neo4j import GraphDatabase
     
    driver = GraphDatabase.driver(
        "bolt://localhost:7687",
        auth=("neo4j", "parol123"),
    )
     
     
    def uchlikni_yoz(tx, bosh, munosabat, quyruq):
        """MERGE — agar tugun bor bo'lsa qayta yaratmaydi."""
        tx.run(
            """
            MERGE (b:Obyekt {nom: $bosh})
            MERGE (q:Obyekt {nom: $quyruq})
            MERGE (b)-[:BOGLANGAN {turi: $munosabat}]->(q)
            """,
            bosh=bosh, munosabat=munosabat, quyruq=quyruq,
        )
     
     
    with driver.session() as session:
        for u in uchliklarni_chiqar(matn):
            session.execute_write(
                uchlikni_yoz, u["bosh"], u["munosabat"], u["quyruq"]
            )
  3. Cypher bilan so'rov

    Cypher — Neo4j'ning so'rov tili. U grafdagi naqshlarni izlaydi:

    def qidir(tx, nom):
        """Berilgan ob'ekt bilan bog'liq hamma narsani topadi."""
        natija = tx.run(
            """
            MATCH (b:Obyekt {nom: $nom})-[r:BOGLANGAN]->(q:Obyekt)
            RETURN b.nom AS bosh, r.turi AS munosabat, q.nom AS quyruq
            """,
            nom=nom,
        )
        return [dict(qator) for qator in natija]
     
     
    with driver.session() as session:
        for f in session.execute_read(qidir, "Salvatore Raieli"):
            print(f"{f['bosh']} --[{f['munosabat']}]--> {f['quyruq']}")

    Cypher sintaksisi vizual — () tugun, -[]-> yo'naltirilgan qirra. So'rov aslida grafning rasmi kabi o'qiladi.

LLM'ni Cypher generatoriga aylantirish#

Eng chiroyli qismi: foydalanuvchi o'zbekcha so'raydi, LLM uni Cypherga aylantiradi.

def tabiiy_sorov(savol: str, sxema: str) -> str:
    """Tabiiy tilni Cypher so'roviga aylantiradi."""
    prompt = f"""Sen Neo4j Cypher mutaxassisisan.
 
Graf sxemasi:
{sxema}
 
Quyidagi savol uchun Cypher so'rovini yoz.
Faqat so'rovni qaytar, izohsiz.
 
Savol: {savol}"""
 
    javob = client.messages.create(
        model="claude-opus-5",
        max_tokens=512,
        messages=[{"role": "user", "content": prompt}],
    )
    return "".join(b.text for b in javob.content if b.type == "text").strip()
 
 
sxema = "(:Obyekt {nom})-[:BOGLANGAN {turi}]->(:Obyekt {nom})"
cypher = tabiiy_sorov("Milanda kim ishlaydi?", sxema)
print(cypher)
# MATCH (p:Obyekt)-[:BOGLANGAN {turi: 'ishlaydi'}]->(:Obyekt {nom: 'Milan'})
# RETURN p.nom

LangChain buni tayyor beradi:

from langchain_neo4j import Neo4jGraph, GraphCypherQAChain
from langchain_anthropic import ChatAnthropic
 
graph = Neo4jGraph(url="bolt://localhost:7687", username="neo4j", password="parol123")
llm = ChatAnthropic(model="claude-opus-5")
 
chain = GraphCypherQAChain.from_llm(llm, graph=graph, verbose=True, allow_dangerous_requests=False)
natija = chain.invoke({"query": "Milanda kim ishlaydi?"})
print(natija["result"])

allow_dangerous_requests=False — yuqoridagi xavfsizlik muammosini hal qiladi.


GraphRAG#

Endi grafni LLM bilan bog'laymiz. Tuzilma vektor RAG bilan bir xil, faqat baza o'rnida graf.

G-indexing
grafni qurish va indekslash
G-retrieval
so'rovga mos QISM GRAFNI topish
G-generation
topilgan bilimni LLM'ga berib javob yozdirish
GraphRAG: uch bosqich

Granularlik — nimani olib kelamiz#

Vektor RAG'da granularlikni bo'lak o'lchami boshqaradi. GraphRAG'da bu yerda nimani olishni tanlaysiz:

DarajaNima olinadiQachon
TugunFaqat ob'ekt va xususiyatlari"Aspirin nima?"
UchlikOb'ekt + munosabat"Aspirin nimani davolaydi?"
Yo'lX dan Y gacha butun zanjir"Bu ikki kasallik qanday bog'liq?"
Qism grafTugunlar va munosabatlar to'plamiMurakkab tahlil
def yol_topish(tx, boshlanish, tugash, maks_uzunlik=4):
    """Ikki ob'ekt orasidagi eng qisqa yo'lni topadi."""
    natija = tx.run(
        """
        MATCH yol = shortestPath(
            (a:Obyekt {nom: $boshlanish})-[*..%d]-(b:Obyekt {nom: $tugash})
        )
        RETURN [tugun IN nodes(yol) | tugun.nom] AS zanjir
        """ % maks_uzunlik,
        boshlanish=boshlanish, tugash=tugash,
    )
    qator = natija.single()
    return qator["zanjir"] if qator else None
 
 
# "Aspirin bilan yurak xuruji qanday bog'liq?"
zanjir = yol_topish(session, "aspirin", "yurak_xuruji")
# ['aspirin', 'qon_suyultirish', 'tromboz', 'yurak_xuruji']

Vektor RAG bu zanjirni hech qachon topa olmasdi — chunki hech bir bo'lakda to'rttala tushuncha birga yozilmagan bo'lishi mumkin. Graf esa ularni bog'lab beradi.

Vektor RAG yoki GraphRAG?#

Bu yo yoki yo savoli emas.

GraphRAG kuchli
  • Bog'lanishlar va ko'p qadamli mantiq: «A → B → C qanday bog'liq?»
  • Xulosa chiqarish: ontologiya qoidalari bilan yangi fakt
  • Aniq ob'ektlar orasidagi munosabatlar
  • Ma'lumot manbasini aniq kuzatish
Vektor RAG kuchli
  • Erkin matn ichidan parcha topish: «bu haqda nima yozilgan?»
  • Qurish arzon — hujjatni tashlaysiz va tayyor
  • Yangilash oson — yangi hujjat qo'shasiz
  • Ontologiya, NER, RE bilan shug'ullanish shart emas

Ko'p real tizimlarda IKKALASI birga ishlaydi — router har bir so'rovni qayerga yuborishni hal qiladi. Oddiy fakt savollari vektor RAG'ga, bog'lanish savollari GraphRAG'ga.


Graf ustida fikrlash#

Grafning eng katta qiymati — undan yangi bilim chiqarish mumkinligi.

(Anvar, eri, Dilnoza)  ∧  (Anvar, otasi, Sardor)
                       ↓
(Dilnoza, onasi, Sardor)     ← hech kim yozmagan, mantiq chiqardi

TransE — grafni vektorga#

Graf embeddingi grafni past o'lchamli vektor fazosiga joylashtiradi. TransE — eng sodda va eng chiroyli g'oya:

bosh + munosabat ≈ quyruq

Birinchi bobdagi podshoh − erkak + ayol ≈ malika ni eslaysizmi? Aynan o'sha g'oya, faqat so'zlar emas, faktlar ustida.

import numpy as np
 
 
def transe_bashorat(bosh_vek, munosabat_vek, hamma_obyektlar):
    """bosh + munosabat ga eng yaqin ob'ektni topadi."""
    maqsad = bosh_vek + munosabat_vek
 
    masofalar = {
        nom: np.linalg.norm(maqsad - vek)
        for nom, vek in hamma_obyektlar.items()
    }
    return sorted(masofalar.items(), key=lambda x: x[1])[:3]
 
 
# (Napoleon + tug'ilgan) ≈ ? → Ayachcho
natija = transe_bashorat(
    obyektlar["Napoleon"], munosabatlar["tug'ilgan"], obyektlar
)

Bu yetishmayotgan bog'lanishlarni bashorat qilish (link prediction) imkonini beradi — grafda yozilmagan, lekin mantiqan mavjud bo'lgan faktlarni.

GNN — graf neyron tarmoqlari#

Klassik neyron tarmoq to'rtburchak ma'lumot kutadi. Graf esa to'rtburchak emas.

GNNning asosiy mexanizmi — xabar uzatish (message passing):

boshlang'ich: har tugunda o'z vektori
1-qadam: qo'shnilardan ma'lumot yig'iladi
har tugun bevosita qo'shnilarini biladi
2-qadam: yana yig'iladi
endi qo'shnining qo'shnisini ham biladi
natija: har tugun butun mahallasini o'zida saqlaydi
Message passing: har tugun qo'shnilaridan ma'lumot yig'adi

Bir necha qadamdan keyin har bir tugun nafaqat o'zi, balki atrofidagi butun mahalla haqidagi ma'lumotni o'zida saqlaydi. Bu tugun tasnifi, bog'lanish bashorati kabi vazifalar uchun ishlatiladi.


Amaliyot: hujjatdan grafgacha#

To'liq quvur — matndan so'rab bo'ladigan grafgacha.

class GrafRAG:
    def __init__(self, neo4j_driver, client):
        self.driver = neo4j_driver
        self.client = client
 
    def hujjatni_qosh(self, matn: str):
        """Matndan uchliklar chiqarib grafga yozadi."""
        uchliklar = uchliklarni_chiqar(matn)     # yuqoridagi funksiya
 
        with self.driver.session() as s:
            for u in uchliklar:
                s.execute_write(
                    uchlikni_yoz, u["bosh"], u["munosabat"], u["quyruq"]
                )
        return len(uchliklar)
 
    def sora(self, savol: str) -> str:
        """Tabiiy tilda so'raydi."""
        # 1. Savolni Cypher'ga aylantiramiz
        cypher = tabiiy_sorov(savol, self.sxema())
 
        # 2. Xavfsizlik tekshiruvi
        if any(t in cypher.upper() for t in ["DELETE", "CREATE", "SET", "REMOVE"]):
            return "Faqat o'qish so'rovlariga ruxsat"
 
        # 3. Grafda bajaramiz
        with self.driver.session() as s:
            natijalar = [dict(q) for q in s.run(cypher)]
 
        if not natijalar:
            return "Grafda javob topilmadi"
 
        # 4. Natijani tabiiy tilga o'giramiz
        javob = self.client.messages.create(
            model="claude-opus-5",
            max_tokens=1024,
            messages=[{
                "role": "user",
                "content": f"Savol: {savol}\n\nGraf natijasi: {natijalar}\n\n"
                           f"Shu ma'lumotga tayanib tabiiy tilda javob bering.",
            }],
        )
        return "".join(b.text for b in javob.content if b.type == "text")
 
    def sxema(self):
        return "(:Obyekt {nom})-[:BOGLANGAN {turi}]->(:Obyekt {nom})"
Amaliy topshiriq

Kichik bilim grafikasi quring

Neo4j'ni ishga tushiring va kichik bilim grafikasi quring.

  1. 5-10 ta paragraf matn oling (Vikipediya, kompaniya hujjati — nima bo'lsa ham)
  2. Har biridan LLM bilan uchliklar chiqaring
  3. Neo4j'ga yozing va brauzerda grafni ko'ring — ob'ektlar bir-biriga qanday bog'langanini vizual ko'rish juda foydali
  4. Tabiiy tilda 5 ta savol bering

Keyin solishtiring:

  • Bir xil matndan vektor RAG ham quring (5-bobdagi kod bilan)
  • Ikkala tizimga "X va Y qanday bog'liq?" turidagi savol bering
  • Qaysi biri yaxshiroq javob berdi? Nima uchun?
Maslahatni ko'rsatish

Ma'lumot manbalari: - O'zingizga tanish sohaning Vikipediya maqolalari - Kompaniya xodimlari va bo'limlari haqidagi hujjat - Kitob personajlari va ular orasidagi munosabatlar Neo4j Docker bilan ishga tushiring, keyin: 1. 5-10 ta paragraf oling 2. Har biridan uchliklar chiqaring (haiku bilan, arzon) 3. Neo4j'ga yozing 4. Brauzerda (localhost:7474) grafni KO'RING — bu eng qiziqarli qism 5. Tabiiy tilda 5 ta savol bering Vektor RAG bilan solishtirish uchun: - Bir xil matndan vektor RAG ham quring - 'X va Y qanday bog'liq?' turidagi savol bering - Qaysi biri yaxshiroq javob berdi? Graf vizualizatsiyasi Cypher: MATCH (n)-[r]->(m) RETURN n,r,m LIMIT 50


Ochiq muammolar#

Bilim grafikalari kuchli, lekin muammosiz emas:

  • Qurish qimmat — vektor RAG'da hujjatni tashlaysiz va tayyor. Graf uchun ontologiya, NER, RE, tozalash kerak
  • To'liq emas — har doim yetishmayotgan bog'lanishlar bo'ladi
  • Yangilash murakkab — yangi fakt kelganda uni butun grafga moslash kerak
  • Baholash standarti yo'q — grafning "yaxshi"ligini o'lchash hali ochiq masala

Xulosa#

Vektor RAG
matn → bo'laklar → vektorlar
«nima yozilgan?»
GraphRAG
matn → uchliklar → graf
«nima nima bilan bog'liq?»
Vektor RAG va GraphRAG
Yodda saqlang
  • 01Graf — bog'lanishlar haqida. «X va Y qanday bog'liq?» turidagi savollar uchun grafsiz iloji yo'q. Oddiy faktlar uchun vektor RAG arzonroq va yetarli.
  • 02LLM graf qurishni arzonlashtirdi. Ilgari yorliqlangan ma'lumot va oylab ish kerak edi. Endi yaxshi yozilgan prompt yetadi.
  • 03LLM'ni Cypher generatoriga aylantiring — foydalanuvchi o'zbekcha so'raydi, model so'rov yozadi. Lekin yozuv operatsiyalarini albatta bloklang.
  • 04TransE — bosh + munosabat ≈ quyruq. Birinchi bobdagi so'z arifmetikasining o'zi, faqat faktlar ustida. Yetishmayotgan bog'lanishlarni bashorat qiladi.
  • 05Ikkalasi raqib emas. Ko'p real tizimlarda router bilan vektor RAG va GraphRAG birga ishlaydi.

Endi agent bilim topishni ham, uni tarmoq sifatida saqlashni ham biladi. Lekin keyingi bobda butunlay boshqa savol turadi: agent o'z tajribasidan o'rganishi mumkinmi?

Javob — mustahkamlovchi o'qitishda.