RAG chatbot, embeddings, wyszukiwanie wektorowe i wdrożenie w 2026

rag5 min czytania20 lipca 2026

Autor: DevStudio.it

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
  1. Ingest, markdown z repo, PDF oferty, eksport FAQ z Branchly
  2. Chunking, 400–800 tokenów, overlap 50–100, nagłówek w metadanych
  3. Embed, text-embedding-3-small (tańszy) lub -large (dokładniejszy)
  4. Store, tabela document_chunks z kolumną embedding vector(1536)
  5. Query, embed pytania → ORDER BY embedding <=> query_vec LIMIT 5
  6. 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 locale w 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ć?

Powiązane wpisy

AI chatbot na stronie firmowej, kiedy się opłaca, a kiedy nie (2026)
9 min czytania
Chatbot AI w firmie: 7 scenariuszy, które realnie oszczędzają czas
6 min czytania
Chatbot AI dla firmy: jak wdrożyć i ile kosztuje w 2026
6 min czytania

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.

Podoba Ci się nasze podejście? Zbudujmy coś razem.

Rozpocznij konfigurację projektu