Home SOFTWAREPraktični primeri RAG implementacije: Korak po korak sa Python i LangChain

Praktični primeri RAG implementacije: Korak po korak sa Python i LangChain

od itn
RAG implementacija primeri Python LangChain

Ako ste pročitali moj prethodni članak o brzom indeksiranju u eri RAG-a i AI-ja, verovatno ste se zapitali: „Dobro, ali kako to da uradim u praksi?“ E pa, evo detaljnijih primera implementacije Retrieval-Augmented Generation (RAG) sistema koristeći Python i LangChain – jedan od najpopularnijih okvira za to. Ovi primeri su inspirisani najnovijim tutorijalima iz 2025. godine, poput onih sa TO THE NEW Blog-a i Medium-a, gde se fokusira na realne scenarije kao što je analiza govora ili pretraga kroz dokumente. Dodao sam svoje komentare, savete za optimizaciju i male izmene da budu još pristupačniji. Ako ste početnik, ovo će vas voditi kroz osnove; za iskusne, tu su trikovi za skaliranje.

RAG nije samo teorija – to je način da vaš AI „proširi“ znanje iz spoljnih izvora, smanjujući halucinacije i čineći odgovore preciznijim. Hajde da krenemo sa konkretnim kodom. Pretpostavljam da imate Python 3.11+ i OpenAI API ključ (besplatan za testiranje, ali plaćate po upitu).

Preduslovi: Priprema okruženja

Pre nego što zaronimo u kod, postavite bazu. Kreirajte virtuelno okruženje da izbegnete haos:

python -m venv rag_env
# Na Windows: rag_env\Scripts\activate
# Na Mac/Linux: source rag_env/bin/activate
pip install langchain langchain-openai langchain-chroma langchain-text-splitters python-dotenv tiktoken
Kreirajte .env fajl za tajne:
OPENAI_API_KEY=sk-vaš-ključ-ovde
Učitajte ga u kodu:
from dotenv import load_dotenv
import os
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
Savet: Koristite .gitignore da ne uploadujete ključeve na GitHub. Ovo je osnova za sve primere – bez ovoga, ništa neće raditi.

Primer 1: Jednostavan RAG sa Chroma vektorskom bazom (lokalno indeksiranje)

Ovaj primer koristi govor Bidena iz 2024. (kao u tutorijalu sa Medium-a) da pokaže kako da indeksirate tekst i odgovarate na pitanja. Chroma je besplatna, lokalna vektorska baza – savršena za testiranje bez cloud troškova.

Korak 1: Učitavanje i razbijanje teksta

Preuzmite neki tekst (npr. „2024_state_of_the_union.txt“) i razbijte ga na delove (chunks) da se lakše indeksira.

python
from langchain_text_splitters import CharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_chroma import Chroma

# Učitaj tekst
with open("2024_state_of_the_union.txt", "r") as f:
    tekst = f.read()

# Razbij na delove
splitter = CharacterTextSplitter(
    chunk_size=1000,  # Velicina bloka
    chunk_overlap=200,  # Preklapanje za kontekst
    length_function=len
)
dokumenti = splitter.create_documents([tekst])
Objašnjenje: Chunking sprečava gubitak konteksta – ako je dokument prevelik, embedding modeli (kao OpenAI-ov) neće ga dobro razumeti. Preklapanje od 20% pomaže da se veze ne prekinu.

Korak 2: Kreiranje vektorske baze i indeksiranje

# Embedding model za pretvaranje teksta u vektore
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")

# Kreiraj Chroma bazu
vektor_baza = Chroma(
    collection_name="state-union",
    embedding_function=embeddings
)

# Dodaj dokumente
id_evi = vektor_baza.add_documents(dokumenti)
Objašnjenje: Embeddings pretvaraju reči u brojeve (vektore) za semantičku pretragu. Chroma čuva ovo lokalno – brzo za male setove (do 1GB), ali za veće, prelazite na Pinecone.

Korak 3: Kreiranje retrievera i LLM-a

from langchain_openai import ChatOpenAI
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate

# Retriever – traži slične delove
retriever = vektor_baza.as_retriever(search_kwargs={"k": 3})  # Top 3 rezultata

# LLM za generaciju
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.2)  # Niska temperatura za tačnost

# Formatiranje rezultata
def formatiraj_dokumenti(docs):
    return "\n\n".join(doc.page_content for doc in docs)

# Prompt šablon
prompt_template = """
Koristi sledeći kontekst da odgovoriš na pitanje. Ako ne znaš odgovor na osnovu konteksta, reci da ne znaš i izvini se.

Kontekst: {context}
Pitanje: {query}
Odgovor:
"""

prompt = PromptTemplate.from_template(prompt_template)

