This commit is contained in:
Ján Pták 2026-08-13 21:41:53 +02:00
parent f67de6dcaa
commit 9dc45a687b

332
README.md
View File

@ -1,34 +1,93 @@
# ZP Agent # 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é ## Implementované
- načítanie Markdown súborov a YAML front matter, - načítanie Markdown súborov a YAML front matter,
- normalizácia názvov, autorov, tagov, kategórií a `published`, - normalizácia názvov, autorov, tagov, kategórií a `published`,
- tokenové chunkovanie pomocou `tiktoken`, - 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, - zachovanie názvu dokumentu a hierarchie nadpisov v chunku,
- SQLite databáza a FTS5 fulltextový index, - SQLite databáza a FTS5 fulltextový index,
- BM25 vyhľadávanie s podporou diakritiky a prefixových výrazov, - BM25 vyhľadávanie s podporou diakritiky a prefixových výrazov,
- embeddingy pre každý chunk pomocou modelu `intfloat/multilingual-e5-small`, - 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, - uloženie embeddingov priamo v SQLite,
- vektorové vyhľadávanie pomocou cosine similarity, - vektorové vyhľadávanie pomocou cosine similarity,
- hybridné vyhľadávanie FTS5 + embeddings pomocou RRF, - hybridné vyhľadávanie FTS5 + embeddings pomocou RRF,
- nižšia váha pre slabú `any_term` FTS stratégiu, - 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, - 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, - filtrovanie publikovaných dokumentov,
- FastAPI endpointy `/health`, `/search`, `/sync` a `/webhook/gitea`, - generovanie `source_url` pre dohľadateľnosť výsledkov,
- autorizácia `/search` a `/sync` pomocou API kľúča, - RAG vrstva s pripraveným kontextom, zdrojmi a pravidlami pre
- Gitea webhook s HMAC-SHA256 podpisom a kontrolou udalosti a repozitára, 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, - zámok proti súbežnému reindexovaniu,
- atomická výmena databázy po úspešnom reindexovaní, - atomická výmena databázy po úspešnom reindexovaní,
- automatizované a integračné testy. - 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 ## Štruktúra
```text ``` text
zp-agent/ zp-agent/
├── app/ ├── app/
│ └── main.py │ └── main.py
@ -38,6 +97,7 @@ zp-agent/
│ ├── build_chunks.py │ ├── build_chunks.py
│ ├── build_sqlite_index.py │ ├── build_sqlite_index.py
│ ├── embedding_utils.py │ ├── embedding_utils.py
│ ├── rag_utils.py
│ ├── rebuild_index.py │ ├── rebuild_index.py
│ ├── search_db.py │ ├── search_db.py
│ └── search_utils.py │ └── search_utils.py
@ -52,7 +112,7 @@ zp-agent/
Projekt očakáva repozitáre v tejto štruktúre: Projekt očakáva repozitáre v tejto štruktúre:
```text ``` text
~/DP/ ~/DP/
├── zpwiki/ ├── zpwiki/
└── zp-agent/ └── zp-agent/
@ -62,7 +122,7 @@ Projekt očakáva repozitáre v tejto štruktúre:
V koreňovom priečinku vytvor `.env`: V koreňovom priečinku vytvor `.env`:
```dotenv ``` dotenv
WEBHOOK_SECRET=<náhodná hodnota s minimálne 32 znakmi> WEBHOOK_SECRET=<náhodná hodnota s minimálne 32 znakmi>
SYNC_API_KEY=<iná náhodná hodnota s minimálne 32 znakmi> SYNC_API_KEY=<iná náhodná hodnota s minimálne 32 znakmi>
SEARCH_API_KEY=<ďalšia náhodná hodnota s minimálne 32 znakmi> 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: Tajomstvá je možné vygenerovať príkazom:
```bash ``` bash
openssl rand -hex 32 openssl rand -hex 32
``` ```
Súbor `.env` sa nesmie commitovať. 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 ## Spustenie cez Docker
```bash ``` bash
docker compose build docker compose up -d --build
docker compose up -d
``` ```
Kontrola služby: Kontrola služby:
```bash ``` bash
curl http://127.0.0.1:8000/health curl http://127.0.0.1:8000/health
``` ```
Swagger UI: Swagger UI:
```text ``` text
http://127.0.0.1:8000/docs http://127.0.0.1:8000/docs
``` ```
Logy:
``` bash
docker compose logs -f zp-agent-api
```
Zastavenie: Zastavenie:
```bash ``` bash
docker compose down 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 ## 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 docker compose run --rm zp-agent-api python scripts/rebuild_index.py
``` ```
Vzniknú súbory: Vzniknú súbory:
```text ``` text
data/documents.json data/documents.json
data/chunks.json data/chunks.json
data/zp_index.sqlite data/zp_index.sqlite
@ -125,11 +203,14 @@ data/zp_index.sqlite
Databáza obsahuje dokumenty, chunky, FTS5 index, metadata a embeddingy. 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: Vyhľadávanie kombinuje:
```text ``` text
dotaz dotaz
├── FTS5 / BM25 ├── FTS5 / BM25
└── embeddingové vyhľadávanie └── embeddingové vyhľadávanie
@ -139,16 +220,27 @@ dotaz
výsledky 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: Test z terminálu:
```bash ``` bash
docker compose run --rm zp-agent-api \ docker compose run --rm zp-agent-api python scripts/search_db.py "rag agent" --limit 5
python scripts/search_db.py "rag agent" --limit 5
``` ```
Pred volaním API načítaj premenné z `.env`: Pred volaním API načítaj premenné z `.env`:
```bash ``` bash
set -a set -a
source .env source .env
set +a set +a
@ -156,59 +248,197 @@ set +a
Vyhľadávanie cez zabezpečené API: Vyhľadávanie cez zabezpečené API:
```bash ``` bash
curl -X POST http://127.0.0.1:8000/search \ curl -X POST http://127.0.0.1:8000/search -H "Content-Type: application/json" -H "Authorization: Bearer $SEARCH_API_KEY" -d '{
-H "Content-Type: application/json" \ "query": "strojový preklad",
-H "X-API-Key: $SEARCH_API_KEY" \ "limit": 3,
-d '{
"query": "rag agent",
"limit": 5,
"published_only": false, "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 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: Manuálne reindexovanie cez zabezpečený endpoint:
```bash ``` bash
curl -X POST http://127.0.0.1:8000/sync \ 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}'
-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: <SEARCH_API_KEY>
```
aj Bearer autentifikáciu:
``` text
Authorization: Bearer <SEARCH_API_KEY>
```
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 ## Testy
Inštalácia testovacích závislostí: Inštalácia testovacích závislostí:
```bash ``` bash
pip install -r requirements-dev.txt pip install -r requirements-dev.txt
``` ```
Bežné automatizované testy: Bežné automatizované testy:
```bash ``` bash
pytest -q test pytest -q test
``` ```
Aktuálna testovacia sada: Aktuálny stav:
```text ``` text
65 passed, 2 skipped 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 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.