From afdfc31d1aa1c0213b6faba93da58579f2f0cb3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Jasi=C5=84ski?= Date: Sun, 3 May 2026 16:12:07 +0200 Subject: [PATCH] feat: implement KM-RAG methodology artifacts and core architectural standards with supporting query and service updates --- .agent/skills/km-rag-methodology/SKILL.md | 29 + .../artifacts/core_concepts.md | 28 + .../artifacts/deep-research-report-rag.md | 588 ++++++++++++++++++ .../artifacts/evaluation_checklist.md | 23 + .../artifacts/implementation_patterns.md | 89 +++ .../nexus-architecture-standards/SKILL.md | 40 ++ .../scripts/arch_check.sh | 15 + .../Commands/AI/VerifyGroundednessCommand.cs | 1 - .../Graph/GetKnowledgeGraphQueryHandler.cs | 13 +- .../Library/SearchLibrarySemanticallyQuery.cs | 3 +- .../Services/WasmKnowledgeService.cs | 5 + 11 files changed, 823 insertions(+), 11 deletions(-) create mode 100644 .agent/skills/km-rag-methodology/SKILL.md create mode 100644 .agent/skills/km-rag-methodology/artifacts/core_concepts.md create mode 100644 .agent/skills/km-rag-methodology/artifacts/deep-research-report-rag.md create mode 100644 .agent/skills/km-rag-methodology/artifacts/evaluation_checklist.md create mode 100644 .agent/skills/km-rag-methodology/artifacts/implementation_patterns.md create mode 100644 .agent/skills/nexus-architecture-standards/SKILL.md create mode 100755 .agent/skills/nexus-architecture-standards/scripts/arch_check.sh diff --git a/.agent/skills/km-rag-methodology/SKILL.md b/.agent/skills/km-rag-methodology/SKILL.md new file mode 100644 index 0000000..dfd74f2 --- /dev/null +++ b/.agent/skills/km-rag-methodology/SKILL.md @@ -0,0 +1,29 @@ +--- +name: km-rag-methodology +description: Expertise in implementing Knowledge-Map RAG (KM-RAG), focusing on structured Knowledge Units, Graph relationships, and multi-stage retrieval in .NET. +tags: [RAG, KnowledgeMap, GraphRAG, AI, .NET, CleanArchitecture] +version: 1.0.0 +--- + +# KM-RAG Methodology + +This skill provides a comprehensive framework for transitioning from basic chunk-based RAG to a structured **Knowledge-Map RAG (KM-RAG)** approach. + +## Core Concepts +- **Knowledge Units (KU)**: Granular pieces of information with stable IDs and types (Section, Table, Definition, Rule). +- **Knowledge Map (Graph)**: Explicit links between units (`Next`, `Defines`, `Contains`) enabling contextual expansion. +- **Multi-Stage Retrieval**: A pipeline starting with semantic candidate generation followed by graph expansion and optional reranking. +- **Provenance & Governance**: Full traceability of AI answers back to their source units. + +## Key Artifacts +- [Core Concepts](artifacts/core_concepts.md): Deep dive into the methodology. +- [Implementation Patterns (.NET)](artifacts/implementation_patterns.md): C# code for units, links, and retrieval. +- [Quality Checklist](artifacts/evaluation_checklist.md): Metrics and safety procedures. +- [Deep Research Report](artifacts/deep-research-report-rag.md): Original research on the KM-RAG approach. + +## Usage +Use this skill when: +- Designing or refactoring RAG systems for high precision. +- Implementing multi-tenant knowledge bases. +- Enhancing AI answers with structural context from a graph. +- Building evaluation pipelines for hallucination detection. diff --git a/.agent/skills/km-rag-methodology/artifacts/core_concepts.md b/.agent/skills/km-rag-methodology/artifacts/core_concepts.md new file mode 100644 index 0000000..5e6a4ec --- /dev/null +++ b/.agent/skills/km-rag-methodology/artifacts/core_concepts.md @@ -0,0 +1,28 @@ +# Core Concepts of KM-RAG (Knowledge-Map RAG) + +Knowledge-Map RAG (KM-RAG) shifts the paradigm from "mechanical chunking" to "structured knowledge engineering". + +## 1. From Chunks to Knowledge Units (KU) +Instead of random character-based splits, knowledge is partitioned into **Knowledge Units** that preserve structural meaning: +- **Unit Types**: `Section`, `Table`, `Definition`, `ProcedureStep`, `PolicyRule`. +- **Properties**: Stable ID, Version, Canonical Text, Rendered Context, Provenance (source, page, path). + +## 2. The Knowledge Map (Graph) +Relationships between Knowledge Units are explicitly modeled to enhance retrieval and context assembly: +- `HAS_UNIT`: Document contains Unit. +- `NEXT` / `PREVIOUS`: Sequential flow between units. +- `DEFINES`: Unit defines a specific entity or term. +- `REFERENCES`: Unit refers to another unit. +- `EXCEPTION_OF`: Unit describes an exception to a rule in another unit. + +## 3. Retrieval Strategy: "Plan over Similarity" +Retrieval is not just `top-k` similarity but a multi-stage process: +1. **Candidate Generation**: Hybrid search (Vector + Keyword) to find potential matches. +2. **Graph Expansion**: Pulling related units (e.g., "Get the section this table belongs to" or "Get the definition of term X used here"). +3. **Reranking**: Using a Cross-Encoder to precisely score the expanded candidates. +4. **Context Assembly**: Building a grounded context with explicit citations. + +## 4. Governance and Provenance +- **Audit Trail**: Every answer must be traceable back to specific Knowledge Units with valid provenance. +- **Permission-Aware**: Retrieval filters must enforce ACLs at the unit/graph level before the LLM sees the data. +- **Continuous Evaluation**: Monitoring "Faithfulness" (groundedness) and "Answer Relevance" using tools like RAGAS or TruLens. diff --git a/.agent/skills/km-rag-methodology/artifacts/deep-research-report-rag.md b/.agent/skills/km-rag-methodology/artifacts/deep-research-report-rag.md new file mode 100644 index 0000000..1005198 --- /dev/null +++ b/.agent/skills/km-rag-methodology/artifacts/deep-research-report-rag.md @@ -0,0 +1,588 @@ +# Mapa Wiedzy i kontrola w RAG: jak wdrożyć „nowe podejście” w sposób inżynieryjny + +## Executive summary + +Autor posta (entity["people","Vladimir Alekseichenko","dataworkshop ceo"], entity["organization","DataWorkshop","ml/ai training poland"]) kontrastuje „klasyczny” RAG oparty o mechaniczne chunkowanie i wektoryzację z podejściem, w którym buduje się **Mapę Wiedzy**: „graf z metadanymi, powiązaniami i odniesieniami do źródeł” (w kontekście praktyki na danych z entity["organization","Giełda Papierów Wartościowych w Warszawie","warsaw stock exchange"]). citeturn2view0turn2view1 + +W tym raporcie formalizuję tę ideę jako **Knowledge‑Map RAG (KM‑RAG)**: RAG, w którym warstwa „R” nie jest tylko wyszukiwaniem semantycznym po losowych fragmentach, ale **kontrolowanym wyborem jednostek wiedzy** (sekcja, tabela, rekord, definicja, reguła) powiązanych grafowo, z pełną **proweniencją (skąd to jest), politykami dostępu, wersjonowaniem i testowalnością**. To jest spójne z tezą autora, że „R w RAG” to przede wszystkim **ryzyko**: jeśli retrieval jest błędny, model będzie „pewnie” odpowiadał na podstawie złego kontekstu. citeturn2view0turn6view0 + +Ponieważ nie podałeś ograniczeń (skala, budżet, SLA/latencja), przyjmuję **brak specyficznych constraintów** i podaję warianty: od małych wdrożeń (Postgres/pgvector) po architektury wielotenancy (Qdrant/Pinecone/Weaviate) oraz hybrydy graf + wektory. citeturn12search2turn14search1turn14search16turn14search0turn14search2 + +Najważniejsze rekomendacje wdrożeniowe: + +Po pierwsze, zastąp „losowe chunki” **jednostkami sensu**: segmentacją strukturalną (nagłówki/sekcje/tabele) i/lub semantyczną, z metadanymi i relacjami (poprzedni/następny, należy do sekcji, cytuje, definiuje). citeturn6view0turn11search1turn11search29 + +Po drugie, zbuduj **Mapę Wiedzy jako graf** (property graph) + indeksy (wektorowy i leksykalny/hybrydowy). Praktycznie: graf przechowuje relacje i proweniencję, a wektory dają tani „candidate generation”; dopiero potem używasz grafu do „dociągnięcia” brakujących kontekstów i do audytu. To jest zgodne z rodziną podejść GraphRAG (np. publikacja entity["company","Microsoft","tech company"] o GraphRAG: graf encji + „community summaries” dla lepszych odpowiedzi na pytania globalne). citeturn0search1turn3search4turn3search20 + +Po trzecie, „kontrola zamiast nadziei” oznacza: (a) **mierniki retrieval i generation**, (b) automatyczne testy regresji i audyt ścieżki źródeł, (c) monitoring i alerty driftu oraz incydentów bezpieczeństwa (prompt injection, data leakage). W praktyce: RAGAS/TruLens + OWASP LLM Top 10 jako checklisty, plus logowanie „trace” (kontekst → odpowiedź → cytowania). citeturn4search1turn4search2turn4search6turn4search13turn4search7 + +## Definicja podejścia „Mapa Wiedzy zamiast losowych chunków” + +W poście autor opisuje Mapę Wiedzy jako artefakt, który budujesz **w 3 dni**: „graf z metadanymi, powiązaniami i odniesieniami do źródeł” (wspomina też kontekst narzędziowy: repozytorium na entity["company","GitHub","code hosting platform"] i notatki w entity["company","Obsidian","note-taking app company"]). citeturn2view1 + +Jednocześnie w dłuższym materiale autor rozwija intuicję, dlaczego „chunking + vector DB” bywa drogą donikąd: mechaniczne cięcie rozrywa jednostki sensu (akapit, tabela), a model językowy zwykle **nie weryfikuje kontekstu** – odpowiada w oparciu o to, co mu dostarczysz, nawet jeśli kontekst jest sprzeczny (stąd losowość i halucynacje). citeturn6view0turn7view1 + +### Precyzyjna definicja operacyjna (KM‑RAG) + +**Knowledge‑Map RAG (KM‑RAG)** to architektura RAG, w której warstwa „R” jest realizowana przez: + +**Reprezentację wiedzy**: dokumenty są przekształcane do zbioru **jednostek wiedzy** (Knowledge Units) o stabilnej proweniencji (ID, wersja, lokalizacja w źródle) i spójnej semantyce (sekcja definicji, tabela, rozdział, procedura), a nie losowych wycinków znaków. citeturn6view0turn11search9turn16search0 + +**Mapę (graf) zależności**: jednostki są węzłami grafu (np. DOCUMENT → SECTION → UNIT; ENTITY ↔ UNIT; UNIT ↔ UNIT przez „refers_to/next/derives_from”), a krawędzie niosą informację ułatwiającą retrieval i audyt (np. „to jest definicja terminu X”, „to jest wyjątek od reguły”). citeturn2view1turn10search3turn3search4 + +**Polityki retrieval**: zapytanie jest mapowane na intencję i encje, a retrieval wykonuje plan: generuje kandydatów (wektory/keyword/hybrid), następnie rozszerza kontekst grafowo (np. sekcja nadrzędna, definicje encji, powiązane tabele), na końcu dokonuje selekcji (rerank/pruning) i buduje kontekst z cytowaniami. citeturn12search3turn12search11turn10search6turn10search31 + +**Kontrolę i audytowalność**: system jest projektowany tak, aby można było odpowiedzieć na pytania: „Dlaczego ten fragment?”, „Czy użytkownik miał uprawnienia?”, „Jaka wersja źródła?”, „Czy odpowiedź jest ugruntowana (grounded) w kontekście?”. Autor wprost wiąże „mapę wiedzy” z uszczelnianiem rozwiązań, wymaganiami prawnymi/bezpieczeństwa oraz audytowalnością. citeturn7view1turn14search2 + +### Dlaczego „losowe chunki” są słabą abstrakcją inżynieryjną + +Mechaniczne chunkowanie jest często liczone w znakach/tokenach; nawet z overlapem rozrywa strukturę i wymusza „magiczne” heurystyki (większy chunk_size, więcej chunków w kontekście), które łatwo psują wcześniej działające przypadki i utrudniają stabilną ewaluację. citeturn6view0 + +Z perspektywy governance kluczowy problem jest też bezpieczeństwo: w jednym dokumencie mogą być fragmenty o różnych poziomach dostępu, więc „wrzucanie wszystkiego do jednego kontekstu” łamie zasady separacji i komplikuje zgodność (ten motyw pojawia się u autora wprost). citeturn7view1turn14search2 + +## Architektura referencyjna i komponenty + +Poniżej przedstawiam architekturę komponentową KM‑RAG, obejmującą: ingestion, mapę wiedzy, strategie segmentacji, embeddingi i wektory, retrievery i rerankery, prompt engineering i grounding, oraz kontrolę halucynacji i ewaluację. + +### Diagram architektury + +```mermaid +flowchart LR + subgraph Ingestion + A[Źródła: PDF/HTML/DOCX/DB] --> B[Parsing + normalizacja] + B --> C[Jednostki wiedzy: sekcje, tabele, rekordy] + C --> D[Metadane: źródło, wersja, ACL, lokalizacja] + C --> E[Ekstrakcja encji/relacji] + E --> G[(Graf / Mapa Wiedzy)] + C --> F[Embedding + indeks] + F --> V[(Vector DB)] + end + + subgraph QueryTime + Q[Zapytanie użytkownika] --> R[Routing/intencja/encje] + R --> V1[Candidate gen: vector/keyword/hybrid] + V1 --> V + V --> K[Top-K kandydatów] + K --> G1[Graph expansion\n(definicje, zależności, sekcje)] + G1 --> G + G --> S[Context assembly + dedup + cytowania] + S --> L[LLM generacja\n(z zasadą "answer from sources")] + L --> O[Odpowiedź + cytowania + confidence] + end + + subgraph Control + O --> M[Logi/trace] + M --> EV[Ewaluacja offline/online] + M --> MON[Monitoring KPI + alerty] + end +``` + +Model ten jest kompatybilny zarówno z „klasycznym RAG” w sensie pracy na wektorach (RAG w ujęciu Lewis et al. zakłada połączenie pamięci parametrycznej i nieparametrycznej poprzez retrieval z indeksu wektorowego), jak i z odmianami grafowymi (GraphRAG: budowa grafu encji i „community summaries” jako warstwa indeksu). citeturn0search2turn0search5turn0search1turn3search4 + +image_group{"layout":"carousel","aspect_ratio":"16:9","query":["GraphRAG architecture diagram","knowledge graph retrieval augmented generation diagram","vector database similarity search diagram","Neo4j graph visualization example"],"num_per_query":1} + +### Ingestion: parsowanie, normalizacja i jednostki wiedzy + +W KM‑RAG ingestion nie kończy się na „wyciągnij tekst z PDF”. Kluczowe jest zachowanie/rekonstrukcja struktury: tytuły, listy, tabele, numer stron, sekcje. Biblioteka entity["company","Unstructured","document processing company"] wprost opisuje „partitioning” jako ekstrakcję ustrukturyzowanych elementów (Title/NarrativeText/ListItem itd.), aby móc decydować, co zachować. citeturn16search0turn16search8turn16search4 + +Jeśli pracujesz na bardzo różnych formatach lub potrzebujesz także metadanych i obsługi np. zaszyfrowanych PDF, narzędzia z ekosystemu entity["organization","Apache Software Foundation","open source foundation"] (Apache Tika) podkreślają możliwość parsowania PDF, w tym obsługi dokumentów szyfrowanych przy podaniu hasła. citeturn16search1turn16search30 + +Wniosek projektowy: „Jednostka wiedzy” w KM‑RAG to obiekt typu np.: + +- `unit_type`: `section`, `definition`, `table`, `row`, `procedure_step`, `policy_rule` +- `canonical_text` (tekst do embeddingu i rerankingu) +- `rendered_context` (tekst/fragment do wklejenia do prompta) +- `provenance`: `source_id`, `page`, `section_path`, `span_offsets` +- `governance`: `acl_tags`, `pii_class`, `retention_class` +- `links`: `prev/next`, `references`, `same_topic` + +Taki model danych bezpośrednio adresuje problem autora: model nie „weźmie odpowiedzialności” za konfliktujący kontekst, więc to system ma pilnować jakości kontekstu i jego zaufania. citeturn6view0turn7view1 + +### Strategie segmentacji: od „chunków” do „węzłów” (Nodes) + +Jeżeli musisz działać na tekście, i tak będziesz coś „dzielił” – różnica polega na tym, czy są to losowe fragmenty znaków, czy **węzły semantyczne**. + +- W ekosystemie entity["company","LangChain","llm app framework company"] często proponuje się `RecursiveCharacterTextSplitter` jako „solidny default” dla wielu przypadków, ale to nadal jest heurystyka bazująca na znakach i separatorach. citeturn11search8turn11search0 +- entity["company","LlamaIndex","llm data framework company"] oferuje semantyczne parsowanie węzłów: `SemanticSplitterNodeParser` dzieli tekst na grupy zdań powiązane semantycznie (z użyciem embeddingów), a dokumentacja podkreśla, że to alternatywa dla stałego rozmiaru chunków. citeturn11search1turn11search9turn11search29 + +KM‑RAG traktuje segmentację jako element modelowania danych: węzły mają typ, hierarchię i relacje. + +### Embeddingi i Vector DB: candidate generation + filtrowanie po metadanych + +Embeddingi są nadal bardzo użyteczne, ale w KM‑RAG pełnią rolę „szybkiego generatora kandydatów”, a nie „wyroczni”. + +Otwartoźródłowo, entity["company","Hugging Face","ml model hub company"] utrzymuje Sentence Transformers, które dostarcza zarówno modele embeddingowe (bi-encoders), jak i rerankery (cross-encoders). citeturn12search38turn12search3 + +Warstwa metadanych jest w KM‑RAG krytyczna: np. do ograniczania domeny, wersji dokumentu, języka, daty wejścia w życie, uprawnień. + +- entity["company","Qdrant","vector database company"] opisuje payload/metadata i filtrowanie oraz zaleca indeksowanie pól payload dla efektywności filtrowania. citeturn11search2turn11search6turn11search37 +- entity["company","Pinecone","vector database company"] opisuje filtrowanie po metadanych oraz pokazuje wzorzec multitenancy przez namespaces. citeturn11search7turn14search16turn14search12 +- entity["company","Weaviate","vector database company"] opisuje hybrydę BM25F + wektory (fuzja wyników i wagi są konfigurowalne) oraz posiada natywną wielodzierżawność (tenant per request). citeturn12search0turn14search0 +- entity["company","Milvus","vector database project"] dokumentuje hybrydę sparse+dense i wskazuje scenariusze, w których połączenie poprawia wyniki (semantyka + dopasowanie słów kluczowych). citeturn12search1turn12search5 + +W KM‑RAG niemal zawsze warto rozważyć hybrid retrieval (dense + sparse), bo ogranicza „semantic drift” i poprawia precyzję przy terminach domenowych (np. numery, nazwy własne). Jest to wspólny wątek w dokumentacji Weaviate i Pinecone, opisującej fuzję wyników i podejścia do hybrydy. citeturn12search0turn11search3turn11search19 + +### Retrievery, rerankery i kontrola halucynacji + +KM‑RAG rozdziela retrieval na etapy: + +**Candidate generation (tani):** dense retriever (np. dual-encoder) i/lub sparse (BM25). Klasyczna praca o dense retrieval (DPR) pokazuje dual-encoder jako praktyczny mechanizm retrieval i porównuje go do BM25 w QA. citeturn8search0turn8search4 + +**Reranking (droższy):** cross-encoder reranker znacząco poprawia ranking, ale jest kosztowny, bo ocenia pary (query, doc) wspólnie w modelu. Sentence Transformers opisuje retrieve‑&‑rerank pipeline oraz rolę CrossEncodera. citeturn12search11turn12search19 + +**Graph expansion (precyzja i kompletność):** graf dostarcza „brakujących mostów” (definicje, zależności, wyjątki, kontekst sekcji) oraz daje audyt – to jest sedno „Mapy Wiedzy”. W wariantach GraphRAG (Microsoft) graf jest budowany z encji i relacji, a następnie grupowany w społeczności i streszczany, co poprawia odpowiedzi na pytania „globalne” (np. „jakie są główne tematy w korpusie?”), gdzie naiwny RAG zawodzi. citeturn0search1turn0search13turn3search4turn3search20 + +**Halucynacje i „kontrola”:** literatura proponuje pętle weryfikacji (np. Chain‑of‑Verification: draft → pytania weryfikacyjne → niezależne odpowiedzi → final) i mechanizmy samorefleksji (Self‑RAG) oraz korekty retrieval (CRAG). Są to techniki „kontroli” na poziomie architektury, a nie tylko promptu. citeturn8search3turn9search1turn9search2 + +## Opcje projektowe i trade‑offy + +### Porównanie: klasyczny RAG vs KM‑RAG + +| Wymiar | Klasyczny „chunk + vector DB” | KM‑RAG (Mapa Wiedzy) | Konsekwencja praktyczna | +|---|---|---|---| +| Jednostka indeksowania | fragment znaków/tokenów | jednostka sensu: sekcja/tabela/rekord + typ | mniej „urwanych” kontekstów, mniej przypadkowości | +| Reprezentacja | embedding + (czasem) metadata | embedding + metadata + graf relacji + proweniencja | lepsza ścieżka audytu i „dlaczego to” | +| Retrieval | top‑k similarity | plan retrieval: hybrid + graf expansion + rerank | wyższa precyzja i odporność na trudne pytania | +| Zmiany w danych | częsty re‑index, ryzyko regresji | wersjonowanie, testy regresji per typ jednostki | stabilniejsze wdrożenia i migracje | +| Bezpieczeństwo/ACL | łatwo mieszać fragmenty o różnych uprawnieniach | ACL na poziomie jednostki i ścieżki grafu | mniejsze ryzyko wycieku kontekstu | +| Debuggowanie | „dlaczego takie chunki?” | „jaki węzeł, z jakiego źródła, jaka relacja?” | szybsze RCA i audyt | + +Uzasadnienie co do problemów chunkingu i „model ufa kontekstowi” pochodzi z materiału autora; definicja Mapy Wiedzy jako grafu z metadanymi i odniesieniami jest wprost w poście. citeturn6view0turn2view1turn7view1 + +### Wybory technologiczne: wektory, graf, hybryda + +Poniżej pokazuję typowe opcje i kompromisy (bez narzuconych constraintów – dobór zależy od QPS, wolumenu i wymagań bezpieczeństwa). + +**Vector store** + +- Qdrant: mocne filtrowanie payload + mechanizmy multitenancy (w tym „tiered multitenancy”). citeturn11search6turn14search1turn14search18 +- Pinecone: proste multitenancy przez namespaces; dobrze opisane podejścia do hybrid search (single hybrid index vs osobne indeksy, z plusami i minusami). citeturn14search16turn11search3 +- Weaviate: wbudowany hybrid BM25F + wektor, oraz multi‑tenancy z tenantem w operacjach. citeturn12search0turn14search0 +- Milvus: rozbudowane podejścia do sparse+dense i multi‑vector, z dokumentacją dla hybrydy. citeturn12search1turn12search5turn12search33 +- pgvector: dobre, gdy chcesz „mniej systemów” i akceptujesz kompromisy wydajności; repo dokumentuje różnice IVFFlat vs HNSW (build time/memory vs speed‑recall). citeturn12search2turn12search14 +- Elasticsearch: istotny, gdy potrzebujesz „enterprise security” (RBAC, field/document‑level security) i hybrydowego wyszukiwania w jednej platformie. citeturn14search2turn14search15 + +**Graph / Knowledge Map store** + +- Neo4j: bogate wzorce GraphRAG (graph traversal, full‑text, vector, text2cypher). Neo4j publikuje GraphRAG field guide i pakiet GraphRAG dla Pythona. citeturn10search18turn10search14turn10search31turn10search2 +- Microsoft GraphRAG: gotowy pipeline budowy grafowego indeksu (encje → społeczności → streszczenia), open‑source na GitHubie + dokumentacja „Getting started”. citeturn3search0turn3search31turn3search20turn0search1 +- LlamaIndex KnowledgeGraphIndex: praktyczna automatyzacja budowy grafu z tekstu i query po encjach. citeturn10search3turn10search11 + +**Kompromisy** + +- Skalowalność: graf może zmniejszać liczbę „strzałów” w LLM (np. przez pre‑streszczenia społeczności w GraphRAG) kosztem cięższego ingestion i większej złożoności danych. citeturn0search1turn3search4 +- Latencja: rerankery cross‑encoder podnoszą jakość, ale zwiększają czas (N par do oceny); dlatego standardem jest retrieval → rerank top‑N, nie rerank całego korpusu. citeturn12search11turn12search19 +- Koszt: hybryda i graf często zwiększają koszt ingest (LLM do ekstrakcji encji/relacji), ale zmniejszają koszt „ratowania” jakości w runtime przez kolejne heurystyki. To jest w duchu argumentu autora o „dokładaniu mini‑klocków” versus poprawa fundamentu. citeturn6view0turn7view1 +- Maintainability: mniej „magicznych” parametrów chunk_size; więcej jawnych typów jednostek i testów per typ. citeturn7view1turn13search3 +- Security/data governance: najlepiej wspierać **permission‑aware retrieval** już w retrieverze (prefilter), bo wtedy model nie ma czego „wyciec”. Dokumentacja Elastic i wektor DB pokazuje mechanizmy RBAC/DLS, namespaces/tenants i filtrowanie po metadanych. citeturn14search2turn14search16turn14search0turn11search6 + +## Migracja z klasycznego RAG do KM‑RAG + +Migracja jest łatwiejsza, jeśli potraktujesz ją jak refactoring warstwy danych i retrieval, a nie „przepisanie wszystkiego od zera”. + +### Ścieżka migracji krok po kroku + +**Krok pierwszy: ustal bazową prawdę (baseline) i testy.** +Bez ewaluacji będziesz „liczyć na cud” – wprost przeciwieństwo postulatu „kontrola zamiast nadziei”. Zacznij od małego zestawu pytań i oczekiwań (golden set) oraz logowania kontekstu i odpowiedzi. W praktyce możesz użyć RAGAS (metryki retrieval i faithfulness bez konieczności pełnych anotacji) oraz TruLens (RAG triad: context relevance, groundedness, answer relevance). citeturn4search1turn4search2turn4search6 + +**Krok drugi: dołóż metadane i proweniencję zanim dołożysz graf.** +W klasycznym RAG często brakuje stabilnych ID i lokalizacji w źródle; tymczasem autor wiąże mapę wiedzy z odniesieniami do źródeł. Minimalny zestaw to: `source_id`, `version`, `page/section`, `timestamp`, `acl_tags`. Mechanizmy filtrowania po metadanych są standardem m.in. w Pinecone i Qdrant. citeturn2view1turn11search7turn11search6 + +**Krok trzeci: zamień chunki na węzły o typach i relacjach.** +Zamiast „1000 znaków”, twórz: `SectionNode`, `TableNode`, `DefinitionNode`, `PolicyNode`. Jeśli nie możesz od razu, przejdź etapowo przez semantyczne node parsers (LlamaIndex) lub segmentację po strukturze dokumentu (partitioning). citeturn11search9turn16search0turn11search1 + +**Krok czwarty: zbuduj Mapę Wiedzy (graf) i zacznij od najtańszego użycia w runtime.** +Nie musisz od razu robić pełnego „GraphRAG global”. Najpierw używaj grafu do: (a) definicji i wyjątków, (b) dołączania kontekstu „nadrzędna sekcja” / „poprzedni‑następny”, (c) audytu ścieżki cytowań. Dopiero potem dokładaj stricte grafowe retrievery. citeturn10search6turn10search31turn3search4 + +**Krok piąty: wprowadź gating i rollout.** +Zgodnie z najlepszymi praktykami ewaluacji: iteruj, porównuj wersje, ustaw continuous evaluation i progi akceptacji. citeturn13search3turn13search35 + +### Proponowana sekwencja wdrożenia + +| Faza | Co dostarczasz | Typowy czas (brak constraintów) | Kryterium „done” | +|---|---|---:|---| +| Audit RAG | logi + golden set + baseline metryk | 1–2 tyg. | masz mierzalne recall/faithfulness + top failure modes | +| Metadata-first | proweniencja + filtry + ACL | 1–2 tyg. | brak „orphan” chunków bez źródła; prefiltrowanie działa | +| Nodes & map | węzły typowane + relacje | 2–4 tyg. | stable IDs, relacje prev/next/contains/refers_to | +| Hybrid + rerank | dense+sparse + rerank top‑N | 1–3 tyg. | poprawa metryk retrieval bez wzrostu halucynacji | +| Graph expansion | dołączanie kontekstu grafem | 2–4 tyg. | poprawa trudnych pytań „łączących fakty” | +| Produkcja | monitoring KPI + procedury incydentów | ciągłe | CE + alerty + playbook audytu | + +Metryki i praktykę continuous evaluation wspiera dokumentacja OpenAI (zalecenia dot. progów context recall/precision i pipeline’u ewaluacji), co jest spójne z „kontrolą” jako procesem, nie jednorazową konfiguracją. citeturn13search3turn13search27 + +## Implementacje przykładowe + +Poniższe implementacje są „szkieletami” (reference implementations). W obu wariantach zakładam brak narzuconych wymagań co do skali, więc pokazuję rozwiązania, które da się skalować horyzontalnie (wektor DB) i/lub uprościć (pgvector zamiast osobnej bazy). + +### Stack A: open‑source embeddings + open‑source Vector DB (Sentence Transformers + Qdrant) + graf w Neo4j + +**Kiedy wybrać:** gdy chcesz uniezależnić embeddingi od dostawcy, mieć pełną kontrolę nad danymi i implementować multitenancy/filtry wprost w wektor DB. Payload/filtry i multitenancy są natywnie wspierane w Qdrant. citeturn11search6turn14search1turn14search7 + +**Zależności (przykład):** `sentence-transformers`, `qdrant-client`, `neo4j`, parser dokumentów (`unstructured` lub Tika). + +```python +# --- Ingestion: parse -> units -> embeddings -> Qdrant + graph --- +from dataclasses import dataclass +from typing import Iterable, Optional +import hashlib +import time + +from sentence_transformers import SentenceTransformer, CrossEncoder +from qdrant_client import QdrantClient, models as qmodels +from neo4j import GraphDatabase + +@dataclass +class KnowledgeUnit: + unit_id: str + source_id: str + version: str + unit_type: str # e.g. "section", "definition", "table" + text: str # canonical text for embedding + page: Optional[int] = None + section_path: Optional[str] = None + acl: str = "public" # e.g. role/tenant tag + +def stable_id(source_id: str, version: str, unit_type: str, page: str, text: str) -> str: + raw = f"{source_id}|{version}|{unit_type}|{page}|{text}".encode("utf-8") + return hashlib.sha256(raw).hexdigest()[:24] + +# 1) Embeddings (bi-encoder) + reranker (cross-encoder) +embed_model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2") # example +reranker = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-6-v2") # example + +# 2) Vector DB: Qdrant +qdrant = QdrantClient(url="http://localhost:6333", timeout=30) +COLLECTION = "kmrag_units" + +DIM = embed_model.get_sentence_embedding_dimension() +qdrant.recreate_collection( + collection_name=COLLECTION, + vectors_config=qmodels.VectorParams(size=DIM, distance=qmodels.Distance.COSINE), +) + +# Index payload fields frequently used in filters (performance) +qdrant.create_payload_index( + collection_name=COLLECTION, + field_name="acl", + field_schema=qmodels.PayloadSchemaType.KEYWORD, +) +qdrant.create_payload_index( + collection_name=COLLECTION, + field_name="source_id", + field_schema=qmodels.PayloadSchemaType.KEYWORD, +) + +# 3) Graph DB: Neo4j (property graph) +neo4j_driver = GraphDatabase.driver( + "neo4j://localhost:7687", auth=("neo4j", "password") +) + +def upsert_units(units: Iterable[KnowledgeUnit]) -> None: + batch = list(units) + # embeddings + vectors = embed_model.encode([u.text for u in batch], normalize_embeddings=True) + + # upsert into Qdrant with payload metadata (provenance + ACL) + qdrant.upsert( + collection_name=COLLECTION, + points=[ + qmodels.PointStruct( + id=u.unit_id, + vector=vectors[i].tolist(), + payload={ + "source_id": u.source_id, + "version": u.version, + "unit_type": u.unit_type, + "page": u.page, + "section_path": u.section_path, + "acl": u.acl, + "ingested_at": int(time.time()), + }, + ) + for i, u in enumerate(batch) + ], + ) + + # build/update graph nodes + relationships + cypher = """ + UNWIND $rows AS r + MERGE (d:Document {source_id: r.source_id, version: r.version}) + MERGE (u:Unit {unit_id: r.unit_id}) + SET u.unit_type = r.unit_type, + u.page = r.page, + u.section_path = r.section_path + MERGE (d)-[:HAS_UNIT]->(u) + """ + with neo4j_driver.session() as s: + s.run(cypher, rows=[u.__dict__ for u in batch]) + +# --- Query-time retrieval: vector -> graph expansion -> rerank -> context --- +def retrieve(query: str, acl: str, top_k: int = 30, rerank_k: int = 8): + qvec = embed_model.encode([query], normalize_embeddings=True)[0].tolist() + + # 1) Candidate generation with metadata filter (permission-aware) + hits = qdrant.search( + collection_name=COLLECTION, + query_vector=qvec, + limit=top_k, + query_filter=qmodels.Filter( + must=[qmodels.FieldCondition(key="acl", match=qmodels.MatchValue(value=acl))] + ), + ) + candidate_ids = [h.id for h in hits] + + # 2) Graph expansion: pull neighbor units from same document/section (simple example) + expand_cypher = """ + MATCH (u:Unit) WHERE u.unit_id IN $ids + OPTIONAL MATCH (d:Document)-[:HAS_UNIT]->(u) + OPTIONAL MATCH (d)-[:HAS_UNIT]->(u2:Unit) + WHERE u2.section_path = u.section_path + RETURN DISTINCT u2.unit_id AS unit_id + LIMIT 200 + """ + with neo4j_driver.session() as s: + rows = s.run(expand_cypher, ids=candidate_ids).data() + expanded_ids = list({r["unit_id"] for r in rows}) or candidate_ids + + # 3) Fetch texts for reranking (here: from Qdrant payload 'text' not stored; you'd load from your storage) + # In production: keep canonical text in your doc store; Qdrant payload keeps provenance only. + # For demo: assume we can map id->text elsewhere: + id_to_text = load_texts(expanded_ids) # implement in your system + + pairs = [(query, id_to_text[i]) for i in expanded_ids] + scores = reranker.predict(pairs) + ranked = sorted(zip(expanded_ids, scores), key=lambda x: x[1], reverse=True)[:rerank_k] + + return ranked # list of (unit_id, score) + you can also return provenance from payload + +def load_texts(unit_ids): + # Placeholder: pull canonical text from your document store / data lake + raise NotImplementedError +``` + +Co w tym szkielecie jest „Mapą Wiedzy”: Neo4j przechowuje relacje (Document→Unit, a dalej możesz dodać Entity↔Unit, REFERENCES, NEXT), a Qdrant przechowuje wektory + payload do filtrowania; filtrowanie i indeksowanie payload jest sformalizowane w dokumentacji Qdrant. citeturn11search6turn11search2turn14search7 + +Rerank to klasyczny krok „retrieve‑then‑rerank” opisywany przez Sentence Transformers, gdzie CrossEncoder podnosi jakość finalnych wyników kosztem obliczeń. citeturn12search11turn12search19 + +### Stack B: managed LLM + Vector DB (OpenAI + Pinecone) + graf (Neo4j GraphRAG / Text2Cypher) + +**Kiedy wybrać:** gdy zależy Ci na szybkości iteracji, jakości modeli oraz gotowych mechanizmach „structured output”, a retrieval chcesz oprzeć o managed vector DB z namespaces i hybrid search. citeturn13search1turn14search16turn11search3 + +W wariancie managed sensownie jest też wykorzystać Structured Outputs do wymuszenia formatu odpowiedzi (np. `answer` + `citations[]`), co jest elementem „kontroli” i audytu. OpenAI opisuje Structured Outputs jako mechanizm gwarantujący zgodność odpowiedzi z JSON Schema. citeturn13search1turn13search8 + +```python +# --- Managed stack: OpenAI embeddings + Pinecone + structured outputs + graph retrieval --- +from openai import OpenAI +from pinecone import Pinecone +from neo4j_graphrag import GraphRAG # example usage; adjust to actual package API + +OPENAI_MODEL_EMB = "text-embedding-3-large" +OPENAI_MODEL_GEN = "gpt-5.4-mini" # example; choose by latency/cost needs + +client = OpenAI() +pc = Pinecone(api_key="PINECONE_API_KEY") +index = pc.Index("kmrag") + +def embed(texts): + resp = client.embeddings.create(model=OPENAI_MODEL_EMB, input=texts) + return [d.embedding for d in resp.data] + +def upsert_to_pinecone(units, namespace): + vecs = embed([u["text"] for u in units]) + index.upsert( + vectors=[ + (u["unit_id"], vecs[i], { + "source_id": u["source_id"], + "version": u["version"], + "unit_type": u["unit_type"], + "page": u.get("page"), + "section_path": u.get("section_path"), + "acl": u.get("acl"), + }) + for i, u in enumerate(units) + ], + namespace=namespace, # multitenancy / workspace isolation + ) + +def retrieve_candidates(query, namespace, acl, top_k=30): + qvec = embed([query])[0] + res = index.query( + vector=qvec, + top_k=top_k, + include_metadata=True, + namespace=namespace, + filter={"acl": {"$eq": acl}}, + ) + return res["matches"] + +# Optional: graph retrieval pattern via Text2Cypher (Neo4j GraphRAG package) +# The idea: use graph schema + question -> generated Cypher -> execute -> return records as extra grounded context. +gr = GraphRAG(neo4j_uri="neo4j+s://...", user="neo4j", password="...") + +ANSWER_SCHEMA = { + "name": "kmrag_answer", + "schema": { + "type": "object", + "properties": { + "answer": {"type": "string"}, + "citations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "unit_id": {"type": "string"}, + "source_id": {"type": "string"}, + "quote": {"type": "string"} + }, + "required": ["unit_id", "source_id"] + } + }, + "confidence": {"type": "number", "minimum": 0, "maximum": 1} + }, + "required": ["answer", "citations", "confidence"] + } +} + +def answer(query, namespace, acl): + hits = retrieve_candidates(query, namespace, acl) + text_context = "\n\n".join( + f"[{m['id']}] ({m['metadata'].get('source_id')}) {load_unit_text(m['id'])}" + for m in hits[:8] + ) + + graph_context = gr.text2cypher_retrieve(query) # e.g. definitions, relationships + + system = ( + "Odpowiadasz wyłącznie na podstawie kontekstu i grafu.\n" + "Jeśli brakuje danych, powiedz wprost, czego nie wiesz.\n" + "Zwróć cytowania do unit_id/source_id." + ) + + resp = client.responses.create( + model=OPENAI_MODEL_GEN, + input=[ + {"role": "system", "content": system}, + {"role": "user", "content": f"Pytanie: {query}\n\nKontekst:\n{text_context}\n\nGraf:\n{graph_context}"} + ], + text={ + "format": { + "type": "json_schema", + "json_schema": {**ANSWER_SCHEMA, "strict": True} + } + } + ) + return resp.output_text + +def load_unit_text(unit_id): + # fetch canonical unit text from your storage + raise NotImplementedError +``` + +Źródła dla tego stosu: OpenAI opisuje nowe modele embeddingowe (`text-embedding-3-small/large`) i guide embeddings, a także Structured Outputs i evaluation best practices. citeturn13search2turn13search1turn13search3turn13search9 +Pinecone opisuje hybrydę oraz filtrowanie po metadanych i multitenancy przez namespaces. citeturn11search3turn11search7turn14search16 +Wzorzec Text2Cypher – tłumaczenie pytania + schematu grafu na Cypher i wykonanie query – jest opisany w materiałach Neo4j. citeturn10search2turn10search6turn10search10 + +## Kontrola jakości, audyt i monitoring + +„Kontrola zamiast nadziei” warto potraktować jako trzy warstwy: (A) kontrola danych i retrieval, (B) kontrola generacji, (C) kontrola procesu (ewaluacja i monitoring). + +### Metryki i ewaluacja + +**Ewaluacja retrieval** (czyt. „czy przynosimy właściwy kontekst”) + +- Recall@K / Precision@K / MRR / NDCG: standardowe metryki IR; w pracach o retrieval z grafami i/lub KG są one explicite używane do oceny retrieval (np. praca o RAG+KG dla customer service raportuje MRR/Recall@K/NDCG@K). citeturn10search1turn10search5 +- Offline test set buduj iteracyjnie na podstawie prawdziwych porażek (failure traces) – to jest zgodne z podejściem „evaluation flywheel” i continuous evaluation. citeturn13search35turn13search3 + +**Ewaluacja generation** (czyt. „czy odpowiedź jest ugruntowana w źródłach”) + +- RAGAS: framework do „reference‑free evaluation” RAG, mierzący różne wymiary retrieval i generation. citeturn4search1turn4search5 +- TruLens: RAG triad – context relevance, groundedness, answer relevance – jako praktyczny zestaw ocen dla halucynacji. citeturn4search2turn4search6 + +**Progi jakości (przykład)** +OpenAI w evaluation best practices podaje przykładowe targety (np. context recall ≥ 0.85, context precision > 0.7) jako część praktyk ewaluacji i porównywania wersji. Traktuj to jako punkt startowy, nie prawo natury. citeturn13search3 + +### Checklist audytu KM‑RAG + +**Dane i ingestion** + +- Czy parser zachowuje strukturę (sekcje/tabele/numery stron) i czy masz testy parsera na „trudnych dokumentach” (tabele, wielokolumnowe layouty)? citeturn16search0turn16search10turn6view0 +- Czy każda jednostka wiedzy ma stabilne `source_id`, `version`, lokalizację i politykę retencji/PII? citeturn7view1turn14search2 + +**Mapa Wiedzy** + +- Czy graf ma jasno zdefiniowane typy węzłów i relacje (HAS_UNIT, DEFINES, EXCEPTION_OF, REFERENCES, NEXT), oraz czy masz reguły walidacji (np. brak cykli w „NEXT”, spójność sekcji)? citeturn2view1turn10search31 +- Czy ekstrakcja encji/relacji jest mierzalna (precision/recall) i odporna na duplikaty/rozbieżności nazw? (w praktyce: canonicalization + entity resolution). Koncepcja grafu encji jako indeksu jest centralna w GraphRAG. citeturn0search1turn0search13 + +**Retrieval** + +- Czy stosujesz prefilter po ACL/tenant (permission-aware retrieval), zanim cokolwiek trafi do prompta? (mechanizmy namespaces/tenants i DLS/RBAC istnieją w narzędziach retrieval). citeturn14search16turn14search0turn14search2 +- Czy masz hybrydę dense+sparse tam, gdzie słowa kluczowe są krytyczne (regulacje, numery, tickery)? Pinecone i Weaviate opisują hybrydę jako fuzję wyników. citeturn11search3turn12search0 +- Czy reranking działa na top‑N, a nie na setkach wyników (koszt/latencja), i czy jest mierzony? citeturn12search11turn12search19 + +**Generacja i grounding** + +- Czy model ma jasną instrukcję „answer from sources” oraz czy odpowiedź wymusza strukturę (JSON schema) i cytowania? Structured Outputs jest mechanizmem wspierającym niezawodność formatu. citeturn13search1turn13search8 +- Czy masz mechanizm „I don’t know / insufficient evidence” zamiast konfabulacji (np. minimalny próg evidence coverage)? Podejścia typu CoVe/Self‑RAG/CRAG pokazują, że pętle weryfikacji i korekty podnoszą factuality. citeturn8search3turn9search1turn9search2 + +**Bezpieczeństwo** + +- Czy testujesz prompt injection na poziomie aplikacji, nie tylko promptu? OWASP opisuje prompt injection jako manipulację zachowaniem modelu przez wejście, a cheat sheet sugeruje praktyki obrony. citeturn4search3turn4search7turn4search13 +- Czy masz kontrolę kosztu (rate limits, timeouts, budżety tokenów) – to też „kontrola”, bo DoS na LLM to realny wektor ryzyka (OWASP LLM Top 10 zawiera kategorie dot. DoS i supply chain). citeturn4search13turn13search12 + +### KPI i monitoring w produkcji + +Rekomendowany zestaw KPI (z podziałem na warstwy): + +**Retrieval KPI** + +- Context Recall@K / Context Precision@K (offline i online na próbie logów). citeturn13search3turn4search1 +- % zapytań, w których retrieval zwraca „pustkę” lub tylko niskie score (sugeruje routing lub brak danych). + +**Generation KPI** + +- Faithfulness/groundedness (TruLens/RAGAS). citeturn4search1turn4search6 +- Citation coverage: % zdań mających przypisane źródło, oraz „citation accuracy” (czy cytat faktycznie zawiera wspierający fragment). Self‑RAG raportuje poprawę citation accuracy w długich generacjach jako jeden z efektów frameworku. citeturn9search1turn9search9 + +**Ops KPI** + +- Latencja p95/p99 per etap (retrieval, rerank, LLM). +- Koszt per zapytanie (tokeny, liczba wywołań modeli) + alerty „unbounded consumption”. OpenAI publikuje production best practices i evaluation tooling jako część przejścia prototyp → produkcja. citeturn13search12turn13search3 + +**Narzędzia do obserwowalności** + +- RAGAS opisuje łączenie ewaluacji z tracingiem/analizą (np. Phoenix). citeturn4search34 +- TruLens ma integracje i dokumentację quickstart dla trace + feedback. citeturn4search2turn4search27 +- Jeśli używasz OpenAI, masz też guidance dot. ewaluacji i ciągłego monitorowania regresji. citeturn13search3turn13search6 + +### Typowe failure modes KM‑RAG i mitigacje + +**„Graf rośnie w chaos” (sprawl, duplikaty encji, zła kanonikalizacja).** +Mitigacja: wprowadź entity resolution, reguły normalizacji nazw, walidację schematu grafu i testy na podzbiorze; zacznij od grafu dokument‑sekcja‑unit, dopiero potem dodawaj encje/relacje automatyczne. GraphRAG wprost zaczyna od grafu encji jako indeksu, ale też pipeline’u budowy i transformacji danych, co sugeruje konieczność procesu, nie jednorazowego prompta. citeturn3search0turn0search1 + +**„Retrieval jest poprawny semantycznie, ale zły merytorycznie” (conflicts).** +Mitigacja: hybryda dense+sparse + rerank + kontrola jakości źródeł + mechanizmy korekty (CRAG: evaluator jakości retrieval i akcje naprawcze). citeturn9search2turn11search3turn12search0 + +**„Źródła przenoszą instrukcje (prompt injection z dokumentów)”** +Mitigacja: separacja „instructions vs data”, sanitation, polityki „nie wykonuj instrukcji z kontekstu”, oraz przede wszystkim permission-aware retrieval (prefilter). OWASP opisuje prompt injection i praktyki obrony. citeturn4search3turn4search7turn14search2 + +**„Latency/cost eksploduje przez reranking i graf”** +Mitigacja: ogranicz N rerankowanych kandydatów; cache embeddingów; cache wyników graf expansion; pre‑streszczenia (GraphRAG community summaries) dla klas pytań globalnych. citeturn12search11turn0search1turn3search4 + +**„Zgodność i audyt”** +Mitigacja: loguj trace: query → (filtry ACL) → dokumenty → fragmenty → odpowiedź; uzupełnij o standardy zarządzania ryzykiem i bezpieczeństwem (entity["organization","NIST","us standards institute"] AI RMF; entity["organization","ISO","international standards body"]/IEC 27001; entity["organization","OWASP","security foundation"] LLM Top 10). Zapewnia to język kontroli dla audytu, nawet jeśli implementacje są różne. citeturn15search1turn15search2turn4search13turn15search3 + +### Źródła priorytetowe do dalszej pracy + +Najbardziej „nośne” (load‑bearing) źródła do wdrożenia KM‑RAG, w kolejności praktycznej użyteczności: + +Źródła autora: definicja Mapy Wiedzy (graf + metadane + odniesienia) oraz argument o „R jako ryzyku” i potrzebie kontroli retrieval. citeturn2view1turn7view1 + +Podstawy RAG: praca Lewis et al. (RAG jako retrieval + generacja z nieparametrycznej pamięci) – jako fundament terminologiczny. citeturn0search2turn0search5 + +GraphRAG: publikacja i repozytorium Microsoft (graf encji, społeczności, streszczenia) – jako referencyjny wariant Mapy Wiedzy w postaci pipeline’u. citeturn0search1turn3search0turn3search4turn3search20 + +KG‑RAG / hybrydy: prace o łączeniu KG i RAG (np. HybridRAG; RAG+KG w customer service) – pokazują, że graf zmniejsza skutki segmentacji i poprawia retrieval. citeturn10search0turn10search1 + +Ewaluacja i kontrola jakości: RAGAS + TruLens + best practices ewaluacji – jako praktyczny „system kontroli”. citeturn4search1turn4search2turn13search3 + +Bezpieczeństwo: OWASP prompt injection i LLM Top 10 – jako checklisty dla warstwy „R” i integracji z danymi. citeturn4search3turn4search13turn4search7 \ No newline at end of file diff --git a/.agent/skills/km-rag-methodology/artifacts/evaluation_checklist.md b/.agent/skills/km-rag-methodology/artifacts/evaluation_checklist.md new file mode 100644 index 0000000..1287cc9 --- /dev/null +++ b/.agent/skills/km-rag-methodology/artifacts/evaluation_checklist.md @@ -0,0 +1,23 @@ +# Quality and Evaluation Checklist + +To move from "hope-based RAG" to "controlled RAG", implement these checks. + +## 1. Retrieval Metrics (Search Quality) +- [ ] **Context Recall**: Are the units necessary to answer the question actually in the retrieved set? +- [ ] **Context Precision**: Is the retrieved set clean of irrelevant noise? +- [ ] **MRR (Mean Reciprocal Rank)**: Is the most relevant unit appearing at the top? + +## 2. Generation Metrics (Answer Quality) +- [ ] **Faithfulness (Groundedness)**: Can every claim in the answer be traced to a retrieved Knowledge Unit? +- [ ] **Answer Relevance**: Does the answer actually address the user's intent? +- [ ] **Citation Accuracy**: Do the citations correctly point to the unit that supports the claim? + +## 3. Governance & Safety +- [ ] **ACL Pre-Filtering**: Is there a hard check ensuring units from different tenants/roles are NEVER mixed? +- [ ] **PII Scanning**: Are units scanned for sensitive data during ingestion? +- [ ] **Hallucination Gating**: Is there a "Confidence Score" or "Low Evidence" flag to warn users? + +## 4. Operational Health +- [ ] **Latency Monitoring**: Break down time spent in: Embedding -> Vector Search -> Graph Expansion -> Reranking -> LLM. +- [ ] **Token Efficiency**: Are we sending unnecessary fluff to the LLM, or is the context tightly packed with relevant units? +- [ ] **Index Drift**: Are we re-evaluating the "Golden Set" of questions when we update embedding models or chunking strategies? diff --git a/.agent/skills/km-rag-methodology/artifacts/implementation_patterns.md b/.agent/skills/km-rag-methodology/artifacts/implementation_patterns.md new file mode 100644 index 0000000..11b086a --- /dev/null +++ b/.agent/skills/km-rag-methodology/artifacts/implementation_patterns.md @@ -0,0 +1,89 @@ +# Implementation Patterns for KM-RAG in .NET + +This guide outlines how to implement KM-RAG patterns using C# and .NET, building on existing infrastructures like EF Core and `Microsoft.Extensions.AI`. + +## 1. Defining Knowledge Units +Represent units as strongly-typed entities to capture metadata and relationships. + +```csharp +public enum KnowledgeUnitType { Section, Table, Definition, Step, Rule } + +public class KnowledgeUnit +{ + public string Id { get; set; } // Stable Hash(Source, Content, Version) + public string SourceId { get; set; } + public string Version { get; set; } + public KnowledgeUnitType Type { get; set; } + public string Content { get; set; } + public string MetadataJson { get; set; } // page, section_path, etc. + public Vector? Embedding { get; set; } + + // Graph Relationships + public List OutgoingLinks { get; set; } = new(); +} + +public class KnowledgeUnitLink +{ + public string TargetUnitId { get; set; } + public string RelationType { get; set; } // "Next", "Defines", "References" +} +``` + +## 2. Multi-Stage Retrieval +Transition from simple `Take(Limit)` to a pipeline. + +### Step A: Hybrid Candidate Generation +Combine `pgvector` cosine similarity with full-text search if available. + +```csharp +var queryVector = await _embeddingGenerator.GenerateAsync(queryText); + +var candidates = await _dbContext.KnowledgeUnits + .Where(u => u.TenantId == tenantId) + .OrderBy(u => u.Embedding.CosineDistance(queryVector)) + .Take(20) // Get more candidates for reranking + .Select(u => new { u.Id, u.Content, u.Type }) + .ToListAsync(); +``` + +### Step B: Graph Expansion +Retrieve related units to provide full context. + +```csharp +// Example: Get "Contextual Neighbors" +var expandedIds = await _dbContext.KnowledgeUnitLinks + .Where(l => candidateIds.Contains(l.SourceUnitId) && l.RelationType == "ParentSection") + .Select(l => l.TargetUnitId) + .Distinct() + .ToListAsync(); + +var contextUnits = await _dbContext.KnowledgeUnits + .Where(u => expandedIds.Contains(u.Id)) + .ToListAsync(); +``` + +## 3. Reranking and Citations +Use a model to score the relevance of the expanded context and ensure the LLM cites sources. + +```csharp +// System Prompt for Grounded Generation +var systemPrompt = @" +You are a precision assistant. Answer ONLY using the provided Knowledge Units. +If the information is missing, state 'Information not found in knowledge map'. +Each answer segment MUST include a citation in format [UnitId]. +"; + +// Response Structure (using System.Text.Json or Structured Outputs) +public class RagResponse +{ + public string Answer { get; set; } + public List Citations { get; set; } +} +``` + +## 4. Ingestion Workflow +Instead of `string.Split`, use structural parsers: +1. **Parse**: Extract sections/tables (e.g., using `Unstructured` or custom Logic). +2. **Normalize**: Assign stable IDs based on content hash + source metadata. +3. **Embed**: Generate vectors for the canonical text of each unit. +4. **Relate**: Build links (e.g., `prev` -> `curr` -> `next`). diff --git a/.agent/skills/nexus-architecture-standards/SKILL.md b/.agent/skills/nexus-architecture-standards/SKILL.md new file mode 100644 index 0000000..97bd670 --- /dev/null +++ b/.agent/skills/nexus-architecture-standards/SKILL.md @@ -0,0 +1,40 @@ +--- +name: nexus-architecture-standards +description: Guidelines and automated checks for maintaining Clean Architecture and SaaS standards in the NexusReader project. +tags: [Architecture, CleanArchitecture, .NET, MediatR, SaaS, MultiTenancy] +version: 1.0.0 +--- + +# NexusReader Architecture Standards + +This skill defines the architectural guardrails for the NexusReader project to ensure consistency, scalability, and security. + +## Core Rules + +### 1. Clean Architecture Layers +- **Domain**: Pure business logic, entities, and enums. Zero dependencies on other layers. +- **Application**: Use cases, MediatR handlers, and interfaces. Depends ONLY on Domain. +- **Infrastructure**: Implementation details (DB context, AI services, Auth). Depends on Application and Domain. +- **Web/Mobile**: Presentation layer. Depends on Application (and Infrastructure for DI setup). + +> [!CAUTION] +> **Application MUST NOT depend on Infrastructure.** This is a common failure mode. Always use abstractions (interfaces) in Application and implement them in Infrastructure. + +### 2. Multi-Tenancy (Tenant Isolation) +- Every entity related to user data MUST have a `TenantId` property. +- Every query MUST filter by `TenantId` to prevent data leakage. +- Default `TenantId` is "global" for shared resources. + +### 3. Error Handling +- Use `FluentResults` (`Result`) for all Application services and handlers. +- Avoid throwing exceptions for expected business failures; use `Result.Fail()`. + +### 4. MediatR Patterns +- **Queries**: Read-only operations. Should return `Result`. Use `AsNoTracking()` in EF Core. +- **Commands**: State-changing operations. Should return `Result` or `Result`. + +## Audit Scripts +- [ArchCheck.sh](scripts/arch_check.sh): A shell script to scan for illegal cross-layer imports. + +## Reference Materials +- [Layer Dependency Matrix](artifacts/layer_matrix.md) diff --git a/.agent/skills/nexus-architecture-standards/scripts/arch_check.sh b/.agent/skills/nexus-architecture-standards/scripts/arch_check.sh new file mode 100755 index 0000000..39bfc9d --- /dev/null +++ b/.agent/skills/nexus-architecture-standards/scripts/arch_check.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Simple script to check for Clean Architecture violations in NexusReader + +APP_DIR="src/NexusReader.Application" +VIOLATIONS=$(grep -r "using NexusReader.Infrastructure" "$APP_DIR") + +if [ -n "$VIOLATIONS" ]; then + echo "ERROR: Clean Architecture violations found in $APP_DIR:" + echo "$VIOLATIONS" + exit 1 +else + echo "SUCCESS: No illegal Infrastructure dependencies found in Application layer." + exit 0 +fi diff --git a/src/NexusReader.Application/Commands/AI/VerifyGroundednessCommand.cs b/src/NexusReader.Application/Commands/AI/VerifyGroundednessCommand.cs index cba3a73..e1a738f 100644 --- a/src/NexusReader.Application/Commands/AI/VerifyGroundednessCommand.cs +++ b/src/NexusReader.Application/Commands/AI/VerifyGroundednessCommand.cs @@ -1,7 +1,6 @@ using FluentResults; using MediatR; using Microsoft.Extensions.AI; -using NexusReader.Infrastructure.Services; // For PromptRegistry namespace NexusReader.Application.Commands.AI; diff --git a/src/NexusReader.Application/Queries/Graph/GetKnowledgeGraphQueryHandler.cs b/src/NexusReader.Application/Queries/Graph/GetKnowledgeGraphQueryHandler.cs index bfc4ff7..c693761 100644 --- a/src/NexusReader.Application/Queries/Graph/GetKnowledgeGraphQueryHandler.cs +++ b/src/NexusReader.Application/Queries/Graph/GetKnowledgeGraphQueryHandler.cs @@ -28,15 +28,10 @@ internal sealed class GetKnowledgeGraphQueryHandler : IQueryHandler new GraphNodeDto(n.Id, n.Label, n.Group)) - .ToList(); - - var links = graph.Links - .Select(l => new GraphLinkDto(l.Source, l.Target, l.Value)) - .ToList(); - - return Result.Ok(new GraphDataDto { Nodes = nodes, Links = links }); + if (graph is null) + return Result.Ok(new GraphDataDto()); + + return Result.Ok(graph); } } diff --git a/src/NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs b/src/NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs index 2eeff2d..9d8d8f1 100644 --- a/src/NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs +++ b/src/NexusReader.Application/Queries/Library/SearchLibrarySemanticallyQuery.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.AI; using NexusReader.Application.DTOs.AI; using NexusReader.Application.Abstractions.Persistence; using Pgvector.EntityFrameworkCore; +using System.Text.Json; namespace NexusReader.Application.Queries.Library; @@ -88,7 +89,7 @@ public class SearchLibrarySemanticallyQueryHandler : IRequestHandler>(c.MetadataJson) + : JsonSerializer.Deserialize>(c.MetadataJson) }; // Enrich snippet with definitions if present diff --git a/src/NexusReader.Web.Client/Services/WasmKnowledgeService.cs b/src/NexusReader.Web.Client/Services/WasmKnowledgeService.cs index 58de739..ba8f4e1 100644 --- a/src/NexusReader.Web.Client/Services/WasmKnowledgeService.cs +++ b/src/NexusReader.Web.Client/Services/WasmKnowledgeService.cs @@ -24,6 +24,11 @@ public class WasmKnowledgeService : IKnowledgeService return await CallKnowledgeApiAsync("/api/knowledge/graph", text, cancellationToken); } + public async Task> GetKnowledgeMapAsync(string text, CancellationToken cancellationToken = default) + { + return await CallKnowledgeApiAsync("/api/knowledge/map", text, cancellationToken); + } + public async Task> GetSummaryAndQuizAsync(string text, CancellationToken cancellationToken = default) { return await CallKnowledgeApiAsync("/api/knowledge/summary", text, cancellationToken);