1010 lines
22 KiB
Markdown
1010 lines
22 KiB
Markdown
# ZP Agent
|
|
|
|
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. 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.
|
|
|
|
Súčasná hlavná retrieval vetva používa klasický hybridný RAG:
|
|
FTS5/BM25 + embeddingy + RRF. GraphRAG zatiaľ nie je implementovaný;
|
|
je preň pripravený samostatný evaluačný dataset a bude sa dopĺňať ako
|
|
ďalšia experimentálna vetva.
|
|
|
|
## Implementované
|
|
|
|
- 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,
|
|
- lexikálne zvýhodnenie presných alebo veľmi silných zhôd,
|
|
- 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ď,
|
|
- rozšírenie RAG kontextu o začiatok rovnakej sekcie
|
|
(`section-lead expansion`) bez globálneho zvýšenia
|
|
`max_per_document`,
|
|
- pravidlá proti používaniu neoverených informácií a zamieňaniu
|
|
rôznych typov údajov,
|
|
- no-answer správanie pri chýbajúcej alebo nedostatočne podloženej
|
|
informácii,
|
|
- FastAPI endpointy `/health`, `/rag`, `/search`, `/sync` a
|
|
`/webhook/gitea`,
|
|
- striktná validácia API vstupov,
|
|
- 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,
|
|
- bezpečnostné HTTP hlavičky,
|
|
- integrácia s OpenWebUI cez OpenAPI Tool Server,
|
|
- Gitea webhook s HMAC-SHA256 podpisom, limitom veľkosti payloadu 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,
|
|
- retrieval evaluácia pre FTS, embeddings a hybridný retrieval,
|
|
- answer-level RAG evaluácia cez OpenWebUI model a RAG tool,
|
|
- oddelené answer-level overrides bez úpravy frozen retrieval
|
|
benchmarku,
|
|
- príprava rozšírených datasetov pre extended RAG, GraphRAG,
|
|
robustness a performance experimenty.
|
|
|
|
## Architektúra
|
|
|
|
```text
|
|
zpwiki
|
|
↓
|
|
Markdown + YAML
|
|
↓
|
|
scan_zpwiki.py
|
|
↓
|
|
normalizované dokumenty
|
|
↓
|
|
build_chunks.py
|
|
↓
|
|
tokenové chunky
|
|
↓
|
|
build_sqlite_index.py
|
|
↓
|
|
SQLite
|
|
├── dokumenty
|
|
├── metadata
|
|
├── chunky
|
|
├── FTS5
|
|
└── embeddingy
|
|
↓
|
|
search_core.py / search_utils.py
|
|
↓
|
|
hybridné vyhľadávanie
|
|
├── FTS5 / BM25
|
|
├── embeddingové vyhľadávanie
|
|
└── RRF fusion + lexical anchor
|
|
↓
|
|
rag_utils.py
|
|
├── výber zdrojov
|
|
├── section-lead expansion
|
|
├── RAG kontext
|
|
└── grounding pravidlá
|
|
↓
|
|
FastAPI /rag
|
|
↓
|
|
OpenWebUI / ZP Agent
|
|
↓
|
|
jazykový model
|
|
↓
|
|
odpoveď + source_url
|
|
```
|
|
|
|
Synchronizačná vetva:
|
|
|
|
```text
|
|
Gitea push
|
|
↓
|
|
POST /webhook/gitea
|
|
↓
|
|
HMAC + repository + event validácia
|
|
↓
|
|
voliteľný git pull --ff-only
|
|
↓
|
|
rebuild_index.py
|
|
↓
|
|
nový SQLite index
|
|
↓
|
|
atomická výmena databázy
|
|
```
|
|
|
|
Evaluačná vetva:
|
|
|
|
```text
|
|
evaluation/json_files/*.json
|
|
↓
|
|
retrieval evaluator / RAG answer evaluator
|
|
↓
|
|
runner
|
|
↓
|
|
metriky
|
|
↓
|
|
evaluation/results/
|
|
```
|
|
|
|
`evaluation/results/` nie je v nižšie uvedenom stromčeku, pretože
|
|
obsahuje generované výstupy experimentov.
|
|
|
|
## Štruktúra projektu
|
|
|
|
Nižšie je funkčná štruktúra projektu. Testovacie súbory, generované
|
|
výsledky, cache, `__pycache__`, Git interné súbory a podobné pomocné
|
|
artefakty sú zámerne vynechané.
|
|
|
|
```text
|
|
zp-agent/
|
|
├── app/
|
|
│ ├── main.py
|
|
│ ├── routes.py
|
|
│ └── security.py
|
|
│
|
|
├── scripts/
|
|
│ ├── common.py
|
|
│ ├── scan_zpwiki.py
|
|
│ ├── build_chunks.py
|
|
│ ├── build_sqlite_index.py
|
|
│ ├── embedding_utils.py
|
|
│ ├── rag_utils.py
|
|
│ ├── rebuild_index.py
|
|
│ ├── search_db.py
|
|
│ ├── search_core.py
|
|
│ └── search_utils.py
|
|
│
|
|
├── evaluation/
|
|
│ ├── evaluate_retrieval.py
|
|
│ ├── retrieval_runner.py
|
|
│ ├── metrics.py
|
|
│ ├── evaluate_rag_answers.py
|
|
│ ├── rag_runner.py
|
|
│ ├── rag_metrics.py
|
|
│ └── json_files/
|
|
│ ├── questions.json
|
|
│ ├── questions_before_ambiguity_cleanup.json
|
|
│ ├── questions_before_validation.json
|
|
│ ├── rag_answer_overrides.json
|
|
│ ├── questions_extended_2000.json
|
|
│ ├── graphrag_questions.json
|
|
│ ├── robustness_questions.json
|
|
│ └── performance_queries.json
|
|
│
|
|
├── data/
|
|
│ ├── documents.json
|
|
│ ├── chunks.json
|
|
│ └── zp_index.sqlite
|
|
│
|
|
├── Dockerfile
|
|
├── docker-compose.yml
|
|
├── requirements.txt
|
|
├── requirements-dev.txt
|
|
└── README.md
|
|
```
|
|
|
|
### `app/`
|
|
|
|
`app/main.py`
|
|
|
|
- vytvára FastAPI aplikáciu,
|
|
- nastavuje lifespan aplikácie,
|
|
- validuje bezpečnostnú konfiguráciu pri štarte,
|
|
- vykonáva warm-up embeddingovej vrstvy,
|
|
- nastavuje CORS a bezpečnostné hlavičky,
|
|
- pripája API routery,
|
|
- ponecháva OpenAPI schému dostupnú pre OpenWebUI.
|
|
|
|
Interaktívne Swagger/Redoc rozhranie môže byť v produkčnej konfigurácii
|
|
vypnuté. Pre integráciu OpenWebUI je dôležitý endpoint:
|
|
|
|
```text
|
|
/openapi.json
|
|
```
|
|
|
|
`app/routes.py`
|
|
|
|
- definuje `/health`,
|
|
- definuje verejne publikovaný RAG nástroj `/rag`,
|
|
- obsahuje interné/zabezpečené `/search` a `/sync`,
|
|
- obsluhuje `/webhook/gitea`,
|
|
- vykonáva validáciu requestov a sanitizáciu chýb,
|
|
- používa reindexovací zámok,
|
|
- kontroluje webhook payload pred spracovaním.
|
|
|
|
`app/security.py`
|
|
|
|
- spracúva `SEARCH_API_KEY`,
|
|
- spracúva `SYNC_API_KEY`,
|
|
- spracúva `WEBHOOK_SECRET`,
|
|
- vyžaduje dostatočne dlhé a navzájom odlišné tajomstvá,
|
|
- používa bezpečné porovnávanie autentifikačných hodnôt,
|
|
- validuje očakávaný Gitea repozitár a súvisiacu konfiguráciu.
|
|
|
|
### `scripts/`
|
|
|
|
`common.py`
|
|
|
|
Spoločné utility a konfiguračné funkcie používané indexovacou a
|
|
vyhľadávacou vrstvou.
|
|
|
|
`scan_zpwiki.py`
|
|
|
|
- prechádza repozitár `zpwiki`,
|
|
- načítava Markdown a YAML front matter,
|
|
- normalizuje dokumentové metadata,
|
|
- pripravuje dokumenty na ďalšie spracovanie.
|
|
|
|
`build_chunks.py`
|
|
|
|
- rozdeľuje dokumenty na tokenové chunky,
|
|
- používa `tiktoken`,
|
|
- zachováva nadpisy, kódové bloky a tabuľky,
|
|
- podporuje tokenový overlap,
|
|
- eviduje token count a hash obsahu chunku.
|
|
|
|
`build_sqlite_index.py`
|
|
|
|
- vytvára SQLite databázu,
|
|
- ukladá dokumenty, chunky a metadata,
|
|
- vytvára FTS5 index,
|
|
- ukladá embeddingy do SQLite,
|
|
- pripravuje databázu pre hybridný retrieval.
|
|
|
|
`embedding_utils.py`
|
|
|
|
- načítava embeddingový model,
|
|
- vytvára embeddingy pre dokumenty a query,
|
|
- normalizuje vektory,
|
|
- poskytuje utility pre vektorové vyhľadávanie.
|
|
|
|
`search_core.py`
|
|
|
|
Nízkoúrovňové jadro vyhľadávania:
|
|
|
|
- normalizácia query,
|
|
- FTS5 vyhľadávanie,
|
|
- embeddingové vyhľadávanie,
|
|
- scoring,
|
|
- RRF fusion,
|
|
- lexical anchor,
|
|
- metadata,
|
|
- diverzifikácia výsledkov.
|
|
|
|
`search_utils.py`
|
|
|
|
Vyššia orchestration vrstva nad `search_core.py` a kompatibilné
|
|
vyhľadávacie utility používané ostatnými časťami projektu.
|
|
|
|
`search_db.py`
|
|
|
|
CLI rozhranie na ručné vyhľadávanie nad lokálnym SQLite indexom.
|
|
|
|
`rag_utils.py`
|
|
|
|
- zostavuje RAG kontext,
|
|
- pripravuje zdrojové metadata,
|
|
- pridáva `source_url`,
|
|
- aplikuje grounding pravidlá,
|
|
- podporuje no-answer správanie,
|
|
- rozširuje primárny chunk o začiatok rovnakej sekcie,
|
|
- zachováva väzbu medzi primárnym chunkom a section-lead chunkom.
|
|
|
|
`rebuild_index.py`
|
|
|
|
Orchestruje kompletný rebuild:
|
|
|
|
```text
|
|
scan
|
|
→ chunking
|
|
→ SQLite/FTS
|
|
→ embeddings
|
|
→ validácia
|
|
→ atomická výmena DB
|
|
```
|
|
|
|
### `evaluation/`
|
|
|
|
`evaluate_retrieval.py`
|
|
|
|
CLI vstup pre retrieval benchmark. Umožňuje spúšťať DEV, TEST alebo
|
|
celý dataset a používa strict dataset validáciu.
|
|
|
|
`retrieval_runner.py`
|
|
|
|
Spúšťa jednotlivé retrieval stratégie nad evaluačnými otázkami.
|
|
|
|
`metrics.py`
|
|
|
|
Počíta retrieval metriky, napríklad:
|
|
|
|
```text
|
|
Hit@1
|
|
Hit@3
|
|
Hit@5
|
|
MRR
|
|
Recall@5
|
|
```
|
|
|
|
`evaluate_rag_answers.py`
|
|
|
|
CLI vstup pre answer-level RAG evaluáciu. Hodnotí celý tok:
|
|
|
|
```text
|
|
otázka
|
|
→ OpenWebUI model
|
|
→ ZP Agent tool
|
|
→ /rag
|
|
→ finálna odpoveď
|
|
```
|
|
|
|
Podporuje answer-level overrides, aby nebolo potrebné meniť frozen
|
|
retrieval benchmark pri otázkach, ktoré sú pre generatívnu evaluáciu
|
|
nejednoznačné.
|
|
|
|
`rag_runner.py`
|
|
|
|
Spúšťa jednotlivé answer-level prípady a komunikuje s OpenWebUI/API.
|
|
|
|
`rag_metrics.py`
|
|
|
|
Počíta answer-level metriky, napríklad:
|
|
|
|
- prítomnosť očakávaných faktov,
|
|
- správnosť `source_url`,
|
|
- `should_answer`,
|
|
- použitie toolu,
|
|
- strict pass,
|
|
- latency a tokenové údaje.
|
|
|
|
### `evaluation/json_files/`
|
|
|
|
`questions.json`
|
|
|
|
Hlavný frozen benchmark pre klasický retrieval a RAG. Po zmrazení
|
|
benchmarku sa nemá meniť len preto, aby sa zlepšil výsledok answer-level
|
|
evaluácie.
|
|
|
|
`rag_answer_overrides.json`
|
|
|
|
Obsahuje iba answer-level úpravy formulácie alebo očakávaní pri
|
|
nejednoznačných otázkach. Retrieval benchmark tým ostáva nezmenený.
|
|
|
|
`questions_before_ambiguity_cleanup.json`
|
|
|
|
Historická záloha datasetu pred úpravami nejednoznačností.
|
|
|
|
`questions_before_validation.json`
|
|
|
|
Historická záloha datasetu pred validačnými úpravami.
|
|
|
|
`questions_extended_2000.json`
|
|
|
|
Rozšírený benchmark s presne 2000 otázkami. Je pripravený pre neskoršie
|
|
rozsiahlejšie experimenty nad klasickým retrievalom a RAG.
|
|
|
|
Obsahuje kombináciu:
|
|
|
|
- faktických otázok,
|
|
- parafráz,
|
|
- otázok bez diakritiky,
|
|
- preklepov,
|
|
- krátkych query,
|
|
- no-answer prípadov,
|
|
- negatívnej verifikácie,
|
|
- multi-document otázok,
|
|
- porovnávania,
|
|
- citation-oriented prípadov.
|
|
|
|
Tento dataset je zatiaľ pripravený, ale nemá sa používať na priebežné
|
|
ladenie frozen benchmarku.
|
|
|
|
`graphrag_questions.json`
|
|
|
|
Samostatný benchmark pripravený pre budúcu GraphRAG vetvu.
|
|
|
|
Obsahuje 500 otázok zameraných na:
|
|
|
|
- multi-hop vzťahy,
|
|
- spoločné témy,
|
|
- spoločné roky,
|
|
- person → title → year,
|
|
- person → topic → title,
|
|
- person → category → author,
|
|
- agregácie,
|
|
- konjunktívnu disambiguáciu,
|
|
- multi-document reasoning.
|
|
|
|
Dataset obsahuje aj GraphRAG metadata ako:
|
|
|
|
```text
|
|
graph.task
|
|
graph.hop_count
|
|
graph.start_entities
|
|
graph.expected_entities
|
|
graph.expected_relations
|
|
graph.expected_paths
|
|
```
|
|
|
|
Dôležité: existencia tohto datasetu neznamená, že je GraphRAG už
|
|
implementovaný. Dataset je pripravený na neskorší vývoj a porovnanie.
|
|
|
|
`robustness_questions.json`
|
|
|
|
Samostatný dataset s 200 otázkami pre testovanie robustnosti.
|
|
|
|
Pokrýva napríklad:
|
|
|
|
- chýbajúcu diakritiku,
|
|
- preklepy,
|
|
- nekonzistentnú kapitalizáciu a interpunkciu,
|
|
- nerelevantný šum,
|
|
- prompt injection,
|
|
- konfliktné tvrdenia používateľa,
|
|
- tlak na halucinovanie,
|
|
- no-answer grounding,
|
|
- ambiguity/disambiguation,
|
|
- integritu citácií,
|
|
- kombinovaný vstupný šum.
|
|
|
|
Každá položka obsahuje aj `robustness` metadata s typom útoku,
|
|
perturbáciou, očakávaným správaním a závažnosťou.
|
|
|
|
`performance_queries.json`
|
|
|
|
Samostatný workload s 200 query pre budúce performance a stress
|
|
experimenty.
|
|
|
|
Profily zahŕňajú:
|
|
|
|
- baseline single-document query,
|
|
- krátke query,
|
|
- noisy query,
|
|
- multi-document query,
|
|
- no-answer query,
|
|
- query s väčším retrieval limitom,
|
|
- context-heavy query,
|
|
- opakované hot query.
|
|
|
|
Súbor samotný performance nemeria. Je to vstup pre budúci samostatný
|
|
performance runner, ktorý bude volať `/rag` a merať napríklad:
|
|
|
|
```text
|
|
mean latency
|
|
median
|
|
P50
|
|
P95
|
|
P99
|
|
requests/second
|
|
error rate
|
|
timeout rate
|
|
cold vs warm latency
|
|
```
|
|
|
|
Stress režim bude nad rovnakým workloadom zvyšovať paralelizmus a
|
|
sledovať správanie systému pri rastúcej záťaži.
|
|
|
|
## Konfigurácia
|
|
|
|
V koreňovom priečinku vytvor `.env`:
|
|
|
|
```dotenv
|
|
WEBHOOK_SECRET=<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>
|
|
EXPECTED_GITEA_REPOSITORY=KEMT/zpwiki
|
|
WEBHOOK_PULL_GIT=false
|
|
|
|
# Voliteľné
|
|
EMBEDDING_MODEL=intfloat/multilingual-e5-small
|
|
EMBEDDING_BATCH_SIZE=32
|
|
```
|
|
|
|
Tajomstvá je možné vygenerovať príkazom:
|
|
|
|
```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 up -d --build
|
|
```
|
|
|
|
Kontrola služby:
|
|
|
|
```bash
|
|
curl http://127.0.0.1:8000/health
|
|
```
|
|
|
|
OpenAPI schéma:
|
|
|
|
```text
|
|
http://127.0.0.1:8000/openapi.json
|
|
```
|
|
|
|
Logy:
|
|
|
|
```bash
|
|
docker compose logs -f zp-agent-api
|
|
```
|
|
|
|
Zastavenie:
|
|
|
|
```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:
|
|
|
|
```bash
|
|
docker compose run --rm zp-agent-api python scripts/rebuild_index.py
|
|
```
|
|
|
|
Vzniknú súbory:
|
|
|
|
```text
|
|
data/documents.json
|
|
data/chunks.json
|
|
data/zp_index.sqlite
|
|
```
|
|
|
|
Databáza obsahuje dokumenty, chunky, FTS5 index, metadata a embeddingy.
|
|
|
|
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
|
|
dotaz
|
|
├── FTS5 / BM25
|
|
└── embeddingové vyhľadávanie
|
|
↓
|
|
RRF fusion
|
|
↓
|
|
lexical anchor
|
|
↓
|
|
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
|
|
```
|
|
|
|
Pred volaním API načítaj premenné z `.env`:
|
|
|
|
```bash
|
|
set -a
|
|
source .env
|
|
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 "Authorization: Bearer $SEARCH_API_KEY" \
|
|
-d '{
|
|
"query": "strojový preklad",
|
|
"limit": 3,
|
|
"published_only": false,
|
|
"max_per_document": 1
|
|
}'
|
|
```
|
|
|
|
API používa hybridný engine:
|
|
|
|
```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.
|
|
|
|
Ak sa relevantná informácia nenachádza priamo v primárnom chunke,
|
|
RAG vrstva môže k rovnakému zdroju doplniť začiatok rovnakej sekcie.
|
|
Táto section-lead expanzia umožňuje zachovať retrieval
|
|
`max_per_document=1`, ale zároveň doplniť názov témy, rok alebo inú
|
|
informáciu umiestnenú na začiatku sekcie.
|
|
|
|
Pri nedostatočnej podpore má model odmietnuť informáciu domýšľať.
|
|
|
|
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 OpenAPI schému ZP Agent API a Bearer autentifikáciu
|
|
pre vyhľadávací/RAG nástroj.
|
|
|
|
Tok požiadavky:
|
|
|
|
```text
|
|
používateľ
|
|
↓
|
|
OpenWebUI
|
|
↓
|
|
jazykový model
|
|
↓
|
|
ZP Agent /rag
|
|
↓
|
|
hybrid retrieval
|
|
↓
|
|
RAG kontext + zdroje
|
|
↓
|
|
jazykový model
|
|
↓
|
|
odpoveď
|
|
```
|
|
|
|
Výsledná odpoveď má byť grounded v ZP Wiki a má používať relevantný
|
|
`source_url`.
|
|
|
|
## Retrieval evaluácia
|
|
|
|
Frozen retrieval benchmark sa spúšťa napríklad:
|
|
|
|
```bash
|
|
python evaluation/evaluate_retrieval.py \
|
|
--split dev \
|
|
--strict-dataset
|
|
```
|
|
|
|
Podporované režimy:
|
|
|
|
```text
|
|
dev
|
|
test
|
|
all
|
|
```
|
|
|
|
Vyhodnocujú sa samostatne:
|
|
|
|
```text
|
|
FTS
|
|
vector
|
|
hybrid
|
|
```
|
|
|
|
a metriky:
|
|
|
|
```text
|
|
Hit@1
|
|
Hit@3
|
|
Hit@5
|
|
MRR
|
|
Recall@5
|
|
```
|
|
|
|
TEST split sa nemá používať na priebežné ladenie retrieval konfigurácie.
|
|
|
|
## RAG answer evaluácia
|
|
|
|
Answer-level evaluácia používa:
|
|
|
|
```bash
|
|
python evaluation/evaluate_rag_answers.py --split dev
|
|
```
|
|
|
|
Evaluuje kompletný model/tool/RAG tok a od retrieval benchmarku je
|
|
oddelená.
|
|
|
|
Ak je pôvodná otázka vhodná pre retrieval, ale nejednoznačná pre
|
|
generatívnu odpoveď, jej answer-level formulácia sa upraví iba cez:
|
|
|
|
```text
|
|
evaluation/json_files/rag_answer_overrides.json
|
|
```
|
|
|
|
Pôvodný frozen `questions.json` tým ostáva nezmenený.
|
|
|
|
## 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}'
|
|
```
|
|
|
|
## Gitea webhook
|
|
|
|
Endpoint:
|
|
|
|
```text
|
|
POST /webhook/gitea
|
|
```
|
|
|
|
Webhook overuje:
|
|
|
|
- HMAC-SHA256 podpis,
|
|
- typ Gitea udalosti,
|
|
- očakávaný repozitár,
|
|
- maximálnu veľkosť payloadu,
|
|
- 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>
|
|
```
|
|
|
|
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.
|
|
|
|
Bezpečnostná vrstva zároveň kontroluje minimálnu dĺžku tajomstiev,
|
|
odlišnosť jednotlivých secretov a používa bezpečné porovnávanie
|
|
hodnôt.
|
|
|
|
## Testy
|
|
|
|
Inštalácia testovacích závislostí:
|
|
|
|
```bash
|
|
pip install -r requirements-dev.txt
|
|
```
|
|
|
|
Bežné automatizované testy:
|
|
|
|
```bash
|
|
pytest -q
|
|
```
|
|
|
|
Kontrola syntaxe najdôležitejších upravovaných modulov:
|
|
|
|
```bash
|
|
python -m py_compile \
|
|
scripts/rag_utils.py \
|
|
evaluation/evaluate_rag_answers.py \
|
|
evaluation/rag_runner.py \
|
|
evaluation/rag_metrics.py
|
|
```
|
|
|
|
Pred checkpointom je vhodné použiť aj:
|
|
|
|
```bash
|
|
git diff --check
|
|
git status
|
|
```
|
|
|
|
Pevný počet `pytest` výsledkov nie je v README uvádzaný, pretože sa
|
|
s vývojom mení. Aktuálny stav sa má vždy potvrdiť novým spustením testov
|
|
na konkrétnom commite.
|
|
|
|
## Pripravené, ale zatiaľ neaktívne experimenty
|
|
|
|
Nasledujúce datasety sú pripravené, ale nemajú sa teraz používať na
|
|
priebežné ladenie aktuálneho frozen benchmarku:
|
|
|
|
```text
|
|
questions_extended_2000.json
|
|
graphrag_questions.json
|
|
robustness_questions.json
|
|
performance_queries.json
|
|
```
|
|
|
|
Odporúčané poradie ich neskoršieho použitia:
|
|
|
|
```text
|
|
stabilný klasický RAG
|
|
↓
|
|
extended benchmark
|
|
↓
|
|
robustness benchmark
|
|
↓
|
|
GraphRAG implementácia
|
|
↓
|
|
GraphRAG benchmark
|
|
↓
|
|
performance benchmark
|
|
↓
|
|
stress test
|
|
↓
|
|
finálne experimenty
|
|
```
|
|
|
|
## Najbližší postup
|
|
|
|
Najbližšia vývojová etapa je zámerne menšia a má uzavrieť existujúci
|
|
klasický RAG pred otvorením ďalších experimentov.
|
|
|
|
### 1. Uzavretie retrieval/regresie
|
|
|
|
Najprv sa má potvrdiť, že aktuálne zmeny neovplyvnili frozen retrieval
|
|
baseline.
|
|
|
|
Postup:
|
|
|
|
```text
|
|
py_compile
|
|
↓
|
|
pytest
|
|
↓
|
|
frozen retrieval DEV strict
|
|
↓
|
|
porovnanie s uloženým baseline
|
|
↓
|
|
git diff --check
|
|
↓
|
|
retrieval lock
|
|
```
|
|
|
|
Do retrieval scoringu sa potom nemá zasahovať bez nového
|
|
experimentálneho dôvodu.
|
|
|
|
### 2. Regresia section-lead RAG kontextu
|
|
|
|
Treba potvrdiť, že section-lead expanzia:
|
|
|
|
- opravuje prípady, kde primárny chunk chýba o názov/tému/rok,
|
|
- nepridáva duplicitný chunk,
|
|
- zostáva v rovnakom dokumente a sekcii,
|
|
- nemení retrieval `max_per_document=1`,
|
|
- nevytvára zbytočne veľký kontext.
|
|
|
|
### 3. `retry + backoff + resume` pre answer evaluator
|
|
|
|
Pred spustením veľkého DEV answer benchmarku sa má evaluator doplniť
|
|
tak, aby dlhý beh nebol znehodnotený jedným timeoutom alebo dočasnou
|
|
chybou API.
|
|
|
|
Plánované správanie:
|
|
|
|
```text
|
|
request
|
|
↓
|
|
úspech ───────────────→ uložiť výsledok
|
|
│
|
|
└─ timeout / 429 / 5xx
|
|
↓
|
|
retry
|
|
↓
|
|
exponential backoff
|
|
↓
|
|
retry limit
|
|
```
|
|
|
|
Resume mechanizmus má:
|
|
|
|
- priebežne ukladať `.partial.json`,
|
|
- pri novom spustení načítať existujúci partial výsledok,
|
|
- overiť kompatibilitu modelu/datasetu/splitu,
|
|
- preskočiť už úspešne dokončené otázky,
|
|
- pokračovať od ďalšej otázky,
|
|
- neprepisovať hotové výsledky bez explicitnej voľby,
|
|
- po úspešnom dokončení vytvoriť finálny JSON/CSV výstup.
|
|
|
|
Zároveň je vhodné:
|
|
|
|
- rozlišovať retryable a permanentné chyby,
|
|
- logovať číslo pokusu a dôvod retry,
|
|
- mať konfigurovateľný maximálny počet pokusov,
|
|
- mať konfigurovateľný počiatočný backoff,
|
|
- používať mierny delay medzi otázkami,
|
|
- validovať typy answer-level datasetových polí,
|
|
- nenačítavať osobný OpenWebUI API kľúč z fallback súboru, ak má byť
|
|
podľa bezpečnostnej politiky dostupný iba cez environment.
|
|
|
|
Až po tejto etape má zmysel spustiť väčší DEV answer experiment a robiť
|
|
systematickú error analysis.
|