Dieses Proof of Concept demonstriert ein GraphRAG-System, das strikt entlang des BDAT-Modells sowie der Trennung zwischen Indexing (Offline) und Querying (Online) wie in meiner Bachelorarbeit "GraphRAG im Unternehmenskontext: Gestaltung eines Referenzmodells für das Enterprise Architecture Management" beschrieben, organisiert ist. Alle Komponenten sind so geschnitten, dass Governance- und Security-Funktionen nachvollziehbar eingebettet bleiben.
Voraussetzungen
- Python 3.11
- Neo4j (lokal oder remote erreichbar)
- Ollama (lokal oder remote erreichbar)
1) Python-Umgebung vorbereiten
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
2) Modelle für Ollama bereitstellen
ollama pull phi3
ollama pull nomic-embed-text
3) .env anlegen Lege eine Datei .env im Projektroot an:
NEO4J_URI=bolt://localhost:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=<dein_passwort>
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL_CHAT=phi3
OLLAMA_MODEL_EMBED=nomic-embed-text
CHROMA_PERSIST_DIR=./data/chroma
CHROMA_COLLECTION_NAME=graphrag_poc
4) Indexing ausführen (Offline)
python main.py index
5) Query ausführen (Online)
python main.py query --question "Welche Auflagen gelten für Vertragskündigungen?" --role legal_analyst
6) Golden-Workflow (Referenzlauf)
python main.py golden --role legal_analyst
Erwartete Outputs
- out/golden_result.json (Antwort + EvidenceObject + Metrics)
- out/audit.jsonl (Audit-Events)
- Lokale Laufartefakte unter runs/YYYY/MM/DD (nicht im Repo versioniert)
- Business: Nachvollziehbare Nutzung von Vertrags- und Policywissen für Audits.
- Data: Konsistente Pflege von Ontologie-, Policy-, Dokument- und Provenance-Daten.
- Application: Saubere Schnittstellen zwischen Retrieval, Kontextaufbau, Orchestrierung und Governance.
- Technology: Austauschbare Adapter für Graph-/Vektor-Stores und LLM-Anbieter.
PoC-Bachelorarbeit/ # Projekt-Root
│
├── main.py # CLI-Einstiegspunkt für index/query/golden
│
├── data/ # Eingabedaten
│ ├── contracts/ # Vertragsdokumente für Ingestion
│ └── rules/ # Regel-/Policy-Dokumente für den PoC
│
├── indexing_subsystem/ # Offline-Indexing (Ingestion → Embeddings → Graph)
│ ├── ingestion.py # Einlesen/Chunking/Normalisierung
│ ├── graph_builder.py # Entitäten/Relationen → Neo4j
│ ├── embedding_builder.py # Embeddings → Chroma
│ └── provenance_collector.py # Lineage/Provenance
│
├── querying_subsystem/ # Online-Querying (RAG-Orchestrierung)
│ ├── query_interface.py # Einstiegspunkt; initiiert AuthZ-Flow + RequestContext
│ ├── query_rewriter_prompt_builder.py # Query-Planung/Token-Budget
│ ├── hybrid_retriever.py # Graph+Vector Retrieval (rollenbewusst)
│ ├── context_builder.py # EvidenceObject aus Quellen/Pfaden/Chunks
│ ├── policy_gate.py # Pre-Gen Policy Enforcement
│ ├── answer_formatter_output_filter.py # Attribution + Output-Filter
│ ├── llm_gateway.py # LLM-Abstraktion (Provider-agnostisch)
│ ├── authz_interceptor.py # Pre-Retrieval AuthZ-Check
│ ├── reranker_consolidator.py # Reranking/Consolidation
│ └── subgraph_cache.py # Cache für Traversal-Ergebnisse
│
├── governance_security/ # Governance & Security (Querschnitt)
│ ├── authz_service.py # RBAC/Claims-Logik
│ ├── policy_engine.py # Policy-Evaluierung aus policies.yaml
│ └── audit_logger.py # Audit-Events & Metriken
│
├── shared_infrastructure/ # Gemeinsame Infrastruktur
│ ├── config.py # Settings/ENV-Konfiguration
│ │
│ ├── adapters/ # Konkrete Store/LLM-Adapter
│ │ ├── openai_adapter_optional.py # Optionaler OpenAI-Adapter
│ │ ├── neo4j_adapter.py # Neo4j-Adapter
│ │ ├── ollama_adapter.py # Ollama-Adapter
│ │ └── chroma_adapter.py # Chroma-Adapter
│ ├── models/ # Domänenmodelle (Dataclasses)
│ │ ├── answer.py # Antwortmodell
│ │ ├── evidence_object.py # EvidenceObject
│ │ ├── policy_decision.py # Policy-Entscheidung
│ │ ├── provenance.py # Provenance
│ │ ├── request_context.py # RequestContext
│ │ └── retrieval_result.py # RetrievalResult
│ │
│ ├── interfaces/ # Abstrakte Schnittstellen
│ │ ├── llm_interface.py # LLM-Interface
│ │ └── store_interface.py # Store-Interfaces
│ │
│ │
│ └── registry/ # Governance-Artefakte
│ ├── ontology.json # Ontologie/Graphschema
│ └── policies.yaml # Policies/Regeln
│
├── scripts/ # Hilfsskripte (Betrieb/Checks/Workflows)
│ ├── verify_setup.py # Registry/Dataset/Config-Check
│ ├── run_harness.py # Validierungs-Harness
│ ├── run_golden_workflow.py # Golden-Workflow
│ └── ... # Weitere Skripte
│
├── tests/ # Pytest-Tests
│ ├── test_golden_query_legal_analyst.py # Golden-Query-Flow
│ ├── test_business_user_blocked_or_filtered.py # RBAC/Filter
│ └── test_policy_pre_gen_order_and_risk_trigger.py # Policy-Order/Risk
│
└── requirements.txt # Python-Abhängigkeiten
indexing_subsystem/ingestion.py: Einlesen der Rohdokumente, Chunking/Segmentierung sowie Normalisierung von Basis-Metadaten (z. B. Dokument-ID, Quelle, Timestamp).indexing_subsystem/provenance_collector.py: Erzeugung und Persistierung von Provenance-/Lineage-Metadaten (z. B. source_id, version, chunk_id) als Grundlage für Auditierbarkeit (AR4).indexing_subsystem/embedding_builder.py: Erzeugung von Embeddings für Text-Chunks und Persistierung im Vector Store (Chroma).indexing_subsystem/graph_builder.py: Extraktion/Mapping von Entitäten und Relationen gemäßshared_infrastructure/registry/ontology.jsonund Persistierung im Graph Store (Neo4j); Verknüpfung zu chunk_id zur Rückverfolgbarkeit (AR4).
querying_subsystem/query_interface.py: Externer Einstiegspunkt (I_Querying) für Nutzeranfragen;RequestContextwird nach AuthZ-Prüfung erstellt/weitergereicht (AR1).querying_subsystem/authz_interceptor.py: Pre-Retrieval-Autorisierungsprüfung (RBAC/Claims) als erster Security-Checkpoint (AR8).querying_subsystem/query_rewriter_prompt_builder.py: Query-Planning inkl. Normalisierung, Extraktion von Suchparametern und Token-Budgetierung (AR5).querying_subsystem/hybrid_retriever.py: Hybrid Retrieval (Graph + Vector) unter Berücksichtigung von Rollen/Claims; Anbindung an Neo4j/Chroma (AR2, AR8).querying_subsystem/subgraph_cache.py: Laufzeit-Cache für wiederkehrende Subgraph-/Traversal-Ergebnisse zur Latenz- und Kostenreduktion (AR5).querying_subsystem/reranker_consolidator.py: Verdichtung und Deduplizierung der Retrieval-Kandidaten (Score-Fusion/Reranking) zur Kontextoptimierung (AR5).querying_subsystem/context_builder.py: Konstruktion des EvidenceObject aus Textquellen, Graphpfaden und Metadaten; zentrale Grundlage für Attribution (AR3).querying_subsystem/policy_gate.py: Pre-Generation Policy Enforcement (Redaction/Block/Allow) gegenshared_infrastructure/registry/policies.yaml(AR8).querying_subsystem/llm_gateway.py: Provider-agnostische LLM-Anbindung überLLMInterface(Ollama; optional OpenAI) als Austauschbarkeitsnachweis (AR6).querying_subsystem/answer_formatter_output_filter.py: Finales Formatting, Attribution (Quellen/Pfade aus EvidenceObject) sowie Post-Generation Output-Filter/Redaction (AR3, AR8).
governance_security/authz_service.py: Zentraler RBAC/Claims-Service (Rollenlogik, Ressourcen-/Scope-Prüfung) (AR8).governance_security/policy_engine.py: Policy-Evaluierung (z. B. Risk-V-01, Klassifikations-/Redaction-Regeln) auspolicies.yaml(AR8).governance_security/audit_logger.py: Strukturierte Events, Trace-/Request-Korrelation, Basis-Metriken zur Observability/Audit-Spur (AR7, AR4).
shared_infrastructure/interfaces/: Operationalisiert AR6 (Austauschbarkeit) durch lose Kopplung zwischen Orchestrierung und Technologieprovidern.llm_interface.py:LLMClientmitgenerate()undembed()für anbieterneutrale Generierung und Embeddings.store_interface.py:GraphStore(Risk-Query + Pfade) undVectorStore(Similarity Search) als minimale AR2-Schnittstellen.
shared_infrastructure/adapters/: Konkrete Implementierungen (neo4j_adapter.py,chroma_adapter.py,ollama_adapter.py, optionalopenai_adapter_optional.py).shared_infrastructure/models/: Explizite Artefaktmodelle (request_context.py,provenance.py,evidence_object.py,retrieval_result.py,policy_decision.py,answer.py) zur Nachvollziehbarkeit und zu sauberen Übergaben zwischen Komponenten (AR3/AR4).shared_infrastructure/registry/: Statische Governance-Artefakte (ontology.json,policies.yaml) als Source of Truth für Mapping/Policy (AR1, AR8).
- scripts/: Hilfsskripte für Setup-Checks, Harness-Runs und Exporte (z. B.
verify_setup.py,run_harness.py,run_golden_workflow.py). - tests/: Pytest-basierte Regressionstests für zentrale Governance- und Retrieval-Fälle.
- Offline: Ingestion → Provenance → Embeddings (Chroma) → Graphaufbau (Neo4j).
- Online: Query Intake → AuthZ → Query Planning → Hybrid Retrieval → Reranking → EvidenceObject → Policy Gate → LLM → Output Filter/Attribution → Logging/Metriken.
Architekturhinweis (AR5/EAM): Durch die strikte Trennung von Offline-Indexing und Online-Querying werden rechenintensive Transformationen vorverlagert. Das adressiert Effizienz- und Kostenanforderungen (AR5).
- Neo4j lokal (z. B.
NEO4J_URI=neo4j://127.0.0.1:7687) - Ollama lokal (z. B.
OLLAMA_BASE_URL=http://localhost:11434) - Modelle lokal installiert:
phi3(Chat) undnomic-embed-text(Embeddings)
- Neo4j & Chroma lokal, Ollama remote
OLLAMA_BASE_URLauf den Remote-Host setzen (z. B.http://<remote-ip>:11434)- Keine Codeänderungen nötig, nur ENV/Config
- Getestet mit Python 3.11 auf einem Apple Silicon Mac um Library kompatibilität zu sichern (onnxruntime/chromadb)
- Abhängigkeiten installieren:
pip install -r requirements.txt - CLI (Kap. 4.3 → 4.4):
python main.py indexpython main.py query --question "…" --role legal_analystpython main.py golden --role legal_analyst
- Output:
out/golden_result.json(JSON mit Answer + EvidenceObject + Metrics)out/audit.jsonl(korrelierbare Events)
Die Anwendung lädt Variablen aus .env (siehe shared_infrastructure/config.py). Wichtige Variablen:
- NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD
- OLLAMA_BASE_URL, OLLAMA_MODEL_CHAT, OLLAMA_MODEL_EMBED
- CHROMA_PERSIST_DIR, CHROMA_COLLECTION_NAME
- TOKEN_BUDGET_MAX_CHUNKS, TOP_K_VECTOR, TOP_K_GRAPH
- Fehler “NEO4J_PASSWORD ist nicht in der .env Datei gesetzt.” → .env anlegen und Passwort setzen.
- Leere Antworten/keine Evidenzen → zuerst index ausführen und prüfen, ob Neo4j/Ollama erreichbar sind.
- Langsame Runs → TOP_K_* reduzieren oder TOKEN_BUDGET_MAX_CHUNKS anpassen.
Alle Laufartefakte (Runs, Audit-Exporte, Plots) werden lokal erzeugt und sind bewusst vom Git-Repo ausgeschlossen. Das Repo enthält den vollständigen PoC-Code sowie Beispiel-Daten und die Konfigurationsanleitung für einen reproduzierbaren Aufbau.