Génération de texte avancée et ingénierie des invites avec le "AI SDK" de Vercel - Partie 4
Dans la partie 3, nous avons exploré les complétions de texte de base. Maintenant, allons un peu plus loin. "La génération de texte" peut couvrir une large gamme de tâches, allant de l'écriture d'histoires créatives et de poèmes à la génération de code, de textes marketing ou d'explications détaillées. La clé pour débloquer ces capacités réside souvent dans l'ingénierie de l'invite – l'art et la science de créer des invites efficaces pour guider le LLM.

Technologies Used
Ce post va s'appuyer sur notre exemple de complétion dans la Partie 3, en se concentrant sur :
- Stratégies pour des invites plus sophistiquées.
- Utiliser les messages système pour définir le contexte ou la personnalité.
- Techniques d'incitation en few-shot.
- Contrôler des paramètres de sortie tels que la température et le nombre maximal de jetons.
Prérequis
- Familiarité avec la configuration de la Partie 3 (utilisant
streamText
etuseCompletion
).
Le pouvoir de l'ingénierie des invites
La même fonction streamText et le hook useCompletion peuvent produire des résultats très différents en fonction de l'invite. Voici quelques techniques :
Étape 1 : Instructions claires et contexte
Soyez explicite sur ce que vous voulez.
- Mauvaise consigne : "Écrivez à propos des chiens."
- Bonne Consigne : "Rédigez une introduction de 100 mots pour un article intitulé 'Les joies d'adopter un chien âgé', en vous concentrant sur les avantages émotionnels pour le chien et le propriétaire. Le ton doit être chaleureux et encourageant."
Étape 2 : Messages du système (pour les modèles de chat)
Lors de l'utilisation de modèles de discussion (comme gpt-3.5-turbo
, gpt-4o
) via streamText
(en passant un tableau de messages
au lieu d'une simple chaîne de prompt
), vous pouvez utiliser un message "système" pour définir le comportement global ou la personnalité de l'IA.
Modification de la route de l'API (app/api/generate-text/route.ts
- une nouvelle ou adapter complète
):
// app/api/generate-text/route.ts
import { OpenAI } from '@ai-sdk/openai';
import { StreamingTextResponse, streamText, Message } from 'ai';
export const runtime = 'edge';
export const maxDuration = 60; // Les tâches plus longues peuvent nécessiter plus de temps
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
export async function POST(req: Request) {
const { userPrompt, systemMessage, temperature, maxTokens } = await req.json();
if (!userPrompt) {
return new Response('Le message de l'utilisateur est requis', { status: 400 });
}
const messages: Message[] = [];
if (systemMessage) {
messages.push({ role: 'system', content: systemMessage });
}
messages.push({ role: 'user', content: userPrompt });
const result = await streamText({
model: openai.chat('gpt-4o'), // Ou votre modèle de chat préféré
messages,
temperature: temperature ? parseFloat(temperature) : 0.7, // Par défaut 0.7
maxTokens: maxTokens ? parseInt(maxTokens) : 500, // Limite raisonnable par défaut
// topP, frequencyPenalty, presencePenalty peuvent aussi être définis
});
return result.toAIStreamResponse();
}
Côté client (app/advanced-textgen/page.tsx
):
// app/advanced-textgen/page.tsx
'use client';
import { FormEvent, useState } from 'react';
import { useCompletion } from 'ai/react';
export default function AdvancedTextGenPage() {
const [userPrompt, setUserPrompt] = useState('');
const [systemMessage, setSystemMessage] = useState('');
const [temperature, setTemperature] = useState('0.7');
const [maxTokens, setMaxTokens] = useState('500');
const { completion, complete, isLoading, stop } = useCompletion({
api: '/api/generate-text', // Notre nouveau point de terminaison API mis à jour
});
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
// La fonction `complete` du hook `useCompletion` peut prendre l'invite
// et un `body` optionnel pour des paramètres supplémentaires.
complete(userPrompt, {
body: {
systemMessage,
temperature: parseFloat(temperature),
maxTokens: parseInt(maxTokens),
},
});
};
return (
<div className="flex flex-col w-full max-w-xl py-12 mx-auto">
<h1 className="text-2xl font-bold mb-6">Génération de texte avancée</h1>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="system-message" className="block text-sm font-medium text-gray-700">
Message système (Persona/Contexte) :
</label>
<textarea
id="system-message"
className="w-full p-2 border border-gray-300 rounded shadow-sm text-black"
rows={2}
value={systemMessage}
placeholder="par exemple, Vous êtes un capitaine pirate sarcastique."
onChange={(e) => setSystemMessage(e.target.value)}
/>
</div>
<div>
<label htmlFor="user-prompt" className="block text-sm font-medium text-gray-700">
Invite de l'utilisateur :
</label>
<textarea
id="user-prompt"
className="w-full p-2 border border-gray-300 rounded shadow-sm text-black"
rows={4}
value={userPrompt}
placeholder="par exemple, Racontez-moi une courte histoire sur la découverte d'un trésor."
onChange={(e) => setUserPrompt(e.target.value)}
required
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label htmlFor="temperature" className="block text-sm font-medium text-gray-700">
Température (0-1) : {temperature}
</label>
<input
type="range"
id="temperature"
min="0" max="1" step="0.1"
value={temperature}
onChange={(e) => setTemperature(e.target.value)}
className="w-full"
/>
</div>
<div>
<label htmlFor="max-tokens" className="block text-sm font-medium text-gray-700">
Nombre maximal de jetons : {maxTokens}
</label>
<input
type="number"
id="max-tokens"
min="50" max="4000" step="50"
value={maxTokens}
onChange={(e) => setMaxTokens(e.target.value)}
className="w-full p-2 border border-gray-300 rounded text-black"
/>
</div>
</div>
<div className="flex items-center space-x-2">
<button
type="submit"
disabled={isLoading}
className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 disabled:bg-gray-300"
>
{isLoading ? 'Génération...' : 'Générer le texte'}
</button>
{isLoading && (
<button
type="button"
onClick={stop}
className="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600"
>
Arrêter
</button>
)}
</div>
</form>
{completion && (
<div className="mt-6 p-4 border border-gray-200 rounded bg-gray-50">
<h3 className="text-lg font-semibold mb-2">Texte généré :</h3>
<p className="whitespace-pre-wrap text-gray-800">{completion}</p>
</div>
)}
</div>
);
}
Maintenant, vous pouvez définir un message système tel que "Vous êtes un assistant utile qui explique des sujets complexes en termes simples" puis une invite utilisateur comme "Expliquez l'enchevêtrement quantique."
Étape 3 : Amorçage avec peu d'exemples
Fournissez des exemples dans votre consigne pour montrer au modèle de langage à grande échelle le format ou le style de sortie souhaité.
Exemple de message d'utilisateur (pour l'API ci-dessus, aucun message système requis ici) :
Traduisez les expressions anglaises suivantes en français :
loutre de mer => loutre de mer
menthe poivrée => menthe poivrée
fromage => fromage
cerise =>
Le LLM a plus de chances de simplement produire "cerise".
Cette technique est puissante pour des tâches telles que :
- Classification : "Classifiez le sentiment de ces avis : [exemple positif], [exemple négatif], Avis : [nouvel avis] => Sentiment :"
- Imitation de style : Fournissez quelques phrases dans un style d'écriture spécifique, puis demandez-lui de continuer.
Étape 4 : Contrôle des paramètres de sortie
- Température : (0,0 - 2,0, typiquement 0-1 pour la plupart des modèles). Des valeurs plus basses (par exemple, 0,2) rendent la sortie plus déterministe et concentrée. Des valeurs plus élevées (par exemple, 0,8) la rendent plus aléatoire et créative.
- Jetons maximum (
maxTokens
) : Limite la longueur de la réponse générée. Utile pour contrôler les coûts et le temps de réponse. - Top P (
topP
) : Échantillonnage du noyau. Ne prend en compte que les jetons dont la masse de probabilité cumulative dépassetopP
. - Pénalité de Fréquence/Présence : Décourager la répétition des jetons.
Nous avons ajouté la température
et maxTokens
à notre API et à l'exemple de client ci-dessus.
Étape 5 : Expérimentez !
La meilleure façon de maîtriser la génération de texte est d'expérimenter.
- Essayez différents personnages dans le message du système.
- Créez des invites à quelques essais pour diverses tâches (par exemple, écrire un tweet, générer une signature de fonction, résumer un titre de nouvelle).
- Jouez avec la température pour voir comment elle affecte la créativité par rapport à la prévisibilité.
- Si vous essayez d'obtenir une sortie structurée (comme du JSON), soyez très précis dans votre invite sur le format souhaité. Conseil : La partie 5 abordera une meilleure manière pour le JSON structuré !
Points clés
- L'ingénierie des invites est une compétence cruciale pour l'utilisation efficace des modèles de langage à grande échelle.
- Les messages système préparent le terrain pour les interactions avec le modèle de discussion.
- Des exemples avec peu d'instances peuvent considérablement améliorer la qualité de la production et le respect du format.
- Des paramètres tels que la
température
et lemaxTokens
offrent un contrôle précis sur le processus de génération. - Le SDK IA de Vercel
streamText
(avec des messages) etuseCompletion
(avec un corps pour des paramètres supplémentaires) vous donnent la flexibilité pour mettre en œuvre ces techniques avancées.
Quelle est la prochaine étape ?
Parfois, vous ne souhaitez pas seulement du texte libre ; vous avez besoin de données structurées, comme un objet JSON. Dans la partie 5, nous explorerons la fonction generateObject du SDK Vercel AI, qui est spécialement conçue pour générer des objets structurés et typés à l'aide des LLMs, souvent avec validation de schéma.