Strona główna / Artykuły / Uwagi praktyczne: Podział na fragmenty to ukryta decyzja projektowa w RAG

Uwagi praktyczne: Podział na fragmenty to ukryta decyzja projektowa w RAG

Praktyczne wskazówki: Podział na fragmenty to ukryta decyzja projektowa w RAG – umowy, sprawdzania oraz gotowe miejsca na kod dla zespołów wdrażających ten wzorzec.

1980 słów

To przewodnictwo pokazuje, jak odbudować proces od surowców do działającego systemu w następujący sposób: podział na fragmenty to ukryta decyzja projektowa w RAG. Skupiamy się na krokach realizowalnych, wyraźnych sprawdzeniach oraz kodzie, który można bez żadnych domysłów wdrożyć do repozytorium. Na etapie przeglądu należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg procesu, jak i ścieżkę naprawczą. Próby ponownych działań, kontrola przez ludzi oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później.

Przepływ w RAG

Gdy przechodzisz przez etap procesu RAG, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Wolij małe, testowalne jednostki od rozbudowanych skryptów. Gdy jakiś krok się nie powiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Zmierz stopień odzyskiwania informacji na ustalonej serii pytań przed dostosowywaniem promptów. Częste zmiany promptów rzadko naprawiają słabe możliwości wyszukiwania.

Od tekstu do wektorów

Gdy przechodzisz przez etap przekształcania tekstu w wektory, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Zmierz stopień przywoływalności na ustalonej grupie pytań przed dostosowywaniem promptów. Częste zmiany promptów rzadko naprawiają słabe możliwości wyszukiwania.

Rozmiar i nakładanie się fragmentów

Gdy przechodzisz przez etap określania rozmiaru i nakładania się fragmentów, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zapisz czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy ścieżka przechodzi z wersji demonstracyjnej do środowisk współdzielonych. Zmierz stopień odzyskiwania informacji na ustalonej grupie pytań przed dostosowywaniem promptów. Częste zmiany promptów rzadko poprawiają słabą skuteczność wyszukiwania. Gdy przechodzisz przez etap określania rozmiaru i nakładania się fragmentów, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrola przez ludzi oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dopiero późniejszej optymalizacji.

DEFAULT_CHUNK_SIZE = 800      # characters
DEFAULT_CHUNK_OVERLAP = 150   # characters
stride = chunk_size − chunk_overlap
       = 800 − 150
       = 650 characters
"…but left school at the age of ten."

Co zawiera rekord w magazynie wektorowym

Etap „Co zawiera rekord w magazynie wektorowym” funkcjonuje najlepiej, gdy traktowany jest jako mierzalna struktura. Zapisz jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres badania. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok zawiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Rozdziel politykę dzielenia na fragmenty od polityki wyszukiwania. Zmiana jednej z nich nie powinna zmuszać do przepisywania drugiej wraz ze zmianą wskaźników jakości.

id
document
embedding
metadata
id         7c2a1e90-4b11-4d3e-9f08-12a6c0e84b21

document   "His boyhood in Boston was a stern beginning of the habit
            of hard work and rigid economy which marked the man. For
            a year he went to the Latin Grammar School on School
            Street, but left off at the age of ten to help his father
            in making soap and candles."

embedding  384 floats — [-0.0412, 0.0187, 0.0621, -0.0094, 0.0330, …]
           norm = 1.0

metadata   {
             book: "Franklin's Autobiography",
             source: "https://www.gutenberg.org/cache/epub/36151/pg36151-images.html",
             gutenberg_id: 36151,
             page_label: "5",
             chunk_index: 2
           }

Dlaczego ważna jest normalizacja

Etap analizy znaczenia normalizacji działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię. Zapisz jeden idealny przekaz, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Oddziel zasadę dzielenia na fragmenty od zasady wyszukiwania. Zmiana jednej z nich nie powinna zmuszać do przepisywania drugiej, gdy zmieniają się metryki jakości.

