TL;DR
RAG (Retrieval-Augmented Generation) to chatbot, który przed odpowiedzią wyszukuje relevantne fragmenty w bazie wiedzy, a dopiero potem generuje tekst LLM. Kluczowe elementy: chunking, embeddingi, magazyn wektorowy (np. pgvector w Branchly) i prompt z cytowanymi źródłami. Poniżej pipeline od PDF/FAQ do API w Next.js — techniczny kąt uzupełniający artykuł o treści bazy wiedzy, nie o samym pisaniu FAQ.
Dla kogo
- Zespołów produktowych wdrażających chatbot na stronie firmowej lub w SaaS
- Developerów szukających alternatywy dla „wrzuć cały regulamin do promptu”
- Firm z setkami stron dokumentacji, gdzie fine-tuning modelu nie ma sensu ekonomicznego
- CTO oceniających koszt inference vs jakość odpowiedzi
Fraza (SEO)
rag chatbot wdrożenie, embeddings vector search, pgvector nextjs, chatbot ai baza wiedzy technicznie 2026
RAG vs prompt stuffing — dlaczego embeddingi
| Podejście | Limit | Koszt | Aktualizacja wiedzy |
|---|---|---|---|
| Cały FAQ w system prompt | Okno kontekstu (~128k tokenów i mniej efektywnie) | Wysoki przy każdym pytaniu | Ręczna edycja promptu |
| Fine-tuning | Drogi, wolna iteracja | Jednorazowy + retrain | Retrain |
| RAG + embeddings | Skaluje do tysięcy chunków | Embedding raz + tanie query | Re-index chunków |
Embedding to wektor (np. 1536 wymiarów) reprezentujący semantykę akapitu. Pytanie użytkownika też staje się wektorem — szukasz najbliższych sąsiadów cosinusowych, nie dopasowania słów kluczowych.
Pipeline wdrożenia — 6 kroków
[Dokumenty] → chunking → embedding API → [vector store]
↓
[User question] → embedding → top-k retrieval → prompt + LLM → odpowiedź + źródła- Ingest — markdown z repo, PDF oferty, eksport FAQ z Branchly
- Chunking — 400–800 tokenów, overlap 50–100, nagłówek w metadanych
- Embed —
text-embedding-3-small(tańszy) lub-large(dokładniejszy) - Store — tabela
document_chunksz kolumnąembedding vector(1536) - Query — embed pytania →
ORDER BY embedding <=> query_vec LIMIT 5 - Generate — GPT-4o-mini z instrukcją: „Odpowiedz tylko na podstawie kontekstu”
Chunking — praktyyczne reguły
Źle pocięty tekst = złe odpowiedzi, nawet z dobrym modelem.
- Dziel po nagłówkach Markdown (
##), nie na środku zdania - Do metadanych:
source_url,locale,updated_at,section_title - Tabele i listy cen — osobny chunk z kontekstem „Cennik 2026”
- Duplikaty między PL/EN — osobne embeddingi per język, filtr
localew query
Przykład rekordu w Branchly (branchly.cloud) z pgvector:
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE document_chunks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
content TEXT NOT NULL,
embedding vector(1536),
source_url TEXT,
locale TEXT DEFAULT 'pl',
updated_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX ON document_chunks
USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);Dla <10k chunków wystarczy ivfflat; powyżej rozważ HNSW lub dedykowany silnik (Qdrant, Pinecone) — nadal możliwe jako rozszerzenie tego samego API.
Kod ingest w Next.js
// scripts/ingest-knowledge.ts
import OpenAI from 'openai';
import { db } from '@/lib/db';
const openai = new OpenAI();
async function embedAndStore(chunks: { text: string; meta: ChunkMeta }[]) {
for (const batch of chunk(chunks, 50)) {
const res = await openai.embeddings.create({
model: 'text-embedding-3-small',
input: batch.map((c) => c.text),
});
for (let i = 0; i < batch.length; i++) {
await db.$executeRaw`
INSERT INTO document_chunks (content, embedding, source_url, locale)
VALUES (
${batch[i].text},
${JSON.stringify(res.data[i].embedding)}::vector,
${batch[i].meta.sourceUrl},
${batch[i].meta.locale}
)
`;
}
}
}Uruchamiasz po deployu treści lub z cron na DevStudioIT Cloud — nie przy każdym pytaniu użytkownika.
Endpoint chat z RAG
// app/api/chat/route.ts
import OpenAI from 'openai';
import { streamText } from 'ai';
export async function POST(req: Request) {
const { message, locale } = await req.json();
const queryEmbedding = await embed(message);
const chunks = await db.$queryRaw<Chunk[]>`
SELECT content, source_url
FROM document_chunks
WHERE locale = ${locale}
ORDER BY embedding <=> ${queryEmbedding}::vector
LIMIT 5
`;
const context = chunks.map((c, i) => `[${i + 1}] ${c.content}`).join('\n\n');
return streamText({
model: openai('gpt-4o-mini'),
system: `Odpowiadaj po polsku. Używaj wyłącznie kontekstu poniżej. Jeśli brak danych — powiedz, że nie wiesz.
Kontekst:
${context}`,
messages: [{ role: 'user', content: message }],
});
}Front-end: widget na stronie firmowej z linkami do source_url pod odpowiedzią — buduje zaufanie i redukuje halucynacje.
Jakość retrieval — co poprawia trafność
- Hybrid search: BM25 (pełnotekst w Postgres) + vector, merge wyników — lepsze na SKU i kody produktów
- Re-ranking: po top-20 wektorowym, cross-encoder lub LLM wybiera top-5 (drożej, precyzyjniej)
- Query rewrite: LLM przepisuje pytanie użytkownika na „search query” przed embed
- Threshold: jeśli max similarity < 0,75 — odpowiedź „Nie mam tej informacji” zamiast zgadywania
Loguj question, chunk_ids, similarity scores w Branchly — co tydzień review 20 rozmów z niskim score.
Koszty i latency (orientacyjnie 2026)
- Embedding 1M tokenów
text-embedding-3-small: rząd wielkości kilku USD - GPT-4o-mini z 2k tokenów kontekstu: grosze na rozmowę
- pgvector query <50 ms przy indeksie — bottleneck to LLM (TTFT ~300–800 ms)
- Cache embeddingów dla identycznych pytań (hash normalized question) — 30% oszczędności na support FAQ
Hosting na DevStudioIT Cloud (devstudioit.cloud): Route Handler ze streamingiem, limity rate per IP, klucze OpenAI w env.
Bezpieczeństwo i RODO
- Nie indeksuj danych osobowych klientów, wewnętrznych cenników B2B
- Rate limiting i CAPTCHA na publicznym
/api/chat - Retencja logów rozmów — polityka 90 dni, anonimizacja
- Informacja w polityce prywatności o przetwarzaniu przez OpenAI (DPA, region EU jeśli wymagane)
Metryki sukcesu po wdrożeniu
Po 4 tygodniach produkcji mierz:
- Answer accuracy — ręczna ocena 50 losowych rozmów (cel: >85% trafnych)
- Fallback rate — ile razy bot odmawia z powodu niskiego similarity (cel: 10–20%, nie 0% — zero oznacza overfitting)
- Średnia liczba chunków w kontekście vs latency
- Kliknięcia w source_url pod odpowiedzią — proxy zaufania użytkownika
Dashboard w Branchly: tabela chat_logs z kolumnami question, chunk_ids, user_rating (thumbs up/down w UI). Iteruj chunking co kwartał, nie codziennie — stabilność odpowiedzi ważniejsza niż chase na 100% accuracy.
FAQ
Czy RAG zastępuje artykuł o bazie wiedzy?
Nie — tam opisujemy co wrzucić (FAQ, regulaminy). Tu jak technicznie wyszukać i wygenerować odpowiedź.
pgvector vs Pinecone?
pgvector w Branchly = mniej moving parts dla małego/średniego projektu. Pinecone/Qdrant gdy >500k chunków lub multi-tenant z izolacją.
Jak często re-index?
Przy zmianie treści na stronie — webhook z CMS → partial re-ingest zmienionych URL-i, nie cała baza.
Czy można bez OpenAI?
Tak — lokalne modele embedding (Ollama, sentence-transformers) + Llama; trade-off: jakość PL i ops GPU.
Co z wielojęzycznością?
Filtr locale w SQL + osobne chunki; nie mieszaj PL i DE w jednym embed bez normalizacji języka pytania.
CTA
Potrzebujesz chatbota, który cytuje Waszą dokumentację zamiast wymyślać?
- Wycena RAG chatbot — architektura, Branchly pgvector, Next.js, DevStudioIT Cloud
- Chatbot AI dla firmy — proces biznesowy i koszty
O autorze
Budujemy szybkie strony WWW, aplikacje web/mobile, chatboty AI i hosting — z naciskiem na SEO i konwersję.
Przydatne linki
Od teorii do produkcji — Branchly, hosting i realizacje.
