RAG w produkcji. Jak zbudować własnego asystenta AI ze swoją bazą wiedzy
Pierwszy raz zbudowałem RAG dla klienta w 2024. Kancelaria prawna, tysiące dokumentów, ChatGPT miał być “asystentem prawnika”. Wtedy myślałem, że to prosta rzecz. Fine-tuning nie potrzebny, wystarczy embedding plus vector database.
Pierwsze pół roku RAG działał źle. Odpowiedzi były prawdopodobne, ale nie prawdziwe. Prawnik trafiał na halucynacje, przestawał ufać systemowi. Klient rozważał zamknięcie projektu.
Potem zainwestowałem 2 miesiące w chunking, reranking, evaluation, guardrails. Po tym RAG działał. Prawnik używa go codziennie. Dokładność powyżej 90% na typowych zapytaniach.
Ten post to wszystko, czego nauczyłem się w tej podróży. Nie akademicki wykład o RAG. Konkretne architektury, cost analysis, częste błędy.
Co to jest RAG (bez marketingu)
RAG (Retrieval Augmented Generation) to technika łączenia modelu językowego z bazą wiedzy. Zamiast polegać tylko na wiedzy modelu (którą ma z treningu), wyszukujesz relevantne dokumenty i wstawiasz je do promptu.
Pipeline:
- Query user (“Jak wygląda procedura X?”)
- Retrieval (wyszukanie relevantnych dokumentów w bazie)
- Augmentation (włączenie znalezionych dokumentów do promptu)
- Generation (model generuje odpowiedź na podstawie query + retrieved docs)
Model “widzi” tylko to, co znalazłeś. Jeśli retrieval jest zły, odpowiedź będzie zła.
Kiedy RAG ma sens
Ma sens:
- Baza wiedzy specyficzna dla firmy (procedury, produkty, klienci)
- Dane, które zmieniają się (dokumentacja, ceny, polityki)
- Duża baza dokumentów, których nie zmieścisz w kontekście modelu
- Compliance / audit trail wymagany (“skąd wziąłeś tę odpowiedź”)
Nie ma sensu:
- Ogólna wiedza (Wikipedia, general reasoning) - model już to zna
- Bardzo mała baza (30 dokumentów) - wstaw wszystko do promptu
- Zadania wymagające deep reasoning, nie faktów - RAG nie pomoże
- Real-time data (giełda, pogoda) - użyj API tools
Podstawowy pipeline
Minimalny RAG w praktyce:
Krok 1: chunking. Dzielisz dokumenty na kawałki (200-1000 tokenów). Każdy kawałek staje się osobnym rekordem do wyszukania.
Krok 2: embedding. Każdy kawałek przechodzi przez embedding model (OpenAI, Cohere, own). Wynik: 1500-dimensional vector.
Krok 3: vector storage. Vectors zapisywane w vector database (Pinecone, pgvector, Weaviate).
Krok 4: retrieval. User pyta pytanie. Pytanie też przechodzi przez embedding. Vector database zwraca top-K najbliższych kawałków.
Krok 5: prompting. Prompt: “Odpowiedz na pytanie na podstawie kontekstu: [retrieved chunks]. Pytanie: [user question]”.
Krok 6: generation. Model odpowiada. User dostaje odpowiedź.
To wszystko. Prostote na papierze. Diabeł w detalach.
Gdzie boli w produkcji
Konkretnie, co pękało w moich projektach.
Problem 1: bad chunking. Zła strategia dzielenia dokumentów = złe search results.
Naiwne: dziel na 500 znaków. Wynik: przecinasz zdania, chunki nie mają sensu.
Lepsze: dziel po paragrafach, sekcjach, semantycznych granicach. Overlap 10-20% między chunkami (bo relevantna informacja może się rozciągać).
Najlepsze: hierarchiczne chunking. Duże chunki dla ogólnego kontekstu, małe dla precyzyjnych faktów. Retrieval na obu poziomach.
Problem 2: bad retrieval. Model retrieval nie łapie tego, co potrzeba.
Techniki poprawy:
- Hybrid search: kombinacja semantic (embedding) + keyword (BM25). Semantic łapie “aboutness”, keyword łapie konkretne terminy.
- Reranking: pierwszy retrieval zwraca top-50, reranker (Cohere, cross-encoder) sortuje ponownie i zwraca top-5 dla LLM.
- Query rewriting: user pyta “jak wypłacić pieniądze”. LLM przepisuje na “procedura wypłaty środków z konta”, robi retrieval na tym.
- Multi-query: LLM generuje 3-5 wariantów query, robi retrieval na każdym, łączy wyniki.
Problem 3: halucynacje mimo retrieval. Model dostaje kontekst, ignoruje go, halucynuje.
Fix: explicit instructions w prompt (“Odpowiedz WYŁĄCZNIE na podstawie dostarczonego kontekstu. Jeśli w kontekście nie ma odpowiedzi, powiedz ‘Nie wiem’”). Plus post-generation check: extract cited sources i weryfikuj.
Problem 4: outdated content. Dokumenty się zmieniają. Twój index jest stary.
Fix: cron jobs update index. Delta detection (co się zmieniło od ostatniego indexu). W kancelarii prawnej codzienny reindex.
Problem 5: privacy/security. Wyciek danych między klientami. Embedding jednego klienta widoczny w search innego.
Fix: multi-tenant vector DB z filtrami. Każdy chunk ma metadata client_id, retrieval filtruje.
Vector database: wybór
Pinecone: managed, świetne performance, drogi. Free tier 100k vectors, potem od $70/miesiąc.
pgvector (PostgreSQL extension): tanie, self-hosted, dobre performance dla <10M vectors. Mój default dla projektów >50k dokumentów.
Weaviate: open source, mocne semantic search, filters. Wybór dla complex queries.
Qdrant: open source, wydajny, dobre filters. Rising star, konkurencja dla Weaviate.
Chroma: embedded, dev-friendly. Prototypy tak. Produkcja niekoniecznie.
Redis Vector Search: jeśli już masz Redis. Wystarcza dla <1M vectors, prosty use case.
Dla większości projektów: pgvector. Prostszy stack (jedna baza), tańszy, wystarcza do dobrej skali. Powyżej 10M vectors: Pinecone albo Weaviate.
Pisałem szerzej o wyborze bazy. pgvector dodaje vector search do świata SQL.
Embedding model: wybór
OpenAI text-embedding-3-large (albo -small): standard w branży. Dobra jakość, tanie ($0.13/M tokens dla large). Wady: closed source, dane idą do OpenAI.
Cohere Embed v3: konkurencja dla OpenAI, świetna dla multilingual (włącznie z polskim). $0.10/M tokens.
Voyage AI: niche player, doskonała jakość, drogie.
BGE / E5 (open source): Twoje własne, self-hosted. Free, ale wymaga infrastructure. Wybór dla privacy-sensitive projektów.
Mój standard: OpenAI text-embedding-3-large dla większości. Cohere dla multilingual heavy projekty. Own hosting dla klientów fintech z sensitive data.
Reranking: gdzie 90% jakości RAG lezy
Retrieval zwraca top-K semantic matches. Nie zawsze są to najlepsze matches dla konkretnego pytania.
Reranker to model, który dla każdego kandydata liczy relevance score względem query.
Cohere Rerank v3: managed API, świetne wyniki, $2/M tokens. Standard w branży.
Cross-encoder (open source, jina, mixedbread): self-hosted, wolniejsze, ale free.
LLM as reranker: użyj GPT-4/Claude do rankingu. Najdroższe, ale najlepsze.
Reranking to zwykle różnica między “OK” a “świetnym” RAG. Warty każdego dolara.
Pipeline z reranking:
- Retrieval top-50 (fast, semantic)
- Rerank top-50 (slower, better quality)
- Top-5 do LLM
Dodaje 500ms latency, ale poprawia dokładność o 30-50%.
Chunking strategies w praktyce
Konkretne dla różnych typów danych.
Techniczna dokumentacja: chunking po sekcjach markdown, plus preserve headers jako metadata.
def chunk_markdown(content):
sections = split_by_headers(content)
chunks = []
for section in sections:
if len(section.text) < 1000:
chunks.append({
"text": section.text,
"header_path": section.header_path, # metadata
})
else:
sub_chunks = split_by_paragraphs(section.text, max_size=500)
for sub in sub_chunks:
chunks.append({
"text": sub,
"header_path": section.header_path,
})
return chunks
Dokumenty prawne: chunking po artykułach/paragrafach. Preserve document_id, article_number w metadata.
Emaile/chaty: chunking po thread/conversation. Include timestamp, sender w metadata.
Kod: chunking po funkcjach/klasach, nie liniach. Include file_path, function_name.
PDF-y: OCR jeśli scan, potem chunking jak Markdown. Include page_number.
Zły chunking = zła jakość. Zainwestuj czas w tę część.
Metadata: sekret dobrego retrieval
Każdy chunk to nie tylko tekst. To tekst plus struktura.
Przykład dla kancelarii prawnej:
{
"text": "Artykuł 8. Umowa najmu wymaga formy pisemnej...",
"metadata": {
"document_type": "kodeks_cywilny",
"article_number": "8",
"chapter": "III",
"last_updated": "2024-01-15",
"confidence": "high",
"client_visible": true
}
}
Retrieval z filtrami:
- User pyta o “umowa najmu” → filter document_type=kodeks_cywilny
- User z klientem premium → filter client_visible=true
- User w projekcie z 2023 → filter last_updated<2024
Metadata pozwala na precyzyjne retrieval bez customowej fine-tuning.
Evaluation: jak wiedzieć, że RAG działa
Bez ewaluacji budujesz w ciemno.
Manual evaluation: 100-200 realnych pytań plus expected answers. Regularnie sprawdzasz, czy RAG odpowiada dobrze.
LLM-as-judge: LLM sprawdza, czy odpowiedź RAG odpowiada na pytanie i czy jest poparta contextem. Automatic, skalowalny.
Retrieval metrics: precision@K, recall@K. Ile z retrieved chunks jest naprawdę relevantnych.
End-to-end metrics:
- Faithfulness: czy odpowiedź jest podparta contextem (nie halucynacja)?
- Answer relevance: czy odpowiedź pasuje do pytania?
- Context relevance: czy retrieved chunks pasują do pytania?
Narzędzia: RAGAS, TruLens, LangSmith. Wszystkie robią to samo, wybierz jedno.
Regel: bez continuous evaluation nie wiesz, czy release’y poprawiają czy pogarszają.
Koszty
Konkretnie dla RAG w kancelarii prawnej (mój case):
Setup jednorazowy:
- Embedding 100k chunków × 500 tokens × $0.13/M = $6.5
- Vector DB setup: 0 (pgvector w istniejącej Postgres)
Miesięcznie:
- 500 queries dziennie × 30 dni = 15k queries
- Każde query: embedding query + retrieval + reranking + LLM
- Embedding query: 15k × 100 tokens × $0.13/M = $0.20
- Rerank: 15k × 50 candidates × $2/M = $1.5
- LLM (Claude Sonnet): 15k × 5k tokens input + 500 tokens output = $45 + $22.5 = $67.5
Miesięczny koszt inference: ~$70. Klient zaoszczędza 60h/miesiąc pracy prawnika. ROI natychmiastowy.
Za większą skalę (50k queries dziennie) koszty rosną do $2000-5000 miesięcznie. Nadal ROI positive, ale bardziej wymaga optymalizacji (caching, mniejsze modele).
Deployment i architektura
Mój standard stack dla RAG w produkcji:
Frontend: Next.js z chat interface
Backend: Node.js API (albo Python FastAPI)
Vector DB: PostgreSQL z pgvector extension
Embedding: OpenAI API
Reranking: Cohere API
LLM: Claude Sonnet 4 przez OpenRouter (dla redundancy)
Observability: Langfuse (open source) albo LangSmith
Queue: BullMQ dla async processing (index update)
Auth: NextAuth albo Clerk
Deployment: Next.js na Vercel, Postgres na Neon albo self-hosted, Redis dla queue.
Setup takiego stack: 3-5 dni pracy. Dopracowanie do produkcji: 4-8 tygodni.
Advanced techniki (dla większej dokładności)
Kiedy standard RAG nie wystarcza:
Query decomposition: skomplikowane pytanie (“Compare X i Y w kontekście Z”) rozbite na sub-queries przez LLM. Retrieval na każdym, kombinacja wyników.
HyDE (Hypothetical Document Embeddings): LLM generuje hipotetyczną odpowiedź na pytanie. Embedding tej odpowiedzi używany do retrieval (nie query). Często lepiej łapie relevantne dokumenty.
Recursive retrieval: retrieval → LLM ocenia, czy wystarczy → jeśli nie, sformułuj nowe query → retrieval → LLM.
Graph RAG: budujesz knowledge graph z dokumentów. Retrieval działa na graf plus embeddings. Świetny dla domen z jasnymi relations (medycyna, prawo).
Adaptive RAG: różne strategie retrieval dla różnych typów pytań. LLM klasyfikuje pytanie, wybiera strategię.
Te techniki dodają 20-40% dokładności, ale znacznie komplikują system. Wprowadzaj tylko, kiedy prosty RAG naprawdę nie wystarcza.
Fine-tuning vs RAG
Częste pytanie od klientów: “Nie lepiej fine-tunować model?”
Fine-tuning: uczysz model konkretnej wiedzy przez trenowanie. Wiedza wbudowana w wagi modelu.
RAG: wiedza w bazie, model tylko wyszukuje.
Kiedy fine-tuning:
- Konkretny styl output (napiszę jak marka X)
- Bardzo specyficzny domain language (medyczny, prawniczy jargon)
- Wysoki throughput (fine-tune tańsze per query niż RAG)
Kiedy RAG:
- Zmieniające się dane (fine-tune to re-train co release)
- Compliance/audit (musisz pokazać źródło)
- Duża baza wiedzy (fine-tune limited by model capacity)
- Multi-tenant (każdy klient ma swoje dane)
Napisałem osobny post fine-tuning vs RAG vs prompting. Krótko: w 90% przypadków RAG wygrywa.
Częste błędy
Ignoring evaluation. Budujesz RAG, wygląda dobrze na demo, wypuszczasz. Klient znajduje 30 halucynacji. Bez continuous eval jesteś ślepy.
Bad chunking without testing. Losowa strategia chunking, potem miesiąc “dlaczego RAG jest zły”. Testuj chunking na golden dataset od dnia 1.
Skipping reranking. Semantic search sam daje mediocre wyniki. Reranking to 2x jakość za 20% cost.
Overengineering. Zaczyna od GraphRAG plus HyDE plus multi-query. Prosty RAG nie działa, complex się psuje. Zacznij prosto.
Ignoring costs. Budujesz prototyp, wypuszczasz, dostajesz $5000 bill. Add spending caps, monitor, alerts.
Zero guardrails. RAG odpowiada wszystko. Klient prosi “napisz mi email do konkurencji”. RAG pisze. Bad. Add domain restrictions w prompt.
Co czytać dalej
- “Building LLM-Powered Applications” Valentina Alto. Praktyczna, świeża.
- LangChain docs on RAG. Konceptualnie dobre, przykłady niekoniecznie best practice.
- Anthropic’s cookbook on RAG. Krótkie, ale solidne przykłady.
- Papers: HyDE, RAG-Fusion, RAPTOR. Advanced techniques.
Unikaj kursów “RAG w 24h za 500 zł”. Podstawy są w free tutorials, resztę uczysz się przez projekt.
Od czego zacząć
Jeśli chcesz zbudować pierwszego RAG:
- Wybierz konkretny use case. “Q&A na dokumentacji techniczną firmy X”.
- Zbierz golden dataset: 50-100 par (pytanie, expected answer) od real users.
- Zbuduj MVP: pgvector + OpenAI embedding + Claude jako LLM. 2 dni pracy.
- Testuj na golden datasec. Zbierz metryki.
- Iteruj: chunking, retrieval, reranking. Każda zmiana testowana.
- Deploy z observability. Loguj queries, retrievals, responses.
- Feedback loop: user ratings, incident reports, continuous improvement.
RAG jest jedną z najlepszych aplikacji AI dla firm. Jeśli klient ma dużą bazę wiedzy, którą pracownicy muszą przeszukiwać, RAG płaci się w 3-6 miesięcy.
Napisałem też o AI agents i MCP. RAG często łączy się z tymi dwoma - agent używający RAG jako tool to potężny wzorzec 2026.
Ten obszar rośnie 5x rocznie. Programiści z RAG w portfolio będą mieć przewagę na rynku pracy przez najbliższe 3-5 lat.
Powiązane wpisy
-
N8n dla agencji. Automatyzacje, które oszczędzają mi 10 godzin tygodniowo w agencji
W 2024 płaciłem Zapierowi 400 zł miesięcznie za 15 automatyzacji. W 2025 przeszedłem na n8n self-hosted. Płacę 40 zł ...