13 KiB
Les 13 — Agents
Slide Overzicht (Klas A — 3 uur fysiek, demo-driven)
Lesvorm: Tim demonstreert klassikaal. Studenten kijken. Zelf bouwen = huiswerk. Demo-app: Nieuwe research-agent (from scratch, los van Polderfest) Vervolg op: Les 12 — Tool Calling Aansluit op: Les 14 — RAG + embeddings
Slide 1: Title
Les 13 — Agents
Visual:
- Background: CREAM
- "Les 13" in BLUE
- "Agents" in BLACK
- Subtitle: "Een LLM in een loop met tools — autonoom tot het klaar is"
Slide 2: Terugblik
Waar staan we?
Vorige les (Les 12):
- Tool Calling — AI roept zelf functies aan
tool({ description, inputSchema, execute })stopWhen: stepCountIs(5)— multi-step- Polderfest chat met 6 tools (search, stats, schedule, favorites)
Wat een tool-call bot nog NIET kan:
- Lange ketens (30+ stappen)
- Eigen plan opstellen + bijstellen
- Tools die andere tools triggeren
- Dynamisch het model wisselen per stap
Vandaag: agents. Eén stap verder.
Visual: Pijltje van "5-step tool calling" naar "20-50 step agent loop"
Slide 3: Planning
Vandaag — 180 minuten
| Onderwerp | Duur |
|---|---|
| Welkom + Terugblik | 10 min |
| Theorie: wat is een agent? | 30 min |
| Live Demo 1 — Setup nieuwe research-agent | 25 min |
| Live Demo 2 — ToolLoopAgent + stopWhen | 25 min |
| Pauze | 15 min |
| Live Demo 3 — prepareStep + dynamic control | 25 min |
| Live Demo 4 — Planning patterns + done-tool | 20 min |
| Wanneer agent vs tool-call vs workflow? | 10 min |
| Lesopdracht + Huiswerk uitleg | 15 min |
| Vragen + Afsluiting | 5 min |
Format: Demo-driven. Code-fragmenten in slides + live in editor.
Slide 4: Wat is een agent?
LLM + Tools + Loop
De definitie van Vercel AI SDK:
Agents are LLMs that use tools in a loop to accomplish tasks.
Drie componenten:
- LLM — beslist wat de volgende actie is
- Tools — uitbreiding (search, read, write, anything)
- Loop — runtime die deze twee orchestreert
- Context management: wat ziet model in elke stap
- Stopping condition: wanneer is de taak klaar
Het verschil met Les 12:
- Les 12: tot 5 stappen, korte taken
- Les 13: 20-50+ stappen, langere autonome workflows
Visual: Loop-diagram — LLM → kies tool → execute → resultaat → LLM → ... → klaar
Slide 5: De anatomie van de loop
Wat gebeurt er per stap?
┌─────────────────────────────────────┐
│ Loop iteratie (1 step): │
│ │
│ 1. Stuur messages naar model │
│ 2. Model genereert response: │
│ - text? → loop stopt │
│ - tool-call? → ga door │
│ 3. Voer tool execute() uit │
│ 4. Voeg tool-result toe aan msgs │
│ 5. Check stop-conditie │
│ 6. Volgende iteratie │
└─────────────────────────────────────┘
De loop stopt wanneer:
- Model geeft text in plaats van tool-call (natural finish), OF
stopWhen-conditie is voldaan, OF- Tool zonder execute wordt aangeroepen (done-pattern), OF
- Tool-call needs approval
Default in v6: stepCountIs(20) — veiligheidsgrens.
Slide 6: ToolLoopAgent
De nieuwe agent-abstractie in v6
In plaats van zelf streamText loopen, gebruik je ToolLoopAgent:
import { ToolLoopAgent, tool, stepCountIs } from "ai";
const researchAgent = new ToolLoopAgent({
model: "openai/gpt-4o",
system: "You are a research assistant...",
tools: {
webSearch,
readPage,
saveReport,
},
stopWhen: stepCountIs(30),
});
const result = await researchAgent.generate({
prompt: "Onderzoek de impact van AI op de Nederlandse bouwsector",
});
console.log(result.text); // antwoord
console.log(result.steps); // alle stappen
Wat krijg je:
- Minder boilerplate (geen eigen loop schrijven)
- Herbruikbaar (definieer 1x, gebruik overal)
- Built-in loop, context, stopping
Visual: Side-by-side: handmatige while-loop vs ToolLoopAgent.
Slide 7: Stop-condities
Wanneer is een agent klaar?
Built-in condities:
| Conditie | Wanneer | Wanneer gebruiken |
|---|---|---|
stepCountIs(N) |
Na N stappen | Default veiligheid |
hasToolCall("done") |
Specifieke tool gebruikt | Done-pattern |
isLoopFinished() |
Nooit — model bepaalt | Lange autonomie |
Combineren met array:
stopWhen: [
stepCountIs(50), // max budget
hasToolCall("submit"), // OF submit-tool aangeroepen
]
Custom conditie:
const budgetExceeded: StopCondition<typeof tools> = ({ steps }) => {
const cost = computeCost(steps);
return cost > 0.50; // stop bij $0.50
};
Visual: Drie traffic lights — rood (step limit), oranje (tool reached), groen (kostgrens).
Slide 8: prepareStep
Per stap iets anders doen
prepareStep runt VOOR elke stap. Je kunt aanpassen:
- Model wisselen (mini → sonnet voor complex)
- Tools beperken (alleen search in fase 1, alleen write in fase 3)
- Messages trimmen (context-budget bewaken)
toolChoiceforceren
Voorbeeld — dynamic model:
new ToolLoopAgent({
model: "openai/gpt-4o-mini", // default
prepareStep: async ({ stepNumber, messages }) => {
if (stepNumber > 2 && messages.length > 10) {
return { model: "anthropic/claude-sonnet-4.5" };
}
return {}; // niks aanpassen
},
});
Voorbeeld — fase-gebaseerde tools:
prepareStep: async ({ stepNumber }) => {
if (stepNumber <= 3) return { activeTools: ["webSearch"] };
if (stepNumber <= 6) return { activeTools: ["readPage"] };
return { activeTools: ["saveReport"], toolChoice: "required" };
};
Slide 9: Wat we vandaag bouwen
Research-agent from scratch
Doel: Een agent die zelfstandig een onderzoeksvraag beantwoordt door web te zoeken, pagina's te lezen, en een rapport in Supabase op te slaan.
Stack:
- Next.js 16 + TypeScript + Tailwind + Shadcn
- AI SDK v6 (ToolLoopAgent)
- Tavily API (web search)
- Supabase (rapport opslag)
- OpenAI gpt-4o / Anthropic Sonnet
Tools die we bouwen:
| Tool | Wat | Gebruik in flow |
|---|---|---|
webSearch |
Tavily query → 5 resultaten | Fase 1: oriëntatie |
readPage |
URL → fulltext extractie | Fase 2: diepgang |
saveReport |
Insert in research_reports |
Fase 3: opslaan |
done |
No-execute, signaal klaar | Eind: stoppen |
Visual: Diagram van research-flow: vraag → search → read → save → done.
Slide 10: LIVE DEMO 1 — Setup research-agent
~25 min
Wat ik laat zien:
pnpm create next-app research-agent --typescript --tailwind --apppnpm add ai @ai-sdk/openai @ai-sdk/anthropic zod @supabase/supabase-js.env.local— TAVILY_API_KEY, OPENAI_API_KEY, SUPABASE_*- Supabase schema:
research_reports(id, query, summary, sources jsonb, created_at) lib/tools.ts— eerste toolwebSearchmet Tavily fetchlib/agent.ts—ToolLoopAgentinitialiserenapp/api/research/route.ts— POST endpoint die agent.generate() doet- Eerste test in terminal:
curl /api/research -d '{"query": "..."}'
Belangrijk: Tavily API key is gratis tier (1000 calls/maand). Studenten krijgen instructie om zelf account te maken.
Visual: Folder-tree van de research-agent repo.
Slide 11: LIVE DEMO 2 — ToolLoopAgent + stopWhen
~25 min
Wat ik laat zien:
- Tweede en derde tool toevoegen:
readPage,saveReport ToolLoopAgentconfiguren met alle drie +stopWhen: stepCountIs(30)- System prompt schrijven: "plan eerst, search dan, lees relevante pagina's, vat samen, sla op"
- Test met
"Schrijf een rapport over de Polderfest 2027 lineup" result.stepsloggen — zien dat agent 8-15 stappen doet- Wisselen naar
isLoopFinished()— zien dat agent zelf stopt hasToolCall("saveReport")toevoegen — stoppen zodra opgeslagen
Visual: Console-log met alle stappen (toolName, input, output) — laat zien hoe agent zelf plant.
Slide 12: Pauze
15 minuten
Slide 13: LIVE DEMO 3 — prepareStep
~25 min
Wat ik laat zien:
Use case 1 — Dynamic model:
- Default:
gpt-4o-mini(snel + goedkoop) - Vanaf stap 5:
claude-sonnet-4.5(beter reasoning) - Console-log per stap welk model
Use case 2 — Fase-gebaseerde tools:
- Stap 0-3: alleen
webSearch(oriëntatie) - Stap 4-7: alleen
readPage(diepgang) - Stap 8+: alleen
saveReport+done(afronden) - Zien: agent kan niet 'cheaten' door te vroeg op te slaan
Use case 3 — Context-trimming:
- Na 15 messages: trim oude tool-results
- System prompt + laatste 10 berichten
- Voorkomt token-explosie bij lange agents
Visual: Timeline-strip met de drie fasen + model-switch.
Slide 14: LIVE DEMO 4 — Done-tool + custom stop
~20 min
Wat ik laat zien:
Pattern 1 — Done-tool (no-execute):
done: tool({
description: "Signaleer dat onderzoek klaar is.",
inputSchema: z.object({
finalReportId: z.number(),
summary: z.string(),
}),
// GEEN execute — stopt de loop
})
Met toolChoice: "required" forceer je dat agent ALTIJD een tool aanroept — en done is hoe-ie stopt.
Pattern 2 — Custom stop op kosten:
const costLimit: StopCondition<typeof tools> = ({ steps }) => {
const tokens = steps.reduce((sum, s) =>
sum + (s.usage?.totalTokens ?? 0), 0);
return tokens > 50_000;
};
Pattern 3 — Plan-act-reflect loop:
- Stap 0: agent maakt plan (text)
- Stap 1-N: voert plan uit (tools)
- Eind: agent schrijft reflectie (text)
Visual: Plan-Act-Reflect ReAct-diagram.
Slide 15: Wanneer agent vs tool-call vs workflow?
Niet alles hoeft autonoom
| Scenario | Aanpak |
|---|---|
| Vraag → 1 tool → antwoord | Plain tool-call |
| Vraag → 2-5 tools → antwoord | stopWhen: stepCountIs(5) (Les 12) |
| Onderzoek → 10-50 tools → rapport | Agent (Les 13) |
| Productie pipeline met validatie | Workflow (explicit code) |
| Wettelijk: must be reproducible | Workflow — geen agent |
Wanneer GEEN agent gebruiken:
- Deterministisch nodig (audit, finance, juridisch)
- Voorspelbare kosten
- Latency-sensitive (< 1s antwoord)
Wanneer WEL agent:
- Open-ended taken (research, planning, debugging)
- Tot stand komen via meerdere stappen
- Cost en latency mag wat hoger
Quote uit AI SDK docs: "Agents are flexible and powerful, but non-deterministic. When you need reliable, repeatable outcomes, use workflow patterns."
Slide 16: Lesopdracht + Huiswerk
Bouw je eigen agent
Lesopdracht (in-class, 30 min):
- Setup research-agent in eigen repo
- Tavily account aanmaken + key in .env
- Agent draaien met
stepCountIs(10)en eerste eigen query stellen - Logs bekijken: hoeveel stappen, welke tools
Huiswerk (voor Les 14):
- 4e tool toevoegen —
listReportsom opgeslagen rapporten op te halen prepareSteptoevoegen — minimaal 1 use case (model OF tools OF context)- Custom
StopConditionschrijven (kosten OF specifieke conditie) AGENT.mdschrijven: tool-lijst + stop-strategie + 1 voorbeeld-run met logs
Bonus:
- UI met live-step-rendering (elke stap als card)
- Sub-agent: 2e agent die per pagina samenvat, hoofdagent gebruikt sub-agent als tool
Slide 17: Volgende les + Afsluiting
Vragen?
Vandaag gezien:
- Agent = LLM + tools + loop
ToolLoopAgentmetstopWhenenprepareStep- 4 stop-condities: stepCountIs, hasToolCall, isLoopFinished, custom
- prepareStep voor dynamic model / tools / context
- Done-tool pattern voor forced tool calling
- Wanneer wel/niet een agent
Volgende les (Les 14): RAG + embeddings
- Semantic search op grote datasets
- pgvector in Supabase
- Embedding models — wat zijn vectors
- RAG-pipeline: chunk → embed → retrieve → generate
- Combo: RAG-tool in een agent — best of both worlds
Daarna in deze leerlijn:
- Les 15-16: Testing + Deployment + Performance
- Les 17-18: Eindopdracht-werkdagen + Pitch
Vragen? Feedback?
Slide Summary
| # | Title | Type |
|---|---|---|
| 1 | Title | Opening |
| 2 | Terugblik | Recap |
| 3 | Planning | 180-min |
| 4 | Wat is een agent | Theorie |
| 5 | Anatomie van de loop | Theorie |
| 6 | ToolLoopAgent | Theorie |
| 7 | Stop-condities | Theorie |
| 8 | prepareStep | Theorie |
| 9 | Wat we vandaag bouwen | Intro demo |
| 10 | LIVE DEMO 1 — Setup | Demo |
| 11 | LIVE DEMO 2 — stopWhen | Demo |
| 12 | Pauze | Break |
| 13 | LIVE DEMO 3 — prepareStep | Demo |
| 14 | LIVE DEMO 4 — done + custom stop | Demo |
| 15 | Wanneer wel/niet | Reflectie |
| 16 | Lesopdracht + Huiswerk | Praktijk |
| 17 | Afsluiting + Les 14 preview | Closing |
Bronnen
- AI SDK Agents — Overview: https://ai-sdk.dev/docs/agents/overview
- AI SDK Agents — Loop Control: https://ai-sdk.dev/docs/agents/loop-control
- AI SDK Agents — Building Agents: https://ai-sdk.dev/docs/agents/building-agents
- AI SDK Agents — Workflows: https://ai-sdk.dev/docs/agents/workflows
- Tavily API: https://tavily.com/
- Anthropic — Building effective agents: https://www.anthropic.com/research/building-effective-agents