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

6.5 KiB
Raw Blame History

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)

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:

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)

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.