# RAG lanac
rag_lanac = (
    {"context": retriever | formatiraj_dokumenti, "query": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)
Korak 4: Testiranje
# Upit
odgovor = rag_lanac.invoke("Prema govoru iz 2024, ko je napao Ukrajinu?")
print(odgovor)
# Očekivani output: "Prema govoru iz 2024. Državnog Saveza, Putin Rusije je napao Ukrajinu."

# Test van konteksta
odgovor_van = rag_lanac.invoke("Kakav je smisao života?")
print(odgovor_van)
# Output: "Izvinjavam se, ali ne znam odgovor na tvoje pitanje na osnovu datog konteksta."
Savet: Testirajte sa metrikama poput BLEU skora (iz NLTK biblioteke) da merite tačnost. Ovaj primer traje 5-10 minuta za setup i radi na laptopu – idealno za prototip.

Primer 2: Napredni RAG sa Pinecone (cloud skalabilnost)

Za veće baze (npr. hiljade dokumenata), koristite Pinecone za brzo indeksiranje. Ovaj primer je proširen iz TO THE NEW tutorijala, sa fokusom na API integraciju.

Korak 1: Učitavanje i procesiranje dokumenata

from langchain.document_loaders import DirectoryLoader
from langchain.text_splitter import CharacterTextSplitter

class BazaZnanja:
    def __init__(self, direktorijum):
        self.direktorijum = direktorijum
        self.splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
    
    def ucitaj_dokumente(self):
        loader = DirectoryLoader(self.direktorijum)
        dokumenti = loader.load()
        return self.splitter.split_documents(dokumenti)
Objašnjenje: Koristite DirectoryLoader za folder sa PDF-ovima ili TXT fajlovima – super za korporativne baze.

Korak 2: Retriever sa Pinecone

import pinecone
from langchain.vectorstores import Pinecone
from langchain.embeddings.openai import OpenAIEmbeddings

class RAGRetriever:
    def __init__(self, api_kljuc, okolina="us-west1-gcp"):
        pinecone.init(api_key=api_kljuc, environment=okolina)
        self.embeddings = OpenAIEmbeddings()
    
    def kreiraj_indeks(self, dokumenti, ime_indeksa="rag-indeks"):
        return Pinecone.from_documents(
            dokumenti, self.embeddings, index_name=ime_indeksa
        )
    
    def dohvati_retriever(self, vektor_baza, k=3):
        return vektor_baza.as_retriever(search_type="similarity", search_kwargs={"k": k})
Savet: Pinecone je plaćen (od 0.1$ po upitu), ali skalira na milione – koristite za produkciju. Dodajte metapodatke (npr. autor, datum) za bolju filtraciju.

Korak 3: Generacija i lanac

from langchain.llms import OpenAI
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

class RAGGenerator:
    def __init__(self, model="gpt-3.5-turbo"):
        self.llm = OpenAI(model_name=model, temperature=0.7)
    
    def kreiraj_lanac(self, retriever):
        template = """
        Koristi kontekst da odgovoriš na pitanje. Ako ne znaš, reci to.
        
        Kontekst: {context}
        Pitanje: {question}
        Odgovor:
        """
        prompt = PromptTemplate(template=template, input_variables=["context", "question"])
        
        return RetrievalQA.from_chain_type(
            llm=self.llm,
            chain_type="stuff",
            retriever=retriever,
            chain_type_kwargs={"prompt": prompt}
        )
Korak 4: Kompletan pipeline i API (sa Flask)
from flask import Flask, request, jsonify

app = Flask(__name__)

# Inicijalizuj
baza = BazaZnanja("./dokumenti")
dokumenti = baza.ucitaj_dokumente()
retriever_klasa = RAGRetriever(os.getenv("PINECONE_API_KEY"))
vektor_baza = retriever_klasa.kreiraj_indeks(dokumenti)
retriever = retriever_klasa.dohvati_retriever(vektor_baza)
generator = RAGGenerator()
lanac = generator.kreiraj_lanac(retriever)

@app.route("/upit", methods=["POST"])
def upit():
    data = request.json
    if "upit" not in data:
        return jsonify({"greška": "Nedostaje upit"}), 400
    odgovor = lanac.run(data["upit"])
    return jsonify({"odgovor": odgovor})

if __name__ == "__main__":
    app.run(port=5000)

Objašnjenje: Ovaj Flask API omogućava da vaš RAG radi kao servis – pozovite POST /upit sa JSON-om {„upit“: „Tvoje pitanje“}. Dodajte logging za praćenje performansi.

Napredni saveti: Reranking i multi-upiti

  • Reranking: Nakon pretrage, rangirajte rezultate sa Cohere Rerank (pip install cohere). Povećava tačnost za 20-40%.
  • Multi-query: Razbijte složeno pitanje na pod-upite: „Šta je RAG?“ -> [„Definicija RAG“, „Prednosti RAG“, „Implementacija RAG“] – spojite rezultate za bogatiji odgovor.
  • Optimizacija: Koristite FAISS za lokalno (brže od Chroma) ili ažurirajte embedding-e svakih 24h za dinamične podatke. Prema LangChain docs (2025), testirajte sa RAGAS bibliotekom za evaluaciju.

Ovi primeri su testirani i rade – počnite sa prvim za brzi prototip, pa skalirajte. Ako imate greške, proverite API ključeve. Šta ćete implementirati prvo? Podignite u komentarima, ili pitajte za više detalja!

Banner

Banner

Možda će vam se svideti i