Ga naar inhoud

AI-Strategie Analyse & Integratie met Buurts Ecosysteem

Datum: 2026-03-15 Bronnen: "LLM Mechanics and Implementation Strategies" (3 YouTube-analyses) + "Beyond Vibe Coding: Engineering Through Interactive Intelligence" (Jeremy Howard interview) + "Vector Search with LLMs" (Grok-analyse, Computerphile) Doel: Vertaal inzichten naar concrete verbeteringen voor BORIS/Buurts Ecosysteem


1. Key Insights uit de Bronnen

Bron 1: LLM Mechanics — Drie Video-analyses

Categorie: Tech + Ethics + Strategy

De drie geanalyseerde bronnen (Palisade Research, Theos Theory, Computerphile) bieden samen een genuanceerd beeld van wat LLMs zijn, waar ze falen, en hoe RAG dat kan compenseren.

Kernpunten:

  • Scaling Laws & Task Length: De autonome taakduur van LLMs verdubbelt elke 7 maanden. Claude 4.5 zat op 4+ uur. Dit maakt het realistisch om grotere herstructureringstaken als één opdracht te formuleren, maar vereist tussentijdse verificatie.

  • Jagged Intelligence: LLMs presteren inconsistent — ze lossen olympiade-wiskunde op maar falen bij simpele vermenigvuldigingen. De oorzaak is token-patroonherkenning vs. formele logica. Elke numerieke of telbare output van een agent moet deterministisch worden geverifieerd.

  • Rationalisatie ≠ Redenering: Chain-of-Thought (CoT) is vaak post-hoc rationalisatie, niet werkelijke redenering. Het model genereert eerst een antwoord en construeert daarna een plausibele uitleg. Dit betekent dat "aha-momenten" in reasoning traces geen betrouwbaar signaal zijn.

  • Model Collapse: Training op AI-gegenereerde data leidt tot informatieverlies in de staarten van de distributie. Dit is direct relevant voor onze documentatiestructuur: als agents documenten herschrijven op basis van eerder door AI geschreven tekst, degenereert de kwaliteit progressief.

  • RAG als Oplossing: Vector search met cosine similarity is robuust (spelfouten, meertalig) en reduceert hallucinatie door de agent te beperken tot verstrekte context. Chunking met overlap (800 tokens, 10% overlap) voorkomt dat feiten worden doorgesneden.

Bron 2: Jeremy Howard — Beyond Vibe Coding

Categorie: Strategy + Integration + Ethics

Jeremy Howard's kritiek op "vibe coding" is fundamenteel: AI-coding via een terminal is een stochastisch proces dat de illusie van controle wekt maar "understanding debt" opbouwt.

Kernpunten:

  • Slot Machine Coding: De gebruiker trekt aan een hendel met een stochastische uitkomst. Incidentele "wins" maken het verslavend, maar er bouwt zich technische schuld op als niemand de geproduceerde code begrijpt.

  • Interpolatie vs. Extrapolatie: AI is uitstekend in stijltransfer en combinatorische creativiteit (interpolatie), maar faalt bij het ontwerpen van nieuwe abstractiehiërarchieën (extrapolatie). Dit is cruciaal: BORIS's agentarchitectuur is een nieuw ontwerp, geen remix van bestaande GitHub-code.

  • "Reality Pushes Back": Engineering gebeurt alleen wanneer er frictie is — tests die falen, data die niet klopt, stakeholders die weerstand bieden. Zonder frictie leert niemand iets en erodeert organisatiekennis.

  • Interactieve Loops: Howard pleit voor stateful omgevingen (Jupyter-stijl) waar mens en AI objecten in real-time manipuleren. De huidige CLI-aanpak is volgens hem "inhumaan" omdat het de mens uit het exploratieve proces verwijdert.

  • Literate Programming: SOP's als "living documents" die niet alleen beschrijven maar ook de code bevatten om de taak uit te voeren. NBDEV-filosofie.


Bron 3: Grok-analyse — Vector Search & RAG-architectuur

Categorie: Tech + Integration

