Bir RAG sisteminde "çöp girerse çöp çıkar" (Garbage In, Garbage Out) kuralı geçerlidir. Kullanıcılar her zaman teknik olarak mükemmel sorular sormazlar. Bazen çok dar, bazen çok karmaşık, bazen de veritabanındaki dökümanların diliyle tamamen uyumsuz sorular gelir.
Bugün, bu engelleri aşmak için geliştirilmiş üç devrimsel tekniği inceleyeceğiz.
1. HyDE (Hypothetical Document Embeddings)
HyDE, kullanıcının sorusunu doğrudan veritabanında aramak yerine, önce LLM'e "Bu sorunun cevabı muhtemelen nasıl bir dökümanda yazar?" diye sorar. LLM hayali (hipotetik) bir cevap yazar. Biz de kullanıcının sorusunu değil, bu hayali cevabı veritabanında aratırız.
from langchain.chains import HypotheticalDocumentEmbedder, LLMChain
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import PromptTemplate
# 1. Hazırlık
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
base_embeddings = OpenAIEmbeddings()
# 2. Hayali döküman üretecek prompt
prompt_template = "Soru: {question}\nCevap: Lütfen bu soruyu cevaplayan kısa bir paragraf yaz."
prompt = PromptTemplate(input_variables=["question"], template=prompt_template)
# 3. HyDE Zinciri
# Bu zincir, döküman üreten bir LLM ve baz embedding modelini birleştirir
llm_chain = LLMChain(llm=llm, prompt=prompt)
hyde_embeddings = HypotheticalDocumentEmbedder(
llm_chain=llm_chain,
base_embeddings=base_embeddings
)
# 4. Kullanım: Vektör aramasında artık hyde_embeddings kullanılır
query = "Kuantum bilgisayarların soğutma sistemleri nasıl çalışır?"
# Arka planda: Soru -> Hayali Cevap -> Vektör -> Gerçek DökümanHypotheticalDocumentEmbedder: Soru ile döküman arasındaki "anlamsal uçurumu" kapatır. Sorular (soru kipi) ve dökümanlar (açıklama kipi) vektör uzayında birbirinden uzak olabilir. Hayali bir açıklama metni üzerinden arama yapmak, gerçek dökümanlara çok daha yakın sonuçlar verir.base_embeddings: Hayali dökümanı vektöre çevirecek asıl matematiksel motor.llm_chain: Hayali dökümanı yazacak olan "yaratıcı" katman.
2. Step-back Prompting
Karmaşık bir soruyu cevaplamadan önce "bir adım geri atıp" konunun temel prensibini sormaktır. Örneğin; "2023 model X marka aracın motor yağı ne olmalı?" yerine "X marka araçların genel motor yağı spesifikasyonları nelerdir?" diye sormak, daha geniş ve doğru bağlam sağlar.
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# 1. Step-back (Geriye doğru adım) Promptu
step_back_template = """Sen bir sorgu uzmanısın.
Aşağıdaki spesifik soruyu, bu konunun temel prensibini sorgulayan daha genel bir soruya dönüştür.
Soru: {question}
Genişletilmiş Soru:"""
step_back_prompt = ChatPromptTemplate.from_template(step_back_template)
step_back_chain = step_back_prompt | llm | StrOutputParser()
# 2. Uygulama
question = "iPhone 15 Pro Max kamerasında neden 5x optik zoom var?"
step_back_question = step_back_chain.invoke({"question": question})
# Çıktı muhtemelen: "Akıllı telefonlarda optik zoom teknolojisinin çalışma prensibi nedir?"- Strateji: Spesifik detaylar bazen dökümanlarda doğrudan bulunmayabilir. Ancak konunun "temel prensibi" (step-back) her zaman dökümanlarda mevcuttur. Bu teknikle LLM'e hem spesifik soruyu hem de genel prensip dökümanını vererek hatasız sentez yapmasını sağlıyoruz.
3. Rewrite-Retrieve-Read
Bu yöntem, kullanıcının sorusunu arama motorunun (Retriever) daha iyi anlayacağı şekilde tamamen yeniden yazar. Karmaşık, devrik veya eksik anlatılmış soruları "temizler".
# 1. Yeniden Yazım (Rewrite) Promptu
rewrite_template = """Aşağıdaki kullanıcı sorusunu, bir arama motorunda en iyi sonucu verecek şekilde yeniden yaz.
Sadece yeniden yazılmış soruyu döndür.
Soru: {question}
Optimize Edilmiş Soru:"""
rewrite_prompt = ChatPromptTemplate.from_template(rewrite_template)
rewrite_chain = rewrite_prompt | llm | StrOutputParser()
# 2. Zincirleme: Rewrite -> Retrieve -> Read
user_query = "Ya şu bizim 2024 tatil şeysi vardı ya, onun süresi ne kadar?"
optimized_query = rewrite_chain.invoke({"question": user_query})
# Çıktı: "2024 yılı çalışan yıllık izin süreleri ve tatil politikası nedir?"optimized_query: Kullanıcının günlük konuşma dilini, veritabanının "kurumsal/teknik" diliyle eşleştiriyoruz. Vektör veritabanları "şey", "şu" gibi belirsiz kelimelerle arama yapıldığında çok düşük başarı oranı gösterir.
Özet: Hangi Silahı Ne Zaman Kullanmalı?
- HyDE: Sorunuz çok kısaysa ve veritabanınız çok teknik/detaylıysa kullanın.
- Step-back: Soru çok spesifik bir detay içeriyorsa ve bağlamsal bilgiye (background) ihtiyaç varsa kullanın.
- Rewrite: Kullanıcı sorusu çok dağınık veya belirsiz ifadeler içeriyorsa kullanın.
Sonuç
Query Transformations, RAG sistemine "düşünme payı" bırakmaktır. Soruyu hemen aratmak yerine, onu analiz edip en uygun forma sokmak, retrieval kalitesini manuel iyileştirmelerden çok daha fazla artırır.
Bu yazı, 55 günlük kapsamlı bir LangChain eğitim serisinin 29. gününü temsil etmektedir. Serinin tamamı için LangChain MasterClass makalesini inceleyebilirsiniz.