AI Prompt Engineering · Lekcja

Poza naiwnym RAG

Ograniczenia podstawowego wyszukiwania

Lekcja 1 z 413 kroki

Poza naiwnym RAG to bezpłatna lekcja AI Prompt Engineering na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Prompt Engineering, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.

Działanie naiwnego RAG

Naiwny RAG to rozwiązanie bazowe: dzieli dokumenty na fragmenty, tworzy ich embeddingi, przechowuje wektory, tworzy embedding zapytania, pobiera elementy top-k według podobieństwa cosinusowego, umieszcza fragmenty w prompcie i generuje odpowiedź. To solidny punkt wyjścia, który w przewidywalny sposób zawodzi przy dużej skali.

Zrozumienie tych trybów awarii jest warunkiem wstępnym zastosowania zaawansowanych technik (rerankingu, kompresji i przepisywania zapytań) omawianych w tym kursie.

def naive_rag(query, k=5):
    q = embed(query)
    chunks = vector_store.search(q, k)        # top-k by cosine
    context = '\n\n'.join(c.text for c in chunks)
    return llm('Context:\n' + context + '\n\nQ: ' + query)

Czułość i precyzja wyszukiwania

Naiwne top-k optymalizuje surowe podobieństwo wektorów, które miesza istotność z powierzchownym podobieństwem semantycznym. Powstaje kompromis: małe k grozi pominięciem odpowiedzi (niski recall), a duże k zalewa kontekst rozpraszającymi elementami (niska precyzja).

Podobieństwo embeddingów sterujące wyszukiwaniem jest przybliżonym wskaźnikiem rzeczywistej istotności i stanowi źródło kilku dalszych problemów.

# The core dilemma
# small k -> may miss the gold chunk (recall problem)
# large k -> distractors crowd context (precision + cost problem)
# Advanced RAG decouples 'retrieve many' from 'use few'

Problem niedopasowania embeddingów

Zapytania i dokumenty często są sformułowane w różnych rejestrach językowych: krótkie pytanie zestawione z długim fragmentem oznajmującym. Embeddingi bi-encodera mogą umieścić istotną odpowiedź daleko od pytania, ponieważ zostały sformułowane odmiennie (problem niedopasowania słownictwa).

To prowadzi do technik takich jak przepisywanie zapytań i HyDE, które przed wyszukiwaniem przekształcają zapytanie tak, aby pasowało do przestrzeni dokumentów.

# Query:  'how do I revoke a token?'
# Doc:    'Token invalidation is performed via the /sessions endpoint.'
# Lexically and semantically distant -> bi-encoder may miss it
sim = cos(embed('how do I revoke a token?'),
          embed('Token invalidation via /sessions'))  # may be low

Zagubienie w środku

Nawet gdy właściwy fragment zostanie pobrany, umieszczenie wielu fragmentów w kontekście wywołuje efekt lost-in-the-middle: model poświęca mniej uwagi treści znajdującej się w środku długiego kontekstu. Poprawny fragment ukryty na trzeciej pozycji z dziesięciu może zostać praktycznie zignorowany.

Uzasadnia to stosowanie rerankingu (umieszczenie najlepszego fragmentu w miejscu, na które model zwraca uwagę) oraz kompresji (zmniejszenie kontekstu, aby nic nie zostało ukryte).

# Retrieval rank != attention rank
# Place the highest-relevance chunk at the START or END,
# never stranded in the middle of a large concatenation.

Podatność na elementy rozpraszające

LLM-y są podatne na działanie nieistotnego kontekstu. Dodanie wiarygodnych, ale błędnych fragmentów może sprowadzić odpowiedź na złą drogę, nawet gdy poprawny fragment również jest obecny. Większa ilość pobranego kontekstu nie zawsze oznacza lepszy wynik.

Dlatego precyzja ma znaczenie: zwarty, poddany rerankingowi i skompresowany kontekst często daje lepsze wyniki niż duży zbiór luźno powiązanych fragmentów.

