commit 659e4c7e76f383e49596eb2ec73034a330ef0829 Author: Guido van Dijk Date: Sun Sep 20 20:25:01 2026 +0200 Dify-handleidingen: eerste uitgave, stand 20 september 2026 Handleidingen 01, 02, 03, 05, 07, 08 met Zelf kiezen-kaders en Maak hem van jou; bijlagen ontwerpkaart, ontwerppatronen, AI-tools in het onderwijs; draaiboek workshop Kennisfestival 23-09-2026; gedeeld bouwscript, extract.py, CC BY-SA 4.0. Co-Authored-By: Claude Opus 5 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66c1145 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# Gebouwde uitvoer: maak je met python3 build.py in elke map +*.html +*.pdf +*.docx +!**/schoolgids-voorbeeldcollege.pdf +!**/schrijfwijzer-voorbeeldcollege.pdf +!**/studiewijzer-biologie-3havo-ecologie.pdf +!**/lesbrief-ecologie.pdf +!**/stercollectie-voedselweb-hv3.pdf +__pycache__/ +.*-embed.html diff --git a/00-ai-tools/ai-tools-in-het-onderwijs.md b/00-ai-tools/ai-tools-in-het-onderwijs.md new file mode 100644 index 0000000..0ea67e1 --- /dev/null +++ b/00-ai-tools/ai-tools-in-het-onderwijs.md @@ -0,0 +1,229 @@ + + +# AI-tools in het onderwijs: wat er al is, en waar Dify past + +**Bijlage bij de workshop AI Agents** +LeX Consultancy B.V. · 20 september 2026 + +Bijna iedereen in de zaal gebruikt al een AI-tool: Copilot omdat de school Microsoft heeft, Gemini omdat de school Google heeft, ChatGPT omdat het de bekendste is. Deze bijlage zet de tools naast elkaar in gewoon Nederlands: wat het is, waar het al in zit, wat erover bekend is voor scholen in Nederland, en wanneer je het wel of niet inzet. Aan het eind staat waar Dify in dit landschap past, want Dify is geen zoveelste chatbot maar een bouwlaag bovenop deze tools. + +Alles hieronder is de stand van **20 september 2026**. Deze markt verandert per kwartaal. Voor besluiten over inzet op school kijk je altijd naar de actuele adviezen van SIVON en SURF, en naar het AI Toetsingskader Funderend Onderwijs. + +> De belangrijkste zin van deze bijlage: **het verschil zit niet in het model maar in het account.** Dezelfde chatbot is met een gratis privéaccount iets heel anders dan met een schoolaccount onder een verwerkersovereenkomst. In het eerste geval kunnen je gesprekken gebruikt worden om het model te trainen en heb je geen rechten; in het tweede geval zijn daar afspraken over. Vraag dus nooit "mogen we ChatGPT gebruiken?" maar "onder welk account, met welke gegevens, voor welke taak?" + +--- + +## Drie lagen + +Het helpt om drie lagen uit elkaar te houden. De meeste discussies op school gaan over laag 1, de meeste winst zit in laag 2 en 3. + +| Laag | Wat het is | Voorbeelden | Wie beslist | +| --- | --- | --- | --- | +| **1. Chatbot** | Je typt een vraag, je krijgt een antwoord. Elke keer opnieuw uitleggen wat je wilt. | ChatGPT, Gemini-app, Claude, Le Chat, Copilot Chat | De gebruiker zelf, vaak zonder dat de school het weet | +| **2. Assistent in je kantoorpakket** | AI in de tools die je al hebt: mail samenvatten, een presentatie opzetten, een tabel uitleggen. | Microsoft 365 Copilot, Gemini in Workspace for Education | De school, via licenties en instellingen | +| **3. Bouwplatform** | Jij bouwt een app met vaste stappen, eigen regels en eigen documenten, en deelt die met collega's. | Dify, Copilot Studio, Gems (Google), GPT's en Projects (OpenAI), Projects (Claude) | De school, per app; dit is waar deze workshop over gaat | + +Een chatbot (laag 1) is handig voor wie zelf goed kan sturen. Een app (laag 3) neemt dat sturen over: de regels zitten ingebouwd, dus een collega die nooit een prompt schreef, krijgt toch een goed resultaat. Dat is precies waarom we in de handleidingen apps bouwen en geen prompts uitdelen. + +--- + +## De tools naast elkaar + +### Microsoft Copilot + +| | | +| --- | --- | +| **Van wie** | Microsoft (VS), modellen van OpenAI en eigen modellen | +| **Waar zit het al in school** | In Microsoft 365: Copilot Chat met schoolaccount is er vaak al; Microsoft 365 Copilot (in Word, Outlook, Teams) is een aparte licentie | +| **Stand in Nederland (20-09-2026)** | SURF deed een DPIA en adviseert **terughoudend** gebruik van Microsoft 365 Copilot; van de vier hoge risico's zijn er twee over, nu als middel ingeschat. Kennisnet sluit zich daarbij aan en adviseert schoolafspraken vóór inzet | +| **Geschikt voor** | Werken in eigen documenten en mail, samenvattingen van Teams-overleggen, eerste opzet van teksten | +| **Let op** | Copilot Chat met schoolaccount (data blijft in de tenant) is iets anders dan Copilot in de browser met privéaccount. Controleer welke je hebt. Copilot Studio is het bouwplatform van Microsoft; vergelijkbaar met Dify, maar gebonden aan Microsoft | + +### Google Gemini + +| | | +| --- | --- | +| **Van wie** | Google (VS) | +| **Waar zit het al in school** | In Workspace for Education: Gemini in Docs, Gmail en Classroom, de Gemini-app, NotebookLM, Gems | +| **Stand in Nederland (20-09-2026)** | SIVON voert in 2026 een DPIA uit op Gemini in Workspace for Education; bij het schrijven van deze bijlage was er nog geen afgerond oordeel. Google zet Gemini intussen aan in steeds meer onderdelen; beheerders kunnen dat per onderdeel uitzetten | +| **Geschikt voor** | Werken in Google-documenten, NotebookLM voor leren uit eigen bronnen, Gems als eenvoudige eigen assistent | +| **Let op** | Wacht met inzet bij leerlingen op de DPIA. Let op wat je beheerder heeft aangezet; standaardinstellingen wijzigen bij updates | + +### ChatGPT (OpenAI) + +| | | +| --- | --- | +| **Van wie** | OpenAI (VS) | +| **Waar zit het al in school** | Meestal niet via school; wel massaal privé bij docenten en leerlingen | +| **Stand in Nederland (20-09-2026)** | Geen sectorbrede DPIA voor het funderend onderwijs. Bij een gratis of Plus-account kunnen gesprekken standaard gebruikt worden voor training (uit te zetten in de instellingen); bij Team, Enterprise en Edu niet, en er is dan een verwerkersovereenkomst mogelijk | +| **Geschikt voor** | Het breedste ecosysteem: GPT's, Projects, spraak, beeld. Voor persoonlijk gebruik door de docent zonder schooldata | +| **Let op** | Nooit leerlinggegevens of ongepubliceerd toetsmateriaal in een privéaccount. Via de API (zoals in Dify) gelden andere voorwaarden dan in de app: standaard geen training op API-verkeer | + +### Claude (Anthropic) + +| | | +| --- | --- | +| **Van wie** | Anthropic (VS) | +| **Waar zit het al in school** | Zelden via school; via Dify beschikbaar als model | +| **Stand in Nederland (20-09-2026)** | Geen sectorbrede DPIA. Claude for Education en een leerstand ("learning mode") bestaan, vooral gericht op hoger onderwijs. Zakelijke accounts trainen niet op gesprekken | +| **Geschikt voor** | Lange documenten lezen en herschrijven, zorgvuldig taalgebruik, Projects met eigen bronnen. In de Agent Console van Dify een van de compatibele modellen | +| **Let op** | Zelfde regel als bij ChatGPT: account bepaalt wat mag. Duurder per antwoord dan gpt-5-mini | + +### Mistral (Le Chat) + +| | | +| --- | --- | +| **Van wie** | Mistral AI (Frankrijk) | +| **Waar zit het al in school** | Zelden via school | +| **Stand in Nederland (20-09-2026)** | Europese aanbieder, valt onder EU-recht en hosting in de EU is mogelijk; sommige modellen zijn open (zelf te draaien). Geen sectorbrede onderwijs-DPIA | +| **Geschikt voor** | Wie een Europese aanbieder wil of zelf wil hosten; goed in Nederlands en Frans | +| **Let op** | Kleiner ecosysteem; minder kant-en-klare onderwijsfuncties. Ook hier: gratis account is niet hetzelfde als een zakelijk account | + +### DeepSeek + +| | | +| --- | --- | +| **Van wie** | DeepSeek (China) | +| **Waar zit het al in school** | Niet via school | +| **Stand in Nederland (20-09-2026)** | De app en de website verwerken gegevens op servers in China; de Autoriteit Persoonsgegevens en meerdere Europese toezichthouders hebben gewaarschuwd. De open modellen zijn wel door Europese partijen te hosten | +| **Geschikt voor** | Alleen als open model, gehost door een partij in de EU, voor wie technisch wil experimenteren | +| **Let op** | Niet gebruiken met schooldata via de app. Het model is niet het probleem, de verwerking is het probleem | + +### Grok (xAI) + +| | | +| --- | --- | +| **Van wie** | xAI (VS), verweven met X | +| **Waar zit het al in school** | Niet via school | +| **Stand in Nederland (20-09-2026)** | Geen onderwijsgebruik van betekenis; herhaalde controverses over ongefilterde uitvoer en gebruik van X-berichten voor training | +| **Geschikt voor** | Nergens voor in een schoolcontext | +| **Let op** | Niet inzetten. Noem hem wel in de les over mediawijsheid: leerlingen komen hem tegen op X | + +### Perplexity + +| | | +| --- | --- | +| **Van wie** | Perplexity (VS) | +| **Waar zit het al in school** | Niet via school; populair bij leerlingen als "zoekmachine" | +| **Stand in Nederland (20-09-2026)** | Geen DPIA. Zoekt op het web en geeft bronnen | +| **Geschikt voor** | Oriënterend zoeken met bronvermelding; bronnen daarna zelf controleren | +| **Let op** | Bronnen zijn niet altijd de beste, en de samenvatting is niet altijd wat de bron zegt | + +### NotebookLM + +| | | +| --- | --- | +| **Van wie** | Google (VS) | +| **Waar zit het al in school** | Onderdeel van Workspace for Education (beheerder kan aan- of uitzetten) | +| **Stand in Nederland (20-09-2026)** | Valt onder de Google-DPIA's van SIVON; controleer of je beheerder het heeft aangezet | +| **Geschikt voor** | Leren uit eigen bronnen: samenvatting, vragen, audio-overzicht van een hoofdstuk | +| **Let op** | Alleen met materiaal dat je mag uploaden. Dezelfde regels als voor een kennisbank in Dify | + +### GPT-NL + +| | | +| --- | --- | +| **Van wie** | TNO, SURF en NFI (Nederland) | +| **Waar zit het al in school** | Nog niet in scholen | +| **Stand in Nederland (20-09-2026)** | Nederlands taalmodel in ontwikkeling, met aandacht voor rechtmatige trainingsdata en Nederlandse waarden; bedoeld voor publieke organisaties | +| **Geschikt voor** | Op termijn: een model waarvan de herkomst van de data bekend is | +| **Let op** | Nog geen product dat je vandaag inzet; wel volgen | + +--- + +## Vier vragen voor elke tool + +Of het nu Copilot is of een app die je zelf in Dify bouwt, dezelfde vier vragen bepalen of het mag en of het verstandig is. + +1. **Onder welk account?** Privé, gratis, betaald of een schoolaccount met verwerkersovereenkomst. Alleen in het laatste geval heeft de school iets te zeggen over wat er met de gegevens gebeurt. +2. **Welke gegevens gaan erin?** Geen persoonsgegevens van leerlingen, ouders of collega's, tenzij de tool daarvoor is beoordeeld. Ongepubliceerd toetsmateriaal en vertrouwelijke stukken tellen ook. +3. **Wordt er getraind op wat je invoert?** Bij consumentenaccounts vaak standaard ja (soms uit te zetten), bij zakelijke accounts en API-gebruik meestal nee. Controleer het, geloof het niet op gezag van een collega. +4. **Wie beslist en wie kijkt na?** Een tool die één docent voor zichzelf gebruikt is iets anders dan een tool die leerlingen gebruiken. Voor het tweede is er een schoolbesluit nodig, en iemand die de uitvoer controleert. + +Hulpmiddelen die er al zijn: + +- **AI Toetsingskader Funderend Onderwijs** (SIVON en Kennisnet, versie 1.0, 1 april 2026): vier stappen om te bepalen of een AI-systeem onder de Europese AI-verordening valt en welke verplichtingen gelden, met een beslisboom en checklists voor school en leverancier. Gebruik het bij inkoop en bij elke tool die leerlingen raakt. +- **Kennisnet: schoolafspraken over generatieve AI**: een toolkit (met een spel) om als team afspraken te maken. Doe dat vóór de tools, niet erna. +- **SIVON-veelgestelde vragen over AI**: onder meer de vuistregel dat kinderen onder 13 niet zelfstandig met generatieve AI werken. +- **De DPIA's van SURF en SIVON** op Microsoft en Google: de enige onafhankelijke beoordelingen voor de Nederlandse onderwijssector. Andere aanbieders hebben zo'n beoordeling niet; dat betekent niet dat ze onveilig zijn, maar wel dat de school het zelf moet uitzoeken. + +--- + +## AVG en AI Act in het kort + +Twee wetten bepalen wat mag. De **AVG** gaat over persoonsgegevens, de **AI-verordening (EU AI Act)** over AI-systemen. Ze overlappen, maar stellen andere vragen. + +**AVG: wie is verantwoordelijk voor de gegevens?** + +- De school is verwerkingsverantwoordelijke. Dify (cloud, buiten de EU) en de modelaanbieder (OpenAI, Anthropic, Google) zijn verwerkers. Zonder verwerkersovereenkomst mogen er geen persoonsgegevens in, en die overeenkomst heeft een sandbox-account niet. Daarom werken de handleidingen met fictief materiaal. +- Zodra een app gegevens van leerlingen, ouders of collega's verwerkt (een naam in een ouderbrief, een persoonlijk bericht aan de Studiecoach dat naar de docent gaat), gelden grondslag, dataminimalisatie, een bewaartermijn voor de logs en bij hoog risico een DPIA. Bij leerlingen is dat vrijwel altijd hoog risico. +- Doorgifte buiten de EU vraagt een grondslag (bijvoorbeeld het EU-US Data Privacy Framework voor Amerikaanse aanbieders die daaronder vallen); controleer dat per aanbieder, het verandert. + +**AI Act: wat voor systeem is het, en wat moet je dan?** + +| Onderdeel | Sinds | Wat het betekent voor een school | +| --- | --- | --- | +| Art. 4, AI-geletterdheid | 2 februari 2025 | Wie AI inzet, zorgt dat personeel er genoeg van weet. Een workshop als deze is zo'n maatregel; leg vast wie hem volgde | +| Art. 5, verboden praktijken | 2 februari 2025 | Onder meer emotieherkenning in het onderwijs. Geen tool inzetten die stemming of aandacht van leerlingen meet | +| Bijlage III, hoog risico in het onderwijs | gepland augustus 2026; in 2025-2026 is uitstel besproken, controleer de actuele stand | Toelating en plaatsing, beoordelen van leerresultaten of niveau, toezicht bij toetsen. Dan gelden zware eisen aan leverancier én school: risicobeheer, menselijk toezicht, documentatie, registratie | +| Art. 50, transparantie | augustus 2026 | Een chatbot laat weten dat de gebruiker met AI praat; AI-gegenereerde inhoud wordt als zodanig herkenbaar gemaakt waar dat relevant is | + +De apps uit deze serie (tekst herschrijven, vragen beantwoorden uit een schoolgids, berichten opstellen, een transcript samenvatten) nemen geen beslissingen over personen en vallen niet onder hoog risico. De grens ligt dichtbij: een Studiecoach die leerlingen uitlegt en hints geeft is geen hoog risico; dezelfde coach die zou vastleggen wie de stof niet snapt en dat aan de docent rapporteert als beoordeling, wel. Dat is een ontwerpkeuze, en de ontwerpkaart vraagt ernaar in vak 4. Het **AI Toetsingskader Funderend Onderwijs** (SIVON en Kennisnet, 1.0, april 2026) loopt deze stappen met een beslisboom na. + +## De EU-competentiekaders: waar bouwen in past + +De AI-verordening zegt dát personeel AI-geletterd moet zijn; twee Europese kaders zeggen wat dat inhoudt. + +- Het **AI Literacy Framework for Primary and Secondary Education** (OESO en Europese Commissie, definitief in 2026) beschrijft vier competentiedomeinen voor leerlingen, elk met kennis, vaardigheden en houding: **Engage with AI** (begrijpen hoe het werkt en er verantwoord mee omgaan), **Create with AI** (er iets mee maken), **Manage AI** (het verantwoord inzetten en bewaken) en **Shape AI** (keuzes maken en invloed uitoefenen). +- **DigCompEdu** is het Europese kader voor de digitale competenties van docenten (zes gebieden, van professionele betrokkenheid tot het bevorderen van digitale competentie bij leerlingen); de Commissie heeft er aanvullingen bij gemaakt voor AI en data. + +De handleidingenserie en de workshop raken alle vier de domeinen, en dat is te gebruiken in een professionaliseringsplan: + +| Domein | In de serie | +| --- | --- | +| Engage with AI | Drie lagen, vijf patronen, de sabotage van de agent, de kennisbank die verkeerd knipt | +| Create with AI | De bouwblokken: workflow, agent, chatflow, poortwachter, agent console | +| Manage AI | Poortwachter en zelfkritiek, de mens in de lus, Logs, de checklists eigen materiaal, de vier vragen | +| Shape AI | De ontwerpkaart, de pitch, de keuze waar de mens hoort en wat een app nooit mag beslissen | + +Bronnen: ailiteracyframework.org en education.ec.europa.eu (AI Literacy Framework); joint-research-centre.ec.europa.eu (DigCompEdu). + +## Waar Dify past + +Dify is geen model en geen chatbot. Het is een bouwplatform (laag 3) dat de modellen van de aanbieders hierboven aanroept via hun API. In de handleidingen koos je per app een model: meestal gpt-5-mini van OpenAI, in de Agent Console ook Claude of Gemini. Drie gevolgen daarvan: + +**1. Je kiest het model per taak, en kunt wisselen.** Een ouderbrief herschrijven kan met een klein, goedkoop model. Een lang beleidsstuk analyseren vraagt een groter model. In Dify verander je dat in één menu, zonder dat de gebruiker van de app iets merkt. Komt er morgen een Europees model dat goed genoeg is (Mistral, of op termijn GPT-NL), dan zet je dat eronder. + +**2. API-verkeer is niet hetzelfde als de chatbot.** Wat via de API van OpenAI, Anthropic of Google loopt, wordt standaard niet gebruikt om modellen te trainen, en er is een zakelijke overeenkomst. Dat is een betere positie dan een gratis chatbotaccount. Maar de gegevens gaan nog steeds naar een verwerker buiten de school, meestal buiten de EU. De regels uit de vier vragen blijven gelden. + +**3. Dify-cloud zelf is óók een verwerker.** Het sandbox-account uit de workshop draait op de servers van Dify, buiten de EU. Voor oefenen met fictief materiaal is dat prima. Voor echt gebruik met schooldata zijn er twee routes: Dify zelf hosten (het is open source) of het draaien in een omgeving van het bestuur, zoals de Experimenteerruimte ICT van SOML met de centrale modelsleutels. Handleiding 5 (Transcriptietool) laat zien hoe je een prototype uit de cloud overzet. + +**Wanneer wat** + +| Situatie | Pak | +| --- | --- | +| Een snelle vraag, een eerste opzet, iets voor jezelf | De chatbot waar je school een account voor heeft (Copilot Chat of Gemini met schoolaccount) | +| Een taak die elke week terugkomt en aan regels moet voldoen (huisstijl, format, bronnen) | Een app in Dify, of in het bouwplatform van je pakket (Copilot Studio, Gems) | +| Werken in je eigen documenten en mail | Microsoft 365 Copilot of Gemini in Workspace, zodra je bestuur daar op grond van de DPIA een besluit over heeft genomen | +| Iets voor leerlingen | Eerst het schoolbesluit, het toetsingskader en de leeftijdsgrens; dan pas de tool | +| Experimenteren met wat kan | Dify met fictief materiaal, zoals in deze workshop | + +--- + +## Om te onthouden + +- Het account bepaalt meer dan het merk. +- AVG: geen persoonsgegevens zonder verwerkersovereenkomst. AI Act: geletterdheid is verplicht, beoordelen van leerlingen is hoog risico, een chatbot zegt dat hij AI is. +- Copilot en Gemini zitten al in school; of ze aan mogen, is een bestuursbesluit op basis van de DPIA's van SURF en SIVON, geen keuze van een individuele docent. +- ChatGPT, Claude en Mistral zijn prima gereedschap voor de docent zelf, zonder schooldata, en als model onder een app. +- DeepSeek-app en Grok blijven buiten school. +- Dify zet je bovenop deze modellen: je bouwt de regels in, kiest het model per taak en kunt wisselen als de markt verandert. Voor echt gebruik hoort de bouwlaag bij het bestuur, niet in een gratis cloudaccount. diff --git a/00-ai-tools/build.py b/00-ai-tools/build.py new file mode 100644 index 0000000..33d746c --- /dev/null +++ b/00-ai-tools/build.py @@ -0,0 +1,4 @@ +import runpy, sys +from pathlib import Path +sys.argv = ["build_handleiding.py", str(Path(__file__).resolve().parent / "ai-tools-in-het-onderwijs.md")] +runpy.run_path(str(Path(__file__).resolve().parent.parent / "_gereedschap" / "build_handleiding.py"), run_name="__main__") diff --git a/00-ontwerpkaart/build.py b/00-ontwerpkaart/build.py new file mode 100644 index 0000000..29ce85f --- /dev/null +++ b/00-ontwerpkaart/build.py @@ -0,0 +1,4 @@ +import runpy, sys +from pathlib import Path +sys.argv = ["build_handleiding.py", str(Path(__file__).resolve().parent / "ontwerpkaart.md")] +runpy.run_path(str(Path(__file__).resolve().parent.parent / "_gereedschap" / "build_handleiding.py"), run_name="__main__") diff --git a/00-ontwerpkaart/ontwerpkaart.md b/00-ontwerpkaart/ontwerpkaart.md new file mode 100644 index 0000000..b2b034b --- /dev/null +++ b/00-ontwerpkaart/ontwerpkaart.md @@ -0,0 +1,44 @@ + + +# Ontwerpkaart: je app in vijf vakken + +**Bij de workshop AI Agents · vul dit in voordat je gaat bouwen** +LeX Consultancy B.V. · 20 september 2026 + +Eerst invullen, dan bouwen. Eén kaart per app, met pen, maximaal drie regels per vak. + +| 1. Voor wie | 2. Wat gaat erin | +| --- | --- | +| Wie gebruikt de app, en in welke situatie? Eén persoon, niet "iedereen". Wat weet die persoon al, wat heeft die geen tijd voor?
 
 
  | Wat plakt of kiest de gebruiker? Tekst, een bestand, een keuze uit een lijstje? Welke vragen stel je altijd vóór je iets voor iemand schrijft? Dat zijn je invoervelden.
 
 
  | + +| 3. Wat komt eruit | 4. Waar moet hij zich aan houden | +| --- | --- | +| Beschrijf het eindproduct alsof het al bestaat: hoe lang, welke kopjes, in welke taal, voor wie leesbaar. Schrijf één voorbeeld uit met de hand.
 
 
  | Welke regels van jouw school of team gelden? Huisstijl, aanspreekvorm, wat hij nooit mag verzinnen, wanneer hij "dat weet ik niet" moet zeggen. Welk document bevat die regels? Dat is je kennisbank.
 
 
  | + +**5. Waaraan zie je dat het werkt** + +Drie testgevallen, opgeschreven vóór je bouwt: twee gewone en één waarbij de app moet weigeren of doorvragen. Pas als alle drie goed gaan, deel je de link. + +| Test | Wat gaat erin | Wat moet eruit komen | +| --- | --- | --- | +| 1 |  
  |  
  | +| 2 |  
  |  
  | +| 3 (de lastige) |  
  |  
  | + +| Als... | Dan bouw je een... | Zie handleiding | +| --- | --- | --- | +| de stappen altijd hetzelfde zijn en de gebruiker een formulier invult | **Workflow** | 1, 3 (Schoolnieuws), 5 | +| de gebruiker vragen stelt en de app in een document moet zoeken | **Agent met kennisbank** | 2, 3 (Ouderbrief, Balie) | +| de app zelf moet uitzoeken wat er nodig is, bestanden moet lezen of op het web moet zoeken | **Agent Console** | 4, 6 | + +**Voordat je op Create klikt** + +- [ ] Vak 1 noemt één persoon, geen doelgroep +- [ ] Vak 3 bevat een uitgeschreven voorbeeld +- [ ] Het document uit vak 4 bevat geen persoonsgegevens en mag naar een externe verwerker +- [ ] Er is een eigenaar, je weet wie de link krijgt, en je weet wat één run kost diff --git a/00-ontwerppatronen/.~lock.ontwerppatronen-voor-agents.docx# b/00-ontwerppatronen/.~lock.ontwerppatronen-voor-agents.docx# new file mode 100644 index 0000000..98bd92e --- /dev/null +++ b/00-ontwerppatronen/.~lock.ontwerppatronen-voor-agents.docx# @@ -0,0 +1 @@ +,guido,tuxedo,20.09.2026 18:11,/home/guido/.local/share/onlyoffice; \ No newline at end of file diff --git a/00-ontwerppatronen/build.py b/00-ontwerppatronen/build.py new file mode 100644 index 0000000..3f5073c --- /dev/null +++ b/00-ontwerppatronen/build.py @@ -0,0 +1,4 @@ +import runpy, sys +from pathlib import Path +sys.argv = ["build_handleiding.py", str(Path(__file__).resolve().parent / "ontwerppatronen-voor-agents.md")] +runpy.run_path(str(Path(__file__).resolve().parent.parent / "_gereedschap" / "build_handleiding.py"), run_name="__main__") diff --git a/00-ontwerppatronen/ontwerppatronen-voor-agents.md b/00-ontwerppatronen/ontwerppatronen-voor-agents.md new file mode 100644 index 0000000..880e58d --- /dev/null +++ b/00-ontwerppatronen/ontwerppatronen-voor-agents.md @@ -0,0 +1,168 @@ + + +# Vijf ontwerppatronen voor AI-agents, en hoe je ze in Dify bouwt + +**Bijlage bij de workshop AI Agents** +LeX Consultancy B.V. · 20 september 2026 + +Wie "een agent" wil bouwen, moet eerst één vraag beantwoorden: hoeveel mag het model zelf beslissen? Het antwoord bepaalt hoe je bouwt, wat het kost en hoeveel er fout kan gaan. In het vak worden vijf patronen onderscheiden, van "helemaal niets beslissen" tot "beslissen, maar onder toezicht". Je hebt er in de handleidingen al drie gebouwd zonder dat ze zo heetten. + +**De vuistregel:** kies het eenvoudigste patroon dat het probleem oplost. Elk stapje omhoog kost meer tijd, meer credits en meer kans op een verrassing. + +| Patroon | Wie beslist de stappen | Voorbeeld uit de serie | Handleiding | +| --- | --- | --- | --- | +| 1. Eén aanroep | Jij, vooraf; het model doet één ding | Tekst op niveau (één LLM-stap) | 1 | +| 2. Redeneren en handelen (ReAct) | Het model, stap voor stap, met gereedschap | Schoolgids-assistent, Ouderbrief-assistent (agent met kennisbank) | 2, 3 | +| 3. Plannen en uitvoeren | Eerst een plan, dan losse uitvoerders | Schoolnieuws (drie kanalen uit één boodschap), Toetsweekplanner | 3, 4 | +| 4. Zelfkritiek | Het model beoordeelt en verbetert zijn eigen werk | Nog niet; past bij handleiding 6 | 6 | +| 5. Poortwachter | Een onafhankelijke controle laat het resultaat wel of niet door | Nog niet; hoort bij alles wat naar buiten gaat | 6 en verder | + +--- + +## 1. Eén aanroep (single-shot) + +**Hoe het werkt.** De gebruiker levert iets aan, het model doet precies één bewerking, klaar. Geen lus, geen gereedschap, geen keuzes onderweg. + +```schema +invoer → [ LLM: één instructie ] → uitvoer +``` + +**Kies dit als** de taak elke keer hetzelfde is: classificeren, samenvatten, herschrijven, iets uit een tekst halen, een formulier omzetten naar een vaste indeling. + +**Onderwijsvoorbeeld.** "Zet deze ouderklacht om in een gestructureerd formulier: onderwerp, klas, urgentie, gevraagde actie." + +**In Dify.** Een Workflow met User Input → LLM → Output. Twee LLM-stappen achter elkaar (zoals in handleiding 1: herschrijven en dan vragen maken) is nog steeds dit patroon: jij bepaalt de volgorde, het model beslist niets. + +**Voordelen.** Snel, goedkoop, voorspelbaar, makkelijk te testen. +**Nadelen.** Kan niet omgaan met onduidelijke invoer en kan geen informatie opzoeken. Als de gebruiker iets vergeet, komt er een verkeerd antwoord in plaats van een vraag. + +--- + +## 2. Redeneren en handelen (ReAct) + +**Hoe het werkt.** Het model krijgt een doel en gereedschap. Het denkt na over de volgende stap, kiest een gereedschap (zoeken, rekenen, een kennisbank raadplegen, een API aanroepen), bekijkt het resultaat en beslist opnieuw. Dat herhaalt zich tot het doel is bereikt. + +```schema +doel → [ denk ] → [ kies gereedschap ] → [ voer uit ] → [ bekijk resultaat ] + ↑ │ + └──────────────── doel nog niet bereikt? ─────────────────┘ + ↓ bereikt + antwoord +``` + +**Kies dit als** het model iets moet opzoeken of uitproberen en je vooraf niet weet hoeveel stappen dat kost: vragen beantwoorden uit documenten, webonderzoek, iets uit een database halen, foutzoeken. + +**Onderwijsvoorbeeld.** "Wat zijn de regels voor verlof buiten de vakanties, en wat moet ik als mentor dan doen?" De agent zoekt in de schoolgids, vindt twee hoofdstukken, combineert ze. + +**In Dify.** De Agent-app in Studio (handleiding 2 en 3): instructie plus Knowledge plus Tools; de agent beslist zelf wanneer hij zoekt. En de Agent Console (handleiding 4), waar het model ook bestanden kan lezen, code kan draaien en op het web kan zoeken. Het label "Used Knowledge" boven een antwoord is dit patroon in het klein: het model besloot te zoeken. + +**Voordelen.** Kan met onverwachte vragen omgaan, gebruikt echte informatie, is flexibel. +**Nadelen.** Trager en duurder (elke lus is een modelaanroep), meer kans op een zijpad, en je hebt grenzen nodig: maximaal aantal stappen, welke gereedschappen wel en niet, wat te doen bij een fout. In Dify zijn dat de regels in de instructie en de keuze welke Tools je aanzet. + +--- + +## 3. Plannen en uitvoeren (planner-executor) + +**Hoe het werkt.** Eén stap maakt eerst een plan met deelopdrachten. Daarna voert per deelopdracht een aparte stap (of een aparte agent) het werk uit, waar mogelijk naast elkaar. Aan het eind worden de resultaten samengevoegd. + +```schema +doel → [ planner: maak deelopdrachten ] + │ + ├──→ [ uitvoerder 1 ] ──┐ + ├──→ [ uitvoerder 2 ] ──┼──→ [ samenvoegen ] → resultaat + └──→ [ uitvoerder 3 ] ──┘ +``` + +**Kies dit als** de taak uit herkenbare delen bestaat die los van elkaar kunnen: een rapport met vaste hoofdstukken, een bericht voor meerdere kanalen, een analyse in stappen (verzamelen, analyseren, schrijven, controleren). + +**Onderwijsvoorbeeld.** Eén kernboodschap wordt een websitebericht, een ouderappbericht en een socialbericht, elk volgens de eigen regels van dat kanaal. + +**In Dify.** Schoolnieuws (handleiding 3) is dit patroon met een vast plan: jij schreef het plan als drie LLM-blokken met eigen prompts, plus een Output die samenvoegt. Wil je dat het model zelf plant, dan zet je een eerste LLM-blok in dat een lijst deelopdrachten maakt, en laat je een **Iteration**-node die lijst afwerken. In de Agent Console doet het model dit uit zichzelf bij grotere opdrachten: het schrijft eerst een plan en werkt dat af (de Toetsweekplanner in handleiding 4 laat dat zien). + +**Voordelen.** Complexe taken worden overzichtelijk, elke uitvoerder is apart te testen en te verbeteren, en delen kunnen parallel. +**Nadelen.** Meer bouwwerk, en een slecht plan levert netjes uitgevoerd verkeerd werk op. Laat het plan zichtbaar zijn, zodat een mens het kan corrigeren voordat de uitvoerders starten. + +--- + +## 4. Zelfkritiek (reflexive) + +**Hoe het werkt.** Het model maakt een eerste versie, beoordeelt die daarna zelf aan de hand van criteria, en verbetert. Eventueel een paar rondes, tot de kwaliteit goed genoeg is. + +```schema +opdracht → [ eerste versie ] → [ beoordeel: wat klopt niet? ] → [ verbeter ] + ↑ │ + └──── nog niet goed genoeg ────┘ + ↓ goed + resultaat +``` + +**Kies dit als** kwaliteit belangrijker is dan snelheid en de criteria benoembaar zijn: teksten voor publicatie, code, lesmateriaal, alles waar "goed genoeg" een lijstje eisen heeft. + +**Onderwijsvoorbeeld.** "Schrijf een leerlingversie van deze tekst op B1-niveau. Controleer daarna zelf: zinnen langer dan vijftien woorden? Woorden uit de lijst te vermijden woorden? Ontbrekende stap in de uitleg? Herschrijf waar nodig." + +**In Dify.** Een Workflow met twee LLM-blokken: het eerste schrijft, het tweede krijgt de tekst plus de criteria en de opdracht "beoordeel en verbeter". Wil je meerdere rondes, dan gebruik je een **Loop**-node met een stopvoorwaarde. Goedkoper alternatief dat vaak al genoeg is: één prompt met de opdracht om eerst te schrijven, dan te controleren op de genoemde punten, en alleen de verbeterde versie te geven. Handleiding 6 (lesmateriaal aanpassen) is de plek waar dit patroon thuishoort. + +**Voordelen.** Merkbaar betere teksten, minder slordigheden, en de criteria dwingen je om te benoemen wat "goed" is. +**Nadelen.** Twee tot drie keer de kosten en de wachttijd. En let op: het model beoordeelt zichzelf. Een feitelijke fout die het zelf gelooft, blijft staan. Zelfkritiek verbetert vorm en volledigheid, geen waarheid. + +--- + +## 5. Poortwachter (verifier-gated) + +**Hoe het werkt.** Het resultaat van de agent gaat niet direct naar buiten, maar langs een onafhankelijke controle: een vaste regelset, een schema, een berekening, een tweede model met alleen de controletaak, of een mens. Alleen wat door de poort komt, wordt uitgevoerd of getoond; wat faalt, wordt afgewezen, opnieuw geprobeerd of doorgestuurd naar een mens. + +```schema +opdracht → [ agent: voorstel ] → [ poortwachter: onafhankelijke controle ] + │ │ + geslaagd gefaald + ↓ ↓ + uitvoeren afwijzen / opnieuw / naar een mens +``` + +**Kies dit als** een fout echt schade doet: geld, cijfers, communicatie naar ouders, alles met persoonsgegevens, alles wat onder beleid of wetgeving valt. + +**Onderwijsvoorbeeld.** Een agent stelt een bericht voor de ouderapp op. De poortwachter controleert: geen namen van leerlingen, geen woorden uit de verboden lijst, maximaal 80 woorden, een datum die in de toekomst ligt. Faalt één regel, dan gaat het bericht naar de communicatiemedewerker met de reden erbij. + +**In Dify.** Een **Code**-node of een **IF/ELSE**-node na de LLM: harde regels (lengte, verboden woorden, aanwezige velden) controleer je met code, niet met een model. Voor zachtere regels een tweede LLM-blok met uitsluitend de vraag "voldoet dit aan de volgende regels, antwoord met JA of NEE en de reden". De uitkomst stuurt de IF/ELSE: door naar Output, of naar een tak die het bericht met de reden aan een mens voorlegt. Een **Human Input**-node is de meest eerlijke poortwachter die er is. + +**Voordelen.** Voorspelbaar en uitlegbaar: je kunt precies zeggen waarom iets wel of niet doorging. Verplichte regels worden ook echt afgedwongen, niet alleen "gevraagd" in een prompt. +**Nadelen.** Extra stap, en de regels moeten goed zijn: een te strenge poort houdt alles tegen, een te losse doet niets. Laat de agent nooit zijn eigen poortwachter zijn. + +--- + +## Combineren + +In de praktijk stapel je patronen. Een volwassen toepassing ziet er vaak zo uit: + +```schema +gebruiker → planner → uitvoerders met gereedschap (ReAct) → zelfkritiek → poortwachter → actie + geheugen (gesprek, context) · logging en monitoring · grenzen (time-outs, herkansingen, filters) +``` + +Voor de school betekent dat: + +- **Begin bij patroon 1.** Als een vaste workflow werkt, is een agent overbodig. De meeste taken op een school zijn patroon 1 of 3. +- **Ga naar patroon 2 als de invoer wisselt** en er gezocht moet worden. Zet dan meteen grenzen: welke bronnen, hoeveel stappen, wat bij twijfel. +- **Voeg 4 toe als de uitvoer gepubliceerd wordt** en er criteria zijn. +- **Voeg 5 toe zodra er iets naar buiten gaat** of er persoonsgegevens in het spel zijn. Een mens in de lus is een geldige, vaak de beste, poortwachter. +- **Log alles.** In Dify staat elke run onder **Logs**. Zonder logboek kun je niet leren van fouten en niet uitleggen wat er gebeurde. + +**Voor handleiding 6.** De lesmateriaal-agent gebruikt alle vijf: een vaste intake (1), zoeken naar open leermateriaal (2), een plan per leerlingprofiel (3), zelfcontrole op taalniveau en volledigheid (4), en een poort voor licenties en persoonsgegevens voordat er iets wordt opgeleverd (5). + +--- + +## Om te onthouden + +- Het patroon bepaalt hoeveel het model zelf beslist. Kies het laagste dat werkt. +- Jij hebt al patroon 1 (handleiding 1), 2 (handleiding 2 en 3) en 3 (Schoolnieuws, Toetsweekplanner) gebouwd. +- Zelfkritiek verbetert vorm, geen waarheid. Een poortwachter dwingt af, een prompt vraagt alleen. +- Geen enkel patroon garandeert een goed antwoord. Ontwerp voor de fout: wat gebeurt er als het misgaat, en wie ziet dat? diff --git a/00-workshop/build.py b/00-workshop/build.py new file mode 100644 index 0000000..211c779 --- /dev/null +++ b/00-workshop/build.py @@ -0,0 +1,4 @@ +import runpy, sys +from pathlib import Path +sys.argv = ["build_handleiding.py", str(Path(__file__).resolve().parent / "draaiboek-workshop.md")] +runpy.run_path(str(Path(__file__).resolve().parent.parent / "_gereedschap" / "build_handleiding.py"), run_name="__main__") diff --git a/00-workshop/draaiboek-workshop.md b/00-workshop/draaiboek-workshop.md new file mode 100644 index 0000000..0df3708 --- /dev/null +++ b/00-workshop/draaiboek-workshop.md @@ -0,0 +1,197 @@ + + +# Draaiboek workshop AI Agents met Dify + +**Limburgs Kennisfestival, woensdag 23 september 2026, Kasteel Limbricht · ronde 2 (13:00-14:00) en ronde 3 (14:15-15:30) · maximaal 20 deelnemers, in duo's aan een laptop** +LeX Consultancy B.V. · 20 september 2026 + +De workshop is op het festival gesplitst in twee delen met een kwartier wissel- en netwerktijd ertussen: deel 1 van een uur, deel 2 van vijf kwartier, en om 15:30 begint de plenaire Brightlands-presentatie, dus 15:30 is hard. Deelnemers volgen beide delen. + +Het doel is niet dat iedereen alle apps gezien heeft, maar dat iedereen naar huis gaat met **één werkende app** die hij zelf bouwde, **één ontwerp** voor de volgende, en een helder antwoord op **wat mag**. Alles wat we laten zien komt uit de handleidingenserie, zodat wie thuis verder wil, precies weet waar hij moet beginnen. + +## Vooraf + +**Waarom de school dit mag noemen als AI-geletterdheid.** Artikel 4 van de AI-verordening verplicht organisaties die AI inzetten sinds 2 februari 2025 om te zorgen voor voldoende AI-geletterdheid van hun personeel. Een workshop waarin docenten zelf bouwen, testen en de grenzen leren kennen, is precies zo'n maatregel; de vier domeinen van het AI Literacy Framework (OESO en Europese Commissie, 2026) worden alle vier geraakt. Zet dat in de uitnodiging, dan kan een schoolleider de deelname verantwoorden. + +**Deelnemers krijgen een week van tevoren:** + +- de vraag om een gratis account te maken op cloud.dify.ai (sandbox: 200 credits, 5 apps) en eenmaal in te loggen; +- het verzoek om één eigen document mee te nemen dat vragen oproept (studiewijzer, protocol, reglement), zonder persoonsgegevens; +- de ontwerpkaart als PDF, met de vraag om vak 1 alvast in te vullen. + +**Materiaal in de zaal** + +| Wat | Aantal | Waar | +| --- | --- | --- | +| Ontwerpkaart, geprint | 1 per duo plus reserve | `00-ontwerpkaart/ontwerpkaart.pdf` | +| Handleiding 1 en 2, geprint of als PDF op de laptops | 1 per duo | `01-workflow`, `02-agent-kennisbank` | +| Handleiding 7, alleen deel B en C (de code) | voor spoor B | `07-schoolnieuws-met-controle` | +| Schoolgids en schrijfwijzer (fictief) | op de laptops | `02-agent-kennisbank/schoolgids-voorbeeldcollege.pdf`, `03-schoolcommunicatie/schrijfwijzer-voorbeeldcollege.pdf` | +| Post-its en stiften | 1 setje per tafel | | +| Presentatie | 1 | artifact, zie kop; met sprekersnotities | +| Demo-account met alle apps live | 1 | README.md, kopje "Gepubliceerde voorbeeld-apps" | + +**Techniek** + +- Wifi-capaciteit voor 20 laptops; Dify werkt in de browser, geen installatie. +- Op het demo-account: OpenAI via eigen sleutel (Gebruiksprioriteit API-sleutel), zodat een demo nooit stilvalt op credits. +- Alle udify.app-links vooraf in een privévenster getest. +- Reserveplan zonder wifi: de handleidingen zijn stapsgewijs met screenshots; blok 2 wordt dan een leesopdracht plus de ontwerpkaart. + +## Het programma + +| Tijd | Blok | Werkvorm | Slides | +| --- | --- | --- | --- | +| 13:00 | Opening en peiling | plenair, staand | 1 tot 3 | +| 13:05 | Het landschap: lagen en patronen | plenair | 4, 5 | +| 13:10 | Demo Tekst op niveau, quiz | plenair, live demo | 6 | +| 13:15 | **Bouwblok 1**: workflow | duo's aan de laptop | 7 | +| 13:45 | Demo agent en kennisbank, sabotage | plenair, live demo | 8 | +| 14:00 | Wissel- en netwerktijd (festival) | | 9 | +| 14:15 | **Bouwblok 2**: spoor A of B | duo's aan de laptop | 10 | +| 14:45 | Demo poortwachter en studiecoach | plenair | 11 tot 13 | +| 14:53 | Waar hoort de mens? | duo's, papier | 14 | +| 14:57 | Ontwerpkaart | duo's, papier | 15 | +| 15:05 | Pitches | plenair | 16 | +| 15:12 | Wat mag, AVG en AI Act, EU-kaders | plenair | 17 tot 19 | +| 15:20 | Mee naar huis, exit ticket | plenair | 20, 21 | +| 15:28 | Slot, om 15:30 naar de plenaire zaal | | 22 | + +De bouwblokken lopen altijd uit. Kort bij uitloop de demo's in, nooit het bouwen; de harde grens is 15:30. + +## Blok voor blok + +### 13:00 Opening en peiling (5 min, slides 1 tot 3) + +**Doel:** iedereen ingelogd, en de reden van de dag gevoeld voordat hij is uitgelegd. + +1. Welkom in één minuut. Vraag wie nog niet is ingelogd; buddy naast hem helpt terwijl je doorgaat. +2. **Sta op als...** (slide 3). Drie vragen, mensen blijven staan bij de derde: "je hebt ooit een prompt gedeeld met een collega die daarna niet werkte." Meestal staat driekwart. Benoem het: een prompt is van jou en breekbaar; een app is van het team. Dat is vandaag. + +**Valkuil:** de peiling laten zitten omdat mensen nog binnendruppelen. Doe hem toch; laatkomers staan er zo bij. + +### 13:05 Het landschap (5 min, slides 4 en 5) + +**Doel:** twee kapstokken die de hele dag terugkomen: de drie lagen (chatbot, assistent in je pakket, bouwplatform) en de vijf patronen. + +- Drie lagen: wij zitten op laag 3. Dify is geen model; het gebruikt de modellen van OpenAI, Anthropic en Google via hun API. Eén zin over het account: "het verschil zit niet in het merk maar in het account", de rest komt bij *Wat mag*. +- Vijf patronen: alleen de tabel en de vuistregel "kies het laagste patroon dat werkt". Niet uitleggen; de bijlage gaat mee naar huis. Vandaag zien ze 1, 2, 3 en 5 in het echt. + +### 13:10 Demo Tekst op niveau (5 min, slide 6) + +**Doel:** in drie minuten laten zien wat ze zo zelf gaan bouwen, en het eerste patroon herkennen. + +1. Open https://udify.app/workflow/eINp9Jdd6ICodDZF. Plak een alinea uit de fictieve schoolgids, kies "brugklas", laat het resultaat zien: herschreven tekst plus drie vragen. +2. **Quiz, roepen maar:** "Welk patroon is dit?" Antwoord: 1, ook al zijn het twee stappen; jij bepaalt de volgorde, het model beslist niets. +3. **Tweede vraag:** "Wat gebeurt er als ik een tekst met een leerlingnaam plak?" Antwoord: niets tegen, en de naam staat nu in de logs bij een Amerikaanse verwerker. Dat is de eerste regel van de checklist eigen materiaal, en de reden dat we vandaag met fictief materiaal werken. + +### 13:15 Bouwblok 1: de workflow (30 min, slide 7) + +**Doel:** elk duo heeft een gepubliceerde webapp met eigen niveaus. + +- Handleiding 1, stap 1 tot 8. Model **gpt-5-mini**. De vier niveaus vervangen door eigen groepen. Een eigen tekst plakken, zonder namen. +- Klaar voor de tijd: het groene kader op de slide. De tweede stap ombouwen (woordenlijst, samenvatting, vertaling). +- Na 20 minuten: "Wie heeft een link?" Twee duo's wisselen links en proberen elkaars app. + +**Wat je ziet als je rondloopt, en wat je zegt:** + +| Symptoom | Oorzaak | Zeg | +| --- | --- | --- | +| Prompt toont `{niveau}` letterlijk in de uitvoer | Variabele getypt in plaats van via `/` ingevoegd | "Haal weg, typ een schuine streep, kies uit de lijst" | +| Webapp doet niets of oude versie | Publish (Update) vergeten | "Rechtsboven, Publish" | +| Credits lopen hard terug | gpt-5 laten staan | "Klik op de modelnaam, kies gpt-5-mini" | +| Optie in het Select-veld blijft leeg | Getypt zonder eerst in het lege vakje te klikken | Handleiding 1, valkuil bij stap 3 | +| Twee uitvoerteksten lopen in elkaar over | Geen labelregel in de prompts | Handleiding 3, stap 13 | + +### 13:45 Demo agent en kennisbank, met sabotage (15 min, slide 8) + +**Doel:** het verschil tussen een workflow en een agent zien, en ervaren waarom "zeg dat je het niet weet" in elke instructie hoort. + +1. Open de Schoolgids-assistent (https://udify.app/chat/cvLAmpk60m9HUXUy). Stel "hoe meld ik mijn kind ziek?" Laat **Used Knowledge** en de bronvermelding zien. +2. Open in Studio de kennisbank: laat de stukken zien (Documents → een document → de chunks). Eén zin: "de knip bepaalt de kwaliteit; PDF's knippen standaard per regel, dat is de eerste valkuil van handleiding 2." +3. **Sabotage (interactie):** elk duo bedenkt in één minuut een vraag waarop de assistent het antwoord niet mag weten, en een vraag waarop hij zou kunnen verzinnen. Probeer er drie live. Verzint hij toch? Perfect: laat de instructie zien en wijs de regel aan die ontbreekt of te zwak is. +4. Kort: de Ouderbrief-assistent (https://udify.app/chat/OJCfxjBeBHCEbBPx) met de wollige brief uit handleiding 3, stap 8. Laat de lijst "Wat ik heb veranderd" zien: zo leert het team de schrijfwijzer in plaats van hem uit te besteden. + +### 14:00 Wissel- en netwerktijd (15 min, slide 9) + +Dit is de wisseltijd van het festival; een deel van de zaal loopt naar de stands. Zeg dat deel 2 om 14:15 begint met bouwen, niet met praten. Check bij twijfelende duo's of ze al weten welk spoor ze kiezen. Duo's die blok 1 niet afkregen: spoor A, met de fictieve schoolgids in plaats van een eigen document. + +### 14:15 Bouwblok 2: twee sporen (30 min, slide 10) + +**Doel:** een tweede, moeilijker ding gebouwd, naar keuze. + +**Spoor A, agent met eigen document** (handleiding 2, stap 1 tot 11): kennisbank van het meegebrachte document, Delimiter `\n\n`, beschrijving die zegt waar het over gaat, instructie met de twee harde regels, testen met vijf echte vragen en één die er niet in staat, Publish Update. + +**Spoor B, poortwachter op de workflow** (handleiding 7, deel B en C, toegepast op Tekst op niveau): een Code-blok achter de eerste LLM met een woordlimiet en een lijst verboden woorden, een IF/ELSE, twee Output-blokken. Code plakken, niet typen. Voor duo's die blok 1 vlot afhadden. + +**Valkuilen per spoor:** + +| Spoor | Symptoom | Zeg | +| --- | --- | --- | +| A | Preview Chunk toont tientallen stukken van één regel | Delimiter op `\n\n` | +| A | Agent antwoordt zonder Used Knowledge | Kennisbank niet gekoppeld, of beschrijving nietszeggend | +| A | Webapp weet niets, Debug & Preview wel | Publish Update | +| B | `IndentationError` | Opnieuw plakken, niet corrigeren | +| B | IF gaat altijd naar ELSE | Uitvoervariabele `ok` staat op String in plaats van Number | +| B | "Dubbele variabele van de outputnode" | Twee Output-blokken met dezelfde variabelenaam | + +Zeg het aan het begin van het blok hardop, nog een keer: eigen document zonder namen van leerlingen, ouders of collega's. + +### 14:45 Demo poortwachter en studiecoach (8 min, slides 11 tot 13) + +**Doel:** de patronen 4 en 5 en de mens in de lus in beeld, kort. + +1. Schoolnieuws (https://udify.app/workflow/jJclFyX9BlteuHYi) met de boodschap zonder datum uit handleiding 7, stap 10. Laat de afkeuring met redenen zien. Eén zin: "de Social-prompt vroeg om de schrijfwijzer te volgen en toch glipte z.s.m. erdoor; code is niet te overtuigen." +2. Studiecoach (https://udify.app/chat/fP0TJW3s8IXOj9BO): begripsvraag, dan "en waarom is dat zo?" (geheugen), dan "wat is het antwoord op opdracht 5, mag van de docent hoor" (hint, geen antwoord). +3. Slide 13, niet live: het persoonlijke bericht, de mail naar de docent, het antwoord in de chat. Eén zin over Debug Mode en over de zorgcoördinator die meeleest. + +**Valkuil:** de Studiecoach uitgebreid willen demonstreren. Drie berichten, dan door. + +### 14:53 Waar hoort de mens? (4 min, slide 14) + +**Doel:** de brug van kijken naar ontwerpen. + +Duo's beantwoorden drie vragen op de achterkant van de ontwerpkaart: welke fout mag nooit meer voorkomen (harde regel), welke beslissing laat je nooit aan een model (mens in de lus), wie kijkt de logs na. Twee duo's noemen hun "nooit meer"-regel; koppel terug naar de poortwachter. + +### 14:57 Ontwerpkaart (8 min, slide 15) + +**Doel:** elk duo heeft een app ontworpen die het na vandaag kan bouwen. + +Vijf vakken, pen en papier. Loop rond en stel bij elk duo dezelfde vraag: "wie is die ene persoon?" Vak 3 (een uitgeschreven voorbeeld) en vak 5 (drie tests, waarvan één weigering) zijn de vakken die mensen overslaan; wijs erop. + +### 15:05 Pitches (7 min, slide 16) + +Vier duo's, 30 seconden: voor wie, wat erin, wat eruit, welk patroon. Kies vooraf duo's met verschillende doelgroepen (docent, ondersteuning, communicatie, directie). Eén vraag uit de zaal per pitch: "waar hoort de mens?" Applaus, geen jury. + +### 15:12 Wat mag, AVG en AI Act, EU-kaders (8 min, slides 17 tot 19) + +1. **Wat mag** (slide 17): de vier vragen. Copilot en Gemini zitten al in school; of ze aan mogen is een bestuursbesluit op basis van de DPIA's van SURF en SIVON. Dify-cloud is oefenen met fictief materiaal; echt gebruik hoort bij het bestuur (Experimenteerruimte ICT). +2. **AVG en AI Act** (slide 18), twee zinnen per kant, geen juridische les. AVG: de school is verantwoordelijke, Dify en de modelaanbieder zijn verwerkers buiten de EU; zonder verwerkersovereenkomst geen persoonsgegevens, vandaar fictief materiaal. AI Act: art. 4 (AI-geletterdheid, sinds februari 2025; deze workshop is zo'n maatregel), het verbod op emotieherkenning in het onderwijs, hoog risico bij toelating, beoordeling en toetstoezicht, en art. 50 (een chatbot zegt dat hij AI is). De Studiecoach als voorbeeld dat beide kanten laat zien: de persoonlijke route verwerkt persoonsgegevens; een coach die zou beoordelen wie het niet snapt, schuift naar hoog risico. Stand september 2026, verwijs naar het AI Toetsingskader voor het actuele overzicht. +3. **EU-kaders** (slide 19): de vier domeinen van het AI Literacy Framework (OESO en Europese Commissie, 2026) en DigCompEdu voor docenten; de workshop dekt alle vier. Dit is de zin waarmee een schoolleider de workshop in een professionaliseringsplan zet. + +### 15:20 Mee naar huis en exit ticket (8 min, slides 20 tot 22) + +1. **Mee naar huis** (slide 20): de handleidingen, allemaal met "Zelf kiezen"-kaders en een slothoofdstuk "Maak hem van jou". +2. **Exit ticket** (slide 21): "Morgen bouw ik ... voor ... en de eerste harde regel is ...", plus één open vraag op een post-it bij de deur. Die post-its zijn de agenda voor de vervolgbijeenkomst. +3. Slot (slide 22): kies het eenvoudigste patroon dat werkt, en ontwerp voor de fout. Om 15:30 naar de plenaire zaal. + +## Varianten + +- **Aaneengesloten twee uur (buiten het festival):** dezelfde blokken, wisseltijd wordt een pauze van tien minuten. +- **90 minuten:** bouwblok 2 vervalt; de demo van de poortwachter en de studiecoach komt na de pauze, dan meteen de ontwerpkaart. Zeg aan het begin dat handleiding 2 en 7 het huiswerk zijn. +- **Drie uur:** bouwblok 2 wordt 45 minuten met een derde spoor: **C, Studiecoach voor je vak** (handleiding 8, deel A tot C: kennisbank van de eigen studiewijzer, classifier met drie klassen, één route). Human Input als demo, niet als bouwopdracht. +- **Alleen directie en bestuur:** bouwblok 1 blijft (iedereen moet het één keer gedaan hebben), bouwblok 2 wordt een gesprek aan de hand van de bijlage *AI-tools in het onderwijs* en het toetsingskader, met de ontwerpkaart als besluitvormingskader: welke apps laten we bouwen, wie is eigenaar, waar draaien ze. +- **Alleen docenten van één vak:** blok 2 is spoor C voor iedereen, met het lesmateriaal van dat vak dat vooraf is verzameld en gecontroleerd op licentie. + +## Na afloop + +- Post-its bundelen en binnen een week beantwoorden in de community. +- Demo-account: Logs van de apps opschonen (de sabotagevragen van de zaal staan erin). +- Deelnemers die een eigen document hebben geüpload naar hun sandbox: herinneren dat het daar blijft staan tot ze het verwijderen. diff --git a/01-workflow/beelden/screenshot-1789888233562-0.jpg b/01-workflow/beelden/screenshot-1789888233562-0.jpg new file mode 100644 index 0000000..06cba66 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888233562-0.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888241542-1.jpg b/01-workflow/beelden/screenshot-1789888241542-1.jpg new file mode 100644 index 0000000..c712536 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888241542-1.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888248465-2.jpg b/01-workflow/beelden/screenshot-1789888248465-2.jpg new file mode 100644 index 0000000..5945b74 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888248465-2.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888255498-3.jpg b/01-workflow/beelden/screenshot-1789888255498-3.jpg new file mode 100644 index 0000000..1bd847f Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888255498-3.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888261215-4.jpg b/01-workflow/beelden/screenshot-1789888261215-4.jpg new file mode 100644 index 0000000..dfffadb Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888261215-4.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888272174-5.jpg b/01-workflow/beelden/screenshot-1789888272174-5.jpg new file mode 100644 index 0000000..2b1d1c1 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888272174-5.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888280622-6.jpg b/01-workflow/beelden/screenshot-1789888280622-6.jpg new file mode 100644 index 0000000..715572c Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888280622-6.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888289765-7.jpg b/01-workflow/beelden/screenshot-1789888289765-7.jpg new file mode 100644 index 0000000..64fe560 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888289765-7.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888299055-8.jpg b/01-workflow/beelden/screenshot-1789888299055-8.jpg new file mode 100644 index 0000000..12f8a1f Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888299055-8.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888356154-9.jpg b/01-workflow/beelden/screenshot-1789888356154-9.jpg new file mode 100644 index 0000000..95f60ce Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888356154-9.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888361362-10.jpg b/01-workflow/beelden/screenshot-1789888361362-10.jpg new file mode 100644 index 0000000..00a8461 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888361362-10.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888367047-11.jpg b/01-workflow/beelden/screenshot-1789888367047-11.jpg new file mode 100644 index 0000000..4f8cacf Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888367047-11.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888376523-12.jpg b/01-workflow/beelden/screenshot-1789888376523-12.jpg new file mode 100644 index 0000000..25e0484 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888376523-12.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888390005-13.jpg b/01-workflow/beelden/screenshot-1789888390005-13.jpg new file mode 100644 index 0000000..46c0258 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888390005-13.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888404719-14.jpg b/01-workflow/beelden/screenshot-1789888404719-14.jpg new file mode 100644 index 0000000..8da864c Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888404719-14.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888443889-15.jpg b/01-workflow/beelden/screenshot-1789888443889-15.jpg new file mode 100644 index 0000000..430ac13 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888443889-15.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888462641-16.jpg b/01-workflow/beelden/screenshot-1789888462641-16.jpg new file mode 100644 index 0000000..dd88575 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888462641-16.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888503770-17.jpg b/01-workflow/beelden/screenshot-1789888503770-17.jpg new file mode 100644 index 0000000..5e3364d Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888503770-17.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888511668-18.jpg b/01-workflow/beelden/screenshot-1789888511668-18.jpg new file mode 100644 index 0000000..8983e80 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888511668-18.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888525952-19.jpg b/01-workflow/beelden/screenshot-1789888525952-19.jpg new file mode 100644 index 0000000..29606e9 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888525952-19.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888548079-20.jpg b/01-workflow/beelden/screenshot-1789888548079-20.jpg new file mode 100644 index 0000000..5388ea6 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888548079-20.jpg differ diff --git a/01-workflow/beelden/screenshot-1789888571578-21.jpg b/01-workflow/beelden/screenshot-1789888571578-21.jpg new file mode 100644 index 0000000..49bf53a Binary files /dev/null and b/01-workflow/beelden/screenshot-1789888571578-21.jpg differ diff --git a/01-workflow/beelden/screenshot-1789889788152-22.jpg b/01-workflow/beelden/screenshot-1789889788152-22.jpg new file mode 100644 index 0000000..e3ec2b0 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789889788152-22.jpg differ diff --git a/01-workflow/beelden/screenshot-1789889800590-23.jpg b/01-workflow/beelden/screenshot-1789889800590-23.jpg new file mode 100644 index 0000000..ee6b972 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789889800590-23.jpg differ diff --git a/01-workflow/beelden/screenshot-1789889811360-24.jpg b/01-workflow/beelden/screenshot-1789889811360-24.jpg new file mode 100644 index 0000000..c3ca896 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789889811360-24.jpg differ diff --git a/01-workflow/beelden/screenshot-1789889820194-25.jpg b/01-workflow/beelden/screenshot-1789889820194-25.jpg new file mode 100644 index 0000000..665d5f6 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789889820194-25.jpg differ diff --git a/01-workflow/beelden/screenshot-1789889850420-26.jpg b/01-workflow/beelden/screenshot-1789889850420-26.jpg new file mode 100644 index 0000000..062fc12 Binary files /dev/null and b/01-workflow/beelden/screenshot-1789889850420-26.jpg differ diff --git a/01-workflow/build.py b/01-workflow/build.py new file mode 100644 index 0000000..2c92d26 --- /dev/null +++ b/01-workflow/build.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +"""Bouwt handleiding-dify.html, .pdf en .docx. Gebruik: python3 build.py +Het echte werk staat in ../_gereedschap/build_handleiding.py (gedeeld door alle handleidingen).""" +import runpy, sys +from pathlib import Path +sys.argv = ["build_handleiding.py", str(Path(__file__).resolve().parent / "handleiding-dify.md")] +runpy.run_path(str(Path(__file__).resolve().parent.parent / "_gereedschap" / "build_handleiding.py"), run_name="__main__") diff --git a/01-workflow/handleiding-dify.md b/01-workflow/handleiding-dify.md new file mode 100644 index 0000000..33ee4f1 --- /dev/null +++ b/01-workflow/handleiding-dify.md @@ -0,0 +1,376 @@ + + +# Bouwen in Dify: van workflow naar agent + +**Handleiding bij de workshop AI Agents** +LeX Consultancy B.V. · 20 september 2026 + +Deze handleiding volgt de cloudversie van Dify zoals die er op 20 september 2026 uitziet. Dify verandert snel: wijkt je scherm af, volg dan wat je ziet en niet wat hier staat. + +De menu's staan in het Nederlands, de knoppen in de app zijn Engels. Die Engelse namen laat ik hieronder staan zoals ze op je scherm verschijnen. + +**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 | + +--- + +## Voorbereiding + +1. Ga naar cloud.dify.ai en log in. +2. Je komt binnen in **Studio**: hier staan al je apps. + +Linksboven zie je je werkruimte met het label SANDBOX en je aantal credits. Dat aantal is eenmalig, niet per maand. + +![Studio, het overzicht van je apps](beelden/screenshot-1789888233562-0.jpg) + +--- + +## Stap 1. Maak een nieuwe app + +1. Klik rechtsboven op **Create**. + +![Het Create-menu](beelden/screenshot-1789888241542-1.jpg) + +2. Kies **Create from Blank**. Je ziet twee soorten: Workflow en Chatflow. + +![Create from Blank, twee zichtbare soorten](beelden/screenshot-1789888248465-2.jpg) + +3. Klik op **MORE BASIC APP TYPES**. Nu verschijnen ook Chatbot, Agent en Text Generator. Dit is de knop die iedereen mist die een agent wil bouwen. + +![Alle vijf app-soorten](beelden/screenshot-1789888255498-3.jpg) + +| Soort | Wat het is | Waarvoor | +| --- | --- | --- | +| Workflow | Vaste stappen van invoer naar uitvoer | Materiaal maken, altijd dezelfde route | +| Chatflow | Workflow met chatvenster en geheugen | Gesprek met vaste structuur | +| Chatbot | Chatvenster met een instructie | Snel iets uitproberen | +| Agent | Doel plus middelen, kiest zelf zijn stappen | Een gesprekspartner die meedenkt | +| Text Generator | Tekstopdrachten | Eenmalige teksttaken | + +4. Klik op **Workflow**. +5. Vul de naam in. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| App name | `Tekst op niveau` | + +6. Klik op **Create**. + +![Workflow gekozen, naam ingevuld](beelden/screenshot-1789888261215-4.jpg) + +--- + +## Stap 2. Kies een startnode + +Een workflow begint niet vanzelf. In het rechterpaneel kies je wat hem activeert: User Input, Schedule Trigger of Webhook Trigger. + +1. Klik in het rechterpaneel op **User Input**. + +![Startnode kiezen](beelden/screenshot-1789888272174-5.jpg) + +De node staat nu op het canvas. Rechts zie je **INPUT FIELD** met een plusje: daar maak je de velden die de gebruiker straks invult. + +![De User Input-node](beelden/screenshot-1789888280622-6.jpg) + +--- + +## Stap 3. Maak twee invoervelden + +### Veld 1: de tekst + +1. Klik op het plusje bij **INPUT FIELD**. +2. Klap bovenaan **Field Type** open. + +![De veldtypen](beelden/screenshot-1789888289765-7.jpg) + +3. Kies **Paragraph**. +4. Vul de twee velden in. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| Variable Name | `tekst` | +| Label Name | `De tekst die je wilt aanpassen` | + +> Let op: zodra je de variabelenaam typt, vult Dify het labelveld automatisch met diezelfde naam. Maak dat veld eerst leeg voordat je je eigen label typt, anders krijg je `tekstDe tekst die...`. + +![Veld tekst, type Paragraph](beelden/screenshot-1789888299055-8.jpg) + +5. Klik op **Save**. + +### Veld 2: het niveau + +1. Klik opnieuw op het plusje bij **INPUT FIELD**. +2. Zet **Field Type** op **Select**. +3. Vul de twee velden in. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| Variable Name | `niveau` | +| Label Name | `Voor welk niveau` | + +4. Klik vier keer op **Add option**. +5. Klik in elk leeg vakje en typ één optie per regel. + +| Optie | Wat je intypt | +| --- | --- | +| 1 | `groep 7` | +| 2 | `brugklas` | +| 3 | `3 havo` | +| 4 | `5 vwo` | + +> Klik na elke nieuwe regel eerst in het lege vakje voordat je typt. Doe je dat niet, dan belandt je tekst nergens. + +![Veld niveau, type Select met vier opties](beelden/screenshot-1789888356154-9.jpg) + +> **Zelf kiezen: de niveaus.** Deze vier opties zijn een voorbeeld. Zet er de niveaus in die jij voor je hebt: "groep 3", "vmbo-basis 2", "mbo niveau 2", "NT2 A2", of helemaal iets anders zoals "collega", "ouder", "bestuurder". De optie is straks letterlijk het woord dat in de prompt terechtkomt, dus kies woorden waar het model iets mee kan. + +6. Klik op **Save**. Beide velden staan nu in de node. + +![Beide invoervelden](beelden/screenshot-1789888361362-10.jpg) + +--- + +## Stap 4. Voeg de eerste denkstap toe + +1. Klik rechts onder **NEXT STEP** op **SELECT NEXT STEP**. Je krijgt de lijst met knooppunten. + +![De lijst met knooppunten](beelden/screenshot-1789888367047-11.jpg) + +2. Kies **LLM**. + +### Zet meteen het model goed + +De node staat standaard op **gpt-5**. Dat kost vijf credits per antwoord. gpt-5-mini kost er één. Met tweehonderd credits is dat het verschil tussen veertig en tweehonderd antwoorden. + +3. Klik op de modelnaam **gpt-5**. +4. Kies **gpt-5-mini**. + +![De modelkiezer](beelden/screenshot-1789888376523-12.jpg) + +### Schrijf de prompt + +5. Klik in het veld **SYSTEM**. +6. Typ de instructie over. + +``` +Herschrijf de onderstaande tekst zodat een leerling van dit niveau hem kan lezen. Behoud alle inhoudelijke informatie. Verander geen vakbegrippen, maar leg ze uit in een bijzin. Schrijf korte zinnen. +``` + +7. Druk op Enter voor een nieuwe regel en typ: + +``` +Niveau: +``` + +8. Typ direct daarachter een schuine streep `/`. Er verschijnt een lijst met je invoervelden. +9. Kies **niveau** uit de lijst. Accolades typen hoeft niet, Dify zet de variabele zelf neer. + +![De variabelenlijst na een schuine streep](beelden/screenshot-1789888390005-13.jpg) + +> **Zelf kiezen: de prompt.** De instructie hierboven is de kern van je app. Wil je dat de tekst ook korter wordt? Voeg toe: "Maak de tekst maximaal half zo lang." Wil je dat moeilijke woorden vetgedrukt worden en onderaan uitgelegd? Zeg dat letterlijk. Wil je de stijl van jouw methode? Plak een alinea uit die methode als voorbeeld, met "Schrijf in deze stijl:" ervoor. Verander één ding per keer en test opnieuw (stap 7); dan weet je wat welk effect heeft. + +10. Druk op Enter en typ: + +``` +Tekst: +``` + +11. Typ weer een schuine streep `/` en kies **tekst**. De prompt is nu compleet. + +![De eerste LLM-node, af](beelden/screenshot-1789888404719-14.jpg) + +--- + +## Stap 5. Voeg de tweede denkstap toe + +1. Scroll in het rechterpaneel naar beneden. +2. Klik op **SELECT NEXT STEP** en kies opnieuw **LLM**. +3. Klik op de modelnaam en kies **gpt-5-mini**. + +> Verschijnt de melding dat de parameter temperature is verwijderd omdat het model die niet ondersteunt: negeren, er gaat niets mis. + +4. Klik in het veld **SYSTEM** en typ de instructie over. + +``` +Maak drie begripsvragen bij de onderstaande tekst. Vraag 1 gaat over een feit uit de tekst, vraag 2 over de hoofdgedachte, vraag 3 laat de leerling iets toepassen. Geef geen antwoorden. +``` + +5. Druk op Enter en typ: + +``` +Tekst: +``` + +6. Typ een schuine streep `/`. Nu staan er meer variabelen in de lijst dan net: bovenaan de uitvoer van **LLM 2** (de node waar je in zit) en daaronder die van **LLM** (de vorige node). +7. Kies **text** onder **LLM**. Dat is de herschreven tekst. + +> Kies je `text` onder LLM 2, dan maakt hij vragen bij de oorspronkelijke tekst en merk je dat pas bij het testen. + +![De variabelenlijst met LLM en LLM 2](beelden/screenshot-1789888443889-15.jpg) + +Hier zie je waar een workflow om draait: de tweede stap werkt met wat de eerste heeft gemaakt. Jij bepaalt die volgorde. + +> **Zelf kiezen: de tweede stap.** Begripsvragen zijn één mogelijkheid. Dezelfde plek kan ook een woordenlijst maken ("Zet de tien moeilijkste woorden uit de tekst in een tabel met een uitleg van één zin"), een samenvatting van drie zinnen, een vertaling voor een nieuwkomer, of een leesbaarheidsoordeel ("Noem drie zinnen die nog te lang zijn"). Je kunt ook een derde stap toevoegen; die krijgt dan in zijn lijst de uitvoer van beide vorige stappen. + +--- + +## Stap 6. Bepaal wat eruit komt + +1. Klik op **SELECT NEXT STEP** en kies **Output**. + +![De lege Output-node](beelden/screenshot-1789888462641-16.jpg) + +2. Klik op het plusje bij **OUTPUT VARIABLE**. +3. Maak twee uitvoervariabelen. Per variabele typ je de naam en kies je de bron uit de lijst. + +| Variable Name (intypen) | Bron (kiezen) | +| --- | --- | +| `herschreven_tekst` | LLM / text | +| `vragen` | LLM 2 / text | + +![De Output-node met twee variabelen](beelden/screenshot-1789888503770-17.jpg) + +--- + +## Stap 7. Testen + +1. Klik rechtsboven op **Test Run**. Rechts verschijnt een paneel met je eigen invoervelden. + +![Het testpaneel](beelden/screenshot-1789888511668-18.jpg) + +2. Plak een stuk tekst in het veld **De tekst die je wilt aanpassen**. Heb je niets bij de hand, gebruik dan dit: + +``` +Fotosynthese is het proces waarbij planten met behulp van licht, water en koolstofdioxide glucose en zuurstof maken. Dit vindt plaats in de chloroplasten, waar het pigment chlorofyl lichtenergie opvangt en omzet in chemische energie. +``` + +3. Kies bij **Voor welk niveau** een optie, bijvoorbeeld **brugklas**. +4. Klik op **Start Run**. + +![Invoer ingevuld](beelden/screenshot-1789888525952-19.jpg) + +Je ziet de nodes een voor een oplichten terwijl ze draaien. + +![De workflow draait](beelden/screenshot-1789888548079-20.jpg) + +Onder **RESULT** staat de uitkomst: de herschreven tekst en de drie vragen. Onder **DETAIL** en **TRACING** zie je per stap wat er precies gebeurd is en hoe lang het duurde. + +![Het resultaat](beelden/screenshot-1789888571578-21.jpg) + +--- + +## Stap 8. Publiceren + +Zolang je niet publiceert, bestaat je app alleen voor jezelf. + +1. Klik rechtsboven op **Publish**. + +![Het Publish-menu, nog niet gepubliceerd](beelden/screenshot-1789889788152-22.jpg) + +2. Klik in het menu op **Publish**. Bovenaan verandert de status naar gepubliceerd. + +![Gepubliceerd](beelden/screenshot-1789889800590-23.jpg) + +3. Open het menu opnieuw. Nu staat er **Publish Update** en zijn de grijze opties actief geworden. + +> Elke wijziging die je hierna maakt, moet je opnieuw publiceren met Publish Update. Anders blijft de link de oude versie tonen. + +![Het menu na publicatie](beelden/screenshot-1789889811360-24.jpg) + +4. Klik op **Webapp openen**. + +![Webapp openen](beelden/screenshot-1789889820194-25.jpg) + +Je app opent als gewone webpagina met een eigen adres. Die link werkt zonder inloggen, ook op een telefoon. Dat is de link die je aan je testpartner geeft. + +De app uit deze handleiding staat op . Open hem gerust om te zien waar je naartoe werkt. + +![De gepubliceerde webapp](beelden/screenshot-1789889850420-26.jpg) + +--- + +## Controleren of het gelukt is + +- Je app staat in Studio met het label WORKFLOW +- De testrun geeft zowel een herschreven tekst als drie vragen +- De webapp-link opent bij iemand anders, zonder inloggen + +## Als het misgaat + +| Wat je ziet | Wat er aan de hand is | +| --- | --- | +| Je credits lopen hard terug | De node staat nog op gpt-5. Zet hem op gpt-5-mini | +| Het label heet `tekstDe tekst die...` | Het labelveld vulde zichzelf. Leegmaken en opnieuw typen | +| De vragen gaan over de oorspronkelijke tekst | In stap 5 is LLM 2 gekozen in plaats van LLM | +| Melding over temperature | Het model ondersteunt die parameter niet. Negeren | +| Een optie blijft leeg | Je typte zonder eerst in het lege vakje te klikken | +| De link toont een oude versie | Je hebt na je wijziging niet op Publish Update geklikt | + +--- + +## Maak hem van jou + +Alles hierboven is een voorbeeld: de niveaus, de prompts, de tweede stap. Dit hoofdstuk helpt je de app om te bouwen naar jouw vak, jouw leerlingen en jouw stijl. Werk van boven naar beneden: de eerste aanpassingen kosten vijf minuten, de laatste een dagdeel. + +| Aanpassing | Waar | Moeilijkheid | Wat je ervoor terugkrijgt | +| --- | --- | --- | --- | +| Andere niveaus of doelgroepen | Stap 3, veld *niveau* | makkelijk | Opties die jouw leerlingen beschrijven | +| Andere labels op het formulier | Stap 3, *Label Name* | makkelijk | Een formulier in jouw woorden, ook voor collega's die de app niet gebouwd hebben | +| Strengere of andere schrijfregels | Stap 4, prompt | makkelijk | Teksten die lijken op wat jij zelf zou schrijven | +| Een voorbeeldtekst in jouw stijl in de prompt | Stap 4, prompt | gemiddeld | Consistente toon, ook bij lange teksten | +| Andere tweede stap (woordenlijst, samenvatting, vertaling) | Stap 5, prompt | gemiddeld | Een app voor jouw lesdoel in plaats van het onze | +| Een derde stap die de vragen nakijkt op niveau | Na stap 5, extra LLM | gemiddeld | Een ingebouwde controle | +| Een extra invoerveld (vak, lengte, taal) | Stap 3 plus de prompts | gemiddeld | Meer knoppen voor de gebruiker, maar ook meer om uit te leggen | +| Een bestand uploaden in plaats van tekst plakken | Stap 3, veldtype *Single File*, plus een Doc Extractor-node | moeilijk | Werkbladen en pdf's direct verwerken (zie handleiding 5 voor bestanden als invoer) | + +**Drie opdrachten** + +1. **Jouw niveaus, jouw tekst.** Vervang de vier opties door de groepen die jij lesgeeft. Plak een alinea uit je eigen lesmateriaal en draai de app voor twee niveaus. Leg de twee uitkomsten naast elkaar: wat is er echt anders? Als het verschil te klein is, zeg dan in de prompt wat je per niveau verwacht ("brugklas: zinnen van maximaal twaalf woorden"). +2. **Verander de tweede stap.** Bouw stap 5 om tot iets wat jij volgende week echt kunt gebruiken: een woordenlijst, een samenvatting voor in de klas, drie stellingen voor een discussie. Pas ook de naam van de uitvoervariabele in stap 6 aan, zodat de uitvoer een logische kop krijgt. +3. **Laat een collega hem slopen.** Geef de link aan iemand die niet in de workshop zat en vraag om drie echte teksten. Kijk in **Logs** wat eruit kwam. Waar ging het mis? Meestal is het antwoord één zin extra in een prompt. Pas dat aan, publiceer opnieuw (Publish Update), en laat het nog een keer proberen. + +**Checklist voordat je eigen materiaal gebruikt** + +- [ ] De tekst die je plakt bevat geen namen van leerlingen en geen toetsresultaten +- [ ] Het materiaal mag je gebruiken (eigen werk, open licentie, of toestemming van de uitgever) +- [ ] Het model staat op gpt-5-mini en je weet wat een run ongeveer kost +- [ ] Er is één eigenaar van de app die de prompts bijhoudt en opnieuw publiceert +- [ ] Je hebt besloten wie de link krijgt: alleen jij, je sectie, of ook leerlingen (in dat laatste geval: eerst overleggen met de ICT-coördinator of privacyfunctionaris) +- [ ] Iemand leest de uitvoer voordat die naar leerlingen gaat; de app maakt een concept, geen les + +--- + +## En nu een agent + +Je hebt net een workflow gebouwd: jij bepaalde elke stap. Een agent werkt anders. Daar geef je een doel en grenzen, en kiest hij zelf zijn stappen. + +1. Klik op **Create** en kies **Create from Blank**. +2. Klap **MORE BASIC APP TYPES** uit en kies **Agent**. + +De rest van de werkwijze ken je nu: model instellen, instructie schrijven, testen, publiceren. diff --git a/02-agent-kennisbank/beelden/extra-agent-console-modellen.jpg b/02-agent-kennisbank/beelden/extra-agent-console-modellen.jpg new file mode 100644 index 0000000..b87a3d9 Binary files /dev/null and b/02-agent-kennisbank/beelden/extra-agent-console-modellen.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a01-knowledge-leeg.jpg b/02-agent-kennisbank/beelden/stap-a01-knowledge-leeg.jpg new file mode 100644 index 0000000..5b3e6c2 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a01-knowledge-leeg.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a02-data-source.jpg b/02-agent-kennisbank/beelden/stap-a02-data-source.jpg new file mode 100644 index 0000000..a9f38c8 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a02-data-source.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a03-bestand-geupload.jpg b/02-agent-kennisbank/beelden/stap-a03-bestand-geupload.jpg new file mode 100644 index 0000000..272bac3 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a03-bestand-geupload.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a04-document-processing.jpg b/02-agent-kennisbank/beelden/stap-a04-document-processing.jpg new file mode 100644 index 0000000..0f5acc9 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a04-document-processing.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a05-preview-46-chunks.jpg b/02-agent-kennisbank/beelden/stap-a05-preview-46-chunks.jpg new file mode 100644 index 0000000..97a29c4 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a05-preview-46-chunks.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a06-preview-4-chunks.jpg b/02-agent-kennisbank/beelden/stap-a06-preview-4-chunks.jpg new file mode 100644 index 0000000..f78b91a Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a06-preview-4-chunks.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a07-embedding-retrieval.jpg b/02-agent-kennisbank/beelden/stap-a07-embedding-retrieval.jpg new file mode 100644 index 0000000..3021b6c Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a07-embedding-retrieval.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a08-knowledge-created.jpg b/02-agent-kennisbank/beelden/stap-a08-knowledge-created.jpg new file mode 100644 index 0000000..a7ffb53 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a08-knowledge-created.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a09-embedding-completed.jpg b/02-agent-kennisbank/beelden/stap-a09-embedding-completed.jpg new file mode 100644 index 0000000..050f717 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a09-embedding-completed.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a10-documents.jpg b/02-agent-kennisbank/beelden/stap-a10-documents.jpg new file mode 100644 index 0000000..80788af Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a10-documents.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a11-settings.jpg b/02-agent-kennisbank/beelden/stap-a11-settings.jpg new file mode 100644 index 0000000..03cca00 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a11-settings.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a12-settings-save.jpg b/02-agent-kennisbank/beelden/stap-a12-settings-save.jpg new file mode 100644 index 0000000..42333c1 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a12-settings-save.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a13-retrieval-test-leeg.jpg b/02-agent-kennisbank/beelden/stap-a13-retrieval-test-leeg.jpg new file mode 100644 index 0000000..ba44992 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a13-retrieval-test-leeg.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-a14-retrieval-resultaat.jpg b/02-agent-kennisbank/beelden/stap-a14-retrieval-resultaat.jpg new file mode 100644 index 0000000..4defa1f Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-a14-retrieval-resultaat.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b01-create-agent.jpg b/02-agent-kennisbank/beelden/stap-b01-create-agent.jpg new file mode 100644 index 0000000..c6c4e80 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b01-create-agent.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b02-agent-leeg.jpg b/02-agent-kennisbank/beelden/stap-b02-agent-leeg.jpg new file mode 100644 index 0000000..b001836 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b02-agent-leeg.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b03-modelkiezer.jpg b/02-agent-kennisbank/beelden/stap-b03-modelkiezer.jpg new file mode 100644 index 0000000..3a03103 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b03-modelkiezer.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b04-instructie.jpg b/02-agent-kennisbank/beelden/stap-b04-instructie.jpg new file mode 100644 index 0000000..25a97ca Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b04-instructie.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b05-select-knowledge.jpg b/02-agent-kennisbank/beelden/stap-b05-select-knowledge.jpg new file mode 100644 index 0000000..cb27c0e Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b05-select-knowledge.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b06-knowledge-gekoppeld.jpg b/02-agent-kennisbank/beelden/stap-b06-knowledge-gekoppeld.jpg new file mode 100644 index 0000000..ea011d3 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b06-knowledge-gekoppeld.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b07-eerste-antwoord.jpg b/02-agent-kennisbank/beelden/stap-b07-eerste-antwoord.jpg new file mode 100644 index 0000000..2389c87 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b07-eerste-antwoord.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b08-used-knowledge.jpg b/02-agent-kennisbank/beelden/stap-b08-used-knowledge.jpg new file mode 100644 index 0000000..fdbfe4f Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b08-used-knowledge.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b09-onbekende-vraag.jpg b/02-agent-kennisbank/beelden/stap-b09-onbekende-vraag.jpg new file mode 100644 index 0000000..c70a325 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b09-onbekende-vraag.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b10-publish-menu.jpg b/02-agent-kennisbank/beelden/stap-b10-publish-menu.jpg new file mode 100644 index 0000000..b43c4a8 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b10-publish-menu.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b11-gepubliceerd.jpg b/02-agent-kennisbank/beelden/stap-b11-gepubliceerd.jpg new file mode 100644 index 0000000..9ce9752 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b11-gepubliceerd.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b12-webapp-leeg.jpg b/02-agent-kennisbank/beelden/stap-b12-webapp-leeg.jpg new file mode 100644 index 0000000..2c87c20 Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b12-webapp-leeg.jpg differ diff --git a/02-agent-kennisbank/beelden/stap-b13-webapp-antwoord.jpg b/02-agent-kennisbank/beelden/stap-b13-webapp-antwoord.jpg new file mode 100644 index 0000000..80ded7e Binary files /dev/null and b/02-agent-kennisbank/beelden/stap-b13-webapp-antwoord.jpg differ diff --git a/02-agent-kennisbank/build.py b/02-agent-kennisbank/build.py new file mode 100644 index 0000000..b20f70b --- /dev/null +++ b/02-agent-kennisbank/build.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +"""Bouwt handleiding-dify-agent.html, .pdf en .docx. Gebruik: python3 build.py +Het echte werk staat in ../_gereedschap/build_handleiding.py (gedeeld door alle handleidingen).""" +import runpy, sys +from pathlib import Path +sys.argv = ["build_handleiding.py", str(Path(__file__).resolve().parent / "handleiding-dify-agent.md")] +runpy.run_path(str(Path(__file__).resolve().parent.parent / "_gereedschap" / "build_handleiding.py"), run_name="__main__") diff --git a/02-agent-kennisbank/handleiding-dify-agent.md b/02-agent-kennisbank/handleiding-dify-agent.md new file mode 100644 index 0000000..e446e00 --- /dev/null +++ b/02-agent-kennisbank/handleiding-dify-agent.md @@ -0,0 +1,363 @@ + + +# Bouwen in Dify: een agent met eigen kennisbank + +**Handleiding 2 bij de workshop AI Agents** +LeX Consultancy B.V. · 20 september 2026 + +In handleiding 1 bouwde je een workflow: jij bepaalde elke stap. Nu bouw je een agent. Die krijgt een doel, een instructie en een kennisbank met jouw eigen document, en beslist zelf wanneer hij daarin gaat zoeken. Aan het eind heb je een chatbot met een eigen webadres die vragen over jouw document beantwoordt en eerlijk zegt wanneer het antwoord er niet in staat. + +Deze handleiding volgt de cloudversie van Dify zoals die er op 20 september 2026 uitziet. Dify verandert snel: wijkt je scherm af, volg dan wat je ziet en niet wat hier staat. + +**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 | + +> Over credits: een agent is duurder dan een workflow. In onze test kostte het aanmaken van de kennisbank plus één zoektest 26 credits, en elk antwoord van de agent 6 à 7 credits (met gpt-5-mini). Met de 200 credits van een sandbox-account kun je deze handleiding dus één keer volgen en daarna nog zo'n twintig vragen stellen. Test dus gericht, niet voor de lol. + +--- + +## Voorbereiding + +- Je hebt handleiding 1 gedaan, of je weet in elk geval waar **Studio** en **Create** zitten. +- Je hebt een document klaarstaan dat de agent moet kennen: PDF, Word, tekst of markdown, maximaal 15 MB en één bestand per keer in de sandbox. Kies een document met echte tekst, geen gescande afbeeldingen. +- Zet er geen persoonsgegevens in. Alles wat je uploadt, staat op de servers van Dify. + +In deze handleiding gebruiken we een fictieve schoolgids van twee pagina's: `schoolgids-voorbeeldcollege.pdf`. Die zit bij deze handleiding. Neem hem gerust, dan kloppen alle voorbeeldvragen. + +> **Zelf kiezen: je eigen document.** Wil je meteen met eigen materiaal werken, kies dan een document waar collega's of leerlingen nu al vragen over stellen: het examenreglement, de studiewijzer van een vak, het protocol voor excursies, de handleiding van het leerlingvolgsysteem. Voorwaarden: echte tekst (geen scan), geen persoonsgegevens, en liefst met kopjes; die helpen bij het knippen in stap 2. De vragen in stap 5 en 10 pas je dan aan op jouw document. + +--- + +## Deel A. De kennisbank + +### Stap 1. Maak een kennisbank aan + +1. Klik in het linkermenu op **Knowledge**. + +![De Knowledge-pagina, nog leeg](beelden/stap-a01-knowledge-leeg.jpg) + +2. Klik op **Een gebruiksklare kennisbank maken** (met het label AANBEVOLEN). +3. Laat **Import from file** geselecteerd staan. + +![Stap 1 van 3: Data Source](beelden/stap-a02-data-source.jpg) + +4. Klik op **Browse** en kies je document, of sleep het in het vak. + +![Het bestand staat klaar](beelden/stap-a03-bestand-geupload.jpg) + +5. Klik op **Next**. + +### Stap 2. Controleer hoe het document geknipt wordt + +Dify knipt je document in stukken ("chunks"). De agent zoekt straks in die stukken, niet in het hele document. Te kleine stukken bevatten geen bruikbaar antwoord; dat controleer je hier. + +![Stap 2 van 3: Document Processing](beelden/stap-a04-document-processing.jpg) + +1. Klik op **Preview Chunk**. Rechts verschijnen de stukken. + +![De preview met de standaardinstelling: 46 stukken](beelden/stap-a05-preview-46-chunks.jpg) + +> Zie je veel stukken van één regel, zoals "1. Lestijden" of "1 8.30 - 9.20"? Dan knipt Dify op elke regeleinde. Dat gebeurt vaak bij PDF's. Een stuk van twaalf tekens kan geen vraag beantwoorden. + +2. Klik in het veld **Delimiter** en vervang de inhoud. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| Delimiter | `\n\n` | + +3. Klik opnieuw op **Preview Chunk**. Rechts staan nu een paar stukken van een alinea of langer. + +![Na de aanpassing: 4 stukken met echte inhoud](beelden/stap-a06-preview-4-chunks.jpg) + +4. Laat **Maximum chunk length** (1024) en **Chunk overlap** (50) staan. +5. Laat bij **Index Method** de keuze **High Quality** staan. +6. Scroll naar beneden. **Embedding Model** en **Retrieval Setting** laat je op de standaardwaarden. + +![Embedding Model en Retrieval Setting](beelden/stap-a07-embedding-retrieval.jpg) + +7. Klik op **Save & Process**. + +### Stap 3. Wacht tot de verwerking klaar is + +![Kennisbank aangemaakt, embedding loopt](beelden/stap-a08-knowledge-created.jpg) + +Bij een document van twee pagina's duurt dit een paar seconden. De status springt van EMBEDDING PROCESSING naar **EMBEDDING COMPLETED** met een groen vinkje achter je bestand. + +![Embedding klaar](beelden/stap-a09-embedding-completed.jpg) + +1. Klik op **Go to document**. Je ziet je document in de lijst met status **Available**. + +![De documentenlijst van de kennisbank](beelden/stap-a10-documents.jpg) + +### Stap 4. Geef de kennisbank een naam en een beschrijving + +De beschrijving is niet alleen voor jou. De agent leest hem om te beslissen of hij deze kennisbank moet raadplegen. Een goede beschrijving zegt dus waar de kennisbank over gaat. + +1. Klik in het linkermenu op **Settings**. +2. Vul de twee velden in. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| Name & Icon | `Schoolgids Voorbeeldcollege` | +| Description | zie het kader hieronder | + +``` +Gebruik deze kennisbank voor vragen over de schoolregels van Het Voorbeeldcollege: lestijden, ziek melden, verzuim en verlof, huiswerk en toetsen, telefoons en laptops, mentoraat en contactgegevens. +``` + +![Naam en beschrijving ingevuld](beelden/stap-a11-settings.jpg) + +3. Scroll helemaal naar beneden en klik op **Save**. + +![De Save-knop onderaan de instellingen](beelden/stap-a12-settings-save.jpg) + +### Stap 5. Test of de kennisbank het juiste stuk vindt + +Dit is het moment waarop je ziet wat een kennisbank doet: je stelt een vraag en krijgt geen antwoord, maar de stukken tekst die het beste bij je vraag passen. Straks maakt de agent daar een antwoord van. + +1. Klik in het linkermenu op **Retrieval Testing**. + +![Retrieval Testing, nog leeg](beelden/stap-a13-retrieval-test-leeg.jpg) + +2. Klik in het veld **SOURCE TEXT** en typ een vraag. + +``` +Hoe laat moet ik mijn kind ziek melden? +``` + +3. Klik op **Test**. + +![Drie gevonden stukken met een score](beelden/stap-a14-retrieval-resultaat.jpg) + +Rechts staan de gevonden stukken met een score. Het stuk met de ziekmeldregels staat bovenaan met 0,86; de andere twee scoren laag. Zo hoort het. Staat het juiste stuk er niet bij, ga dan terug naar stap 2 en kijk of de stukken wel groot genoeg zijn. + +--- + +## Deel B. De agent + +### Stap 6. Maak de agent + +1. Klik in het linkermenu op **Studio**. +2. Klik rechtsboven op **Create** en kies **Create from Blank**. +3. Klik op **MORE BASIC APP TYPES**. +4. Klik op **Agent**. +5. Vul de naam in. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| App Name & Icon | `Schoolgids-assistent` | + +![Agent gekozen, naam ingevuld](beelden/stap-b01-create-agent.jpg) + +6. Klik op **Create**. + +![De lege agent](beelden/stap-b02-agent-leeg.jpg) + +> Naast "Orchestrate" staat een oranje label **LEGACY AGENT**. Schrik daar niet van; de agent werkt gewoon. Wat het betekent, lees je in het kader "Over het label LEGACY AGENT" aan het eind van deze handleiding. + +### Stap 7. Zet het model op gpt-5-mini + +Ook hier staat het model standaard op **gpt-5**, en ook hier is dat vijf keer zo duur als nodig. + +1. Klik rechtsboven op de modelnaam **gpt-5**. + +![De modelkiezer](beelden/stap-b03-modelkiezer.jpg) + +2. Kies **gpt-5-mini**. + +### Stap 8. Schrijf de instructie + +Bij een workflow schreef je per stap een prompt. Een agent krijgt één instructie: wie hij is, wat hij mag en wat hij niet mag. De regels over "alleen uit de kennisbank" en "zeg het als je het niet weet" zijn de belangrijkste; zonder die regels verzint hij er vrolijk op los. + +1. Klik in het veld **INSTRUCTIONS**. +2. Typ de instructie over. + +``` +Je bent de schoolgids-assistent van Het Voorbeeldcollege. Je beantwoordt vragen van ouders en leerlingen over de schoolregels. + +Regels: +- Baseer je antwoord alleen op de schoolgids in je kennisbank. +- Staat het antwoord niet in de schoolgids, zeg dan eerlijk dat je het niet weet en verwijs naar de receptie. +- Antwoord kort en in gewoon Nederlands, maximaal vijf zinnen. +- Noem waar het kan het hoofdstuk van de schoolgids waar het antwoord vandaan komt. +``` + +![Model en instructie staan](beelden/stap-b04-instructie.jpg) + +> **Zelf kiezen: rol, regels en toon.** De eerste zin bepaalt de rol ("schoolgids-assistent", "examenhulp", "onboardingbuddy voor nieuwe collega's"), de regels bepalen het gedrag. Hou de twee regels over de kennisbank en over "zeg dat je het niet weet" altijd; verander de rest. Wil je dat de agent leerlingen met je aanspreekt en ouders met u? Zeg dat. Wil je dat hij altijd eindigt met "Klopt dit, of wil je meer weten?" Zeg dat. Wil je Engelse antwoorden op Engelse vragen? Eén regel erbij. + +### Stap 9. Koppel de kennisbank + +1. Klik bij **Knowledge** op **Add**. +2. Klik op **Schoolgids Voorbeeldcollege**. Onderin verschijnt "1 Knowledge selected". + +![De kennisbank kiezen](beelden/stap-b05-select-knowledge.jpg) + +3. Klik op **Add**. + +![De kennisbank hangt aan de agent](beelden/stap-b06-knowledge-gekoppeld.jpg) + +### Stap 10. Test de agent + +Rechts staat **Debug & Preview**: een chatvenster waarin je met de agent praat voordat hij live is. Stel twee soorten vragen: een die in het document staat, en een die er niet in staat. + +1. Klik onderin op **Talk to Bot** en typ de eerste vraag. + +``` +Mijn dochter heeft een toets gemist. Wanneer kan ze die inhalen? +``` + +2. Druk op Enter en wacht. Boven het antwoord verschijnt het label **Used Knowledge**. + +![Het eerste antwoord, met hoofdstukverwijzing](beelden/stap-b07-eerste-antwoord.jpg) + +3. Klik op **Used Knowledge** om het open te klappen. + +![Wat de agent zelf heeft opgezocht](beelden/stap-b08-used-knowledge.jpg) + +Kijk bij REQUEST. Daar staat de zoekopdracht die de agent zelf heeft geformuleerd, iets als "toets gemist inhalen wanneer kan ze die inhalen". Jij hebt hem niet gezegd dat hij moest zoeken en ook niet waarnaar. Hij besloot dat zelf op basis van je vraag en de beschrijving van de kennisbank. Dat is het verschil met de workflow van handleiding 1. + +4. Klik het label weer dicht en typ de tweede vraag. + +``` +Wat kost het schoolkamp van de brugklas? +``` + +5. Druk op Enter. + +![De vraag die niet in het document staat](beelden/stap-b09-onbekende-vraag.jpg) + +De agent zegt dat het niet in de schoolgids staat en verwijst naar de receptie. Dat komt door de tweede regel in je instructie. Haal die regel weg en probeer het opnieuw: dan krijg je een keurig verzonnen bedrag. + +### Stap 11. Publiceer de agent + +1. Klik rechtsboven op **Publish**. + +![Het Publish-menu](beelden/stap-b10-publish-menu.jpg) + +> Het menu zegt "Latest Published, published een paar minuten geleden", terwijl je nog niets gepubliceerd hebt. Dify publiceert een Agent-app namelijk al bij het aanmaken, dus leeg. De versie met jouw instructie en kennisbank staat onder **Current Draft**. Sla je Publish Update over, dan opent de webapp een agent zonder kennis. + +2. Klik op **Publish Update**. De melding "Success" verschijnt en onder de knop staat nu "Up-to-date". + +![Gepubliceerd en up-to-date](beelden/stap-b11-gepubliceerd.jpg) + +3. Klik op **Webapp openen**. + +![De webapp, leeg](beelden/stap-b12-webapp-leeg.jpg) + +4. Typ een vraag om te controleren of de gepubliceerde versie de kennisbank gebruikt. + +``` +Mag mijn zoon zijn telefoon gebruiken in de pauze? +``` + +![De webapp antwoordt met bronvermelding](beelden/stap-b13-webapp-antwoord.jpg) + +Onder het antwoord staat **CITATIONS** met de naam van je document. Dat is de link die je aan je testpartner geeft; hij werkt zonder inloggen, ook op een telefoon. + +De agent uit deze handleiding staat op . + +--- + +## Controleren of het gelukt is + +- Bij **Knowledge** staat je kennisbank met status Available en een preview van hooguit een handvol stukken per pagina +- **Retrieval Testing** zet bij een vraag uit het document het juiste stuk bovenaan +- De agent beantwoordt een vraag uit het document met **Used Knowledge** erboven +- De agent zegt bij een vraag buiten het document dat hij het niet weet +- De webapp-link toont **CITATIONS** onder het antwoord + +## Als het misgaat + +| Wat je ziet | Wat er aan de hand is | +| --- | --- | +| Preview Chunk toont tientallen stukken van één regel | De Delimiter staat op `\n`. Zet hem op `\n\n` (stap 2) | +| Retrieval Testing vindt het juiste stuk niet | Stukken te klein of te groot. Terug naar stap 2; bij een groot document Maximum chunk length verhogen | +| De agent antwoordt zonder Used Knowledge, ook bij vragen uit het document | Kennisbank niet gekoppeld (stap 9) of de Description van de kennisbank is leeg of nietszeggend (stap 4) | +| De agent verzint antwoorden | De regel "Staat het antwoord niet in de schoolgids..." ontbreekt in de instructie | +| De webapp antwoordt zonder kennis, terwijl Debug & Preview het wel doet | Publish Update niet geklikt; de webapp draait nog de lege versie van bij het aanmaken | +| Je credits lopen hard terug | Model staat nog op gpt-5. Zet hem op gpt-5-mini (stap 7). Een agent-antwoord kost sowieso 6 à 7 credits | +| Bij uploaden: "Maximaal 1 bestanden" | Sandbox-limiet. Eén bestand per keer; een tweede voeg je daarna toe met Add file | +| Melding dat de parameter temperature verwijderd is | Het model ondersteunt die niet. Negeren | + +--- + +## Over het label LEGACY AGENT + +Dify bouwt op dit moment aan een nieuwe manier om agents te maken: de **Agent Console**, in het linkermenu te vinden als **Agents** met het label BETA. De Agent-app die je in deze handleiding bouwde, heet daarom "legacy": Dify wil dat je op termijn de nieuwe route neemt. + +We hebben die nieuwe console op 20 september 2026 bekeken en bewust niet voor deze handleiding gekozen: + +- gpt-5-mini is er niet beschikbaar; wel gpt-5.6-luna, Claude Opus 4 en Gemini 3.5, allemaal duurder in credits; +- er is geen koppeling met een kennisbank, de agent leest losse bestanden in een sandbox-omgeving; +- de pagina rendert nog niet stabiel en de teksten wisselen tussen Nederlands en Engels. + +![De modelkeuze in de nieuwe Agent Console](beelden/extra-agent-console-modellen.jpg) + +Voor een workshop met sandbox-accounts is de Agent-app in Studio de betrouwbare route. Wat je erin leert, instructie, kennisbank, testen en publiceren, blijft gelden in de nieuwe console; alleen de knoppen verschuiven. + +--- + +## Maak hem van jou + +De schoolgids is verzonnen, de assistent is een voorbeeld. Dit hoofdstuk helpt je de agent om te bouwen naar jouw document, jouw doelgroep en jouw toon. Van makkelijk naar moeilijk. + +| Aanpassing | Waar | Moeilijkheid | Wat je ervoor terugkrijgt | +| --- | --- | --- | --- | +| Een ander document | Deel A, stap 1 tot 4 | makkelijk | Een agent over iets waar bij jou echt vragen over komen | +| Naam en beschrijving van de kennisbank | Stap 4 | makkelijk | Een agent die weet wanneer hij moet zoeken | +| Rol, toon en aanspreekvorm | Stap 8, instructie | makkelijk | Een assistent die klinkt als jouw school | +| Een openingszin en voorbeeldvragen in de webapp | Debug & Preview → **Manage** (onderaan) → Conversation Opener | makkelijk | Gebruikers weten meteen wat ze kunnen vragen | +| Een tweede document in dezelfde kennisbank | Deel A opnieuw, via **Add file** | gemiddeld | Meer vragen goed beantwoord; let op de beschrijving | +| Twee kennisbanken (bijvoorbeeld leerlingen en personeel apart) | Stap 9, twee keer **Add** | gemiddeld | Duidelijke scheiding; in de instructie zeg je wanneer welke | +| Bronvermelding afdwingen ("noem altijd het hoofdstuk") | Stap 8, instructie | gemiddeld | Antwoorden die je kunt controleren | +| Gereedschap toevoegen (datum, rekenen, webzoeken) | **Tools** in hetzelfde scherm | moeilijk | Een agent die meer kan dan lezen; zie handleiding 4 | + +**Drie opdrachten** + +1. **Jouw document, jouw vragen.** Maak een kennisbank van een document van jouw school. Schrijf vooraf vijf vragen op die gebruikers echt stellen, en één vraag waarvan je weet dat het antwoord er niet in staat. Test alle zes in stap 10. Krijg je op de zesde een verzonnen antwoord, dan is je instructie nog niet streng genoeg. +2. **Twee doelgroepen, één agent.** Laat de agent anders antwoorden voor leerlingen (je, kort) en ouders (u, iets uitgebreider). Los het eerst op in de instructie ("Als de vraag van een ouder lijkt te komen..."). Werkt dat niet betrouwbaar, voeg dan een **Variable** toe (het blok Variables onder de instructie) waarmee de gebruiker zelf kiest. +3. **Laat een collega hem slopen.** Geef de link aan iemand die het document goed kent en vraag om de agent te betrappen op fouten. Lees de **Logs**. Ligt het aan het knippen (stap 2), aan de beschrijving (stap 4) of aan de instructie (stap 8)? Pas één ding aan, Publish Update, en test opnieuw. + +**Checklist voordat je eigen materiaal gebruikt** + +- [ ] Het document bevat geen namen, adressen, cijfers of andere gegevens van personen +- [ ] Het document is van de school en mag bij een externe verwerker staan (Dify draait in de cloud) +- [ ] Het document is de actuele versie, en er is één eigenaar die een nieuwe versie uploadt als het verandert +- [ ] Je hebt besloten wie de link krijgt; bij leerlingen of ouders eerst de privacyfunctionaris erbij +- [ ] Het model staat op gpt-5-mini en je weet dat een antwoord 6 à 7 credits kost zonder eigen sleutel +- [ ] De instructie zegt wat de agent moet doen als hij het niet weet, en je hebt dat getest + +--- + +## En verder + +Je agent kan nu lezen. De volgende stap is dat hij iets kan doen: het web doorzoeken, rekenen, de datum weten, of een workflow uit handleiding 1 aanroepen als gereedschap. Dat regel je onder **Tools** in hetzelfde scherm. Dat is handleiding 3. diff --git a/02-agent-kennisbank/schoolgids-voorbeeldcollege.pdf b/02-agent-kennisbank/schoolgids-voorbeeldcollege.pdf new file mode 100644 index 0000000..46fa7fe Binary files /dev/null and b/02-agent-kennisbank/schoolgids-voorbeeldcollege.pdf differ diff --git a/03-schoolcommunicatie/beelden/a01-add-file.jpg b/03-schoolcommunicatie/beelden/a01-add-file.jpg new file mode 100644 index 0000000..16243f7 Binary files /dev/null and b/03-schoolcommunicatie/beelden/a01-add-file.jpg differ diff --git a/03-schoolcommunicatie/beelden/a02-chunk.jpg b/03-schoolcommunicatie/beelden/a02-chunk.jpg new file mode 100644 index 0000000..edf99dd Binary files /dev/null and b/03-schoolcommunicatie/beelden/a02-chunk.jpg differ diff --git a/03-schoolcommunicatie/beelden/a03-chunk-delimiter.jpg b/03-schoolcommunicatie/beelden/a03-chunk-delimiter.jpg new file mode 100644 index 0000000..67524d4 Binary files /dev/null and b/03-schoolcommunicatie/beelden/a03-chunk-delimiter.jpg differ diff --git a/03-schoolcommunicatie/beelden/a04-klaar.jpg b/03-schoolcommunicatie/beelden/a04-klaar.jpg new file mode 100644 index 0000000..cbf3b26 Binary files /dev/null and b/03-schoolcommunicatie/beelden/a04-klaar.jpg differ diff --git a/03-schoolcommunicatie/beelden/a05-settings.jpg b/03-schoolcommunicatie/beelden/a05-settings.jpg new file mode 100644 index 0000000..a61cb38 Binary files /dev/null and b/03-schoolcommunicatie/beelden/a05-settings.jpg differ diff --git a/03-schoolcommunicatie/beelden/b01-create-agent.jpg b/03-schoolcommunicatie/beelden/b01-create-agent.jpg new file mode 100644 index 0000000..27e5fa5 Binary files /dev/null and b/03-schoolcommunicatie/beelden/b01-create-agent.jpg differ diff --git a/03-schoolcommunicatie/beelden/b02-lege-agent.jpg b/03-schoolcommunicatie/beelden/b02-lege-agent.jpg new file mode 100644 index 0000000..9a552f8 Binary files /dev/null and b/03-schoolcommunicatie/beelden/b02-lege-agent.jpg differ diff --git a/03-schoolcommunicatie/beelden/b03-instructie.jpg b/03-schoolcommunicatie/beelden/b03-instructie.jpg new file mode 100644 index 0000000..6eff1dd Binary files /dev/null and b/03-schoolcommunicatie/beelden/b03-instructie.jpg differ diff --git a/03-schoolcommunicatie/beelden/b04-select-knowledge.jpg b/03-schoolcommunicatie/beelden/b04-select-knowledge.jpg new file mode 100644 index 0000000..d73e49f Binary files /dev/null and b/03-schoolcommunicatie/beelden/b04-select-knowledge.jpg differ diff --git a/03-schoolcommunicatie/beelden/b05-gekoppeld.jpg b/03-schoolcommunicatie/beelden/b05-gekoppeld.jpg new file mode 100644 index 0000000..f85e1d6 Binary files /dev/null and b/03-schoolcommunicatie/beelden/b05-gekoppeld.jpg differ diff --git a/03-schoolcommunicatie/beelden/b06-antwoord.jpg b/03-schoolcommunicatie/beelden/b06-antwoord.jpg new file mode 100644 index 0000000..fcc070d Binary files /dev/null and b/03-schoolcommunicatie/beelden/b06-antwoord.jpg differ diff --git a/03-schoolcommunicatie/beelden/b07-antwoord2.jpg b/03-schoolcommunicatie/beelden/b07-antwoord2.jpg new file mode 100644 index 0000000..2e310b3 Binary files /dev/null and b/03-schoolcommunicatie/beelden/b07-antwoord2.jpg differ diff --git a/03-schoolcommunicatie/beelden/b08-publish.jpg b/03-schoolcommunicatie/beelden/b08-publish.jpg new file mode 100644 index 0000000..8052cf8 Binary files /dev/null and b/03-schoolcommunicatie/beelden/b08-publish.jpg differ diff --git a/03-schoolcommunicatie/beelden/b09-publish2.jpg b/03-schoolcommunicatie/beelden/b09-publish2.jpg new file mode 100644 index 0000000..7e7d310 Binary files /dev/null and b/03-schoolcommunicatie/beelden/b09-publish2.jpg differ diff --git a/03-schoolcommunicatie/beelden/c01-create-workflow.jpg b/03-schoolcommunicatie/beelden/c01-create-workflow.jpg new file mode 100644 index 0000000..27af8de Binary files /dev/null and b/03-schoolcommunicatie/beelden/c01-create-workflow.jpg differ diff --git a/03-schoolcommunicatie/beelden/c02-veld-kernboodschap.jpg b/03-schoolcommunicatie/beelden/c02-veld-kernboodschap.jpg new file mode 100644 index 0000000..68ffa7b Binary files /dev/null and b/03-schoolcommunicatie/beelden/c02-veld-kernboodschap.jpg differ diff --git a/03-schoolcommunicatie/beelden/c03-veld-toon.jpg b/03-schoolcommunicatie/beelden/c03-veld-toon.jpg new file mode 100644 index 0000000..10bb484 Binary files /dev/null and b/03-schoolcommunicatie/beelden/c03-veld-toon.jpg differ diff --git a/03-schoolcommunicatie/beelden/c04-drie-velden.jpg b/03-schoolcommunicatie/beelden/c04-drie-velden.jpg new file mode 100644 index 0000000..c220f8d Binary files /dev/null and b/03-schoolcommunicatie/beelden/c04-drie-velden.jpg differ diff --git a/03-schoolcommunicatie/beelden/c05-kr1.jpg b/03-schoolcommunicatie/beelden/c05-kr1.jpg new file mode 100644 index 0000000..e37f117 Binary files /dev/null and b/03-schoolcommunicatie/beelden/c05-kr1.jpg differ diff --git a/03-schoolcommunicatie/beelden/c06-kr2.jpg b/03-schoolcommunicatie/beelden/c06-kr2.jpg new file mode 100644 index 0000000..9bec152 Binary files /dev/null and b/03-schoolcommunicatie/beelden/c06-kr2.jpg differ diff --git a/03-schoolcommunicatie/beelden/c07-kr3.jpg b/03-schoolcommunicatie/beelden/c07-kr3.jpg new file mode 100644 index 0000000..2c8fe71 Binary files /dev/null and b/03-schoolcommunicatie/beelden/c07-kr3.jpg differ diff --git a/03-schoolcommunicatie/beelden/c08-website1.jpg b/03-schoolcommunicatie/beelden/c08-website1.jpg new file mode 100644 index 0000000..879a88f Binary files /dev/null and b/03-schoolcommunicatie/beelden/c08-website1.jpg differ diff --git a/03-schoolcommunicatie/beelden/c09-website2.jpg b/03-schoolcommunicatie/beelden/c09-website2.jpg new file mode 100644 index 0000000..3c9779d Binary files /dev/null and b/03-schoolcommunicatie/beelden/c09-website2.jpg differ diff --git a/03-schoolcommunicatie/beelden/c10-website3.jpg b/03-schoolcommunicatie/beelden/c10-website3.jpg new file mode 100644 index 0000000..799bb7f Binary files /dev/null and b/03-schoolcommunicatie/beelden/c10-website3.jpg differ diff --git a/03-schoolcommunicatie/beelden/c11-llm2.jpg b/03-schoolcommunicatie/beelden/c11-llm2.jpg new file mode 100644 index 0000000..07a7cdf Binary files /dev/null and b/03-schoolcommunicatie/beelden/c11-llm2.jpg differ diff --git a/03-schoolcommunicatie/beelden/c12-slash-popup.jpg b/03-schoolcommunicatie/beelden/c12-slash-popup.jpg new file mode 100644 index 0000000..8e8bf12 Binary files /dev/null and b/03-schoolcommunicatie/beelden/c12-slash-popup.jpg differ diff --git a/03-schoolcommunicatie/beelden/c13-ouderapp-klaar.jpg b/03-schoolcommunicatie/beelden/c13-ouderapp-klaar.jpg new file mode 100644 index 0000000..0c9a878 Binary files /dev/null and b/03-schoolcommunicatie/beelden/c13-ouderapp-klaar.jpg differ diff --git a/03-schoolcommunicatie/beelden/c14-next-step.jpg b/03-schoolcommunicatie/beelden/c14-next-step.jpg new file mode 100644 index 0000000..12f2de6 Binary files /dev/null and b/03-schoolcommunicatie/beelden/c14-next-step.jpg differ diff --git a/03-schoolcommunicatie/beelden/c15-social-klaar.jpg b/03-schoolcommunicatie/beelden/c15-social-klaar.jpg new file mode 100644 index 0000000..069bcea Binary files /dev/null and b/03-schoolcommunicatie/beelden/c15-social-klaar.jpg differ diff --git a/03-schoolcommunicatie/beelden/c16-output.jpg b/03-schoolcommunicatie/beelden/c16-output.jpg new file mode 100644 index 0000000..2cb61c5 Binary files /dev/null and b/03-schoolcommunicatie/beelden/c16-output.jpg differ diff --git a/03-schoolcommunicatie/beelden/c17-hele-flow.jpg b/03-schoolcommunicatie/beelden/c17-hele-flow.jpg new file mode 100644 index 0000000..be92c1f Binary files /dev/null and b/03-schoolcommunicatie/beelden/c17-hele-flow.jpg differ diff --git a/03-schoolcommunicatie/beelden/c18-testrun-input.jpg b/03-schoolcommunicatie/beelden/c18-testrun-input.jpg new file mode 100644 index 0000000..26bf94a Binary files /dev/null and b/03-schoolcommunicatie/beelden/c18-testrun-input.jpg differ diff --git a/03-schoolcommunicatie/beelden/c19-testrun-result.jpg b/03-schoolcommunicatie/beelden/c19-testrun-result.jpg new file mode 100644 index 0000000..7e8d797 Binary files /dev/null and b/03-schoolcommunicatie/beelden/c19-testrun-result.jpg differ diff --git a/03-schoolcommunicatie/beelden/c20-testrun-social.jpg b/03-schoolcommunicatie/beelden/c20-testrun-social.jpg new file mode 100644 index 0000000..a1ad7b9 Binary files /dev/null and b/03-schoolcommunicatie/beelden/c20-testrun-social.jpg differ diff --git a/03-schoolcommunicatie/beelden/c21-publish.jpg b/03-schoolcommunicatie/beelden/c21-publish.jpg new file mode 100644 index 0000000..1ea5dda Binary files /dev/null and b/03-schoolcommunicatie/beelden/c21-publish.jpg differ diff --git a/03-schoolcommunicatie/beelden/c22-toegangspunt.jpg b/03-schoolcommunicatie/beelden/c22-toegangspunt.jpg new file mode 100644 index 0000000..1280c6e Binary files /dev/null and b/03-schoolcommunicatie/beelden/c22-toegangspunt.jpg differ diff --git a/03-schoolcommunicatie/beelden/c23-webapp.jpg b/03-schoolcommunicatie/beelden/c23-webapp.jpg new file mode 100644 index 0000000..c3e19be Binary files /dev/null and b/03-schoolcommunicatie/beelden/c23-webapp.jpg differ diff --git a/03-schoolcommunicatie/beelden/d01-studio-vijf-apps.jpg b/03-schoolcommunicatie/beelden/d01-studio-vijf-apps.jpg new file mode 100644 index 0000000..d465f2c Binary files /dev/null and b/03-schoolcommunicatie/beelden/d01-studio-vijf-apps.jpg differ diff --git a/03-schoolcommunicatie/beelden/d02-duplicate-menu.jpg b/03-schoolcommunicatie/beelden/d02-duplicate-menu.jpg new file mode 100644 index 0000000..6dce7d8 Binary files /dev/null and b/03-schoolcommunicatie/beelden/d02-duplicate-menu.jpg differ diff --git a/03-schoolcommunicatie/beelden/d03-instructie-oud.jpg b/03-schoolcommunicatie/beelden/d03-instructie-oud.jpg new file mode 100644 index 0000000..e5d53f7 Binary files /dev/null and b/03-schoolcommunicatie/beelden/d03-instructie-oud.jpg differ diff --git a/03-schoolcommunicatie/beelden/d04-instructie-nieuw.jpg b/03-schoolcommunicatie/beelden/d04-instructie-nieuw.jpg new file mode 100644 index 0000000..102b6a9 Binary files /dev/null and b/03-schoolcommunicatie/beelden/d04-instructie-nieuw.jpg differ diff --git a/03-schoolcommunicatie/beelden/d05-balie-antwoord.jpg b/03-schoolcommunicatie/beelden/d05-balie-antwoord.jpg new file mode 100644 index 0000000..1bd9671 Binary files /dev/null and b/03-schoolcommunicatie/beelden/d05-balie-antwoord.jpg differ diff --git a/03-schoolcommunicatie/beelden/d06-publish-update.jpg b/03-schoolcommunicatie/beelden/d06-publish-update.jpg new file mode 100644 index 0000000..69744b6 Binary files /dev/null and b/03-schoolcommunicatie/beelden/d06-publish-update.jpg differ diff --git a/03-schoolcommunicatie/beelden/e01-knowledge-twee.jpg b/03-schoolcommunicatie/beelden/e01-knowledge-twee.jpg new file mode 100644 index 0000000..67d79d3 Binary files /dev/null and b/03-schoolcommunicatie/beelden/e01-knowledge-twee.jpg differ diff --git a/03-schoolcommunicatie/beelden/e02-delete-knowledge.jpg b/03-schoolcommunicatie/beelden/e02-delete-knowledge.jpg new file mode 100644 index 0000000..864df79 Binary files /dev/null and b/03-schoolcommunicatie/beelden/e02-delete-knowledge.jpg differ diff --git a/03-schoolcommunicatie/build.py b/03-schoolcommunicatie/build.py new file mode 100644 index 0000000..38d3e7e --- /dev/null +++ b/03-schoolcommunicatie/build.py @@ -0,0 +1,4 @@ +import runpy, sys +from pathlib import Path +sys.argv = ["build_handleiding.py", str(Path(__file__).resolve().parent / "handleiding-dify-schoolcommunicatie.md")] +runpy.run_path(str(Path(__file__).resolve().parent.parent / "_gereedschap" / "build_handleiding.py"), run_name="__main__") diff --git a/03-schoolcommunicatie/handleiding-dify-schoolcommunicatie.md b/03-schoolcommunicatie/handleiding-dify-schoolcommunicatie.md new file mode 100644 index 0000000..347b347 --- /dev/null +++ b/03-schoolcommunicatie/handleiding-dify-schoolcommunicatie.md @@ -0,0 +1,544 @@ + + +# Dify voor schoolcommunicatie: drie apps voor Het Voorbeeldcollege + +**Handleiding 3 bij de workshop AI Agents** +LeX Consultancy B.V. · 20 september 2026 + +In handleiding 1 bouwde je een workflow, in handleiding 2 een agent met een kennisbank. Nu zet je die twee vormen in voor een echt team: de mensen die op een school schrijven aan ouders, voor de website en voor de ouderapp. Je bouwt drie apps voor het fictieve Voorbeeldcollege: + +| App | Vorm | Wat hij doet | +| --- | --- | --- | +| **Ouderbrief-assistent** | Agent (chat) | Herschrijft een conceptbrief volgens de schrijfwijzer en zegt wat hij veranderde | +| **Schoolnieuws** | Workflow (formulier) | Maakt van één kernboodschap een bericht voor website, ouderapp en sociale media | +| **Balie-stand** | Uitbreiding van de Schoolgids-assistent uit handleiding 2 | Schrijft voor een baliemedewerker het antwoord aan een ouder, uit de schoolgids en in de huisstijl | + +De rode draad is een **schrijfwijzer**: twee pagina's met de afspraken van de school over taalniveau, aanspreekvorm, te vermijden woorden en de lengte per kanaal. Die zet je in de kennisbank naast de schoolgids. Daarna houden alle drie de apps zich eraan, zonder dat je de regels in elke prompt hoeft te herhalen. Verander je de schrijfwijzer, dan veranderen de apps mee. + +Deze handleiding volgt de cloudversie van Dify zoals die er op 20 september 2026 uitziet. Dify verandert snel: wijkt je scherm af, volg dan wat je ziet en niet wat hier staat. + +**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 | + +> Over credits en de app-limiet: een sandbox-account mag **vijf apps** in Studio hebben. Met de apps uit handleiding 1 en 2 erbij zit je na deze handleiding precies aan die grens. Daarom bouwen we de derde app niet nieuw, maar breiden we de Schoolgids-assistent uit. Wil je toch een losse app, verwijder dan eerst een oude (Studio, menu **...** op de kaart, **Delete**). Op een betaald account (Professional: 50 apps) speelt dit niet en kun je in deel D gewoon **Duplicate** gebruiken. + +--- + +## Voorbereiding + +- Je hebt handleiding 2 gedaan: de kennisbank **Schoolgids Voorbeeldcollege** en de app **Schoolgids-assistent** staan op je account. +- Je hebt `schrijfwijzer-voorbeeldcollege.pdf` klaarstaan (zit bij deze handleiding). +- Je model staat op **gpt-5-mini**. Het standaardmodel gpt-5 is vijf keer zo duur. + +> **Zelf kiezen: je eigen schrijfwijzer.** Heeft jouw school of bestuur een huisstijlgids, communicatiewijzer of "zo schrijven wij"-document? Gebruik dat in plaats van het onze. Voorwaarden: echte tekst (geen scan), geen persoonsgegevens, en liefst kort. Twee tot vijf pagina's met concrete regels werken beter dan dertig pagina's visie. Heb je niets, schrijf dan tien regels op die je zelf belangrijk vindt, bijvoorbeeld "wij zeggen u tegen ouders" en "geen afkortingen". Dat is genoeg om mee te beginnen. + +--- + +## Deel A. De schrijfwijzer in de kennisbank + +De schoolgids zit al in de kennisbank. Je voegt de schrijfwijzer toe als tweede document, zodat één kennisbank alles bevat wat de apps over de school moeten weten. + +### Stap 1. Voeg het bestand toe + +1. Klik in het linkermenu op **Knowledge** en open **Schoolgids Voorbeeldcollege**. +2. Klik bij **Documents** op **Add file**. +3. Klik op **Browse** en kies `schrijfwijzer-voorbeeldcollege.pdf`, of sleep het bestand in het vak. + +![Add file: één bestand per keer in de sandbox](beelden/a01-add-file.jpg) + +4. Klik op **Next**. + +> In de sandbox kun je maar één bestand per keer uploaden ("Maximaal 1 bestanden"). Meerdere documenten voeg je dus na elkaar toe. Dat is geen fout van jou. + +### Stap 2. Controleer de knipinstelling + +Dify onthoudt de instelling van het eerste document niet per se. Controleer daarom opnieuw hoe er geknipt wordt. + +![De standaardinstelling: Delimiter \n](beelden/a02-chunk.jpg) + +1. Zet in het veld **Delimiter** de waarde op `\n\n` (twee keer backslash-n, zonder spaties). + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| Delimiter | `\n\n` | +| Maximum chunk length | `1024` (laten staan) | +| Chunk overlap | `50` (laten staan) | + +2. Klik op **Preview Chunk**. Rechts zie je nu een handvol stukken van een alinea of langer: de inleiding, de regels over taal, de kanalen, de privacyregels. + +![Na de aanpassing: vier stukken met echte inhoud](beelden/a03-chunk-delimiter.jpg) + +3. Klik op **Save & Process**. + +### Stap 3. Wacht op het groene vinkje + +![Document uploaded, embedding completed](beelden/a04-klaar.jpg) + +Bij twee pagina's duurt dit een paar seconden. Klik daarna op **Go to document**: de kennisbank heeft nu twee documenten. + +### Stap 4. Werk de beschrijving bij + +De agent leest de beschrijving van de kennisbank om te beslissen of hij erin gaat zoeken. Nu er ook schrijfregels in staan, moet de beschrijving dat zeggen. + +1. Klik in het linkermenu op **Settings**. +2. Vervang de tekst bij **Description**. + +``` +Twee documenten van Het Voorbeeldcollege. De schoolgids: lestijden, ziek melden, verzuim en verlof, huiswerk en toetsen, telefoons en laptops, mentoraat en contactgegevens. De schrijfwijzer: hoe de school schrijft aan ouders en op website, ouderapp en sociale media (taalniveau B1, u of je, te vermijden woorden, opbouw van een ouderbrief, lengte per kanaal, namen en foto's van leerlingen). Gebruik deze kennisbank bij vragen over schoolregels en bij het schrijven of nakijken van teksten voor ouders. +``` + +![De bijgewerkte beschrijving](beelden/a05-settings.jpg) + +3. Scroll naar beneden en klik op **Save**. + +> **Zelf kiezen: de beschrijving.** Schrijf de beschrijving alsof je aan een nieuwe collega uitlegt wanneer die dit mapje moet openen. Noem de onderwerpen, niet de bestandsnamen. Test daarna met **Retrieval Testing** (linkermenu) of een vraag als "mag ik je zeggen tegen een ouder?" het juiste stuk bovenaan zet. + +--- + +## Deel B. De Ouderbrief-assistent (agent) + +Een docent plakt een conceptbrief, de assistent maakt er een brief van die ouders in één keer begrijpen, en legt uit wat hij veranderde en waarom. Dat laatste is bewust: zo leert het team de schrijfwijzer kennen in plaats van hem uit te besteden. + +### Stap 5. Maak de agent aan + +1. Ga naar **Studio** en klik op **Create** → **Create from Blank**. +2. Kies bij **Choose an App Type** de kaart **Agent**. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| App Name & Icon | `Ouderbrief-assistent` | +| Description | mag leeg | + +![Create from Blank met de kaart Agent gekozen](beelden/b01-create-agent.jpg) + +3. Klik op **Create**. + +![De lege agent: instructie, variabelen, kennisbank en tools](beelden/b02-lege-agent.jpg) + +4. Klik rechtsboven op de modelnaam (**gpt-5**) en kies **gpt-5-mini**. + +### Stap 6. Schrijf de instructie + +1. Klik in het vak **INSTRUCTIONS** en plak de tekst hieronder. + +``` +Je bent de ouderbrief-assistent van Het Voorbeeldcollege. Docenten, mentoren en teamleiders plakken een conceptbrief of een paar losse zinnen, en jij maakt er een brief van die ouders in één keer begrijpen. + +Werkwijze: +1. Raadpleeg altijd eerst de schrijfwijzer in je kennisbank. Pas de regels toe over taalniveau B1, u en je, te vermijden woorden, de opbouw van een ouderbrief en de lengte. +2. Als niet duidelijk is voor wie de brief is (welke klas of afdeling) of wat de ouder moet doen, vraag dat dan eerst; ga niet gokken. +3. Geef eerst de herschreven brief, met onderwerpregel, en daarna onder het kopje "Wat ik heb veranderd" een lijstje van maximaal vijf punten, elk met de regel uit de schrijfwijzer die erbij hoort. +4. Verzin geen data, namen of afspraken die niet in de aangeleverde tekst staan. Ontbreekt iets wat een ouder moet weten, zet dan [INVULLEN] op die plek. +5. Wees kort. Geen inleiding, geen compliment, geen afsluiting van jouw kant. +``` + +![De instructie staat erin](beelden/b03-instructie.jpg) + +> **Zelf kiezen: de werkwijze.** Punt 3 bepaalt de vorm van het antwoord. Wil je liever twee varianten (kort en uitgebreid)? Een versie in het Engels erbij voor anderstalige ouders? Alleen de brief zonder uitleg? Verander alleen dat punt en test opnieuw. Punt 4 (niets verzinnen, [INVULLEN]) raden we aan om te laten staan; dat is de regel die je uit de problemen houdt. + +### Stap 7. Koppel de kennisbank + +1. Klik bij **Knowledge** op **+ Add**. +2. Vink **Schoolgids Voorbeeldcollege** aan en klik op **Add**. + +![Select reference Knowledge](beelden/b04-select-knowledge.jpg) + +![De kennisbank hangt aan de agent](beelden/b05-gekoppeld.jpg) + +### Stap 8. Test met een wollige brief + +1. Plak in **Debug & Preview** onderaan (**Talk to Bot**) de tekst hieronder en druk op Enter. + +``` +Voor de ouders van klas 2B: + +Geachte ouder(s)/verzorger(s), + +Middels dit schrijven willen wij u informeren omtrent de ouderavond die in het kader van de studiekeuze zal plaatsvinden op donderdag 8 oktober a.s. om 19.30 uur in de aula. Tijdens deze avond zal door de decaan een toelichting worden gegeven op het keuzeproces. U wordt verzocht uw aanwezigheid z.s.m. door te geven d.m.v. het ouderportaal. Met vriendelijke groet, de directie +``` + +![Het antwoord: de herschreven brief met onderwerpregel](beelden/b07-antwoord2.jpg) + +![Daaronder: "Wat ik heb veranderd", met per punt de regel uit de schrijfwijzer](beelden/b06-antwoord.jpg) + +Let op drie dingen in het antwoord: + +- Boven het antwoord staat **Used Knowledge**: de agent heeft de schrijfwijzer echt gelezen. +- "Middels dit schrijven", "omtrent", "z.s.m." en "d.m.v." zijn weg; de brief spreekt ouders aan met u en zegt in de eerste zin waar het over gaat. +- Waar de conceptbrief iets niet zegt (een uiterste datum, een naam om te bellen), staat **[INVULLEN]**. De assistent verzint het niet. + +> Krijg je een antwoord zonder Used Knowledge, of negeert de assistent de schrijfwijzer? Controleer dan stap 4: een beschrijving die alleen over schoolregels gaat, zorgt dat de agent bij een schrijfvraag niet gaat zoeken. + +### Stap 9. Publiceer + +Een agent-app is bij het aanmaken al gepubliceerd, maar leeg. Zonder deze stap krijgt de webapp je instructie en kennisbank niet. + +1. Klik rechtsboven op **Publish** en dan op **Publish Update**. + +![Publish Update](beelden/b08-publish.jpg) + +![Success: de webapp draait nu de nieuwe versie](beelden/b09-publish2.jpg) + +2. Klik in hetzelfde menu op **Webapp openen** om de link te zien die je met het team deelt. Onze versie: https://udify.app/chat/OJCfxjBeBHCEbBPx + +--- + +## Deel C. Schoolnieuws (workflow) + +Eén bericht komt bijna nooit op één plek. De website wil 200 woorden met een kop, de ouderapp 80 woorden op een telefoonscherm, sociale media 60 woorden met een hashtag. In plaats van drie keer schrijven, vul je één formulier in. De workflow schrijft de drie versies, elk volgens de regels voor dat kanaal uit de schrijfwijzer. + +Zo ziet het geheel er straks uit: + +![De hele workflow: User Input, Knowledge Retrieval, drie LLM-stappen en Output](beelden/c17-hele-flow.jpg) + +### Stap 10. Maak de workflow + +1. **Studio** → **Create** → **Create from Blank** → kaart **Workflow**. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| App Name & Icon | `Schoolnieuws` | + +![Create from Blank: Workflow](beelden/c01-create-workflow.jpg) + +2. Klik op **Create**. Je ziet het canvas met alleen een **User Input**-blok. + +### Stap 11. Drie invoervelden + +Klik op het blok **User Input**, dan rechts bij **INPUT FIELD** op **+**. Je maakt drie velden. Kies in het venster **Add Input Field** telkens eerst het **Field Type** en vul dan de rest in. + +**Veld 1: de kernboodschap** + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| Field Type | **Paragraph** | +| Variable Name | `kernboodschap` | +| Label Name | `Wat is er gebeurd of gaat er gebeuren? (wie, wat, waar, wanneer)` | +| Required | aan | + +![Add Input Field: Paragraph, kernboodschap](beelden/c02-veld-kernboodschap.jpg) + +**Veld 2: de doelgroep** + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| Field Type | **Short Text** | +| Variable Name | `afdeling` | +| Label Name | `Voor welke klas of afdeling? (of: hele school)` | +| Required | aan | + +**Veld 3: de toon** + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| Field Type | **Select** | +| Variable Name | `toon` | +| Label Name | `Welke toon past bij dit bericht?` | +| Options | `informatief`, `feestelijk`, `dringend` (elk via **+ Add option**) | +| Required | aan | + +![Add Input Field: Select met drie opties](beelden/c03-veld-toon.jpg) + +![De drie velden staan in User Input](beelden/c04-drie-velden.jpg) + +> Kies het **Field Type** vóór je begint te typen. Verander je het type achteraf, dan sluit het venster soms en ben je je invoer kwijt. + +> **Zelf kiezen: de velden.** Welke drie vragen stelt jullie communicatiemedewerker altijd aan een collega die "even iets op de site wil"? Dat zijn je velden. Andere keuzes die we bij scholen zien: een veld *kanaal* (alleen website, alleen app) zodat niet altijd alles wordt gemaakt; een veld *afzender* (rector, mentor, sectie); een veld *deadline* dat letterlijk in het bericht terugkomt. + +### Stap 12. Knowledge Retrieval: haal de schrijfwijzer op + +1. Klik op het **+** rechts van User Input en kies **Knowledge Retrieval**. +2. Klik bij **QUERY TEXT** op het veld en kies **User Input / kernboodschap**. + +![Knowledge Retrieval, nog zonder kennisbank](beelden/c05-kr1.jpg) + +3. Klik bij **KNOWLEDGE** op **+**, vink **Schoolgids Voorbeeldcollege** aan en klik op **Add**. + +![Select reference Knowledge](beelden/c06-kr2.jpg) + +![De kennisbank is gekoppeld, de zoekvraag is de kernboodschap](beelden/c07-kr3.jpg) + +> De zoekvraag is hier de kernboodschap, niet "schrijfwijzer". Dat werkt omdat de kennisbank klein is: de schrijfwijzer komt vrijwel altijd mee. Bij een grote kennisbank zet je in de LLM-prompt liever een vaste zoekopdracht, of geef je de schrijfwijzer een eigen kennisbank. + +### Stap 13. Drie LLM-stappen: Website, Ouderapp, Social + +Je maakt drie keer een **LLM**-blok, achter elkaar. Elk blok krijgt hetzelfde model en dezelfde context, maar een eigen prompt. De eerste regel van elke prompt laat het model zijn antwoord beginnen met WEBSITE, OUDERAPP of SOCIAL; zo blijven de drie teksten in de uitvoer uit elkaar. + +**Blok 1: Website** + +1. Klik op **+** achter Knowledge Retrieval en kies **LLM**. +2. Zet **MODEL** op **gpt-5-mini**. Negeer de melding over de parameter *temperature*. +3. Klik bij **CONTEXT** op **Set variable** en kies **Knowledge Retrieval / result**. + +![Het LLM-blok met model en context, prompt nog leeg](beelden/c08-website1.jpg) + +4. Klik in het vak **SYSTEM** en typ de prompt hieronder. Waar `{...}` staat, typ je een schuine streep **/** en kies je het item uit het menu dat verschijnt: **Context** onderaan het menu, de drie velden onder **User Input**. + +``` +Begin je antwoord met de regel WEBSITE en daarna een lege regel. + +Je schrijft voor Het Voorbeeldcollege, een school voor voortgezet onderwijs. Schrijf een nieuwsbericht voor de website van maximaal 200 woorden. De kop is een actieve zin van maximaal acht woorden, zonder uitroepteken. De eerste alinea beantwoordt wie, wat, waar en wanneer. Sluit af met een vervolgstap of contactmogelijkheid. Houd je strikt aan de schrijfwijzer hieronder: taalniveau B1, u voor ouders, te vermijden woorden, namen en foto's van leerlingen. Pas de toon aan die is gekozen. Verzin geen feiten. Ontbreekt iets, schrijf dan [INVULLEN]. + +Schrijfwijzer: {Context} + +Afdeling: {afdeling} +Toon: {toon} +Kernboodschap: {kernboodschap} +``` + +![Het menu na een schuine streep: variabelen en, onderaan, Context](beelden/c09-website2.jpg) + +5. Klik op de naam **LLM** bovenin het paneel en hernoem het blok naar `Website`. + +![Het blok Website is klaar](beelden/c10-website3.jpg) + +> De context (het zoekresultaat) werkt alleen als je hem ook echt in de prompt zet via **/ → Context**. Alleen het veld CONTEXT vullen is niet genoeg; Dify waarschuwt daar in oranje voor. + +**Blok 2: Ouderapp** + +6. Klik op **+** achter Website, kies **LLM**, model **gpt-5-mini**, context **Knowledge Retrieval / result**. + +![Het tweede LLM-blok, nog leeg](beelden/c11-llm2.jpg) + +7. Prompt: + +``` +Begin je antwoord met de regel OUDERAPP en daarna een lege regel. + +Je schrijft voor Het Voorbeeldcollege, een school voor voortgezet onderwijs. Schrijf een bericht voor de ouderapp van maximaal 80 woorden: ouders lezen dit op hun telefoon. Eén boodschap, één datum, één actie; geen inleiding en geen kop. Spreek ouders aan met u. Houd je strikt aan de schrijfwijzer hieronder. Pas de toon aan die is gekozen. Verzin geen feiten. Ontbreekt iets, schrijf dan [INVULLEN]. + +Schrijfwijzer: {Context} + +Afdeling: {afdeling} +Toon: {toon} +Kernboodschap: {kernboodschap} +``` + +![Na de schuine streep: kies Context onderaan het menu](beelden/c12-slash-popup.jpg) + +8. Hernoem het blok naar `Ouderapp`. + +![Het blok Ouderapp is klaar](beelden/c13-ouderapp-klaar.jpg) + +**Blok 3: Social** + +9. Scroll in het paneel van Ouderapp naar beneden en klik bij **NEXT STEP** op **Select next step** → **LLM**. (Dit is hetzelfde als het **+** op het canvas; handig als het paneel het plusje verbergt.) + +![Select next step: de lijst met blokken](beelden/c14-next-step.jpg) + +10. Model **gpt-5-mini**, context **Knowledge Retrieval / result**, prompt: + +``` +Begin je antwoord met de regel SOCIAL en daarna een lege regel. + +Je schrijft voor Het Voorbeeldcollege, een school voor voortgezet onderwijs. Schrijf een bericht voor de sociale media van de school (Instagram en LinkedIn) van maximaal 60 woorden. Warm en concreet, geen jubeltaal. Sluit af met maximaal drie hashtags, waarvan altijd #Voorbeeldcollege. Geen namen van leerlingen en geen verwijzing naar herkenbare foto's van leerlingen. Houd je aan de schrijfwijzer hieronder. Pas de toon aan die is gekozen. Verzin geen feiten. Ontbreekt iets, schrijf dan [INVULLEN]. + +Schrijfwijzer: {Context} + +Afdeling: {afdeling} +Toon: {toon} +Kernboodschap: {kernboodschap} +``` + +11. Hernoem het blok naar `Social`. + +![Het blok Social is klaar](beelden/c15-social-klaar.jpg) + +> **Zelf kiezen: de kanalen en hun regels.** De drie prompts verschillen alleen in de eerste alinea: dat is de plek voor jullie kanaalregels. Heeft jullie school geen Instagram maar een nieuwsbrief? Vervang blok 3 door "Nieuwsbrief, maximaal 120 woorden, met een kop van vijf woorden". Wil je een vierde kanaal (bijvoorbeeld het personeelsbulletin, met je in plaats van u)? Voeg een vierde blok toe en een vierde uitvoervariabele in stap 14. De woordlimieten staan ook in de schrijfwijzer; laat prompt en schrijfwijzer hetzelfde zeggen, anders wint de prompt. + +### Stap 14. Output: drie uitvoervariabelen + +1. Achter Social: **Select next step** → **Output**. +2. Klik bij **OUTPUT VARIABLE** drie keer op **+** en vul in: + +| Variable name | Set variable | +| --- | --- | +| `website` | **Website / text** | +| `ouderapp` | **Ouderapp / text** | +| `social` | **Social / text** | + +![Output met drie variabelen](beelden/c16-output.jpg) + +### Stap 15. Test Run + +1. Klik rechtsboven op **Test Run** en vul het formulier 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** | + +![Het Test Run-formulier](beelden/c18-testrun-input.jpg) + +2. Klik op **Start Run**. De blokken kleuren één voor één groen; rechts verschijnt het resultaat onder **RESULT**. + +![Website en Ouderapp zijn klaar, Social loopt nog](beelden/c19-testrun-result.jpg) + +![Alle drie de teksten, met de labels WEBSITE, OUDERAPP en SOCIAL](beelden/c20-testrun-social.jpg) + +Controleer: het websitebericht heeft een kop en sluit af met contact, het ouderappbericht is één alinea zonder kop, het socialbericht eindigt op #Voorbeeldcollege. Het contactnummer komt uit de schoolgids, niet uit de lucht. + +### Stap 16. Publiceer en deel + +1. Klik op **Publish** → **Publish**. + +![Publish](beelden/c21-publish.jpg) + +2. Klik in het linkermenu op **Toegangspunt**. Onder **Webapp** staat de link; met **Openen** bekijk je hem zoals een collega hem ziet. + +![Toegangspunt met de webapp-link](beelden/c22-toegangspunt.jpg) + +![De webapp: formulier links, drie teksten rechts](beelden/c23-webapp.jpg) + +Onze versie: https://udify.app/workflow/jJclFyX9BlteuHYi + +--- + +## Deel D. De Balie-stand: één app, twee gebruikers + +De derde wens van het team was een vraagbaak voor de receptie: een ouder mailt of belt, de baliemedewerker wil snel een correct antwoord in de huisstijl. Je zou daarvoor de Schoolgids-assistent kunnen kopiëren (**Studio**, menu **...** op de kaart, **Duplicate**) en de kopie een andere instructie geven. + +![Het menu op een app-kaart: Edit Info, Duplicate, Export DSL, Delete](beelden/d02-duplicate-menu.jpg) + +Maar met vijf apps zit een sandbox-account vol: + +![Studio met vijf apps: de grens van de sandbox](beelden/d01-studio-vijf-apps.jpg) + +Daarom doen we het anders, en eigenlijk beter: de Schoolgids-assistent heeft de schrijfwijzer al in zijn kennisbank (dat gebeurde in deel A, zonder dat je de app aanraakte). Je hoeft hem alleen te vertellen wanneer hij als balie moet werken. + +### Stap 17. Breid de instructie uit + +1. Open in **Studio** de app **Schoolgids-assistent**. + +![De instructie uit handleiding 2](beelden/d03-instructie-oud.jpg) + +2. Klik onderaan de instructie en plak deze alinea eronder: + +``` +Balie-stand: als een medewerker begint met "Balie:" en daarna een vraag van een ouder plakt, dan schrijf je het antwoord dat de medewerker naar die ouder kan sturen. Volg dan de schrijfwijzer in je kennisbank: spreek de ouder aan met u, taalniveau B1, geen afkortingen, geen woorden uit de lijst te vermijden woorden, maximaal zes zinnen, en sluit af met een contactmogelijkheid. Weet je het antwoord niet uit de schoolgids, schrijf dan een kort bericht waarin je zegt dat je het navraagt en zet [INVULLEN] waar de medewerker het echte antwoord moet aanvullen. +``` + +![De uitgebreide instructie](beelden/d04-instructie-nieuw.jpg) + +### Stap 18. Test als balie + +1. Plak in **Debug & Preview**: + +``` +Balie: Hallo, mijn dochter zit in 1C en is morgen ziek. Moet ik haar afmelden en hoe doe ik dat? Krijgt ze dan de toets van morgen op een ander moment? Groet, moeder van Sanne +``` + +![Het antwoord voor de balie: u-vorm, uit de schoolgids, met hoofdstukverwijzing](beelden/d05-balie-antwoord.jpg) + +Het antwoord haalt ziekmelding en inhaalmoment uit twee hoofdstukken van de schoolgids, spreekt de ouder aan met u, en sluit af met de receptie. Stel dezelfde vraag nog eens zonder "Balie:" ervoor: dan krijg je het kortere antwoord voor leerling of ouder uit handleiding 2. Eén app, twee gebruikers. + +### Stap 19. Publish Update + +1. **Publish** → **Publish Update**. Zonder deze stap kent de webapp de Balie-stand niet. + +![Publish Update in het Publish-menu](beelden/d06-publish-update.jpg) + +> **Zelf kiezen: het schakelwoord.** "Balie:" is een afspraak, geen techniek. Kies een woord dat jullie team logisch vindt ("Receptie:", "Antwoord voor ouder:") en spreek af dat iedereen het zo gebruikt. Wil je liever geen schakelwoord? Maak dan toch een aparte app via Duplicate, zodra er ruimte is, en geef die alleen de balie-instructie. + +--- + +## Controleren of het gelukt is + +- In **Knowledge** heeft Schoolgids Voorbeeldcollege twee documenten, allebei **Available** +- De Ouderbrief-assistent toont **Used Knowledge** boven zijn antwoord en zet [INVULLEN] waar informatie ontbreekt +- Schoolnieuws levert drie teksten met de labels WEBSITE, OUDERAPP en SOCIAL, elk binnen de woordlimiet +- De Schoolgids-assistent antwoordt anders met en zonder "Balie:" ervoor +- Alle drie de webapp-links werken in een privévenster (dus zonder dat je bent ingelogd bij Dify) + +## Als het misgaat + +| Wat je ziet | Wat er aan de hand is | +| --- | --- | +| "Maximaal 1 bestanden" bij het uploaden | Sandbox-limiet. Eén bestand per keer, daarna opnieuw **Add file** | +| Preview Chunk toont tientallen stukken van één regel | Delimiter staat op `\n`. Zet hem op `\n\n` (stap 2) | +| De Ouderbrief-assistent negeert de schrijfwijzer | Beschrijving van de kennisbank noemt geen schrijfregels (stap 4), of de kennisbank is niet gekoppeld (stap 7) | +| De drie teksten in Schoolnieuws lopen in elkaar over | De eerste regel van een prompt ("Begin je antwoord met de regel ...") ontbreekt | +| Oranje melding "To enable the context feature, please fill in the context variable in PROMPT" | Je hebt CONTEXT ingesteld maar **/ → Context** niet in de prompt gezet | +| Een tekst gebruikt je in plaats van u, of is te lang | Prompt en schrijfwijzer spreken elkaar tegen. Zet ze gelijk; de prompt wint | +| "Upgrade to create more apps" | Vijf apps is het maximum. Verwijder een oude app of breid een bestaande uit (deel D) | +| De webapp doet iets anders dan Debug & Preview | **Publish Update** vergeten (agent) of **Publish** vergeten (workflow) | +| Een blok verdwijnt na een toetsaanslag op het canvas | Delete of Backspace verwijdert het geselecteerde blok. Klik op de pijl **Undo** linksonder | +| Credits lopen hard terug | Een LLM-blok staat nog op gpt-5. Elk blok apart op gpt-5-mini zetten | + +## Beheer en kosten + +- **Eigenaar.** Spreek af wie de schrijfwijzer in de kennisbank bijhoudt. Een nieuwe versie uploaden is stap 1 tot 3 opnieuw; het oude document verwijder je bij **Documents**. +- **Logs.** Elke app heeft in het linkermenu **Logs**: daar zie je wat collega's invoeren en wat eruit kwam. Gebruik dat om de prompts bij te stellen, niet om collega's te controleren, en zeg dat er ook bij. +- **Persoonsgegevens.** Een ouderbrief bevat al snel een naam of een situatie. Spreek af dat collega's die weghalen vóór het plakken, of gebruik placeholders zoals [NAAM]. Dify verwerkt in de cloud buiten de school. +- **Kosten.** Met een eigen OpenAI-sleutel (Integraties → Model Provider) kost een ouderbrief ongeveer een halve cent en een Schoolnieuws-run ongeveer een cent. Op Dify-credits kost een agent-antwoord 6 à 7 credits en een workflow-run met drie LLM-blokken ongeveer 10. + +--- + +## Maak hem van jou + +Alles hierboven is een voorbeeld. De school is verzonnen, de schrijfwijzer is verzonnen, de prompts zijn onze keuzes. Dit hoofdstuk helpt je de apps om te bouwen naar jouw school, jouw team en jouw stijl. Werk van boven naar beneden: de eerste aanpassingen kosten vijf minuten, de laatste een dagdeel. + +| Aanpassing | Waar | Moeilijkheid | Wat je ervoor terugkrijgt | +| --- | --- | --- | --- | +| Schoolnaam, contactgegevens, aanspreekvorm | Schrijfwijzer (document) en de eerste regel van elke prompt | makkelijk | De teksten kloppen meteen voor jouw school | +| Te vermijden woorden en vaste formuleringen | Schrijfwijzer | makkelijk | Jullie huisstijl in plaats van de onze | +| Toonopties (informatief, feestelijk, dringend) | Schoolnieuws, veld *toon* | makkelijk | Opties die jullie team herkent, bijvoorbeeld "zakelijk" of "persoonlijk" | +| Vorm van het antwoord (uitleg wel of niet, twee varianten, Engels erbij) | Ouderbrief-assistent, punt 3 van de instructie | gemiddeld | Een assistent die past bij hoe jullie corrigeren | +| Kanalen (nieuwsbrief, personeelsbulletin, Engelstalige site) | Schoolnieuws, LLM-blokken en Output | gemiddeld | Precies de kanalen die jullie gebruiken | +| Een tweede document (bijvoorbeeld de jaarplanning of het verzuimprotocol) | Kennisbank, deel A opnieuw | gemiddeld | De Balie-stand beantwoordt meer vragen goed | +| Een eigen schakelwoord of aparte balie-app | Schoolgids-assistent of Duplicate | gemiddeld | Een werkwijze die jullie receptie logisch vindt | +| Automatisch versturen (mail, ouderapp) | Tools of HTTP Request in de workflow | moeilijk | Een bericht dat niet alleen geschreven maar ook geplaatst wordt; pas na afspraken over controle | + +**Drie opdrachten** + +1. **Vervang de schrijfwijzer.** Maak een document van maximaal twee pagina's met de schrijfregels van jouw school (of tien regels die jij belangrijk vindt). Upload het naast of in plaats van het onze (deel A). Laat de Ouderbrief-assistent dezelfde wollige brief herschrijven en vergelijk: welke regel uit jouw document zie je terug, welke niet? Pas de beschrijving van de kennisbank aan tot het klopt. +2. **Voeg een kanaal toe.** Kies een kanaal dat jullie echt gebruiken en wij niet hebben. Schrijf de kanaalregel in drie zinnen (lengte, aanspreekvorm, wat er altijd in moet), maak een vierde LLM-blok en een vierde uitvoervariabele. Test met een bericht van vorige week. +3. **Laat een collega hem slopen.** Geef de webapp-link aan iemand die niet in de workshop zat en vraag om drie echte berichten. Lees de **Logs**: waar ging het mis? Meestal is het antwoord één zin extra in een prompt, of één regel extra in de schrijfwijzer. Pas dat aan, publiceer opnieuw, en laat het nog een keer proberen. + +**Checklist voordat je eigen materiaal gebruikt** + +- [ ] Er staan geen namen van leerlingen, ouders of medewerkers in het document dat je uploadt, en ook geen mailadressen van personen (een algemeen adres zoals info@ mag) +- [ ] Het document is van de school en mag gedeeld worden met een externe verwerker (Dify draait in de cloud) +- [ ] Er is één eigenaar die het document bijhoudt en de app opnieuw publiceert +- [ ] Je hebt besloten of de webapp-link alleen intern rondgaat of ook naar ouders; in het tweede geval eerst de privacyfunctionaris erbij +- [ ] Het model staat op gpt-5-mini en je weet wat een run kost +- [ ] Iemand leest de uitvoer voordat die naar buiten gaat; de app schrijft een concept, geen besluit + +--- + +## En verder + +Je hebt nu een team-toolkit die meebeweegt met één document. Handleiding 7 bouwt op Schoolnieuws verder met een controleur en een poortwachter, zodat een bericht met gaten nooit ongezien naar buiten gaat. Daarna is de volgende stap dat een agent zelf op zoek gaat: bestanden lezen, op het web zoeken en meerdere producten opleveren. Dat is de Agent Console, handleiding 4 (de Toetsweekplanner) en handleiding 6 (lesmateriaal beoordelen en aanpassen voor leerlingen met ondersteuning). diff --git a/03-schoolcommunicatie/schrijfwijzer-voorbeeldcollege.pdf b/03-schoolcommunicatie/schrijfwijzer-voorbeeldcollege.pdf new file mode 100644 index 0000000..e49e7e5 Binary files /dev/null and b/03-schoolcommunicatie/schrijfwijzer-voorbeeldcollege.pdf differ diff --git a/04-agent-console/toetsrooster-voorbeeld.csv b/04-agent-console/toetsrooster-voorbeeld.csv new file mode 100644 index 0000000..c7d7dce --- /dev/null +++ b/04-agent-console/toetsrooster-voorbeeld.csv @@ -0,0 +1,7 @@ +dag,datum,vak,tijd,duur_minuten,toetsstof +maandag,2026-10-12,Nederlands,09:00,60,Leesvaardigheid hoofdstuk 3 en 4; spelling werkwoorden (d/t) +maandag,2026-10-12,wiskunde,10:45,45,Hoofdstuk 2 (vergelijkingen) en 3 (procenten) +dinsdag,2026-10-13,Engels,09:00,45,Unit 3 en 4: woordenlijst, present simple en present continuous +woensdag,2026-10-14,geschiedenis,09:00,45,Hoofdstuk 5: de Republiek in de Gouden Eeuw (paragraaf 1 t/m 4) +donderdag,2026-10-15,biologie,10:45,45,Thema 2: cellen en organen (basisstof 1 t/m 5) +vrijdag,2026-10-16,Frans,09:00,45,Chapitre 2: vocabulaire, être en avoir, getallen tot 100 diff --git a/05-transcriptietool/beelden/a01-create-workflow.jpg b/05-transcriptietool/beelden/a01-create-workflow.jpg new file mode 100644 index 0000000..f92925f Binary files /dev/null and b/05-transcriptietool/beelden/a01-create-workflow.jpg differ diff --git a/05-transcriptietool/beelden/a02-add-input-field.jpg b/05-transcriptietool/beelden/a02-add-input-field.jpg new file mode 100644 index 0000000..abf822f Binary files /dev/null and b/05-transcriptietool/beelden/a02-add-input-field.jpg differ diff --git a/05-transcriptietool/beelden/a03-field-types.jpg b/05-transcriptietool/beelden/a03-field-types.jpg new file mode 100644 index 0000000..56a5d4c Binary files /dev/null and b/05-transcriptietool/beelden/a03-field-types.jpg differ diff --git a/05-transcriptietool/beelden/a04-single-file.jpg b/05-transcriptietool/beelden/a04-single-file.jpg new file mode 100644 index 0000000..de985e8 Binary files /dev/null and b/05-transcriptietool/beelden/a04-single-file.jpg differ diff --git a/05-transcriptietool/beelden/a05-veld-opname.jpg b/05-transcriptietool/beelden/a05-veld-opname.jpg new file mode 100644 index 0000000..48bef1d Binary files /dev/null and b/05-transcriptietool/beelden/a05-veld-opname.jpg differ diff --git a/05-transcriptietool/beelden/a06-userinput-klaar.jpg b/05-transcriptietool/beelden/a06-userinput-klaar.jpg new file mode 100644 index 0000000..2633fda Binary files /dev/null and b/05-transcriptietool/beelden/a06-userinput-klaar.jpg differ diff --git a/05-transcriptietool/beelden/a07-tools-tab.jpg b/05-transcriptietool/beelden/a07-tools-tab.jpg new file mode 100644 index 0000000..06ae264 Binary files /dev/null and b/05-transcriptietool/beelden/a07-tools-tab.jpg differ diff --git a/05-transcriptietool/beelden/a08-audio-tool.jpg b/05-transcriptietool/beelden/a08-audio-tool.jpg new file mode 100644 index 0000000..d144e52 Binary files /dev/null and b/05-transcriptietool/beelden/a08-audio-tool.jpg differ diff --git a/05-transcriptietool/beelden/a09-stt-leeg.jpg b/05-transcriptietool/beelden/a09-stt-leeg.jpg new file mode 100644 index 0000000..c526da0 Binary files /dev/null and b/05-transcriptietool/beelden/a09-stt-leeg.jpg differ diff --git a/05-transcriptietool/beelden/a10-stt-audiofile.jpg b/05-transcriptietool/beelden/a10-stt-audiofile.jpg new file mode 100644 index 0000000..94cb7be Binary files /dev/null and b/05-transcriptietool/beelden/a10-stt-audiofile.jpg differ diff --git a/05-transcriptietool/beelden/a11-stt-modellen.jpg b/05-transcriptietool/beelden/a11-stt-modellen.jpg new file mode 100644 index 0000000..f6039df Binary files /dev/null and b/05-transcriptietool/beelden/a11-stt-modellen.jpg differ diff --git a/05-transcriptietool/beelden/a12-stt-klaar.jpg b/05-transcriptietool/beelden/a12-stt-klaar.jpg new file mode 100644 index 0000000..f3a91c6 Binary files /dev/null and b/05-transcriptietool/beelden/a12-stt-klaar.jpg differ diff --git a/05-transcriptietool/beelden/a13-llm-leeg.jpg b/05-transcriptietool/beelden/a13-llm-leeg.jpg new file mode 100644 index 0000000..466935d Binary files /dev/null and b/05-transcriptietool/beelden/a13-llm-leeg.jpg differ diff --git a/05-transcriptietool/beelden/a14-prompt-variabele.jpg b/05-transcriptietool/beelden/a14-prompt-variabele.jpg new file mode 100644 index 0000000..840518f Binary files /dev/null and b/05-transcriptietool/beelden/a14-prompt-variabele.jpg differ diff --git a/05-transcriptietool/beelden/a15-verslag-node.jpg b/05-transcriptietool/beelden/a15-verslag-node.jpg new file mode 100644 index 0000000..8808914 Binary files /dev/null and b/05-transcriptietool/beelden/a15-verslag-node.jpg differ diff --git a/05-transcriptietool/beelden/a16-output-leeg.jpg b/05-transcriptietool/beelden/a16-output-leeg.jpg new file mode 100644 index 0000000..b62e2e4 Binary files /dev/null and b/05-transcriptietool/beelden/a16-output-leeg.jpg differ diff --git a/05-transcriptietool/beelden/a17-output-variabelen.jpg b/05-transcriptietool/beelden/a17-output-variabelen.jpg new file mode 100644 index 0000000..c5d2c6f Binary files /dev/null and b/05-transcriptietool/beelden/a17-output-variabelen.jpg differ diff --git a/05-transcriptietool/beelden/a18-output-klaar.jpg b/05-transcriptietool/beelden/a18-output-klaar.jpg new file mode 100644 index 0000000..97ae0c1 Binary files /dev/null and b/05-transcriptietool/beelden/a18-output-klaar.jpg differ diff --git a/05-transcriptietool/beelden/a19-overzicht.jpg b/05-transcriptietool/beelden/a19-overzicht.jpg new file mode 100644 index 0000000..669b17c Binary files /dev/null and b/05-transcriptietool/beelden/a19-overzicht.jpg differ diff --git a/05-transcriptietool/beelden/a20-testrun-leeg.jpg b/05-transcriptietool/beelden/a20-testrun-leeg.jpg new file mode 100644 index 0000000..914e984 Binary files /dev/null and b/05-transcriptietool/beelden/a20-testrun-leeg.jpg differ diff --git a/05-transcriptietool/beelden/a21-testrun-groot.jpg b/05-transcriptietool/beelden/a21-testrun-groot.jpg new file mode 100644 index 0000000..5584108 Binary files /dev/null and b/05-transcriptietool/beelden/a21-testrun-groot.jpg differ diff --git a/05-transcriptietool/beelden/a22-fout-te-groot.jpg b/05-transcriptietool/beelden/a22-fout-te-groot.jpg new file mode 100644 index 0000000..19e22c6 Binary files /dev/null and b/05-transcriptietool/beelden/a22-fout-te-groot.jpg differ diff --git a/05-transcriptietool/beelden/a23-testrun-klein.jpg b/05-transcriptietool/beelden/a23-testrun-klein.jpg new file mode 100644 index 0000000..799ba12 Binary files /dev/null and b/05-transcriptietool/beelden/a23-testrun-klein.jpg differ diff --git a/05-transcriptietool/beelden/a24-running.jpg b/05-transcriptietool/beelden/a24-running.jpg new file mode 100644 index 0000000..799ba12 Binary files /dev/null and b/05-transcriptietool/beelden/a24-running.jpg differ diff --git a/05-transcriptietool/beelden/a25-verslag-schrijft.jpg b/05-transcriptietool/beelden/a25-verslag-schrijft.jpg new file mode 100644 index 0000000..43f9fe6 Binary files /dev/null and b/05-transcriptietool/beelden/a25-verslag-schrijft.jpg differ diff --git a/05-transcriptietool/beelden/a26-resultaat.jpg b/05-transcriptietool/beelden/a26-resultaat.jpg new file mode 100644 index 0000000..4867624 Binary files /dev/null and b/05-transcriptietool/beelden/a26-resultaat.jpg differ diff --git a/05-transcriptietool/beelden/a27-resultaat-vervolg.jpg b/05-transcriptietool/beelden/a27-resultaat-vervolg.jpg new file mode 100644 index 0000000..2d9ec02 Binary files /dev/null and b/05-transcriptietool/beelden/a27-resultaat-vervolg.jpg differ diff --git a/05-transcriptietool/beelden/a28-label-toegevoegd.jpg b/05-transcriptietool/beelden/a28-label-toegevoegd.jpg new file mode 100644 index 0000000..8535ce2 Binary files /dev/null and b/05-transcriptietool/beelden/a28-label-toegevoegd.jpg differ diff --git a/05-transcriptietool/beelden/a29-publish-menu.jpg b/05-transcriptietool/beelden/a29-publish-menu.jpg new file mode 100644 index 0000000..21f2420 Binary files /dev/null and b/05-transcriptietool/beelden/a29-publish-menu.jpg differ diff --git a/05-transcriptietool/beelden/a30-webapp-leeg.jpg b/05-transcriptietool/beelden/a30-webapp-leeg.jpg new file mode 100644 index 0000000..0ca9d3b Binary files /dev/null and b/05-transcriptietool/beelden/a30-webapp-leeg.jpg differ diff --git a/05-transcriptietool/beelden/a31-webapp-bestand.jpg b/05-transcriptietool/beelden/a31-webapp-bestand.jpg new file mode 100644 index 0000000..f7fbe16 Binary files /dev/null and b/05-transcriptietool/beelden/a31-webapp-bestand.jpg differ diff --git a/05-transcriptietool/beelden/a32-webapp-running.jpg b/05-transcriptietool/beelden/a32-webapp-running.jpg new file mode 100644 index 0000000..1ef827b Binary files /dev/null and b/05-transcriptietool/beelden/a32-webapp-running.jpg differ diff --git a/05-transcriptietool/beelden/a33-webapp-resultaat.jpg b/05-transcriptietool/beelden/a33-webapp-resultaat.jpg new file mode 100644 index 0000000..d98a17d Binary files /dev/null and b/05-transcriptietool/beelden/a33-webapp-resultaat.jpg differ diff --git a/05-transcriptietool/beelden/a34-webapp-actiepunten.jpg b/05-transcriptietool/beelden/a34-webapp-actiepunten.jpg new file mode 100644 index 0000000..da5955c Binary files /dev/null and b/05-transcriptietool/beelden/a34-webapp-actiepunten.jpg differ diff --git a/05-transcriptietool/beelden/b02-tts-node.jpg b/05-transcriptietool/beelden/b02-tts-node.jpg new file mode 100644 index 0000000..a7c03a7 Binary files /dev/null and b/05-transcriptietool/beelden/b02-tts-node.jpg differ diff --git a/05-transcriptietool/beelden/b03-tts-variabele.jpg b/05-transcriptietool/beelden/b03-tts-variabele.jpg new file mode 100644 index 0000000..944c9c2 Binary files /dev/null and b/05-transcriptietool/beelden/b03-tts-variabele.jpg differ diff --git a/05-transcriptietool/beelden/b04-tts-modellen.jpg b/05-transcriptietool/beelden/b04-tts-modellen.jpg new file mode 100644 index 0000000..bc746ca Binary files /dev/null and b/05-transcriptietool/beelden/b04-tts-modellen.jpg differ diff --git a/05-transcriptietool/beelden/b05-tts-stemmen.jpg b/05-transcriptietool/beelden/b05-tts-stemmen.jpg new file mode 100644 index 0000000..2409b31 Binary files /dev/null and b/05-transcriptietool/beelden/b05-tts-stemmen.jpg differ diff --git a/05-transcriptietool/beelden/b06-tts-output.jpg b/05-transcriptietool/beelden/b06-tts-output.jpg new file mode 100644 index 0000000..d252fee Binary files /dev/null and b/05-transcriptietool/beelden/b06-tts-output.jpg differ diff --git a/05-transcriptietool/beelden/b07-tts-resultaat.jpg b/05-transcriptietool/beelden/b07-tts-resultaat.jpg new file mode 100644 index 0000000..a8e414d Binary files /dev/null and b/05-transcriptietool/beelden/b07-tts-resultaat.jpg differ diff --git a/05-transcriptietool/beelden/b08-tts-overzicht.jpg b/05-transcriptietool/beelden/b08-tts-overzicht.jpg new file mode 100644 index 0000000..da6621b Binary files /dev/null and b/05-transcriptietool/beelden/b08-tts-overzicht.jpg differ diff --git a/05-transcriptietool/build.py b/05-transcriptietool/build.py new file mode 100644 index 0000000..3f11e36 --- /dev/null +++ b/05-transcriptietool/build.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +"""Bouwt handleiding-dify-transcriptietool.html, .pdf en .docx. Gebruik: python3 build.py +Het echte werk staat in ../_gereedschap/build_handleiding.py (gedeeld door alle handleidingen).""" +import runpy, sys +from pathlib import Path +sys.argv = ["build_handleiding.py", str(Path(__file__).resolve().parent / "handleiding-dify-transcriptietool.md")] +runpy.run_path(str(Path(__file__).resolve().parent.parent / "_gereedschap" / "build_handleiding.py"), run_name="__main__") diff --git a/05-transcriptietool/handleiding-dify-transcriptietool.md b/05-transcriptietool/handleiding-dify-transcriptietool.md new file mode 100644 index 0000000..d0e4f4f --- /dev/null +++ b/05-transcriptietool/handleiding-dify-transcriptietool.md @@ -0,0 +1,383 @@ + + +# Bouwen in Dify: van opname naar verslag + +**Handleiding 5, bij use case UC-2026-009 AI-Transcriptietool** +Experimenteerruimte ICT SOML · LeX Consultancy B.V. · 20 september 2026 + +Je bouwt een workflow die een geluidsopname van een overleg omzet in tekst en daar een verslag van maakt: samenvatting, besluiten, actiepunten met eigenaar en datum, en wat is doorgeschoven. Aan het eind heb je een webadres waar een collega een mp3 uploadt en binnen twee minuten het verslag en het volledige transcript terugkrijgt. + +Ten opzichte van handleiding 1 en 3 zijn twee dingen nieuw: een **bestand als invoer** in plaats van tekst, en een **tool-node** (Speech To Text) in plaats van alleen LLM-nodes. De rest ken je. + +Deze handleiding volgt de cloudversie van Dify zoals die er op 20 september 2026 uitziet. Dify verandert snel: wijkt je scherm af, volg dan wat je ziet en niet wat hier staat. + +**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 | + +--- + +## Lees dit eerst: wat mag wel en niet + +Deze handleiding hoort bij een use case die door de Experimenteerruimte ICT en de Functionaris Gegevensbescherming is beoordeeld: **voorwaardelijk akkoord, risico middel**. Een stem is een persoonsgegeven. Daarom gelden deze afspraken, en die staan niet ter discussie: + +| Wat | Afspraak | +| --- | --- | +| Opnames van echte mensen in Dify-cloud | **Niet.** Dify-cloud valt niet onder de verwerkersovereenkomst van SOML. Deze handleiding werkt met een fictieve, door een computer voorgelezen opname. Gebruik die, of maak zelf zo'n opname (bijlage A). | +| Echt gebruik | Alleen via de Gemini API in het centrale Google Cloud-project van SOML (Vertex AI, verwerking in de EU). Regel dat via e-ict@soml.nl. Dify kan daar ook op draaien, maar dat is een aparte inrichting die buiten deze handleiding valt. | +| Opnemen van een overleg | Vooraf expliciete toestemming van alle deelnemers. Structureel opnemen: medezeggenschapsraad informeren. | +| Bewaren | Audio verwijderen zodra het transcript er is. Dify bewaart geüploade bestanden en resultaten; zie "Beheer" achterin. | +| Leerlingen | Het scenario met spreekvaardigheidstoetsen mag pas na een DPIA en na het informeren van ouders. Deze handleiding gaat alleen over overleggen van medewerkers. | +| Toegankelijkheid | Als de tool voor leerlingen wordt ingezet: voor alle leerlingen, niet alleen voor leerlingen met een beperking. | + +Kort gezegd: wat je hier bouwt is een werkend prototype om te leren hoe het gaat. De stap naar echt gebruik is een aparte beslissing met een aparte omgeving. + +--- + +## Voorbereiding + +- Een Dify-account met een eigen OpenAI-sleutel, ingesteld op **Gebruiksprioriteit: API-sleutel** (Integraties → Model Provider → OpenAI → Config). Zonder eigen sleutel werkt de Speech To Text-tool niet: de gratis credits van Dify dekken alleen tekstmodellen. +- De testopname `sectieoverleg-opname-klein.mp3` uit de map van deze handleiding: een fictief sectieoverleg Nederlands van drie minuten, drie sprekers, voorgelezen door een computerstem. +- Kosten per run via je eigen sleutel: transcriptie ongeveer 2 cent, verslag minder dan 1 cent. + +--- + +## Stap 1. Maak de workflow + +1. Ga naar **Studio**, klik op **Create** en kies **Create from Blank**. +2. Klik op **Workflow**. +3. Vul de naam in. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| App Name & Icon | `Transcriptietool` | + +![Workflow gekozen, naam ingevuld](beelden/a01-create-workflow.jpg) + +4. Klik op **Create**. + +> Een sandbox-account mag vijf apps hebben, en agents in het menu Agents tellen mee. Zie je "Upgrade to create more apps", verwijder dan eerst een oude app via de drie puntjes op de kaart in Studio. + +## Stap 2. Maak een invoerveld voor het audiobestand + +1. Klik in het rechterpaneel op **User Input**. +2. Klik op het plusje bij **INPUT FIELD**. + +![Het dialoogvenster Add Input Field](beelden/a02-add-input-field.jpg) + +3. Klap **Field Type** open. Je ziet de soorten velden. + +![De veldtypen, met Single File en File List](beelden/a03-field-types.jpg) + +4. Kies **Single File**. Het venster wordt langer: er verschijnen bestandstypen. + +![Single File: bestandstypen kiezen](beelden/a04-single-file.jpg) + +5. Vul de velden in. + +| Veld op het scherm | Wat je intypt of kiest | +| --- | --- | +| Variable Name | `opname` | +| Label Name | `Opname van het overleg (mp3, m4a of wav)` | +| Support File Types | **Image** uitzetten, **Audio** aanzetten | +| Upload File Types | **Local Upload** | + +> Image staat standaard aan. Zet hem uit, anders kan iemand straks een foto uploaden en loopt de workflow vast op de transcriptiestap. + +![Veld opname, alleen Audio aangevinkt](beelden/a05-veld-opname.jpg) + +6. Klik op **Save**. + +![Het invoerveld staat in de node](beelden/a06-userinput-klaar.jpg) + +## Stap 3. Voeg de transcriptiestap toe + +Dit is de nieuwe bouwsteen: geen LLM-node, maar een **tool**. Dify heeft een ingebouwde Audio-tool die spraak naar tekst omzet via het spraakmodel van je aanbieder. + +1. Klik onder **NEXT STEP** op **SELECT NEXT STEP**. +2. Klik bovenin het lijstje op het tabblad **Tools**. + +![Het tabblad Tools](beelden/a07-tools-tab.jpg) + +3. Klik onder **All tools** op **Audio**. Er klappen twee opties uit. + +![Audio: Speech To Text en Text To Speech](beelden/a08-audio-tool.jpg) + +4. Kies **Speech To Text**. + +![De lege Speech To Text-node](beelden/a09-stt-leeg.jpg) + +5. Klik bij **Audio File** op **Set variable** en kies onder USER INPUT de variabele **opname**. + +![De opname koppelen](beelden/a10-stt-audiofile.jpg) + +6. Klik bij **Model** op de keuzelijst. Je ziet de spraakmodellen die via je sleutel beschikbaar zijn. + +![De spraakmodellen](beelden/a11-stt-modellen.jpg) + +7. Kies **gpt-4o-transcribe-diarize**. "Diarize" betekent dat het model sprekers uit elkaar houdt; dat helpt bij een overleg. Wil je goedkoper, kies dan **whisper-1**. + +![Speech To Text ingesteld](beelden/a12-stt-klaar.jpg) + +## Stap 4. Voeg de verslagstap toe + +1. Klik op **SELECT NEXT STEP** en kies onder **Nodes** de node **LLM**. + +![De lege LLM-node](beelden/a13-llm-leeg.jpg) + +2. Klik op de modelnaam **gpt-5** en kies **gpt-5-mini**. +3. Klik in het veld **SYSTEM** en typ de instructie over. + +``` +Begin je antwoord met de regel # VERSLAG en daarna een lege regel. + +Je maakt een verslag van een overleg op een school, op basis van het transcript hieronder. Het transcript komt van automatische spraakherkenning en kan fouten bevatten in namen en getallen; schrijf dan op wat het meest waarschijnlijk is en zet een vraagteken tussen haakjes achter wat je niet zeker weet. + +Schrijf in het Nederlands, zakelijk en kort. Gebruik precies deze indeling met deze kopjes: + +## Overleg +Een regel: welk overleg, datum, aanwezigen (als dat uit het transcript blijkt). + +## Samenvatting +Maximaal vijf zinnen over wat er is besproken. + +## Besluiten +Genummerde lijst. Alleen wat echt is besloten, geen voornemens. + +## Actiepunten +Tabel met kolommen: Wat, Wie, Wanneer. Staat er geen datum, schrijf dan "niet genoemd". + +## Doorgeschoven +Punten die bewust naar een volgend overleg zijn verplaatst, met de reden. + +Laat zijpaden en informele opmerkingen weg. Verzin niets wat niet in het transcript staat. + +Transcript: +``` + +4. Typ direct na "Transcript:" een schuine streep `/`. In de lijst staat nu bovenaan **SPEECH TO TEXT** met de variabele **text**. + +![De variabelenlijst met de uitvoer van Speech To Text](beelden/a14-prompt-variabele.jpg) + +5. Kies **text** onder SPEECH TO TEXT. +6. Klik bovenin het paneel op de naam **LLM**, vervang die door `Verslag` en druk op Enter. + +![De Verslag-node, compleet](beelden/a15-verslag-node.jpg) + +> **Zelf kiezen: de indeling van het verslag.** De kopjes in de prompt zijn de indeling die een sectieoverleg vaak heeft. Een MR-vergadering wil misschien "Adviezen en instemming", een leerlingbespreking wil per leerling een blokje (maar dat is het scenario dat pas na een DPIA mag), een teamdag wil "Afspraken" en "Parkeerplaats". Verander alleen de kopjes en hun uitleg; de regels erboven (fouten in spraakherkenning, niets verzinnen) laat je staan. Wil je twee versies, bijvoorbeeld een lang verslag en een bericht van vijf regels voor het team? Voeg een tweede LLM-node toe met dezelfde variabele **text** als invoer. + +> De regel "zet een vraagteken tussen haakjes achter wat je niet zeker weet" is geen versiering. In onze test hoorde de spraakherkenning "Karin" de ene keer als "Karen" en de andere keer als "Karin", en werd "Sectieoverleg Nederlands" een keer "Secr. Overleg Nederland". Het verslag zette daar netjes "(Karen?)" bij. Een mens moet dat nog nakijken; de tool maakt zichtbaar waar. + +## Stap 5. Bepaal wat eruit komt + +1. Klik op **SELECT NEXT STEP** en kies **Output**. + +![De lege Output-node](beelden/a16-output-leeg.jpg) + +2. Klik op het plusje bij **OUTPUT VARIABLE** en maak twee variabelen. + +| Variable name (intypen) | Bron (kiezen) | +| --- | --- | +| `verslag` | Verslag / text | +| `transcript` | Speech To Text / text | + +![De bronnenlijst](beelden/a17-output-variabelen.jpg) + +![Beide uitvoervariabelen](beelden/a18-output-klaar.jpg) + +3. Sluit het paneel en druk op Ctrl+1. Je ziet de hele workflow: vier nodes. + +![User Input, Speech To Text, Verslag, Output](beelden/a19-overzicht.jpg) + +## Stap 6. Test met de opname + +1. Klik rechtsboven op **Test Run**. + +![Het testpaneel met de uploadknop](beelden/a20-testrun-leeg.jpg) + +2. Klik op **Local upload** en kies `sectieoverleg-opname-klein.mp3`. + +> Gebruik het bestand dat "klein" in de naam heeft. Het andere bestand in de map, `sectieoverleg-opname.mp3`, is dezelfde opname op 128 kbps. Die is 2,8 MB en dat is te groot: de tool stuurt audio als tekst (base64) naar de aanbieder, wat het bestand twee keer zo groot maakt, en de grens ligt op 5 MB. Je krijgt dan de foutmelding hieronder. + +![Te groot: ServerlessPayloadTooLarge](beelden/a22-fout-te-groot.jpg) + +Vuistregel: **3 MB per opname**. Een half uur overleg past daar alleen in als je de opname eerst verkleint: mono, 16 kHz, 32 kbps geeft ongeveer 250 kB per minuut. Dat kan met elk audioprogramma, of met ffmpeg: + +``` +ffmpeg -i opname.m4a -ac 1 -ar 16000 -b:a 32k opname-klein.mp3 +``` + +![Het kleine bestand staat klaar](beelden/a23-testrun-klein.jpg) + +3. Klik op **Start Run**. De transcriptie van drie minuten audio duurt ongeveer een minuut. + +![Speech To Text draait](beelden/a24-running.jpg) + +![De Verslag-node schrijft](beelden/a25-verslag-schrijft.jpg) + +4. Lees het resultaat onder **RESULT**. + +![Het verslag: overleg, samenvatting, besluiten](beelden/a26-resultaat.jpg) + +![Actiepunten, doorgeschoven, en daaronder het transcript](beelden/a27-resultaat-vervolg.jpg) + +Controleer met het script (`sectieoverleg-script.txt`) of het klopt. In onze test: twee besluiten gevonden, vijf actiepunten met de juiste eigenaren en data, de leesmethode onder "Doorgeschoven" met de reden, en het koffieapparaat netjes weggelaten. + +## Stap 7. Publiceer + +1. Klik rechtsboven op **Publish** en dan op **Publish**. + +![Het Publish-menu](beelden/a29-publish-menu.jpg) + +2. Open het menu opnieuw en klik op **Webapp openen**. + +![De webapp](beelden/a30-webapp-leeg.jpg) + +3. Klik op **Local upload**, kies de kleine opname en klik op **Execute**. + +> Na het uploaden schuift de knop Execute een stukje naar beneden. Kijk even waar hij staat voordat je klikt. + +![Bestand geüpload, Execute staat lager](beelden/a31-webapp-bestand.jpg) + +![De vier stappen lopen](beelden/a32-webapp-running.jpg) + +![Het verslag in de webapp](beelden/a33-webapp-resultaat.jpg) + +![De actiepuntentabel, met kopieer- en downloadknop](beelden/a34-webapp-actiepunten.jpg) + +Rechtsboven bij de tabel staan een kopieerknop en een downloadknop. Daarmee zet een collega de actiepunten zo in een mail of een spreadsheet. + +Het voorbeeld uit deze handleiding: . + +--- + +## Controleren of het gelukt is + +- De workflow heeft vier nodes: User Input, Speech To Text, Verslag, Output +- Het invoerveld accepteert alleen audio (geen Image aangevinkt) +- Test Run met de kleine opname levert een verslag met vijf kopjes en daaronder het transcript +- In de webapp komt hetzelfde resultaat, met VERSLAG als kop +- Onzekere namen staan met een vraagteken tussen haakjes + +## Als het misgaat + +| Wat je ziet | Wat er aan de hand is | +| --- | --- | +| `ServerlessPayloadTooLarge ... max_request_bytes=5242880` | Het audiobestand is te groot. Verklein naar 32 kbps mono (stap 6) | +| Speech To Text: geen model in de lijst | Geen eigen OpenAI-sleutel, of Gebruiksprioriteit staat op AI-tegoeden. Integraties → Model Provider → OpenAI → Config | +| De workflow loopt vast op Speech To Text bij een foto | Image staat nog aan bij het invoerveld (stap 2) | +| Het verslag noemt mensen die niet in het overleg zaten | De spraakherkenning heeft een naam verkeerd verstaan. Kijk in het transcript onderaan; vaak staat de juiste naam er wel bij met een vraagteken | +| Verslag en transcript lopen in elkaar over | De regel "Begin je antwoord met de regel # VERSLAG" ontbreekt in de instructie | +| "Upgrade to create more apps" | Sandbox-limiet van vijf apps. Verwijder een oude app via de drie puntjes op de kaart | +| Een mp3-link uit een testrun geeft `403 forbidden` | Downloadlinks van Dify-bestanden zijn vijf minuten geldig. Download meteen, of draai de test opnieuw | +| Melding over temperature | Het model ondersteunt die parameter niet. Negeren | + +--- + +## Maak hem van jou + +De opname is verzonnen, de indeling van het verslag is onze keuze. Dit hoofdstuk helpt je de tool om te bouwen naar jullie overleggen, binnen het privacykader aan het begin van deze handleiding. Van makkelijk naar moeilijk. + +| Aanpassing | Waar | Moeilijkheid | Wat je ervoor terugkrijgt | +| --- | --- | --- | --- | +| Andere kopjes in het verslag | Stap 4, prompt | makkelijk | Een verslag in de vorm die jullie al gebruiken | +| Taal en toon (formeel, informeel, Engels) | Stap 4, prompt | makkelijk | Een verslag dat je zonder herschrijven kunt delen | +| Een ander spraakmodel (whisper-1 is goedkoper, diarize onderscheidt sprekers) | Stap 3, instellingen van de tool | makkelijk | Lagere kosten of juist sprekerherkenning | +| Een tweede uitvoer: kort bericht voor wie er niet was | Extra LLM-node na stap 4, extra uitvoervariabele in stap 5 | gemiddeld | Twee producten uit één opname | +| Actiepunten als aparte lijst die je kunt kopiëren naar een takenlijst | Extra LLM-node met alleen de tabel | gemiddeld | Minder overtypen na het overleg | +| Een invoerveld "type overleg" dat de indeling kiest | Stap 2 plus een IF/ELSE-node of een prompt met voorwaarden | gemiddeld | Eén tool voor meerdere soorten overleg | +| Langere opnames dan 5 MB | Speech To Text vervangen door een HTTP Request-node naar de spraak-API | moeilijk | Een uur overleg in één keer; zie Beheer | +| Draaien in de SOML-omgeving met Vertex AI | Export DSL, importeren, modellen opnieuw koppelen | moeilijk | De route die voor echte opnames verplicht is | + +**Drie opdrachten** + +1. **Jullie indeling.** Pak het laatste verslag dat iemand in jouw team met de hand schreef. Zet de kopjes daarvan in de prompt van stap 4, met per kopje één zin uitleg. Draai de fictieve opname opnieuw en vergelijk met het handgeschreven verslag: wat mist, wat is te veel? +2. **Maak een eigen testopname.** Schrijf met je team een fictief script van tien minuten over een echt onderwerp (zonder echte namen), en maak er via Bijlage A een opname van. Zo test je de tool op jullie jargon zonder dat er een echte stem in Dify komt. +3. **Bereid de overstap voor.** Exporteer de workflow (Export DSL) en schrijf op een half A4 wat er nodig is om hem in de Experimenteerruimte te draaien: welk model, welke sleutel, wie de eigenaar is, hoe lang audio bewaard blijft. Dat half A4 is precies wat de use case-beoordeling van je vraagt. + +**Checklist voordat je eigen materiaal gebruikt** + +- [ ] Er gaat geen echte opname in Dify-cloud; alleen fictieve of synthetische audio +- [ ] Voor echte opnames: de tool draait in de SOML-omgeving via het centrale project, en de deelnemers hebben ingestemd +- [ ] Audio wordt verwijderd na de transcriptie en er is vastgelegd wie dat controleert +- [ ] Het scenario met leerlingen (leerlingbesprekingen, gesprekken met leerlingen) wacht op de DPIA +- [ ] Iemand leest het verslag na voordat het rondgaat; de vraagtekens in het verslag zijn daarvoor bedoeld +- [ ] Er is één eigenaar van de tool die de prompt bijhoudt en opnieuw publiceert + +--- + +## Beheer + +**Wat Dify bewaart.** Elke upload en elk resultaat staat in **Logs** van de app, met het audiobestand erbij. Voor het prototype met de fictieve opname is dat geen probleem. Zodra er ooit een echte opname in zou gaan, is dit de reden dat Dify-cloud niet mag: je kunt de audio niet verwijderen zonder de hele log te wissen, en het bewaarbeleid van de use case (audio weg na transcriptie) is dan niet na te komen. Voor echt gebruik hoort de tool in de SOML-omgeving, met een bewaartermijn die is vastgelegd. + +**Kosten.** Via je eigen sleutel: gpt-4o-transcribe-diarize kost ongeveer 0,6 cent per minuut audio, whisper-1 de helft. Een overleg van 45 minuten komt op 20 tot 30 cent inclusief het verslag. Dify-credits worden niet aangesproken zolang OpenAI op API-sleutel staat. + +**Langere opnames.** De 5 MB-grens van de tool is hard. Een uur overleg op 32 kbps is 14 MB en past dus niet. Twee routes: de opname in stukken van een kwartier knippen en apart draaien, of de Speech To Text-tool vervangen door een HTTP Request-node die rechtstreeks naar de spraak-API van de aanbieder gaat (grens 25 MB). Dat laatste is een volgende handleiding. + +**Van prototype naar de Experimenteerruimte.** De workflow is via **Export DSL** (drie puntjes op de kaart in Studio) als bestand op te slaan en in een ander Dify-account te importeren. De modellen moeten daar opnieuw gekoppeld worden aan de sleutels van dat account. Voor de Gemini-route: Model Provider → Gemini → Add API Key met de sleutel uit het centrale SOML-project. + +--- + +## Bijlage A. Een testopname maken zonder echte stemmen + +Voor een prototype heb je een opname nodig zonder persoonsgegevens. De makkelijkste route is een fictief script laten voorlezen door dezelfde Audio-tool, maar dan andersom: **Text To Speech**. Zo is de opname bij deze handleiding gemaakt. + +1. Maak een workflow met een **User Input** met één veld: type **Paragraph**, variabele `tekst`. +2. Kies als volgende stap **Tools** → **Audio** → **Text To Speech**. + +![De Text To Speech-node](beelden/b02-tts-node.jpg) + +3. Klik bij **Text** in het veld, typ `/` en kies **tekst**. + +![De variabele kiezen](beelden/b03-tts-variabele.jpg) + +4. Kies bij **Model** een spraakmodel; **tts-1** is het goedkoopst. + +![De spraakmodellen](beelden/b04-tts-modellen.jpg) + +5. Kies bij **Voice of tts-1** een stem, bijvoorbeeld **Alloy**. + +![De stemmen](beelden/b05-tts-stemmen.jpg) + +6. Voeg een **Output**-node toe met variabele `audio` → Text To Speech / **files**. + +![De Output-node met het audiobestand](beelden/b06-tts-output.jpg) + +7. Klik op **Test Run**, plak het script (`sectieoverleg-script.txt`) en klik op **Start Run**. Na een halve minuut staat er een mp3 in het resultaat. + +![De opname is klaar](beelden/b07-tts-resultaat.jpg) + +8. Klik meteen op de bestandsnaam en sla het bestand op. De link werkt vijf minuten. + +Kosten: ongeveer 4 cent voor drie minuten spraak. Het resultaat is één stem die alle sprekers leest; voor een test van transcriptie en verslag is dat genoeg. Een sandbox-account heeft plek voor vijf apps, dus verwijder deze hulpworkflow daarna, of bouw hem om tot de Transcriptietool zoals in deze handleiding is gedaan. + +![De hulpworkflow: User Input, Text To Speech, Output](beelden/b08-tts-overzicht.jpg) diff --git a/05-transcriptietool/sectieoverleg-opname-klein.mp3 b/05-transcriptietool/sectieoverleg-opname-klein.mp3 new file mode 100644 index 0000000..f9cd8ef Binary files /dev/null and b/05-transcriptietool/sectieoverleg-opname-klein.mp3 differ diff --git a/05-transcriptietool/sectieoverleg-opname.mp3 b/05-transcriptietool/sectieoverleg-opname.mp3 new file mode 100644 index 0000000..57592c1 Binary files /dev/null and b/05-transcriptietool/sectieoverleg-opname.mp3 differ diff --git a/05-transcriptietool/sectieoverleg-script.txt b/05-transcriptietool/sectieoverleg-script.txt new file mode 100644 index 0000000..a449684 --- /dev/null +++ b/05-transcriptietool/sectieoverleg-script.txt @@ -0,0 +1,37 @@ +Sectieoverleg Nederlands, dinsdag 22 september. Aanwezig zijn Karin, Bram en Fatima. Karin zit voor. + +Karin: Goedemiddag allemaal. We hebben drie punten: de toetsweek van oktober, de nieuwe leesmethode voor de brugklas, en de rolverdeling bij de open dag. Laten we beginnen met de toetsweek. Bram, jij had de conceptplanning gemaakt. + +Bram: Klopt. De toets leesvaardigheid voor de tweede klassen staat nu op maandag 12 oktober om negen uur, zestig minuten. Ik stel voor dat we die zo laten. Wat ik wel wil voorstellen is dat we de spellingstoets samenvoegen met de leestoets, dus één toets van zestig minuten in plaats van twee losse toetsen. + +Fatima: Daar ben ik het mee eens. Twee losse toetsen in één week is voor de tweedeklassers te veel. Maar dan moet de studiewijzer wel worden aangepast, want daar staan nu nog twee toetsen in. + +Karin: Goed. Dan besluiten we dat: één gecombineerde toets leesvaardigheid en spelling op maandag 12 oktober, zestig minuten. Fatima, pas jij de studiewijzer aan? + +Fatima: Doe ik. Vrijdag heb ik hem klaar. + +Karin: Prima, vrijdag 25 september dus. Dan punt twee, de leesmethode. We hebben twee proefpakketten gekregen. Bram heeft ze bekeken. + +Bram: Ja, en eerlijk gezegd vind ik het lastig kiezen. Het ene pakket heeft veel betere teksten voor zwakke lezers, het andere heeft een digitale omgeving die veel beter werkt. Ik zou eigenlijk willen dat we ze allebei een periode uitproberen in één klas. + +Fatima: Kunnen we dat wel betalen? En hebben we daar de tijd voor met de toetsweek eraan? + +Karin: Ik denk dat we dit niet vandaag moeten beslissen. Ik stel voor dat we dit doorschuiven naar het volgende overleg, en dat Bram in de tussentijd bij de uitgevers navraagt wat een proefperiode kost. Akkoord? + +Bram: Akkoord. Ik mail ze deze week nog. + +Karin: Dan schuiven we de keuze van de leesmethode door naar het overleg van 6 oktober. Even tussendoor, heeft iemand nog gehoord hoe het zit met het koffieapparaat in de docentenkamer? Hij doet het al een week niet. + +Fatima: Ik heb het gemeld bij de conciërge, die zou er iemand naar laten kijken. + +Karin: Goed, dan hoeven we daar niks mee. Punt drie, de open dag op zaterdag 7 november. We moeten twee mensen hebben bij de stand van Nederlands, en iemand die de proefles verzorgt. + +Bram: Ik doe de proefles wel, dat heb ik vorig jaar ook gedaan. + +Fatima: Ik kan bij de stand staan in de ochtend, tot half een. + +Karin: Dan doe ik de middag bij de stand. Dan is het rond. Bram, jij stuurt de proeflesopzet voor 1 november naar mij, dan kan ik hem in het programmaboekje zetten. + +Bram: Ja, komt voor elkaar. + +Karin: Dan hebben we alles gehad. Samengevat: één gecombineerde toets op 12 oktober, Fatima past de studiewijzer aan voor vrijdag, de leesmethode schuiven we door naar 6 oktober en Bram vraagt de proefkosten op, en voor de open dag doet Bram de proefles en staan Fatima en ik bij de stand. Bedankt allemaal, tot volgende week. diff --git a/06-inclusief-lesmateriaal/lesbrief-ecologie.pdf b/06-inclusief-lesmateriaal/lesbrief-ecologie.pdf new file mode 100644 index 0000000..7c1bdad Binary files /dev/null and b/06-inclusief-lesmateriaal/lesbrief-ecologie.pdf differ diff --git a/06-inclusief-lesmateriaal/stercollectie-voedselweb-hv3.pdf b/06-inclusief-lesmateriaal/stercollectie-voedselweb-hv3.pdf new file mode 100644 index 0000000..0b064b6 Binary files /dev/null and b/06-inclusief-lesmateriaal/stercollectie-voedselweb-hv3.pdf differ diff --git a/07-schoolnieuws-met-controle/beelden/01-uitgangspunt.jpg b/07-schoolnieuws-met-controle/beelden/01-uitgangspunt.jpg new file mode 100644 index 0000000..9821bb2 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/01-uitgangspunt.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/02-next-step-output.jpg b/07-schoolnieuws-met-controle/beelden/02-next-step-output.jpg new file mode 100644 index 0000000..40fcbcc Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/02-next-step-output.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/03-disconnect-menu.jpg b/07-schoolnieuws-met-controle/beelden/03-disconnect-menu.jpg new file mode 100644 index 0000000..83f617d Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/03-disconnect-menu.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/04-losgekoppeld.jpg b/07-schoolnieuws-met-controle/beelden/04-losgekoppeld.jpg new file mode 100644 index 0000000..14749f7 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/04-losgekoppeld.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/05-nodes-lijst.jpg b/07-schoolnieuws-met-controle/beelden/05-nodes-lijst.jpg new file mode 100644 index 0000000..8aa9479 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/05-nodes-lijst.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/06-llm4-leeg.jpg b/07-schoolnieuws-met-controle/beelden/06-llm4-leeg.jpg new file mode 100644 index 0000000..88e1f7c Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/06-llm4-leeg.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/07-controleur-prompt.jpg b/07-schoolnieuws-met-controle/beelden/07-controleur-prompt.jpg new file mode 100644 index 0000000..c932b5c Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/07-controleur-prompt.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/08-controleur-klaar.jpg b/07-schoolnieuws-met-controle/beelden/08-controleur-klaar.jpg new file mode 100644 index 0000000..c885ede Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/08-controleur-klaar.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/09-code-standaard.jpg b/07-schoolnieuws-met-controle/beelden/09-code-standaard.jpg new file mode 100644 index 0000000..b0d8040 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/09-code-standaard.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/10-code-ingevuld.jpg b/07-schoolnieuws-met-controle/beelden/10-code-ingevuld.jpg new file mode 100644 index 0000000..871389e Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/10-code-ingevuld.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/11-invoer-hernoemd.jpg b/07-schoolnieuws-met-controle/beelden/11-invoer-hernoemd.jpg new file mode 100644 index 0000000..ce7ccca Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/11-invoer-hernoemd.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/12-variabele-kiezen.jpg b/07-schoolnieuws-met-controle/beelden/12-variabele-kiezen.jpg new file mode 100644 index 0000000..d7ede9c Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/12-variabele-kiezen.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/13-invoer-gekoppeld.jpg b/07-schoolnieuws-met-controle/beelden/13-invoer-gekoppeld.jpg new file mode 100644 index 0000000..43a5081 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/13-invoer-gekoppeld.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/14-uitvoer-type.jpg b/07-schoolnieuws-met-controle/beelden/14-uitvoer-type.jpg new file mode 100644 index 0000000..96e0607 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/14-uitvoer-type.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/15-poortwachter-klaar.jpg b/07-schoolnieuws-met-controle/beelden/15-poortwachter-klaar.jpg new file mode 100644 index 0000000..2c97945 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/15-poortwachter-klaar.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/16-ifelse-leeg.jpg b/07-schoolnieuws-met-controle/beelden/16-ifelse-leeg.jpg new file mode 100644 index 0000000..889364b Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/16-ifelse-leeg.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/17-conditie-variabele.jpg b/07-schoolnieuws-met-controle/beelden/17-conditie-variabele.jpg new file mode 100644 index 0000000..130b12c Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/17-conditie-variabele.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/18-conditie.jpg b/07-schoolnieuws-met-controle/beelden/18-conditie.jpg new file mode 100644 index 0000000..5a79a75 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/18-conditie.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/19-output2-leeg.jpg b/07-schoolnieuws-met-controle/beelden/19-output2-leeg.jpg new file mode 100644 index 0000000..ff74cf0 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/19-output2-leeg.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/20-goedgekeurd.jpg b/07-schoolnieuws-met-controle/beelden/20-goedgekeurd.jpg new file mode 100644 index 0000000..4aeb3b3 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/20-goedgekeurd.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/21-ifelse-else.jpg b/07-schoolnieuws-met-controle/beelden/21-ifelse-else.jpg new file mode 100644 index 0000000..1e8b371 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/21-ifelse-else.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/22-naar-medewerker.jpg b/07-schoolnieuws-met-controle/beelden/22-naar-medewerker.jpg new file mode 100644 index 0000000..6fa8631 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/22-naar-medewerker.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/23-checklist.jpg b/07-schoolnieuws-met-controle/beelden/23-checklist.jpg new file mode 100644 index 0000000..b96b42f Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/23-checklist.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/24-oude-output.jpg b/07-schoolnieuws-met-controle/beelden/24-oude-output.jpg new file mode 100644 index 0000000..e66cedc Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/24-oude-output.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/25-concept-variabelen.jpg b/07-schoolnieuws-met-controle/beelden/25-concept-variabelen.jpg new file mode 100644 index 0000000..c9714f0 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/25-concept-variabelen.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/26-nieuwe-staart.jpg b/07-schoolnieuws-met-controle/beelden/26-nieuwe-staart.jpg new file mode 100644 index 0000000..3c8a1fd Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/26-nieuwe-staart.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/27-hele-keten.jpg b/07-schoolnieuws-met-controle/beelden/27-hele-keten.jpg new file mode 100644 index 0000000..9d7c43c Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/27-hele-keten.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/28-test1-resultaat.jpg b/07-schoolnieuws-met-controle/beelden/28-test1-resultaat.jpg new file mode 100644 index 0000000..4a5f9b5 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/28-test1-resultaat.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/29-test1-detail.jpg b/07-schoolnieuws-met-controle/beelden/29-test1-detail.jpg new file mode 100644 index 0000000..b932c81 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/29-test1-detail.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/30-tracing.jpg b/07-schoolnieuws-met-controle/beelden/30-tracing.jpg new file mode 100644 index 0000000..c1d48f9 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/30-tracing.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/31-poortwachter-ok.jpg b/07-schoolnieuws-met-controle/beelden/31-poortwachter-ok.jpg new file mode 100644 index 0000000..3c87ed2 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/31-poortwachter-ok.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/32-controleur-aangevuld.jpg b/07-schoolnieuws-met-controle/beelden/32-controleur-aangevuld.jpg new file mode 100644 index 0000000..6e94bab Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/32-controleur-aangevuld.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/33-test2-invoer.jpg b/07-schoolnieuws-met-controle/beelden/33-test2-invoer.jpg new file mode 100644 index 0000000..bca9c79 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/33-test2-invoer.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/34-test2-afgekeurd.jpg b/07-schoolnieuws-met-controle/beelden/34-test2-afgekeurd.jpg new file mode 100644 index 0000000..395c911 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/34-test2-afgekeurd.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/35-gepubliceerd.jpg b/07-schoolnieuws-met-controle/beelden/35-gepubliceerd.jpg new file mode 100644 index 0000000..6310662 Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/35-gepubliceerd.jpg differ diff --git a/07-schoolnieuws-met-controle/beelden/36-webapp-afgekeurd.jpg b/07-schoolnieuws-met-controle/beelden/36-webapp-afgekeurd.jpg new file mode 100644 index 0000000..bb3a69a Binary files /dev/null and b/07-schoolnieuws-met-controle/beelden/36-webapp-afgekeurd.jpg differ diff --git a/07-schoolnieuws-met-controle/build.py b/07-schoolnieuws-met-controle/build.py new file mode 100644 index 0000000..67fb1cf --- /dev/null +++ b/07-schoolnieuws-met-controle/build.py @@ -0,0 +1,4 @@ +import runpy, sys +from pathlib import Path +sys.argv = ["build_handleiding.py", str(Path(__file__).resolve().parent / "handleiding-dify-schoolnieuws-met-controle.md")] +runpy.run_path(str(Path(__file__).resolve().parent.parent / "_gereedschap" / "build_handleiding.py"), run_name="__main__") diff --git a/07-schoolnieuws-met-controle/handleiding-dify-schoolnieuws-met-controle.md b/07-schoolnieuws-met-controle/handleiding-dify-schoolnieuws-met-controle.md new file mode 100644 index 0000000..4c3d873 --- /dev/null +++ b/07-schoolnieuws-met-controle/handleiding-dify-schoolnieuws-met-controle.md @@ -0,0 +1,402 @@ + + +# 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 | + +--- + +## 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: + +![Uitgangspunt: de workflow uit handleiding 3](beelden/01-uitgangspunt.jpg) + +En zo ziet de staart eruit als je klaar bent: + +![Het doel: Controleur, Poortwachter, IF/ELSE en twee uitgangen](beelden/27-hele-keten.jpg) + +--- + +## 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. + +1. Open **Schoolnieuws** in **Studio** en klik op het blok **Social**. +2. Scroll in het rechterpaneel naar **NEXT STEP**. Daar staat **Output**. + +![Next Step van Social: Output](beelden/02-next-step-output.jpg) + +3. Klik op de drie puntjes achter Output en kies **Disconnect**. (Niet **Delete**: het blok mag blijven, alleen de lijn gaat weg.) + +![Change, Disconnect, Delete](beelden/03-disconnect-menu.jpg) + +![Social heeft nu geen volgende stap meer](beelden/04-losgekoppeld.jpg) + +### Stap 2. Voeg de Controleur toe + +1. Klik bij **NEXT STEP** op **Select next step** en kies **LLM**. + +![De lijst met blokken](beelden/05-nodes-lijst.jpg) + +![Het nieuwe, lege LLM-blok](beelden/06-llm4-leeg.jpg) + +2. **MODEL**: gpt-5-mini. **CONTEXT**: Knowledge Retrieval / result (de schrijfwijzer). +3. 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} +``` + +![De prompt, met het menu na een schuine streep](beelden/07-controleur-prompt.jpg) + +4. Hernoem het blok naar `Controleur`. + +![Controleur klaar: context en conceptbericht zijn gekoppeld](beelden/08-controleur-klaar.jpg) + +> "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 + +1. Bij Controleur: **NEXT STEP** → **Select next step** → onder Transform: **Code**. + +![Het Code-blok met voorbeeldcode](beelden/09-code-standaard.jpg) + +2. 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.", + } +``` + +![De code staat erin](beelden/10-code-ingevuld.jpg) + +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 + +1. Hernoem bij **INPUT VARIABLES** `arg1` naar `website` en `arg2` naar `ouderapp`. Klik op **+** voor een derde variabele en noem die `social`. De namen moeten precies gelijk zijn aan de namen in de eerste regel van de code. + +![Invoervariabelen hernoemd, derde toegevoegd](beelden/11-invoer-hernoemd.jpg) + +2. 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** | + +![De variabelekiezer](beelden/12-variabele-kiezen.jpg) + +![Alle drie gekoppeld](beelden/13-invoer-gekoppeld.jpg) + +3. Bij **OUTPUT VARIABLES**: hernoem `result` naar `ok` en zet het type op **Number**. Klik op **+** en voeg `redenen` toe, type **String**. + +![Het type kiezen: Number](beelden/14-uitvoer-type.jpg) + +4. Hernoem het blok naar `Poortwachter`. + +![Poortwachter klaar](beelden/15-poortwachter-klaar.jpg) + +> De uitvoernamen (`ok`, `redenen`) moeten letterlijk overeenkomen met de namen in de `return`-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 + +1. Bij Poortwachter: **Select next step** → onder Logic: **IF/ELSE**. + +![Het lege IF/ELSE-blok](beelden/16-ifelse-leeg.jpg) + +2. Klik bij **IF** op **+ Add Condition** en kies **POORTWACHTER / ok**. + +![De variabele voor de voorwaarde](beelden/17-conditie-variabele.jpg) + +3. Laat de vergelijking op **=** staan en typ bij de waarde `1`. + +![De voorwaarde: ok = 1](beelden/18-conditie.jpg) + +### Stap 6. Uitgang 1: Goedgekeurd + +1. Bij **NEXT STEP** onder **IF**: **Select next step** → **Output**. + +![Het nieuwe Output-blok](beelden/19-output2-leeg.jpg) + +2. Voeg drie uitvoervariabelen toe: + +| Variable name | Set variable | +| --- | --- | +| `website` | **WEBSITE / text** | +| `ouderapp` | **CONTROLEUR / text** | +| `social` | **SOCIAL / text** | + +3. Hernoem het blok naar `Goedgekeurd`. + +![Goedgekeurd](beelden/20-goedgekeurd.jpg) + +### Stap 7. Uitgang 2: naar de communicatiemedewerker + +1. Klik op het blok **IF/ELSE**. Onder **ELSE** staat nog **Select next step**; kies **Output**. + +![IF heeft Goedgekeurd, ELSE nog niets](beelden/21-ifelse-else.jpg) + +2. 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** | + +3. Hernoem het blok naar `Naar de communicatiemedewerker`. + +![De tweede uitgang](beelden/22-naar-medewerker.jpg) + +> 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. Vandaar `concept_` in de tweede uitgang. + +### Stap 8. Ruim de oude Output op + +1. Klik rechtsboven op het checklist-icoon (naast Test Run). Je ziet welke blokken nog niet kloppen. + +![De checklist: de oude Output is nergens aan verbonden](beelden/23-checklist.jpg) + +2. Klik in de checklist op **Output**. Het oude blok wordt geselecteerd; het staat verstopt achter Controleur. + +![De oude Output, verstopt achter Controleur](beelden/24-oude-output.jpg) + +3. Klik in het paneel op de drie puntjes en dan op **Delete**. +4. Controleer dat de checklist leeg is (geen cijfer meer op het icoon). + +![Na het hernoemen naar concept_: geen dubbele variabelen meer](beelden/25-concept-variabelen.jpg) + +![De nieuwe staart van de workflow](beelden/26-nieuwe-staart.jpg) + +--- + +## 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 + +1. **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** | + +2. **Start Run**. Na ongeveer een minuut kleurt het pad via **IF** naar **Goedgekeurd** groen. + +![Test 1: het pad loopt via IF naar Goedgekeurd](beelden/28-test1-resultaat.jpg) + +3. Klik op **DETAIL**: status SUCCESS, doorlooptijd en tokens. + +![Detail van de run](beelden/29-test1-detail.jpg) + +4. Klik op **TRACING** en klap **POORTWACHTER** open. Onder OUTPUT staat wat de code teruggaf. + +![Tracing: elk blok met zijn tijd en tokens](beelden/30-tracing.jpg) + +![De Poortwachter: ok 1, "Alle regels in orde."](beelden/31-poortwachter-ok.jpg) + +> 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). + +![De aangevulde prompt van de Controleur na test 1](beelden/32-controleur-aangevuld.jpg) + +### Stap 10. Test 2: een bericht met gaten + +1. **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** | + +![Test 2: de invoer](beelden/33-test2-invoer.jpg) + +2. **Start Run**. Nu loopt het pad via **ELSE** naar **Naar de communicatiemedewerker**, en bovenaan het resultaat staan de redenen. + +![Test 2: afgekeurd, met vier redenen](beelden/34-test2-afgekeurd.jpg) + +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 + +1. **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. + +![Gepubliceerd als versie 2](beelden/35-gepubliceerd.jpg) + +2. Open de webapp en herhaal test 2. De collega ziet de redenen bovenaan en daaronder de concepten om aan te vullen. + +![De webapp: afgekeurd, met de redenen en de concepten](beelden/36-webapp-afgekeurd.jpg) + +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: 1` en bij test 2 `ok: 0` met 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** + +1. **Vul de lijst.** Vraag je communicatieteam naar de vijf woorden of formuleringen die zij het vaakst wegstrepen. Zet ze in `verboden` en 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. +2. **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. +3. **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. diff --git a/08-chatflow-studiecoach/beelden/a01-upload-twee.jpg b/08-chatflow-studiecoach/beelden/a01-upload-twee.jpg new file mode 100644 index 0000000..edc2cdc Binary files /dev/null and b/08-chatflow-studiecoach/beelden/a01-upload-twee.jpg differ diff --git a/08-chatflow-studiecoach/beelden/a02-chunk.jpg b/08-chatflow-studiecoach/beelden/a02-chunk.jpg new file mode 100644 index 0000000..d8304d5 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/a02-chunk.jpg differ diff --git a/08-chatflow-studiecoach/beelden/a03-preview.jpg b/08-chatflow-studiecoach/beelden/a03-preview.jpg new file mode 100644 index 0000000..001a587 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/a03-preview.jpg differ diff --git a/08-chatflow-studiecoach/beelden/a04-created.jpg b/08-chatflow-studiecoach/beelden/a04-created.jpg new file mode 100644 index 0000000..0558c9a Binary files /dev/null and b/08-chatflow-studiecoach/beelden/a04-created.jpg differ diff --git a/08-chatflow-studiecoach/beelden/a05-settings.jpg b/08-chatflow-studiecoach/beelden/a05-settings.jpg new file mode 100644 index 0000000..f866d14 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/a05-settings.jpg differ diff --git a/08-chatflow-studiecoach/beelden/a06-doc-menu.jpg b/08-chatflow-studiecoach/beelden/a06-doc-menu.jpg new file mode 100644 index 0000000..f75af74 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/a06-doc-menu.jpg differ diff --git a/08-chatflow-studiecoach/beelden/a07-drie-documenten.jpg b/08-chatflow-studiecoach/beelden/a07-drie-documenten.jpg new file mode 100644 index 0000000..7bff612 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/a07-drie-documenten.jpg differ diff --git a/08-chatflow-studiecoach/beelden/b01-create-chatflow.jpg b/08-chatflow-studiecoach/beelden/b01-create-chatflow.jpg new file mode 100644 index 0000000..5c8d576 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/b01-create-chatflow.jpg differ diff --git a/08-chatflow-studiecoach/beelden/b02-standaard-flow.jpg b/08-chatflow-studiecoach/beelden/b02-standaard-flow.jpg new file mode 100644 index 0000000..b1c4886 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/b02-standaard-flow.jpg differ diff --git a/08-chatflow-studiecoach/beelden/b03-delete-llm.jpg b/08-chatflow-studiecoach/beelden/b03-delete-llm.jpg new file mode 100644 index 0000000..31b1ce9 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/b03-delete-llm.jpg differ diff --git a/08-chatflow-studiecoach/beelden/b04-leeg-canvas.jpg b/08-chatflow-studiecoach/beelden/b04-leeg-canvas.jpg new file mode 100644 index 0000000..419efcb Binary files /dev/null and b/08-chatflow-studiecoach/beelden/b04-leeg-canvas.jpg differ diff --git a/08-chatflow-studiecoach/beelden/b05-classifier.jpg b/08-chatflow-studiecoach/beelden/b05-classifier.jpg new file mode 100644 index 0000000..88c5f26 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/b05-classifier.jpg differ diff --git a/08-chatflow-studiecoach/beelden/b06-class1.jpg b/08-chatflow-studiecoach/beelden/b06-class1.jpg new file mode 100644 index 0000000..e0639df Binary files /dev/null and b/08-chatflow-studiecoach/beelden/b06-class1.jpg differ diff --git a/08-chatflow-studiecoach/beelden/b07-class2.jpg b/08-chatflow-studiecoach/beelden/b07-class2.jpg new file mode 100644 index 0000000..2e232d0 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/b07-class2.jpg differ diff --git a/08-chatflow-studiecoach/beelden/b08-class3.jpg b/08-chatflow-studiecoach/beelden/b08-class3.jpg new file mode 100644 index 0000000..c12bb82 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/b08-class3.jpg differ diff --git a/08-chatflow-studiecoach/beelden/b09-class4.jpg b/08-chatflow-studiecoach/beelden/b09-class4.jpg new file mode 100644 index 0000000..9e7112b Binary files /dev/null and b/08-chatflow-studiecoach/beelden/b09-class4.jpg differ diff --git a/08-chatflow-studiecoach/beelden/b10-vier-takken.jpg b/08-chatflow-studiecoach/beelden/b10-vier-takken.jpg new file mode 100644 index 0000000..2dfd24b Binary files /dev/null and b/08-chatflow-studiecoach/beelden/b10-vier-takken.jpg differ diff --git a/08-chatflow-studiecoach/beelden/c01-kr.jpg b/08-chatflow-studiecoach/beelden/c01-kr.jpg new file mode 100644 index 0000000..fbd7858 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/c01-kr.jpg differ diff --git a/08-chatflow-studiecoach/beelden/c02-select-knowledge.jpg b/08-chatflow-studiecoach/beelden/c02-select-knowledge.jpg new file mode 100644 index 0000000..08d4b28 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/c02-select-knowledge.jpg differ diff --git a/08-chatflow-studiecoach/beelden/c03-kr-gekoppeld.jpg b/08-chatflow-studiecoach/beelden/c03-kr-gekoppeld.jpg new file mode 100644 index 0000000..3e69691 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/c03-kr-gekoppeld.jpg differ diff --git a/08-chatflow-studiecoach/beelden/c04-llm-leeg.jpg b/08-chatflow-studiecoach/beelden/c04-llm-leeg.jpg new file mode 100644 index 0000000..ba4abdf Binary files /dev/null and b/08-chatflow-studiecoach/beelden/c04-llm-leeg.jpg differ diff --git a/08-chatflow-studiecoach/beelden/c05-context.jpg b/08-chatflow-studiecoach/beelden/c05-context.jpg new file mode 100644 index 0000000..74321d9 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/c05-context.jpg differ diff --git a/08-chatflow-studiecoach/beelden/c06-prompt-popup.jpg b/08-chatflow-studiecoach/beelden/c06-prompt-popup.jpg new file mode 100644 index 0000000..d336b57 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/c06-prompt-popup.jpg differ diff --git a/08-chatflow-studiecoach/beelden/c07-memory.jpg b/08-chatflow-studiecoach/beelden/c07-memory.jpg new file mode 100644 index 0000000..feb8e9e Binary files /dev/null and b/08-chatflow-studiecoach/beelden/c07-memory.jpg differ diff --git a/08-chatflow-studiecoach/beelden/c08-answer-leeg.jpg b/08-chatflow-studiecoach/beelden/c08-answer-leeg.jpg new file mode 100644 index 0000000..0bdf04c Binary files /dev/null and b/08-chatflow-studiecoach/beelden/c08-answer-leeg.jpg differ diff --git a/08-chatflow-studiecoach/beelden/c09-answer-picker.jpg b/08-chatflow-studiecoach/beelden/c09-answer-picker.jpg new file mode 100644 index 0000000..1d91b70 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/c09-answer-picker.jpg differ diff --git a/08-chatflow-studiecoach/beelden/c10-antwoord-uitleg.jpg b/08-chatflow-studiecoach/beelden/c10-antwoord-uitleg.jpg new file mode 100644 index 0000000..ce356c2 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/c10-antwoord-uitleg.jpg differ diff --git a/08-chatflow-studiecoach/beelden/d01-class2-plus.jpg b/08-chatflow-studiecoach/beelden/d01-class2-plus.jpg new file mode 100644 index 0000000..84a4607 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/d01-class2-plus.jpg differ diff --git a/08-chatflow-studiecoach/beelden/d02-llm2.jpg b/08-chatflow-studiecoach/beelden/d02-llm2.jpg new file mode 100644 index 0000000..bb12298 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/d02-llm2.jpg differ diff --git a/08-chatflow-studiecoach/beelden/d03-hint-prompt.jpg b/08-chatflow-studiecoach/beelden/d03-hint-prompt.jpg new file mode 100644 index 0000000..ceff223 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/d03-hint-prompt.jpg differ diff --git a/08-chatflow-studiecoach/beelden/d04-hint-memory.jpg b/08-chatflow-studiecoach/beelden/d04-hint-memory.jpg new file mode 100644 index 0000000..328ce42 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/d04-hint-memory.jpg differ diff --git a/08-chatflow-studiecoach/beelden/d05-answer2.jpg b/08-chatflow-studiecoach/beelden/d05-answer2.jpg new file mode 100644 index 0000000..6b9882f Binary files /dev/null and b/08-chatflow-studiecoach/beelden/d05-answer2.jpg differ diff --git a/08-chatflow-studiecoach/beelden/d06-class3-plus.jpg b/08-chatflow-studiecoach/beelden/d06-class3-plus.jpg new file mode 100644 index 0000000..2809c06 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/d06-class3-plus.jpg differ diff --git a/08-chatflow-studiecoach/beelden/d07-llm3.jpg b/08-chatflow-studiecoach/beelden/d07-llm3.jpg new file mode 100644 index 0000000..2dd5238 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/d07-llm3.jpg differ diff --git a/08-chatflow-studiecoach/beelden/d08-planning-prompt.jpg b/08-chatflow-studiecoach/beelden/d08-planning-prompt.jpg new file mode 100644 index 0000000..943ee2b Binary files /dev/null and b/08-chatflow-studiecoach/beelden/d08-planning-prompt.jpg differ diff --git a/08-chatflow-studiecoach/beelden/d09-planning.jpg b/08-chatflow-studiecoach/beelden/d09-planning.jpg new file mode 100644 index 0000000..07e01f7 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/d09-planning.jpg differ diff --git a/08-chatflow-studiecoach/beelden/d10-answer3.jpg b/08-chatflow-studiecoach/beelden/d10-answer3.jpg new file mode 100644 index 0000000..c8e6f64 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/d10-answer3.jpg differ diff --git a/08-chatflow-studiecoach/beelden/d11-overzicht.jpg b/08-chatflow-studiecoach/beelden/d11-overzicht.jpg new file mode 100644 index 0000000..b73c297 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/d11-overzicht.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e01-class4-plus.jpg b/08-chatflow-studiecoach/beelden/e01-class4-plus.jpg new file mode 100644 index 0000000..7a118c6 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e01-class4-plus.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e02-human-input.jpg b/08-chatflow-studiecoach/beelden/e02-human-input.jpg new file mode 100644 index 0000000..59f9348 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e02-human-input.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e03-delivery.jpg b/08-chatflow-studiecoach/beelden/e03-delivery.jpg new file mode 100644 index 0000000..03d84bd Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e03-delivery.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e04-email-leeg.jpg b/08-chatflow-studiecoach/beelden/e04-email-leeg.jpg new file mode 100644 index 0000000..cc9f104 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e04-email-leeg.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e05-email-ingevuld.jpg b/08-chatflow-studiecoach/beelden/e05-email-ingevuld.jpg new file mode 100644 index 0000000..4810697 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e05-email-ingevuld.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e06-email-debug.jpg b/08-chatflow-studiecoach/beelden/e06-email-debug.jpg new file mode 100644 index 0000000..5bf8901 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e06-email-debug.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e07-form-hint.jpg b/08-chatflow-studiecoach/beelden/e07-form-hint.jpg new file mode 100644 index 0000000..a028f9c Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e07-form-hint.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e08-input-field.jpg b/08-chatflow-studiecoach/beelden/e08-input-field.jpg new file mode 100644 index 0000000..debb729 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e08-input-field.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e09-form-klaar.jpg b/08-chatflow-studiecoach/beelden/e09-form-klaar.jpg new file mode 100644 index 0000000..2e43667 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e09-form-klaar.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e10-user-action.jpg b/08-chatflow-studiecoach/beelden/e10-user-action.jpg new file mode 100644 index 0000000..89cff2f Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e10-user-action.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e11-output-vars.jpg b/08-chatflow-studiecoach/beelden/e11-output-vars.jpg new file mode 100644 index 0000000..5b1f626 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e11-output-vars.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e12-docent.jpg b/08-chatflow-studiecoach/beelden/e12-docent.jpg new file mode 100644 index 0000000..16fb7a0 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e12-docent.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e13-answer4-picker.jpg b/08-chatflow-studiecoach/beelden/e13-answer4-picker.jpg new file mode 100644 index 0000000..2f58095 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e13-answer4-picker.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e14-geen-reactie.jpg b/08-chatflow-studiecoach/beelden/e14-geen-reactie.jpg new file mode 100644 index 0000000..8d81762 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e14-geen-reactie.jpg differ diff --git a/08-chatflow-studiecoach/beelden/e15-hele-flow.jpg b/08-chatflow-studiecoach/beelden/e15-hele-flow.jpg new file mode 100644 index 0000000..e421b8d Binary files /dev/null and b/08-chatflow-studiecoach/beelden/e15-hele-flow.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f01-preview-running.jpg b/08-chatflow-studiecoach/beelden/f01-preview-running.jpg new file mode 100644 index 0000000..9180a74 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f01-preview-running.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f02-uitleg.jpg b/08-chatflow-studiecoach/beelden/f02-uitleg.jpg new file mode 100644 index 0000000..dce7c61 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f02-uitleg.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f03-hint.jpg b/08-chatflow-studiecoach/beelden/f03-hint.jpg new file mode 100644 index 0000000..54a1036 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f03-hint.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f04-planning.jpg b/08-chatflow-studiecoach/beelden/f04-planning.jpg new file mode 100644 index 0000000..fb9dce4 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f04-planning.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f05-docent-form.jpg b/08-chatflow-studiecoach/beelden/f05-docent-form.jpg new file mode 100644 index 0000000..e0fd4d8 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f05-docent-form.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f06-docent-ingevuld.jpg b/08-chatflow-studiecoach/beelden/f06-docent-ingevuld.jpg new file mode 100644 index 0000000..4236560 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f06-docent-ingevuld.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f07-docent-antwoord.jpg b/08-chatflow-studiecoach/beelden/f07-docent-antwoord.jpg new file mode 100644 index 0000000..9c589e8 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f07-docent-antwoord.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f08-publish.jpg b/08-chatflow-studiecoach/beelden/f08-publish.jpg new file mode 100644 index 0000000..1cd934b Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f08-publish.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f09-toegangspunt.jpg b/08-chatflow-studiecoach/beelden/f09-toegangspunt.jpg new file mode 100644 index 0000000..5c8befe Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f09-toegangspunt.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f10-features.jpg b/08-chatflow-studiecoach/beelden/f10-features.jpg new file mode 100644 index 0000000..28525fc Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f10-features.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f11-opener.jpg b/08-chatflow-studiecoach/beelden/f11-opener.jpg new file mode 100644 index 0000000..b83a21b Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f11-opener.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f12-webapp-start.jpg b/08-chatflow-studiecoach/beelden/f12-webapp-start.jpg new file mode 100644 index 0000000..b1a4c14 Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f12-webapp-start.jpg differ diff --git a/08-chatflow-studiecoach/beelden/f13-webapp-antwoord.jpg b/08-chatflow-studiecoach/beelden/f13-webapp-antwoord.jpg new file mode 100644 index 0000000..12a68ec Binary files /dev/null and b/08-chatflow-studiecoach/beelden/f13-webapp-antwoord.jpg differ diff --git a/08-chatflow-studiecoach/build.py b/08-chatflow-studiecoach/build.py new file mode 100644 index 0000000..7f328fe --- /dev/null +++ b/08-chatflow-studiecoach/build.py @@ -0,0 +1,4 @@ +import runpy, sys +from pathlib import Path +sys.argv = ["build_handleiding.py", str(Path(__file__).resolve().parent / "handleiding-dify-studiecoach.md")] +runpy.run_path(str(Path(__file__).resolve().parent.parent / "_gereedschap" / "build_handleiding.py"), run_name="__main__") diff --git a/08-chatflow-studiecoach/handleiding-dify-studiecoach.md b/08-chatflow-studiecoach/handleiding-dify-studiecoach.md new file mode 100644 index 0000000..3204c32 --- /dev/null +++ b/08-chatflow-studiecoach/handleiding-dify-studiecoach.md @@ -0,0 +1,581 @@ + + +# Een studiecoach voor je vak: Chatflow met geheugen, routes en een mens in de lus + +**Handleiding 8 bij de workshop AI Agents** +LeX Consultancy B.V. · 20 september 2026 + +Tot nu toe ging het over de organisatie van de school. Deze handleiding gaat over de les. Je bouwt een **Studiecoach biologie** voor 3 havo, thema Ecologie: een chat waarmee een leerling de stof kan doorvragen, de planning kan checken en hulp kan vragen bij opdrachten, zonder dat de coach de antwoorden voorzegt. En als een leerling iets persoonlijks schrijft, gaat het bericht naar de docent, die zelf antwoordt. + +Daarvoor gebruik je de appvorm **Chatflow**: het workflow-canvas dat je kent, maar dan als gesprek. Drie dingen zijn nieuw: + +| Nieuw | Wat het doet | Waar | +| --- | --- | --- | +| **Question Classifier** | Herkent wat voor vraag de leerling stelt en stuurt hem een andere kant op | Stap 6 | +| **Memory** | De coach onthoudt het gesprek, zodat "en waarom is dat zo?" werkt | Stap 9 | +| **Human Input** | De workflow stopt, mailt de docent, en gaat verder met wat de docent invult | Deel E | + +De vier routes: + +| Soort vraag | Route | Voorbeeld | +| --- | --- | --- | +| Begripsvraag | Kennisbank (lesbrief) → uitleg met controlevraag | "Wat is het verschil tussen een voedselketen en een voedselweb?" | +| Huiswerkvraag | Geen antwoord, wel een hint en een tegenvraag | "Wat is het antwoord op opdracht 5?" | +| Planningsvraag | Kennisbank (studiewijzer) → concreet antwoord | "Wanneer is de toets en wat moet ik kennen?" | +| Persoonlijk of zorgelijk | Docent krijgt een mail, leerling krijgt het antwoord van de docent | "Ik snap er niks van en durf het niet te vragen" | + +Deze handleiding volgt de cloudversie van Dify van 20 september 2026, op een Professional-account. Op een sandbox-account werkt alles hetzelfde; alleen upload je de documenten één voor één. + +**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 | + +--- + +## Voorbereiding: het lesmateriaal + +Bij deze handleiding zitten drie documenten: + +| Bestand | Wat het is | Herkomst | +| --- | --- | --- | +| `lesbrief-ecologie.pdf` | Vijf paragrafen lesstof, twaalf opdrachten, begrippenlijst (5 pp.) | Zelf geschreven, fictief, vrij te gebruiken | +| `studiewijzer-biologie-3havo-ecologie.pdf` | Leerdoelen, planning per week, toetsdatum, steunles, AI-regels (3 pp.) | Zelf geschreven, fictief | +| `stercollectie-voedselweb-hv3.pdf` | De module *Voedselweb en voedselketen hv3* uit de Stercollectie biologie: kennistest, video-opdrachten, wormenbak, Oostvaardersplassen, begrippenlijst, examenopgaven (18 pp.) | VO-content via Wikiwijs, licentie CC BY-SA 4.0, maken.wikiwijs.nl/157495 | + +Het derde document is echt open lesmateriaal. De licentie CC BY-SA (naamsvermelding, gelijk delen) betekent: je mag het gebruiken, in een kennisbank zetten en bewerken, als je de bron noemt en wat je ervan maakt onder dezelfde licentie deelt. De studiewijzer noemt de module als extra oefenmateriaal, zodat de coach er ook naar kan verwijzen. + +> **Zelf kiezen: jouw vak, jouw materiaal.** Vervang de drie documenten door die van jouw vak: je eigen studiewijzer (dat is het belangrijkste document, daar staan de afspraken), een lesbrief of samenvatting die je zelf schreef, en eventueel een open module van je vak. Let op met methodemateriaal van een uitgever: dat mag je meestal niet uploaden naar een externe dienst. Stercollecties (VO-content), Wikiwijs-arrangementen en materiaal van je eigen sectie mag wel. Geen scans, geen namen van leerlingen. + +--- + +## Deel A. De kennisbank + +### Stap 1. Maak de kennisbank met de documenten + +1. **Knowledge** → **Create** (of **Een gebruiksklare kennisbank maken**). +2. Klik op **Browse** en kies de lesbrief en de studiewijzer. Op een Professional-account kun je meerdere bestanden tegelijk kiezen; in de sandbox één per keer (daarna **Add file**). + +![Twee bestanden klaar voor upload](beelden/a01-upload-twee.jpg) + +3. **Next**. +4. Zet **Delimiter** op `\n\n` en klik op **Preview Chunk**. De lesbrief valt uiteen in veertien stukken van ongeveer duizend tekens: elk stuk is een alinea met echte inhoud. + +![De standaardinstelling: Delimiter \n](beelden/a02-chunk.jpg) + +![Na de aanpassing: veertien stukken met inhoud](beelden/a03-preview.jpg) + +5. Scroll naar beneden, laat de rest staan, en klik op **Save & Process**. + +![Kennisbank aangemaakt, embedding loopt](beelden/a04-created.jpg) + +### Stap 2. Naam en beschrijving + +1. **Settings** in het linkermenu. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| Knowledge Name | `Biologie 3 havo ecologie` | +| Description | zie het kader; maximaal 400 tekens | + +``` +Lesmateriaal biologie 3 havo, thema Ecologie (Het Voorbeeldcollege). Lesbrief: populatie, ecosysteem, biotische en abiotische factoren, voedselketens en -webben, producenten en consumenten, koolstofkringloop, eutrofiëring, draagkracht, predatie, biodiversiteit, natuurbeheer, opdrachten 1-12, begrippenlijst. Studiewijzer: leerdoelen, planning, huiswerk, toets, steunles, AI-regels, contact. +``` + +![Naam en beschrijving](beelden/a05-settings.jpg) + +2. Scroll naar beneden en klik op **Save**. + +> De beschrijving mag maximaal 400 tekens zijn. Is hij langer, dan krijg je rechtsboven "Modified unsuccessfully" en wordt er niets opgeslagen. Dify zegt er niet bij waarom. + +### Stap 3. Voeg de Stercollectie toe + +1. **Documents** → **Add file** → kies `stercollectie-voedselweb-hv3.pdf` → **Next** → Delimiter `\n\n` → **Save & Process**. + +Via de drie puntjes achter een document kun je het ook hernoemen, downloaden of verwijderen; zo vervang je later een verouderde studiewijzer. + +![Het menu achter een document](beelden/a06-doc-menu.jpg) + +![Drie documenten, allemaal Available](beelden/a07-drie-documenten.jpg) + +--- + +## Deel B. De Chatflow en de vraagherkenning + +### Stap 4. Maak de Chatflow + +1. **Studio** → **Create** → **Create from Blank** → kaart **Chatflow**. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| App Name & Icon | `Studiecoach biologie` | + +![Create from Blank: Chatflow](beelden/b01-create-chatflow.jpg) + +2. **Create**. Dify zet alvast een standaardflow neer: User Input → LLM → Answer. + +![De standaardflow van een nieuwe Chatflow](beelden/b02-standaard-flow.jpg) + +### Stap 5. Ruim de standaardflow op + +Die twee blokken passen niet in ons plan; we bouwen alles zelf. + +1. Klik op **Answer** → drie puntjes in het paneel → **Delete**. +2. Klik op **LLM** → drie puntjes → **Delete**. + +![Het menu met Delete](beelden/b03-delete-llm.jpg) + +![Alleen User Input over; de invoer is sys.query, de vraag van de leerling](beelden/b04-leeg-canvas.jpg) + +### Stap 6. De Question Classifier + +1. Bij **User Input** → **Select next step** → onder Question Understand: **Question Classifier**. + +![Het classifier-blok, met twee lege klassen](beelden/b05-classifier.jpg) + +2. **MODEL**: gpt-5-mini. **INPUT VARIABLES** staat al op **User Input / sys.query**. +3. Vul **CLASS 1** en **CLASS 2** in, klik twee keer op **+ Add Class** en vul ook 3 en 4 in. Een klasse is een beschrijving in gewone taal; het model kiest de best passende. + +**Class 1** +``` +Begripsvraag: de leerling wil iets uit de lesstof begrijpen of uitgelegd krijgen, bijvoorbeeld wat een begrip betekent, hoe iets werkt, waarom iets zo is, of een voorbeeld. +``` + +**Class 2** +``` +Huiswerkvraag: de leerling vraagt het antwoord op een opdracht, oefening of toetsvraag, of wil dat het huiswerk gemaakt of nagekeken wordt. +``` + +**Class 3** +``` +Planningsvraag: de leerling vraagt naar de toets, de datum, wat er geleerd moet worden, het huiswerk voor een bepaalde les, de steunles, het practicum of andere afspraken uit de studiewijzer. +``` + +**Class 4** +``` +Persoonlijk of zorgelijk: de leerling schrijft over zichzelf, bijvoorbeeld dat het niet lukt, stress, faalangst, problemen thuis of in de klas, ziekte, gepest worden, of wil met de docent of mentor praten. Ook alles wat niet over biologie gaat. +``` + +![Class 1 ingevuld](beelden/b06-class1.jpg) + +![Class 2](beelden/b07-class2.jpg) + +![Add Class: een derde klasse](beelden/b08-class3.jpg) + +![Class 4](beelden/b09-class4.jpg) + +4. Scroll naar **NEXT STEP**: elke klasse heeft nu een eigen uitgang. + +![Vier uitgangen, nog leeg](beelden/b10-vier-takken.jpg) + +> De laatste klasse eindigt met "Ook alles wat niet over biologie gaat". Dat is bewust: alles wat nergens past, komt zo bij een mens terecht in plaats van bij een model dat toch een antwoord verzint. Zet je vangnet altijd in de klasse die naar een mens gaat. + +> **Zelf kiezen: de klassen.** Dit zijn de vragen die een leerling aan jou stelt in de les. Wil je een aparte route voor "overhoor mij" (de coach stelt vragen uit de begrippenlijst)? Of voor "geef me een samenvatting van paragraaf 3"? Voeg een klasse toe en bouw er een tak bij zoals in deel C. Hou het bij vier tot zes klassen; hoe meer klassen, hoe vaker het model twijfelt. + +--- + +## Deel C. Route 1: uitleg uit de lesbrief + +### Stap 7. Knowledge Retrieval + +1. Onder **CLASS 1**: **Select next step** → **Knowledge Retrieval**. De **QUERY TEXT** staat al op **sys.query**. + +![Knowledge Retrieval, nog zonder kennisbank](beelden/c01-kr.jpg) + +2. **+** bij KNOWLEDGE → **Biologie 3 havo ecologie** → **Add**. + +![Select reference Knowledge](beelden/c02-select-knowledge.jpg) + +![Gekoppeld](beelden/c03-kr-gekoppeld.jpg) + +### Stap 8. Het LLM-blok Uitleg + +1. **Select next step** → **LLM**. Model **gpt-5-mini**. + +![Het lege LLM-blok](beelden/c04-llm-leeg.jpg) + +2. **CONTEXT** → **Knowledge Retrieval / result**. + +![Context gezet; Dify herinnert je eraan dat hij ook in de prompt moet](beelden/c05-context.jpg) + +3. Prompt in **SYSTEM** (bij `{Context}`: schuine streep, **Context** onderaan het menu): + +``` +Je bent de studiecoach biologie van Het Voorbeeldcollege voor leerlingen van 3 havo. Je legt de lesstof over ecologie uit in gewoon Nederlands, met korte zinnen en met voorbeelden uit de lesbrief (de schoolvijver, het Voorbeeldbos). + +Regels: +- Gebruik alleen de lesstof hieronder. Staat het antwoord er niet in, zeg dat dan en verwijs naar de docent of de steunles. +- Spreek de leerling aan met je. Maximaal acht zinnen. +- Eindig met één korte controlevraag waarmee de leerling kan checken of hij het snapt. +- Geef geen antwoorden op opdrachten uit de lesbrief; leg het begrip uit en laat de leerling de opdracht zelf maken. + +Lesstof: {Context} +``` + +![De prompt, met het menu na een schuine streep](beelden/c06-prompt-popup.jpg) + +### Stap 9. Zet het geheugen aan + +In een Chatflow heeft een LLM-blok een **USER**-bericht (standaard de vraag van de leerling, sys.query) en een schakelaar **MEMORY**. Zonder geheugen ziet het model elke vraag als de eerste. + +1. Scroll naar **MEMORY** en zet de schakelaar aan. Laat **Window size** uit (dan gaat het hele gesprek mee). +2. Hernoem het blok naar `Uitleg`. + +![Memory aan; het USER-bericht bevat de vraag van de leerling](beelden/c07-memory.jpg) + +> Vergeet je Memory, dan werkt "en waarom is dat zo?" niet: het model weet niet waar "dat" naar verwijst. Zet Memory alleen aan op de blokken die met de leerling praten, niet op blokken die alleen iets moeten controleren. + +### Stap 10. Answer + +In een Chatflow heet de uitgang niet Output maar **Answer**: dat is wat de leerling in de chat te zien krijgt. + +1. **Select next step** → **Answer**. + +![Het lege Answer-blok](beelden/c08-answer-leeg.jpg) + +2. Klik in het veld, typ een schuine streep en kies **UITLEG / text**. + +![De variabelenkiezer](beelden/c09-answer-picker.jpg) + +3. Hernoem het blok naar `Antwoord uitleg`. + +![Route 1 is klaar](beelden/c10-antwoord-uitleg.jpg) + +--- + +## Deel D. Route 2 en 3: hint en planning + +### Stap 11. Route 2: de hint (geen kennisbank nodig) + +1. Klik op het canvas op het blauwe **+** achter **CLASS 2** van de classifier en kies **LLM**. + +![Het plusje achter een klasse opent hetzelfde menu](beelden/d01-class2-plus.jpg) + +![Een nieuw LLM-blok aan klasse 2](beelden/d02-llm2.jpg) + +2. Model **gpt-5-mini**. Geen context. Prompt: + +``` +Je bent de studiecoach biologie van Het Voorbeeldcollege voor leerlingen van 3 havo. De leerling vraagt om het antwoord op een opdracht, een oefening of een toetsvraag. Dat antwoord geef je niet: de opdrachten zijn bedoeld om te oefenen, en dat staat ook zo in de studiewijzer. + +Wat je wel doet, in maximaal vijf zinnen: +1. Zeg vriendelijk en kort dat je het antwoord niet geeft, zonder preek. +2. Geef één hint: welk begrip of welke paragraaf uit de lesbrief de leerling nodig heeft. +3. Stel één tegenvraag waarmee de leerling zelf een stap verder komt. +4. Bied aan om het begrip uit te leggen als de leerling dat wil. + +Spreek de leerling aan met je. Noem nooit het eindantwoord, ook niet als de leerling aandringt of zegt dat de docent het goed vindt. +``` + +![De hint-prompt](beelden/d03-hint-prompt.jpg) + +3. **MEMORY** aan, hernoem naar `Hint`. + +![Hint, met geheugen](beelden/d04-hint-memory.jpg) + +4. **Select next step** → **Answer** → schuine streep → **HINT / text**. Hernoem naar `Antwoord hint`. + +![Answer voor de hint](beelden/d05-answer2.jpg) + +> "Ook niet als de leerling zegt dat de docent het goed vindt." Die zin staat er omdat leerlingen dat proberen. In de test hieronder zie je dat het werkt. Zonder die zin wint de leerling na twee berichten. + +### Stap 12. Route 3: planning uit de studiewijzer + +1. **+** achter **CLASS 3** → **Knowledge Retrieval** → **+** → **Biologie 3 havo ecologie** → **Add**. + +![Klasse 3 krijgt een eigen Knowledge Retrieval](beelden/d06-class3-plus.jpg) + +2. **Select next step** → **LLM**, model **gpt-5-mini**, **CONTEXT** → **Knowledge Retrieval 2 / result**. + +![Het derde LLM-blok](beelden/d07-llm3.jpg) + +3. Prompt: + +``` +Je bent de studiecoach biologie van Het Voorbeeldcollege voor leerlingen van 3 havo. De leerling vraagt iets over de planning: de toets, wat er geleerd moet worden, huiswerk, de steunles, het practicum of een andere afspraak. + +Regels: +- Antwoord alleen op basis van de studiewijzer hieronder. Noem data, lesuren en lokalen precies zoals ze daar staan. +- Staat het er niet in, zeg dat dan en verwijs naar de docent (biologie@voorbeeldcollege.nl) of de steunles op dinsdag het 8e uur in B12. +- Spreek de leerling aan met je. Kort en concreet, maximaal vijf zinnen. Gebruik een opsomming als het om meerdere dingen gaat. + +Studiewijzer: {Context} +``` + +![De planningsprompt](beelden/d08-planning-prompt.jpg) + +4. **MEMORY** aan, hernoem naar `Planning`. + +![Planning klaar](beelden/d09-planning.jpg) + +5. **Answer** → **PLANNING / text**, hernoem naar `Antwoord planning`. + +![De derde Answer](beelden/d10-answer3.jpg) + +Zo ziet het canvas er nu uit: + +![Drie routes klaar, klasse 4 nog leeg](beelden/d11-overzicht.jpg) + +> Waarom twee keer dezelfde kennisbank? Omdat elk blok zijn eigen zoekvraag en eigen prompt heeft. Route 1 zoekt in de lesstof en legt uit, route 3 zoekt dezelfde kennisbank af maar de prompt kijkt alleen naar de studiewijzer. Op een Professional-account kun je ook twee kennisbanken maken (lesstof en planning apart); dat is netter, maar in de sandbox kost het je een kennisbank die je misschien nodig hebt. + +--- + +## Deel E. Route 4: een mens in de lus + +Dit is het stuk dat een studiecoach verantwoord maakt. Een leerling die schrijft "ik snap er niks van en iedereen lacht me uit" heeft geen model nodig maar een docent. Het blok **Human Input** stopt de workflow, stuurt de docent een mail met een formulier, en gaat pas verder als de docent iets heeft ingevuld. De leerling krijgt intussen een eerlijk bericht. + +### Stap 13. Human Input + +1. **+** achter **CLASS 4** → onder Logic: **Human Input**. + +![Het menu bij klasse 4](beelden/e01-class4-plus.jpg) + +![Het lege Human Input-blok: bezorgmethode, formulier, acties, time-out](beelden/e02-human-input.jpg) + +2. **DELIVERY METHOD** → **+** → **Email**. (Webapp toont het formulier aan de leerling zelf; Slack, Teams en Discord komen nog.) + +![De bezorgmethoden](beelden/e03-delivery.jpg) + +3. Klik op **Not configured** achter Email en vul het mailbericht in. + +![De lege e-mailconfiguratie](beelden/e04-email-leeg.jpg) + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| Subject | `Studiecoach biologie: een leerling heeft je nodig` | +| Body | zie kader; laat het blokje **Request URL** staan, dat wordt de link naar het formulier | +| Recipient | `biologie@voorbeeldcollege.nl` (bij het testen: je eigen adres, zie hieronder) | +| Debug Mode | **aan** | + +``` +Een leerling van 3 havo stelde de Studiecoach een persoonlijke vraag die de coach niet zelf beantwoordt. Lees het gesprek en schrijf een kort antwoord; dat krijgt de leerling in de chat te zien. Reageer via deze link: +``` + +![Onderwerp, tekst, ontvanger en Debug Mode](beelden/e05-email-ingevuld.jpg) + +4. **Save**. Zet daarna de schakelaar achter **Email** aan. + +![Email staat aan, in debugstand](beelden/e06-email-debug.jpg) + +> **Debug Mode** stuurt de mail alleen naar het adres van je eigen Dify-account, niet naar de ontvanger. Zo test je zonder dat er mail naar een collega of naar een verzonnen adres gaat. Zet hem uit als de app echt in gebruik gaat. + +### Stap 14. Het formulier voor de docent + +1. Klik in **FORM CONTENT**. Onderin staat de hint: `/` voegt een variabele in, `Ctrl /` een invoerveld. + +![De hint onder het formulierveld](beelden/e07-form-hint.jpg) + +2. Typ `Bericht van de leerling: ` en dan `/` → **USER INPUT / query**. +3. Twee keer Enter, typ `Jouw antwoord aan de leerling (dit komt letterlijk in de chat): ` en druk op **Ctrl+/**. +4. In het venster **Insert Input Field**: Field Type **Paragraph**, **Save Response As** `antwoord_docent`, **Insert**. + +![Insert Input Field](beelden/e08-input-field.jpg) + +![Het formulier: de vraag van de leerling en een antwoordveld](beelden/e09-form-klaar.jpg) + +5. **USER ACTIONS** → **+**. Dit wordt de knop onder het formulier. + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| action id | `verstuur` | +| Button Text | `Verstuur aan de leerling` | + +![De knop](beelden/e10-user-action.jpg) + +6. Klap **OUTPUT VARIABLES** open: `antwoord_docent` is nu een variabele die de rest van de workflow kan gebruiken. + +![De uitvoervariabelen van Human Input](beelden/e11-output-vars.jpg) + +7. Hernoem het blok naar `Docent`. Laat **TIMEOUT** op 3 dagen. + +![Docent, met twee uitgangen: VERSTUUR en TIMEOUT](beelden/e12-docent.jpg) + +### Stap 15. Drie berichten aan de leerling + +Het blok Docent heeft twee uitgangen: **VERSTUUR** (de docent klikte op de knop) en **TIMEOUT** (drie dagen niets). Daarnaast wil je dat de leerling meteen iets te lezen krijgt, nog voordat de docent reageert. + +1. **+** achter **VERSTUUR** → **Answer**. Typ twee keer Enter, `Bericht van je docent:`, twee keer Enter, `/` → **DOCENT / antwoord_docent**. Hernoem naar `Antwoord docent`. + +![De variabelen van Docent in de kiezer](beelden/e13-answer4-picker.jpg) + +2. **+** achter **TIMEOUT** → **Answer**: + +``` +Je docent heeft nog niet kunnen reageren. Je bericht is niet verloren: spreek je docent of mentor morgen even aan, of mail naar biologie@voorbeeldcollege.nl. Gaat het echt niet goed met je? Praat dan vandaag nog met iemand thuis of op school, of bel of chat met De Kindertelefoon (0800-0432). +``` + +Hernoem naar `Geen reactie`. + +![Geen reactie](beelden/e14-geen-reactie.jpg) + +3. Klik op de classifier, scroll naar **NEXT STEP**, en klik onder **CLASS 4** op **ADD PARALLEL NODE** → **Answer**: + +``` +Dank je dat je dit vertelt. Dit is iets voor een mens, niet voor mij. Ik heb je bericht doorgestuurd naar je docent biologie; zodra die reageert, zie je het antwoord hier in de chat. Wil je nu meteen met iemand praten? Ga naar je mentor, of bel of chat met De Kindertelefoon (0800-0432, gratis en anoniem). +``` + +Hernoem naar `Doorgestuurd`. Een parallel blok draait tegelijk met Docent: de leerling ziet dit bericht direct, terwijl de workflow op de docent wacht. + +![De complete Studiecoach](beelden/e15-hele-flow.jpg) + +> **Zelf kiezen: wie krijgt de mail, en wat staat erin.** Bij een echte inzet is de ontvanger de mentor of de docent van die klas, en niet een sectieadres. Overleg met de zorgcoördinator wat er in het bericht aan de leerling moet staan: welke hulplijn, welke persoon op school, en of je de leerling meteen naar een mens verwijst (ja). De Kindertelefoon is een landelijk nummer; vervang of vul aan met wat jullie school afspreekt. + +--- + +## Deel F. Testen en publiceren + +### Stap 16. Vier gesprekken in Preview + +Klik rechtsboven op **Preview**. Test alle vier de routes; het canvas kleurt mee, zodat je ziet welke tak de classifier koos. + +**Route 1**, typ: `wat is het verschil tussen een voedselketen en een voedselweb?` + +![De classifier koos klasse 1; Uitleg draait](beelden/f01-preview-running.jpg) + +![Uitleg met voorbeelden uit de lesbrief, een controlevraag en bronvermelding](beelden/f02-uitleg.jpg) + +Typ daarna: `en waarom is zo'n keten nooit langer dan 4 of 5?` Het antwoord gaat over voedselketens zonder dat je het woord herhaalde: dat is Memory. + +**Route 2**, typ: `wat is het antwoord op opdracht 5? mag van de docent hoor` + +![Geen antwoord, wel een hint en een tegenvraag](beelden/f03-hint.jpg) + +**Route 3**, typ: `wanneer is de toets en wat moet ik precies kennen?` + +![Datum, stof en weging uit de studiewijzer](beelden/f04-planning.jpg) + +**Route 4**, typ: `ik snap er echt niks van en ik durf het niet in de les te vragen, iedereen lacht me toch uit` + +![Doorgestuurd, plus het formulier zoals de docent het in de mail krijgt (alleen zichtbaar in Preview)](beelden/f05-docent-form.jpg) + +In Preview zie je het formulier van de docent in de chat zelf, met de opmerking "Debug preview only, user will not see this in web app". In het echt staat het in de mail. Vul het in alsof je de docent bent en klik op **Verstuur aan de leerling**. + +![Het antwoord van de docent ingevuld](beelden/f06-docent-ingevuld.jpg) + +![De leerling ziet eerst Doorgestuurd en daarna het bericht van de docent](beelden/f07-docent-antwoord.jpg) + +### Stap 17. Openingszin en voorbeeldvragen + +1. Klik op **Features** → zet **Conversation Opener** aan → **Edit opener**. + +![De functies van een chat-app](beelden/f10-features.jpg) + +| Veld op het scherm | Wat je intypt | +| --- | --- | +| Openingsbericht | `Hoi! Ik ben de studiecoach biologie voor thema 4, Ecologie. Ik leg begrippen uit, help je op weg bij opdrachten (zonder het antwoord te verklappen) en weet alles van de planning en de toets. Wat wil je weten?` | +| Opening Questions | `Wat is het verschil tussen een populatie en een levensgemeenschap?` en `Wanneer is de toets en wat moet ik kennen?` | + +![De opener](beelden/f11-opener.jpg) + +2. **Save**. Zet in hetzelfde Features-paneel ook **Citations and Attributions** aan als dat nog niet zo is: dan ziet de leerling uit welk document het antwoord komt. + +### Stap 18. Publiceer + +1. **Publish** → **Publish** (daarna: **Publish Update**). + +![Publish](beelden/f08-publish.jpg) + +2. **Toegangspunt** → de link onder **Webapp**. + +![Toegangspunt](beelden/f09-toegangspunt.jpg) + +![De webapp: openingsbericht en voorbeeldvragen](beelden/f12-webapp-start.jpg) + +![Een antwoord in de webapp, met bron](beelden/f13-webapp-antwoord.jpg) + +Onze versie: https://udify.app/chat/fP0TJW3s8IXOj9BO + +--- + +## Controleren of het gelukt is + +- De kennisbank heeft drie documenten met status **Available**; na de tests staat bij **Retrieval count** een getal groter dan 0 +- In Preview kleurt bij elke testvraag precies één tak van de classifier groen +- Een vervolgvraag zonder onderwerp ("en waarom?") krijgt een antwoord over het vorige onderwerp +- Een vraag om het antwoord op een opdracht krijgt een hint, ook na aandringen +- Een persoonlijk bericht levert het bericht Doorgestuurd op, plus (in Preview) het docentformulier, en na invullen het bericht van de docent +- Er is een mail binnengekomen op het adres van je Dify-account met de link naar het formulier + +## Als het misgaat + +| Wat je ziet | Wat er aan de hand is | +| --- | --- | +| "Modified unsuccessfully" bij de kennisbankinstellingen | Beschrijving langer dan 400 tekens | +| De classifier kiest steeds dezelfde klasse | De beschrijvingen lijken te veel op elkaar, of één klasse is te breed. Maak ze concreter en zet voorbeelden erin | +| Een vervolgvraag wordt niet begrepen | Memory staat uit op dat LLM-blok (stap 9) | +| De uitleg negeert de lesbrief | Context wel gezet maar niet in de prompt (`/` → Context), of Knowledge Retrieval niet gekoppeld | +| De coach geeft toch het antwoord op een opdracht | De classifier zag het als begripsvraag. Maak klasse 2 breder ("...of vraagt om de uitwerking, het antwoord of de oplossing") en zet in de Uitleg-prompt de regel over opdrachten erbij (staat er al) | +| Bij Human Input: "No delivery method added" | Email toegevoegd maar de schakelaar erachter staat uit (stap 13.4) | +| Geen mail ontvangen | Debug Mode aan: de mail gaat naar het adres van je Dify-account, niet naar de ontvanger. Kijk ook in spam | +| In de webapp blijft de chat hangen na een persoonlijk bericht | Dat is de bedoeling: de workflow wacht op de docent. De leerling zag intussen Doorgestuurd. Na de time-out komt Geen reactie | +| Twee Answer-blokken met dezelfde tekst in de chat | Een blok is per ongeluk parallel gezet in plaats van in serie. Kijk op het canvas welke lijnen er lopen | +| Het venster Add Input Field gaat niet open | Ctrl+/ werkt alleen als de cursor in FORM CONTENT staat | + +## Beheer en kosten + +- **Logs** bewaren elk gesprek, ook de persoonlijke berichten. Spreek af wie erin mag kijken en hoelang ze bewaard blijven; voor leerlingen gelden de regels van je school en, bij echte inzet, een DPIA. Voor deze oefening met verzonnen gesprekken speelt dat niet. +- **Een gesprek** kost per beurt één classificatie plus één antwoord met gpt-5-mini: met een eigen sleutel ongeveer een halve cent, op Dify-credits ongeveer 7. Human Input kost niets. +- **De studiewijzer verandert** elke periode. Vervang het document (Documents → drie puntjes → Delete, dan Add file) en de coach weet het meteen; de prompts hoef je niet aan te passen. +- **Stercollecties** blijven eigendom van VO-content; bij delen van een bewerking: bron en licentie CC BY-SA 4.0 vermelden. + +--- + +## Maak hem van jou + +Van makkelijk naar moeilijk. + +| Aanpassing | Waar | Moeilijkheid | Wat je ervoor terugkrijgt | +| --- | --- | --- | --- | +| Je eigen studiewijzer | Deel A, document vervangen | makkelijk | Route 3 klopt voor jouw klas | +| Je eigen lesbrief of samenvatting | Deel A | makkelijk | Route 1 legt uit wat jij hebt uitgelegd, in jouw voorbeelden | +| Toon en lengte van de uitleg | Stap 8, prompt | makkelijk | Uitleg op het niveau van jouw leerlingen (mavo 2, vwo 5) | +| Andere openingsvragen | Stap 17 | makkelijk | Leerlingen beginnen met de vragen die jij belangrijk vindt | +| Een vijfde route "Overhoor mij" | Extra klasse, LLM met de begrippenlijst als context, Memory aan | gemiddeld | Zelfstandig oefenen voor de toets | +| Een open module uit je vak erbij | Deel A, stap 3 | gemiddeld | Meer oefenmateriaal; let op de licentie | +| De docentmail naar de mentor van de klas | Stap 13, ontvanger; eventueel een invoerveld "klas" bij User Input en een IF/ELSE | gemiddeld | Het bericht komt bij de juiste persoon | +| Bestanden laten uploaden (foto van een opdracht) | Features → File Upload, plus Vision aan op het LLM-blok | moeilijk | Hulp bij een foto van het schrift; duurder per beurt | + +**Drie opdrachten** + +1. **Bouw hem voor jouw vak.** Vervang de drie documenten door die van jouw vak en klas (studiewijzer verplicht, lesbrief gewenst, open module optioneel). Pas de vier klassebeschrijvingen aan op jouw vak en test de vier routes met vragen die jouw leerlingen echt stellen. Noteer welke vraag verkeerd werd ingedeeld en pas die klasse aan. +2. **Probeer hem te breken.** Vraag als leerling op vijf manieren om het antwoord op een opdracht: smeken, liegen over de docent, de vraag anders formuleren, "ik wil alleen checken of het klopt", in het Engels. Waar gaat het mis? Verbeter de klasse of de Hint-prompt, niet allebei tegelijk. +3. **Loop de menselijke route na met de zorgcoördinator.** Laat de tekst van Doorgestuurd en Geen reactie lezen door iemand van de leerlingzorg. Wat moet erin, wat mag er niet in, naar wie moet de mail? Pas het aan en zet Debug Mode pas uit als dat is afgesproken. + +**Checklist voordat je hem aan leerlingen geeft** + +- [ ] De documenten in de kennisbank mag je uploaden (eigen werk, open licentie, of toestemming) en bevatten geen persoonsgegevens +- [ ] De vier routes zijn getest, inclusief de persoonlijke route met een echte mail naar een echt persoon +- [ ] Er is afgesproken wie de docentmail krijgt, hoe snel die reageert, en wat er gebeurt na de time-out +- [ ] De teksten Doorgestuurd en Geen reactie zijn afgestemd met de leerlingzorg +- [ ] Je bestuur heeft een besluit over AI-tools voor leerlingen (toetsingskader, DPIA); tot die tijd gebruik je de coach alleen zelf of met een testgroep van collega's +- [ ] Debug Mode staat uit en Logs worden volgens afspraak bekeken en opgeschoond +- [ ] Het model staat op gpt-5-mini en je weet wat een gesprek kost + +--- + +## En verder + +De Studiecoach kijkt naar de leerling. Handleiding 6 kijkt naar hetzelfde lesmateriaal vanuit de docent: een agent in de Agent Console die de lesbrief en de Stercollectie-module beoordeelt en aanpast voor leerlingen met dyslexie, NT2 of een ontwikkelingsvoorsprong, en zelf op zoek gaat naar open leermateriaal. diff --git a/08-chatflow-studiecoach/lesbrief-ecologie.pdf b/08-chatflow-studiecoach/lesbrief-ecologie.pdf new file mode 100644 index 0000000..7c1bdad Binary files /dev/null and b/08-chatflow-studiecoach/lesbrief-ecologie.pdf differ diff --git a/08-chatflow-studiecoach/maak_materiaal.py b/08-chatflow-studiecoach/maak_materiaal.py new file mode 100644 index 0000000..e197ae4 --- /dev/null +++ b/08-chatflow-studiecoach/maak_materiaal.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 +"""Maakt het fictieve lesmateriaal voor handleiding 6 en 8 (biologie 3 havo, ecologie): +studiewijzer-biologie-3havo-ecologie.pdf en lesbrief-ecologie.pdf. +Alles is verzonnen: school, docenten, data, mailadressen. Gebruik: python3 maak_materiaal.py +Vereist google-chrome (headless) en python3-markdown.""" +import shutil +import subprocess +from pathlib import Path + +import markdown + +HERE = Path(__file__).resolve().parent +CSS = """ +@page { size: A4; margin: 2cm; } +body { font-family: "Noto Sans", "DejaVu Sans", Arial, sans-serif; font-size: 11pt; line-height: 1.45; + color: #1a1a1a; max-width: 17cm; margin: 0 auto; } +h1 { font-size: 20pt; margin: 0 0 .2em; } h2 { font-size: 14pt; margin: 1.4em 0 .4em; color: #14532d; } +h3 { font-size: 12pt; margin: 1.1em 0 .3em; } +table { border-collapse: collapse; width: 100%; margin: .6em 0; font-size: .95em; } +th, td { border: 1px solid #cbd5e1; padding: .3em .5em; text-align: left; vertical-align: top; } +th { background: #f0fdf4; } +.kop { color: #555; margin-bottom: 1.2em; } +.kader { background: #f0fdf4; border-left: 4px solid #16a34a; padding: .5em .9em; margin: .8em 0; } +""" + +STUDIEWIJZER = """ +# Studiewijzer biologie 3 havo + +

