Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
23 KiB
Schoolnieuws met controle: zelfkritiek en een poortwachter
Handleiding 7 bij de workshop AI Agents
LeX Consultancy B.V. · 20 september 2026
In handleiding 3 bouwde je Schoolnieuws: één kernboodschap wordt een bericht voor website, ouderapp en sociale media. De teksten waren goed, maar ze gingen ongecontroleerd naar buiten. Deze handleiding voegt twee dingen toe die in de bijlage Ontwerppatronen patroon 4 en 5 heten:
| Toevoeging | Patroon | Wat het doet |
|---|---|---|
| Controleur (LLM) | Zelfkritiek | Leest het ouderappbericht nog eens tegen de schrijfwijzer en verbetert het |
| Poortwachter (Code) plus IF/ELSE | Poortwachter | Controleert harde regels met code: woordaantal, verboden woorden, hashtag, ontbrekende informatie. Klopt alles, dan naar buiten; anders naar de communicatiemedewerker mét de redenen |
Het verschil tussen die twee is de kern van deze handleiding. De Controleur is een model dat een model nakijkt: goed voor vorm en toon, maar het kan zichzelf overtuigen. De Poortwachter is zes regels Python die niet te overtuigen zijn: 81 woorden is te veel, punt. Samen leveren ze wat een communicatiemedewerker wil: minder nakijkwerk, en zekerheid dat de regels die er echt toe doen ook echt gelden.
Deze handleiding volgt de cloudversie van Dify van 20 september 2026. Wijkt je scherm af, volg dan wat je ziet.
Zo lees je deze handleiding
| Vorm | Betekenis |
|---|---|
| 1. 2. 3. | Wat je doet: klikken, kiezen, openen |
| Vet | Een knop, menu of veld zoals het op je scherm staat |
| Tabel Wat je intypt | Waarden die je in een formulierveld zet |
| Grijs kader Intypen | Tekst die je letterlijk overtypt of plakt |
| Oranje kader | Een valkuil die je anders zelf ontdekt |
| Groen kader Zelf kiezen | Een plek waar je ons voorbeeld kunt vervangen door je eigen materiaal, stijl of prompt |
De ontwerpkaart van deze app
Voordat we gingen klikken, is deze kaart ingevuld (de lege kaart staat in de bijlage Ontwerpkaart). Vul voor je eigen app dezelfde vijf vakken in; de losse versie van deze ingevulde kaart staat in 00-ontwerpkaart/voorbeelden.
| 1. Voor wie | 2. Wat gaat erin |
|---|---|
| De communicatiemedewerker die elk bericht drie keer moet schrijven (website, ouderapp, social) en die geen tijd heeft om elke versie langs de schrijfwijzer te leggen. | Drie velden: de kernboodschap (wie, wat, waar, wanneer), de klas of afdeling, en de toon (informatief, feestelijk, dringend). |
| 3. Wat komt eruit | 4. Waar moet hij zich aan houden |
|---|---|
| Bij goedkeuring: drie versies klaar om te plaatsen. Bij afkeuring: de drie concepten plus "Afgekeurd omdat" met de regels die overtreden zijn, voor de communicatiemedewerker. | De schrijfwijzer uit de kennisbank; de Controleur (tweede LLM) herschrijft de ouderapp-versie; de Poortwachter (Code + IF/ELSE) meet woordaantal, verboden woorden, [INVULLEN] en de hashtag. Wat niet door de poort komt, gaat niet naar buiten. |
5. Waaraan zie je dat het werkt
| Test | Wat gaat erin | Wat moet eruit komen |
|---|---|---|
| 1 | Compleet bericht over de sportdag, feestelijk | Goedgekeurd, drie versies binnen de woordlimieten, met #Voorbeeldcollege |
| 2 | Bericht zonder datum | Afgekeurd: bevat [INVULLEN] |
| 3 (de lastige) | Bericht met "gelieve" en "z.s.m." | Afgekeurd met de twee verboden woorden benoemd |
Voorbereiding
- De workflow Schoolnieuws uit handleiding 3 staat op je account en werkt.
- Je weet wat een LLM-blok en een Output-blok zijn (handleiding 1 en 3).
- Je hoeft niet te kunnen programmeren. De code plak je; wat hij doet, staat ernaast uitgelegd.
Zo ziet Schoolnieuws eruit voordat je begint:
En zo ziet de staart eruit als je klaar bent:
Deel A. De Controleur (zelfkritiek)
Stap 1. Maak de Output los van Social
De nieuwe blokken komen tussen Social en Output. Je koppelt Output daarom eerst los.
- Open Schoolnieuws in Studio en klik op het blok Social.
- Scroll in het rechterpaneel naar NEXT STEP. Daar staat Output.
- Klik op de drie puntjes achter Output en kies Disconnect. (Niet Delete: het blok mag blijven, alleen de lijn gaat weg.)
Stap 2. Voeg de Controleur toe
- Klik bij NEXT STEP op Select next step en kies LLM.
- MODEL: gpt-5-mini. CONTEXT: Knowledge Retrieval / result (de schrijfwijzer).
- Plak in SYSTEM de prompt hieronder. Bij
{Context}typ je een schuine streep en kies je Context; bij{Ouderapp/text}kies je onder OUDERAPP het item text.
Je bent de controleur van Het Voorbeeldcollege. Hieronder staat een conceptbericht voor de ouderapp. Beoordeel het op deze punten uit de schrijfwijzer: maximaal 80 woorden; ouders worden aangesproken met u; één boodschap, één datum en één actie; geen afkortingen en geen woorden uit de lijst te vermijden woorden; geen namen van leerlingen; taalniveau B1 (korte zinnen, gewone woorden).
Werk in twee stappen. Stap 1: noem kort wat niet klopt (of schrijf: niets). Stap 2: geef de verbeterde versie. Verzin geen feiten; wat niet in het concept staat, blijft [INVULLEN]. Haal geen feiten, data of tijden weg die in het concept staan; een uiterste datum om aan te melden hoort bij de actie en blijft staan. Verander cijfers niet in woorden.
Geef als antwoord ALLEEN de verbeterde tekst, zonder stap 1, zonder kop en zonder uitleg. Is het concept al goed, geef het dan ongewijzigd terug.
Schrijfwijzer: {Context}
Conceptbericht: {Ouderapp/text}
- Hernoem het blok naar
Controleur.
"Werk in twee stappen, maar geef alleen stap 2." Dat is geen tegenstrijdigheid maar een truc: het model beoordeelt eerst (dat verbetert het resultaat) en je krijgt toch schone tekst terug die je direct kunt doorgeven. Laat je stap 1 in het antwoord staan, dan komt die uitleg ook in de ouderapp terecht.
In onze eerste test deed de Controleur precies wat we vroegen, en dat was te veel: "één datum" las hij als "haal de aanmelddatum weg", en "klas 2" werd "klas twee". Daarom staan de twee zinnen over feiten en cijfers in de prompt. Zelfkritiek verbetert vorm; wat er inhoudelijk mag veranderen, moet jij begrenzen.
Zelf kiezen: wat de Controleur nakijkt. De eerste alinea van de prompt is jullie checklist. Wil je ook controleren op "staat er een contactmogelijkheid in"? Of op de toon per kanaal? Zet het erbij. Wil je de Controleur ook op het websitebericht zetten? Kopieer het blok (drie puntjes op het blok, Duplicate), koppel Website/text als conceptbericht en pas de regels aan (200 woorden, kop van acht woorden).
Deel B. De Poortwachter (code)
Stap 3. Voeg een Code-blok toe
- Bij Controleur: NEXT STEP → Select next step → onder Transform: Code.
- Klik in de editor, selecteer alles (Ctrl+A) en plak de code hieronder.
def main(website: str, ouderapp: str, social: str) -> dict:
redenen = []
verboden = ["middels", "omtrent", "z.s.m.", "d.m.v.", " a.s.", "gelieve", "ouder(s)/verzorger(s)"]
teksten = (("website", website, 230), ("ouderapp", ouderapp, 90), ("social", social, 70))
for naam, tekst, maximum in teksten:
aantal = len(tekst.split())
if aantal > maximum:
redenen.append(f"{naam}: {aantal} woorden, maximaal {maximum}")
if "[INVULLEN]" in tekst:
redenen.append(f"{naam}: bevat [INVULLEN], er ontbreekt informatie")
for woord in verboden:
if woord in tekst.lower():
redenen.append(f"{naam}: bevat het te vermijden woord '{woord.strip()}'")
if "#voorbeeldcollege" not in social.lower():
redenen.append("social: #Voorbeeldcollege ontbreekt")
return {
"ok": 0 if redenen else 1,
"redenen": "\n".join(redenen) if redenen else "Alle regels in orde.",
}
Wat de code doet, regel voor regel in gewone taal:
| Regel | Betekenis |
|---|---|
verboden = [...] |
De lijst woorden die nooit in een tekst mogen. Dit is de lijst uit de schrijfwijzer, hier hard gemaakt |
teksten = (...) |
De drie teksten met hun maximum in woorden. De maxima liggen iets boven de schrijfwijzer (200, 80, 60), omdat de kop en het label WEBSITE meetellen |
if aantal > maximum |
Te lang: noteer een reden |
if "[INVULLEN]" in tekst |
Het model heeft iets niet geweten: noteer een reden. Dit is de belangrijkste regel: een bericht met een gat gaat nooit naar buiten |
for woord in verboden |
Staat een verboden woord in de tekst: noteer een reden |
if "#voorbeeldcollege" not in ... |
Het socialbericht moet de schoolhashtag hebben |
return {...} |
Geef twee dingen terug: ok (1 = goed, 0 = fout) en redenen (de lijst, of "Alle regels in orde.") |
Let op de inspringing: in Python telt elke spatie aan het begin van een regel. Plakken met Ctrl+V gaat goed. Overtypen gaat bijna altijd mis, doe dat niet.
Stap 4. Koppel de invoer en de uitvoer
- Hernoem bij INPUT VARIABLES
arg1naarwebsiteenarg2naarouderapp. Klik op + voor een derde variabele en noem diesocial. De namen moeten precies gelijk zijn aan de namen in de eerste regel van de code.
- Klik per variabele op Set variable en kies:
| Variabele | Kies |
|---|---|
| website | WEBSITE / text |
| ouderapp | CONTROLEUR / text (de verbeterde versie, niet de ruwe) |
| social | SOCIAL / text |
- Bij OUTPUT VARIABLES: hernoem
resultnaaroken zet het type op Number. Klik op + en voegredenentoe, type String.
- Hernoem het blok naar
Poortwachter.
De uitvoernamen (
ok,redenen) moeten letterlijk overeenkomen met de namen in dereturn-regel van de code. Eén letter anders en de workflow stopt met een foutmelding over een ontbrekende uitvoer.
Zelf kiezen: de harde regels. Alles wat je met zekerheid kunt controleren, hoort hier en niet in een prompt: lengte, verboden woorden, verplichte onderdelen (hashtag, contactregel, datum in de toekomst), geen e-mailadressen van personen, geen telefoonnummers behalve dat van de receptie. Vraag je communicatiemedewerker: "Welke fout mag nooit meer voorkomen?" Dat is je eerste regel.
Deel C. De poort: IF/ELSE en twee uitgangen
Stap 5. IF/ELSE
- Bij Poortwachter: Select next step → onder Logic: IF/ELSE.
- Klik bij IF op + Add Condition en kies POORTWACHTER / ok.
- Laat de vergelijking op = staan en typ bij de waarde
1.
Stap 6. Uitgang 1: Goedgekeurd
- Bij NEXT STEP onder IF: Select next step → Output.
- Voeg drie uitvoervariabelen toe:
| Variable name | Set variable |
|---|---|
website |
WEBSITE / text |
ouderapp |
CONTROLEUR / text |
social |
SOCIAL / text |
- Hernoem het blok naar
Goedgekeurd.
Stap 7. Uitgang 2: naar de communicatiemedewerker
- Klik op het blok IF/ELSE. Onder ELSE staat nog Select next step; kies Output.
- Voeg vier uitvoervariabelen toe. De redenen komen bovenaan, zodat de medewerker meteen ziet wat er mis is.
| Variable name | Set variable |
|---|---|
afgekeurd_omdat |
POORTWACHTER / redenen |
concept_website |
WEBSITE / text |
concept_ouderapp |
CONTROLEUR / text |
concept_social |
SOCIAL / text |
- Hernoem het blok naar
Naar de communicatiemedewerker.
Twee Output-blokken mogen geen gelijknamige variabelen hebben. Noem je ze in beide
website, dan zet Dify een oranje "Dubbele variabele" in de checklist en kun je niet publiceren. Vandaarconcept_in de tweede uitgang.
Stap 8. Ruim de oude Output op
- Klik rechtsboven op het checklist-icoon (naast Test Run). Je ziet welke blokken nog niet kloppen.
- Klik in de checklist op Output. Het oude blok wordt geselecteerd; het staat verstopt achter Controleur.
- Klik in het paneel op de drie puntjes en dan op Delete.
- Controleer dat de checklist leeg is (geen cijfer meer op het icoon).
Deel D. Testen: één keer goed, één keer fout
Een poortwachter test je altijd twee kanten op. Alleen de goede kant testen bewijst niets.
Stap 9. Test 1: een compleet bericht
- Test Run. Vul in:
| Veld op het scherm | Wat je intypt |
|---|---|
| Wat is er gebeurd... | Op donderdag 8 oktober om 19.30 uur is er een ouderavond voor klas 2 in de aula. Mentoren vertellen over de profielkeuze en het toetsweekrooster. Ouders kunnen zich tot 5 oktober aanmelden via het ouderportaal. Er is koffie en thee vanaf 19.15 uur. |
| Voor welke klas of afdeling? | klas 2 |
| Welke toon past bij dit bericht? | informatief |
- Start Run. Na ongeveer een minuut kleurt het pad via IF naar Goedgekeurd groen.
- Klik op DETAIL: status SUCCESS, doorlooptijd en tokens.
- Klik op TRACING en klap POORTWACHTER open. Onder OUTPUT staat wat de code teruggaf.
Tracing is je vriend. Bij elke vraag "waarom kwam dit eruit?" open je hier het blok en zie je precies wat erin ging en wat eruit kwam. Dat is ook het scherm waarop je zag dat de Controleur de aanmelddatum had weggehaald (zie het oranje kader in stap 2).
Stap 10. Test 2: een bericht met gaten
- Test Run opnieuw, nu met een boodschap zonder datum, zonder tijd en met een afkorting:
| Veld op het scherm | Wat je intypt |
|---|---|
| Wat is er gebeurd... | Binnenkort is er weer een ouderavond voor de brugklassen. De mentoren vertellen dan hoe het gaat en wat er komend jaar gebeurt. Ouders moeten zich z.s.m. aanmelden. |
| Voor welke klas of afdeling? | brugklassen |
| Welke toon past bij dit bericht? | informatief |
- Start Run. Nu loopt het pad via ELSE naar Naar de communicatiemedewerker, en bovenaan het resultaat staan de redenen.
Lees de redenen: alle drie de teksten bevatten [INVULLEN] (de modellen wisten de datum niet en hebben hem netjes niet verzonnen), en in het socialbericht staat "z.s.m.". Dat laatste is leerzaam: de prompt van Social vroeg om de schrijfwijzer te volgen, en toch glipte de afkorting uit de kernboodschap erdoorheen. Een prompt vraagt; de poortwachter dwingt af.
Stap 11. Publiceer
- Publish → Publish Update. Dify maakt versie 2 van de app; met Naam geven kun je een versie een naam geven, en via het klokje rechtsboven kun je altijd terug naar versie 1.
- Open de webapp en herhaal test 2. De collega ziet de redenen bovenaan en daaronder de concepten om aan te vullen.
De link is dezelfde gebleven: https://udify.app/workflow/jJclFyX9BlteuHYi
Controleren of het gelukt is
- De checklist rechtsboven toont geen cijfer
- Test 1 eindigt in Goedgekeurd, test 2 in Naar de communicatiemedewerker
- In TRACING geeft Poortwachter bij test 1
ok: 1en bij test 2ok: 0met minstens één reden - Het ouderappbericht in Goedgekeurd komt van Controleur (te zien in de Output-instellingen), niet van Ouderapp
- De webapp toont bij een afgekeurd bericht de redenen bovenaan
Als het misgaat
| Wat je ziet | Wat er aan de hand is |
|---|---|
Code-blok: fout over IndentationError of SyntaxError |
De inspringing is beschadigd. Selecteer alles, verwijder, plak opnieuw |
| Code-blok: fout over een ontbrekende uitvoervariabele | De namen bij OUTPUT VARIABLES wijken af van ok en redenen in de return-regel |
Code-blok: main() missing argument |
Een invoervariabele heet anders dan in de eerste regel van de code, of is niet gekoppeld |
| IF/ELSE gaat altijd naar ELSE | Het type van ok staat op String in plaats van Number, of je vergelijkt met "1" in plaats van 1 |
| Checklist: "Dubbele variabele van de outputnode" | Twee Output-blokken gebruiken dezelfde variabelenaam. Hernoem er één (stap 7) |
| Checklist: "This step is not connected to anything" | Het oude Output-blok bestaat nog. Verwijder het (stap 8) |
| De Controleur haalt informatie weg of verandert cijfers | De prompt begrenst niet wat inhoudelijk mag veranderen. Zie de twee zinnen in stap 2 |
| Goedgekeurd toont het ruwe ouderappbericht | De variabele ouderapp in Goedgekeurd wijst naar Ouderapp/text in plaats van Controleur/text |
| De run duurt meer dan twee minuten | Vier LLM-blokken achter elkaar; normaal is 60 tot 90 seconden. Duurt het langer, kijk in Tracing welk blok blijft hangen |
Beheer en kosten
- Eén run kost nu vier modelaanroepen (Website, Ouderapp, Social, Controleur) en zo'n 7.500 tokens; met een eigen OpenAI-sleutel ongeveer anderhalve cent, op Dify-credits ongeveer 13. Het Code-blok en IF/ELSE kosten niets. Een sandbox-account (200 credits) haalt daarmee zo'n vijftien runs; een Professional-account (5.000 credits per maand) is voor een team ruim voldoende.
- De verboden lijst staat op twee plekken: in de schrijfwijzer (voor de modellen) en in de code (voor de poort). Verandert de schrijfwijzer, pas dan ook de code aan. Wie dat vergeet, krijgt afkeuringen die de modellen niet begrijpen.
- Versies. Elke Publish Update is een nieuwe versie. Gaat een aanpassing mis, dan zet je via het klokje rechtsboven de vorige versie terug zonder opnieuw te bouwen.
- Logs tonen ook welke berichten zijn afgekeurd en waarom. Dat is precies de informatie die je nodig hebt om de prompts van Website, Ouderapp en Social te verbeteren: elke reden die vaak voorkomt, is een zin die in een prompt ontbreekt.
Maak hem van jou
Van makkelijk naar moeilijk.
| Aanpassing | Waar | Moeilijkheid | Wat je ervoor terugkrijgt |
|---|---|---|---|
| Andere verboden woorden | Code, regel verboden |
makkelijk | De echte lijst van jullie schrijfwijzer wordt afgedwongen |
| Andere woordlimieten | Code, regel teksten |
makkelijk | Limieten die bij jullie kanalen passen |
| Extra controlepunt voor de Controleur | Stap 2, eerste alinea van de prompt | makkelijk | Meer nakijkwerk van je bord |
| Een Controleur voor het websitebericht | Duplicate van het blok, andere invoer en regels | gemiddeld | Ook de langste tekst nagekeken |
| Een regel "datum moet in de toekomst liggen" | Code, met datetime |
gemiddeld | Geen berichten meer over gisteren |
| Een derde uitgang: "twijfel" voor kleine overtredingen | Tweede voorwaarde in IF/ELSE (ELIF) en een tweede teller in de code | gemiddeld | Kleine dingen automatisch door, grote naar een mens |
| Een mens in de lus: het bericht pas plaatsen na een klik | Blok Human Input vóór Goedgekeurd | moeilijk | De eerlijkste poortwachter die er is |
| Zelfkritiek in een lus tot de poort open gaat (maximaal twee rondes) | Blok Loop rond Controleur en Poortwachter | moeilijk | Minder afkeuringen, wel dubbele kosten |
Drie opdrachten
- Vul de lijst. Vraag je communicatieteam naar de vijf woorden of formuleringen die zij het vaakst wegstrepen. Zet ze in
verbodenen draai test 1 en test 2 opnieuw. Wordt test 1 nu ook afgekeurd? Dan is je lijst te breed (een woord als "even" komt overal voor) en moet je preciezer zijn. - Breek de poort. Schrijf een kernboodschap die door de poort komt maar toch fout is: een verkeerde datum, een verzonnen naam van een leerling, een toon die niet past. Wat vangt de Controleur, wat vangt de code, en wat vangt niemand? Voor dat laatste schrijf je een nieuwe regel, of je besluit dat een mens dat blijft doen.
- Meet het. Draai tien echte berichten van de afgelopen maand door de app. Tel: hoeveel kwamen er direct door, hoeveel werden afgekeurd, en hoeveel van de afkeuringen waren terecht? Die drie getallen zijn je gesprek met de directie over of dit de moeite waard is.
Checklist voordat je eigen materiaal gebruikt
- De verboden lijst en de limieten in de code komen overeen met de schrijfwijzer in de kennisbank
- Je hebt beide kanten getest: een bericht dat door de poort moet, en een dat moet worden tegengehouden
- Er is afgesproken wie de afgekeurde berichten oppakt en binnen hoeveel tijd
- De kernboodschappen die collega's invoeren bevatten geen namen van leerlingen; de poort controleert daar niet op
- Iemand leest ook goedgekeurde berichten steekproefsgewijs na; de poort controleert vorm, geen waarheid
- Je hebt de vorige versie van de app nog (versiegeschiedenis), voor het geval de nieuwe iets breekt
En verder
Je hebt nu alle vijf de patronen uit de bijlage Ontwerppatronen in handen: één aanroep (handleiding 1), redeneren met gereedschap (2 en 3), plannen en uitvoeren (3 en 4), zelfkritiek en een poortwachter (deze). Handleiding 6, de lesmateriaal-agent in de Agent Console, zet ze alle vijf tegelijk in.



































