Files
DBAdmin/inbox/todo/artykuł-jak-zbudować-projekt-generative-ai-llm-rag-w-sposób-produkcyjny.md
T
2026-05-18 06:40:19 +00:00

433 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
type: Note
---
# Artykuł: „Jak zbudować projekt Generative AI (LLM + RAG) w sposób produkcyjny”
Pewnie — zrobię z tej struktury **(1) artykuł** (czytelny, edukacyjny) oraz **(2) procedurę operacyjną (SOP/runbook)**, tak żeby dało się to wdrożyć i utrzymywać w zespole.
***
# 1) Artykuł: „Jak zbudować projekt Generative AI (LLM + RAG) w sposób produkcyjny”
## Wstęp
Zbudowanie działającego prototypu opartego na modelu językowym (LLM) i architekturze RAG (Retrieval-Augmented Generation) w notatniku Jupyter zajmuje dziś zaledwie kilka godzin. Jednak droga od "działającego dema" do stabilnego, skalowalnego i bezpiecznego systemu produkcyjnego to zupełnie inne wyzwanie techniczne.
Wiele projektów Generative AI umiera na etapie Proof of Concept (PoC) lub szybko przeradza się w trudną do utrzymania plątaninę skryptów. Dlaczego? Ponieważ na etapie skalowania zaczyna brakować w nich **wyraźnego podziału odpowiedzialności**, **powtarzalnego pipeline'u danych**, **wersjonowania promptów** oraz **twardych zasad testowania i automatyzacji**.
W tym artykule omówimy, jak ustrukturyzować produkcyjne repozytorium dla projektu AI. Pokażę Ci sprawdzony szkielet architektury, który:
- **bezboleśnie obsługuje wielu dostawców modeli** (OpenAI, Anthropic, modele lokalne),
- **posiada dedykowany moduł RAG** i uporządkowany pipeline ekstrakcji danych,
- **separuje warstwę inżynierii promptów** od logiki biznesowej aplikacji,
- **jest w pełni gotowy do konteneryzacji** (Docker) i wdrażania w cyklach CI/CD.
Jeśli chcesz, aby Twoje systemy sztucznej inteligencji opierały się na solidnych fundamentach inżynierii oprogramowania, a nie tylko "magii promptów" ten przewodnik jest dla Ciebie.
***
## Cel architektury: porządek zamiast „magii”
W systemach GenAI najbardziej kosztowne błędy biorą się z:
1. braku wersjonowania i powtarzalności danych / indeksów,
2. braku kontroli nad promptami (zmiany „na żywo” bez śladu),
3. braku testów regresji (model/prompt/dane zmieniają zachowanie),
4. mieszania logiki RAG z logiką aplikacji.
Ta struktura rozwiązuje to przez **jasne granice** między warstwami.
***
## Omówienie katalogów „co gdzie mieszka i dlaczego”
## `config/` konfiguracja projektu
Tu trzymasz pliki konfiguracyjne:
- `model_config.yaml` wybór modelu, ustawienia (temperatura, max tokens), klucze API lub referencje do secret managera,
- `logging_config.yaml` format logów, poziomy, destynacje, korelacja requestów.
**Dlaczego to ważne?**\
\
Konfiguracja nie powinna być „zaszyta” w kodzie, bo będziesz przełączać modele i tryby (dev/stage/prod), a logowanie jest podstawą operacyjności.
***
## `data/` dane projektu (artefakty)
Podział:
- `cache/` przetworzone dane, cache odpowiedzi, snapshoty,
- `embeddings/` wygenerowane embeddingi (np. batch do dalszego indeksowania),
- `vectordb/` pliki/bazy vector store (w zależności od technologii).
**Zasada**: to nie jest „źródło prawdy” (source of truth), tylko **artefakty** powstające z danych wejściowych i pipelineu.\
\
W produkcji warto dodać:
- politykę retencji,
- wersjonowanie indeksów,
- metadane: data budowy, model embeddingów, parametry chunkingu.
***
## `src/` kod aplikacji (serce systemu)
### `src/core/` abstrakcja LLM i integracje
Pliki typu:
- `base_llm.py` wspólny interfejs (send(), generate(), stream(), itp.),
- `gpt_client.py` klient do OpenAI,
- `claude_client.py` klient do Anthropic,
- `local_llm.py` klient do modeli lokalnych,
- `model_factory.py` fabryka wybierająca backend na podstawie configu.
**Korzyść**: aplikacja nie jest „przyspawana” do jednego dostawcy. Zmiana modelu = zmiana configu.
***
### `src/prompts/` narzędzia do promptów
- `templates.py` szablony promptów (np. Jinja), stałe sekcje system/developer/user,
- `chain.py` chaining: wieloetapowe promptowanie (np. plan → wykonanie → walidacja).
**Dyscyplina**: prompty są „kodem”, więc:
- powinny mieć wersjonowanie,
- powinny mieć testy,
- powinny mieć style guide.
***
### `src/rag/` moduł Retrieval-Augmented Generation
- `embedder.py` generowanie embeddingów dla chunków,
- `retriever.py` wyszukiwanie dokumentów (top-k, MMR, filtry),
- `vector_store.py` wrapper na bazę wektorową,
- `indexer.py` indeksowanie dokumentów (ETL → chunk → embed → store).
**To jest warstwa**, która „przynosi wiedzę” do LLM.\
\
RAG powinien być **odseparowany**, bo ma osobny cykl życia: indeksy budujesz/odświeżasz niezależnie od inference.
***
### `src/processing/` przygotowanie danych (pipeline)
- `chunking.py` dzielenie tekstu na segmenty,
- `tokenizer.py` pomocnicze funkcje tokenizacji,
- `preprocessor.py` czyszczenie danych (usuwanie śmieci, normalizacja, deduplikacja).
**Dlaczego osobno?**\
\
Bo zmiany w chunkingu/tokenizacji potrafią totalnie zmienić jakość RAG i koszt embeddingów. To musi być testowalne i mierzalne.
***
### `src/inference/` wykonanie i format odpowiedzi
- `inference_engine.py` spina prompt + RAG + LLM, zarządza parametrami,
- `response_parser.py` walidacja/formatowanie outputu (np. JSON schema, ekstrakcja pól).
**Klucz**: inference to osobny etap od budowy indeksu.
***
## `tests/` testowanie (w tym regresja promptów)
- `unit/`
- `test_llm_clients.py` testy klientów (mocki, retry, limity),
- `test_prompts.py` testy promptów (np. czy zawierają wymagane sekcje).
- `integration/`
- `test_end_to_end.py` e2e: pipeline od query do odpowiedzi,
- `test_api_integration.py` testy integracji API.
W GenAI testy powinny obejmować:
- „czy to się uruchamia” (klasyczne),
- „czy to daje sensowny wynik” (regresja jakości, choćby heurystyczna),
- „czy output ma poprawny format” (parser/validator).
***
## `scripts/` automatyzacja (operacyjnie krytyczna)
- `setup_env.sh` setup środowiska,
- `run_tests.sh` uruchomienie testów,
- `build_embeddings.py` budowa embeddingów,
- `cleanup.py` sprzątanie artefaktów.
Ten katalog to most między repo a operacjami: CI/CD, cron, joby w platformie.
***
## Pliki root: `.gitignore`, `Dockerfile`, `docker-compose.yml`, `requirements.txt`
To zapewnia:
- przenośność,
- powtarzalność środowiska,
- szybki start dla dev/test.
***
## Podsumowanie: jak myśleć o tym repo
Masz tu trzy kluczowe „pętle życia”:
1. **Data/Index lifecycle**: processing → embeddings → vectordb
2. **Inference lifecycle**: query → retriever → prompt → LLM → response_parser
3. **Ops lifecycle**: config → logging → scripts → tests → docker/compose
Takie podejście skraca czas debugowania, ogranicza ryzyko regresji i ułatwia wejście nowych osób do projektu.
***
***
# 2) Procedura operacyjna (SOP): Utrzymanie i rozwój projektu Generative AI (LLM + RAG)
Poniższe SOP jest „do użycia” — możesz wkleić do wewnętrznej dokumentacji zespołu.
## 2.1 Cel SOP
Zapewnić powtarzalny, bezpieczny i kontrolowany proces:
- budowy indeksów RAG,
- uruchamiania inference,
- wdrażania zmian w promptach/modelach,
- monitorowania i diagnostyki.
## 2.2 Zakres
Dotyczy repozytorium o strukturze:
- `config/`, `data/`, `src/`, `tests/`, `scripts/` oraz plików root.
## 2.3 Role i odpowiedzialności
- **Operator/On-call**: uruchamia procedury, reaguje na alerty, wykonuje rollback.
- **Maintainer**: zatwierdza zmiany w promptach/pipeline, dba o standardy testów.
- **Owner produktu**: zatwierdza zmiany jakościowe (np. zmiana modelu).
## 2.4 Definicje
- **Index build**: proces zasilenia `vectordb/` na podstawie dokumentów.
- **Embedding model**: model użyty do wektorów (wpływa na kompatybilność indeksu).
- **Chunking params**: parametry dzielenia tekstu (wpływ na recall/precision).
***
## 2.5 Procedura: Setup środowiska (pierwsze uruchomienie)
**Wejście**: czyste środowisko dev/stage/prod\
\
**Wyjście**: działające środowisko uruchomieniowe
1. Sklonuj repo i przejdź do katalogu projektu.
2. Uruchom:
```bash
scripts/setup_env.sh
```
1. Zweryfikuj, że konfiguracje istnieją:
- `config/model_config.yaml`
- `config/logging_config.yaml`
2. Uruchom testy smoke:
```bash
scripts/run_tests.sh
```
**Kryterium akceptacji**: testy przechodzą; logi zapisują się zgodnie z config.
***
## 2.6 Procedura: Budowa / odświeżenie indeksu RAG
**Wejście**: dane źródłowe (dokumenty), parametry chunkingu, model embeddingów\
\
**Wyjście**: nowy indeks w `data/vectordb/` oraz artefakty w `data/embeddings/`
### Krok po kroku
1. **Pre-flight** (kontrola przed startem):
- sprawdź wolne miejsce na dysku,
- potwierdź wybrany embedding model w `model_config.yaml`,
- sprawdź parametry chunkingu w `src/processing/chunking.py` (lub config jeśli tak ustalisz).
2. Uruchom budowę embeddingów:
```bash
python scripts/build_embeddings.py
```
1. Walidacja:
- czy `data/embeddings/` nie jest puste,
- czy `data/vectordb/` zawiera nowy stan indeksu,
- czy logi nie pokazują błędów rate-limit/timeout.
2. (Opcjonalnie) Test integracyjny RAG:
```bash
pytest -q tests/integration/test_end_to_end.py
```
**Kryterium akceptacji**: indeks zbudowany, test e2e przechodzi.
### Rollback
- zachowuj poprzedni katalog indeksu jako `vectordb_prev/` (lub snapshot wolumenu).
- rollback polega na podmianie wskazania na poprzedni indeks (symlink/konfiguracja).
***
## 2.7 Procedura: Uruchomienie inference (obsługa zapytań)
**Wejście**: zapytanie użytkownika, konfiguracja modelu, dostęp do vectordb\
\
**Wyjście**: odpowiedź sformatowana przez `response_parser.py`
1. Sprawdź, czy indeks istnieje i jest dostępny.
2. Sprawdź, jaki model jest aktywny (config).
3. Uruchom komponent aplikacji (zależnie od tego, jak startujesz projekt: CLI/API).
4. W logach weryfikuj:
- czas retrieval,
- liczba pobranych dokumentów (top-k),
- czas odpowiedzi LLM,
- błędy parsera odpowiedzi.
**Kryterium akceptacji**: odpowiedź spełnia format, brak błędów w logach.
***
## 2.8 Procedura: Zmiana promptów (kontrolowana)
**Ryzyko**: prompt changes = natychmiastowa zmiana zachowania systemu.
### Zasady
1. Każda zmiana w `src/prompts/` wymaga:
- PR,
- testu `tests/unit/test_prompts.py`,
- krótkiego opisu „dlaczego zmiana” i „jak mierzymy efekt”.
2. Minimalna walidacja:
- „zachowanie” na 510 przykładowych zapytaniach (golden set),
- poprawność formatu outputu (parser/validator).
### Kroki
1. Zmiana w `templates.py` / `chain.py`.
2. Testy:
```bash
scripts/run_tests.sh
```
1. E2E:
```bash
pytest -q tests/integration/test_end_to_end.py
```
1. Deploy (zgodnie z pipeline).
2. Monitoring po wdrożeniu: error-rate i czas odpowiedzi.
### Rollback
- revert commit / przywrócenie poprzednich promptów,
- jeśli zmiana promptów wymagała zmiany parsera — rollback obu.
***
## 2.9 Procedura: Zmiana modelu (GPT ↔ Claude ↔ Local)
**Ryzyko**: inne modele mają inne limity, styl, deterministykę.
1. Zmiana tylko w `config/model_config.yaml` (preferowane).
2. Wykonaj test klientów:
```bash
pytest -q tests/unit/test_llm_clients.py
```
1. Sprawdź rate limit / retry policy w logach.
2. Walidacja jakości na golden set.
3. Deploy etapami (canary jeśli możesz).
Rollback: powrót do poprzedniego configu.
***
## 2.10 Monitoring i diagnostyka (minimum operacyjne)
W logach muszą się pojawić (jako pola lub jednoznaczne wpisy):
- `request_id` / korelacja,
- czas: `retrieval_ms`, `llm_ms`, `total_ms`,
- `top_k`, `source_count`,
- `model_id`, `embedding_model_id`,
- błędy parsera i błędy narzędzi.
**W razie incydentu**:
1. Sprawdź logi `inference_engine.py` (czy problem po stronie RAG czy LLM).
2. Jeśli RAG:
- czy retriever zwraca wyniki,
- czy vectordb nie jest uszkodzone,
- czy filtry nie wykluczają wszystkiego.
3. Jeśli LLM:
- rate limit / auth / timeout,
- zmiana modelu lub parametrów.
***
## 2.11 Sprzątanie (retencja)
1. Uruchom:
```bash
python scripts/cleanup.py
```
1. Zasady:
- cache starszy niż X dni usuwać,
- embeddings trzymać wersjami (jeśli wspierasz multi-index),
- vectordb snapshotować przed nadpisaniem.
***
## 2.12 Checklisty (do wykorzystania „na szybko”)
### Checklist: Index build
- [ ] Dysk OK / miejsce OK
- [ ] Embedding model potwierdzony
- [ ] Chunking parametry potwierdzone
- [ ] Build embeddings wykonany
- [ ] Vectordb zaktualizowane
- [ ] Test e2e OK
- [ ] Snapshot/rollback przygotowany
### Checklist: Prompt deploy
- [ ] PR + opis zmiany
- [ ] Unit test promptów OK
- [ ] Parser kompatybilny
- [ ] Golden set OK
- [ ] Monitoring po deploy OK
- [ ] Plan rollback gotowy
***
## Co dalej?
Jeśli chcesz, dopracuję to pod Twoje standardy operacyjne:
1. **Wersja w org-mode** (wiem, że to Twój „single source of truth”).
2. Dodanie sekcji „Bezpieczeństwo i sekrety”: gdzie trzymać API keys (vault/ENV), co w `.gitignore`.
3. Dodanie „Quality Gates”: golden set, metryki RAG (recall@k), regresja promptów.
4. Gotowy „Runbook incidentowy”: *RAG returns empty*, *LLM timeouts*, *parser errors*, *vectordb corruption*.
Powiedz tylko: **czy to ma być SOP pod dev/test**, czy **pod produkcję (on-call, incident response, change management)** i w jakim środowisku odpalasz (Docker/VM/K8s)?