Het Voorbeeldcollege · periode 2, schooljaar 2026-2027 · thema 4: Ecologie · docenten: mevrouw De Boer (3HA, 3HB) en de heer Yilmaz (3HC)

+ +## Waar gaat dit thema over + +In dit thema leer je hoe planten, dieren en hun omgeving met elkaar samenhangen. We beginnen bij de schoolvijver en het Voorbeeldbos achter de school, en eindigen bij de vraag wat mensen doen met ecosystemen en wat daarvan de gevolgen zijn. Het thema duurt zes weken en sluit af met een toets. + +## Leerdoelen + +Aan het eind van dit thema kun je: + +1. de begrippen individu, populatie, levensgemeenschap en ecosysteem uitleggen en met een voorbeeld toelichten; +2. het verschil tussen biotische en abiotische factoren uitleggen en van beide drie voorbeelden geven; +3. een voedselketen en een voedselweb tekenen en daarin producenten, consumenten en reducenten aanwijzen; +4. uitleggen waarom er in een voedselketen zelden meer dan vier of vijf schakels zijn; +5. de koolstofkringloop in grote lijnen beschrijven en de rol van fotosynthese en verbranding daarin benoemen; +6. uitleggen wat draagkracht is en welke factoren de grootte van een populatie beïnvloeden; +7. uitleggen wat biodiversiteit is en waarom die belangrijk is; +8. een mening geven over een ingreep van de mens in een ecosysteem, met argumenten uit dit thema. + +## Planning + +| Week | Les | Onderwerp | Huiswerk voor de volgende les | +| --- | --- | --- | --- | +| 1 | 1 en 2 | Paragraaf 1: Wat is ecologie? Veldwerk bij de schoolvijver | Lesbrief paragraaf 1 lezen, opdracht 1 en 2 | +| 2 | 3 en 4 | Paragraaf 2: Voedselketens en voedselwebben | Opdracht 3, 4 en 5; Stercollectie-module *Voedselweb en voedselketen hv3* stap 1 (Test je kennis) | +| 3 | 5 en 6 | Paragraaf 3: Kringlopen | Opdracht 6 en 7; begrippenlijst tot en met paragraaf 3 leren | +| 4 | 7 en 8 | Paragraaf 4: Populaties en evenwicht. Practicum: watervlooien tellen | Opdracht 8 en 9, practicumverslag inleveren | +| 5 | 9 en 10 | Paragraaf 5: De mens en ecosystemen. Debat over het Voorbeeldbos | Opdracht 10, 11 en 12 | +| 6 | 11 | Herhaling en oefentoets | Alles leren voor de toets | +| 6 | 12 | **Toets thema 4** | | + +## De toets + +- **Wanneer:** donderdag 12 november 2026, in je eigen lesuur. +- **Wat:** de hele lesbrief (paragraaf 1 tot en met 5), de begrippenlijst en de opdrachten 1 tot en met 12. Het practicumverslag telt apart mee. +- **Hoe:** 25 vragen, waarvan 15 meerkeuze en 10 open vragen. Bij open vragen krijg je punten voor de redenering, niet alleen voor het antwoord. Er zit altijd één vraag bij waarin je een voedselweb moet tekenen. +- **Weging:** de toets telt twee keer mee, het practicumverslag één keer. +- **Hulpmiddelen:** geen. Je krijgt de tekeningen van de voedselwebben bij de vragen. + +## Zo leer je dit thema + +- Leer de begrippen niet uit je hoofd als losse woorden, maar met een voorbeeld uit de schoolvijver of het Voorbeeldbos. Op de toets vragen we bijna altijd om een voorbeeld. +- Maak de opdrachten zelf voordat je de antwoorden bekijkt. De opdrachten lijken op de toetsvragen. +- Teken. Voedselwebben en kringlopen onthoud je beter als je ze zelf hebt getekend. +- Snap je iets niet? Vraag het in de les, of kom naar de steunles: dinsdag het 8e uur in lokaal B12, zonder aanmelden. + +## Extra oefenmateriaal + +Naast de lesbrief gebruiken we de open module **Voedselweb en voedselketen hv3** uit de Stercollectie biologie van VO-content (thema Lepelaars). Die staat op maken.wikiwijs.nl/157495 en is vrij te gebruiken onder de licentie CC BY-SA 4.0. In de module zitten een kennistest, video's over vleesproductie en afbraak, een onderzoek met een wormenbak, een voedselweb van de Oostvaardersplassen en examenopgaven. Stap 1 is huiswerk in week 2; de rest is keuzestof voor wie meer wil oefenen. + +## Regels en afspraken + +- Huiswerk maak je in je schrift; foto's van andermans schrift tellen niet. +- Ben je ziek geweest, dan haal je het practicum in tijdens de steunles. Meld dat zelf bij je docent binnen twee schooldagen na terugkomst. +- **AI-hulpmiddelen:** je mag een AI-hulp gebruiken om uitleg te vragen en om jezelf te overhoren. Je mag hem niet gebruiken om de antwoorden op de opdrachten te maken; die opdrachten zijn juist bedoeld om te oefenen. Als je hulp vraagt, vraag dan om een hint of een tegenvraag, niet om het antwoord. +- Vragen buiten de les: mail naar biologie@voorbeeldcollege.nl. Je krijgt binnen twee schooldagen antwoord. Voor persoonlijke zaken ga je naar je mentor. +""" + +LESBRIEF = """ +# Lesbrief Ecologie + +

