Intelligence artificielle pour développeurs : premiers pas concrets
LLMs, prompt engineering, API OpenAI, agents — ce que les développeurs doivent savoir pour intégrer l'IA dans leurs applications, sans la hype.
En 2023, "intégrer l'IA" voulait dire coller une iframe ChatGPT dans une page. En 2026, ça veut dire construire des workflows où des LLMs raisonnent, appellent des outils, lisent des fichiers et prennent des décisions. La distance entre ces deux situations est une API et quelques patterns bien compris.
Ce guide est pour les développeurs qui veulent aller au-delà du copier-coller de l'exemple de la documentation.
Ce qu'est un LLM, sans les métaphores inutiles
Un LLM (Large Language Model) est un modèle statistique entraîné sur du texte. Il prédit le prochain token le plus probable étant donné les tokens précédents. C'est tout.
Ce qui en fait un outil utile : avec assez de données et de paramètres, "prédire le prochain token" capture la grammaire, les faits, le raisonnement logique, et les conventions de code. Le modèle n'a pas de conscience — il produit du texte statistiquement cohérent avec ce qu'il a vu pendant l'entraînement.
Implications pratiques :
- Il peut se tromper avec confiance (hallucinations)
- Il est non-déterministe — même prompt, réponse légèrement différente
- Il a une fenêtre de contexte fixe — il ne se souvient pas des conversations passées sans infrastructure externe
- Il est bon pour du texte structuré, du code, des transformations de données, des résumés
Premier appel API
npm install openai
# Ou pour Claude (Anthropic)
npm install @anthropic-ai/sdkimport OpenAI from 'openai'
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{
role: 'system',
content: 'Tu es un assistant qui répond uniquement en français, de façon concise.',
},
{
role: 'user',
content: 'Explique ce qu\'est un index en base de données en 2 phrases.',
},
],
temperature: 0.3, // 0 = très déterministe, 1 = plus créatif
max_tokens: 200,
})
console.log(response.choices[0].message.content)
console.log(response.usage) // tokens utilisés — impact sur le coûtimport Anthropic from '@anthropic-ai/sdk'
const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY })
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-6',
max_tokens: 200,
system: 'Tu es un assistant qui répond en français, de façon concise.',
messages: [{ role: 'user', content: 'Explique ce qu\'est un index en BDD en 2 phrases.' }],
})
console.log(response.content[0].text)Prompt engineering : les patterns qui fonctionnent
Un bon prompt n'est pas une question poli — c'est une spécification.
System prompt : poser le cadre
const systemPrompt = `
Tu es un assistant spécialisé dans la revue de code JavaScript.
Quand on te soumet du code :
1. Identifie les bugs ou vulnérabilités de sécurité en premier
2. Suggère des améliorations de performance si pertinent
3. Garde tes réponses sous 300 mots
4. Format : bullet points pour les problèmes, puis un bloc de code corrigé
Tu n'expliques pas ce que fait le code — seulement ce qui pourrait être amélioré.
`Few-shot prompting : montrer des exemples
const messages = [
{ role: 'system', content: 'Tu extrais des données JSON depuis du texte.' },
{
role: 'user',
content: 'Commande reçue de Alice Martin, 3 pizzas margherita, livraison rue de la Paix à 19h30',
},
{
role: 'assistant',
content: JSON.stringify({
client: 'Alice Martin',
items: [{ name: 'pizza margherita', quantity: 3 }],
address: 'rue de la Paix',
delivery_time: '19:30',
}),
},
{
role: 'user',
content: 'Bob Dupont a commandé 2 burgers et 1 frite, pour 20h, 12 avenue Victor Hugo',
},
// Le modèle suit le pattern établi dans les exemples
]Chain-of-thought : raisonner étape par étape
const prompt = `
Analyse ce bug et trouve la cause racine.
Raisonne étape par étape avant de conclure.
Code :
\`\`\`javascript
async function getUsers() {
const users = await db.query('SELECT * FROM users')
return users.map(u => u.name.toUpperCase())
}
\`\`\`
Erreur en production : "Cannot read properties of undefined (reading 'toUpperCase')"
`
// Le "raisonne étape par étape" améliore significativement la qualité sur les problèmes complexesStreaming : réponses en temps réel
Les LLMs génèrent token par token. Streamer la réponse au client évite d'attendre 10s avant de voir le premier caractère.
const stream = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Écris un article de 500 mots sur Redis.' }],
stream: true,
})
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content ?? ''
process.stdout.write(delta) // Afficher au fur et à mesure
}app.get('/api/generate', authenticate, async (req, res) => {
res.setHeader('Content-Type', 'text/event-stream')
res.setHeader('Cache-Control', 'no-cache')
res.setHeader('Connection', 'keep-alive')
const stream = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: req.query.prompt }],
stream: true,
})
for await (const chunk of stream) {
const delta = chunk.choices[0]?.delta?.content ?? ''
if (delta) res.write(`data: ${JSON.stringify({ text: delta })}\n\n`)
}
res.write('data: [DONE]\n\n')
res.end()
})Function calling / Tool use
Le vrai pouvoir des LLMs modernes : ils peuvent décider d'appeler des fonctions. Le modèle ne les exécute pas lui-même — il retourne les paramètres, et votre code exécute la fonction.
const tools = [
{
type: 'function',
function: {
name: 'get_weather',
description: 'Retourne la météo actuelle pour une ville',
parameters: {
type: 'object',
properties: {
city: { type: 'string', description: 'Nom de la ville' },
unit: { type: 'string', enum: ['celsius', 'fahrenheit'], default: 'celsius' },
},
required: ['city'],
},
},
},
{
type: 'function',
function: {
name: 'search_database',
description: 'Recherche des articles dans la base de données',
parameters: {
type: 'object',
properties: {
query: { type: 'string' },
limit: { type: 'number', default: 5 },
},
required: ['query'],
},
},
},
]
async function runWithTools(userMessage) {
const messages = [{ role: 'user', content: userMessage }]
while (true) {
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages,
tools,
tool_choice: 'auto',
})
const message = response.choices[0].message
messages.push(message)
// Si pas d'appel d'outil — réponse finale
if (!message.tool_calls) return message.content
// Exécuter les outils demandés
for (const toolCall of message.tool_calls) {
const args = JSON.parse(toolCall.function.arguments)
let result
if (toolCall.function.name === 'get_weather') {
result = await getWeatherAPI(args.city, args.unit)
} else if (toolCall.function.name === 'search_database') {
result = await searchArticles(args.query, args.limit)
}
messages.push({
role: 'tool',
tool_call_id: toolCall.id,
content: JSON.stringify(result),
})
}
// Continuer la boucle — le modèle va générer une nouvelle réponse avec les résultats
}
}
const answer = await runWithTools('Quel temps fait-il à Paris et y a-t-il des articles sur Docker ?')Construire un agent simple
Un agent est une boucle : observe → décide → agit → observe.
class SimpleAgent {
constructor(tools) {
this.tools = tools
this.messages = []
}
async run(task) {
this.messages = [
{
role: 'system',
content: `Tu es un assistant. Pour accomplir des tâches, utilise les outils disponibles.
Réfléchis étape par étape. Quand tu as la réponse finale, réponds directement sans appeler d'outil.`,
},
{ role: 'user', content: task },
]
let iterations = 0
const maxIterations = 10 // Éviter les boucles infinies
while (iterations < maxIterations) {
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: this.messages,
tools: this.tools,
})
const message = response.choices[0].message
this.messages.push(message)
if (!message.tool_calls) return message.content // Réponse finale
// Exécuter les outils et continuer
for (const call of message.tool_calls) {
const result = await this.executeTool(call)
this.messages.push({
role: 'tool',
tool_call_id: call.id,
content: JSON.stringify(result),
})
}
iterations++
}
return 'Nombre maximum d\'itérations atteint.'
}
async executeTool(toolCall) {
// Dispatcher vers la bonne implémentation
const fn = this.toolImplementations[toolCall.function.name]
if (!fn) throw new Error(`Outil inconnu: ${toolCall.function.name}`)
return fn(JSON.parse(toolCall.function.arguments))
}
}Coûts et optimisation
Les LLMs se facturent au token (1 token ≈ 0.75 mot). Quelques repères (GPT-4o, juin 2026) :
- Input : ~$2.50 / million de tokens
- Output : ~$10 / million de tokens
// Estimer le coût avant d'envoyer
// GPT-4o : ~$0.0025 pour 1000 tokens input
// Un article de 1500 mots ≈ 2000 tokens ≈ $0.005
// Bonnes pratiques coût :
// 1. Utiliser un modèle moins puissant pour les tâches simples (gpt-4o-mini, claude-haiku)
// 2. Cacher les réponses quand possible
// 3. Réduire le contexte — ne passer que ce qui est nécessaire
// 4. Limiter max_tokens pour les réponses courtes
const response = await openai.chat.completions.create({
model: 'gpt-4o-mini', // 20x moins cher que gpt-4o pour la classification/extraction
messages,
max_tokens: 100, // Suffisant pour une réponse courte
})Considérations de données et RGPD
Avant d'envoyer des données utilisateurs à une API LLM, vérifiez les implications légales. RGPD et IA soulèvent des questions non triviales sur le traitement des données — notamment si les données envoyées sont utilisées pour l'entraînement des modèles.
Solutions : API Tier Enterprise (données non utilisées pour l'entraînement), modèles on-premise (Llama, Mistral), ou anonymisation avant envoi.
L'IA dans les applications n'est plus expérimentale — c'est une compétence d'ingénierie standard. Les patterns du function calling et des agents que vous venez de voir couvrent 80% des cas d'usage réels. L'impact sociétal plus large de l'IA mérite aussi attention : les décisions de design que vous prenez aujourd'hui sur vos applications IA ont des conséquences au-delà du code.