‖v‖ = √(v₁² + v₂² + … + vₙ²)
cos θ = (a · b) / (‖a‖ ‖b‖)
If ‖a‖ = ‖b‖ = 1:
cos θ = a · b

Limit tokenów, którego nie możesz zobaczyć

Limity tokenów w fazie testowej działają najlepiej, gdy traktuje się je jako coś mierzalnego. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy przechodzi się z środowiska demonstracyjnego do współdzielonych środowisk. Przydziel budżet tokenów na każdy ruch i sesję. Narzędzia typu agentic intensywnie rozszerzają kontekst; sztywne limity zapobiegają temu, by demonstracje przerodziły się w niespodziewane rachunki. Limity tokenów w fazie testowej działają najlepiej, gdy traktuje się je jako coś mierzalnego. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Zdokumentuj zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrola przez ludzi oraz obsługa wiadomości błędowych są częścią produktu, a nie elementem dodatkowej obróbki później.

maximum safe chunk size in characters
≈ model token limit × 4

Kawałki kodu

W fazie fragmentów kodu należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy preferować małe, łatwe do przetestowania jednostki zamiast rozbudowanych skryptów. Gdy dany krok zawiedzie, powód awarii powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowaną strukturę procesów. Należy podawać konkretne fragmenty tekstu, które stanowią podstawę odpowiedzi. Bez tych odniesień operatorzy nie będą w stanie odróżnić fałszywych informacji od braków w indeksowaniu.

from rag_qa.gutenberg import load_pages
from rag_qa.chunk import chunk_documents
from rag_qa.config import load_settings

s = load_settings()
print(s.summary())
# {
#   'chunk_size_chars': 800,
#   'chunk_overlap_chars': 150,
#   'stride_chars': 650,            # size − overlap; this sets chunk count
#   'model': 'all-MiniLM-L6-v2',
#   'model_max_tokens': 256,        # hard cap; overflow is silent
#   'embedding_dims': 384,
#   'max_safe_chunk_chars': 1024,   # 256 × 4
#   'book': "Franklin's Autobiography",
#   'gutenberg_id': 36151,
# }
pages = load_pages()
chunks = chunk_documents(pages, s.chunk_size, s.chunk_overlap)
print(len(pages), len(chunks), s.stride)
from sentence_transformers import SentenceTransformer
from rag_qa.tokens import check_chunk

m = SentenceTransformer("all-MiniLM-L6-v2")
print(m.max_seq_length)                    # 256
for c in chunks:
    r = check_chunk(c)
    if r.truncated:
        print("silent truncate:", r.n_chars, "chars /", r.n_tokens, "tokens")
256
256
silent truncate: 1820 chars / 412 tokens
silent truncate: 960 chars / 301 tokens
from rag_qa.store import ingest, open_store

store = open_store()
ingest(chunks, store)
row = store.get(limit=1)
print(row["ids"][0])
print(row["documents"][0][:200])
print(len(row["embeddings"][0]), row["metadatas"][0])
# 384 floats, norm 1.0, metadata.page_label == printed [Pg N]
doc-12-p3-c0
She left school at the age of ten. The next sentence continues on the same page…
384 {'page_label': '3', 'source': 'notes.pdf'}
from rag_qa.retrieve import search, search_mmr

q = "why did Franklin want Britain to keep Canada"

for hit in search(q, k=5):
    print(f"{hit['score']:.3f}  p.{hit['metadata']['page_label']}  {hit['document'][:120]}")
# overlap makes near-duplicate hits; MMR trades a little score for diversity

for hit in search_mmr(q, k=5):
    print(hit["metadata"]["page_label"], hit["score"])
0.812  p.7  I have long been of opinion that the foundations of the future grandeur and stability of the British empire lie in America
0.781  p.7  they are, nevertheless, broad and strong enough to support the greatest political structure that human wisdom ever yet
0.744  p.7  I am, therefore, by no means for restoring Canada. If we keep it all the country from the St. Lawrence to the Mississippi
0.691  p.8  I left England about the end of August, 1762, in company with ten sail of merchant ships
0.640  p.6  In this Autobiography Franklin tells of his own life to the year 1757, when he went to England