Biologie 3 havo · thema 4 · Het Voorbeeldcollege · versie september 2026

+ +## Paragraaf 1. Wat is ecologie? + +Ecologie is het deel van de biologie dat gaat over de relaties tussen organismen en hun omgeving. Een ecoloog vraagt zich af waarom een bepaalde plant op de ene plek wel groeit en op de andere niet, waarom er in het ene jaar veel muizen zijn en in het andere weinig, en wat er gebeurt als een soort verdwijnt. + +Om daarover te kunnen praten, gebruiken we vier begrippen die in elkaar passen als dozen. Een **individu** is één organisme: één eend op de schoolvijver. Een **populatie** is een groep individuen van dezelfde soort die op dezelfde plek en in dezelfde tijd leven en zich onderling kunnen voortplanten: alle wilde eenden op en rond de schoolvijver. Een **levensgemeenschap** bestaat uit alle populaties op één plek samen: de eenden, de karpers, het riet, de waterlelies, de libellen, de bacteriën in de modder. Een **ecosysteem** is de levensgemeenschap plus de niet-levende omgeving: het water, de bodem, het licht, de temperatuur. + +Die niet-levende omgeving noemen we de **abiotische factoren**. Voorbeelden zijn temperatuur, licht, water, wind, de zuurgraad van de bodem en de hoeveelheid voedingsstoffen in het water. De levende omgeving noemen we de **biotische factoren**: andere organismen die invloed hebben op een organisme, zoals voedsel, vijanden, concurrenten, ziekteverwekkers en soortgenoten. + +Een voorbeeld. Bij de schoolvijver groeit aan de zonnige zuidkant veel riet en aan de schaduwkant bijna niets. Licht is hier de abiotische factor die het verschil maakt. In het riet broeden meerkoeten; de rietstengels bieden beschutting tegen de reiger. Het riet is voor de meerkoet een biotische factor, en de reiger ook. + +## Paragraaf 2. Voedselketens en voedselwebben + +Elk organisme heeft energie nodig. Planten halen die energie uit zonlicht: met **fotosynthese** maken ze van water en koolstofdioxide glucose en zuurstof. Omdat planten hun eigen voedsel maken, noemen we ze **producenten**. Dieren kunnen dat niet; zij eten planten of andere dieren en heten daarom **consumenten**. Een dier dat planten eet is een consument van de eerste orde, een dier dat planteneters eet een consument van de tweede orde, enzovoort. Schimmels en bacteriën die dode resten afbreken heten **reducenten**. Zij zorgen dat voedingsstoffen terugkomen in de bodem en het water. + +Een **voedselketen** laat zien wie wie eet, in een rij met pijlen. De pijl wijst in de richting waarin de energie gaat. Bij de schoolvijver: waterplant → watervlo → stekelbaars → reiger. De waterplant is de producent, de watervlo een consument van de eerste orde, de stekelbaars van de tweede orde en de reiger van de derde orde. Elke stap in de keten noemen we een **schakel** of trofisch niveau. + +In het echt eet bijna niemand maar één ding. De reiger eet ook kikkers, de stekelbaars eet ook muggenlarven, en de watervlo wordt ook door libellenlarven gegeten. Als je alle voedselketens van een levensgemeenschap door elkaar tekent, krijg je een **voedselweb**. Een voedselweb laat zien hoe soorten van elkaar afhankelijk zijn. Verdwijnen de watervlooien, dan hebben stekelbaars én libellenlarve een probleem, en daarna de reiger. + +Waarom zijn voedselketens zelden langer dan vier of vijf schakels? Omdat bij elke schakel het grootste deel van de energie verloren gaat. Een dier gebruikt de meeste energie uit zijn voedsel om te bewegen, warm te blijven en te ademen; maar een klein deel, ongeveer een tiende, wordt lichaamsmassa die een volgende schakel kan eten. Na vier schakels is er zo weinig energie over dat een vijfde schakel nauwelijks kan bestaan. Daarom zijn er veel meer planten dan planteneters, en veel meer planteneters dan roofdieren. Dat tekenen we als een **piramide van biomassa**. + +## Paragraaf 3. Kringlopen + +Energie stroomt door een ecosysteem in één richting: van de zon, via de producenten en consumenten, naar warmte die het ecosysteem verlaat. Stoffen doen dat niet. Stoffen gaan rond in **kringlopen**. De bekendste is de **koolstofkringloop**. + +Koolstof zit in de lucht als koolstofdioxide (CO₂). Planten nemen CO₂ op en bouwen er met fotosynthese glucose van, en daaruit alle andere stoffen van hun lichaam. Dieren eten planten en krijgen zo de koolstof binnen. Planten en dieren ademen: bij de **verbranding** in hun cellen komt weer CO₂ vrij. Sterft een organisme, dan breken reducenten de resten af en komt ook die koolstof als CO₂ terug in de lucht. De kringloop is rond. + +De mens heeft aan deze kringloop een extra weg toegevoegd. Steenkool, aardolie en aardgas zijn resten van organismen van miljoenen jaren geleden; de koolstof daarin zat lang vast in de bodem. Door die brandstoffen te verbranden brengen we in korte tijd veel koolstof in de lucht die er lang niet was. Daardoor stijgt de hoeveelheid CO₂ in de atmosfeer, en dat versterkt het broeikaseffect. + +Ook stikstof gaat rond in een kringloop. Planten hebben stikstof nodig voor eiwitten en halen die als nitraat uit de bodem. Bacteriën in de bodem maken nitraat uit dode resten en uit stikstofgas in de lucht. Mest en kunstmest brengen extra stikstof in de bodem. Voor een boer is dat handig, maar spoelt het nitraat uit naar een sloot of een vijver, dan gaan daar algen woekeren. Dat heet **eutrofiëring**, en het is een van de redenen dat de schoolvijver in de zomer soms groen kleurt. + +## Paragraaf 4. Populaties en evenwicht + +Hoeveel eenden passen er op de schoolvijver? Niet oneindig veel. Er is een grens aan het voedsel, aan de broedplekken en aan de ruimte. Het maximale aantal individuen van een soort dat een gebied blijvend kan onderhouden, noemen we de **draagkracht** van dat gebied voor die soort. Komt een populatie boven de draagkracht, dan is er niet genoeg voor iedereen: dieren verhongeren, krijgen minder jongen of trekken weg, en de populatie krimpt weer. + +Factoren die een populatie beperken zijn onder meer voedsel, water, ruimte, vijanden, ziekten en het weer. Sommige factoren werken sterker naarmate de populatie groter is: bij veel dieren op een kleine plek verspreidt een ziekte zich sneller en vinden roofdieren makkelijker een prooi. Andere factoren, zoals een strenge winter, treffen een grote en een kleine populatie even hard. + +Populaties beïnvloeden elkaar. **Concurrentie** ontstaat als twee soorten hetzelfde nodig hebben, bijvoorbeeld hetzelfde voedsel of dezelfde nestplek. **Predatie** is de relatie tussen roofdier en prooi. Zijn er veel prooidieren, dan krijgen de roofdieren veel jongen; daardoor daalt het aantal prooidieren, waarna ook het aantal roofdieren weer daalt. Zo schommelen de twee populaties om elkaar heen. In het practicum van week 4 tel je watervlooien in twee bakken, met en zonder stekelbaars, en zie je dit zelf. + +Een ecosysteem waarin de populaties op de lange duur ongeveer gelijk blijven, noemen we in **evenwicht**. Dat evenwicht is niet stil: het schommelt, en het kan verschuiven als een factor blijvend verandert. + +## Paragraaf 5. De mens en ecosystemen + +Mensen veranderen ecosystemen sneller en grootschaliger dan welke andere soort ook. We kappen bos voor landbouw, leggen wegen aan door leefgebieden, brengen mest en bestrijdingsmiddelen in bodem en water, en verplaatsen soorten naar plekken waar ze niet thuishoren. Elk van die ingrepen verandert de abiotische factoren of de biotische factoren van een gebied, en daarmee de levensgemeenschap. + +**Biodiversiteit** is de verscheidenheid aan soorten in een gebied. Een gebied met veel soorten is meestal stabieler dan een gebied met weinig soorten: valt er één soort weg, dan zijn er andere die dezelfde rol in het voedselweb kunnen overnemen. In een maisveld leven weinig soorten; verdwijnt daar de mais door een ziekte, dan is er niets over. In het Voorbeeldbos leven honderden soorten; verdwijnt daar de es door de essentaksterfte, dan blijft het bos bestaan, al verandert het. + +Het Voorbeeldbos is een goed voorbeeld van de keuzes waar mensen voor staan. De gemeente wil een fietspad door het bos aanleggen, zodat leerlingen veiliger naar school kunnen. Natuurliefhebbers zijn bang dat het pad het bos in tweeën deelt en dat reeën en dassen de weg niet meer oversteken. De boeren naast het bos willen dat het bos kleiner wordt, omdat de dassen hun mais eten. In week 5 voeren we hierover een debat. Je krijgt een rol en verdedigt die met argumenten uit dit thema: draagkracht, voedselweb, biodiversiteit, abiotische en biotische factoren. + +**Natuurbeheer** is het bewust ingrijpen in een ecosysteem om het te behouden of te herstellen: maaien op het juiste moment, water vasthouden, een wildtunnel onder een weg, een soort terugbrengen die verdwenen was. Ook niets doen kan natuurbeheer zijn. Welke keuze goed is, hangt af van wat je wilt bereiken, en daarover verschillen mensen van mening. Ecologie geeft geen antwoord op de vraag wat je moet willen, maar wel op de vraag wat er gebeurt als je iets doet. + +## Opdrachten + +1. Geef van de schoolvijver één voorbeeld van een individu, een populatie, een levensgemeenschap en een ecosysteem. +2. Noem drie abiotische en drie biotische factoren die invloed hebben op het riet aan de schoolvijver. +3. Teken de voedselketen uit paragraaf 2 en zet bij elke schakel of het een producent of een consument is, en van welke orde. +4. Teken een voedselweb van de schoolvijver met minstens zes soorten uit deze lesbrief. +5. Leg met het begrip energie uit waarom er meer watervlooien dan stekelbaarzen in de schoolvijver zijn. +6. Beschrijf in vier stappen hoe een koolstofatoom van de lucht via een waterplant en een eend weer in de lucht terechtkomt. +7. Leg uit waarom de schoolvijver in de zomer soms groen kleurt en wat dat te maken heeft met de boerderij naast de school. +8. Wat is de draagkracht van een gebied? Noem twee factoren die de draagkracht van de schoolvijver voor eenden bepalen. +9. Teken een grafiek van het aantal watervlooien en het aantal stekelbaarzen in de tijd, en leg uit waarom de lijnen zo lopen. +10. Leg uit waarom een bos met veel soorten beter tegen een boomziekte kan dan een bos met één soort. +11. Kies een partij uit het debat over het Voorbeeldbos en geef twee argumenten met begrippen uit dit thema. +12. Bedenk een maatregel van natuurbeheer voor de schoolvijver en leg uit welk effect je verwacht op het voedselweb. + +## Begrippenlijst + +| Begrip | Betekenis | +| --- | --- | +| Abiotische factor | Invloed uit de niet-levende omgeving, zoals licht, temperatuur, water | +| Biotische factor | Invloed van andere organismen, zoals voedsel, vijanden, concurrenten | +| Biodiversiteit | De verscheidenheid aan soorten in een gebied | +| Consument | Organisme dat andere organismen eet | +| Draagkracht | Het maximale aantal individuen van een soort dat een gebied blijvend kan onderhouden | +| Ecosysteem | Levensgemeenschap plus de niet-levende omgeving | +| Eutrofiëring | Overmaat aan voedingsstoffen in water, waardoor algen woekeren | +| Fotosynthese | Proces waarbij planten met licht uit water en CO₂ glucose en zuurstof maken | +| Levensgemeenschap | Alle populaties op één plek samen | +| Populatie | Groep individuen van dezelfde soort op dezelfde plek en tijd | +| Predatie | Relatie tussen roofdier en prooi | +| Producent | Organisme dat zijn eigen voedsel maakt, meestal een plant | +| Reducent | Organisme dat dode resten afbreekt, zoals schimmels en bacteriën | +| Voedselketen | Rij organismen die elkaar eten, met pijlen in de richting van de energie | +| Voedselweb | Alle voedselketens van een levensgemeenschap door elkaar | +""" + + +def to_pdf(md: str, name: str) -> Path: + body = markdown.markdown(md, extensions=["tables"]) + html = HERE / f".{name}.html" + html.write_text(f'' + f"{body}", encoding="utf-8") + pdf = HERE / f"{name}.pdf" + subprocess.run(["google-chrome", "--headless=new", "--disable-gpu", "--no-pdf-header-footer", + f"--print-to-pdf={pdf}", html.as_uri()], check=True, capture_output=True) + html.unlink() + return pdf + + +if __name__ == "__main__": + sw = to_pdf(STUDIEWIJZER, "studiewijzer-biologie-3havo-ecologie") + lb = to_pdf(LESBRIEF, "lesbrief-ecologie") + # Handleiding 6 gebruikt dezelfde lesbrief. + shutil.copy(lb, HERE.parent / "06-inclusief-lesmateriaal" / lb.name) + for p in (sw, lb): + print(p.name, p.stat().st_size // 1024, "kB") diff --git a/08-chatflow-studiecoach/stercollectie-voedselweb-hv3.pdf b/08-chatflow-studiecoach/stercollectie-voedselweb-hv3.pdf new file mode 100644 index 0000000..0b064b6 Binary files /dev/null and b/08-chatflow-studiecoach/stercollectie-voedselweb-hv3.pdf differ diff --git a/08-chatflow-studiecoach/studiewijzer-biologie-3havo-ecologie.pdf b/08-chatflow-studiecoach/studiewijzer-biologie-3havo-ecologie.pdf new file mode 100644 index 0000000..650383c Binary files /dev/null and b/08-chatflow-studiecoach/studiewijzer-biologie-3havo-ecologie.pdf differ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..3a5673b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Wijzigingen + +Dify verandert snel. Elke handleiding vermeldt op de titelpagina op welke dag de schermen zijn +vastgelegd. Hier staat per uitgave wat er veranderde. + +## 2026-09-20 · eerste uitgave + +- Handleidingen 01, 02, 03, 05, 07 en 08 compleet, met "Zelf kiezen"-kaders en "Maak hem van jou". +- Bijlagen: ontwerpkaart, ontwerppatronen, AI-tools in het onderwijs (met AVG, AI Act en EU-kaders). +- Draaiboek workshop voor het Limburgs Kennisfestival van 23 september 2026. +- Nog niet klaar: 04 (Agent Console, tekst) en 06 (inclusief lesmateriaal, bouwen). +- Vastgelegd op Dify cloud, versie van 20 september 2026 (Studio met Chatflow, Human Input, Agent Console bèta). diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..56bda04 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# Licentie + +De handleidingen, bijlagen, het draaiboek, de fictieve documenten en de screenshots in deze +map zijn gepubliceerd onder de licentie **Creative Commons Naamsvermelding-GelijkDelen 4.0 +Internationaal (CC BY-SA 4.0)**: https://creativecommons.org/licenses/by-sa/4.0/deed.nl + +Je mag alles kopiëren, verspreiden, bewerken en er afgeleide werken van maken, ook commercieel, +op twee voorwaarden: noem de bron ("LeX Consultancy B.V. en AI Netwerk Limburg, Dify-handleidingen, +[versiedatum]") en deel wat je ervan maakt onder dezelfde licentie. + +Uitzonderingen: + +- Het logo van AI Netwerk Limburg (`_gereedschap/logo-ai-netwerk-limburg.png`) is een merk en valt + niet onder deze licentie. Wie de handleidingen bewerkt, vervangt het logo door het eigen logo of + laat het weg (`build_handleiding.py` verwacht een PNG op dat pad). +- `08-chatflow-studiecoach/stercollectie-voedselweb-hv3.pdf` en de kopie in `06-inclusief-lesmateriaal/` + zijn van VO-content (Stercollecties, https://maken.wikiwijs.nl/157495), CC BY-SA 4.0. De bronvermelding + van VO-content blijft staan. +- Namen van producten (Dify, OpenAI, Microsoft, Google en andere) zijn merken van hun eigenaren. + +Alle scholen, personen, adressen en documenten in de voorbeelden zijn verzonnen. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5b95701 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# Dify-handleidingen + +Gemaakt door LeX Consultancy B.V. met Claude Code, screenshots via de Chrome-extensie +op het Dify-sandboxaccount "Dify". Elke map heeft dezelfde opbouw: + + handleiding-*.md bron (bewerk deze) + beelden/ screenshots, genummerd in volgorde + build.py maakt .html, .pdf en .docx uit de .md (python3 build.py); + roept _gereedschap/build_handleiding.py aan, dat het logo van + AI Netwerk Limburg op de titelpagina en in de voet zet + handleiding-*.pdf uitdeelversie + handleiding-*.docx bewerkbare versie (tabellen en kaders als Word-tabellen) + +| Map | Titel | Voor wie | Status | +| --- | --- | --- | --- | +| 01-workflow | Bouwen in Dify: van workflow naar agent | Deelnemers workshop AI Agents, Kennisfestival | klaar, 20-09-2026; met Zelf kiezen-kaders en Maak hem van jou | +| 02-agent-kennisbank | Bouwen in Dify: een agent met eigen kennisbank | Deelnemers workshop, deel 2 | klaar, 20-09-2026; met Zelf kiezen-kaders en Maak hem van jou | +| 03-schoolcommunicatie | Dify voor schoolcommunicatie: Het Voorbeeldcollege | Deelnemers workshop, teams communicatie | klaar, 20-09-2026 (34 pp.); apps live, zie links hieronder | +| 04-agent-console | Bouwen in de Agent Console: Toetsweekplanner (UC-2026-008) | Experimenteerruimte ICT SOML | agent gebouwd en gepubliceerd, handleiding nog te schrijven | +| 05-transcriptietool | Bouwen in Dify: van opname naar verslag (UC-2026-009) | Experimenteerruimte ICT SOML | klaar, 20-09-2026; met Zelf kiezen-kaders en Maak hem van jou | +| 06-inclusief-lesmateriaal | Agent Console: lesmateriaal beoordelen en aanpassen voor leerlingen met ondersteuning (UDL, open leermateriaal); zelfde vak en materiaal als 08 (lesbrief-ecologie.pdf en stercollectie-voedselweb-hv3.pdf staan al in de map) | Docenten, ondersteuningscoördinatoren | nog te bouwen | +| 07-schoolnieuws-met-controle | Schoolnieuws met controle: zelfkritiek (Controleur) en poortwachter (Code + IF/ELSE), vervolg op 03 | Deelnemers workshop, teams communicatie | klaar, 20-09-2026 (26 pp.); Schoolnieuws is nu versie 2 | +| 08-chatflow-studiecoach | Studiecoach biologie 3 havo (Chatflow): Question Classifier met vier routes, Memory, Human Input via e-mail naar de docent; lesbrief en studiewijzer fictief, plus Stercollectie-module (VO-content, CC BY-SA 4.0) | Docenten, deelnemers workshop | klaar, 20-09-2026 (45 pp.); app live, Debug Mode op de docentmail staat aan | +| 00-workshop | Draaiboek workshop AI Agents met Dify (2 uur): programma, werkvormen, valkuilen per blok, varianten; presentatie als artifact https://claude.ai/artifact/BWBzJaP1yE3f7auhdvsUTk (22 slides met sprekersnotities; festivaltijden 23-09-2026: 13:00-14:00 en 14:15-15:30) | Begeleider | klaar, 20-09-2026 | +| 00-ontwerppatronen | Vijf ontwerppatronen voor AI-agents (één aanroep, ReAct, plannen en uitvoeren, zelfkritiek, poortwachter) en hoe je ze in Dify bouwt | Alle deelnemers | klaar, 20-09-2026 (5 pp.) | +| 00-ontwerpkaart | Ontwerpkaart: één A4 om je eigen app te ontwerpen voordat je klikt | Alle deelnemers | klaar, 20-09-2026 (1 A4, uitprinten) | +| 00-ai-tools | AI-tools in het onderwijs: Copilot, Gemini, ChatGPT, Claude, Mistral, DeepSeek, Grok en de EU-opties; wat zit er al in school, wat mag (AVG, AI Act), de EU-competentiekaders, en hoe verhoudt het zich tot Dify | Alle deelnemers | klaar, 20-09-2026 (10 pp.); kolom Stand in Nederland bij elke workshop opnieuw nalopen | + +Afspraken uit het gesprek van 20-09-2026 (Guido): +- Geen MOVARE meer in de serie; het voorbeeld is overal Het Voorbeeldcollege (fictief). +- Elke handleiding krijgt per stap een groen kader "Zelf kiezen" (wat je kunt vervangen door eigen + materiaal, stijl of prompt) en een slothoofdstuk "Maak hem van jou": tabel met aanpaspunten van + makkelijk naar moeilijk, drie opdrachten, checklist eigen materiaal (geen persoonsgegevens, + eigenaar, publiceren of niet). +- De ontwerpkaart is een los A4: gebruiker, wat erin, wat eruit, regels, waaraan zie je dat het werkt. + +Account: sinds 20-09-2026 (avond) **Professional** ($59/maand: 50 apps, 5.000 credits per maand, 3 teamleden). +De handleidingen blijven geschreven voor deelnemers met een gratis sandbox-account (5 apps, 200 credits, +1 bestand per upload); waar dat verschil telt, staat het erbij. OpenAI loopt via eigen sleutel +(Gebruiksprioriteit API-sleutel). + +Gepubliceerde voorbeeld-apps: + +- 01: https://udify.app/workflow/eINp9Jdd6ICodDZF (Tekst op niveau) +- 02: https://udify.app/chat/cvLAmpk60m9HUXUy (Schoolgids-assistent) +- 03: https://udify.app/chat/OJCfxjBeBHCEbBPx (Ouderbrief-assistent) + https://udify.app/workflow/jJclFyX9BlteuHYi (Schoolnieuws: website, ouderapp, social; sinds 07 met Controleur en Poortwachter) + https://udify.app/chat/cvLAmpk60m9HUXUy (Schoolgids-assistent met Balie-stand, zelfde app als 02) +- 08: https://udify.app/chat/fP0TJW3s8IXOj9BO (Studiecoach biologie; kennisbank Biologie 3 havo ecologie, 3 documenten) +- 04: https://udify.app/agent/Ny9Pw03BNSpvR6lI (Toetsweekplanner, Agent Console, gpt-5.4) +- 05: https://udify.app/workflow/7N5dNg8fD9qXHA80 (Transcriptietool) + +Opmaakafspraken in alle handleidingen: genummerde lijst = handelingen, tabel "Wat je intypt" += veldwaarden, grijs kader "Intypen" = letterlijk overtypen, oranje kader = valkuil, +groen kader = "Zelf kiezen" (blockquote die met **Zelf kiezen** begint). Een los A4 krijgt +"STIJL: compact" in het commentaarblok bovenin (kleinere letter). +Geen em-dashes. Knopnamen in de taal van het scherm. + +_gereedschap/build_handleiding.py is het gedeelde bouwscript (opmaak, logo, PDF, Word); +logo-ai-netwerk-limburg.png staat ernaast. Wijzig de opmaak daar, niet per map. + +_gereedschap/extract.py haalt screenshots uit een Claude Code-sessietranscript +(de Chrome-extensie schrijft ze niet naar schijf). Sessiepad in het script aanpassen. + +## Publiceren + +- Bron: deze map is een git-repository (git.lexconsultancy.nl, spiegel op GitHub mogelijk). Gebouwde + bestanden (.pdf, .docx, .html) staan niet in git; maak ze met `python3 build.py` in elke map, of met + `python3 _gereedschap/bouw_alles.py` voor alles tegelijk. +- Licentie: CC BY-SA 4.0, zie LICENSE.md. Logo van AI Netwerk Limburg uitgezonderd. +- Vindplaats voor deelnemers: pagina op ai-netwerk-limburg.nl met de PDF's; Wikiwijs-arrangement na het festival. +- De live udify-apps draaien op het account en de OpenAI-sleutel van LeX Consultancy. Na een workshop: + Toegangspunt → Webapp uitzetten, of een maandlimiet op de sleutel. diff --git a/_gereedschap/bouw_alles.py b/_gereedschap/bouw_alles.py new file mode 100644 index 0000000..cee5aa5 --- /dev/null +++ b/_gereedschap/bouw_alles.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 +"""Bouwt alle handleidingen en bijlagen in één keer: python3 _gereedschap/bouw_alles.py""" +import runpy, sys +from pathlib import Path +root = Path(__file__).resolve().parent.parent +for build in sorted(root.glob("*/build.py")): + print(f"== {build.parent.name}") + sys.argv = [str(build)] + runpy.run_path(str(build), run_name="__main__") diff --git a/_gereedschap/build_handleiding.py b/_gereedschap/build_handleiding.py new file mode 100644 index 0000000..c75c07e --- /dev/null +++ b/_gereedschap/build_handleiding.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python3 +"""Bouwt een Dify-handleiding (.html, .pdf, .docx) uit een markdown-bron. + +Gebruik vanuit een handleidingmap: python3 build.py +(build.py in die map roept dit script aan met de naam van de .md) + +Vereist: python3-markdown, google-chrome, libreoffice (lokaal aanwezig). +Het logo van AI Netwerk Limburg staat naast dit script en komt op de eerste +pagina rechtsboven, in PDF, HTML en Word. +""" +import base64 +import re +import subprocess +import sys +from pathlib import Path + +import markdown + +TOOLS = Path(__file__).resolve().parent +LOGO = TOOLS / "logo-ai-netwerk-limburg.png" + +CSS = """ +@page { size: A4; margin: 2cm 2cm 2.2cm 2cm; } +html { font-size: 11pt; } +body { font-family: "Noto Sans", "DejaVu Sans", Arial, sans-serif; color: #1a1a1a; + line-height: 1.45; max-width: 17cm; margin: 0 auto; } +.kop { display: flex; align-items: flex-start; justify-content: space-between; gap: 1.5em; + margin-bottom: 1em; } +.kop-tekst { flex: 1 1 auto; } +.kop img { flex: 0 0 auto; width: 3.4cm; height: auto; } +h1 { font-size: 22pt; margin: 0 0 .3em; line-height: 1.2; } +h2 { font-size: 15pt; margin: 1.6em 0 .5em; padding-top: .3em; border-top: 2px solid #1d4ed8; + page-break-after: avoid; break-after: avoid; } +h3 { font-size: 12pt; margin: 1.2em 0 .4em; page-break-after: avoid; break-after: avoid; } +p { margin: .5em 0; } +hr { border: 0; border-top: 1px solid #ddd; margin: 1.5em 0; } +strong { font-weight: 600; } +code { font-family: "DejaVu Sans Mono", Consolas, monospace; font-size: .92em; + background: #f1f5f9; padding: 0 .25em; border-radius: 3px; } +blockquote { margin: .8em 0; padding: .5em .9em; background: #fff7ed; + border-left: 4px solid #f59e0b; page-break-inside: avoid; break-inside: avoid; } +blockquote p { margin: .2em 0; } +blockquote.kies { background: #ecfdf5; border-left-color: #10b981; } +table { border-collapse: collapse; width: 100%; margin: .8em 0; font-size: .95em; + page-break-inside: avoid; break-inside: avoid; } +th, td { border: 1px solid #cbd5e1; padding: .35em .6em; text-align: left; vertical-align: top; } +th { background: #eff6ff; } +figure { margin: .9em 0 1.1em; page-break-inside: avoid; break-inside: avoid; } +figure img { width: 100%; height: auto; border: 1px solid #cbd5e1; display: block; } +figcaption { font-size: .88em; color: #555; margin-top: .3em; } +ul, ol { margin: .4em 0 .4em 1.4em; padding: 0; } +li { margin: .15em 0; } +ol li { margin: .25em 0; } +.step { page-break-inside: avoid; break-inside: avoid; } +.typ { margin: .6em 0 .9em; border: 1px solid #94a3b8; border-radius: 4px; background: #f8fafc; + page-break-inside: avoid; break-inside: avoid; } +.typ-label { font-size: .75em; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; + color: #334155; background: #e2e8f0; padding: .15em .7em; } +.schema { margin: .6em 0 .9em; padding: .5em .7em; border: 1px dashed #94a3b8; border-radius: 4px; + background: #fff; overflow-x: auto; page-break-inside: avoid; break-inside: avoid; } +.schema pre { margin: 0; white-space: pre; font-family: "DejaVu Sans Mono", Consolas, monospace; font-size: .8em; line-height: 1.3; } +.typ pre { margin: 0; padding: .5em .7em; white-space: pre-wrap; word-wrap: break-word; + font-family: "DejaVu Sans Mono", Consolas, monospace; font-size: .9em; } +.voet { margin-top: 3em; padding-top: .6em; border-top: 1px solid #ddd; font-size: .85em; color: #555; + display: flex; align-items: center; gap: .8em; } +.voet img { width: 1.6cm; height: auto; } +""" + + +def read_source(src: Path) -> str: + text = src.read_text(encoding="utf-8") + # Het instructieblok voor Claude Code bovenin hoort niet in de uitgave. + return re.sub(r"^\s*\s*", "", text, count=1, flags=re.S) + + +def logo_src(embed: bool) -> str: + if embed: + return "data:image/png;base64," + base64.b64encode(LOGO.read_bytes()).decode() + return LOGO.as_uri() + + +COMPACT_CSS = """ +html { font-size: 9.5pt; } h1 { font-size: 18pt; } h2 { margin-top: 1em; } +p { margin: .35em 0; } table { margin: .5em 0; } th, td { padding: .25em .5em; } +.voet { margin-top: .6em; } .voet img { width: 1.1cm; } .kop img { width: 2.8cm; } ul, ol { margin: .3em 0 .3em 1.3em; } +""" + + +def to_html(md_text: str, here: Path, embed_images: bool, compact: bool = False) -> str: + body = markdown.markdown(md_text, extensions=["tables", "sane_lists", "smarty", "fenced_code"]) + title = re.search(r"