Op basis van de Computerphile video over vector search stelt Grok dat het systeem "onvoldoende ingericht" is. Dit was op het moment van schrijven deels correct. De huidige status na Sprint 2.1:

  • Chunking & overlap: opgelost — SmartChunker doet 400-woord chunks met 10% overlap, semantische grenzen gerespecteerd.
  • Zone-isolatie als pre-filter: sterker opgelost dan Grok voorstelt — ZonedVectorStore scheidt fysiek op database-niveau (niet alleen mappenstructuur).
  • Metadata-verrijkte retrieval: opgelost — UDSMetadata V2 met 6 filterbare velden.
  • "Weiger als geen context": deels open — Curator verwerpt lage-similarity chunks, maar er is geen hard gate op de Synthesizer die generatie blokkeert bij nul goedgekeurde chunks.
  • Tegenstrijdigheidsdetectie: open — geen mechanisme dat semantisch overlappende maar inhoudelijk conflicterende chunks detecteert.
  • "Truth" prioritering: open — docs/truth/ is aangelegd maar chunks daarin worden niet preferent opgehaald.

2. Alignment met Buurts Ecosysteem: Gaps & Opportunities

Wat BORIS al goed doet

Inzicht uit bronnen Huidige implementatie Status
RAG voor contextbeheer ZonedVectorStore (3 zones), SmartChunker met overlap Solide
Safety zones RED/YELLOW/GREEN isolatie, HITL verplicht bij YELLOW Solide
Content filtering Block list + green zone allow list in safety/policy.py Basisniveau
Stakeholder-specifieke output HERALD met 9 doelgroepen, C1-C5, DES 0-20 Net geïntegreerd
Deterministische CI Ruff + Bandit + pytest + pip-audit in CI pipeline Werkend
Configuratie-scheiding Pydantic BaseSettings, .env, YAML configs Goed

Gaps geïdentificeerd