Dodatek

W fazie Dodatku należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Traktuj tę fazę jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Podaj fragmenty tekstu, które faktycznie stanowią podstawę odpowiedzi. Bez tych odniesień operatorzy nie będą w stanie odróżnić halucynacji od luki w indeksowaniu.

A. Ten sam fragment, z przerwami w pokryciu

W fazie nakładania się tych samych fragmentów tekstu należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy rejestrować czasy wykonywania operacji oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do współdzielonych środowisk. Należy wskazać konkretne fragmenty tekstu, które stanowiły podstawę odpowiedzi. Bez tych odniesień operatorzy nie są w stanie odróżnić halucynacji od braku danych w indeksie. W fazie nakładania się tych samych fragmentów tekstu należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie uruchomić ten krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg procesu, jak i ścieżki naprawcze. Próby ponownego wykonania, kontrole ludzkie oraz obsługa błędów stanowią część produktu, a nie elementy dodawane później.

[0] 59  His boyhood in Boston was a stern beginning of the habit of
[1] 55  hard work and rigid economy which marked the man. For a
[2] 58  year he went to the Latin Grammar School on School Street,
[3] 31  but left off at the age of ten.
[0] 59  His boyhood in Boston was a stern beginning of the habit of
[1] 57  ⟦the habit of⟧ hard work and rigid economy which marked the
[2] 55  ⟦marked the⟧ man. For a year he went to the Latin Grammar
[3] 58  ⟦Latin Grammar⟧ School on School Street, but left off at the
[4] 22  ⟦off at the⟧ age of ten.
⟦…⟧ = text repeated from the previous chunk

B. Biblioteki do budowania RAG oraz miejsce przechowywania wektorów

Podczas pracy nad etapem bibliotek do budowania, najpierw zapisz specyfikację: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Wolno preferować małe, testowalne jednostki nad rozbudowane skrypty. Gdy jakiś krok się nie powiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Zmierz stopień odzyskiwania informacji na ustalonej serii pytań przed dostosowywaniem promptów. Częste zmiany promptów rzadko naprawiają słabe możliwości wyszukiwania.

Lista kontrolna operacyjna

Etap listy kontrolnej operacyjnej działa najlepiej, gdy jest traktowany jako mierzalna struktura. Zapisz jeden idealny przykład działania, jeden przypadek niepowodzenia oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy.

Zachowaj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury.

Rozdziel politykę dzielenia na fragmenty od polityki pobierania danych. Zmiana jednej z nich nie powinna zmuszać do przepisywania drugiej w przypadku zmian wskaźników jakości.

Gdy budżet na to pozwala, dodaj test sprawdzający kluczową ścieżkę w procesie CI przy użyciu narzędzi testowych, a nie rzeczywistych płatnych API.

Zdokumentuj zarówno prawidłową ścieżkę działania, jak i ścieżkę odzyskiwania po awarii. Próby ponownych działań, kontrola przez ludzi oraz obsługa wiadomości błędowych stanowią część produktu, a nie element późniejszej optymalizacji.

Rozdziel politykę dzielenia na fragmenty od polityki pobierania danych. Zmiana jednej z nich nie powinna zmuszać do przepisywania drugiej w przypadku zmian wskaźników jakości.

Zanim zaczniesz promować tę architekturę, zamroź wersje, utwórz dokładny zapis dla kluczowych etapów realizacji oraz potwierdź kroki odwracania zmian. Środowiska współdzielone wymagają ograniczeń szybkości, weryfikacji przynależności użytkowników oraz wyraźnego właściciela odpowiedzialnego za rotację haseł. Wolimy nudną niezawodność od pomysłowych, jednorazowych demonstracji.

Uwaga dotycząca 62ec22cbf28d: trzymaj klucze dostawcy poza repozytorium, ustaw ograniczenie liczby tokenów na sesję oraz przechowuj zapisy obok plików testowych, aby późniejsze zmiany modeli pozostawały porównywalne.