Skip to main content
The Vercel AI Chatbot integrates with multiple AI model providers through Vercel AI Gateway, offering a unified interface for accessing models from Anthropic, OpenAI, Google, and xAI.

Available models

The chatbot supports a curated list of top-performing models across different providers:
lib/ai/models.ts
{
  id: "anthropic/claude-haiku-4.5",
  name: "Claude Haiku 4.5",
  provider: "anthropic",
  description: "Fast and affordable, great for everyday tasks",
}

Model configuration

Define your available models in lib/ai/models.ts:
lib/ai/models.ts
export const DEFAULT_CHAT_MODEL = "openai/gpt-4.1-mini";

export type ChatModel = {
  id: string;
  name: string;
  provider: string;
  description: string;
};

export const chatModels: ChatModel[] = [
  // Anthropic
  {
    id: "anthropic/claude-haiku-4.5",
    name: "Claude Haiku 4.5",
    provider: "anthropic",
    description: "Fast and affordable, great for everyday tasks",
  },
  // OpenAI
  {
    id: "openai/gpt-4.1-mini",
    name: "GPT-4.1 Mini",
    provider: "openai",
    description: "Fast and cost-effective for simple tasks",
  },
  // Add more models...
];

// Group models by provider for UI
export const allowedModelIds = new Set(chatModels.map((m) => m.id));

export const modelsByProvider = chatModels.reduce(
  (acc, model) => {
    if (!acc[model.provider]) {
      acc[model.provider] = [];
    }
    acc[model.provider].push(model);
    return acc;
  },
  {} as Record<string, ChatModel[]>
);

AI Gateway integration

The getLanguageModel function provides a unified interface to all models through Vercel AI Gateway:
lib/ai/providers.ts
import { gateway } from "@ai-sdk/gateway";
import { wrapLanguageModel, extractReasoningMiddleware } from "ai";

export function getLanguageModel(modelId: string) {
  const isReasoningModel =
    modelId.endsWith("-thinking") ||
    (modelId.includes("reasoning") && !modelId.includes("non-reasoning"));

  if (isReasoningModel) {
    const gatewayModelId = modelId.replace(/-thinking$/, "");

    return wrapLanguageModel({
      model: gateway.languageModel(gatewayModelId),
      middleware: extractReasoningMiddleware({ tagName: "thinking" }),
    });
  }

  return gateway.languageModel(modelId);
}

Specialized models

Different models are used for specific tasks:
lib/ai/providers.ts
export function getTitleModel() {
  return gateway.languageModel("google/gemini-2.5-flash-lite");
}

export function getArtifactModel() {
  return gateway.languageModel("anthropic/claude-haiku-4.5");
}

Using models in the chat API

The chat API route uses the selected model to generate responses:
app/(chat)/api/chat/route.ts
import { streamText } from "ai";
import { getLanguageModel } from "@/lib/ai/providers";

export async function POST(request: Request) {
  const { selectedChatModel, message } = await request.json();
  
  // Validate model ID
  if (!allowedModelIds.has(selectedChatModel)) {
    return new ChatbotError("bad_request:api").toResponse();
  }

  const isReasoningModel =
    selectedChatModel.endsWith("-thinking") ||
    (selectedChatModel.includes("reasoning") &&
      !selectedChatModel.includes("non-reasoning"));

  const result = streamText({
    model: getLanguageModel(selectedChatModel),
    system: systemPrompt({ selectedChatModel, requestHints }),
    messages: modelMessages,
    experimental_activeTools: isReasoningModel
      ? []
      : [
          "getWeather",
          "createDocument",
          "updateDocument",
          "requestSuggestions",
        ],
    providerOptions: isReasoningModel
      ? {
          anthropic: {
            thinking: { type: "enabled", budgetTokens: 10_000 },
          },
        }
      : undefined,
  });

  return result.toUIMessageStream({ sendReasoning: isReasoningModel });
}

