305 lines
10 KiB
Markdown
305 lines
10 KiB
Markdown
# Les 13 — Agents (Klas A)
|
||
|
||
> **Deel 3: AI Development** (Les 11–16)
|
||
> **Lesvorm:** fysiek, demo-driven
|
||
> **Structuur:** ±1 uur presenteren → pauze → ±1,5 uur zelf bouwen
|
||
|
||
---
|
||
|
||
## Blok-structuur
|
||
|
||
| Blok | Onderwerp | Slides |
|
||
|------|-----------|--------|
|
||
| 1 | Welkom + Terugblik tool calling | 1–3 |
|
||
| 2 | Wat is een agent? | 4–6 |
|
||
| 3 | AI SDK basics: tool, stopWhen, externe API | 7–9 |
|
||
| 4 | Drie agent-extra's: prepareStep + hasToolCall/finishPlan + write-tool | 10 |
|
||
| 5 | Stappenplan Polderfest → Polderfest-met-agent | 11 |
|
||
| 6 | LIVE DEMO — gedeployde Polderfest-agent | 12 |
|
||
| – | ☕ Pauze | – |
|
||
| 7 | Nu jullie — zelf bouwen | 13 |
|
||
| 8 | Afsluiting | 14 |
|
||
|
||
---
|
||
|
||
## BLOK 1 — Welkom + Terugblik tool calling
|
||
|
||
### Slide 1: Title
|
||
**Les 13 — Agents**
|
||
Subtitle: Polderfest krijgt brains — multi-step tools + externe API
|
||
|
||
---
|
||
|
||
### Slide 2: Wat hebben we vorige les gedaan?
|
||
|
||
**Tool calling (Les 12):**
|
||
- AI kreeg toegang tot tools (functies)
|
||
- Eén tool per call: bv. `searchBands(genre)`
|
||
- Goed voor: "ik weet welke functie ik nodig heb, voer 'm uit"
|
||
- We hebben dit gebouwd in de Polderfest-app — onze chat zocht in Supabase
|
||
|
||
**Maar:** wat als de vraag complex is en meerdere stappen nodig heeft?
|
||
|
||
Voorbeeld: *"Plan een zaterdagavond met indie + techno, geen overlap, alleen onder een dak als het regent."*
|
||
|
||
Eén tool-call is niet genoeg. Je hebt nodig: dag-schedule + bands per genre + weer. En ze moeten worden gecombineerd. **Dat is een agent.**
|
||
|
||
---
|
||
|
||
### Slide 3: Tool calling vs Agent — een continuüm
|
||
|
||
**Belangrijk:** er is geen harde lijn. In AI SDK v6 gebruik je voor beide dezelfde syntax (`streamText`, `tool()`, `stopWhen`). Het verschil zit in **hoe je het ontwerpt**.
|
||
|
||
| | Tool calling (Les 12) | Agent (Les 13) |
|
||
|---|----------------------|----------------|
|
||
| Vraag-type | "Voer deze functie uit" | "Bereik dit doel — kies zelf hoe" |
|
||
| Aantal stappen | Meestal 1–3 (ook met `stopWhen`) | Vaak 4–10+, variabel |
|
||
| Wie kiest de volgorde | Jouw prompt stuurt sterk | AI plant zelf, autonomer |
|
||
| Combineren van bronnen | Per tool één bron | Meerdere bronnen door elkaar (DB + externe API + …) |
|
||
| Reflectie / bijsturen | Nee — direct antwoord | AI checkt resultaat, beslist volgende stap |
|
||
|
||
**Beide kunnen externe APIs aanroepen** — `execute()` is gewoon JavaScript, een `fetch` is prima.
|
||
|
||
**Agent ≠ aparte API**, agent = mindset: "geef AI een doel + tools, laat 'm autonomer beslissen". In code uit zich dat in hogere `stopWhen` waardes (8+ ipv 2-3) en bredere, meer open system prompts.
|
||
|
||
---
|
||
|
||
## BLOK 2 — Wat is een agent?
|
||
|
||
### Slide 4: Wanneer voegt een agent écht waarde toe?
|
||
|
||
**Tool calling is genoeg als:**
|
||
- Je weet welke functie nodig is (DB-zoekopdracht, API-call)
|
||
- Het antwoord ligt in één bron
|
||
- Het pad is voorspelbaar — je kunt het zelf in 2-3 tool-calls beschrijven
|
||
|
||
**Een agent is écht zinvol als:**
|
||
- De vraag is open ("plan", "vind het beste", "vergelijk en concludeer")
|
||
- AI moet meerdere bronnen combineren in één antwoord
|
||
- Het pad is onvoorspelbaar — soms 3 stappen, soms 7
|
||
- Eerste resultaat triggert vervolgvragen ("die band is uitverkocht — zoek alternatief")
|
||
|
||
**Risico's van agents (waarom niet altijd):**
|
||
- Lopen langer — meer tokens, hogere kosten
|
||
- Moeilijker te debuggen door non-determinisme
|
||
- Voor simpele vragen overkill — gewone tool calling is sneller én goedkoper
|
||
|
||
**Pragmatisch advies:** start met tool calling. Pas op naar agent-niveau als je merkt dat je system prompt steeds langer wordt om "stappen" voor te schrijven — dan kan AI dat beter zelf bepalen.
|
||
|
||
---
|
||
|
||
### Slide 5: Hoe ziet de agent-loop eruit?
|
||
|
||
```
|
||
┌───────────────────────────────────────┐
|
||
│ Gebruiker stelt een vraag │
|
||
└─────────────┬─────────────────────────┘
|
||
│
|
||
▼
|
||
┌──────────────┐
|
||
┌──▶│ LLM │ → kies een tool of geef antwoord
|
||
│ └──────┬───────┘
|
||
│ │
|
||
│ ▼
|
||
│ ┌──────────────┐
|
||
│ │ Voer tool │ → bv. searchBands of getWeather
|
||
│ │ uit │
|
||
│ └──────┬───────┘
|
||
│ │
|
||
│ ▼
|
||
│ ┌──────────────┐
|
||
│ │ Resultaat │ → terug naar LLM
|
||
│ └──────┬───────┘
|
||
└──────────┘
|
||
|
||
Stopt wanneer: stopWhen-conditie waar wordt
|
||
(bv. stepCountIs(8) of geen tool-call meer)
|
||
```
|
||
|
||
Dit gaat door — soms 2 stappen, soms 6 — tot de agent klaar is.
|
||
|
||
---
|
||
|
||
### Slide 6: Stappen om bij een eindproduct te komen
|
||
|
||
Voor de Polderfest-agent:
|
||
|
||
1. **Bedenk de tools** — welke acties heeft de agent nodig?
|
||
- `searchBands(genre, day)` — Supabase
|
||
- `getStageSchedule(day)` — Supabase
|
||
- `getWeather(date)` — externe API (Open-Meteo)
|
||
|
||
2. **Schrijf de system prompt** — vertel de agent wat hij is, welke tools, welke werkwijze
|
||
|
||
3. **Voeg `stopWhen` toe** — veiligheid (`stepCountIs(8)`)
|
||
|
||
4. **Bouw een UI** — laat de tool-calls zien, anders is het magic zonder zicht
|
||
|
||
5. **Test met echte vragen** — "Plan een avond met...", "Welke band op...?"
|
||
|
||
We gaan dit zo live zien.
|
||
|
||
---
|
||
|
||
## BLOK 3 — Nieuwe AI SDK functies voor agents
|
||
|
||
### Slide 7: `tool({ description, inputSchema, execute })`
|
||
|
||
Bekend uit Les 12, maar essentieel:
|
||
|
||
```typescript
|
||
import { tool } from "ai";
|
||
import { z } from "zod";
|
||
|
||
searchBands: tool({
|
||
description: "Zoek bands op genre en/of dag.",
|
||
inputSchema: z.object({
|
||
genre: z.string().optional(),
|
||
day: z.enum(["vrijdag", "zaterdag", "zondag"]).optional(),
|
||
}),
|
||
execute: async ({ genre, day }) => {
|
||
// Supabase query
|
||
return data;
|
||
},
|
||
}),
|
||
```
|
||
|
||
- **description** — wat de AI hierover leest om te beslissen
|
||
- **inputSchema** — Zod-schema, AI vult dit automatisch in
|
||
- **execute** — wat er gebeurt als de tool wordt aangeroepen
|
||
|
||
---
|
||
|
||
### Slide 8: `stopWhen` — de agent-knop
|
||
|
||
Dit is wat een agent maakt:
|
||
|
||
```typescript
|
||
import { stepCountIs } from "ai";
|
||
|
||
streamText({
|
||
model: openai("gpt-5.2"),
|
||
messages,
|
||
tools: { ... },
|
||
stopWhen: stepCountIs(8), // 👈 dit
|
||
});
|
||
```
|
||
|
||
Zonder `stopWhen`: AI doet één tool-call en stopt.
|
||
Met `stopWhen`: AI loopt door tot conditie waar is — een echte agent-loop.
|
||
|
||
Andere stop-condities die je kunt combineren:
|
||
- `hasToolCall("finishPlan")` — stop als specifieke tool is aangeroepen
|
||
- Eigen functies die op output letten
|
||
|
||
---
|
||
|
||
### Slide 9: Externe API als tool
|
||
|
||
Tools hoeven niet alleen je eigen DB te zijn. Externe APIs werken net zo:
|
||
|
||
```typescript
|
||
getWeather: tool({
|
||
description: "Weer-forecast voor een festivaldag.",
|
||
inputSchema: z.object({ date: z.string() }),
|
||
execute: async ({ date }) => {
|
||
const res = await fetch(
|
||
`https://api.open-meteo.com/v1/forecast?...&start_date=${date}`
|
||
);
|
||
const data = await res.json();
|
||
return {
|
||
temperatureMaxC: data.daily.temperature_2m_max[0],
|
||
rainChancePercent: data.daily.precipitation_probability_max[0],
|
||
};
|
||
},
|
||
}),
|
||
```
|
||
|
||
Open-Meteo: gratis, geen API key. Perfect voor demos.
|
||
|
||
**Vuistregel:** wat een fetch kan, kan een tool. Stripe-saldo opvragen? Tool. GitHub-issues lezen? Tool. Wikipedia? Tool.
|
||
|
||
Externe APIs konden ook met tool calling in Les 12 — dit is niet nieuw. Het verschil bij agents: ze gebruiken vaker **meerdere bronnen door elkaar** in één antwoord (DB + externe API combineren), omdat ze meer stappen mogen zetten.
|
||
|
||
---
|
||
|
||
## BLOK 4 — Van Polderfest naar Polderfest-met-agent
|
||
|
||
### Slide 10: De stappen die we gaan zien
|
||
|
||
In de demo straks doen we (en jullie straks ook):
|
||
|
||
1. **Polderfest-original** uitpakken (Les 12 versie)
|
||
2. Nieuwe route `app/api/agent/route.ts` aanmaken
|
||
3. Eerste tool toevoegen: `searchBands` (Supabase)
|
||
4. `stopWhen: stepCountIs(8)` toevoegen
|
||
5. Tweede tool: `getStageSchedule`
|
||
6. Derde tool: `getWeather` (externe API)
|
||
7. System prompt schrijven
|
||
8. UI-pagina `app/agent/page.tsx` met tool-call-weergave
|
||
9. Testen in browser
|
||
10. Pushen naar Vercel
|
||
|
||
Volledig stap-voor-stap zit in **`Les13-Stap-voor-stap.md`** (in lesbestanden).
|
||
|
||
---
|
||
|
||
## BLOK 5 — LIVE DEMO
|
||
|
||
### Slide 11: LIVE DEMO — Polderfest-agent in actie
|
||
|
||
**Wat ik laat zien:**
|
||
|
||
1. Open de **gedeployde versie** van `polderfest-with-agent` in de browser
|
||
2. Plak prompt 1: *"Plan een avond met indie en techno voor zaterdag."*
|
||
→ Studenten zien meerdere tool-calls (searchBands × 2, getStageSchedule)
|
||
3. Plak prompt 2: *"Wat speelt er op zondag en hoe is het weer?"*
|
||
→ Agent gebruikt nu ook `getWeather` (externe API)
|
||
4. Plak prompt 3: *"Welke band moet ik NIET missen op vrijdag?"*
|
||
→ Agent doet creatieve combinatie, geeft mening
|
||
|
||
**Daarna kijken we in de code:**
|
||
|
||
- `app/api/agent/route.ts` — de drie tools + `stopWhen`
|
||
- `app/agent/page.tsx` — UI met tool-call-weergave
|
||
- Vergelijking met `app/api/chat/route.ts` (Les 11): "kijk hoeveel meer kan met agents"
|
||
|
||
---
|
||
|
||
## BLOK 6 — Nu jullie
|
||
|
||
### Slide 12: Nu jullie
|
||
|
||
**Doel:** bouw zelf een Polderfest-agent vanaf jouw Polderfest-app uit Les 12.
|
||
|
||
**Materialen (in `lesbestanden/`):**
|
||
- `polderfest-original.zip` — startpunt
|
||
- `polderfest-with-agent.zip` — referentie als je vastloopt
|
||
- `Les13-Stap-voor-stap.md` — 11 stappen, volg ze één voor één
|
||
|
||
**Stappen:**
|
||
|
||
1. Unzip de starter OF gebruik je eigen Polderfest-app uit Les 12
|
||
2. Volg `Les13-Stap-voor-stap.md` — werk in jouw eigen tempo
|
||
3. Test in de browser met de drie voorbeeld-prompts
|
||
4. Deploy naar Vercel (env vars niet vergeten!)
|
||
5. Deel je productie-URL in de chat
|
||
|
||
**Vragen?** Type "vraag" in de chat of steek je hand op — ik loop rond.
|
||
|
||
---
|
||
|
||
## BLOK 7 — Afsluiting
|
||
|
||
### Slide 13: Wat we vandaag hebben gedaan
|
||
|
||
- Verschil tool calling vs agent — `stopWhen` is de knop
|
||
- Drie nieuwe AI SDK functies: `tool()`, `stepCountIs()`, multi-step loops
|
||
- Externe APIs als tool — Open-Meteo, geen key
|
||
- Polderfest-app uitgebreid: van chat-met-context naar echte agent
|
||
- Live demo + zelf gebouwd
|
||
|
||
**Volgende les (Les 14):** Externe APIs + Cursor + Vercel deploy in diepte.
|
||
|
||
Vragen?
|