# Empirically: appending a single highly-similar but WRONG chunk
# can flip a previously-correct answer. RAG quality depends on
# keeping distractors OUT, not just getting the gold chunk IN.

Problemy z dzieleniem na fragmenty

Dzielenie na fragmenty o stałym rozmiarze rozcina idee w połowie zdań, oddziela twierdzenie od dowodów i usuwa kontekst strukturalny (z której sekcji i z którego dokumentu pochodzi fragment). Fragment, który samodzielnie wygląda spójnie, może bez otoczenia być bezużyteczny lub wprowadzać w błąd.

Zaawansowane potoki używają dzielenia uwzględniającego strukturę, nakładania fragmentów, rozszerzania do dokumentu nadrzędnego oraz metadanych, aby zachować znaczenie.

def structure_aware_chunks(doc, max_tokens=400, overlap=50):
    sections = split_by_headings(doc)        # respect document structure
    chunks = []
    for sec in sections:
        for c in sliding_window(sec.text, max_tokens, overlap):
            chunks.append(Chunk(c, meta={'section': sec.title}))
    return chunks

Luki w wyszukiwaniu wyłącznie semantycznym

Czyste wyszukiwanie gęste nie radzi sobie z potrzebą dokładnego dopasowania: identyfikatorami, kodami błędów, rzadkimi nazwami własnymi i nazwami API. To właśnie w tych przypadkach użytkownicy oczekują dosłownej precyzji. Wyszukiwanie hybrydowe łączy sygnały gęste (semantyczne) i rzadkie (BM25/słowa kluczowe), aby obsłużyć oba typy potrzeb.

Reciprocal rank fusion to prosty i odporny sposób scalania obu list rankingowych bez dostrajania wagi.

def rrf(dense_ranks, sparse_ranks, k0=60):
    scores = {}
    for ranks in (dense_ranks, sparse_ranks):
        for rank, doc_id in enumerate(ranks):
            scores[doc_id] = scores.get(doc_id, 0) + 1.0 / (k0 + rank)
    return sorted(scores, key=scores.get, reverse=True)

Nieaktualny i nieweryfikowalny kontekst

Naiwny RAG nie uwzględnia aktualności ani pochodzenia danych. Może pobierać nieaktualne dokumenty i nie oferuje wbudowanego sposobu przypisywania twierdzeń do źródeł, co podważa zaufanie i utrudnia wykrywanie halucynacji.

Zaawansowane systemy dołączają metadane (znacznik czasu, źródło, wersję), filtrują na ich podstawie i wymagają od generatora cytowania identyfikatorów fragmentów, aby odpowiedzi można było zweryfikować.

def filtered_retrieve(q, after_date):
    cands = vector_store.search(embed(q), k=50)
    fresh = [c for c in cands if c.meta['date'] >= after_date]
    return fresh  # then re-rank; generator must cite c.id

Brak informacji zwrotnej oznacza brak adaptacji

Naiwny RAG wyszukuje bezrefleksyjnie: nie potrafi rozpoznać nieudanego wyszukiwania, stwierdzić, że wyszukiwanie nie jest potrzebne, ani iterować. Zaawansowane wzorce dodają sprawdzanie istotności, warunkowe wyszukiwanie oraz wieloetapowe (agentowe) wyszukiwanie, które przeformułowuje zapytanie, gdy wyniki wyglądają na słabe.

Potok staje się pętlą z samooceną zamiast pojedynczym przebiegiem w przód.

def adaptive_rag(q):
    chunks = retrieve(q)
    if relevance_score(q, chunks) < 0.4:
        q2 = rewrite_query(q)            # reformulate and retry
        chunks = retrieve(q2)
    if relevance_score(q, chunks) < 0.4:
        return 'I could not find this in the sources.'
    return generate(q, chunks)

Zaawansowany stos RAG

