Getting Started with AI and LLMs in Your Web App

Learn how to integrate large language models into your Next.js application using the Vercel AI SDK, with streaming responses and a clean API design.

Afzal ZubairDecember 15, 20253 min read
Getting Started with AI and LLMs in Your Web App

AI features are no longer optional extras — users increasingly expect intelligent, context-aware experiences. The good news is that integrating LLMs into a Next.js application has never been easier, thanks to the Vercel AI SDK.

Installing the AI SDK

npm install ai @ai-sdk/openai

You'll also need an OpenAI API key. Add it to your .env.local:

OPENAI_API_KEY=sk-...
⚠️

Never expose your API key on the client side. Always call the LLM from a server-side API route or Server Action.

Building a Streaming API Route

Streaming is essential for LLM responses — it shows output as it's generated rather than waiting for the full response.

// app/api/chat/route.ts
import { openai } from '@ai-sdk/openai'
import { streamText } from 'ai'
 
export const runtime = 'edge'
 
export async function POST(req: Request) {
  const { messages } = await req.json()
 
  const result = streamText({
    model: openai('gpt-4o-mini'),
    system: 'You are a helpful assistant for a web development blog.',
    messages,
    maxTokens: 1024,
  })
 
  return result.toDataStreamResponse()
}

The Chat UI Component

The AI SDK provides a useChat hook that handles the entire conversation state:

'use client'
 
import { useChat } from 'ai/react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { SendHorizontal } from 'lucide-react'
 
export function ChatInterface() {
  const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
    api: '/api/chat',
  })
 
  return (
    <div className="flex flex-col h-[600px] border rounded-lg overflow-hidden">
      {/* Messages */}
      <div className="flex-1 overflow-y-auto p-4 space-y-4">
        {messages.map((message) => (
          <div
            key={message.id}
            className={`flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}
          >
            <div
              className={`max-w-[80%] rounded-lg px-4 py-2 text-sm ${
                message.role === 'user'
                  ? 'bg-primary text-primary-foreground'
                  : 'bg-muted text-foreground'
              }`}
            >
              {message.content}
            </div>
          </div>
        ))}
        {isLoading && (
          <div className="flex justify-start">
            <div className="bg-muted rounded-lg px-4 py-2 text-sm text-muted-foreground">
              Thinking...
            </div>
          </div>
        )}
      </div>
 
      {/* Input */}
      <form onSubmit={handleSubmit} className="border-t p-4 flex gap-2">
        <Input
          value={input}
          onChange={handleInputChange}
          placeholder="Ask a question..."
          disabled={isLoading}
          className="flex-1"
        />
        <Button type="submit" disabled={isLoading} size="icon">
          <SendHorizontal className="h-4 w-4" />
        </Button>
      </form>
    </div>
  )
}

Structured Output

Beyond chat, you can use LLMs for structured data extraction:

import { generateObject } from 'ai'
import { openai } from '@ai-sdk/openai'
import { z } from 'zod'
 
const { object } = await generateObject({
  model: openai('gpt-4o-mini'),
  schema: z.object({
    title: z.string(),
    tags: z.array(z.string()),
    readingLevel: z.enum(['beginner', 'intermediate', 'advanced']),
  }),
  prompt: 'Analyse this blog post and extract metadata: ' + postContent,
})

Structured output with generateObject is perfect for AI-powered content moderation, tag generation, and summarisation tasks.

Managing Costs

LLM API calls add up quickly. Here are strategies to keep costs under control:

  • Use smaller models (gpt-4o-mini) for simple tasks
  • Cache responses for identical prompts using Redis or unstable_cache
  • Set maxTokens limits on all requests
  • Rate limit your API routes per user

The Vercel AI SDK makes it genuinely easy to add AI features to Next.js apps. Start small, measure usage, and scale from there.

Related Posts