
Een klant van ons publiceert wekelijks over het vakgebied. Een specialist met tien jaar eigen materiaal: twee eigen boeken, diverse whitepapers en veel case-documenten.
De klant wilde sneller content kunnen maken maar met standaard AI-tools als ChatGPT voelt de content niet authentiek genoeg.
We besloten zelf iets te bouwen met behulp van Claude Code. In dit artikel laten we zien wat we maakten, wat we onderweg leerden over hoe AI-content wel geloofwaardig kan zijn, en hoe je een vergelijkbaar systeem zelf in elkaar zet.
Inhoud
- Waarom standaard AI-tools tekortschieten
- Wat we bouwden
- Eén schrijfronde is niet genoeg
- Hoe je AI dwingt om niet als AI te klinken
- Automatisch interne links uit de XML-sitemap toevoegen
- Claude Code als bouwpartner
- Bouw het zelf in zes stappen
- Wat we eruit halen
Waarom standaard AI-tools tekortschieten
Er staan tientallen tools in de markt die blogs voor je schrijven. De meeste werken hetzelfde: een prompt erin, een tekst eruit.
Voor onze klant werkte dat niet. De standaard tools faalden op twee punten. Ze hallucineerden cijfers en cases. En de toon was generiek, met woorden als "naadloos", "dynamisch" en "in deze snel veranderende wereld" die in elke AI-tekst opduiken.
Wij denken dat de meeste AI-blogs die op dit moment worden gepubliceerd onpubliceerbaar zouden zijn als de auteur ze één keer kritisch zou herlezen.
Ook interessant:
Wat we bouwden
Het systeem doet drie dingen die de meeste tools niet doen.
1. Het werkt op basis van eigen bronnen. De klant levert PDFs aan: zijn boeken, whitepapers en eigen artikelen. Die worden opgesplitst in stukken van rond de 700 karakters en opgeslagen in een vectordatabase. Bij elke nieuwe blog haalt het systeem 30 tot 50 relevante passages op die over het onderwerp gaan. De AI gebruikt geen algemene kennis. Hij schrijft uit de specifieke kennis van de klant. Dit heet RAG: Retrieval-Augmented Generation.
2. Het kijkt naar wat er al rankt in Google. Voor elk keyword scrapen we de top-5 organische resultaten. Een aparte AI-call beoordeelt welke artikelen inhoudelijk goed zijn en bepaalt waar het nieuwe artikel beter kan zijn. Geen kopieerwerk maar wel een automatisch marktonderzoekje.
3. Er zijn drie schrijfrondes, geen één. Hier zit het echte verschil en dat diepen we nu verder uit.
Eén schrijfronde is niet genoeg
In de eerste ronde schrijft Claude een eerste versie op basis van de bronnen en de SERP-analyse. Die versie is meestal goed, maar nog niet publiceerbaar.
In de tweede ronde reviewt een aparte instructie het artikel op stijl, structuur en diepgang. Hier worden gladde passages aangescherpt en wordt AI-vocabulaire eruit gehaald. Woorden als "naadloos", "verweven" en "veelzijdig" sluipen er altijd in. Die worden vervangen.
In de derde ronde gebeurt het belangrijkste: een factcheck tegen de originele bronnen. We verwijderen alle citaten waar de auteur niet in de bronnen voorkomt. Cijfers die niet kloppen halen we eruit. Bedrijven of klanten die we niet kunnen verifiëren herschrijven we naar abstracte voorbeelden, of we laten ze weg.
De essentie zit in deze drie aanroepen:
# Stap 1: Eerste versie schrijven
artikel = schrijf_eerste_versie(keyword, bronnen, serp_analyse)
# Stap 2: Review op stijl en diepgang
artikel = review(artikel, stijlgids)
# Stap 3: Factcheck tegen de originele bronnen
artikel = verifieer_citaten(artikel, bronnen)In productie staat er meer omheen voor logging en foutafhandeling, maar de kern is dit.
We hadden het ook niet meteen goed. De factcheck-pass kwam er pas bij nadat de klant ons een gegenereerd artikel terugstuurde met een cijfer dat hij nog nooit had gezien.
Hoe je AI dwingt om niet als AI te klinken
Dit was technisch het lastigste deel. Modellen vallen standaard terug op een handjevol AI-vocabulaire woorden die overal in opduiken. Je krijgt ze er alleen uit door ze expliciet te verbieden.
Een uitsnede uit onze prompt:
VERBODEN WOORDEN EN FRASES:
- Geen AI-vocabulaire: verweven, naadloos, dynamisch,
cruciaal, pivotaal, veelzijdig
- Geen narrator-as-analyst: onderstreept, benadrukt,
weerspiegelt, illustreert, symboliseert
- Geen brochure-taal: bruisend, adembenemend, "in het hart van"
- Geen clichés: "alles wat je aandacht geeft groeit", "rugzakje"
RITME EN TOON:
- Korte zinnen. Geen lange bijzinnen.
- Nuchter en onderbouwd. Geen poseren.De volledige stijlgids is een stuk langer. Je moet exact opschrijven waar AI normaal de fout in gaat. Zonder deze regels schrijft het model in elke zoveelste alinea "naadloos" of "cruciaal".
We hebben ook hardcoded controles aan het eind. Em-dashes worden alsnog vervangen door komma's, want zelfs met expliciete instructie blijft het model er regelmatig één doorlaten.
Automatisch interne links uit de XML-sitemap toevoegen
Een laatste feature: interne links. Voor SEO is het belangrijk dat artikelen op dezelfde site naar elkaar verwijzen. Bij de meeste content-tools voeg je die handmatig achteraf toe. In ons systeem haalt het de XML-sitemap van de site op en geeft de AI de opdracht om 2 tot 4 natuurlijke links naar bestaande pagina's te plaatsen.
De code is kort en geschreven door Claude Code:
import requests
import xml.etree.ElementTree as ET
def fetch_sitemap_urls(sitemap_url: str) -> list[dict]:
"""Haalt alle URLs op uit een XML-sitemap."""
resp = requests.get(sitemap_url, timeout=10)
root = ET.fromstring(resp.content)
ns = {"sm": "http://www.sitemaps.org/schemas/sitemap/0.9"}
urls = []
for loc in root.findall(".//sm:loc", ns):
url = loc.text.strip()
urls.append({"url": url, "title": slug_to_title(url)})
return urls
def build_internal_links_block(sitemap_url: str) -> str:
"""Bouwt een instructieblok voor de AI met interne links."""
urls = fetch_sitemap_urls(sitemap_url)
url_lines = "\n".join(
f"- {entry['title']}: {entry['url']}" for entry in urls
)
return f"""INTERNE LINKS:
Voeg 2 tot 4 interne links toe in de artikeltekst.
Gebruik alleen URLs uit onderstaande lijst.
{url_lines}
"""Wij geven alleen de lijst en de instructie. Het model kiest zelf welke pagina's relevant zijn en waar ze in de tekst passen. Voor WordPress-sites werkt dit direct op de standaard sitemap-URL.
Claude Code als bouwpartner
We hebben contentgenerator niet zelf geprogrammeerd, maar gevibecode met Claude Code.
In de praktijk betekent dat: we beschreven in gewoon Nederlands wat we wilden, en Claude Code schreef de Python-code.
Twee dingen waren van belang:
We wisten precies wat we wilden bouwen. Geen abstract "AI-blogsysteem" maar een proces met vier stappen: outline, schrijfronde, review en factcheck. Door de scherpe specificatie krijg je iets bruikbaars.
We hebben de gegenereerde code gereviewed. Als je dat overslaat, bouw je iets dat werkt totdat het niet meer werkt. En dan begrijp je niet waarom.
Het werk verschuift. Je codeert minder en specificeert meer.
Bouw het zelf in zes stappen
Hieronder zes prompts die je kunt gebruiken in Claude Code om stap voor stap een vergelijkbaar systeem te bouwen. Elke stap levert iets werkends op, dat je in de volgende stap uitbreidt.
Stap 1: Een basis-schrijver
Een script dat één blog genereert op basis van een keyword.
Maak een Python-script schrijf.py dat een blog genereert via de
Anthropic API.
Eisen:
- Accepteer een --keyword argument via argparse
- Gebruik claude-opus-4-6
- Genereer een blog van ongeveer 800 woorden in HTML
- Sla de output op als output/[keyword].html
- Laad de API-key uit een .env-bestand
- Voeg requirements.txt toe
Houd het zo eenvoudig mogelijk. We breiden dit script later uit.Stap 2: PDFs inlezen in een vectordatabase
Eigen bronnen klaarzetten voor RAG.
Maak een script ingest.py dat PDFs uit een sources/-map inleest en
opslaat in een ChromaDB vectordatabase.
Eisen:
- Gebruik pymupdf4llm voor het uitlezen van PDFs naar Markdown
- Splits de tekst in chunks van rond de 700 karakters, met 150
karakters overlap tussen opeenvolgende chunks
- Splits op natuurlijke grenzen: eerst paragrafen, dan zinnen
- Sla op in db/ met embedding-model
paraphrase-multilingual-mpnet-base-v2
- Zorg dat al-ingelade bestanden niet opnieuw worden verwerkt
Print per PDF hoeveel chunks zijn toegevoegd.Stap 3: RAG retrieval in de schrijver
Het script schrijft nu op basis van je eigen bronnen.
Pas schrijf.py aan zodat voor het keyword de top-10 meest relevante
chunks worden opgehaald uit de vectordatabase, en als context worden
meegegeven aan de prompt.
De prompt moet expliciet vragen om uit deze bronnen te schrijven,
niet uit algemene kennis.
Print welke bronpassages zijn gebruikt, zodat je kunt controleren of
de retrieval goed werkt.Stap 4: Drie-pass schrijfproces
Schrijven, reviewen en factchecken in drie aparte aanroepen.
Splits het schrijven in schrijf.py op in drie aparte API-aanroepen:
1. schrijf_eerste_versie(keyword, bronnen): genereert het eerste artikel
2. review(artikel): reviewt op stijl, structuur en diepgang
3. verifieer_citaten(artikel, bronnen): controleert elke citatie en elk
concreet cijfer tegen de bronnen. Verwijdert beweringen die niet uit
de bronnen komen.
Gebruik voor de factcheck temperature=0 zodat het deterministisch werkt.
Print per stap een korte log-regel met wat er gebeurt.Stap 5: Stijlgids tegen AI-vocabulaire
Artikelen die niet meer naar AI klinken.
Maak een tekstbestand stijlgids.md met expliciete regels over wat de AI
niet mag schrijven:
- Verboden woorden (naadloos, cruciaal, dynamisch, veelzijdig)
- Verboden constructies (em-dash, "Niet X maar Y", praten in drieën)
- Toon en ritme (korte zinnen, actief, nuchter)
Lees de stijlgids in en geef hem mee als deel van de system-prompt in
alle drie de aanroepen.
Voeg een post-processing stap toe die em-dashes alsnog vervangt door
komma's, voor het geval het model er eentje doorlaat.Stap 6: Interne links uit de XML-sitemap
Artikelen die automatisch naar bestaande pagina's op je site linken.
Maak een module sitemap.py die:
- De XML-sitemap van een opgegeven URL ophaalt
- Alle pagina-URLs eruit haalt met hun titel (uit de slug)
- Een instructieblok bouwt voor de AI met de boodschap "voeg 2 tot 4
interne links toe uit deze lijst, op plekken die inhoudelijk passen"
Geef dit instructieblok mee aan de eerste schrijfronde in schrijf.py.Wie deze zes stappen doorloopt heeft een werkend systeem. Niet identiek aan het onze, maar in dezelfde geest. De rest is verfijning: extra bronnen, scherpere stijlgids, andere keywords.
Vergeet overigens nooit de human touch alsnog toe te voegen aan alles wat uit een systeem als deze komt rollen.
Wat we eruit halen
Twee inzichten die ook buiten dit specifieke systeem gelden.
Eigen bronnen geven je een voorsprong. Iedereen heeft toegang tot dezelfde modellen dus je onderscheidt je pas als je rijkere context meegeeft. Een organisatie met tien jaar aan whitepapers, klantgesprekken en case-documenten heeft een database aan onderscheidend materiaal en het is doodzonde als je daar geen gebruik van maakt.
De waarde zit in de checks. Een mens publiceert niet in één keer. Hij leest terug en scherpt aan. AI-tools doen die check standaard niet, omdat het hele verkoopargument is dat het in één keer klaar is. Wie geloofwaardig wil publiceren bouwt die checks zelf in. Anders krijg je content die er goed uitziet tot iemand hem daadwerkelijk leest.
Wil je zelf leren bouwen met Claude Code (zonder dat je programmeerervaring nodig hebt)?
In onze Vibe Coding training / Claude Code training leer je zelfstandig betrouwbare (web)apps bouwen met Claude Code. Of bekijk onze andere AI trainingen. Twijfel je hoe jij je het best verder kunt ontwikkelen? Je kunt altijd even contact opnemen en dan helpen we je verder.