Połączenie tych problemów prowadzi do zaawansowanego potoku, który obejmuje: dzielenie uwzględniające strukturę wraz z metadanymi, hybrydowe wyszukiwanie o wysokim recallu, reranker oparty na cross-encoderze zapewniający precyzję, kompresję kontekstu w celu dopasowania i skupienia, przepisywanie zapytań / HyDE w celu naprawy niedopasowania oraz bramkę istotności z cytowaniami.

W kolejnych lekcjach omówimy każdą warstwę. Wspólna zasada brzmi: wyszukuj szeroko, a następnie agresywnie filtruj i udoskonalaj.

def advanced_rag(q):
    cands = hybrid_retrieve(rewrite_query(q), k=50)  # high recall
    top = rerank(q, cands)[:8]                       # precision
    ctx = compress(q, top)                            # focus + fit
    return generate_with_citations(q, ctx)            # verifiable

Najpierw mierz, potem optymalizuj

Przed dodaniem kolejnych mechanizmów należy zdiagnozować, z którym problemem rzeczywiście mamy do czynienia. Mierz recall@k wyszukiwania (czy właściwy fragment został w ogóle pobrany) niezależnie od dokładności odpowiedzi (czy generator z niego skorzystał). Problem z recall wymaga innych rozwiązań niż problem z precyzją.

Należy monitorować obie części; nie należy dodawać rerankera, gdy rzeczywistym problemem jest dzielenie na fragmenty lub niedopasowanie zapytania.

def diagnose(eval_set):
    return {
        'recall@5':  recall_at_k(eval_set, k=5),     # retrieval health
        'recall@50': recall_at_k(eval_set, k=50),    # ceiling with rerank
        'answer_acc': answer_accuracy(eval_set),      # generation health
    }

Szybki sprawdzian

Zdiagnozować tryb awarii RAG.

Podsumowanie

Najważniejsze wnioski:

  • Naiwny RAG (dzielenie na fragmenty, embeddingi, top-k, umieszczenie w prompcie, generowanie) to solidna baza o przewidywalnych trybach awarii.
  • Podobieństwo bi-encodera jest przybliżonym wskaźnikiem istotności; niedopasowanie rejestru zapytania i dokumentu obniża recall.
  • Więcej kontekstu nie zawsze oznacza lepszy wynik: podatność na elementy rozpraszające i efekt lost-in-the-middle pogarszają odpowiedzi wraz ze wzrostem k.
  • Problemy z dzieleniem na fragmenty, luki wyszukiwania wyłącznie semantycznego, nieaktualność oraz brak informacji zwrotnej ograniczają naiwny RAG.
  • Zaawansowany RAG najpierw wyszukuje szeroko, a potem filtruje: wyszukiwanie hybrydowe, reranking, kompresja, przepisywanie zapytań i bramkowanie istotności. Przed optymalizacją należy osobno mierzyć recall i dokładność odpowiedzi.
Bezpłatny start

Ucz się AI Prompt Engineering dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
53
Lekcje
199

Często zadawane pytania

Czy lekcja „Poza naiwnym RAG” jest bezpłatna?

Tak — pełny tekst „Poza naiwnym RAG” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Prompt Engineering, przejdź na CoddyKit PRO. Kurs AI Prompt Engineering zawiera 4 lekcji w sumie.

Co nauczysz się w „Poza naiwnym RAG”?

Ograniczenia podstawowego wyszukiwania Ćwiczysz AI Prompt Engineering z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć AI Prompt Engineering?

Nie wymagamy żadnego doświadczenia. AI Prompt Engineering w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Poza naiwnym RAG”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji AI Prompt Engineering?

Tak. Każda lekcja AI Prompt Engineering zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Poza naiwnym RAG
  2. Ponowne szeregowanie pobranych fragmentów
  3. Kompresja kontekstu
  4. Przepisywanie zapytań i HyDE
← Powrót do AI Prompt Engineering