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

292
README.md
View File

@ -1,30 +1,89 @@
# 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
@ -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
@ -82,11 +142,19 @@ 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:
@ -101,15 +169,25 @@ Swagger UI:
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
@ -125,7 +203,10 @@ 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:
@ -139,11 +220,22 @@ 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`:
@ -157,32 +249,165 @@ 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í:
@ -197,18 +422,23 @@ Bežné automatizované testy:
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.