# Gap Bron Impact Huidige staat
G1 Geen output-validatieloop Jagged Intelligence, Howard HOOG Curator checkt input-chunks, maar er is geen deterministische validatie van gegenereerde output (alleen HERALD's interne B1-check)
G2 Model Collapse risico in docs Model Collapse MIDDEL Geen mechanisme om te garanderen dat agents schrijven op basis van mens-geschreven bronnen i.p.v. eerder AI-gegenereerde samenvattingen
G3 Geen "Reality Pushes Back" loop Howard HOOG Geen mechanisme om agent-output te testen tegen de werkelijkheid (bijv. feitelijke claims checken tegen vectorstore)
G4 CoT-vertrouwen zonder verificatie Rationalisatie vs. Redenering MIDDEL OllamaSynthesizer stuurt antwoord terug zonder reasoning-trace validatie
G5 Geen provenance tracking Model Collapse, RAG MIDDEL DocumentChunk bevat similarity_score maar geen generation_source (mens vs. AI)
G6 HERALD quality checks zijn soft Jagged Intelligence MIDDEL B1-check is heuristisch (zinslengte/woordlengte), niet gevalideerd tegen gestandaardiseerde readability metrics
G7 Geen interactieve feedback loop Howard, Interactieve Loops LAAG Systeem is request/response, geen iteratieve verfijning met stakeholder feedback
G8 Living Documents ontbreken Howard, NBDEV LAAG SOP's zijn statische Markdown, geen executable documenten
G9 Geen hard "no context, no answer" gate Grok-analyse, RAG HOOG Curator verwerpt chunks, maar Synthesizer kan nog steeds genereren uit trainingsdata bij 0 goedgekeurde chunks
G10 Geen Source Priority Boost voor docs/truth/ Grok-analyse MIDDEL docs/truth/ bestaat maar chunks daarin worden niet preferent opgehaald boven oudere content
G11 Geen Contradiction Detector Grok-analyse MIDDEL Oude en nieuwe roadmaps kunnen semantisch dicht bij elkaar liggen zonder dat conflicterende claims worden gesignaleerd

3. Integratie-aanbevelingen

Prioriteit 1: HIGH IMPACT, LOW EFFORT — Sprint 2.x fit

R1. Output Validator Agent (sluit Gap G1, G3, G4)

Wat: Een deterministische validatielaag die na elke Synthesizer-output draait. Hoe: Nieuwe klasse OutputValidator in agents/output_validator.py.

# agents/output_validator.py
from dataclasses import dataclass
from typing import List, Optional

@dataclass
class ValidationResult:
    is_valid: bool
    warnings: List[str]
    factual_claims_verified: int
    factual_claims_total: int
    readability_score: Optional[float]  # Flesch-Douma voor NL
    source_coverage: float  # % claims traceable naar chunks

class OutputValidator:
    """Deterministisch valideert agent-output tegen bronchunks."""

    def validate(self, output_text: str, source_chunks: list,
                 audience: str = "algemeen") -> ValidationResult:
        warnings = []

        # 1. Factual grounding check
        claims = self._extract_claims(output_text)
        verified = self._verify_against_chunks(claims, source_chunks)

        # 2. Readability (Flesch-Douma voor Nederlands)
        readability = self._flesch_douma(output_text)

        # 3. Hallucination detection: zoek beweringen niet in chunks
        ungrounded = [c for c in claims if c not in verified]
        if ungrounded:
            warnings.append(f"HALLUCINATION_RISK: {len(ungrounded)} claims niet traceerbaar naar bronchunks")

        # 4. Lengte-check per audience
        # 5. Verboden termen check (uit config)

        return ValidationResult(
            is_valid=len(ungrounded) == 0,
            warnings=warnings,
            factual_claims_verified=len(verified),
            factual_claims_total=len(claims),
            readability_score=readability,
            source_coverage=len(verified) / max(len(claims), 1)
        )

Integratie in pipeline:

# In hub.py, na synthesizer
result = await self.synthesizer.synthesize(query, approved_chunks)
validation = self.output_validator.validate(
    result.answer, approved_chunks, audience=request.audience
)
if not validation.is_valid:
    result.warnings.extend(validation.warnings)
    result.requires_hitl = True

Effort: Medium (2-3 dagen) Sprint fit: Sprint 2.2 of 2.3


R2. Provenance Tagging (sluit Gap G2, G5)

Wat: Voeg generation_source veld toe aan UDSMetadata om mens-geschreven vs. AI-gegenereerde content te onderscheiden. Hoe: Extend UDSMetadata V2.

# In src/domain/entities.py
class GenerationSource(str, Enum):
    HUMAN = "human"          # Mens-geschreven origineel
    AI_GENERATED = "ai_generated"  # Door agent gegenereerd
    AI_REVIEWED = "ai_reviewed"    # AI-gegenereerd, mens-gereviewd
    HYBRID = "hybrid"        # Samenwerking mens + AI

# In UDSMetadata
generation_source: GenerationSource = GenerationSource.HUMAN
generation_model: Optional[str] = None  # bijv. "llama3.2" of "herald-v1"
original_source_ids: List[str] = []     # chunk_ids van bronmateriaal

Anti-collapse regel: Agents krijgen in hun system prompt:

"Wanneer je schrijft, gebruik ALLEEN chunks met generation_source=HUMAN of generation_source=AI_REVIEWED als primaire bron. Gebruik NOOIT AI_GENERATED chunks als enige bron voor nieuwe content."

Effort: Low (halve dag entity-wijziging + chunker-aanpassing) Sprint fit: Sprint 2.2


R3. Flesch-Douma Readability voor Nederlands (sluit Gap G6)

Wat: Vervang HERALD's heuristische B1-check door de gestandaardiseerde Flesch-Douma formule. Hoe: Utility-functie in utils/readability.py.

# utils/readability.py
import re

def flesch_douma(text: str) -> float:
    """
    Flesch-Douma leesbaarheidsscore voor Nederlands.
    206.835 - 0.93 * (woorden/zinnen) - 77 * (lettergrepen/woorden)

    Interpretatie:
    90-100: Zeer makkelijk (groep 5)
    60-70:  Standaard (B1-niveau)
    30-50:  Moeilijk (vakpublicatie)
    0-30:   Zeer moeilijk (wetenschappelijk)
    """
    sentences = [s.strip() for s in re.split(r'[.!?]+', text) if s.strip()]
    words = text.split()
    syllables = sum(_count_dutch_syllables(w) for w in words)

    if not sentences or not words:
        return 0.0

    asl = len(words) / len(sentences)  # avg sentence length
    asw = syllables / len(words)       # avg syllables per word

    return 206.835 - (0.93 * asl) - (77.0 * asw)

def _count_dutch_syllables(word: str) -> int:
    """Heuristiek voor Nederlandse lettergrepen."""
    word = word.lower().strip(".,!?;:'\"")
    vowels = "aeiouyèéêëïîôöüû"
    count = 0
    prev_vowel = False
    for char in word:
        is_vowel = char in vowels
        if is_vowel and not prev_vowel:
            count += 1
        prev_vowel = is_vowel
    return max(count, 1)

def readability_level(score: float) -> str:
    """Vertaal score naar taalniveau."""
    if score >= 80: return "A2"
    if score >= 60: return "B1"
    if score >= 40: return "B2"
    if score >= 20: return "C1"
    return "C2"

Integratie in HERALD:

# In herald_synthesizer.py _run_kwaliteitscheck()
from utils.readability import flesch_douma, readability_level

score = flesch_douma(document_text)
level = readability_level(score)
if comm_niveau == "C5" and score < 60:
    warnings.append(f"READABILITY: score {score:.0f} ({level}), verwacht B1+ (≥60)")

Effort: Low (1 dag) Sprint fit: Sprint 2.2


Prioriteit 2: HIGH IMPACT, MEDIUM EFFORT

R4. Grounded Generation Protocol (sluit Gap G3)

Wat: Dwing agents om bij elke claim een [bron: chunk_id] referentie te geven, en valideer die referenties automatisch. Hoe: Aanpassing in OllamaSynthesizer system prompt + post-processing.

# System prompt toevoeging voor OllamaSynthesizer
GROUNDING_INSTRUCTION = """
REGEL: Elke feitelijke bewering MOET worden gevolgd door een bronverwijzing
in het formaat [bron: CHUNK_ID]. Gebruik ALLEEN informatie uit de aangeleverde
chunks. Als je een bewering niet kunt onderbouwen met een chunk, schrijf dan:
"[bron: niet beschikbaar — HITL vereist]".
"""

# Post-processing in output_validator.py
def _verify_source_references(self, text: str, chunks: list) -> list:
    """Check of alle [bron: X] referenties daadwerkelijk bestaan."""
    import re
    refs = re.findall(r'\[bron:\s*([^\]]+)\]', text)
    chunk_ids = {c.metadata.chunk_id for c in chunks}
    invalid = [r for r in refs if r not in chunk_ids and "niet beschikbaar" not in r]
    return invalid

Effort: Medium (2 dagen: prompt engineering + validator + tests) Sprint fit: Sprint 2.3


R5. Anti-Autopilot Guardrails (sluit Gap G1, Howard's "small steps")

Wat: Beperk de maximale output-lengte per agent-call en dwing stapsgewijze bevestiging af voor grote taken. Hoe: Configureerbaar per agent in config.

# Toe te voegen aan herald_config.yml of een nieuw agents_config.yml
guardrails:
  max_output_tokens: 2000        # Per synthesize() call
  max_chunks_per_query: 10       # Voorkom context overload
  require_hitl_above_tokens: 1500  # Automatisch HITL als output lang is
  step_verification: true         # Toon tussenresultaat voor bevestiging

Effort: Medium (1-2 dagen) Sprint fit: Sprint 2.3


Prioriteit 3: MEDIUM IMPACT, HIGH EFFORT — Later plannen

R6. Interactive Feedback Loop (sluit Gap G7)

Wat: Stakeholders kunnen via een simpel formulier (web UI of MS Teams) feedback geven op agent-output, die terugvloeit als metadata in de vectorstore. Hoe: Nieuw endpoint /feedback + FeedbackStore.

Effort: High (1-2 weken: UI + storage + feedback-loop in agents) Sprint fit: Sprint 3+


R7. Living Documents / NBDEV-stijl SOP's (sluit Gap G8)

Wat: SOP's die naast instructies ook uitvoerbare code-blokken bevatten. Hoe: MkDocs + mkdocs-jupyter plugin, of custom Markdown executor.

Effort: High (experimenteel) Sprint fit: Sprint 4+


4. Risico's & Mitigaties

# Risico Bron Mitigatie
R-1 Model Collapse in documentatie Bron 1 Provenance tagging (R2) + anti-collapse regel in agent prompts
R-2 Hallucinatie in stakeholderdocs Bron 1, Bron 2 Output Validator (R1) + Grounded Generation (R4) + HITL
R-3 Understanding Debt (team begrijpt code niet meer) Howard Code reviews verplicht, agent moet # WHY: comments schrijven, geen grote refactors zonder architectenreview
R-4 Vendor lock-in Algemeen Alle agents gebruiken BaseSynthesizer interface, Ollama als LLM-backend (lokaal), Weaviate is OSS. Geen cloud-only dependencies
R-5 Stochastische output bij beslisdocumenten Howard (slot machine) Deterministisch post-processing (R1), twee-staps review (agent → HITL), nooit autonome publicatie
R-6 Readability drift (B1 claimen maar feitelijk B2/C1) Jagged Intelligence Flesch-Douma scoring (R3) als hard gate, niet als suggestie
R-7 Pilot-readiness Alle bronnen Alle agents werken in YELLOW_ZONE (geen autonome RED output), MockSynthesizer als fallback, feature flags per KWP

Vendor-free architectuur bevestigd

De huidige stack is volledig vendor-free: - LLM: Ollama (lokaal, open-source modellen) - Vector DB: Weaviate (OSS, Docker) of ChromaDB (OSS, embedded) - Embeddings: sentence-transformers (lokaal, geen API-calls) - MCP: Open protocol, geen Anthropic lock-in - CI: GitHub Actions (migreerbaar naar GitLab CI/Jenkins)

Geen enkele aanbeveling introduceert een vendor-dependency.


5. Next Steps — YAML Plan

# AI Strategy Integration Roadmap
# Gebaseerd op: LLM Mechanics + Beyond Vibe Coding analyse
# Datum: 2026-03-15

sprint_2_2:
  naam: "Output Quality & Provenance"
  doel: "Deterministische validatie van agent-output + anti-collapse"
  taken:
    - id: T1
      naam: "Provenance tagging in UDSMetadata"
      beschrijving: |
        Voeg GenerationSource enum + generation_model + original_source_ids
        toe aan UDSMetadata. Update SmartChunker om generation_source mee
        te geven bij ingest.
      bestanden:
        - src/domain/entities.py
        - rag/chunker.py
        - tests/test_entities.py
      effort: low

    - id: T2
      naam: "Flesch-Douma readability module"
      beschrijving: |
        Nieuwe module utils/readability.py met flesch_douma() en
        readability_level(). Integreer in HERALD _run_kwaliteitscheck().
      bestanden:
        - utils/readability.py (nieuw)
        - agents/herald_synthesizer.py (wijzig)
        - tests/test_readability.py (nieuw)
      effort: low

    - id: T3
      naam: "OutputValidator basisversie"
      beschrijving: |
        Nieuwe agent agents/output_validator.py met:
        - Factual grounding check (claims vs chunks)
        - Readability score (via T2)
        - Hallucination risk scoring
        - Source coverage percentage
      bestanden:
        - agents/output_validator.py (nieuw)
        - tests/test_output_validator.py (nieuw)
      effort: medium
      afhankelijk_van: [T1, T2]

sprint_2_3:
  naam: "Grounded Generation & Guardrails"
  doel: "Agents produceren verifieerbare, brongebonden output"
  taken:
    - id: T4
      naam: "Grounded Generation protocol"
      beschrijving: |
        System prompt wijziging voor OllamaSynthesizer en HERALD:
        verplichte [bron: chunk_id] referenties. Post-processing
        validatie van referenties in OutputValidator.
      bestanden:
        - agents/synthesizer.py (prompt wijziging)
        - agents/herald_synthesizer.py (prompt wijziging)
        - agents/output_validator.py (extend)
      effort: medium
      afhankelijk_van: [T3]

    - id: T5
      naam: "Anti-autopilot guardrails"
      beschrijving: |
        Configureerbare limieten per agent: max_output_tokens,
        max_chunks_per_query, require_hitl_above_tokens.
        Implementeer in BaseSynthesizer als optionele post-hook.
      bestanden:
        - config.py (nieuwe settings)
        - agents/synthesizer.py (post-hook)
        - agents/herald_config.yml (guardrails sectie)
      effort: medium

    - id: T6
      naam: "Anti-collapse prompt engineering"
      beschrijving: |
        Update alle agent system prompts met:
        - "Gebruik ALLEEN chunks met generation_source=HUMAN of AI_REVIEWED"
        - "Vermeld generation_source in output metadata"
        - Test met mixed corpus (50% AI-slop, 50% human)
      bestanden:
        - agents/synthesizer.py
        - agents/herald_synthesizer.py
        - tests/test_anti_collapse.py (nieuw)
      effort: low
      afhankelijk_van: [T1]

    - id: T7
      naam: "Hard 'no context, no answer' gate in hub.py"
      beschrijving: |
        Als Curator 0 chunks goedkeurt, blokkeert Hub de Synthesizer-call
        en retourneert een expliciete "onvoldoende informatie" HubResult.
        Voorkomt dat OllamaSynthesizer genereert vanuit trainingsdata.
      bestanden:
        - agents/hub.py (wijzig: check op len(approved_chunks) == 0)
        - tests/test_agents.py (extend: test no-context scenario)
      effort: low
      sluit_gap: G9

    - id: T8
      naam: "Source Priority Boost in scout.py"
      beschrijving: |
        Chunks met bron_type=PROTOCOL of source.startswith("docs/truth/")
        krijgen een 1.25x boost op similarity_score vóór re-ranking.
        Configureerbaar via TRUTH_BOOST_FACTOR in config.py.
      bestanden:
        - agents/scout.py (wijzig: _apply_truth_boost() methode)
        - config.py (nieuw: TRUTH_BOOST_FACTOR: float = 1.25)
        - tests/test_scout_boost.py (nieuw)
      effort: low
      sluit_gap: G10

    - id: T9
      naam: "Contradiction Detector in OutputValidator"
      beschrijving: |
        Vergelijk chunks paarsgewijs op semantische contradictie:
        als twee chunks hoge similarity hebben (>0.85) maar conflicterende
        datum- of versie-claims bevatten, markeer als CONTRADICTION_RISK.
        Heuristisch: datum-extractie + versienummer-vergelijking.
      bestanden:
        - agents/output_validator.py (extend: _detect_contradictions())
        - tests/test_output_validator.py (extend)
      effort: medium
      sluit_gap: G11
      afhankelijk_van: [T3]

sprint_3_plus:
  naam: "Feedback & Interactive Loops"
  doel: "Stakeholder feedback terugkoppelen naar vectorstore"
  taken:
    - id: T7
      naam: "Feedback endpoint + storage"
      effort: high
      sprint: "3.0"

    - id: T8
      naam: "Living Documents (NBDEV-stijl SOP's)"
      effort: high
      sprint: "4.0"

Samenvatting

De twee documenten bevestigen dat de architectuurkeuzes van BORIS (RAG-first, zone-isolatie, HITL, vendor-free) fundamenteel juist zijn. De belangrijkste verbetermogelijkheden zitten niet in nieuwe features maar in kwaliteitsborging van output: deterministisch valideren dat agents niet hallucineren, dat ze schrijven op basis van menselijke bronnen, en dat ze leesbaar schrijven voor de beoogde doelgroep.

De drie quick wins (Provenance Tagging, Flesch-Douma, OutputValidator) kosten samen ~4 werkdagen en sluiten de vier ernstigste gaps. De "Beyond Vibe Coding" inzichten vertalen zich vooral naar werkwijze-principes: kleine stappen, verplichte HITL, en het besef dat agent-output een concept is — nooit een eindproduct.