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.

Pridaj komentár
Prepáčte, ale pred zanechaním komentára sa musíte prihlásiť.