Skip to content
All posts

Integrating AI Into Web Apps Without the Hype

Most AI integration tutorials skip the hard parts — latency, cost, fallbacks, and UX. Here's what I've learned shipping AI features in production.

4 min read

  • ai
  • llm
  • nextjs
  • openai
  • vercel-ai-sdk
  • fullstack
  • production

Integrating AI Into Web Apps Without the Hype

Everyone is adding AI to their apps.

Most of them are adding it badly.

Not because the features are wrong — but because the integration is fragile, expensive, or unusable in practice.

Here's what I've learned from building AI-powered features in production.


The Basics Everyone Gets Right

Calling an LLM API is trivially easy:

import OpenAI from "openai";

const client = new OpenAI();

const response = await client.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: prompt }],
});

This works fine in a tutorial.

Production is different.


The Parts Nobody Talks About

1. Latency Is a UX Problem

LLM responses take 2–10 seconds on average.

If you block your UI waiting for a response, your app feels broken.

Always stream. The Vercel AI SDK makes this straightforward with Next.js:

import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";

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

  const result = streamText({
    model: openai("gpt-4o-mini"),
    prompt,
  });

  return result.toDataStreamResponse();
}

On the client, render tokens as they arrive. Users tolerate slow when they see progress.


2. Cost Grows Faster Than You Expect

GPT-4o costs real money at scale.

Rules I follow:

  • Use smaller models by default. gpt-4o-mini handles 80% of tasks at 10× lower cost.
  • Cache deterministic responses. If the same input produces the same output, cache it.
  • Set hard usage limits. Cap monthly spend before you go over budget.
  • Count tokens before sending. Reject requests above your threshold early.
import { encode } from "gpt-tokenizer";

const tokens = encode(prompt).length;
if (tokens > 4000) {
  return new Response("Prompt too long", { status: 400 });
}

3. LLMs Fail. Plan for It.

LLM APIs return errors, rate limits, and timeouts regularly.

Every AI call needs:

  • Retry with exponential backoff
  • A fallback path (degraded experience, not a crash)
  • Timeout enforcement (don't wait indefinitely)
async function callWithRetry(fn: () => Promise<string>, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await fn();
    } catch (err) {
      if (i === retries - 1) throw err;
      await new Promise((r) => setTimeout(r, 2 ** i * 500));
    }
  }
}

4. Prompt Engineering Is Engineering

Prompts are code. Treat them as such.

  • Store prompts in files, not inline strings
  • Version them
  • Test them with regression inputs
  • Log inputs and outputs in development

A prompt that worked last week can produce garbage after a model update.


5. Structured Output Is Your Friend

Free-form LLM text is hard to use programmatically.

Force structured output whenever possible:

import { generateObject } from "ai";
import { z } from "zod";

const { object } = await generateObject({
  model: openai("gpt-4o-mini"),
  schema: z.object({
    summary: z.string(),
    tags: z.array(z.string()),
    sentiment: z.enum(["positive", "neutral", "negative"]),
  }),
  prompt: "Analyze this feedback: " + feedback,
});

Zod schema + generateObject = typed, reliable AI output.


When Not to Use AI

AI adds latency, cost, and unpredictability.

Don't use it when:

  • A regex or simple function works
  • The output needs to be deterministic
  • Response time is critical and streaming isn't an option
  • The feature doesn't justify the cost at scale

My Production AI Checklist

  • [ ] Streaming enabled for long responses
  • [ ] Smaller model as default, larger only when needed
  • [ ] Token limit enforced before API call
  • [ ] Retry + timeout logic in place
  • [ ] Responses cached where input is deterministic
  • [ ] Prompts stored and versioned separately
  • [ ] Structured output with Zod schema
  • [ ] Usage monitoring and spend alerts configured

Final Thought

AI features can be genuinely useful.

But they require the same engineering discipline as any other production system — maybe more, because the failure modes are less predictable.

Build carefully. Ship confidently.