From 9dc45a687bbf26b5ee01dd4a3ab821da61c9f793 Mon Sep 17 00:00:00 2001 From: jp170na Date: Thu, 13 Aug 2026 21:41:53 +0200 Subject: [PATCH] readme --- README.md | 358 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 294 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index bae2098..ef1fdad 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,93 @@ # ZP Agent -Backend pre indexovanie a vyhľadávanie v repozitári záverečných prác `zpwiki`. +Backend pre indexovanie, hybridné vyhľadávanie a RAG nad repozitárom +záverečných prác `zpwiki`. -Projekt načítava Markdown dokumenty, spracuje YAML metadata, rozdelí obsah na tokenové chunky a vytvorí SQLite index kombinujúci FTS5 fulltextové vyhľadávanie a embeddingy. Vyhľadávanie je dostupné cez FastAPI a systém podporuje manuálnu aj webhookovú synchronizáciu. +Projekt načítava Markdown dokumenty, spracuje YAML metadata, rozdelí +obsah na tokenové chunky a vytvorí SQLite index kombinujúci FTS5 +fulltextové vyhľadávanie a embeddingy. Nad hybridným vyhľadávaním je +vytvorená RAG vrstva, ktorá pripravuje kontext, zdroje a pravidlá pre +odpoveď jazykového modelu. API je integrované so školským OpenWebUI ako +OpenAPI Tool Server. ## Implementované -- načítanie Markdown súborov a YAML front matter, -- normalizácia názvov, autorov, tagov, kategórií a `published`, -- tokenové chunkovanie pomocou `tiktoken`, -- zachovanie názvu dokumentu a hierarchie nadpisov v chunku, -- SQLite databáza a FTS5 fulltextový index, -- BM25 vyhľadávanie s podporou diakritiky a prefixových výrazov, -- embeddingy pre každý chunk pomocou modelu `intfloat/multilingual-e5-small`, -- uloženie embeddingov priamo v SQLite, -- vektorové vyhľadávanie pomocou cosine similarity, -- hybridné vyhľadávanie FTS5 + embeddings pomocou RRF, -- nižšia váha pre slabú `any_term` FTS stratégiu, -- zachovanie presných `all_terms` a `prefix_terms` výsledkov bez vektorového šumu, -- filtrovanie publikovaných dokumentov, -- FastAPI endpointy `/health`, `/search`, `/sync` a `/webhook/gitea`, -- autorizácia `/search` a `/sync` pomocou API kľúča, -- Gitea webhook s HMAC-SHA256 podpisom a kontrolou udalosti a repozitára, -- zámok proti súbežnému reindexovaniu, -- atomická výmena databázy po úspešnom reindexovaní, -- automatizované a integračné testy. +- načítanie Markdown súborov a YAML front matter, +- normalizácia názvov, autorov, tagov, kategórií a `published`, +- tokenové chunkovanie pomocou `tiktoken`, +- konfigurovateľná maximálna veľkosť chunku, overlap a minimálna + veľkosť chunku, +- zachovanie názvu dokumentu a hierarchie nadpisov v chunku, +- SQLite databáza a FTS5 fulltextový index, +- BM25 vyhľadávanie s podporou diakritiky a prefixových výrazov, +- vyhľadávacie stratégie `all_terms`, `prefix_terms` a `any_term`, +- embeddingy pre každý chunk pomocou modelu + `intfloat/multilingual-e5-small`, +- uloženie embeddingov priamo v SQLite, +- vektorové vyhľadávanie pomocou cosine similarity, +- hybridné vyhľadávanie FTS5 + embeddings pomocou RRF, +- nižšia váha pre slabú `any_term` FTS stratégiu, +- zachovanie presných `all_terms` a `prefix_terms` výsledkov bez + vektorového šumu, +- obmedzenie počtu výsledkov z jedného dokumentu pomocou + `max_per_document`, +- filtrovanie publikovaných dokumentov, +- generovanie `source_url` pre dohľadateľnosť výsledkov, +- RAG vrstva s pripraveným kontextom, zdrojmi a pravidlami pre + grounded odpoveď, +- pravidlá proti používaniu neoverených informácií a zamieňaniu + rôznych typov údajov, +- FastAPI endpointy `/health`, `/rag`, `/search`, `/sync` a + `/webhook/gitea`, +- autorizácia vyhľadávania pomocou `X-API-Key` alebo Bearer tokenu, +- autorizácia `/sync` pomocou samostatného API kľúča, +- CORS konfigurácia pre OpenWebUI, +- integrácia s OpenWebUI cez OpenAPI Tool Server, +- Gitea webhook s HMAC-SHA256 podpisom a kontrolou udalosti a + repozitára, +- zámok proti súbežnému reindexovaniu, +- atomická výmena databázy po úspešnom reindexovaní, +- persistentná Hugging Face cache v Docker volume, +- warm-up embeddingového modelu, +- automatizované a integračné testy vrátane RAG endpointu. + +## Architektúra + +``` text +zpwiki + ↓ +Markdown + YAML + ↓ +normalizácia dokumentov + ↓ +tokenové chunkovanie + ↓ +SQLite +├── dokumenty a metadata +├── chunky +├── FTS5 +└── embeddingy + ↓ +hybridné vyhľadávanie +├── FTS5 / BM25 +└── embeddingové vyhľadávanie + ↓ +RRF fusion + ↓ +RAG kontext + zdroje + ↓ +FastAPI /rag + ↓ +OpenWebUI / ZP Agent + ↓ +jazykový model + ↓ +odpoveď so source_url +``` ## Štruktúra -```text +``` text zp-agent/ ├── app/ │ └── main.py @@ -38,6 +97,7 @@ zp-agent/ │ ├── build_chunks.py │ ├── build_sqlite_index.py │ ├── embedding_utils.py +│ ├── rag_utils.py │ ├── rebuild_index.py │ ├── search_db.py │ └── search_utils.py @@ -52,7 +112,7 @@ zp-agent/ Projekt očakáva repozitáre v tejto štruktúre: -```text +``` text ~/DP/ ├── zpwiki/ └── zp-agent/ @@ -62,7 +122,7 @@ Projekt očakáva repozitáre v tejto štruktúre: V koreňovom priečinku vytvor `.env`: -```dotenv +``` dotenv WEBHOOK_SECRET= SYNC_API_KEY= SEARCH_API_KEY=<ďalšia náhodná hodnota s minimálne 32 znakmi> @@ -76,48 +136,66 @@ EMBEDDING_BATCH_SIZE=32 Tajomstvá je možné vygenerovať príkazom: -```bash +``` bash openssl rand -hex 32 ``` Súbor `.env` sa nesmie commitovať. +Chunkovanie je možné konfigurovať pomocou premenných prostredia: + +``` dotenv +CHUNK_MAX_TOKENS=450 +CHUNK_OVERLAP_TOKENS=70 +CHUNK_MIN_TOKENS=80 +CHUNK_TOKEN_ENCODING=cl100k_base +``` + ## Spustenie cez Docker -```bash -docker compose build -docker compose up -d +``` bash +docker compose up -d --build ``` Kontrola služby: -```bash +``` bash curl http://127.0.0.1:8000/health ``` Swagger UI: -```text +``` text http://127.0.0.1:8000/docs ``` +Logy: + +``` bash +docker compose logs -f zp-agent-api +``` + Zastavenie: -```bash +``` bash docker compose down ``` +Hugging Face cache je uložená v persistentnom Docker volume, takže sa +embeddingový model pri bežnom reštarte kontajnera nemusí znova sťahovať. + ## Reindexovanie -Celý proces načíta dokumenty, vytvorí chunky, obnoví FTS5 index a vytvorí embedding pre každý chunk: +Celý proces načíta dokumenty, vytvorí chunky, obnoví FTS5 index a +vytvorí embedding pre každý chunk: -```bash +``` bash docker compose run --rm zp-agent-api python scripts/rebuild_index.py ``` Vzniknú súbory: -```text +``` text data/documents.json data/chunks.json data/zp_index.sqlite @@ -125,11 +203,14 @@ data/zp_index.sqlite Databáza obsahuje dokumenty, chunky, FTS5 index, metadata a embeddingy. -## Vyhľadávanie +Pri automatickom reindexovaní sa používa zámok proti súbežnému spusteniu +a atomická výmena databázy po úspešnom vytvorení nového indexu. + +## Hybridné vyhľadávanie Vyhľadávanie kombinuje: -```text +``` text dotaz ├── FTS5 / BM25 └── embeddingové vyhľadávanie @@ -139,16 +220,27 @@ dotaz výsledky ``` +FTS5 používa stratégie: + +``` text +all_terms +prefix_terms +any_term +``` + +Presné lexikálne výsledky majú prednosť pred slabšími sémantickými +zhodami. Pri slabšej `any_term` stratégii sa znižuje jej váha a väčší +význam môže dostať embeddingové vyhľadávanie. + Test z terminálu: -```bash -docker compose run --rm zp-agent-api \ - python scripts/search_db.py "rag agent" --limit 5 +``` bash +docker compose run --rm zp-agent-api python scripts/search_db.py "rag agent" --limit 5 ``` Pred volaním API načítaj premenné z `.env`: -```bash +``` bash set -a source .env set +a @@ -156,59 +248,197 @@ set +a Vyhľadávanie cez zabezpečené API: -```bash -curl -X POST http://127.0.0.1:8000/search \ - -H "Content-Type: application/json" \ - -H "X-API-Key: $SEARCH_API_KEY" \ - -d '{ - "query": "rag agent", - "limit": 5, +``` bash +curl -X POST http://127.0.0.1:8000/search -H "Content-Type: application/json" -H "Authorization: Bearer $SEARCH_API_KEY" -d '{ + "query": "strojový preklad", + "limit": 3, "published_only": false, - "max_per_document": 3 + "max_per_document": 1 }' ``` -API vracia hybridný engine: +API používa hybridný engine: -```text +``` text hybrid_fts5_embeddings ``` +`max_per_document=1` zabezpečí, že sa pri požiadavke na viac výsledkov +preferujú rôzne dokumenty namiesto viacerých chunkov z rovnakého +dokumentu. + +## RAG + +Nad hybridným retrievalom je implementovaná RAG vrstva v +`scripts/rag_utils.py`. + +Endpoint `/rag` vyhľadá relevantné dokumenty a pripraví: + +- textový kontext pre jazykový model, +- metadata použitých zdrojov, +- názov a autora dokumentu, +- `source_url`, +- interné retrieval informácie, +- pravidlá pre grounded odpoveď. + +RAG pravidlá požadujú, aby model odpovedal iba podľa poskytnutých +zdrojov. Zároveň rozlišujú údaje, ktoré sa môžu ľahko zameniť, napríklad +autora dokumentu, osobu, o ktorej dokument pojednáva, rok začiatku +štúdia a rok záverečnej práce. + +Príklad: + +``` bash +curl -X POST http://127.0.0.1:8000/rag -H "Content-Type: application/json" -H "Authorization: Bearer $SEARCH_API_KEY" -d '{ + "query": "V akom roku robil Ján Holp diplomovú prácu?", + "limit": 5, + "published_only": false, + "max_per_document": 1 + }' +``` + +## OpenWebUI + +ZP Agent je pripojený do OpenWebUI ako OpenAPI Tool Server. + +OpenWebUI používa: + +``` text +OpenAPI URL: http://localhost:8000/openapi.json +Authentication: Bearer +Token: SEARCH_API_KEY +``` + +V reálnom nasadení musí byť URL API dostupná z prostredia, v ktorom beží +OpenWebUI; `localhost` je vhodný iba vtedy, ak sa OpenWebUI pripája k +API z rovnakého hostiteľa. + +OpenAPI schéma určená pre integráciu vystavuje RAG nástroj, ktorý môže +jazykový model použiť pri otázkach nad ZP Wiki. + +Tok požiadavky: + +``` text +používateľ + ↓ +OpenWebUI + ↓ +jazykový model + ↓ +ZP Agent /rag + ↓ +hybrid retrieval + ↓ +RAG kontext + zdroje + ↓ +jazykový model + ↓ +odpoveď +``` + +Príklad otázky: + +``` text +Použi ZP Agent a zisti, v akom roku robil Ján Holp diplomovú prácu. +``` + +Výsledná odpoveď obsahuje stručnú informáciu získanú zo ZP Wiki a +príslušný `source_url`. + +## Manuálna synchronizácia + Manuálne reindexovanie cez zabezpečený endpoint: -```bash -curl -X POST http://127.0.0.1:8000/sync \ - -H "Content-Type: application/json" \ - -H "X-API-Key: $SYNC_API_KEY" \ - -d '{"pull_git": false}' +``` bash +curl -X POST http://127.0.0.1:8000/sync -H "Content-Type: application/json" -H "X-API-Key: $SYNC_API_KEY" -d '{"pull_git": false}' ``` +## Gitea webhook + +Endpoint: + +``` text +POST /webhook/gitea +``` + +Webhook overuje: + +- HMAC-SHA256 podpis, +- typ Gitea udalosti, +- očakávaný repozitár, +- stav reindexovacieho zámku. + +Očakávaný repozitár: + +``` dotenv +EXPECTED_GITEA_REPOSITORY=KEMT/zpwiki +``` + +Ak je povolené: + +``` dotenv +WEBHOOK_PULL_GIT=true +``` + +pred reindexovaním sa vykoná: + +``` bash +git pull --ff-only +``` + +## Bezpečnosť + +Vyhľadávanie podporuje API key: + +``` text +X-API-Key: +``` + +aj Bearer autentifikáciu: + +``` text +Authorization: Bearer +``` + +Bearer autentifikácia sa používa najmä pri integrácii s OpenWebUI. + +Endpoint `/sync` používa samostatný `SYNC_API_KEY` a webhook samostatný +`WEBHOOK_SECRET`. + +Tajomstvá sa ukladajú do `.env`, ktorý nesmie byť súčasťou Git +repozitára. + ## Testy Inštalácia testovacích závislostí: -```bash +``` bash pip install -r requirements-dev.txt ``` Bežné automatizované testy: -```bash +``` bash pytest -q test ``` -Aktuálna testovacia sada: +Aktuálny stav: -```text -65 passed, 2 skipped +``` text +77 passed, 2 skipped ``` -Testy vrátane kontroly reálne vygenerovaných dát a databázy: +Testy vrátane kontroly reálnych dát a databázy: -```bash +``` bash RUN_LIVE_TESTS=1 pytest -q test ``` -## Ďalší krok +Aktuálny stav: -Najbližšia etapa je integrácia s OpenWebUI a vytvorenie agentového rozhrania. Následne sa doplnia RAG odpovede so zdrojmi a citáciami. +``` text +79 passed +``` + +Testovacia sada pokrýva indexovanie, vyhľadávanie, hybridný retrieval, +API, autentifikáciu, RAG utility, RAG endpoint a OpenAPI integráciu.