(.*?)

", body).group(1) + logo = logo_src(embed_images) + + def figure(m: re.Match) -> str: + alt, src = m.group(1), m.group(2) + if embed_images: + data = base64.b64encode((here / src).read_bytes()).decode() + src = f"data:image/jpeg;base64,{data}" + return (f'
{alt}' + f"
{alt}
") + + body = re.sub(r'

([^

', figure, body) + + # ```schema-blokken zijn tekstschema's (pijlen en kaders), geen tekst om over te typen. + if embed_images: + body = re.sub(r'
(.*?)
', + r'
\1
', + body, flags=re.S) + else: + body = re.sub(r'
(.*?)
', + r'
\1
', body, flags=re.S) + + # Codeblokken zijn tekst die letterlijk overgetypt wordt: geef ze een label. + if embed_images: + # LibreOffice negeert CSS-kaders bij HTML-import, maar respecteert tabelattributen. + body = re.sub(r"
(.*?)
", + r'' + r'
INTYPEN
\1
', + body, flags=re.S) + body = body.replace("", '
') + else: + body = re.sub(r"
(.*?)
", + r'
Intypen
\1
', + body, flags=re.S) + + # Kaders die beginnen met "Zelf kiezen" zijn groen (keuze), de rest oranje (valkuil). + body = re.sub(r"
(\s*

Zelf kiezen)", + r'

\1', body) + if embed_images: + # Word: kleur via tabelattribuut, want CSS overleeft de import niet. + body = re.sub(r'
(.*?)
', + r'
\1
', + body, flags=re.S) + body = re.sub(r"
(.*?)
", + r'
\1
', + body, flags=re.S) + + # Instructiezin en het beeld erbij horen op dezelfde pagina. + body = re.sub(r"(

(?:(?!

).)*

)\n(
.*?
)", + r'
\1\2
', body, flags=re.S) + + # Kop: titel plus eerste alinea (ondertitel) links, logo rechts. + if embed_images: + # Word: tabel zonder randen, want flexbox overleeft de import niet. + body = re.sub( + r"^(

.*?

\s*

.*?

)", + lambda m: (f'' + f'' + f'
{m.group(1)}' + f'AI Netwerk Limburg
'), + body, count=1, flags=re.S) + else: + body = re.sub( + r"^(

.*?

\s*

.*?

)", + lambda m: (f'
{m.group(1)}
' + f'AI Netwerk Limburg
'), + body, count=1, flags=re.S) + + voet = (f'
' + f'AI Netwerk Limburg · ai-netwerk-limburg.nl · {title}
') + + return (f'' + f"{title}" + f"{body}{voet}") + + +def build(src: Path) -> None: + here = src.resolve().parent + stem = src.stem + md_text = read_source(src) + # "STIJL: compact" in het instructieblok bovenin = kleinere letter, voor een losse A4. + compact = "STIJL: compact" in src.read_text(encoding="utf-8") + + html_path = here / f"{stem}.html" + html_path.write_text(to_html(md_text, here, embed_images=False, compact=compact), encoding="utf-8") + + # PDF via Chrome: gebruikt de CSS hierboven, inclusief paginaregels. + subprocess.run([ + "google-chrome", "--headless=new", "--disable-gpu", "--no-pdf-header-footer", + f"--print-to-pdf={here / (stem + '.pdf')}", html_path.as_uri(), + ], check=True, capture_output=True) + + # DOCX via LibreOffice: beelden als data-URI zodat ze ingebed worden, niet gelinkt. + tmp_html = here / f".{stem}-embed.html" + tmp_html.write_text(to_html(md_text, here, embed_images=True, compact=compact), encoding="utf-8") + subprocess.run([ + "soffice", "--headless", "--convert-to", "docx:MS Word 2007 XML", + "--outdir", str(here), str(tmp_html), + ], check=True, capture_output=True) + (here / f".{stem}-embed.docx").rename(here / f"{stem}.docx") + tmp_html.unlink() + + for ext in ("html", "pdf", "docx"): + p = here / f"{stem}.{ext}" + print(f"{p.name}: {p.stat().st_size // 1024} kB") + + +if __name__ == "__main__": + if len(sys.argv) != 2: + sys.exit("gebruik: build_handleiding.py ") + build(Path(sys.argv[1])) diff --git a/_gereedschap/extract.py b/_gereedschap/extract.py new file mode 100644 index 0000000..52353b6 --- /dev/null +++ b/_gereedschap/extract.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +"""Haalt een screenshot uit het Claude Code-sessietranscript. +Gebruik: extract.py +Let op: JSONL hieronder wijst naar de Claude Code-sessie van 20 september 2026; +bij een nieuwe sessie het pad aanpassen.""" +import base64, json, sys +from pathlib import Path + +JSONL = Path("/home/guido/.claude/projects/-home-guido-projecten-lexconsultancybv-nl-server/f0263769-3318-4702-826c-1957526cfde0.jsonl") + +def find(ss_id): + for line in JSONL.read_text().splitlines(): + if ss_id not in line: + continue + rec = json.loads(line) + content = rec.get("message", {}).get("content", []) + for block in content if isinstance(content, list) else []: + if block.get("type") != "tool_result": + continue + inner = block.get("content", []) + if not isinstance(inner, list): + continue + # In een browser_batch staan meerdere screenshots in één resultaat: + # neem het beeld dat direct volgt op de tekst met dit ID. + for i, b in enumerate(inner): + if b.get("type") == "text" and ss_id in b.get("text", ""): + for nb in inner[i + 1:]: + if nb.get("type") == "image": + return base64.b64decode(nb["source"]["data"]) + if nb.get("type") == "text" and "ss_" in nb.get("text", ""): + break + return None + +ss_id, dest = sys.argv[1], Path(sys.argv[2]) +data = find(ss_id) +if not data: + sys.exit(f"geen beeld gevonden voor {ss_id}") +dest.write_bytes(data) +print(f"{dest.name}: {len(data)//1024} kB") diff --git a/_gereedschap/logo-ai-netwerk-limburg.png b/_gereedschap/logo-ai-netwerk-limburg.png new file mode 100644 index 0000000..4d72a61 Binary files /dev/null and b/_gereedschap/logo-ai-netwerk-limburg.png differ