Files
novi-lessons/Samenvattingen/Les17-Samenvatting.md
2026-01-30 11:56:39 +01:00

7.1 KiB

Les 17: Vercel AI SDK - AI Features in je App


Hoofdstuk

Deel 4: Advanced AI Features (Les 13-18)

Beschrijving

Bouw AI-powered features in je apps met de Vercel AI SDK. Leer hoe je chat interfaces, streaming responses en AI-gegenereerde content implementeert.


Te Behandelen

Groepsdiscussie (15 min)

Bespreek klassikaal de Cursor .cursorrules ervaringen uit Les 16 - welke regels zorgen voor betere AI output?

Waarom Vercel AI SDK?

Het probleem: Direct API calls naar OpenAI/Anthropic zijn complex:

  • Streaming handmatig implementeren
  • Error handling
  • State management

De oplossing: Vercel AI SDK

  • Simpele React hooks
  • Built-in streaming
  • Provider-agnostic (OpenAI, Anthropic, etc.)
  • Edge-ready

Installatie & Setup

npm install ai @ai-sdk/openai
# of voor Anthropic:
npm install ai @ai-sdk/anthropic

Environment variable:

# .env.local
OPENAI_API_KEY=sk-xxxxx

Core Hooks

useChat - Voor Conversaties

'use client'
import { useChat } from 'ai/react'

export function ChatComponent() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat()

  return (
    <div className="flex flex-col h-screen">
      <div className="flex-1 overflow-y-auto p-4">
        {messages.map(m => (
          <div key={m.id} className={m.role === 'user' ? 'text-right' : 'text-left'}>
            <span className="inline-block p-2 rounded-lg bg-gray-100">
              {m.content}
            </span>
          </div>
        ))}
      </div>

      <form onSubmit={handleSubmit} className="p-4 border-t">
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="Type a message..."
          className="w-full p-2 border rounded"
        />
        <button type="submit" disabled={isLoading}>
          {isLoading ? 'Sending...' : 'Send'}
        </button>
      </form>
    </div>
  )
}

useCompletion - Voor Single Completions

import { useCompletion } from 'ai/react'

export function SummaryComponent() {
  const { completion, input, handleInputChange, handleSubmit, isLoading } = useCompletion()

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <textarea
          value={input}
          onChange={handleInputChange}
          placeholder="Paste text to summarize..."
        />
        <button type="submit">Summarize</button>
      </form>
      {completion && <p>{completion}</p>}
    </div>
  )
}

API Routes

app/api/chat/route.ts:

import { openai } from '@ai-sdk/openai'
import { streamText } from 'ai'

export async function POST(req: Request) {
  const { messages } = await req.json()

  const result = streamText({
    model: openai('gpt-4o-mini'),
    system: 'You are a helpful cooking assistant. Suggest recipes based on ingredients.',
    messages,
  })

  return result.toDataStreamResponse()
}

Met custom system prompt:

const result = streamText({
  model: openai('gpt-4o-mini'),
  system: `You are a recipe assistant for the AI Recipe Generator app.

    When the user provides ingredients:
    1. Suggest 2-3 recipes they could make
    2. List required additional ingredients (if any)
    3. Provide brief cooking instructions

    Be concise and practical.`,
  messages,
})

Streaming Responses

Waarom streaming?

  • Betere UX (user ziet direct resultaat)
  • Snellere perceived performance
  • Geen wachten op complete response

Hoe het werkt:

  1. Server stuurt tokens één voor één
  2. Client rendert elke token direct
  3. User ziet "typing" effect

Loading indicator:

{isLoading && (
  <div className="flex items-center gap-2">
    <div className="animate-pulse"></div>
    <span>AI is thinking...</span>
  </div>
)}

Integratie met Supabase

Conversations opslaan:

// Maak tabel in Supabase:
// conversations: id, user_id, created_at
// messages: id, conversation_id, role, content, created_at

// Na elke message:
async function saveMessage(conversationId: string, role: string, content: string) {
  await supabase.from('messages').insert({
    conversation_id: conversationId,
    role,
    content
  })
}

In je component:

const { messages, input, handleSubmit } = useChat({
  onFinish: async (message) => {
    await saveMessage(conversationId, message.role, message.content)
  }
})

Error Handling

const { messages, error, reload } = useChat()

{error && (
  <div className="p-4 bg-red-100 text-red-700 rounded">
    <p>Something went wrong. Please try again.</p>
    <button onClick={reload}>Retry</button>
  </div>
)}

Cost Management

Model keuze:

Model Kosten Gebruik voor
gpt-4o-mini Goedkoop Meeste taken
gpt-4o Duur Complexe reasoning
claude-3-haiku Goedkoop Simpele taken
claude-3-sonnet Medium Balans

Bespaartips:

  1. Gebruik gpt-4o-mini als default
  2. Korte system prompts
  3. Beperk conversation history
  4. Caching waar mogelijk

Tools

  • Vercel AI SDK (ai package)
  • Next.js API Routes
  • OpenAI API / Anthropic API
  • Cursor
  • Supabase

Lesopdracht (2 uur)

Bouw een AI Chat Component

Deel 1: Setup (20 min)

  1. npm install ai @ai-sdk/openai
  2. Voeg OPENAI_API_KEY toe aan .env.local
  3. Maak app/api/chat/route.ts

Deel 2: Basic Chat (40 min)

  1. Maak components/Chat.tsx
  2. Implementeer useChat hook
  3. Bouw chat UI met Tailwind
  4. Test streaming werkt

Deel 3: System Prompt (30 min)

  1. Schrijf system prompt voor je eindproject:
    • Recipe Generator: cooking assistant
    • Budget Buddy: financial advisor
    • Travel Planner: travel expert
  2. Test met relevante vragen

Deel 4: Supabase Integratie (30 min)

  1. Maak messages tabel
  2. Sla berichten op met onFinish
  3. Laad history bij page load

Deliverable

  • Werkende AI chat met streaming
  • Custom system prompt
  • Messages opgeslagen in Supabase

Huiswerk (2 uur)

Bouw AI Feature voor Eindproject

Deel 1: Core AI Feature (1 uur)

Implementeer de AI chat die past bij je eindproject:

Project AI Feature
Recipe Generator "Wat kan ik maken met kip en rijst?"
Budget Buddy "Analyseer mijn uitgaven deze maand"
Travel Planner "Plan een weekend Barcelona"
  • Custom system prompt
  • Context uit je database meegeven

Deel 2: UX Polish (30 min)

Voeg toe:

  • Streaming indicator
  • Suggested prompts / quick actions
  • Copy response button
  • Clear chat button
  • Error handling

Deel 3: Documentatie (30 min)

Maak docs/AI-FEATURE.md:

  • Welke AI feature heb je gebouwd?
  • Wat doet de system prompt?
  • Hoe integreert het met Supabase?
  • Welke model keuzes heb je gemaakt?

Deliverable

  • AI feature in eindproject
  • Deployed preview
  • AI-FEATURE.md documentatie

Leerdoelen

Na deze les kan de student:

  • Vercel AI SDK installeren en configureren
  • useChat en useCompletion hooks gebruiken
  • Streaming responses implementeren
  • API routes opzetten voor AI providers
  • Custom system prompts schrijven
  • Chat history opslaan in Supabase
  • Error handling en loading states implementeren
  • Kostenbewust omgaan met AI APIs