Temel RAG ve Aracı Özelliklerini Uygulama
Belge alma hattını, vektör deposu indekslemeyi, yeniden sıralamalı getirmeyi ve aracı araç entegrasyonlarını, eğitim boyunca öğrendiğiniz kalıpları izleyerek oluşturun.
Temel RAG ve Aracı Özelliklerini Uygulama, CoddyKit'te ücretsiz bir AI Engineering Academy dersidir. Bu, 4 dersinin 2. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, AI Engineering Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. AI Engineering Academy kursu toplamda 4 dersten oluşur.
Uygulama Sırası ve Bağımlılıklar
Sisteminizi aşağıdan yukarıya doğru oluşturun: dış bağımlılığı olmayan bileşenlerle başlayın, ardından bunlara bağlı bileşenleri katman olarak ekleyin. RAG + aracı sistemi için sıra şöyledir: (1) vektör deposu şeması, (2) alma hattı, (3) getirici, (4) temel soru-cevap zinciri, (5) akış uç noktası, (6) araçlara sahip aracı, (7) önbelleğe alma katmanı, (8) izleme araçları. Her bileşeni hata ayıklamayı kolaylaştırmak için hatta entegre etmeden önce tek başına sınayın.
# Build order:
IMPL_ORDER = [
'pgvector_schema', # prerequisite for everything
'document_ingestion', # populate the vector store
'hybrid_retriever', # test retrieval in isolation
'qa_chain_basic', # integrate LLM with retrieval
'streaming_endpoint', # expose via API
'function_calling', # add agent tool calls
'semantic_cache', # reduce repeat API calls
'langsmith_tracing', # add after core works
'injection_filter', # harden before load testing
]Vektör Deposunu Kurmak
Belgeleri almadan önce pgvector tablosunu doğru şemayla oluşturun. Vektör, parça metni, tüm üst veri alanları ve seçmeli yeniden dizinleme için bir updated_at zaman damgası sütunlarını ekleyin. Gömme sütununda hemen bir vektör dizini (HNSW veya IVFFlat) oluşturun — milyonlarca satırdan sonra dizin eklemek, boş bir tabloya baştan eklemekten çok daha yavaştır.
-- PostgreSQL schema with pgvector
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE document_chunks (
id BIGSERIAL PRIMARY KEY,
doc_id TEXT NOT NULL,
chunk_text TEXT NOT NULL,
embedding VECTOR(1536) NOT NULL,
source_file TEXT,
page_number INT,
section TEXT,
doc_type TEXT,
tenant_id TEXT NOT NULL, -- for data isolation
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_chunks_hnsw ON document_chunks
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
CREATE INDEX idx_chunks_tenant ON document_chunks(tenant_id);Alma Hattını Oluşturmak
Almayı, bir dosya yolu veya URL kabul eden ve dizinlenen parça sayısını döndüren tek bir asenkron işlev olarak uygulayın. Farklı dosya türleri için LangChain'in belge yükleyicilerini, parçalara ayırma için de özyinelemeli karakter metni bölücüsünü kullanın. 2048 belirteçlik giriş sınırı içinde kalmak ve API çağrılarını binlerden düzinelere düşürmek için gömme çağrılarını toplu hâle getirin.
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from openai import AsyncOpenAI
async def ingest_document(file_path: str, doc_id: str, tenant_id: str) -> int:
loader = PyPDFLoader(file_path)
pages = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=800, chunk_overlap=100)
chunks = splitter.split_documents(pages)
# Batch embed
texts = [c.page_content for c in chunks]
client = AsyncOpenAI()
embeddings_response = await client.embeddings.create(
model='text-embedding-3-small',
input=texts
)
embeddings = [e.embedding for e in embeddings_response.data]
await insert_chunks_to_pgvector(chunks, embeddings, doc_id, tenant_id)
return len(chunks)Hibrit Getiriciyi Oluşturmak
Yoğun vektör aramasını BM25 anahtar kelime aramasıyla birleştirin ve sonuçları karşılıklı sıra birleştirmesi kullanarak birleştirin. Getiriciyi, tek bir retrieve(query, tenant_id, top_k) yöntemi olan bir sınıf olarak uygulayın. İçeride her iki aramayı da asyncio.gather ile eşzamanlı yürütün, sıralanmış listeleri RRF ile birleştirin, parça kimliğine göre yinelemeleri kaldırın ve kaynak üst verileriyle birlikte ilk top_k sonucu döndürün.
import asyncio
from rank_bm25 import BM25Okapi
class HybridRetriever:
def __init__(self, pool, k_rrf: int = 60):
self.pool = pool
self.k_rrf = k_rrf
async def retrieve(self, query: str, tenant_id: str, top_k: int = 10) -> list:
dense_results, sparse_results = await asyncio.gather(
self._dense_search(query, tenant_id, top_k * 3),
self._bm25_search(query, tenant_id, top_k * 3)
)
merged = self._rrf_merge(dense_results, sparse_results)
return merged[:top_k]
def _rrf_score(self, rank: int) -> float:
return 1.0 / (self.k_rrf + rank + 1)Temel QA Zincirini Uygulamak
Temel soru-cevap zincirini LangChain LCEL kullanarak oluşturun. Zincir bir soru ve getirilen parçaları alır, yalnızca sağlanan bağlamı kullanma talimatları içeren zenginleştirilmiş bir istem biçimlendirir ve yanıtı akış olarak gönderir. Modele kaynakları belge adı ve sayfa numarasıyla belirtmesi, yanıt getirilen bağlamda yoksa da "Bilmiyorum" demesi için açık talimatlar ekleyin.
from langchain.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain.schema.output_parser import StrOutputParser
RAG_PROMPT = ChatPromptTemplate.from_messages([
('system', 'You are a precise assistant. Answer ONLY using the provided context. '
'Cite sources as [DocName, p.N]. If the answer is not in the context, say "I don\'t have information about that."'),
('user', 'Context:\n{context}\n\nQuestion: {question}')
])
llm = ChatOpenAI(model='gpt-4o', temperature=0, streaming=True)
qa_chain = RAG_PROMPT | llm | StrOutputParser()
async def answer_question(question: str, chunks: list) -> str:
context = '\n\n'.join(f'[{c["source"]}]\n{c["text"]}' for c in chunks)
return await qa_chain.ainvoke({'context': context, 'question': question})Aracıya İşlev Çağırma Eklemek
Gerçek zamanlı veri veya hesaplama gerektiren sorguları ele almak için temel soru-cevap sistemini işlev çağırmayla genişletin. Şu araçları tanımlayın: güncel bilgileri bulmak için web'de arama, güvenli salt okunur bir veritabanında SQL sorguları çalıştırma ve ID ile belirli kayıtları arama. Aracı, soruya göre hangi araçların çağrılacağına karar verir, bunları yürütür ve sonuçları nihai yanıta dâhil eder.
from openai import AsyncOpenAI
import json
TOOLS = [
{
'type': 'function',
'function': {
'name': 'search_knowledge_base',
'description': 'Search the internal document knowledge base for relevant information',
'parameters': {
'type': 'object',
'properties': {
'query': {'type': 'string', 'description': 'Search query'},
'top_k': {'type': 'integer', 'default': 5}
},
'required': ['query']
}
}
}
]
async def agent_with_tools(question: str, tenant_id: str) -> str:
client = AsyncOpenAI()
messages = [{'role': 'user', 'content': question}]
while True:
resp = await client.chat.completions.create(
model='gpt-4o', messages=messages, tools=TOOLS)
if resp.choices[0].finish_reason != 'tool_calls':
return resp.choices[0].message.content
tool_call = resp.choices[0].message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
result = await dispatch_tool(tool_call.function.name, args, tenant_id)
messages.append({'role': 'tool', 'tool_call_id': tool_call.id, 'content': result})Aracı Yanıtını Akış Olarak Göndermek
Aracıyı, ön yüzün belirteçleri gelir gelmez görüntülemesi için sunucu tarafından gönderilen olayları kullanarak bir FastAPI StreamingResponse içine sarın. Araç çağrıları içeren aracı yanıtlarında, araç çalışırken bir ilerleme göstergesi ("Bilgi tabanı aranıyor...") akışı sağlayın, ardından nihai yanıtı belirteç belirteç akıtın. Bu, araç çalışırken oluşan gecikme nedeniyle sayfanın donmuş gibi görünmesini önler.
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import asyncio
app = FastAPI()
async def event_stream(question: str, tenant_id: str):
yield 'data: {"type": "start"}\n\n'
chunks = await retriever.retrieve(question, tenant_id)
yield 'data: {"type": "retrieving", "count": ' + str(len(chunks)) + '}\n\n'
async for token in qa_chain.astream({'context': format_context(chunks), 'question': question}):
yield f'data: {{"type": "token", "content": {repr(token)}}}\n\n'
yield 'data: {"type": "done"}\n\n'
@app.post('/query/stream')
async def stream_query(question: str, tenant_id: str):
return StreamingResponse(event_stream(question, tenant_id), media_type='text/event-stream')Semantic Cache'i Bağlama
Semantic Cache'i sorgu hattına, alıp getirmeden önceki bir adım olarak ekleyin. Getiriciyi ve LLM'yi çağırmadan önce kullanıcının sorusunu gömümleyin ve önbelleği kontrol edin. Benzerlik eşik değerinin üzerindeyse, önbellek isabetinde önbelleğe alınan yanıtı cached: true bayrağıyla hemen döndürün. Önbellek kaçırmalarında sorgu hattının tamamı çalıştırılır ve ortaya çıkan yanıt, gelecekteki benzer sorgular için önbelleğe kaydedilir.
async def query_pipeline(question: str, tenant_id: str) -> dict:
# 1. Check semantic cache
cache_hit = await semantic_cache.lookup(question, tenant_id, threshold=0.92)
if cache_hit:
return {'answer': cache_hit.answer, 'cached': True, 'sources': cache_hit.sources}
# 2. Retrieve
chunks = await retriever.retrieve(question, tenant_id, top_k=5)
chunks = await reranker.rerank(question, chunks, top_n=3)
# 3. Generate
answer = await answer_question(question, chunks)
sources = [c['source'] for c in chunks]
# 4. Cache result
await semantic_cache.store(question, tenant_id, answer, sources)
return {'answer': answer, 'cached': False, 'sources': sources}LangSmith İzlemeyi Ekleme
İki ortam değişkeni ayarlayarak sorgu hattını LangSmith ile izlenebilir hâle getirin. Her LangChain zinciri çağrısı; belirteç sayıları, gecikme, girdiler, çıktılar ve varsa hatalarla otomatik olarak izlenir. Özel, LangChain dışı kodlar (getirme, yeniden sıralama) için çağrıları @traceable ek açıklamalarıyla sararak bunları da ize dâhil edin. Böylece sorgu hattındaki her adım uçtan uca eksiksiz biçimde görünür olur.
import os
from langsmith import traceable
os.environ['LANGCHAIN_TRACING_V2'] = 'true'
os.environ['LANGCHAIN_API_KEY'] = os.environ['LANGSMITH_API_KEY']
os.environ['LANGCHAIN_PROJECT'] = 'document-qa-production'
# Wrap non-LangChain steps with @traceable
@traceable(name='hybrid_retrieval')
async def traced_retrieval(question: str, tenant_id: str, top_k: int) -> list:
return await retriever.retrieve(question, tenant_id, top_k)
@traceable(name='cohere_reranking')
async def traced_reranking(question: str, chunks: list) -> list:
return await reranker.rerank(question, chunks)
# LangChain LCEL chains are automatically traced — no extra code neededBütünleşme Testlerini Çalıştırma
Soru girdisinden nihai yanıta kadar sorgu hattının tamamını çalıştıran bütünleşme testleri yazın. Hangi parçaların getirilmesi gerektiği ve yanıtın neleri içermesi gerektiği konusunda belirlenimli doğrulamalar yazabilmek için bilinen belgelere sahip küçük bir sınama vektör deposu kullanın. Bütünleşme testlerini, üretim altyapısını yansıtan ancak ayrı bir vektör deposu ve LLM anahtarı kullanan hazırlık ortamında çalıştırın.
import pytest
@pytest.mark.asyncio
async def test_full_pipeline_returns_grounded_answer():
# Setup: ingest known document
await ingest_document('tests/fixtures/policy.pdf', 'policy_v1', 'test_tenant')
# Query with a question that has a known answer in the document
result = await query_pipeline(
question='What is the cancellation policy?',
tenant_id='test_tenant'
)
assert result['answer'] is not None
assert len(result['answer']) > 50
assert '24 hours' in result['answer'] # known fact in document
assert 'policy.pdf' in str(result['sources'])
assert result['cached'] is False # fresh queryTemel Getirme Kalitesini Ölçme
Herhangi bir iyileştirme yapmadan önce bir getirme temeli oluşturun. İsabet oranını (doğru belge ilk 5 sonuçta görünüyor mu?) ve MRR'yi (kaçıncı sırada yer alıyor?) ölçmek için değerlendirme sınama kümenizi kullanın. Bu temel ölçümü, ilk vektör deposunu kurduktan ve yeniden sıralama ya da karma arama eklemeden önce gerçekleştirin. Temel ölçüm, her iyileştirmenin gerçekte ne sağladığını gösterir; böylece uygulanmaya değer teknikleri kanıtlarla belirleyebilirsiniz.
async def measure_retrieval_baseline(test_cases: list) -> dict:
hits = 0
reciprocal_ranks = []
for case in test_cases:
results = await retriever.retrieve(case['question'], case['tenant_id'], top_k=5)
result_docs = [r['doc_id'] for r in results]
if case['relevant_doc'] in result_docs:
hits += 1
rank = result_docs.index(case['relevant_doc']) + 1
reciprocal_ranks.append(1.0 / rank)
else:
reciprocal_ranks.append(0.0)
return {
'hit_rate_at_5': hits / len(test_cases),
'mrr': sum(reciprocal_ranks) / len(reciprocal_ranks)
}Kısa Kontrol
Temel RAG ve aracı özelliklerini oluşturma konusundaki anlayışınızı sınayın.
Ders Özeti
Bu derste şunları öğrendiniz: tepeden tırnağa uygulama sırası, her bileşenin bütünleştirmeden önce yalıtılmış olarak sınanmasını sağlar; eşzamanlı yoğun ve BM25 aramasına sahip karma getirme, RRF ile birleştirildiğinde en iyi getirme kalitesini sunar; @traceable ek açıklamalarıyla LangSmith izleme ise sorgu hattının tamamını görünür kılar. Sırada sistemi güvenlik, önbelleğe alma ve güvenilirlik kalıplarıyla sağlamlaştırmak var.
Yapay zeka eğitmeniyle Python öğren — ücretsiz
Tarayıcında gerçek kod yaz ve çalıştır, 7/24 yapay zeka eğitmeninden anında yardım al; web'de ya da uygulamada kaldığın yerden devam et.
- Kurslar
- 30
- Dersler
- 120
Sıkça Sorulan Sorular
“Temel RAG ve Aracı Özelliklerini Uygulama” dersi ücretsiz mi?
Evet — “Temel RAG ve Aracı Özelliklerini Uygulama” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve AI Engineering Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. AI Engineering Academy kursu toplamda 4 dersten oluşur.
“Temel RAG ve Aracı Özelliklerini Uygulama” dersinde ne öğreneceğim?
Belge alma hattını, vektör deposu indekslemeyi, yeniden sıralamalı getirmeyi ve aracı araç entegrasyonlarını, eğitim boyunca öğrendiğiniz kalıpları izleyerek oluşturun. AI Engineering Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
AI Engineering Academy öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te AI Engineering Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 2. dersidir.
“Temel RAG ve Aracı Özelliklerini Uygulama” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu AI Engineering Academy dersinde kod yazıp çalıştırabilir miyim?
Evet. Her AI Engineering Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- Üretim Mimarisi Tasarlama
- Temel RAG ve Aracı Özelliklerini Uygulama
- Sağlamlaştırma: Güvenlik, Önbellekleme ve Güvenilirlik
- Değerlendirme, Dağıtım ve Geriye Dönük Değerlendirme