El hook useChat
El hook useChat es la forma principal de construir interfaces de chat con Vercel AI SDK.
Maneja el estado de mensajes, las respuestas en streaming, los estados de carga y la entrada del usuario automáticamente.
Qué ofrece useChat
- messages: Arreglo de mensajes con actualizaciones automáticas
- input: Valor actual del campo de entrada
- handleInputChange: Handler para cambios del input
- handleSubmit: Handler para enviar el formulario
- isLoading: Estado de carga durante la generación
- error: Estado de error si algo falla
Uso básico
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
<div className="flex flex-col h-screen">
{/* Message List */}
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.map((message) => (
<div
key={message.id}
className={`p-4 rounded-lg ${
message.role === 'user'
? 'bg-blue-100 ml-auto max-w-[80%]'
: 'bg-gray-100 mr-auto max-w-[80%]'
}`}
>
<p className="font-semibold">
{message.role === 'user' ? 'You' : 'AI'}
</p>
<p className="whitespace-pre-wrap">{message.content}</p>
</div>
))}
</div>
{/* Input Form */}
<form onSubmit={handleSubmit} className="p-4 border-t">
<div className="flex gap-2">
<input
value={input}
onChange={handleInputChange}
placeholder="Type a message..."
className="flex-1 p-2 border rounded-lg"
/>
<button
type="submit"
className="px-4 py-2 bg-blue-500 text-white rounded-lg"
>
Send
</button>
</div>
</form>
</div>
);
}
Ruta API del servidor
El hook useChat necesita una ruta API en el servidor que reciba los mensajes y devuelva la respuesta en streaming. Esta ruta usa streamText para generar tokens de forma progresiva.
// app/api/chat/route.ts
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
export const maxDuration = 30;
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai('gpt-4-turbo'),
system: 'You are a helpful assistant.',
messages,
});
return result.toDataStreamResponse();
}
Todas las opciones de useChat
El hook expone muchas propiedades y callbacks que permiten personalizar el comportamiento del chat: desde la URL de la API hasta callbacks para eventos de respuesta, error y finalización.
const {
messages, // Message array
input, // Current input value
handleInputChange, // Input onChange handler
handleSubmit, // Form onSubmit handler
isLoading, // Loading state
error, // Error state
reload, // Regenerate last AI response
stop, // Stop current generation
setMessages, // Manually set messages
append, // Append a message programmatically
setInput, // Manually set input value
} = useChat({
api: '/api/chat', // API endpoint (default: '/api/chat')
id: 'my-chat', // Unique ID for multiple chats
initialMessages: [], // Pre-populate messages
initialInput: '', // Initial input value
// Callbacks
onResponse: (response) => {
console.log('Response started:', response);
},
onFinish: (message) => {
console.log('Message complete:', message);
},
onError: (error) => {
console.error('Error:', error);
},
// Additional options
headers: { 'X-Custom-Header': 'value' },
body: { customField: 'value' }, // Extra data to send
sendExtraMessageFields: true, // Include extra message fields
});
Estados de carga
La propiedad isLoading indica si el modelo está generando una respuesta. Se puede usar para mostrar indicadores visuales y deshabilitar el campo de entrada durante la generación.
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat();
return (
<div>
{messages.map((m) => (
<div key={m.id}>{m.content}</div>
))}
{isLoading && (
<div className="flex items-center gap-2 text-gray-500">
<div className="animate-spin h-4 w-4 border-2 border-blue-500 rounded-full border-t-transparent" />
AI is typing...
</div>
)}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={handleInputChange}
disabled={isLoading}
/>
<button type="submit" disabled={isLoading}>
{isLoading ? 'Sending...' : 'Send'}
</button>
</form>
</div>
);
}
Detener y regenerar
Las funciones stop y reload permiten al usuario controlar la generación: detener una respuesta en curso o regenerar la última respuesta del modelo si no fue satisfactoria.
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const {
messages,
input,
handleInputChange,
handleSubmit,
isLoading,
stop,
reload,
} = useChat();
return (
<div>
{messages.map((m) => (
<div key={m.id}>{m.content}</div>
))}
<div className="flex gap-2">
{isLoading ? (
<button onClick={stop} className="text-red-500">
Stop generating
</button>
) : (
messages.length > 0 && (
<button onClick={() => reload()} className="text-blue-500">
Regenerate response
</button>
)
)}
</div>
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
<button type="submit">Send</button>
</form>
</div>
);
}
Control programático de mensajes
Con append y setMessages puedes añadir mensajes de forma programática o modificar el historial completo. Esto es útil para mensajes predefinidos, sugerencias rápidas o limpiar la conversación.
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const { messages, append, setMessages } = useChat();
// Add a message programmatically
const sendPredefinedMessage = () => {
append({
role: 'user',
content: 'Tell me a joke!',
});
};
// Clear all messages
const clearChat = () => {
setMessages([]);
};
// Edit the last message and regenerate
const editLastMessage = (newContent: string) => {
const newMessages = messages.slice(0, -1);
setMessages(newMessages);
append({
role: 'user',
content: newContent,
});
};
return (
<div>
{messages.map((m) => (
<div key={m.id}>{m.content}</div>
))}
<button onClick={sendPredefinedMessage}>Tell me a joke</button>
<button onClick={clearChat}>Clear chat</button>
</div>
);
}
Headers y body personalizados
'use client';
import { useChat } from 'ai/react';
export default function Chat() {
const { messages, input, handleInputChange, handleSubmit } = useChat({
// Send additional data with each request
body: {
userId: 'user-123',
sessionId: 'session-456',
},
// Custom headers
headers: {
'X-Custom-Header': 'my-value',
},
});
return (
<div>
{messages.map((m) => (
<div key={m.id}>{m.content}</div>
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
<button type="submit">Send</button>
</form>
</div>
);
}
💡 Puntos clave
- •
useChatmaneja estado y streaming automáticamente - • Úsalo con una ruta API del servidor usando
streamText - • Usa
isLoadingpara indicadores de carga - •
stop()cancela,reload()regenera - •
append()ysetMessages()para control programático
📚 Más recursos
-
Documentación de useChat →
Referencia completa del hook useChat.
-
useChat con tool calling →
Aprende a usar herramientas con la interfaz de chat.