Reasoning models

Reasoning models support extended thinking for complex problems:

Extended thinking

Models can use additional compute for complex reasoning tasks

Reasoning visibility

The reasoning process is visible to users in real-time

Configuring reasoning

Reasoning models use special configuration:
app/(chat)/api/chat/route.ts
const isReasoningModel =
  selectedChatModel.endsWith("-thinking") ||
  (selectedChatModel.includes("reasoning") &&
    !selectedChatModel.includes("non-reasoning"));

const result = streamText({
  model: getLanguageModel(selectedChatModel),
  providerOptions: isReasoningModel
    ? {
        anthropic: {
          thinking: {
            type: "enabled",
            budgetTokens: 10_000,
          },
        },
      }
    : undefined,
});

Extracting reasoning

The reasoning middleware extracts thinking tags from the response:
lib/ai/providers.ts
import { wrapLanguageModel, extractReasoningMiddleware } from "ai";

if (isReasoningModel) {
  return wrapLanguageModel({
    model: gateway.languageModel(gatewayModelId),
    middleware: extractReasoningMiddleware({ tagName: "thinking" }),
  });
}

Model selector UI

The model selector component allows users to switch between models:
components/multimodal-input.tsx
import {
  ModelSelector,
  ModelSelectorTrigger,
  ModelSelectorContent,
  ModelSelectorList,
  ModelSelectorGroup,
  ModelSelectorItem,
} from "@/components/ai-elements/model-selector";

function ModelSelectorCompact({ selectedModelId, onModelChange }) {
  const selectedModel =
    chatModels.find((m) => m.id === selectedModelId) ??
    chatModels.find((m) => m.id === DEFAULT_CHAT_MODEL);

  return (
    <ModelSelector>
      <ModelSelectorTrigger>
        <ModelSelectorLogo provider={provider} />
        <ModelSelectorName>{selectedModel.name}</ModelSelectorName>
      </ModelSelectorTrigger>
      
      <ModelSelectorContent>
        <ModelSelectorInput placeholder="Search models..." />
        <ModelSelectorList>
          {Object.entries(modelsByProvider).map(
            ([providerKey, providerModels]) => (
              <ModelSelectorGroup heading={providerKey}>
                {providerModels.map((model) => (
                  <ModelSelectorItem
                    value={model.id}
                    onSelect={() => {
                      onModelChange?.(model.id);
                      setCookie("chat-model", model.id);
                    }}
                  >
                    <ModelSelectorLogo provider={logoProvider} />
                    <ModelSelectorName>{model.name}</ModelSelectorName>
                  </ModelSelectorItem>
                ))}
              </ModelSelectorGroup>
            )
          )}
        </ModelSelectorList>
      </ModelSelectorContent>
    </ModelSelector>
  );
}

Model persistence

The selected model is persisted in a cookie:
components/multimodal-input.tsx
function setCookie(name: string, value: string) {
  const maxAge = 60 * 60 * 24 * 365; // 1 year
  document.cookie = `${name}=${encodeURIComponent(value)}; path=/; max-age=${maxAge}`;
}
AI Gateway requires a valid credit card on file to service requests. Users receive free credits upon activation.

Environment configuration

No additional environment variables are needed beyond the standard Vercel deployment. AI Gateway is automatically configured for Vercel deployments.

Testing environment

For testing, you can use mock models:
lib/ai/providers.ts
import { customProvider } from "ai";
import { isTestEnvironment } from "@/lib/constants";

export const myProvider = isTestEnvironment
  ? customProvider({
      languageModels: {
        "chat-model": chatModel,
        "chat-model-reasoning": reasoningModel,
        "title-model": titleModel,
        "artifact-model": artifactModel,
      },
    })
  : null;

Chat interface

Learn how models are used in the chat

Artifacts

Understand artifact generation with specialized models

Build docs developers (and LLMs) love