Waarom hebben AI-agents een ander pad door je app nodig?
Een groeiend deel van de requests naar je application komt van AI-agents: assistants die documentatie voor een gebruiker ophalen, researchtools die productpagina's lezen, autonome workflows die je API aanroepen. De meeste werken via interfaces die voor mensen zijn ontworpen. Ze downloaden volledige HTML-pagina's, parseren layouts, volgen navigatie die voor een muis bedoeld is, en proberen opnieuw wanneer een script-zware pagina niet rendert zoals verwacht.
Dat is inefficiënt voor iedereen. Agents krijgen lawaaierige content en maken fouten. Je servers besteden resources aan het renderen van pagina's die niemand bekijkt. En het verkeer is lastig te verklaren, omdat het lijkt op een browser die zich vreemd gedraagt. Als je nog niet zeker weet hoeveel van je verkeer dit is, begin dan met hoe je ziet of websiteverkeer van AI-agents komt.
Een betere aanpak is om agents een gestructureerd pad te geven: content en acties in formaten die voor programma's zijn gebouwd, vindbaar op standaardlocaties, met limieten die clients belonen die zichzelf correct identificeren. Deze gids laat zien hoe je dat doet zonder een tweede application te bouwen.
Stap 1: Bepaal wat agents moeten kunnen doen
Begin met intentie, niet met technologie. Kijk naar de routes waar je al agentverkeer ziet en groepeer ze:
- Content lezen: documentatie, productinformatie, prijspagina's, helpartikelen, openbare profielen.
- Data opvragen: zoeken, catalogusopvragingen, beschikbaarheid, status.
- Acties uitvoeren: iets aanmaken, bijwerken of verwijderen namens een gebruiker.
Lezen en opvragen zijn goede kandidaten voor een gestructureerd pad dat openstaat voor elke goed gedragende client. Acties hebben authenticatie en autorisatie nodig, ongeacht hoe de client zichzelf identificeert, en komen aan bod in de gids over het beschermen van gevoelige acties.
Stap 2: Bied machinevriendelijke formaten aan
Voor contentroutes bied je dezelfde informatie aan zonder de pagina-opmaak. Twee formaten dekken de meeste behoeften:
- Markdown voor tekstuele content zoals documentatie en artikelen, aangeboden met het
text/markdownmedia type dat is geregistreerd in RFC 7763. Het behoudt koppen, lijsten, links en codeblokken, en is compact. - JSON voor gestructureerde records zoals producten, plannen of status.
Gebruik content negotiation zodat de URL hetzelfde blijft en de client het gewenste formaat opvraagt:
import express from "express";
const app = express();
app.get("/docs/:slug", async (req, res) => {
const doc = await loadDoc(req.params.slug);
if (!doc) return res.status(404).end();
res.vary("Accept");
const preferred = req.accepts(["text/html", "text/markdown", "application/json"]);
if (preferred === "text/markdown") {
return res.type("text/markdown; charset=utf-8").send(doc.markdown);
}
if (preferred === "application/json") {
return res.json({ title: doc.title, updatedAt: doc.updatedAt, body: doc.markdown });
}
return res.render("doc", { doc });
});Stuur een Vary: Accept header (RFC 9110 on Vary) zodat caches elke representatie apart opslaan. Veel teams bieden ook een expliciete alternatieve URL aan, bijvoorbeeld door .md toe te voegen aan een documentatiepad, omdat sommige clients dat makkelijker vinden dan negotiation. Link ernaar vanaf de HTML-pagina met <link rel="alternate" type="text/markdown" href="..."> zodat het vindbaar is. Getypeerde links zoals deze volgen het Web Linking model.
Stap 3: Hoe ontdekken agents je gestructureerde pad?
Agents kunnen niet gebruiken wat ze niet kunnen vinden. Publiceer entry points op plekken waar geautomatiseerde clients al kijken:
/llms.txtop de site root: een korte Markdown-samenvatting van wat je site biedt, met links naar de meest bruikbare pagina's en hun gestructureerde versies, volgens de llms.txt proposal.- Een API-beschrijving zoals een OpenAPI document, gelinkt vanuit je developer documentatie en vanuit
/llms.txt. - Alternatieve links in HTML-pagina's die naar Markdown- of JSON-versies verwijzen.
- Een sitemap met je canonieke content-URL's, in het formaat dat is gedefinieerd door het Sitemaps protocol.
Een minimale llms.txt:
# Example App
> Example App helps teams plan projects. This file lists the best entry points for automated clients.
## Docs
- [Getting started](https://example.com/docs/getting-started.md): setup in five steps
- [API reference](https://example.com/openapi.json): OpenAPI description of the public API
## Policies
- [Automated access](https://example.com/docs/automated-access.md): limits and how to sign requestsHoud een pagina bij die je regels voor geautomatiseerde clients uitlegt: welke routes open zijn, welke limieten gelden, en hoe een client zichzelf kan identificeren met ondertekende requests om betere behandeling te krijgen. Duidelijke regels maken van giswerk samenwerking.
Stap 4: Routeer op actorclass, niet op user-agent string
Zodra je gestructureerde responses hebt, bepaal je wie ze standaard krijgt. Gebruik de actorclass en de basis daarvan in plaats van ad hoc user-agent strings te parsen. AI-operators publiceren hun user agents wel degelijk, zoals OpenAI en Anthropic doen voor hun crawlers en fetchers, maar een stringmatch is nog steeds slechts een verklaring.
type ActorClass = "human" | "human_ai" | "agent" | "unknown";
type Basis = "verified" | "declared" | "inferred" | "unknown";
function preferStructured(actor: ActorClass, basis: Basis, accept: string): boolean {
if (accept.includes("text/markdown") || accept.includes("application/json")) return true;
return actor === "agent" && (basis === "verified" || basis === "declared");
}Twee principes houden dit veilig:
- Expliciete requests winnen altijd. Als een client Markdown of JSON opvraagt, lever het dan, ongeacht de class.
- Defaults nemen nooit iets weg. Een Human of Unknown bezoeker krijgt altijd de volledige pagina. Kiezen voor een gestructureerde default voor agents verandert het formaat, niet wat ze mogen zien.
Stap 5: Welke rate limits moeten AI-agents krijgen?
Rate limits zijn waar actorcontext het duidelijkst rendeert. In plaats van één limiet voor iedereen geef je elke combinatie van class en basis een passend budget:
| Actor en basis | Leesroutes | Opmerkingen |
|---|---|---|
| Agent, verified | Hogere limiet | Operator is identificeerbaar en verantwoordelijk |
| Agent, declared or inferred | Standaardlimiet | Claims zijn niet controleerbaar |
| Unknown | Standaardlimiet | Nooit bestraffend als default |
| Human of Human + AI | Standaardlimiet | Interactief gebruik bereikt zelden limieten |
Koppel de limiet aan de meest stabiele identifier die beschikbaar is. Voor verified agents is dat de origin van de operator en de sleutelidentifier. Voor anderen gebruik je de credential of een key op netwerkniveau.
function limitKey(actor: { actor: ActorClass; basis: Basis; operator?: string }, ip: string, apiKey?: string) {
if (actor.actor === "agent" && actor.basis === "verified" && actor.operator) return `op:${actor.operator}`;
if (apiKey) return `key:${apiKey}`;
return `ip:${ip}`;
}
function limitFor(actor: { actor: ActorClass; basis: Basis }): number {
if (actor.actor === "agent" && actor.basis === "verified") return 600;
return 120;
}De getallen zijn placeholders. Stel de jouwe in op basis van de baseline die je hebt waargenomen. Wanneer een client een limiet overschrijdt, geef dan 429 Too Many Requests terug met een Retry-After header en een link naar je pagina voor geautomatiseerde toegang. Goed gebouwde agents trekken zich terug en lezen die.
Stap 6: Houd acties achter autorisatie
Een gestructureerd pad voor lezen is geen omweg om je securitymodel heen. Elke actie die data wijzigt vereist nog steeds:
- authenticatie met een credential die je application heeft uitgegeven,
- autorisatie voor die specifieke actie, en
- eventuele extra checks die het risiconiveau van de route vereist.
Een verified signature vertelt je welke client aanroept. Het vertelt je niet dat de client namens een bepaalde gebruiker mag handelen. Houd die vragen gescheiden. Ons bericht over wat ondertekende AI-agentrequests bewijzen legt het verschil uit.
Stap 7: Meet het effect
Draai het gestructureerde pad eerst in observation mode en vergelijk daarna:
- het aandeel agentrequests dat gestructureerde formaten gebruikt,
- serverkosten en latency voor agentverkeer voor en na,
- fout- en retrypercentages voor agentclients,
- hoeveel geautomatiseerde clients van declared naar verified verschuiven zodra je je ondertekeningsrichtlijnen publiceert.
Deze cijfers laten zien of het gestructureerde pad zijn werk doet en waar je het verder moet uitbreiden.
Stap 8: Versiebeheer en documenteer het gestructureerde pad
Beschouw het gestructureerde pad als een publieke interface, omdat agents erop zullen voortbouwen. Een paar gewoonten houden het betrouwbaar:
- Houd URL's stabiel. Als een agent heeft geleerd dat
/docs/getting-started.mdbestaat, moet het blijven werken. Wanneer content verhuist, geef dan een301naar de nieuwe locatie in plaats van een404. - Neem update-tijden op. Zet een
updatedAtveld in JSON-responses en eenLast-Modifiedheader op Markdown, zodat agents verstandig kunnen cachen en alleen verversen wanneer iets is veranderd. - Ondersteun conditional requests. Reageer op
If-None-MatchenIf-Modified-Sincemet304 Not Modified. Agents die je content pollen kosten veel minder wanneer ze opnieuw kunnen valideren in plaats van alles opnieuw te downloaden. - Versiebeheer breaking changes. Als een JSON-structuur moet veranderen, voeg dan een nieuw versiepad of een nieuwe media type toe en houd de oude nog een gepubliceerde periode aan.
- Publiceer een changelog voor de pagina voor geautomatiseerde toegang. Operators van goed gedragende agents lezen die, en het geeft jou een plek om nieuwe gestructureerde routes aan te kondigen.
app.get("/api/plans", async (req, res) => {
const plans = await loadPlans();
const etag = `"${plans.version}"`;
res.set("ETag", etag);
res.set("Cache-Control", "public, max-age=300");
if (req.get("if-none-match") === etag) return res.status(304).end();
return res.json({ updatedAt: plans.updatedAt, plans: plans.items });
});Deze praktijken komen ook je eigen frontend en partnerintegraties ten goede. Een gestructureerd pad dat stabiel, cachebaar en gedocumenteerd is, wordt snel de eenvoudigste manier voor elk programma om met je application te werken.
Veelvoorkomende valkuilen
- Andere feiten serveren aan agents en mensen. De gestructureerde versie moet dezelfde informatie bevatten als de pagina. Afwijkende content maakt gebruikers in de war die een assistant over je product vragen.
- Het gestructureerde pad verbergen. Als het niet gelinkt is vanaf
/llms.txt, je API-documentatie of de pagina's zelf, blijven agents HTML scrapen. - Claims belonen. Hogere limieten horen bij verified clients. Een gekopieerde user-agent string mag geen groter budget opleveren.
- Caches vergeten. Zonder
Vary: Acceptkan een cache Markdown aan een browser serveren.
Waar Proof of Actor past
Proof of Actor geeft je de actorclass en basis die je nodig hebt om agents naar gestructureerde content te routeren en eerlijke limieten in te stellen. Het detecteert signed, declared en inferred agents, helpt je begrijpen hoe ze je routes gebruiken, en laat de routeringsbeslissing in je code.
Om samen met ons team een gestructureerd pad voor je eigen application te ontwerpen, vraag vroege toegang aan. Voor API- en MCP-scenario's in het bijzonder, zie APIs en MCP Servers, en lees wie roept je MCP server aan? voor hoe actorcontext van toepassing is op Model Context Protocol tool calls.
Bronnen
- RFC 9110: HTTP Semantics: content negotiation (Section 12),
Vary(Section 12.5.5), conditional requests (Section 13) enRetry-After(Section 10.2.3) - RFC 7763: The text/markdown Media Type: Markdown-representaties aanbieden
- RFC 8288: Web Linking: getypeerde
alternatelinks - RFC 6585: Additional HTTP Status Codes, Section 4:
429 Too Many Requests - llms.txt proposal: het
/llms.txtbestandsformaat - OpenAPI Specification: machineleesbare API-beschrijvingen
- Sitemaps protocol: sitemap-bestandsformaat
- OpenAI: Overview of OpenAI Crawlers: OpenAI's gepubliceerde user agents en IP-ranges
- Anthropic: crawler and fetcher documentation: ClaudeBot, Claude-User en Claude-SearchBot
- Model Context Protocol specification (2026-07-28): de huidige MCP-revisie per November 2026