add les 12
This commit is contained in:
404
Les12-Tool-Calling/Les12-Slide-Overzicht.md
Normal file
404
Les12-Tool-Calling/Les12-Slide-Overzicht.md
Normal file
@@ -0,0 +1,404 @@
|
||||
# Les 12 — Tool Calling
|
||||
## Slide Overzicht (Klas A — 3 uur fysiek, demo-driven)
|
||||
|
||||
**Lesvorm:** Tim demonstreert klassikaal. Studenten kijken. Zelf bouwen = thuis.
|
||||
**Demo-app:** Polderfest 2027 (verder bouwen op Les 11)
|
||||
**Vervolg op:** Les 11 — Vercel AI SDK + chat met data
|
||||
**Aansluit op:** Les 13 — Agents + autonome multi-step workflows
|
||||
|
||||
---
|
||||
|
||||
## Slide 1: Title
|
||||
### Les 12 — Tool Calling
|
||||
|
||||
**Visual:**
|
||||
- Background: CREAM
|
||||
- "Les 12" in BLUE
|
||||
- "Tool Calling" in BLACK
|
||||
- Subtitle: "Laat AI zelf kiezen welke functie aan te roepen"
|
||||
|
||||
---
|
||||
|
||||
## Slide 2: Terugblik
|
||||
### Waar staan we?
|
||||
|
||||
**Vorige les:**
|
||||
- Vercel AI SDK basics + 4 kern-functies
|
||||
- Polderfest 2027 demo — 500 bands in Supabase
|
||||
- Chat-route met `streamText` + `useChat`
|
||||
- AI antwoordt op vragen over de data
|
||||
|
||||
**Het probleem dat we toen lieten zien:**
|
||||
- Vandaag sturen we ALLE 500 bands mee als context bij elke vraag
|
||||
- ~30.000 tokens per call — werkt voor 500, niet voor 50.000
|
||||
|
||||
**Vandaag lossen we dat op met Tool Calling.**
|
||||
|
||||
**Visual:** Pijltje van "alles meesturen" naar "AI kiest tools"
|
||||
|
||||
---
|
||||
|
||||
## Slide 3: Planning
|
||||
### Vandaag — 180 minuten
|
||||
|
||||
| Onderwerp | Duur |
|
||||
|-----------|------|
|
||||
| Welkom + Terugblik + schaalprobleem recap | 10 min |
|
||||
| Theorie: wat is Tool Calling? | 30 min |
|
||||
| **Live Demo 1** — Eerste tool: searchBands | 20 min |
|
||||
| **Live Demo 2** — Multi-step + meer tools | 20 min |
|
||||
| **Pauze** | 15 min |
|
||||
| **Live Demo 3** — Tool-calls in UI tonen | 25 min |
|
||||
| **Live Demo 4** — Edge cases + error handling | 15 min |
|
||||
| Waarom Tool Calling > context-all? | 5 min |
|
||||
| Lesopdracht + Huiswerk uitleg | 20 min |
|
||||
| Vragen + Afsluiting | 15 min |
|
||||
|
||||
**Format:** Demo-driven, jullie kijken mee.
|
||||
|
||||
---
|
||||
|
||||
## Slide 4: Wat is Tool Calling?
|
||||
### AI besluit zelf welke functie te gebruiken
|
||||
|
||||
**Het idee:**
|
||||
In plaats van **alle data** mee te sturen, geef je AI **tools** (functies). AI ziet een vraag, kiest welke tool relevant is, roept 'm aan met de juiste parameters, krijgt resultaat, antwoordt.
|
||||
|
||||
**Voorbeeld-flow:**
|
||||
```
|
||||
User: "Welke bands spelen vrijdag op de Main Stage?"
|
||||
↓
|
||||
AI: ik roep searchBands({ day: "Vrijdag", stage: "Main Stage" }) aan
|
||||
↓
|
||||
Supabase: 12 bands
|
||||
↓
|
||||
AI: "Op vrijdag op de Main Stage spelen: ..."
|
||||
```
|
||||
|
||||
**Wat krijg je:**
|
||||
- Schaalbaar (10 records of 10 miljoen — werkt hetzelfde)
|
||||
- Real-time data (geen verouderde context)
|
||||
- Type-safe (Zod schema voor parameters)
|
||||
- Multi-step (AI kan meerdere tools combineren)
|
||||
|
||||
**Visual:** Schema diagram chat → tool → DB → AI → antwoord.
|
||||
|
||||
---
|
||||
|
||||
## Slide 5: Anatomie van een Tool
|
||||
### description + inputSchema + execute
|
||||
|
||||
```typescript
|
||||
import { tool } from "ai";
|
||||
import { z } from "zod";
|
||||
|
||||
const searchBands = tool({
|
||||
description: "Zoek bands op dag, stage, of genre",
|
||||
inputSchema: z.object({
|
||||
day: z.enum(["Vrijdag", "Zaterdag", "Zondag"]).optional(),
|
||||
stage: z.string().optional(),
|
||||
genre: z.string().optional(),
|
||||
}),
|
||||
execute: async ({ day, stage, genre }) => {
|
||||
// Supabase query
|
||||
const { data } = await supabase.from("bands").select("*")
|
||||
.eq("day", day || undefined)
|
||||
.eq("stage", stage || undefined);
|
||||
return data;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
**Drie verplichte delen:**
|
||||
1. **`description`** — Wat doet de tool? AI leest dit om te beslissen.
|
||||
2. **`inputSchema`** — Wat heeft de tool nodig? Zod schema = type-safe.
|
||||
3. **`execute`** — Wat gebeurt er als de tool wordt aangeroepen?
|
||||
|
||||
**Belangrijk:** beschrijvingen zijn **kritiek**. AI kiest op basis van descriptions — vaag = verkeerde keuze.
|
||||
|
||||
---
|
||||
|
||||
## Slide 6: Multi-step met stopWhen
|
||||
### Eén vraag = meerdere tool-calls
|
||||
|
||||
**Het concept:**
|
||||
Met `stopWhen: stepCountIs(5)` geef je AI toestemming om tot 5 keer een tool aan te roepen voordat hij antwoordt.
|
||||
|
||||
**Voorbeeld:**
|
||||
```
|
||||
User: "Vergelijk de top headliner met de drukst geplande opener"
|
||||
↓
|
||||
AI: stap 1 — searchBands({ tier: "headliner" }) → 50 bands
|
||||
↓
|
||||
AI: stap 2 — searchBands({ tier: "opener" }) → 100 bands
|
||||
↓
|
||||
AI: stap 3 — verwerkt + vergelijkt
|
||||
↓
|
||||
AI: antwoordt met vergelijking
|
||||
```
|
||||
|
||||
**In code:**
|
||||
```typescript
|
||||
const result = streamText({
|
||||
model: openai("gpt-4o-mini"),
|
||||
tools: { searchBands, getStats, getBandByName },
|
||||
stopWhen: stepCountIs(5),
|
||||
messages,
|
||||
});
|
||||
```
|
||||
|
||||
**Visual:** Flowchart met meerdere tool-blokjes.
|
||||
|
||||
---
|
||||
|
||||
## Slide 7: Vandaag — refactor Polderfest naar Tool Calling
|
||||
### Wat gaan we bouwen?
|
||||
|
||||
**Stap voor stap:**
|
||||
1. **Refactor** de chat-route van Les 11 — weg met alle bands meesturen
|
||||
2. Eerste tool: `searchBands` met filter-parameters
|
||||
3. Tweede en derde tool: `getStats`, `getBandByName`, `getScheduleByDay`
|
||||
4. Multi-step in actie — vragen die 2-3 tools combineren
|
||||
5. UI uitbreiden — tonen welke tools AI aanriep (transparantie)
|
||||
6. Edge cases: ongeldige input, lege resultaten, errors
|
||||
|
||||
**Tools die we vandaag bouwen (6 stuks):**
|
||||
|
||||
| Tool | Wat | Tier |
|
||||
|------|-----|------|
|
||||
| `searchBands` | Filter op dag, stage, genre, tier | Read |
|
||||
| `getBandByName` | Exact lookup | Read |
|
||||
| `getStats` | Aggregate (count per groep) | Read |
|
||||
| `getScheduleByDay` | Slot-overzicht per dag | Read |
|
||||
| `addFavorite` | User favorite toevoegen | **Write** |
|
||||
| `listFavorites` | User favorieten ophalen | Read |
|
||||
|
||||
**Visual:** Tools-lijst met read/write icons.
|
||||
|
||||
---
|
||||
|
||||
## Slide 8: LIVE DEMO 1 — Eerste tool: searchBands
|
||||
### ~20 min
|
||||
|
||||
**Wat ik laat zien:**
|
||||
1. Refactor `app/api/chat/route.ts` van Les 11 — weg met de hele context-string
|
||||
2. Import `tool` van `ai`
|
||||
3. Eerste tool definiëren: `searchBands` met description + inputSchema + execute
|
||||
4. System prompt aanpassen: "Gebruik tools, verzin niet"
|
||||
5. `tools: { searchBands }` + `stopWhen: stepCountIs(5)` toevoegen aan `streamText`
|
||||
6. Browse naar `/chat`, vraag: "Welke bands spelen zaterdag op de Beach Stage?"
|
||||
7. Zien: AI roept tool aan met juiste params → antwoordt
|
||||
|
||||
**Visual:** Side-by-side mock-up: oude chat-route vs nieuwe met tools.
|
||||
|
||||
---
|
||||
|
||||
## Slide 9: LIVE DEMO 2 — Meer tools + multi-step
|
||||
### ~20 min
|
||||
|
||||
**Wat ik laat zien:**
|
||||
1. Tweede tool: `getStats` — voor "hoeveel jazz acts?"
|
||||
2. Derde tool: `getBandByName` — voor "vertel me over Lost Tigers"
|
||||
3. Vierde tool: `getScheduleByDay` — voor "tijdschema vrijdag Main Stage"
|
||||
4. System prompt verfijnen — wanneer welke tool
|
||||
5. Vraag stellen die **meerdere tools** triggert: "Vergelijk twee genres qua headliners"
|
||||
6. Tonen: `stopWhen` in actie — 2-3 tool-calls in één antwoord
|
||||
|
||||
**Visual:** Multi-step flow diagram.
|
||||
|
||||
---
|
||||
|
||||
## Slide 10: Pauze
|
||||
### 15 minuten
|
||||
|
||||
---
|
||||
|
||||
## Slide 11: LIVE DEMO 3 — Tool-calls in UI tonen
|
||||
### ~25 min
|
||||
|
||||
**Wat ik laat zien:**
|
||||
1. `useChat` returnt `messages` met **parts** — text én tool-invocations
|
||||
2. UI uitbreiden: parts loopen i.p.v. content
|
||||
3. Tool-call rendering: "🔧 searchBands({ day: 'Vrijdag', stage: 'Main' })"
|
||||
4. Tool-result rendering: collapsed by default, klik om uit te klappen
|
||||
5. Streaming tool-calls visualiseren — typing-effect ook bij tool-naam
|
||||
6. Bonus: loading-icoon tijdens tool-execute
|
||||
|
||||
**Waarom transparantie?**
|
||||
- Studenten zien wat AI doet (debug-hulp)
|
||||
- Vertrouwen — gebruiker ziet "ja, hij heeft echt de DB geraadpleegd"
|
||||
- Voor productie: optioneel kunt verstoppen, voor demo onmisbaar
|
||||
|
||||
**Visual:** Mock-up van chat met tool-call chips.
|
||||
|
||||
---
|
||||
|
||||
## Slide 12: LIVE DEMO 4 — Edge cases + error handling
|
||||
### ~15 min
|
||||
|
||||
**Wat ik laat zien:**
|
||||
|
||||
**Edge case 1: ongeldige input**
|
||||
- Vraag: "Welke bands op Donderdag?"
|
||||
- AI ziet: `day` parameter is enum — Donderdag bestaat niet
|
||||
- Twee opties: AI weigert, of probeert ander filter
|
||||
|
||||
**Edge case 2: lege resultaat**
|
||||
- Vraag: "Death metal bands?"
|
||||
- Tool returnt lege array
|
||||
- AI legt uit: "Geen death metal acts op Polderfest 2027"
|
||||
|
||||
**Edge case 3: database error**
|
||||
- Wat als Supabase down is? Tool returnt `{ error: "..." }`
|
||||
- AI moet dit netjes communiceren — niet hallucineren
|
||||
|
||||
**Edge case 4: write tool — addFavorite**
|
||||
- Demo: AI voegt favoriet toe
|
||||
- Confirmation tonen — "✓ toegevoegd aan favorieten"
|
||||
- Belangrijk: AI mag write-tools niet zonder expliciete user-intent gebruiken
|
||||
|
||||
**Visual:** 4 edge-case scenarios + fixes.
|
||||
|
||||
---
|
||||
|
||||
## Slide 13: Waarom Tool Calling > context-all?
|
||||
### De vergelijking
|
||||
|
||||
| Aspect | Les 11 (context-all) | Les 12 (tool calling) |
|
||||
|--------|---------------------|----------------------|
|
||||
| Tokens per call | ~30.000 (500 bands) | ~2.000 (tools + result) |
|
||||
| Schaal | Tot ~1000 records | Tot duizenden |
|
||||
| Live data | Snapshot bij start | Actueel per call |
|
||||
| Write operaties | Niet mogelijk | Wel (addFavorite) |
|
||||
| Multi-step | Beperkt | Native (`stopWhen`) |
|
||||
| Cost | Hoger | Lager |
|
||||
| Complexiteit | Lager | Iets hoger |
|
||||
|
||||
**Wanneer toch context-all?**
|
||||
- Heel kleine dataset (<100 records)
|
||||
- Snel prototype
|
||||
- Geen schaal nodig
|
||||
|
||||
**Voor productie: bijna altijd Tool Calling.**
|
||||
|
||||
---
|
||||
|
||||
## Slide 14: Lesopdracht
|
||||
### Bouw tools voor jouw eigen thema-app
|
||||
|
||||
**Voor thuis — bouw voort op je app uit Les 11:**
|
||||
|
||||
1. Refactor je chat-route — weg met de hele context-string
|
||||
2. Definieer **minstens 3 tools** voor je eigen dataset
|
||||
3. Voeg `stopWhen: stepCountIs(5)` toe aan je `streamText`
|
||||
4. Pas system prompt aan: "gebruik tools, verzin niet"
|
||||
5. Test 3 vragen die meerdere tools combineren
|
||||
|
||||
**Tools voorbeelden (afhankelijk van jouw thema):**
|
||||
- `searchX(filter)` — read met filters
|
||||
- `getXById(id)` — exact lookup
|
||||
- `getStats(groupBy)` — aggregate
|
||||
- Voor jouw thema-specifieke acties
|
||||
|
||||
**Eisen:**
|
||||
- Werkende refactor (chat werkt nog)
|
||||
- Min 3 tools waarvan minstens 1 met enum parameters
|
||||
- Min 1 vraag die 2+ tools combineert (multi-step)
|
||||
|
||||
---
|
||||
|
||||
## Slide 15: Huiswerk
|
||||
### Tools uitbreiden + UI visualisatie + write-tool
|
||||
|
||||
**Voor volgende week (Les 13):**
|
||||
|
||||
**Onderdeel A — Write-tool toevoegen**
|
||||
- Maak een `user_X` tabel in Supabase (favorites, notes, votes, ...)
|
||||
- Schrijf write-tool: `addX(userId, itemId)`
|
||||
- Stel een vraag die deze tool triggert: "voeg X toe aan mijn lijst"
|
||||
|
||||
**Onderdeel B — Tool-calls in UI**
|
||||
- Refactor je chat UI om tool-invocations te tonen
|
||||
- Style: chip / badge / collapsed result
|
||||
- Reden: transparantie + debug
|
||||
|
||||
**Onderdeel C — `TOOLS.md`**
|
||||
Schrijf in repo-root:
|
||||
- Welke tools heb je gedefinieerd? (lijst + descriptions)
|
||||
- 3 vragen die 1 tool gebruiken
|
||||
- 1 vraag die 2+ tools combineert (multi-step)
|
||||
- 1 voorbeeld van een edge-case die AI goed afhandelde
|
||||
|
||||
**Bonus:** Loading indicator per tool-execute, tool-result formatten als kaartjes.
|
||||
|
||||
---
|
||||
|
||||
## Slide 16: Volgende les — Agents + autonomie
|
||||
### Hoe ver kan een AI autonoom?
|
||||
|
||||
**Wat we vandaag deden:**
|
||||
- AI roept tools aan in 1 ronde, maximaal 5 stappen
|
||||
- Antwoord komt terug naar gebruiker
|
||||
|
||||
**Volgende les (Les 13):**
|
||||
- **AI Agents** — langere autonome workflows
|
||||
- `stopWhen: stepCountIs(20)` of meer — AI plant, voert uit, evalueert, herhaalt
|
||||
- Tools die andere tools triggeren
|
||||
- Stop-condities, retries, error recovery
|
||||
- Voorbeeld: "Plan mijn volledige Polderfest weekend" — AI bekijkt alle dagen, maakt schema, voegt toe aan favorieten
|
||||
|
||||
**Daarna in deze leerlijn:**
|
||||
- Les 14: RAG + embeddings (semantic search op grote datasets)
|
||||
- Les 15-16: Testing + Deployment + Performance
|
||||
- Les 17-18: Eindopdracht-werkdagen + Pitch
|
||||
|
||||
---
|
||||
|
||||
## Slide 17: Afsluiting
|
||||
### Vragen?
|
||||
|
||||
**Vandaag gezien:**
|
||||
- Schaalprobleem van context-all opgelost met Tool Calling
|
||||
- Anatomie van een tool: description + inputSchema + execute
|
||||
- `stopWhen` voor multi-step workflows
|
||||
- Zes tools voor Polderfest gebouwd
|
||||
- Tool-invocations in UI gevisualiseerd
|
||||
- Edge cases + error handling
|
||||
|
||||
**Volgende les:** Agents + autonomie
|
||||
|
||||
**Vragen? Feedback?**
|
||||
|
||||
---
|
||||
|
||||
## Slide Summary
|
||||
|
||||
| # | Title | Type |
|
||||
|---|-------|------|
|
||||
| 1 | Title | Opening |
|
||||
| 2 | Terugblik + schaalprobleem | Recap |
|
||||
| 3 | Planning | 180-min |
|
||||
| 4 | Wat is Tool Calling | Theorie |
|
||||
| 5 | Anatomie van een tool | Theorie |
|
||||
| 6 | Multi-step met stopWhen | Theorie |
|
||||
| 7 | Vandaag bouwen we | Intro demo |
|
||||
| 8 | **LIVE DEMO 1** — searchBands | Demo |
|
||||
| 9 | **LIVE DEMO 2** — Multi-step + meer tools | Demo |
|
||||
| 10 | Pauze | Break |
|
||||
| 11 | **LIVE DEMO 3** — Tool-calls in UI | Demo |
|
||||
| 12 | **LIVE DEMO 4** — Edge cases | Demo |
|
||||
| 13 | Tool Calling vs context-all | Reflectie |
|
||||
| 14 | Lesopdracht | Praktijk |
|
||||
| 15 | Huiswerk | Praktijk |
|
||||
| 16 | Volgende les: Agents | Preview |
|
||||
| 17 | Afsluiting | Closing |
|
||||
|
||||
---
|
||||
|
||||
## Bronnen
|
||||
|
||||
- Vercel AI SDK Tools: https://ai-sdk.dev/docs/foundations/tools
|
||||
- Multi-step: https://ai-sdk.dev/docs/foundations/agents
|
||||
- Zod docs: https://zod.dev
|
||||
- OpenAI Function Calling docs: https://platform.openai.com/docs/guides/function-calling
|
||||
- Supabase JS query builder: https://supabase.com/docs/reference/javascript/select
|
||||
Reference in New Issue
Block a user