Ako vytvoriť jednoduchého chatbota, ktorý funguje pomocou RAG metódy

Veľké jazykové modely (LLMs) priniesli do oblasti automatizácie a umelej inteligencie revolúciu. Napriek tomu však stále narážame na niekoľko ich nedostatkov, medzi ktoré patria:

  • „Odtrhnutie“ od určitého časového bodu – modely nemajú k dispozícii najnovšie dáta
  • (Vo väčšine prípadov) malé vstupné okno – obmedzené množstvo textu, ktoré môžeme vložiť do promptu
  • Halucinácia – LLM si vymýšľa nepravdivé informácie

Niektoré z týchto slabín dokážeme zmierniť (alebo úplne odstrániť) technikou opísanou nižšie.

RAG

RAG je skratka pre Retrieval Augmented Generation. Proces si môžeme predstaviť takto:

  • Vytvoríme dataset informácií a uložíme ho vo forme vektorov.
  • Získame dopyt od používateľa.
  • Dopyt zakódujeme do vektora a vyhľadáme významovo najbližšie informácie v datasete.
  • Nájdené textové pasáže (v datasete máme uložené vektory aj pôvodný text) vložíme do promptu.
  • Na základe rozšíreného promptu nám model vygeneruje odpoveď.

Prostredie a požiadavky

Na vytvorenie jednoduchého RAG chatbota budeme potrebovať:

  • LLM – vhodný je model s nízkym počtom parametrov; na testovanie odporúčam lokálny model spustený cez Ollamu (v príklade používam phi4-mini).
  • Model na tvorbu embeddingov – vytvorí vektory zachytávajúce význam slov; niekedy možno použiť ten istý LLM, ak podporuje generovanie embeddingov.
  • Python, package manager a nasledovné knižnice:
    • chromadb
    • langchain
    • langchain-community
    • ollama
    • pypdf

Tvorba chatbota

Začneme ukladaním vektorov a textu. Na to používame vektorové databázy. Medzi vhodné patrí napríklad:

Pre jednoduchosť som vybral ChromaDB – má otvorený zdrojový kód, stačí pridať knižnicu a je embedded (nie je potrebné inštalovať externú službu, údaje sa ukladajú priamo na disk).

Všetky knižnice nainštalujeme pomocou pip:

pip install ollama chromadb langchain langchain-community pypdf

Potom sa môžeme pustiť do kódu. Ako zdroj dát použijeme voľne dostupnú knihu Think Python 2 vo formáte PDF. Najprv z PDF vyťažíme text a rozdelíme ho na menšie „kúsky“.

import ollama
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
import chromadb

pdf_path = "thinkpython2.pdf"
loader = PyPDFLoader(pdf_path)
pages = loader.load()

splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=64
)
docs = splitter.split_documents(pages)
texts = [doc.page_content for doc in docs]

Všimnite si, že sme použili knižnicu LangChain. Hoci primárne slúži na prácu s LLM, tu sme z nej využili len utilitu na rozbitie textu na menšie časti. Rozdeľujeme na úseky po 512 znakov s prekrytím 64 znakov z predchádzajúcej časti.

Ďalej vytvoríme vektorové embeddingy a uložíme ich do databázy.

# 2. Create embeddings using ollama
def get_ollama_embeddings(texts, model="phi4-mini:latest"):
    embeddings = []
    for i, text in enumerate(texts):
        response = ollama.embeddings(model=model, prompt=text)
        embeddings.append(response["embedding"])
        print(f"Processed {i + 1}/{len(texts)}: {text[:30]}...")  # Print first 30 chars of each text
    return embeddings

embeddings = get_ollama_embeddings(texts)

# 3. Store in ChromaDB
chroma_client = chromadb.Client(database='chroma.db')
collection = chroma_client.get_or_create_collection("ragdb")

# Add documents and embeddings to Chroma, if not already present
if collection.count() == 0:
    ids = [f"doc_{i}" for i in range(len(texts))]
    embeddings = get_ollama_embeddings(texts)
    collection.add(
        documents=texts,
        embeddings=embeddings,
        ids=ids
    )
    chroma_client.persist()

Keďže vytváranie embeddingov môže byť na bežnom hardvéri zdĺhavé, najprv skontrolujeme, či sa v ChromaDB už nenachádzajú. Ak áno, nevytvárame ich znova.

Na záver pridáme jednoduchý cyklus, ktorý zabezpečí komunikáciu s chatbotom.

print("RAG Chatbot (type 'exit' to quit)")
while True:
    query = input("\nYou: ")
    if query.lower() in ["exit", "quit"]:
        break

    # Embed the query using ollama
    query_emb = ollama.embeddings(model="phi4-mini:latest", prompt=query)["embedding"]

    # Retrieve top 3 relevant docs from Chroma
    results = collection.query(
        query_embeddings=[query_emb],
        n_results=3,
        include=["documents"]
    )
    if not results["documents"] or not results["documents"][0]:
        print("\nBot: I don't know.")
        continue

    context = "\n\n".join(results["documents"][0])

    # Build prompt
    prompt = (
        "You are a helpful assistant. Only answer using the information from the provided context below. "
        "If the answer is not in the context, respond with exactly: 'I don't know.'\n\n"
        "Context:\n"
        f"{context}\n\n"
        f"Question: {query}\nAnswer:"
    )

    print(f"\nContext used:\n{context}")

    # Generate response using ollama
    response = ollama.generate(model="phi4-mini:latest", prompt=prompt)
    print(f"\nBot: {response['response'].strip()}")

Chatbot najprv vyhľadá v databáze najrelevantnejšie pasáže a vloží ich do promptu. Kontekst sa zároveň vypíše do konzoly, aby sme videli, z čoho model čerpá. Ak ani jedna z troch najbližších časti textu neobsahuje požadovanú informáciu, chatbot odpovie presne „I don’t know.“

Vďaka technike Retrieval Augmented Generation sme prepojili silu veľkého jazykového modelu s aktuálnymi a presnými dátami uloženými vo vektorovej databáze. Tým sme:

  • rozšírili znalostný rozsah modelu o obsah, ktorý pôvodne nepoznal,
  • znížili riziko halucinácií, keďže odpovede musia vychádzať z konkrétneho kontextu,
  • obmedzili veľkosť promptu na prijateľné hodnoty, pretože doň vkladáme len niekoľko najrelevantnejších pasáží namiesto celého korpusu.

Ak chcete projekt rozvíjať ďalej, môžete skúsiť:

  • pridať viacero zdrojov (PDF, webové stránky, databázové záznamy) a kombinovať ich v jednej kolekcii,
  • experimentovať s rôznymi modelmi na embeddingy a sledovať, ako sa mení kvalita odpovedí,
  • implementovať pokročilejšie rebríčkovanie výsledkov (napr. pomocou dot-produktov či MMR),
  • dodať užívateľské rozhranie (web, Slack bot, Telegram bot),
  • zapracovať spätnú väzbu používateľov a priebežne obohacovať databázu o nové dokumenty.
  • Takýmto spôsobom dokážete vybudovať robustný systém, ktorý kombinuje presnosť vyhľadávania.

Komentáre

Pridaj komentár