Vercel AI SDK 2026 : generateText, streamText, useChat
À la fin de ce tutoriel Vercel AI SDK, vous saurez installer le package
ai, brancher un modèle via Vercel AI Gateway (ou un provider dédié), générer du texte avecgenerateText, streamer avecstreamText, exposer une route Next.js App Router compatibleuseChat, appeler des tools multi-étapes (stopWhen), et produire des outputs structurés avecOutput.object— lab local sans secrets en clair.Niveau : Intermédiaire · Temps estimé : 50–60 min · Versions testées : Node.js 22+, Next.js App Router, package
ai(ligne AI SDK 6) · Dernière vérification : 2026-09-11
Prérequis
- Hub IA pour DevOps : parcours 2026
- Node.js 22+ et un gestionnaire de paquets (
pnpmrecommandé) - Notions TypeScript + Next.js App Router (Route Handlers)
- Une clé Vercel AI Gateway (
AI_GATEWAY_API_KEY) ou une clé provider (OPENAI_API_KEY,ANTHROPIC_API_KEY, …) — uniquement dans.env.local/ coffre CI - Optionnel : lecture latérale OpenRouter multi-modèles, function calling, structured outputs
Ce que nous allons construire
/tmp/lab-vercel-ai-sdk
├── scripts/summarize-incident.mts → generateText (runbook / faux log)
└── (option) my-ai-app/ → Next.js App Router
├── .env.local → AI_GATEWAY_API_KEY (local only)
├── app/api/chat/route.ts → streamText + UI message stream
└── app/page.tsx → useChat (@ai-sdk/react)
→ tools Zod + stopWhen
→ Output.object (schéma incident)
→ tableau erreurs · quiz · FAQ · SEO HOLD
(Schéma à remplacer par une cover locale, alt : « Vercel AI SDK — generateText, streamText, useChat, tools, structured output — 2026 ».)
Leçon 44 (après OpenRouter #43) : standardiser l’intégration LLM TypeScript. Angle DevOps : résumé d’incident, chat runbook, tools infra factices.
Étape 1 — Pourquoi le Vercel AI SDK (carte 2026)
Intégrer un LLM « à la main » (fetch provider, formats messages, streaming SSE, tools) crée un couplage fragile. Le AI SDK (toolkit TypeScript de Vercel) unifie :
| Surface | Rôle |
|---|---|
AI SDK Core (ai) |
generateText, streamText, tools, agents, outputs structurés |
AI SDK UI (@ai-sdk/react, …) |
Hooks chat / objets (useChat, useObject) framework-agnostic |
| AI SDK Harnesses | HarnessAgent pour brancher des harnesses type Claude Code / Codex / Pi |
Providers : Vercel AI Gateway (défaut, modèles en string provider/model), ou packages @ai-sdk/openai, @ai-sdk/anthropic, @ai-sdk/google, etc. Docs : ai-sdk.dev · sdk.vercel.ai/docs.
Étape 2 — Lab : résumé d’incident avec generateText
mkdir -p /tmp/lab-vercel-ai-sdk/scripts && cd /tmp/lab-vercel-ai-sdk
pnpm init
pnpm add ai zod dotenv
# Clé gateway uniquement en local / CI secrets — jamais commitée
printf 'AI_GATEWAY_API_KEY=REMPLACERn' > .env
echo '.env' >> .gitignore
Créez scripts/summarize-incident.mts :
import 'dotenv/config';
import { generateText } from 'ai';
const fakeLog = `
[2026-09-11T03:12:01Z] ERROR api-gateway timeout upstream=payments latency_ms=8200
[2026-09-11T03:12:08Z] WARN k8s Deployment/payments replicas=2 ready=0
[2026-09-11T03:12:40Z] INFO pagerduty incident=INC-1042 sev=2
`.trim();
const { text, usage } = await generateText({
model: 'xai/grok-4.6', // string gateway ; adaptez au modèle dispo
system:
'Tu es un SRE. Réponds en français, structuré, sans inventer de métriques absentes du log.',
prompt: `Résume l'incident en 5 puces max (symptôme, blast radius, hypothèses, prochaines actions) :n${fakeLog}`,
});
console.log(text);
console.log('usage:', usage);
# Exemple d'exécution (Node 22+)
pnpm exec tsx scripts/summarize-incident.mts
generateText convient aux jobs non interactifs : résumé de logs, ticket, message Slack, agent batch. Le résultat expose notamment text, usage, toolCalls / toolResults si tools, et output si schéma structuré.
Étape 3 — Chat streaming Next.js : streamText + useChat
cd /tmp/lab-vercel-ai-sdk
pnpm create next-app@latest my-ai-app
# App Router + TypeScript + Tailwind : oui
cd my-ai-app
pnpm add ai @ai-sdk/react zod
printf 'AI_GATEWAY_API_KEY=REMPLACERn' > .env.local
Route Handler app/api/chat/route.ts :
import {
streamText,
convertToModelMessages,
createUIMessageStreamResponse,
toUIMessageStream,
type UIMessage,
} from 'ai';
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
const result = streamText({
model: 'xai/grok-4.6',
system:
'Assistant runbook DevOps. Français, concret, refuse les secrets et les credentials.',
messages: await convertToModelMessages(messages),
});
return createUIMessageStreamResponse({
stream: toUIMessageStream({ stream: result.stream }),
});
}
UI app/page.tsx — 'use client', hook useChat de @ai-sdk/react : affichez messages (rôle + parts de type text), et sur submit appelez sendMessage({ text: input }) puis videz le champ. Par défaut le hook POST sur /api/chat.
pnpm run dev
# http://localhost:3000 — testez un message court
Les messages UI (UIMessage, parts) ≠ messages modèle : passez par convertToModelMessages. Renvoyez createUIMessageStreamResponse + toUIMessageStream. Branchez onError sur streamText (erreurs avalées côté serveur).
Changer de provider
// Gateway (défaut) — string
model: 'anthropic/claude-sonnet-4.5';
// Provider dédié
import { openai } from '@ai-sdk/openai';
model: openai('gpt-5.1'); // après : pnpm add @ai-sdk/openai
Étape 4 — Tools + multi-étapes (stopWhen)
Les LLM hallucinent facilement sur l’état infra. Un tool expose une action typée (Zod) que le modèle peut appeler ; le serveur exécute execute et renvoie le résultat.
import {
streamText,
tool,
isStepCount,
convertToModelMessages,
createUIMessageStreamResponse,
toUIMessageStream,
type UIMessage,
} from 'ai';
import { z } from 'zod';
export async function POST(req: Request) {
const { messages }: { messages: UIMessage[] } = await req.json();
const result = streamText({
model: 'xai/grok-4.6',
messages: await convertToModelMessages(messages),
stopWhen: isStepCount(5), // sinon 1 step = arrêt après le tool call
tools: {
getServiceHealth: tool({
description: 'Statut factice d’un service lab.',
inputSchema: z.object({
service: z.string().describe('Nom du service, ex. payments'),
}),
execute: async ({ service }) => ({
service,
env: 'lab',
status: service === 'payments' ? 'degraded' : 'ok',
readyReplicas: service === 'payments' ? 0 : 2,
}),
}),
},
});
return createUIMessageStreamResponse({
stream: toUIMessageStream({ stream: result.stream }),
});
}
Sans stopWhen (souvent 1 step), le modèle s’arrête après le tool call (tool-getServiceHealth) sans synthèse. Avec isStepCount(5), il réinjecte le résultat et répond. Tools DevOps lab : status factice, runbook mock — jamais de credentials en entrée.
Étape 5 — Outputs structurés (AI SDK 6)
En AI SDK 6, generateObject / streamObject sont dépréciés. Préférez generateText / streamText avec output: Output.object({ schema }) :
import { generateText, Output } from 'ai';
import { z } from 'zod';
const incidentSchema = z.object({
severity: z.enum(['sev1', 'sev2', 'sev3', 'sev4']),
service: z.string(),
summary: z.string(),
nextActions: z.array(z.string()).min(1).max(5),
});
const { output } = await generateText({
model: 'xai/grok-4.6',
output: Output.object({ schema: incidentSchema }),
prompt:
'À partir de ce log lab, produis un objet incident strict : ERROR payments timeout, ready=0, INC-1042 sev2.',
});
console.log(output);
Zod valide la forme (JSON → ticket / webhook). UI : useObject. Tools + output : augmentez stopWhen (l’output compte comme une step).
Étape 6 — Sécurité et déploiement DevOps
| Règle | Pratique |
|---|---|
| Secrets | .env.local / Secret Manager / variables CI — jamais dans le repo ni le bundle client |
| Surface | Route Handler serveur uniquement pour appels LLM ; le navigateur parle à /api/chat |
| Prompt injection | Instructions système + tools en allowlist ; ne pas exécuter du shell arbitraire depuis le modèle |
| Coût | Limiter max tokens / rate limit (Edge Config, KV, WAF) ; logs usage |
| Observabilité | Callbacks onEnd / lifecycle pour tracer steps, tools, latence |
| Harnesses | Pour agents CLI existants, explorer HarnessAgent (surface Harnesses) plutôt que de réécrire tout |
En prod : env projet séparées (preview / production) et modèle gateway piné (provider/model).
Cas d’usage DevOps (rapide)
Trois patterns : chat runbook (/api/chat + useChat, éventuellement RAG), job one-shot (generateText + mesure usage), agent outillé (tools Zod + stopWhen, allowlist stricte — voir prompt injection). L’IA propose ; l’humain valide les changements destructifs. Avant merge : pas de clé dans le diff, modèle piné, onError sur streamText, rate limit sur /api/chat.
Erreurs fréquentes
| Symptôme | Cause | Correction |
|---|---|---|
| 401 / auth gateway | Clé absente ou mauvaise var | AI_GATEWAY_API_KEY dans .env.local ; redémarrer pnpm dev |
| Chat vide après un tool | 1 seule step | stopWhen: isStepCount(5) (ou condition adaptée) |
Types UIMessage vs modèle |
Mauvais format messages | convertToModelMessages(messages) |
generateObject is deprecated |
Ancien tuto | Migrer vers Output.object sur generateText / streamText |
| Secret commité | .env versionné |
Révoquer la clé, ajouter .env* au .gitignore, rotation |
| Stream qui « ne finit pas » | Stream non consommé | Toujours renvoyer createUIMessageStreamResponse / consommer textStream |
Quiz (3 questions)
1. Quelle fonction Core convient le mieux à un job batch « résumer ce log » ?
– A. useChat
– B. generateText
– C. HarnessAgent uniquement
– D. createNextApp
2. En AI SDK 6, comment produire un objet JSON typé recommandé ?
– A. Parser le markdown à la main
– B. generateText + output: Output.object({ schema })
– C. Uniquement JSON.parse sur text
– D. Forcer streamObject sans alternative
3. Pourquoi ajouter stopWhen: isStepCount(5) avec des tools ?
– A. Accélérer le DNS
– B. Permettre plusieurs steps (tool → synthèse texte)
– C. Remplacer Zod
– D. Désactiver le streaming
Réponses : 1‑B · 2‑B · 3‑B
FAQ rapide
- AI SDK = uniquement Vercel Hosting ? Non — toolkit TypeScript ; Vercel reste l’éditeur et le gateway est optionnel.
- Faut-il Next.js ? Non pour Core (
generateTexten script Node). Next.js +@ai-sdk/reactpour le chat UI rapide. - Gateway vs
@ai-sdk/openai? Gateway = une clé, beaucoup de modèles en string ; package provider = contrôle direct d’un vendor. - Où placer la clé ? Serveur / CI secrets uniquement — jamais
NEXT_PUBLIC_*pour une clé LLM.
FAQ
Pourquoi le Vercel AI SDK en DevOps ?
Pour coller rapidement un assistant interne (runbooks, résumé d’incident) avec streaming et tools, sans réinventer le wiring provider.
Clés API côté browser ?
Non — toujours serveur. Rotation et budgets comme tout secret ops.
Lien OpenRouter ?
Oui pour multi-modèles — openrouter-multi-modeles.
Structured outputs ?
ai-structured-outputs · function calling ai-function-calling.
Pour aller plus loin
- Docs : Getting started Next.js App Router, Generating text, Migration 6.0, llms.txt
- Templates officiels chatbot / RAG / multi-step tools sur ai-sdk.dev
Maillage série IA Outils 2026
| ← Précédent | OpenRouter : multi-modèles |
| → Suivant | Perplexity pour recherche tech |
| Hub | IA pour DevOps : parcours 2026 |
| Aussi | Function calling · Structured outputs · RAG docs infra · MCP DevOps · Ollama locaux |
Compléments opérationnels
Standard de brief réutilisable
Pour vercel-ai-sdk, adoptez un brief unique partagé par l’équipe. Il contient toujours cinq champs : objectif mesurable, contexte borné (lab/staging), liste blanche de fichiers ou ressources, interdits explicites (secrets, réseau, prod), et definition of done exécutable (commande de test ou checklist). Sans ces champs, l’outil improvisera — parfois avec élégance, souvent hors périmètre.
Stockez les briefs gagnants sous briefs/vercel-ai-sdk/ dans un dépôt de documentation interne. Chaque brief cite le commit de référence et le modèle utilisé. Au troisième succès comparable, ouvrez une PR qui transforme le brief en rule, Skill ou slash command. Voir ai-skills-concept, claude-skills-instructions et evaluer-qualite-skill.
Revue de diff comme compétence P0
La vitesse d’un agent n’a aucune valeur si personne ne sait lire un diff. Instituez une règle simple : aucun apply massif sans parcours hunk par hunk. Posez-vous trois questions : ce changement est-il demandé ? est-il testé ? est-il réversible ? Si une réponse est non, refusez ou exigez un plan plus petit.
En atelier, faites commenter un diff à voix haute pendant cinq minutes. Les juniors apprennent ainsi le vocabulaire du refus. Reliez cette pratique à ai-code-review-pr et aux workflows ai-agent-workflows.
Sécurité continue
Les surfaces vercel-ai-sdk multiplient les occasions d’injection et de fuite. Traitez tickets, README upstream, logs et ressources MCP comme des données non fiables. Séparez instructions et données. Allowlist tools. Confirmation humaine avant mutation. Guide : ai-prompt-injection-securite, mcp-servers-devops, claude-code-mcp.
Secrets : variables d’environnement de session, gestionnaire d’équipe, rotation, jamais de commit. Si un secret fuit dans un chat vendor, supposez-le compromis et rotatez.
Coûts, modèles et mode dégradé
Documentez un mapping fast/strong et un soft-cap mensuel dans la stack perso. OpenRouter peut aider à basculer — openrouter-multi-modeles. Le local (ollama-llm-locaux + continue-dev) sert de mode dégradé ou de bac à sable confidentialité.
Surveillez les changements silencieux de modèle par défaut : une régression de qualité est souvent un routing vendor, pas « l’équipe qui a oublié comment prompter ».
Ancrage parcours
vercel-ai-sdk n’est qu’une étape du parcours IA DevOps 2026.
Rituals hebdomadaires
Hebdo : promouvoir un brief en Skill/rule ; archiver un échec instructif ; vérifier le budget tokens.
Quand arrêter l’outil
Arrêtez la session si : le DoD échoue deux fois de suite sans diagnostic clair ; l’outil insiste pour sortir du scope ; une commande dangereuse revient après refus ; vous ne comprenez plus le diff.
Ponts concrets vers d’autres tutoriels
Après ce lab, enchaînez selon besoin : agent CLI (claude-code-demarrer, openai-codex-intro-2026, aider-pair-programming), IDE (windsurf-cascade, continue-dev, cursor-agent-composer-2026), qualité (evaluer-qualite-skill, ai-routines-agents), ou recherche (gemini-cli-deep-research, chatgpt-search-browsing).
Retour parcours IA — hub Claude, Codex, ChatGPT et Skills.