Files
novi-lessons/Les12-Tool-Calling/Les12-Lesopdracht.md
2026-05-21 08:52:47 +02:00

229 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Les 12 — Lesopdracht
## Refactor jouw thema-app naar Tool Calling
**Vak:** AI-Assisted Development
**Opleiding:** NOVI Hogeschool Utrecht
**Wanneer:** Thuis, vóór volgende les
**Inleveren:** GitHub URL + screenshots van werkende multi-step chat
---
## Doel
Bouw voort op je **eigen thema-app** uit Les 11. Refactor de chat-route — weg met de hele dataset meesturen. Vervang door **tools** die AI zelf kan aanroepen.
Je oefent:
- Tools definiëren met description + inputSchema + execute
- `stopWhen: stepCountIs(N)` voor multi-step queries
- System prompts voor tool-gebruik aansturen
- Multi-step vragen testen
---
## Vereisten
- Werkende app uit Les 11 (Next.js + Supabase + chat met data)
- Eigen thema (geen Polderfest namaken)
- 100+ records in je Supabase
- OpenAI key in `.env.local`
> Heb je geen werkende Les 11 app? Eerst die afmaken. Deze opdracht bouwt erop voort.
---
## Wat moet er staan?
### Code
- [ ] **Chat-route gerefactord** — geen `.select("*")` aan begin van POST meer
- [ ] **Minstens 3 tools** gedefinieerd voor jouw dataset
- [ ] Eén tool met **enum parameters** (vaste keuze)
- [ ] Eén tool met **optional filters** (`.optional()` parameters)
- [ ] `stopWhen: stepCountIs(5)` in `streamText`
- [ ] System prompt aangepast: "gebruik tools, verzin niet"
### Werking
- [ ] Chat werkt nog (geen 500-errors)
- [ ] Minstens 3 vragen die elk **1 tool** triggeren
- [ ] Minstens 1 vraag die **2+ tools** triggert (multi-step)
- [ ] AI verzint niet meer — tool-results worden gebruikt
---
## Tools voor jouw thema — voorbeelden
### Restaurant-aggregator
| Tool | Parameters | Wat |
|------|-----------|-----|
| `searchRestaurants` | cuisine?, price_range?, neighborhood? | Filter restaurants |
| `getRestaurantById` | id | Detail + menu |
| `getCuisineStats` | (geen) | Verdeling per cuisine |
### Scriptie-archief
| Tool | Parameters | Wat |
|------|-----------|-----|
| `searchTheses` | year?, supervisor?, keyword? | Filter scripties |
| `getThesisAbstract` | id | Volledige samenvatting |
| `getYearStats` | (geen) | Telling per jaar |
### Museum-collectie
| Tool | Parameters | Wat |
|------|-----------|-----|
| `searchArtworks` | artist?, period?, medium? | Filter kunstwerken |
| `getArtworkDetails` | id | Detail + provenance |
| `getPeriodStats` | (geen) | Verdeling per stroming |
**Voor jouw thema — bedenk:**
- Wat filtert iemand vaak? → `searchX` met filter-parameters
- Wat is een unieke entiteit? → `getXById` of `getXByName`
- Welke aggregaties zijn interessant? → `getStats`
---
## Stappenplan
### Stap 1 — Backup huidige chat-route (2 min)
```bash
cp app/api/chat/route.ts app/api/chat/route.les11.ts.bak
```
Voor het geval de refactor faalt.
### Stap 2 — Refactor route.ts (20 min)
Open `app/api/chat/route.ts`. Verwijder:
- `const { data: bands } = await supabase...select("*")` aan begin
- De grote `context` string
- De grote system prompt met alle data
Voeg toe:
- `import { tool } from "ai"` en `import { z } from "zod"`
- Tool-definities boven je POST-functie
- `tools: { ... }` en `stopWhen: stepCountIs(5)` in `streamText` (importeer `stepCountIs` uit `"ai"`)
- Kortere system prompt — alleen rol + tool-tips
### Stap 3 — Eerste tool: searchX (15 min)
Hier het patroon — pas aan voor jouw thema:
```typescript
const searchItems = tool({
description:
"Zoek items in [thema-naam]. Filter op X, Y, of Z. " +
"Gebruik dit voor filtervragen.",
inputSchema: z.object({
category: z.enum(["A", "B", "C"]).optional(),
minRating: z.number().min(1).max(5).optional(),
keyword: z.string().optional().describe("Zoekterm in titel of beschrijving"),
}),
execute: async ({ category, minRating, keyword }) => {
let q = supabase.from("items").select("*");
if (category) q = q.eq("category", category);
if (minRating) q = q.gte("rating", minRating);
if (keyword) q = q.ilike("title", `%${keyword}%`);
const { data, error } = await q.limit(20);
if (error) return { error: error.message };
return { count: data.length, items: data };
},
});
```
### Stap 4 — Twee extra tools (15 min)
Voeg minstens 2 meer toe. Inspiratie boven.
### Stap 5 — System prompt aanpassen (5 min)
```typescript
const system = `Je bent een assistent voor [thema-naam].
Gebruik de beschikbare tools om vragen te beantwoorden.
Tips:
- Voor "welke X met Y?" → searchItems
- Voor "vertel me over X" → getItemById
- Voor "hoeveel" of "verdeling" → getStats
Verzin nooit data. Antwoord in het Nederlands.`;
```
### Stap 6 — Test multi-step (15 min)
In je chat, probeer:
1. **Single tool** (`searchItems` triggert):
```
Welke [items] hebben [filter]?
```
2. **Single tool** (`getItemById` triggert):
```
Vertel me alles over [specifieke item].
```
3. **Single tool** (`getStats` triggert):
```
Hoeveel [items] in totaal? En per [groep]?
```
4. **Multi-step** (2+ tools):
```
Geef me 3 [items] in categorie X, en vergelijk ze qua [eigenschap].
```
### Stap 7 — Screenshots maken (8 min)
Voor je inleveren bij Brightspace:
- 1 screenshot per single-tool vraag (3 stuks)
- 1 screenshot van multi-step vraag (waar je 2 tool-calls ziet — als je UI ze toont)
---
## Inleveren
1. **GitHub URL** in Brightspace
2. **4 screenshots** in je README (3× single + 1× multi-step)
3. **Eén alinea** in README: welke tools heb je gedefinieerd? Waarom deze?
---
## Veelvoorkomende problemen
| Probleem | Oplossing |
|----------|-----------|
| AI roept geen tools aan | Description verbeteren — wees specifieker |
| AI gebruikt 1 tool meerdere keren | System prompt — zeg "kies juiste tool" |
| AI returnt foutmelding "Tool args invalid" | Zod schema te strict — gebruik `.optional()` waar nodig |
| `Cannot find module 'zod'` | `npm install zod` |
| Tool execute crasht | Error throwen → niet doen, return `{ error: "..." }` |
| Multi-step werkt niet | `stopWhen: stepCountIs(5)` toegevoegd? Default is 1 stap. |
---
## Tijd-indicatie
| Stap | Tijd |
|------|------|
| Backup + refactor route | 22 min |
| 3 tools definiëren | 30 min |
| System prompt + multi-step | 20 min |
| Testen + screenshots | 23 min |
| **Totaal** | **~1,5 uur** |
Loop je vast? Vraag op Brightspace.
---
## Tips
- **Begin klein** — eerst één tool werkend. Dan twee. Dan drie. Niet alles tegelijk.
- **Schrijf descriptions zoals voor een collega** — "Doe X als gebruiker vraagt om Y."
- **Test direct na elke tool** — werkt 't? Goed. Werkt 't niet? Beschrijving aanpassen.
- **Gebruik enums** voor vaste keuzes — AI respecteert ze automatisch.
Succes! Volgende les zien we hoe ver dit kan met Agents.