Kompresja kontekstu
Ograniczanie kontekstu do istotnych informacji
Kompresja kontekstu to bezpłatna lekcja AI Prompt Engineering na CoddyKit. To lekcja 3 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.
Dlaczego warto kompresować kontekst
Pobrane fragmenty są zaszumione: trafny fragment może składać się głównie z szablonowego tekstu i zawierać tylko jedno kluczowe zdanie. Kompresja kontekstu skraca pobrany tekst do treści, która rzeczywiście odpowiada na zapytanie, zanim trafi on do generatora.
Korzyści się kumulują: niższy koszt tokenów, mniejsze opóźnienie, mniej elementów rozpraszających oraz ograniczenie problemu lost-in-the-middle dzięki zmniejszeniu kontekstu, który model musi przetworzyć.
def compress(query, chunks):
# Goal: keep only spans that bear on the query,
# dropping boilerplate, navigation, and off-topic sentences.
return [extract_relevant(query, c) for c in chunks]Ekstrakcyjna a abstrakcyjna
Kompresja ekstrakcyjna wybiera dosłowne fragmenty (zdania, akapity) trafne względem zapytania, zachowując dokładne brzmienie i pochodzenie treści. Kompresja abstrakcyjna parafrazuje lub podsumowuje tekst, zapewniając większy stopień kompresji, ale zwiększając ryzyko utraty informacji i wprowadzenia błędów.
W przypadku faktograficznego RAG z cytowaniami należy preferować metodę ekstrakcyjną, aby zachować możliwość prześledzenia twierdzeń do źródła; metodę abstrakcyjną należy stosować tylko wtedy, gdy można zweryfikować wierność treści.
def extractive(query, chunk):
sents = split_sentences(chunk.text)
scored = [(s, relevance(query, s)) for s in sents]
kept = [s for s, r in scored if r > TAU]
return ' '.join(kept) or top1(scored) # never return emptyFiltrowanie na poziomie zdań
To lekka i odporna technika: należy ocenić każde zdanie każdego fragmentu względem zapytania za pomocą małego cross-encodera lub podobieństwa embeddingów, a następnie usunąć zdania o niskich wynikach. Pozwala to zachować wartościowe zdania i odrzucić wypełniacze.
Należy zachować minimalny kontekst dla każdego fragmentu, aby nie usunąć zdania otaczającego, które nadaje faktowi znaczenie.
def sentence_filter(query, chunk, keep_ratio=0.4):
sents = split_sentences(chunk.text)
scores = embed_sim_batch(query, sents)
n_keep = max(1, int(len(sents) * keep_ratio))
idx = sorted(range(len(sents)), key=lambda i: -scores[i])[:n_keep]
return ' '.join(sents[i] for i in sorted(idx)) # keep original orderKompresja kontekstu oparta na LLM
LLM może kompresować każdy fragment osobno: należy poprosić go o wyodrębnienie wyłącznie części akapitu istotnych dla zapytania i zwrócenie fragmentu z usuniętymi nieistotnymi częściami, ale bez zmiany pozostałego tekstu, albo pustego znacznika, jeśli nic nie jest istotne.
Jest to wzorzec LangChain ContextualCompressionRetriever. Zapewnia większą dokładność niż filtry embeddingów, ale wymaga osobnego wywołania LLM dla każdego fragmentu, dlatego należy rezerwować go dla potoków o wysokich wymaganiach lub przetwarzać fragmenty partiami.
def llm_compress(query, chunk):
prompt = (
'Extract ONLY sentences from the passage relevant to the query. '
'If none are relevant, output NONE. Do not paraphrase.\n'
'Query: ' + query + '\nPassage: ' + chunk.text
)
out = llm(prompt, temperature=0).strip()
return None if out == 'NONE' else outPrzycinanie na poziomie tokenów (LLMLingua)
Metody takie jak LLMLingua kompresują tekst na poziomie tokenów, używając małego modelu do oszacowania zawartości informacyjnej tokenów i usunięcia tych o niskiej wartości informacyjnej. Mogą osiągać duże współczynniki kompresji, zachowując sygnał potrzebny większemu modelowi.
Kompromis polega na tym, że skompresowany tekst staje się mniej czytelny dla człowieka, dlatego takie rozwiązanie nadaje się do kontekstu przetwarzanego wyłącznie przez maszynę, a nie do wyświetlania użytkownikowi.
def token_prune(context, target_ratio=0.3):
# small LM estimates per-token information (perplexity-based);
# drop the least informative tokens down to target_ratio length
scores = small_lm_token_importance(context)
return keep_top_fraction(context, scores, target_ratio)Zależność od zapytania a niezależność od zapytania
Kompresja zależna od zapytania zachowuje to, co jest istotne dla tego zapytania, i zapewnia najbardziej zwięzły kontekst, ale musi być wykonywana przy każdym żądaniu. Kompresja niezależna od zapytania (wstępnie obliczone podsumowania fragmentów) jest tańsza w czasie obsługi żądania, ale nie może skupić się na konkretnym pytaniu.
Rozwiązanie hybrydowe przechowuje offline skondensowane wersje fragmentów i stosuje online lekkie przycinanie zależne od zapytania.
# Offline: precompute a dense summary per chunk (query-agnostic)
chunk.summary = summarize(chunk.text)
# Online: query-aware trim over summaries (cheap) then verify on full
ctx = [sentence_filter(query, Chunk(c.summary)) for c in top_chunks]Ochrona przed utratą informacji
Agresywna kompresja może usunąć jedną klauzulę, która miała kluczowe znaczenie. Należy zastosować kontrolę recall: sprawdzić, czy skompresowany kontekst nadal pozwala wywnioskować odpowiedź, albo zachować możliwość użycia nieskompresowanego fragmentu, gdy kompresor zwróci podejrzanie mało treści.
Nie należy nigdy pozwalać, aby kompresja zmieniła fragment w pustą treść, jeśli reranker ocenił go jako wysoce trafny; oznacza to awarię kompresora, a nie brak trafności.
def safe_compress(query, chunk):
out = llm_compress(query, chunk)
if out is None and chunk.rerank_score > 0.7:
return chunk.text # trust re-ranker over compressor
return out or chunk.textZachowanie pochodzenia treści
Kompresja musi zachować atrybucję źródła. Każdy zachowany fragment należy oznaczyć identyfikatorem fragmentu i dokumentu, aby generator mógł go zacytować. Jeśli metadane zostaną usunięte podczas kompresji, utracona zostaje możliwość weryfikacji oraz wykrywania halucynacji.
Identyfikatory należy przenosić przez cały potok jako pola strukturalne, a nie jako zwykły tekst, który kompresja mogłaby usunąć.
def compress_with_ids(query, chunks):
out = []
for c in chunks:
span = safe_compress(query, c)
out.append({'id': c.id, 'doc': c.meta['doc_id'], 'text': span})
return out # generator cites id; provenance preservedKompresja a budżet tokenów
Kompresja pozwala pobrać więcej kandydatów w celu zwiększenia recall, a jednocześnie zachować niewielki końcowy prompt. Należy ustawić budżet tokenów dla okna kontekstu i zachłannie dodawać skompresowane fragmenty o najwyższej wartości aż do wyczerpania budżetu.
Oddziela to ilość pobieranych treści od ilości zasobów przeznaczanych na generowanie, co stanowi istotny sposób zwiększania efektywności.
def pack(spans, budget_tokens, tok):
spans = sorted(spans, key=lambda s: -s['score'])
used, packed = 0, []
for s in spans:
t = tok(s['text'])
if used + t > budget_tokens:
continue
packed.append(s); used += t
return packedPomiar jakości kompresji
Należy śledzić trzy wartości: współczynnik kompresji (zaoszczędzone tokeny), dokładność odpowiedzi (czy jakość została zachowana) oraz wierność (czy kompresor uniknął zmiany faktów). Celem jest uzyskanie najwyższego współczynnika, który nie pogarsza dokładności odpowiedzi.
Należy przetestować różne poziomy agresywności kompresji i wybrać punkt Pareto spełniający założony cel kosztowy bez utraty jakości.
def eval_compression(eval_set, levels):
return {
lvl: {
'ratio': mean_ratio(eval_set, lvl),
'acc': answer_accuracy(eval_set, lvl),
'faith': faithfulness(eval_set, lvl),
} for lvl in levels
}Potok uwzględniający kompresję
Od początku do końca: należy wyszukiwać szeroko, wykonać reranking, skompresować każdy pozostały fragment (ekstrakcyjnie lub za pomocą LLM), zachowując jego pochodzenie, zabezpieczyć się przed nadmiernym przycięciem, zmieścić treść w budżecie tokenów i wygenerować odpowiedź z cytowaniami.
Kompresja to warstwa, która sprawia, że wyszukiwanie zapewniające wysoki recall staje się przystępne kosztowo i pozwala generatorowi skupić się na tym, co najważniejsze.
def pipeline(query):
top = rerank(query, hybrid_retrieve(query, 50))[:12]
spans = compress_with_ids(query, top)
spans = [s for s in spans if s['text']]
packed = pack(spans, budget_tokens=2000, tok=count_tokens)
return generate_with_citations(query, packed)Szybkie sprawdzenie
Wybierz właściwe podejście do kompresji dla faktograficznego systemu RAG z cytowaniami.
Podsumowanie
Najważniejsze wnioski:
- Kompresja ogranicza pobrane fragmenty do treści istotnych dla zapytania, zmniejszając koszty, opóźnienia i liczbę elementów rozpraszających.
- W przypadku faktograficznego RAG z cytowaniami należy preferować kompresję ekstrakcyjną (dosłowną i możliwą do prześledzenia) zamiast abstrakcyjnej; przycinanie na poziomie tokenów nadaje się do kontekstu przetwarzanego wyłącznie przez maszynę.
- Kompresja zależna od zapytania zapewnia najbardziej zwięzły kontekst, ale musi być wykonywana przy każdym żądaniu; dla większej efektywności warto połączyć ją z podsumowaniami przygotowanymi offline.
- Należy chronić się przed utratą informacji i zachowywać pochodzenie fragmentów oraz dokumentów na potrzeby cytowań.
- Kompresja pozwala wyszukiwać szeroko, zachowując niewielkie prompty; należy ją dostroić tak, aby uzyskać maksymalny współczynnik bez utraty dokładności odpowiedzi.
Często zadawane pytania
Czy lekcja „Kompresja kontekstu” jest bezpłatna?
Tak — pełny tekst „Kompresja kontekstu” 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 „Kompresja kontekstu”?
Ograniczanie kontekstu do istotnych informacji Ć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 3 z 4.
Ile czasu zajmuje lekcja „Kompresja kontekstu”?
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
- Poza naiwnym RAG
- Ponowne szeregowanie pobranych fragmentów
- Kompresja kontekstu
- Przepisywanie zapytań i HyDE