<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>LLM on kenji.blog</title><link>http://kenji.blog/fr/categories/llm/</link><description>Recent content in LLM on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Fri, 11 Sep 2026 16:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/categories/llm/index.xml" rel="self" type="application/rss+xml"/><item><title>Comment affiner TinyLLaMA le plus rapidement possible dans un environnement sur site</title><link>http://kenji.blog/fr/p/tinyllama-on-premises-fast-tuning-guide/</link><pubDate>Fri, 11 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/tinyllama-on-premises-fast-tuning-guide/</guid><description>&lt;img src="http://kenji.blog/p/tinyllama-on-premises-fast-tuning-guide/img/eyecatch.jpg" alt="Featured image of post Comment affiner TinyLLaMA le plus rapidement possible dans un environnement sur site" />&lt;h2 id="1-introduction--pourquoi-tinyllama-et-le-sur-site-aujourdhui-">1. Introduction : Pourquoi TinyLLaMA et le sur site aujourd&amp;rsquo;hui ?
&lt;/h2>&lt;p>L&amp;rsquo;évolution des grands modèles de langage (LLM) progresse à une vitesse fulgurante, et avec elle, le nombre de paramètres des modèles continue de s&amp;rsquo;étendre pour atteindre des centaines de milliards. Si des modèles gigantesques comme GPT-4 et Claude 3 offrent des performances inégalées, les coûts de calcul pour l&amp;rsquo;inférence et l&amp;rsquo;apprentissage, ainsi que les problèmes de sécurité et de confidentialité des données lors de l&amp;rsquo;utilisation d&amp;rsquo;API externes, constituent des obstacles majeurs pour les entreprises. En particulier pour les tâches impliquant des données internes hautement confidentielles ou des informations personnelles, l&amp;rsquo;envoi de données à des API LLM publiques dans le cloud est souvent inacceptable du point de vue de la conformité (RGPD, APPI, etc.).&lt;/p>
&lt;p>C&amp;rsquo;est là que les &lt;strong>petits modèles de langage (SLM : Small Language Models)&lt;/strong> et le &lt;strong>déploiement local dans des environnements sur site&lt;/strong> (on-premises) entrent en jeu. Parmi eux, &amp;ldquo;&lt;strong>TinyLLaMA&lt;/strong>&amp;rdquo; se distingue. Avec une taille compacte de seulement 1,1B (1,1 milliard) de paramètres, il a été pré-entraîné sur un ensemble de données massif d&amp;rsquo;environ 3 billions de jetons (tokens), offrant des performances exceptionnelles par rapport aux modèles de la même catégorie.&lt;/p>
&lt;p>Cet article fournit un guide complet pour affiner (fine-tuning) TinyLLaMA de manière &amp;ldquo;ultra-rapide et très efficace&amp;rdquo; pour vos tâches spécifiques dans un environnement sur site (serveur local ou station de travail). Nous couvrirons tout de manière exhaustive, des fondements mathématiques aux dernières techniques d&amp;rsquo;optimisation, en passant par le code d&amp;rsquo;implémentation concret en PyTorch.&lt;/p>
&lt;hr>
&lt;h2 id="2-architecture-et-caractéristiques-de-tinyllama">2. Architecture et caractéristiques de TinyLLaMA
&lt;/h2>&lt;p>TinyLLaMA suit l&amp;rsquo;architecture LLaMA (Large Language Model Meta AI) développée par Meta. Tout en maintenant le nombre de paramètres à 1,1B, il utilise la même pile technologique que LLaMA 2, ce qui rend son écosystème hautement compatible.&lt;/p>
&lt;h3 id="principaux-composants-de-larchitecture">Principaux composants de l&amp;rsquo;architecture
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>RMSNorm (Root Mean Square Normalization) :&lt;/strong>
Une méthode de normalisation qui améliore l&amp;rsquo;efficacité des calculs en omettant la soustraction de la moyenne des calculs LayerNorm traditionnels. Elle augmente le débit tout en maintenant la stabilité de l&amp;rsquo;apprentissage.&lt;/li>
&lt;li>&lt;strong>Fonction d&amp;rsquo;activation SwiGLU :&lt;/strong>
Dans le Feed Forward Network (FFN), SwiGLU est utilisé à la place des classiques ReLU ou GELU. Mathématiquement, cela s&amp;rsquo;exprime comme suit :
$$ \text{SwiGLU}(x, W, V) = \text{Swish}(xW) \otimes (xV) $$
Ici, $\otimes$ représente le produit élément par élément (produit de Hadamard), et la fonction Swish est $\text{Swish}(z) = z \cdot \sigma(\beta z)$. Cela améliore considérablement la puissance de représentation.&lt;/li>
&lt;li>&lt;strong>RoPE (Rotary Position Embedding) :&lt;/strong>
Une méthode qui combine les avantages de l&amp;rsquo;encodage de position absolu et relatif. Elle présente de fortes performances de généralisation même lorsque la longueur de la séquence est étendue.&lt;/li>
&lt;li>&lt;strong>Grouped Query Attention (GQA) :&lt;/strong>
Une approche intermédiaire entre la Multi-Head Attention (MHA) et la Multi-Query Attention (MQA), qui permet d&amp;rsquo;économiser la bande passante mémoire et d&amp;rsquo;améliorer considérablement la vitesse d&amp;rsquo;inférence en regroupant les têtes de clé (key) et de valeur (value).&lt;/li>
&lt;/ol>
&lt;p>Le diagramme Mermaid ci-dessous illustre le flux de données global de TinyLLaMA et la structure du bloc Transformer.&lt;/p>
&lt;div class="mermaid">graph TD
A["Texte d'entrée"] --> B["Tokeniseur (BPE)"]
B --> C["Couche d'intégration (Embedding)"]
C --> D["Blocs Transformer (x22 Couches pour TinyLLaMA)"]
D --> E["RMSNorm (Final)"]
E --> F["Projection Linéaire (Taille du vocabulaire)"]
F --> G["Probabilités de sortie (Softmax)"]
subgraph "Anatomie du bloc Transformer"
D1["État caché d'entrée"] --> D2["RMSNorm"]
D2 --> D3["Grouped Query Attention (GQA)"]
D3 --> D4["Ajout Résiduel"]
D4 --> D5["RMSNorm"]
D5 --> D6["FFN SwiGLU"]
D6 --> D7["Ajout Résiduel"]
D7 --> D8["Sortie vers la couche suivante"]
D1 -.-> D4
D4 -.-> D7
end&lt;/div>
&lt;hr>
&lt;h2 id="3-la-révolution-du-fine-tuning--lora-et-qlora">3. La révolution du Fine-Tuning : LoRA et QLoRA
&lt;/h2>&lt;p>Pour effectuer un fine-tuning avec tous les paramètres dans un environnement sur site, même avec un modèle de 1,1B, il faut consommer des dizaines de gigaoctets de VRAM (mémoire vidéo) pour stocker les états de l&amp;rsquo;optimiseur et les gradients. Les méthodes &lt;strong>PEFT (Parameter-Efficient Fine-Tuning)&lt;/strong> telles que &amp;ldquo;&lt;strong>LoRA&lt;/strong>&amp;rdquo; et son extension quantifiée &amp;ldquo;&lt;strong>QLoRA&lt;/strong>&amp;rdquo; sont essentielles pour un apprentissage efficace avec des ressources limitées.&lt;/p>
&lt;h3 id="31-contexte-mathématique-de-lora-low-rank-adaptation">3.1 Contexte mathématique de LoRA (Low-Rank Adaptation)
&lt;/h3>&lt;p>LoRA est une méthode qui fixe (gèle) la matrice de poids pré-entraînée et approxime la quantité de mise à jour de ce poids ($\Delta W$) par le produit de deux petites matrices de rang inférieur.&lt;/p>
&lt;p>Soit $W_0 \in \mathbb{R}^{d \times k}$ le poids pré-entraîné. Dans un fine-tuning complet, $W_0$ lui-même est mis à jour en $W_0 + \Delta W$. Cependant, avec LoRA, la matrice de mise à jour $\Delta W$ est décomposée comme suit :&lt;/p>
$$ \Delta W = B \times A $$
&lt;p>Ici, $B \in \mathbb{R}^{d \times r}$ et $A \in \mathbb{R}^{r \times k}$, et $r$ est un hyperparamètre appelé rang (Rank), qui est une très petite valeur (généralement 8, 16, 32, etc.) satisfaisant $r \ll \min(d, k)$.&lt;/p>
&lt;p>Le calcul de la passe avant (forward pass) est le suivant :&lt;/p>
$$ h = W_0 x + \Delta W x = W_0 x + B A x $$
&lt;p>À l&amp;rsquo;état initial, la matrice $A$ est initialisée de manière aléatoire avec une distribution normale (distribution gaussienne), et la matrice $B$ est initialisée avec une matrice nulle. Ainsi, $\Delta W$ au début de l&amp;rsquo;apprentissage est zéro, ce qui permet de commencer l&amp;rsquo;apprentissage tout en conservant parfaitement la sortie du modèle de base.&lt;/p>
&lt;div class="mermaid">graph LR
X["Vecteur d'entrée x"] --> W0["Poids pré-entraîné gelé (W_0)"]
X --> A["Matrice LoRA entraînable A (r x k)"]
A --> B["Matrice LoRA entraînable B (d x r)"]
W0 --> Add["Addition vectorielle"]
B --> Add
Add --> Y["Vecteur de sortie h"]&lt;/div>
&lt;h3 id="32-linnovation-de-qlora-quantized-lora">3.2 L&amp;rsquo;innovation de QLoRA (Quantized LoRA)
&lt;/h3>&lt;p>QLoRA pousse l&amp;rsquo;approche LoRA encore plus loin en quantifiant le modèle de base $W_0$ avec une précision de 4 bits (NormalFloat 4, NF4) et en le chargeant en mémoire. Cela réduit considérablement la consommation de VRAM.&lt;/p>
&lt;p>QLoRA intègre trois technologies importantes :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Quantification 4-bit NormalFloat (NF4) :&lt;/strong> Un type de données théoriquement optimal pour les poids suivant une distribution normale.&lt;/li>
&lt;li>&lt;strong>Double Quantification (Double Quantization) :&lt;/strong> Économise encore plus de mémoire en quantifiant également la constante de quantification (facteur d&amp;rsquo;échelle) elle-même.&lt;/li>
&lt;li>&lt;strong>Paged Optimizers :&lt;/strong> Utilise la fonction de mémoire unifiée de NVIDIA pour évacuer temporairement le statut de l&amp;rsquo;optimiseur vers la RAM du processeur lorsque la VRAM est insuffisante.&lt;/li>
&lt;/ol>
&lt;p>Grâce à cela, un fine-tuning qui nécessite normalement 16 à 24 Go de VRAM peut être exécuté confortablement même sur des GPU grand public (comme la RTX 3060 12 Go ou la RTX 4070).&lt;/p>
&lt;hr>
&lt;h2 id="4-exigences-matérielles-et-configuration-dans-un-environnement-sur-site">4. Exigences matérielles et configuration dans un environnement sur site
&lt;/h2>&lt;p>Les exigences matérielles pour affiner TinyLLaMA (1,1B) avec QLoRA sont extrêmement faibles.&lt;/p>
&lt;h3 id="spécifications-matérielles-recommandées">Spécifications matérielles recommandées
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>GPU :&lt;/strong> NVIDIA RTX 3060 (12 Go), RTX 3090/4090 (24 Go), ou NVIDIA A10G/A100, etc. Un minimum de 8 Go de VRAM est nécessaire pour fonctionner, mais 12 Go ou plus sont recommandés pour augmenter la taille du lot (batch size).&lt;/li>
&lt;li>&lt;strong>CPU :&lt;/strong> Processeur moderne à 8 cœurs ou plus (Intel Core i7/i9, AMD Ryzen 7/9)&lt;/li>
&lt;li>&lt;strong>RAM :&lt;/strong> 32 Go ou plus (Important comme destination d&amp;rsquo;évacuation depuis la VRAM lors de l&amp;rsquo;utilisation de Paged Optimizers)&lt;/li>
&lt;li>&lt;strong>Stockage :&lt;/strong> SSD NVMe (Pour accélérer le chargement des ensembles de données et la sauvegarde du modèle)&lt;/li>
&lt;/ul>
&lt;h3 id="configuration-de-lenvironnement-logiciel">Configuration de l&amp;rsquo;environnement logiciel
&lt;/h3>&lt;p>Voici les étapes d&amp;rsquo;installation prévues pour un environnement Ubuntu 22.04 LTS. Nous utiliserons Python 3.10 ou une version ultérieure.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Création et activation de l&amp;#39;environnement virtuel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">python3 -m venv tinyllama_env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">source&lt;/span> tinyllama_env/bin/activate
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Installation de PyTorch (pour CUDA 12.1)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Installation des bibliothèques liées aux Transformers&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install transformers datasets peft trl accelerate bitsandbytes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="5-techniques-doptimisation-pour-le-fine-tuning-le-plus-rapide">5. Techniques d&amp;rsquo;optimisation pour le fine-tuning le plus rapide
&lt;/h2>&lt;p>Pour terminer le fine-tuning &amp;ldquo;le plus rapidement possible&amp;rdquo; plutôt que de simplement exécuter un script, il est nécessaire de combiner les techniques d&amp;rsquo;optimisation suivantes.&lt;/p>
&lt;h3 id="51-flash-attention-2">5.1 Flash Attention 2
&lt;/h3>&lt;p>Le mécanisme d&amp;rsquo;Attention standard a une complexité temporelle et spatiale de $O(N^2)$ pour une longueur de séquence $N$. Flash Attention 2 optimise l&amp;rsquo;accès mémoire entre la SRAM du GPU et la HBM (High Bandwidth Memory), éliminant ainsi les goulots d&amp;rsquo;étranglement d&amp;rsquo;E/S sans réduire la quantité de calcul, augmentant la vitesse d&amp;rsquo;apprentissage de plusieurs fois et réduisant considérablement la consommation de mémoire.&lt;/p>
&lt;h3 id="52-gradient-checkpointing-point-de-contrôle-du-gradient">5.2 Gradient Checkpointing (Point de contrôle du gradient)
&lt;/h3>&lt;p>Une technique dans laquelle, au lieu de sauvegarder toutes les activations intermédiaires calculées lors de la passe avant dans la VRAM, seule une partie est sauvegardée, et elles sont recalculées lorsqu&amp;rsquo;elles sont nécessaires lors de la passe arrière. Le temps de calcul augmente d&amp;rsquo;environ 20 %, mais la consommation de mémoire peut être considérablement réduite, ce qui permet de définir une taille de lot plus importante et d&amp;rsquo;améliorer le débit global.&lt;/p>
&lt;h3 id="53-mixed-precision-training-apprentissage-en-précision-mixte-et-bfloat16">5.3 Mixed Precision Training (Apprentissage en précision mixte) et Bfloat16
&lt;/h3>&lt;p>Pour maximiser l&amp;rsquo;utilisation des Tensor Cores du GPU, les calculs pendant l&amp;rsquo;apprentissage sont effectués en &lt;code>bfloat16&lt;/code> (Brain Floating Point). Par rapport à &lt;code>float16&lt;/code>, la longueur en bits de l&amp;rsquo;exposant est la même que celle de &lt;code>float32&lt;/code>, de sorte que le risque de dépassement de capacité (overflow) ou de sous-dépassement (underflow) est extrêmement faible, ce qui stabilise l&amp;rsquo;apprentissage.&lt;/p>
&lt;hr>
&lt;h2 id="6-pratique--code-de-fine-tuning-qlora-pour-tinyllama">6. Pratique : Code de fine-tuning QLoRA pour TinyLLaMA
&lt;/h2>&lt;p>Nous allons maintenant expliquer le script PyTorch pour le fine-tuning le plus rapide intégrant toutes les optimisations ci-dessus. Nous utiliserons ici &lt;code>SFTTrainer&lt;/code> de la bibliothèque &lt;code>trl&lt;/code> (Transformer Reinforcement Learning) de Hugging Face.&lt;/p>
&lt;h3 id="61-préparation-de-lensemble-de-données-et-chargement-du-modèle">6.1 Préparation de l&amp;rsquo;ensemble de données et chargement du modèle
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">torch&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">datasets&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">load_dataset&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">transformers&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AutoModelForCausalLM&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">BitsAndBytesConfig&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TrainingArguments&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">peft&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">LoraConfig&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">get_peft_model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">prepare_model_for_kbit_training&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">trl&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">SFTTrainer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Spécification du modèle et du tokeniseur&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;TinyLlama/TinyLlama-1.1B-Chat-v1.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Paramètres de quantification 4-bit pour QLoRA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">bnb_config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BitsAndBytesConfig&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">load_in_4bit&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_use_double_quant&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_quant_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;nf4&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bnb_4bit_compute_dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">bfloat16&lt;/span> &lt;span class="c1"># Les calculs sont effectués en bfloat16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Chargement du modèle (Activation de Flash Attention 2)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Chargement du modèle...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoModelForCausalLM&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_id&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">quantization_config&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">bnb_config&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device_map&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;auto&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">use_flash_attention_2&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span> &lt;span class="c1"># La clé de l&amp;#39;accélération&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. Chargement du tokeniseur&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">trust_remote_code&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">pad_token&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">eos_token&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">padding_side&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;right&amp;#34;&lt;/span> &lt;span class="c1"># Défini sur right pour éviter un bug lors de l&amp;#39;entraînement fp16/bf16&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="62-application-de-ladaptateur-lora-et-formatage-des-données">6.2 Application de l&amp;rsquo;adaptateur LoRA et formatage des données
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 5. Préparation de l&amp;#39;apprentissage k-bit et activation du gradient checkpointing&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gradient_checkpointing_enable&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">prepare_model_for_kbit_training&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 6. Configuration de LoRA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">peft_config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">LoraConfig&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">r&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">16&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Rang&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lora_alpha&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">32&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Facteur d&amp;#39;échelle&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lora_dropout&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.05&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bias&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;none&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">task_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;CAUSAL_LM&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">target_modules&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;q_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;k_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;v_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;o_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;gate_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;up_proj&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;down_proj&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1"># Cibler toutes les couches Linear améliore les performances&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">get_peft_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">peft_config&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">print_trainable_parameters&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exemple de sortie : trainable params: 14,286,848 || all params: 1,114,335,232 || trainable%: 1.282%&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 7. Chargement de l&amp;#39;ensemble de données (ici, un ensemble de données d&amp;#39;instructions en japonais est utilisé comme exemple)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># En réalité, vous chargerez un fichier JSONL privé sur site, etc.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">load_dataset&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;kunishou/databricks-dolly-15k-ja&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">split&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;train&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">format_instruction&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> Formate la chaîne pour correspondre au format ChatML ou au modèle de prompt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;|im_start|&amp;gt;user&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;instruction&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">sample&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;input&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;input&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;|im_end|&amp;gt;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;lt;|im_start|&amp;gt;assistant&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">sample&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;output&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;lt;|im_end|&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">dataset&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">dataset&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">format_instruction&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="63-exécution-de-lentraînement">6.3 Exécution de l&amp;rsquo;entraînement
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 8. Configuration des arguments d&amp;#39;entraînement&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">training_args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TrainingArguments&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output_dir&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-output&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">per_device_train_batch_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">8&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Augmenter s&amp;#39;il y a assez de VRAM&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">gradient_accumulation_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Taille de lot effective = 8 * 2 = 16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">optim&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;paged_adamw_32bit&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Économie de VRAM avec Paged Optimizer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">save_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logging_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">learning_rate&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">2e-4&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fp16&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">bf16&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Apprentissage en précision mixte (bfloat16)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_grad_norm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.3&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_steps&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># 500 étapes pour les tests. En production, spécifier par nombre d&amp;#39;époques&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">warmup_ratio&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mf">0.03&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">group_by_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">lr_scheduler_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;cosine&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 9. Démarrage de l&amp;#39;apprentissage avec SFTTrainer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SFTTrainer&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">train_dataset&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">dataset&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">peft_config&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">peft_config&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">dataset_text_field&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_seq_length&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Ajuster selon la longueur d&amp;#39;entrée prévue&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokenizer&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">tokenizer&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">args&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">training_args&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Démarrage de l&amp;#39;entraînement...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">train&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 10. Sauvegarde de l&amp;#39;adaptateur LoRA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">trainer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Entraînement terminé et modèle sauvegardé.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="7-évaluation-des-performances-et-dépannage">7. Évaluation des performances et dépannage
&lt;/h2>&lt;p>Voici les problèmes courants rencontrés lors de l&amp;rsquo;exécution de l&amp;rsquo;apprentissage dans un environnement sur site et leurs solutions.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>OOM (Out Of Memory) se produit :&lt;/strong>
&lt;ul>
&lt;li>Réduisez &lt;code>per_device_train_batch_size&lt;/code> à &lt;code>1&lt;/code>.&lt;/li>
&lt;li>Augmentez &lt;code>gradient_accumulation_steps&lt;/code> pour maintenir la taille de lot effective.&lt;/li>
&lt;li>Raccourcissez &lt;code>max_seq_length&lt;/code> de &lt;code>2048&lt;/code> à &lt;code>1024&lt;/code> ou &lt;code>512&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>La perte (Loss) ne diminue pas / diverge :&lt;/strong>
&lt;ul>
&lt;li>Le taux d&amp;rsquo;apprentissage (&lt;code>learning_rate&lt;/code>) peut être trop élevé. Essayez de le réduire de &lt;code>2e-4&lt;/code> à environ &lt;code>5e-5&lt;/code>.&lt;/li>
&lt;li>Si vous utilisez Float16 au lieu de Bfloat16, un sous-dépassement de gradient peut se produire. Vérifiez &lt;code>bf16=True&lt;/code>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Des chaînes de caractères mystérieuses sont générées lors de l&amp;rsquo;inférence :&lt;/strong>
&lt;ul>
&lt;li>Assurez-vous que &lt;code>padding_side=&amp;quot;right&amp;quot;&lt;/code> est correctement défini. Il est également nécessaire de vérifier si le format du jeu de données (les tokens spéciaux comme &lt;code>&amp;lt;|im_start|&amp;gt;&lt;/code>) est cohérent avec celui de la phase de pré-entraînement du modèle de base.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-déploiement-du-modèle-après-le-fine-tuning">8. Déploiement du modèle après le fine-tuning
&lt;/h2>&lt;p>Une fois le fine-tuning terminé, ce qui est sauvegardé n&amp;rsquo;est pas &amp;ldquo;l&amp;rsquo;ensemble du modèle de base&amp;rdquo;, mais seulement &amp;ldquo;l&amp;rsquo;&lt;strong>adaptateur LoRA (poids différentiels)&lt;/strong>&amp;rdquo; de quelques mégaoctets à quelques dizaines de mégaoctets. Pour effectuer une inférence à grande vitesse, ce poids LoRA doit être fusionné (intégré) dans le modèle de base d&amp;rsquo;origine et exporté en tant que modèle unique.&lt;/p>
&lt;h3 id="script-de-fusion-de-modèle">Script de fusion de modèle
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">torch&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">peft&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AutoPeftModelForCausalLM&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">transformers&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">output_dir&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./tinyllama-lora-final&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Charger le modèle et l&amp;#39;adaptateur en FP16/BF16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoPeftModelForCausalLM&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output_dir&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">device_map&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;auto&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">torch_dtype&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">torch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">bfloat16&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AutoTokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">output_dir&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Fusionner les poids et sauvegarder&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">merged_model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">merge_and_unload&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">merged_model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-merged&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">safe_serialization&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tokenizer&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">save_pretrained&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;./tinyllama-merged&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Modèle fusionné et sauvegardé avec succès !&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="lancement-dun-serveur-dinférence-ultra-rapide-avec-vllm">Lancement d&amp;rsquo;un serveur d&amp;rsquo;inférence ultra-rapide avec vLLM
&lt;/h3>&lt;p>Pour un déploiement dans un environnement sur site, afin de maximiser la vitesse d&amp;rsquo;inférence (Jetons par seconde), il est fortement recommandé d&amp;rsquo;utiliser &lt;strong>vLLM&lt;/strong> ou &lt;strong>TGI (Text Generation Inference)&lt;/strong> au lieu du &lt;code>pipeline&lt;/code> standard de Hugging Face. vLLM utilise la technologie PagedAttention pour éviter la fragmentation de la mémoire GPU, améliorant considérablement la capacité de traitement des requêtes simultanées.&lt;/p>
&lt;p>Le diagramme Mermaid ci-dessous montre le pipeline allant de l&amp;rsquo;apprentissage au déploiement du serveur d&amp;rsquo;inférence.&lt;/p>
&lt;div class="mermaid">graph TD
A["Données privées brutes"] --> B["Prétraitement et formatage (JSONL)"]
B --> C["Fine-Tuning QLoRA (SFTTrainer)"]
C --> D["Poids de l'adaptateur LoRA (.safetensors)"]
D --> E["Fusion avec le TinyLLaMA 1.1B de base"]
E --> F["Modèle fusionné"]
F --> G["Déploiement via le serveur vLLM"]
G --> H["Point de terminaison API / UI (par ex. Chatbot)"]&lt;/div>
&lt;p>Le démarrage du serveur d&amp;rsquo;API avec vLLM s&amp;rsquo;effectue avec la commande suivante.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">python -m vllm.entrypoints.openai.api_server &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --model ./tinyllama-merged &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --host 0.0.0.0 &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --port &lt;span class="m">8000&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --max-model-len &lt;span class="m">2048&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --dtype bfloat16
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Avec cela, un point de terminaison compatible avec l&amp;rsquo;API OpenAI est construit dans l&amp;rsquo;environnement sur site, vous permettant d&amp;rsquo;utiliser l&amp;rsquo;IA locale de manière sécurisée et à haute vitesse.&lt;/p>
&lt;hr>
&lt;h2 id="9-conclusion">9. Conclusion
&lt;/h2>&lt;p>Dans cet article, nous avons expliqué la méthode de fine-tuning de &amp;ldquo;TinyLLaMA&amp;rdquo;, qui offre des performances élevées malgré son poids léger de 1,1B de paramètres, de manière très rapide et économe en mémoire dans un environnement sur site.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>LoRA / QLoRA&lt;/strong> permet un véritable fine-tuning de LLM même sur des GPU grand public.&lt;/li>
&lt;li>En exploitant &lt;strong>Flash Attention 2&lt;/strong> et &lt;strong>Gradient Checkpointing&lt;/strong>, le temps d&amp;rsquo;apprentissage et la consommation de VRAM sont optimisés à l&amp;rsquo;extrême.&lt;/li>
&lt;li>Le déploiement utilisant &lt;strong>vLLM&lt;/strong> permet d&amp;rsquo;atteindre un débit élevé même dans des environnements de production.&lt;/li>
&lt;/ul>
&lt;p>L&amp;rsquo;exploitation locale de LLM sur site protège non seulement la confidentialité des données, mais constitue également l&amp;rsquo;arme ultime pour construire à faible coût une IA spécialisée pour un domaine spécifique (juridique, médical, réglementations internes, etc.). N&amp;rsquo;hésitez pas à utiliser ce guide comme référence pour développer votre propre TinyLLaMA.&lt;/p></description></item><item><title>Procédure de développement de petits modèles d'IA (TinyLLaMA, etc.) avec C++</title><link>http://kenji.blog/fr/p/cpp-small-ai-model-tinyllama-dev-guide/</link><pubDate>Fri, 11 Sep 2026 14:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/cpp-small-ai-model-tinyllama-dev-guide/</guid><description>&lt;img src="http://kenji.blog/p/cpp-small-ai-model-tinyllama-dev-guide/img/eyecatch.jpg" alt="Featured image of post Procédure de développement de petits modèles d'IA (TinyLLaMA, etc.) avec C++" />&lt;h1 id="procédure-de-développement-de-petits-modèles-dia-tinyllama-etc-avec-c">Procédure de développement de petits modèles d&amp;rsquo;IA (TinyLLaMA, etc.) avec C++
&lt;/h1>&lt;p>Ces dernières années, l&amp;rsquo;intérêt pour l&amp;rsquo;exécution locale de grands modèles de langage (LLM) a augmenté rapidement. En particulier, les petits modèles tels que TinyLLaMA (1,1B paramètres) peuvent effectuer des inférences à une vitesse pratique même sur des appareils périphériques aux ressources limitées ou des PC portables standards (y compris les environnements Windows). Bien que le développement utilisant Python et PyTorch soit courant, lorsqu&amp;rsquo;il s&amp;rsquo;agit d&amp;rsquo;atteindre des performances et une efficacité mémoire ultimes, la combinaison du C++ et de « ggml », une bibliothèque de tenseurs basée sur le langage C, est devenue la norme de facto.&lt;/p>
&lt;p>Cet article explique en détail la procédure de développement pour construire un moteur d&amp;rsquo;inférence à partir de zéro (ou comprendre en profondeur l&amp;rsquo;architecture interne du llama.cpp existant) afin de charger TinyLLaMA et de générer du texte en utilisant C++.&lt;/p>
&lt;hr>
&lt;h2 id="1-pourquoi-c-et-ggml-">1. Pourquoi C++ et ggml ?
&lt;/h2>&lt;p>Dans la phase d&amp;rsquo;apprentissage de l&amp;rsquo;IA, Python, avec sa flexibilité et son écosystème riche, a un avantage écrasant. Cependant, dans les phases de déploiement ou d&amp;rsquo;« inférence (Inference) », C++ devient un choix puissant pour les raisons suivantes.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Réduction des surcoûts&lt;/strong> : Le Global Interpreter Lock (GIL) de Python et les surcoûts d&amp;rsquo;exécution peuvent être complètement éliminés.&lt;/li>
&lt;li>&lt;strong>Efficacité de la mémoire et allocation d&amp;rsquo;arène&lt;/strong> : L&amp;rsquo;allocation et la libération de la mémoire pouvant être contrôlées manuellement, les pics imprévisibles causés par le ramasse-miettes (garbage collection) sont évités.&lt;/li>
&lt;li>&lt;strong>Accès direct au matériel&lt;/strong> : Il est possible d&amp;rsquo;appeler directement des fonctions intrinsèques SIMD (Intrinsics) telles que AVX-512, AVX2 et ARM NEON, exploitant ainsi la puissance de calcul du processeur à son maximum.&lt;/li>
&lt;li>&lt;strong>Élimination des dépendances&lt;/strong> : ggml est une bibliothèque C/C++ sans aucune dépendance (Zero dependencies), et peut être facilement compilée même dans un environnement MSVC sous Windows tant qu&amp;rsquo;il y a un compilateur.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="2-vue-densemble-de-larchitecture">2. Vue d&amp;rsquo;ensemble de l&amp;rsquo;architecture
&lt;/h2>&lt;p>Le diagramme Mermaid ci-dessous montre le flux complet du pipeline d&amp;rsquo;inférence. Il s&amp;rsquo;agit d&amp;rsquo;une série de processus commençant par le texte d&amp;rsquo;entrée de l&amp;rsquo;utilisateur et se terminant par la génération du jeton suivant.&lt;/p>
&lt;div class="mermaid">graph TD
A["Texte d'entrée utilisateur"] --> B["Tokeniseur BPE"]
B --> C["Tableau d'ID de jetons"]
C --> D["Recherche de couche d'intégration"]
D --> E["Blocs Transformer"]
E --> F["RMSNorm"]
F --> G["Couche LM Head"]
G --> H["Tableau des logits"]
H --> I["Module échantillonneur"]
I --> J["ID du jeton suivant"]
J --> K["Détokeniseur"]
K --> L["Morceau de texte de sortie"]
J -.-> |"Ajouter au contexte"| C&lt;/div>
&lt;p>Puisqu&amp;rsquo;il s&amp;rsquo;agit d&amp;rsquo;un modèle autorégressif, le jeton produit est à nouveau ajouté au contexte et circule en tant qu&amp;rsquo;entrée pour la prédiction du jeton suivant (la partie en pointillé du diagramme).&lt;/p>
&lt;hr>
&lt;h2 id="3-format-de-modèle-et-mappage-en-mémoire-mmap">3. Format de modèle et mappage en mémoire (mmap)
&lt;/h2>&lt;p>Le principal obstacle à la gestion des poids des grands réseaux de neurones est l&amp;rsquo;I/O disque et la consommation de mémoire. Dans l&amp;rsquo;implémentation C++ , cela est résolu par le &lt;strong>mappage en mémoire (mmap)&lt;/strong>.&lt;/p>
&lt;h3 id="31-mécanisme-du-mappage-en-mémoire-et-implémentation-sous-windows">3.1 Mécanisme du mappage en mémoire et implémentation sous Windows
&lt;/h3>&lt;p>L&amp;rsquo;utilisation de mmap permet de mapper le contenu d&amp;rsquo;un fichier directement dans l&amp;rsquo;espace mémoire virtuel du processus.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Zéro copie (Zero-copy)&lt;/strong> : Les données sont lues directement depuis le disque vers le cache de pages du noyau, évitant ainsi des copies supplémentaires vers l&amp;rsquo;espace utilisateur.&lt;/li>
&lt;li>&lt;strong>Chargement à la demande (Page Fault)&lt;/strong> : Au moment précis où le processeur accède à cette adresse mémoire, un défaut de page (page fault) se produit, et seul le morceau (chunk) requis (généralement 4 Ko) est chargé dans la mémoire physique.&lt;/li>
&lt;/ul>
&lt;p>Dans l&amp;rsquo;environnement Windows, au lieu du &lt;code>mmap&lt;/code> de POSIX, on utilise les API Win32 &lt;code>CreateFileMapping&lt;/code> et &lt;code>MapViewOfFile&lt;/code>.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant OS["Système d'exploitation Windows"]
participant RAM["Mémoire physique"]
participant App["Application C++"]
App->>OS: "CreateFileMapping / MapViewOfFile"
OS-->>App: "Pointeur d'adresse de mémoire virtuelle"
App->>App: "Lire les données du tenseur au pointeur"
OS->>RAM: "Défaut de page / Charger la page depuis le disque"
RAM-->>App: "Données prêtes pour le calcul SIMD"&lt;/div>
&lt;h3 id="32-structure-binaire-du-format-gguf">3.2 Structure binaire du format GGUF
&lt;/h3>&lt;p>Converti à partir de formats tels que &lt;code>.safetensors&lt;/code> de Hugging Face, le &lt;strong>GGUF (GPT-Generated Unified Format)&lt;/strong> est le format ultime pour l&amp;rsquo;inférence. Il possède la disposition binaire stricte suivante.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Octets magiques (Magic Bytes)&lt;/strong> : &lt;code>0x46554747&lt;/code> (GGUF).&lt;/li>
&lt;li>&lt;strong>Version&lt;/strong> : Numéro de version du format.&lt;/li>
&lt;li>&lt;strong>Nombre de tenseurs et de métadonnées&lt;/strong> : Nombre de tenseurs et de paires clé-valeur de métadonnées.&lt;/li>
&lt;li>&lt;strong>Métadonnées (Paires Clé-Valeur)&lt;/strong> : Clés avec préfixe de longueur de chaîne, et valeurs typées.&lt;/li>
&lt;li>&lt;strong>Infos sur le tenseur&lt;/strong> : Nom de chaque tenseur, nombre de dimensions, type de données (FP16, Q4_K, etc.), et position de décalage (offset) dans le fichier.&lt;/li>
&lt;li>&lt;strong>Remplissage (Padding)&lt;/strong> : Remplissage inséré de sorte que les données du tenseur soient alignées sur une limite spécifique (généralement 32 octets ou 64 octets). Indispensable pour un accès rapide à la mémoire avec les instructions SIMD (en particulier AVX).&lt;/li>
&lt;li>&lt;strong>Données du tenseur&lt;/strong> : Tableau des données de poids réelles alignées.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="4-fondements-mathématiques-de-tinyllama-et-algorithmes-c">4. Fondements mathématiques de TinyLLaMA et algorithmes C++
&lt;/h2>&lt;p>TinyLLaMA intègre plusieurs améliorations architecturales avancées pour l&amp;rsquo;efficacité. Nous expliquons ici les expressions mathématiques pour les implémenter correctement en C++.&lt;/p>
&lt;h3 id="41-rmsnorm-root-mean-square-normalization">4.1 RMSNorm (Root Mean Square Normalization)
&lt;/h3>&lt;p>Il omet le centrage de la moyenne du LayerNorm et n&amp;rsquo;effectue que la mise à l&amp;rsquo;échelle de la variance, ce qui réduit les coûts de calcul.&lt;/p>
$$ \text{RMSNorm}(x) = \frac{x}{\sqrt{\frac{1}{d}\sum_{i=1}^{d} x_i^2 + \epsilon}} \odot \gamma $$
&lt;p>$d$ est le nombre de dimensions, $\gamma$ est le tenseur de mise à l&amp;rsquo;échelle appris.
Lors de l&amp;rsquo;implémentation en C++, on optimise d&amp;rsquo;abord en calculant rapidement la somme des carrés du tableau avec &lt;code>_mm256_fmadd_ps&lt;/code> d&amp;rsquo;AVX2, etc., et en la multipliant par la racine carrée inverse (par ex., avec l&amp;rsquo;instruction &lt;code>_mm256_rsqrt_ps&lt;/code>).&lt;/p>
&lt;h3 id="42-rope-rotary-position-embedding">4.2 RoPE (Rotary Position Embedding)
&lt;/h3>&lt;p>C&amp;rsquo;est une technique qui applique l&amp;rsquo;information de position du jeton sous forme de rotation (Rotate) dans l&amp;rsquo;espace tensoriel. Elle peut être considérée comme une rotation sur un plan complexe, appliquant la rotation suivante à la paire de dimensions adjacentes $(x_1, x_2)$ du vecteur $x$.&lt;/p>
$$ \text{RoPE}(x, m) = \begin{pmatrix} x_{1} \cos(m\theta) - x_{2} \sin(m\theta) \\ x_{1} \sin(m\theta) + x_{2} \cos(m\theta) \end{pmatrix} $$
&lt;p>Ici, $m$ est l&amp;rsquo;index de position absolu du jeton, $\theta$ est la fréquence fondamentale précalculée. Dans ggml, elle s&amp;rsquo;exécute en parallèle simplement en ajoutant l&amp;rsquo;opérateur &lt;code>ggml_rope&lt;/code> pendant la construction du graphe d&amp;rsquo;inférence.&lt;/p>
&lt;h3 id="43-grouped-query-attention-gqa">4.3 Grouped-Query Attention (GQA)
&lt;/h3>&lt;p>Dans le Multi-Head Attention (MHA) standard, on a le même nombre de têtes (heads) pour Query, Key et Value. Cependant, TinyLLaMA utilise le &lt;strong>Grouped-Query Attention (GQA)&lt;/strong> pour réduire drastiquement la bande passante mémoire et la consommation du cache KV.&lt;/p>
$$ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{Q K^T}{\sqrt{d_k}}\right) V $$
&lt;p>Dans le GQA, plusieurs têtes Query partagent une seule tête Key/Value. L&amp;rsquo;implémentation C++ nécessite une opération de diffusion (broadcast) du tenseur KV pour correspondre au nombre de Query avant d&amp;rsquo;exécuter la multiplication matricielle &lt;code>ggml_mul_mat&lt;/code>.&lt;/p>
&lt;h3 id="44-fonction-dactivation-swiglu">4.4 Fonction d&amp;rsquo;activation SwiGLU
&lt;/h3>&lt;p>Dans la couche de réseau à propagation avant (Feed-Forward Network, FFN), SwiGLU est utilisé à la place de GELU.&lt;/p>
$$ \text{SwiGLU}(x) = \text{Swish}(x W_{\text{gate}}) \otimes (x W_{\text{up}}) $$
$$ \text{Swish}(z) = z \cdot \sigma(z) = z \cdot \frac{1}{1 + e^{-z}} $$
&lt;p>Dans le graphe de calcul, ceci est exprimé en combinant les opérateurs &lt;code>ggml_silu&lt;/code> et &lt;code>ggml_mul&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="5-construction-du-graphe-de-calcul-avec-ggml-et-gestion-de-la-mémoire">5. Construction du graphe de calcul avec ggml et gestion de la mémoire
&lt;/h2>&lt;p>ggml adopte une approche « Define-and-Run », construisant un graphe de calcul statique pour l&amp;rsquo;inférence et l&amp;rsquo;évaluant (evaluate) par la suite.&lt;/p>
&lt;h3 id="51-ggml_context-et-allocateur-darène">5.1 ggml_context et allocateur d&amp;rsquo;arène
&lt;/h3>&lt;p>Le point le plus unique de ggml est l&amp;rsquo;« allocation d&amp;rsquo;arène » qui n&amp;rsquo;effectue aucune allocation de mémoire dynamique (&lt;code>malloc&lt;/code> ou &lt;code>new&lt;/code>) à l&amp;rsquo;intérieur de la boucle d&amp;rsquo;inférence.
Lors de l&amp;rsquo;initialisation, une énorme zone mémoire contiguë (arène) est allouée, et chaque fois que &lt;code>ggml_new_tensor&lt;/code> etc. est appelé, le pointeur de cette zone est incrémenté. Une fois qu&amp;rsquo;une étape d&amp;rsquo;inférence est terminée, il suffit de réinitialiser le pointeur d&amp;rsquo;allocation à sa position initiale pour terminer instantanément l&amp;rsquo;allocation de mémoire pour l&amp;rsquo;étape d&amp;rsquo;inférence suivante.&lt;/p>
&lt;h3 id="52-exemple-concret-de-construction-de-graphe">5.2 Exemple concret de construction de graphe
&lt;/h3>&lt;p>À chaque étape d&amp;rsquo;inférence, le graphe de calcul suivant est assemblé en mémoire.&lt;/p>
&lt;div class="mermaid">graph TD
A["ID d'entrée des jetons"] --> B["Recherche d'intégration"]
B --> C["ggml_rms_norm"]
C --> D["Projections Q / K / V"]
D --> E["ggml_rope Positionnel"]
E --> F["Stockage du cache KV"]
E --> G["Chargement du cache KV"]
G --> H["Auto-Attention"]
H --> I["Échelle &amp; Softmax"]
I --> J["Sortie de l'Attention"]
J --> K["Projection de Sortie"]
K --> L["Ajout Résiduel"]&lt;/div>
&lt;hr>
&lt;h2 id="6-quantification-quantization-et-optimisation-windows--simd">6. Quantification (Quantization) et optimisation Windows / SIMD
&lt;/h2>&lt;p>Traiter TinyLLaMA (1.1B) en FP16 nécessite environ 2,2 Go de mémoire, mais cela peut être considérablement réduit à environ 600 Mo grâce à la quantification 4 bits (comme Q4_K).&lt;/p>
&lt;h3 id="61-architecture-de-quantification-par-blocs">6.1 Architecture de quantification par blocs
&lt;/h3>&lt;p>ggml ne quantifie pas l&amp;rsquo;intégralité du tenseur uniformément, mais le fait par unités de « blocs ».
Dans le format &lt;code>Q4_0&lt;/code>, 32 valeurs FP16 sont regroupées en un seul bloc.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Facteur d&amp;rsquo;échelle (Scale factor)&lt;/strong> : 1 valeur FP16 (2 octets)&lt;/li>
&lt;li>&lt;strong>Données quantifiées&lt;/strong> : 32 valeurs 4 bits (16 octets)
Cela minimise l&amp;rsquo;impact des valeurs aberrantes locales.&lt;/li>
&lt;/ul>
&lt;h3 id="62-accélération-du-produit-scalaire-avec-avx2">6.2 Accélération du produit scalaire avec AVX2
&lt;/h3>&lt;p>Lors de la compilation pour les derniers processeurs x86 dans un environnement Windows, en utilisant des indicateurs de compilation (flags) tels que &lt;code>/arch:AVX2&lt;/code>, le traitement SIMD est effectué via le flux suivant.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Chargement (Load)&lt;/strong> : Charge les données quantifiées 4 bits depuis la mémoire dans un registre AVX de 256 bits.&lt;/li>
&lt;li>&lt;strong>Expansion et déballage (Unpack)&lt;/strong> : Développe les valeurs 4 bits en Int8 ou Int16 avec un masque de bits et des opérations de décalage.&lt;/li>
&lt;li>&lt;strong>Déqualification (Dequantize)&lt;/strong> : Multiplie par le facteur d&amp;rsquo;échelle pour convertir en virgule flottante.&lt;/li>
&lt;li>&lt;strong>Opération FMA&lt;/strong> : Exécute en parallèle les opérations de multiplication-addition avec les valeurs d&amp;rsquo;activation en utilisant &lt;code>_mm256_fmadd_ps&lt;/code> (Fused Multiply-Add).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="7-détails-dimplémentation-du-cache-kv">7. Détails d&amp;rsquo;implémentation du cache KV
&lt;/h2>&lt;p>Dans la génération autorégressive, le « cache KV » est une fonctionnalité indispensable pour omettre le calcul des Key et Value des jetons passés.&lt;/p>
&lt;p>Les points clés lors de l&amp;rsquo;implémentation en C++ sont les suivants.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Pré-allocation du tenseur&lt;/strong> : Initialiser un énorme tenseur pour le cache KV correspondant à la longueur de contexte maximale (ex. : 2048 jetons) (FP16 recommandé).&lt;/li>
&lt;li>&lt;strong>Copie avec décalage (Offset copy)&lt;/strong> : Lorsque le calcul pour la position du jeton $N$ est effectué, les vecteurs K et V obtenus à cette étape sont stockés à la $N$-ième ligne du tenseur de cache KV en utilisant &lt;code>ggml_cpy&lt;/code> etc.&lt;/li>
&lt;li>&lt;strong>Création de la vue (view) lors de l&amp;rsquo;Attention&lt;/strong> : Lors du calcul de l&amp;rsquo;Attention, créer une « vue » pointant uniquement sur la partie des jetons de 0 à $N$, et la transmettre à la multiplication matricielle.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-tokeniseur-bpe-et-décodage">8. Tokeniseur BPE et décodage
&lt;/h2>&lt;p>Traite la chaîne d&amp;rsquo;entrée sous forme d&amp;rsquo;une séquence d&amp;rsquo;octets UTF-8 et la compare à un vocabulaire prédéfini. En C++, pour accélérer la recherche dans le vocabulaire, on implémente un algorithme utilisant un &lt;strong>Trie (arbre de préfixes)&lt;/strong> ou une file de priorité.&lt;/p>
&lt;p>À partir des logits sortis du LM Head, les probabilités sont mises à l&amp;rsquo;échelle en utilisant le paramètre de température (Temperature), les candidats sont réduits par des méthodes d&amp;rsquo;extraction Top-K ou Top-P (Nucleus Sampling), et le jeton suivant final est déterminé à l&amp;rsquo;aide de nombres aléatoires.&lt;/p>
&lt;hr>
&lt;h2 id="9-lancement-dun-projet-c-environnement-windows--powershell">9. Lancement d&amp;rsquo;un projet C++ (Environnement Windows / PowerShell)
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cmake_minimum_required&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">VERSION&lt;/span> &lt;span class="s">3.14&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">project&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">TinyLLaMACpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD&lt;/span> &lt;span class="s">17&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Optimisation pour Windows (MSVC) et configuration du flag AVX2
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MSVC&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_compile_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">/O2&lt;/span> &lt;span class="s">/arch:AVX2&lt;/span> &lt;span class="s">/fp:fast&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_link_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">/STACK:8388608&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">else&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">add_compile_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">-O3&lt;/span> &lt;span class="s">-march=native&lt;/span> &lt;span class="s">-ffast-math&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">endif&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_library&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ggml&lt;/span> &lt;span class="s">OBJECT&lt;/span> &lt;span class="s">ggml/ggml.c&lt;/span> &lt;span class="s">ggml/ggml-alloc.c&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_compile_definitions&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ggml&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">GGML_USE_AVX2&lt;/span> &lt;span class="s">GGML_USE_F16C&lt;/span> &lt;span class="s">GGML_USE_FMA&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">main&lt;/span> &lt;span class="s">main.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">main&lt;/span> &lt;span class="s">ggml&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Exemple de commande de build dans PowerShell :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">mkdir&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd &lt;/span>&lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">..&lt;/span> &lt;span class="n">-G&lt;/span> &lt;span class="s2">&amp;#34;Visual Studio 17 2022&amp;#34;&lt;/span> &lt;span class="n">-A&lt;/span> &lt;span class="n">x64&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-build&lt;/span> &lt;span class="p">.&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-config&lt;/span> &lt;span class="n">Release&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="10-conclusion">10. Conclusion
&lt;/h2>&lt;p>Implémenter à partir de zéro un moteur d&amp;rsquo;inférence pour un petit modèle d&amp;rsquo;IA comme TinyLLaMA en utilisant C++ et ggml est une excellente occasion de révéler la boîte noire de l&amp;rsquo;apprentissage profond et d&amp;rsquo;apprendre la beauté du contrôle matériel de bas niveau. Tout en profitant pleinement de l&amp;rsquo;essence de la programmation système, telle que le chargement zéro copie à l&amp;rsquo;aide du mappage mémoire, l&amp;rsquo;optimisation SIMD et la construction du cache KV, ouvrons la voie à l&amp;rsquo;avenir de l&amp;rsquo;IA périphérique (Edge AI).&lt;/p></description></item><item><title>【Introduction à l'implémentation de RAG】 Comment faire lire vos propres documents à une 'IA locale'</title><link>http://kenji.blog/fr/p/rag-local-ai-implementation-guide/</link><pubDate>Fri, 11 Sep 2026 13:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/rag-local-ai-implementation-guide/</guid><description>&lt;img src="http://kenji.blog/p/rag-local-ai-implementation-guide/img/eyecatch.jpg" alt="Featured image of post 【Introduction à l'implémentation de RAG】 Comment faire lire vos propres documents à une 'IA locale'" />&lt;h1 id="introduction">Introduction
&lt;/h1>&lt;p>Ces dernières années, l&amp;rsquo;évolution des grands modèles de langage (LLM) a été remarquable, et de nombreuses IA telles que ChatGPT et Claude ont imprégné nos vies et nos entreprises. Cependant, les LLM généraux présentent une faiblesse évidente. Ils ne connaissent que les « informations publiques au moment de leur entraînement ». Naturellement, ils ne peuvent pas répondre aux questions concernant des « documents privés » tels que les règlements internes d&amp;rsquo;une entreprise, les notes personnelles ou les documents de projets non publiés. Si vous essayez de les forcer à répondre, le risque qu&amp;rsquo;ils génèrent des mensonges plausibles qui ne correspondent pas aux faits (hallucinations) augmente considérablement.&lt;/p>
&lt;p>C&amp;rsquo;est pourquoi l&amp;rsquo;architecture technologique appelée &lt;strong>RAG (Retrieval-Augmented Generation : Génération Augmentée par la Recherche)&lt;/strong> connaît actuellement une diffusion explosive dans le monde entier. L&amp;rsquo;utilisation du RAG permet de fournir dynamiquement des connaissances propres au LLM à partir d&amp;rsquo;une base de données externe, ce qui lui permet de générer des réponses précises et fondées.&lt;/p>
&lt;p>De plus, lors du traitement d&amp;rsquo;informations confidentielles d&amp;rsquo;entreprise ou personnelles, l&amp;rsquo;envoi de données à des API basées sur le cloud telles qu&amp;rsquo;OpenAI est souvent inacceptable du point de vue de la politique de sécurité. C&amp;rsquo;est là qu&amp;rsquo;intervient la construction d&amp;rsquo;un « RAG local » combiné à une &lt;strong>IA locale&lt;/strong> (un LLM qui fonctionne entièrement sur votre propre PC ou serveur sur site).&lt;/p>
&lt;p>Dans cet article, nous expliquerons en détail la théorie de base du RAG, les méthodes concrètes d&amp;rsquo;implémentation d&amp;rsquo;un RAG local avec Python, le contexte mathématique (le fonctionnement de la recherche vectorielle) et les techniques avancées pour faire fonctionner le système en production.&lt;/p>
&lt;hr>
&lt;h1 id="1-architecture-globale-du-rag">1. Architecture globale du RAG
&lt;/h1>&lt;p>Le RAG n&amp;rsquo;est pas un modèle d&amp;rsquo;IA unique, mais une architecture système dans laquelle plusieurs composants collaborent. Il se compose principalement de deux phases : la « phase d&amp;rsquo;ingestion (importation des données) » et la « phase de recherche et de génération (Retrieval &amp;amp; Generation) ».&lt;/p>
&lt;p>Le diagramme Mermaid ci-dessous montre la vue d&amp;rsquo;ensemble du système RAG.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Phase d'ingestion (Préparation)"
Doc["Documents propres (PDF, TXT, etc.)"] --> Loader["Chargeur de documents"]
Loader --> Splitter["Division du texte (Chunking)"]
Splitter --> EmbedModel1["Modèle de plongement (Embedding)"]
EmbedModel1 --> VectorDB["Base de données vectorielle"]
end
subgraph "Phase d'inférence (Lors de la requête de l'utilisateur)"
User["Question de l'utilisateur (Requête)"] --> EmbedModel2["Modèle de plongement (Embedding)"]
EmbedModel2 --> QueryVector["Vecteur de requête"]
QueryVector --> Search["Recherche de similarité (Recherche vectorielle)"]
VectorDB --> Search
Search --> Context["Extraction des morceaux pertinents (Contexte)"]
User --> PromptBuilder["Construction du prompt"]
Context --> PromptBuilder
PromptBuilder --> LocalLLM["LLM local"]
LocalLLM --> Answer["Génération de la réponse finale"]
end&lt;/div>
&lt;h2 id="phase-dingestion-préparation">Phase d&amp;rsquo;ingestion (Préparation)
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>Chargement des documents&lt;/strong> : Chargez des données non structurées telles que des PDF, des documents Word, des fichiers texte, etc.&lt;/li>
&lt;li>&lt;strong>Chunking (Division du texte)&lt;/strong> : Divisez les textes longs en blocs significatifs (chunks) pour les adapter à la limite d&amp;rsquo;entrée (fenêtre de contexte) du LLM et pour améliorer la précision de la recherche.&lt;/li>
&lt;li>&lt;strong>Embedding (Vectorisation)&lt;/strong> : Entrez les chunks divisés dans un modèle de plongement (Embedding Model) et convertissez-les en un tableau de nombres (vecteur) de plusieurs centaines à plusieurs milliers de dimensions.&lt;/li>
&lt;li>&lt;strong>Enregistrement dans la base de données&lt;/strong> : Enregistrez les vecteurs convertis et les données textuelles d&amp;rsquo;origine associées dans une base de données vectorielle (Vector DB).&lt;/li>
&lt;/ol>
&lt;h2 id="phase-dinférence-lors-de-lexécution">Phase d&amp;rsquo;inférence (Lors de l&amp;rsquo;exécution)
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>Vectorisation de la requête&lt;/strong> : Vectorisez la question de l&amp;rsquo;utilisateur en utilisant le même modèle de plongement que celui de la préparation.&lt;/li>
&lt;li>&lt;strong>Recherche de similarité&lt;/strong> : Calculez la similarité entre le vecteur de la requête et les vecteurs des documents dans la base de données, et récupérez les chunks de texte les plus proches sémantiquement (les plus pertinents).&lt;/li>
&lt;li>&lt;strong>Construction du prompt&lt;/strong> : Combinez les textes pertinents obtenus comme « contexte (connaissances de base) » avec la question de l&amp;rsquo;utilisateur pour créer le prompt d&amp;rsquo;entrée pour le LLM.&lt;/li>
&lt;li>&lt;strong>Génération de la réponse&lt;/strong> : Le LLM reçoit le prompt augmenté et génère une réponse basée sur les informations de contexte fournies.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-compréhension-approfondie-de-la-recherche-vectorielle-et-des-plongements-embeddings">2. Compréhension approfondie de la recherche vectorielle et des plongements (Embeddings)
&lt;/h1>&lt;p>Le cœur du RAG est la « recherche vectorielle (recherche sémantique) ». Alors que la recherche par mots-clés traditionnelle (comme BM25) est basée sur la correspondance exacte et la fréquence des mots, la recherche vectorielle est basée sur la « similarité de sens ». Par exemple, même des mots différents comme « chien » et « chiot », ou « PC » et « ordinateur » seront trouvés si leur sens est proche.&lt;/p>
&lt;h2 id="quest-ce-quun-modèle-de-plongement-embedding-model-">Qu&amp;rsquo;est-ce qu&amp;rsquo;un modèle de plongement (Embedding Model) ?
&lt;/h2>&lt;p>Un modèle de plongement est un réseau de neurones qui prend un texte en langage naturel en entrée et génère un vecteur dense de longueur fixe (Dense Vector). Les modèles courants (par exemple, &lt;code>text-embedding-3-small&lt;/code> ou l&amp;rsquo;open source &lt;code>multilingual-e5-large&lt;/code>) associent le texte à un vecteur de nombres réels de 384 ou 1024 dimensions.&lt;/p>
&lt;p>Dans cet espace multidimensionnel (espace latent), l&amp;rsquo;apprentissage est fait de manière à ce que les textes ayant des significations similaires soient plus proches en termes de distance dans l&amp;rsquo;espace des coordonnées.&lt;/p>
&lt;h2 id="contexte-mathématique-du-calcul-de-similarité--similarité-cosinus">Contexte mathématique du calcul de similarité : Similarité cosinus
&lt;/h2>&lt;p>Lorsque la base de données vectorielle recherche des documents pertinents, la mesure de distance la plus couramment utilisée est la &lt;strong>similarité cosinus (Cosine Similarity)&lt;/strong>. Contrairement à la distance euclidienne (distance spatiale absolue), la similarité cosinus se concentre sur « l&amp;rsquo;angle entre deux vecteurs ». Étant donné qu&amp;rsquo;elle est peu affectée par la longueur du texte (la norme du vecteur), elle est très adaptée au calcul de similarité de textes.&lt;/p>
&lt;p>Exprimée mathématiquement, la similarité cosinus des vecteurs $\mathbf{A}$ et $\mathbf{B}$ est la suivante :&lt;/p>
$$ \text{Cosine Similarity}(\mathbf{A}, \mathbf{B}) = \cos(\theta) = \frac{\mathbf{A} \cdot \mathbf{B}}{\|\mathbf{A}\| \|\mathbf{B}\|} = \frac{\sum_{i=1}^{n} A_i B_i}{\sqrt{\sum_{i=1}^{n} A_i^2} \sqrt{\sum_{i=1}^{n} B_i^2}} $$
&lt;ul>
&lt;li>$\mathbf{A} \cdot \mathbf{B}$ représente le produit scalaire (Dot Product).&lt;/li>
&lt;li>$\|\mathbf{A}\|$ représente la norme L2 (longueur) du vecteur $\mathbf{A}$.&lt;/li>
&lt;li>$n$ est le nombre de dimensions du vecteur.&lt;/li>
&lt;/ul>
&lt;p>La similarité cosinus prend une valeur comprise entre -1 et 1.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Proche de 1&lt;/strong> : Les directions des deux vecteurs sont presque les mêmes (les sens sont très similaires)&lt;/li>
&lt;li>&lt;strong>Proche de 0&lt;/strong> : Les deux vecteurs sont orthogonaux (aucun rapport)&lt;/li>
&lt;li>&lt;strong>Proche de -1&lt;/strong> : Les directions des deux vecteurs sont opposées (les sens sont opposés)&lt;/li>
&lt;/ul>
&lt;p>Les bases de données vectorielles récentes (Chroma, FAISS, Qdrant, etc.) adoptent un algorithme de recherche des plus proches voisins approximatifs (ANN) appelé HNSW (Hierarchical Navigable Small World), optimisé pour rechercher des documents ayant une similarité cosinus élevée en millisecondes, même à partir de millions de données vectorielles.&lt;/p>
&lt;hr>
&lt;h1 id="3-pile-technologique-pour-construire-un-rag-local">3. Pile technologique pour construire un RAG local
&lt;/h1>&lt;p>Pour construire un RAG local complet qui ne dépend pas du cloud, nous tirerons parti de l&amp;rsquo;écosystème open source. Voici la pile technologique recommandée.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Modèle de langage (LLM)&lt;/strong>
&lt;ul>
&lt;li>Outils : &lt;code>Ollama&lt;/code> ou &lt;code>Llama.cpp&lt;/code>&lt;/li>
&lt;li>Modèles : Des modèles ouverts légers et performants tels que &lt;code>Llama-3-8B-Instruct&lt;/code>, &lt;code>Gemma-2-9B-It&lt;/code>, &lt;code>Qwen2-7B-Instruct&lt;/code>. Pour les tâches en japonais, des modèles ajustés pour le japonais comme &lt;code>Llama-3-ELYZA-JP-8B&lt;/code> sont appropriés.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Modèle de plongement (Embedding)&lt;/strong>
&lt;ul>
&lt;li>Modèles : &lt;code>intfloat/multilingual-e5-large&lt;/code> ou &lt;code>BAAI/bge-m3&lt;/code>. Lors de l&amp;rsquo;exécution locale, il est courant de les télécharger depuis Hugging Face et de les exécuter avec Sentence-Transformers.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Base de données vectorielle (Vector DB)&lt;/strong>
&lt;ul>
&lt;li>&lt;code>ChromaDB&lt;/code> : Basée sur Python, son installation est extrêmement simple. Idéale pour le développement local.&lt;/li>
&lt;li>&lt;code>FAISS&lt;/code> : Une bibliothèque de recherche vectorielle rapide développée par Meta.&lt;/li>
&lt;li>&lt;code>Qdrant&lt;/code> / &lt;code>Milvus&lt;/code> : À plus grande échelle et destinées aux environnements de production.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Framework d&amp;rsquo;orchestration&lt;/strong>
&lt;ul>
&lt;li>&lt;code>LangChain&lt;/code> : Le standard de facto pour relier les composants (Chain).&lt;/li>
&lt;li>&lt;code>LlamaIndex&lt;/code> : Un framework de connexion de données spécialement conçu pour le RAG.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>Cette fois, nous l&amp;rsquo;implémenterons avec la combinaison la plus simple à introduire : &lt;strong>LangChain + ChromaDB + Ollama + HuggingFaceEmbeddings&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="4-tutoriel-dimplémentation--construction-complète-dun-rag-local-avec-python">4. Tutoriel d&amp;rsquo;implémentation : Construction complète d&amp;rsquo;un RAG local avec Python
&lt;/h1>&lt;p>À partir d&amp;rsquo;ici, nous allons construire un RAG local tout en écrivant du code Python. Au préalable, veuillez installer Ollama sur votre PC et le lancer en arrière-plan. De plus, téléchargez un modèle sur Ollama (exemple : &lt;code>ollama run llama3&lt;/code>).&lt;/p>
&lt;h2 id="étape-1--installation-des-bibliothèques-nécessaires">Étape 1 : Installation des bibliothèques nécessaires
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">pip install langchain langchain-community langchain-huggingface
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install chromadb sentence-transformers pypdf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="étape-2--vue-densemble-du-code-dimplémentation">Étape 2 : Vue d&amp;rsquo;ensemble du code d&amp;rsquo;implémentation
&lt;/h2>&lt;p>Voici un script Python complet pour lire un fichier PDF, le vectoriser et permettre à un LLM local de répondre aux questions.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;span class="lnt">87
&lt;/span>&lt;span class="lnt">88
&lt;/span>&lt;span class="lnt">89
&lt;/span>&lt;span class="lnt">90
&lt;/span>&lt;span class="lnt">91
&lt;/span>&lt;span class="lnt">92
&lt;/span>&lt;span class="lnt">93
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.document_loaders&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PyPDFLoader&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_text_splitters&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_huggingface&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.vectorstores&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Chroma&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_community.llms&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Ollama&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain_core.prompts&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">PromptTemplate&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">langchain.chains&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">RetrievalQA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 1. Chargement des documents&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Chargement des documents...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Spécifiez le chemin du PDF que vous souhaitez charger&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;sample_company_policy.pdf&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">loader&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PyPDFLoader&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">file_path&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">loader&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 2. Division en chunks (Text Splitting)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Diviser en tailles appropriées pour ne pas détruire le sens du texte&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">text_splitter&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RecursiveCharacterTextSplitter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_size&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">500&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Nombre maximum de caractères par chunk&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunk_overlap&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Nombre de caractères qui se chevauchent entre les chunks (empêche la rupture du contexte)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">separators&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;。&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;、&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34; &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chunks&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">text_splitter&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">split_documents&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">documents&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Divisé en &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> chunks.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 3. Initialisation du modèle de plongement (Local HuggingFace Model)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Utilisation d&amp;#39;un modèle multilingue performant&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Chargement du modèle de plongement...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embeddings&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">HuggingFaceEmbeddings&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;intfloat/multilingual-e5-large&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s1">&amp;#39;device&amp;#39;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s1">&amp;#39;cpu&amp;#39;&lt;/span>&lt;span class="p">}&lt;/span> &lt;span class="c1"># Si vous avez un GPU, &amp;#39;cuda&amp;#39; ou &amp;#39;mps&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 4. Construction de la base de données vectorielle (Chroma)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Construction de la base de données vectorielle...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">persist_directory&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;./chroma_db&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">vectorstore&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Chroma&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_documents&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">chunks&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">embedding&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">embeddings&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">persist_directory&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">persist_directory&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Création du système de recherche (Retriever). Configuration pour récupérer les 3 documents les plus pertinents&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retriever&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">vectorstore&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">as_retriever&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">search_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;k&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 5. Initialisation du LLM local (Ollama)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Connexion au LLM local...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Assurez-vous d&amp;#39;obtenir le modèle au préalable avec &amp;#39;ollama pull llama3&amp;#39; par exemple&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Ollama&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;llama3&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 6. Définition du modèle de prompt&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt_template&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Vous êtes un excellent assistant qui connaît bien les règlements de l&amp;#39;entreprise et les informations internes.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">Veuillez répondre en détail à la question de l&amp;#39;utilisateur en français, en utilisant uniquement le contexte (informations de base) ci-dessous.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">Si vous ne trouvez pas la réponse dans le contexte, ne devinez pas et répondez honnêtement « Je ne sais pas à partir des informations fournies ».
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【Contexte】
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{context}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【Question】
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&lt;/span>&lt;span class="si">{question}&lt;/span>&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">【Réponse】:
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PROMPT&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">PromptTemplate&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">template&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">prompt_template&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">input_variables&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;context&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;question&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 7. Construction de la chaîne RAG&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">qa_chain&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">RetrievalQA&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_chain_type&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llm&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">llm&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;stuff&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">retriever&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">retriever&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">return_source_documents&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1"># Définir s&amp;#39;il faut renvoyer la source d&amp;#39;information&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">chain_type_kwargs&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;prompt&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">PROMPT&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># 8. Exécution de la question&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">query&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Veuillez m&amp;#39;expliquer les conditions de remboursement des frais de transport pour le télétravail.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">Question : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">query&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">qa_chain&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">invoke&lt;/span>&lt;span class="p">({&lt;/span>&lt;span class="s2">&amp;#34;query&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">query&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;【Réponse】&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;result&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;【Sources consultées】&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">doc&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s1">&amp;#39;source_documents&amp;#39;&lt;/span>&lt;span class="p">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;- Page &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;page&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s1">&amp;#39;inconnue&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> : &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">doc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">page_content&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">50&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">main&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="explication-des-points-clés-du-code">Explication des points clés du code
&lt;/h2>&lt;ol>
&lt;li>&lt;strong>RecursiveCharacterTextSplitter&lt;/strong> :
C&amp;rsquo;est le diviseur le plus recommandé pour la division du langage naturel. Il tente de diviser dans l&amp;rsquo;ordre par paragraphe (&lt;code>\n\n&lt;/code>), ligne (&lt;code>\n&lt;/code>) et point (&lt;code>。&lt;/code>), en gardant les blocs de sens autant que possible tout en respectant la taille spécifiée &lt;code>chunk_size&lt;/code>. En définissant &lt;code>chunk_overlap&lt;/code>, on évite de perdre des informations aux limites du contexte.&lt;/li>
&lt;li>&lt;strong>HuggingFaceEmbeddings&lt;/strong> :
&lt;code>intfloat/multilingual-e5-large&lt;/code> est un modèle de plongement open source très puissant qui prend en charge plusieurs langues. Sans utiliser d&amp;rsquo;API cloud (telles que &lt;code>text-embedding-ada-002&lt;/code> d&amp;rsquo;OpenAI), vous pouvez vectoriser le texte hors ligne en mémoire locale.&lt;/li>
&lt;li>&lt;strong>ChromaDB&lt;/strong> :
Étant donné qu&amp;rsquo;il fonctionne en mémoire ou sur le stockage local (basé sur SQLite), il n&amp;rsquo;est pas nécessaire de mettre en place un serveur de base de données complexe. En spécifiant &lt;code>persist_directory&lt;/code>, vous pouvez ignorer le processus de vectorisation lors de la réexécution et charger la base de données à partir du disque.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="5-techniques-avancées-de-rag-advanced-rag-techniques">5. Techniques avancées de RAG (Advanced RAG Techniques)
&lt;/h1>&lt;p>Bien que le système RAG de base (Naive RAG) construit dans le tutoriel ci-dessus fonctionne, si une précision de réponse élevée est requise en production, l&amp;rsquo;introduction de techniques avancées telles que les suivantes sera nécessaire.&lt;/p>
&lt;h2 id="51-recherche-hybride-hybrid-search">5.1 Recherche hybride (Hybrid Search)
&lt;/h2>&lt;p>Bien que la recherche vectorielle excelle à saisir le « sens », elle peut avoir des difficultés avec les recherches de mots-clés exacts tels que des « noms propres spécifiques », des « numéros de modèles de produits » ou des « identifiants d&amp;rsquo;employés ».
Par conséquent, en effectuant parallèlement une &lt;strong>recherche sémantique&lt;/strong> basée sur la recherche vectorielle et une &lt;strong>recherche par mot-clé&lt;/strong> utilisant un algorithme tel que BM25, puis en évaluant et en fusionnant les deux résultats (en utilisant des méthodes telles que Reciprocal Rank Fusion ; RRF), il est possible de réduire considérablement les omissions de recherche.&lt;/p>
&lt;h2 id="52-re-classement-re-ranking">5.2 Re-classement (Re-ranking)
&lt;/h2>&lt;p>La recherche vectorielle est rapide, mais elle n&amp;rsquo;évalue pas nécessairement la pertinence contextuelle exacte du contexte. Un pipeline courant pour améliorer la précision de la recherche est le suivant :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Recherche initiale (First-stage Retrieval)&lt;/strong> : Récupérez largement et superficiellement environ 20 à 30 chunks pertinents à partir de la base de données vectorielle.&lt;/li>
&lt;li>&lt;strong>Réévaluation (Re-ranking)&lt;/strong> : Utilisez un autre modèle d&amp;rsquo;apprentissage automatique plus lourd appelé Cross-Encoder (par exemple : &lt;code>bge-reranker&lt;/code>, etc.) pour entrer la paire de la requête de l&amp;rsquo;utilisateur et du chunk récupéré, et recalculez le score de pertinence sémantique.&lt;/li>
&lt;li>&lt;strong>Sélection&lt;/strong> : Seuls les 3 à 5 premiers résultats ayant les scores les plus élevés sont passés au prompt du LLM en tant que contexte final.&lt;/li>
&lt;/ol>
&lt;p>Cette méthode empêche les informations bruyantes non pertinentes d&amp;rsquo;être transmises au LLM et peut considérablement augmenter la précision (Precision) des réponses.&lt;/p>
&lt;div class="mermaid">graph LR
Query["Requête"] --> VSearch["Recherche vectorielle (Top 20)"]
VSearch --> Reranker["Modèle de re-classement (Cross-Encoder)"]
Query --> Reranker
Reranker --> TopK["Top 3 de haute précision"]
TopK --> LLM["Génération par le LLM"]&lt;/div>
&lt;h2 id="53-chunking-sémantique-et-recherche-de-document-parent">5.3 Chunking sémantique et recherche de document parent
&lt;/h2>&lt;p>Plutôt que de diviser mécaniquement le texte par un nombre fixe de caractères, il existe une technique appelée « Semantic Chunking » qui utilise l&amp;rsquo;IA pour détecter les changements de sens dans les phrases et les diviser.
De plus, dans une technique appelée « Parent Document Retriever (Recherche de document parent) », la vectorisation est effectuée en très petites unités (comme des phrases) pour la recherche afin d&amp;rsquo;obtenir une recherche très précise. Mais lorsqu&amp;rsquo;elle est transmise au LLM, c&amp;rsquo;est le « grand paragraphe d&amp;rsquo;origine (document parent) » contenant cette phrase qui est fourni, offrant ainsi un contexte suffisant au LLM.&lt;/p>
&lt;hr>
&lt;h1 id="6-défis-et-solutions-lors-de-lexploitation-dun-rag-local">6. Défis et solutions lors de l&amp;rsquo;exploitation d&amp;rsquo;un RAG local
&lt;/h1>&lt;p>Lors de la construction et de l&amp;rsquo;exploitation d&amp;rsquo;un RAG dans un environnement local, des obstacles spécifiques existent.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Épuisement de la VRAM (Mémoire vidéo)&lt;/strong> :
Pour faire fonctionner un LLM local à une vitesse pratique (des dizaines de tokens par seconde), le modèle doit être chargé dans la VRAM du GPU. Pour exécuter un modèle de classe 8B en fp16 (virgule flottante 16 bits), environ 16 Go de VRAM sont nécessaires. Cependant, en utilisant des technologies de &lt;strong>quantification (Quantization)&lt;/strong> (techniques de compression en 4 bits ou 8 bits telles que les formats GGUF ou AWQ), il est possible de le faire fonctionner suffisamment vite même avec 8 Go de VRAM (PC de jeu standard, etc.). Llama.cpp et Ollama prennent en charge ces formats quantifiés de manière native.&lt;/li>
&lt;li>&lt;strong>Limite de la fenêtre de contexte&lt;/strong> :
Si la quantité de contexte récupérée par la recherche est trop importante, elle peut dépasser la limite d&amp;rsquo;entrée du LLM (limite de tokens), ou le modèle peut oublier les parties intermédiaires de l&amp;rsquo;information (phénomène de Lost in the middle). L&amp;rsquo;ajustement du nombre de chunks extraits et la sélection stricte à l&amp;rsquo;aide de la technologie de re-classement mentionnée ci-dessus sont essentiels.&lt;/li>
&lt;li>&lt;strong>Gestion de la fraîcheur des données&lt;/strong> :
Lorsque le document source est mis à jour, les vecteurs du document correspondant dans la base de données vectorielle doivent également être mis à jour/supprimés (opérations CRUD). Étant donné que ChromaDB prend en charge les mises à jour basées sur les identifiants de documents, il est pratique de mettre en place un traitement par lots qui gère les valeurs de hachage des fichiers et ne synchronise que les différences.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="conclusion">Conclusion
&lt;/h1>&lt;p>Le RAG (Génération Augmentée par la Recherche) est un paradigme puissant qui fait évoluer l&amp;rsquo;IA d&amp;rsquo;un assistant généraliste typique vers « votre expert exclusif » ou un « expert spécialisé dans les opérations internes ».&lt;/p>
&lt;p>Nous avons vu que même pour des exigences hautement confidentielles où les services cloud ne peuvent pas être utilisés, un environnement « RAG local » complet peut être construit relativement facilement en combinant l&amp;rsquo;écosystème open source comme Ollama, LangChain et ChromaDB.&lt;/p>
&lt;p>En vous basant sur la compréhension mathématique de l&amp;rsquo;espace vectoriel, la division de texte et les approches avancées telles que le re-classement expliquées dans cet article, n&amp;rsquo;hésitez pas à développer votre propre système d&amp;rsquo;IA original en utilisant vos propres données. La vitesse d&amp;rsquo;évolution de l&amp;rsquo;IA locale est stupéfiante, et le système que vous construisez aujourd&amp;rsquo;hui peut voir ses performances mises à jour instantanément, simplement en le remplaçant par un modèle léger encore plus intelligent qui sortira demain.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Dans ce blog, nous continuerons à publier des articles approfondis sur la technologie de l&amp;rsquo;IA et le RAG. Si vous avez des questions ou des commentaires, n&amp;rsquo;hésitez pas à nous en faire part dans la section des commentaires.&lt;/em>&lt;/p></description></item><item><title>Comparaison complète des API ChatGPT, Gemini et Claude ! Laquelle choisir ?</title><link>http://kenji.blog/fr/p/chatgpt-gemini-claude-api-comparison/</link><pubDate>Fri, 11 Sep 2026 12:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/chatgpt-gemini-claude-api-comparison/</guid><description>&lt;img src="http://kenji.blog/p/chatgpt-gemini-claude-api-comparison/img/eyecatch.jpg" alt="Featured image of post Comparaison complète des API ChatGPT, Gemini et Claude ! Laquelle choisir ?" />&lt;h1 id="comparaison-complète-des-api-chatgpt-gemini-et-claude--laquelle-choisir-">Comparaison complète des API ChatGPT, Gemini et Claude ! Laquelle choisir ?
&lt;/h1>&lt;p>L&amp;rsquo;évolution de la technologie de l&amp;rsquo;IA est remarquable, en particulier dans le domaine des grands modèles de langage (LLM : Large Language Model), où ChatGPT (série GPT) d&amp;rsquo;OpenAI, Gemini de Google et Claude d&amp;rsquo;Anthropic se livrent une lutte acharnée pour la suprématie à trois. En 2026, chaque entreprise publie de nouveaux modèles et fonctionnalités d&amp;rsquo;API en l&amp;rsquo;espace de quelques mois, voire de quelques semaines, et pour les développeurs ou les architectes informatiques des entreprises, la question de savoir &amp;ldquo;quelle API intégrer dans un produit&amp;rdquo; est devenue une décision cruciale qui peut déterminer le succès ou l&amp;rsquo;échec d&amp;rsquo;un projet.&lt;/p>
&lt;p>Dans cet article, nous comparerons et expliquerons en détail les API de ces 3 principaux fournisseurs d&amp;rsquo;IA du point de vue des développeurs, sans nous limiter à une simple liste de spécifications, mais en allant jusqu&amp;rsquo;à la conception de l&amp;rsquo;architecture, la structure tarifaire détaillée, l&amp;rsquo;analyse mathématique de la latence, des exemples d&amp;rsquo;implémentation concrets avec Python et Node.js, et les dernières méthodes d&amp;rsquo;optimisation des coûts telles que le cache de prompts.&lt;/p>
&lt;p>Nous visons à ce que cela devienne un guide complet pour que nos lecteurs puissent sélectionner l&amp;rsquo;API LLM la plus adaptée à leur propre cas d&amp;rsquo;utilisation, et construire des applications d&amp;rsquo;IA évolutives et rentables.&lt;/p>
&lt;hr>
&lt;h2 id="1-philosophie-et-concepts-de-conception-de-chaque-api-llm">1. Philosophie et concepts de conception de chaque API LLM
&lt;/h2>&lt;p>Lors du choix technologique, il est d&amp;rsquo;abord très important de comprendre avec quelle philosophie chaque entreprise construit ses modèles et API.&lt;/p>
&lt;h3 id="11-openai-chatgpt">1.1 OpenAI (ChatGPT)
&lt;/h3>&lt;p>OpenAI s&amp;rsquo;est donné pour mission la &amp;ldquo;réalisation de l&amp;rsquo;intelligence artificielle générale (IAG)&amp;rdquo; et continue de tirer vers le haut les standards de facto de l&amp;rsquo;industrie. Ils fournissent une variété de modèles adaptés à chaque cas d&amp;rsquo;utilisation, tels que GPT-4o, GPT-4o-mini, et le modèle o1 spécialisé dans le raisonnement. Leur écosystème est le plus mature, et ils possèdent l&amp;rsquo;abondance de bibliothèques et de documentation la plus importante, qu&amp;rsquo;elle soit officielle ou non.&lt;/p>
&lt;h3 id="12-google-gemini">1.2 Google (Gemini)
&lt;/h3>&lt;p>Google met en avant la politique &amp;ldquo;AI First&amp;rdquo; et fait de sa scalabilité, qui exploite au maximum sa propre infrastructure (réseau TPU), son arme principale. Gemini 1.5 Pro/Flash possède une fenêtre de contexte impressionnante allant jusqu&amp;rsquo;à 2 millions de jetons (tokens), ce qui lui permet de traiter d&amp;rsquo;énormes documents, ainsi que des heures de vidéo et d&amp;rsquo;audio en une seule fois, ce qui constitue sa principale caractéristique. L&amp;rsquo;intégration forte avec Google Cloud (Vertex AI) est également très attrayante pour les entreprises.&lt;/p>
&lt;h3 id="13-anthropic-claude">1.3 Anthropic (Claude)
&lt;/h3>&lt;p>Anthropic est une entreprise fondée par d&amp;rsquo;anciens membres d&amp;rsquo;OpenAI, adoptant une approche unique de sécurité appelée &amp;ldquo;Constitutional AI&amp;rdquo; (IA Constitutionnelle). Claude 3.5 Sonnet et Opus recueillent un soutien enthousiaste de la part de nombreux développeurs grâce à leur grande capacité de raisonnement, leur compétence en génération de code, et surtout leurs &amp;ldquo;conversations naturelles, semblables à celles des humains&amp;rdquo; et leur &amp;ldquo;faible taux d&amp;rsquo;hallucinations&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="2-comparaison-détaillée-des-spécifications-des-familles-de-modèles">2. Comparaison détaillée des spécifications des familles de modèles
&lt;/h2>&lt;p>Nous comparons les spécifications des modèles phares actuels en 2026.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Fournisseur&lt;/th>
&lt;th>Modèle phare&lt;/th>
&lt;th>Longueur max du contexte&lt;/th>
&lt;th>Principaux atouts&lt;/th>
&lt;th>Cas d&amp;rsquo;utilisation recommandés&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>OpenAI&lt;/strong>&lt;/td>
&lt;td>GPT-4o&lt;/td>
&lt;td>128K&lt;/td>
&lt;td>Vitesse, reconnaissance visuelle, prise en charge audio&lt;/td>
&lt;td>Applications interactives, tâches d&amp;rsquo;ordre général&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>OpenAI&lt;/strong>&lt;/td>
&lt;td>o1-preview&lt;/td>
&lt;td>128K&lt;/td>
&lt;td>Raisonnement logique avancé, mathématiques, codage&lt;/td>
&lt;td>Génération d&amp;rsquo;algorithmes complexes, recherche&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Google&lt;/strong>&lt;/td>
&lt;td>Gemini 1.5 Pro&lt;/td>
&lt;td>2,000K&lt;/td>
&lt;td>Traitement de textes très longs, multimodal (vidéo, audio)&lt;/td>
&lt;td>Analyse de bases de code gigantesques, résumé de vidéos&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Google&lt;/strong>&lt;/td>
&lt;td>Gemini 1.5 Flash&lt;/td>
&lt;td>2,000K&lt;/td>
&lt;td>Faible latence, haut débit, coût extrêmement bas&lt;/td>
&lt;td>Traitement en temps réel, traitement par lots de données massives&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Anthropic&lt;/strong>&lt;/td>
&lt;td>Claude 3.5 Sonnet&lt;/td>
&lt;td>200K&lt;/td>
&lt;td>Capacité de codage, génération de textes naturels&lt;/td>
&lt;td>Assistance au développement logiciel, support client avancé&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Anthropic&lt;/strong>&lt;/td>
&lt;td>Claude 3.5 Haiku&lt;/td>
&lt;td>200K&lt;/td>
&lt;td>Réponse ultra-rapide, rapport coût-performance&lt;/td>
&lt;td>IA Edge (en périphérie), chatbots en temps réel&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="3-plongée-dans-larchitecture--les-coulisses-des-requêtes-api">3. Plongée dans l&amp;rsquo;architecture : les coulisses des requêtes API
&lt;/h2>&lt;p>Lorsque l&amp;rsquo;on appelle une API LLM, quel type de traitement a lieu en arrière-plan ? Pour optimiser les performances, il est nécessaire de comprendre cette architecture.&lt;/p>
&lt;p>Le diagramme Mermaid ci-dessous montre la vue d&amp;rsquo;ensemble, depuis l&amp;rsquo;envoi de la requête API par le client jusqu&amp;rsquo;au retour des jetons (tokens) en streaming.&lt;/p>
&lt;div class="mermaid">graph TD
A["Application Client"] -->|HTTP/REST or gRPC| B["Passerelle API"]
B --> C["Équilibreur de charge"]
C --> D["Cluster d'inférence"]
D --> E["Tokeniseur (BPE / SentencePiece)"]
E --> F["Cache KV &amp; Mécanisme d'attention"]
F --> G["Blocs Transformer (Passe avant)"]
G --> H["Couche de sortie (Logits)"]
H --> I["Échantillonneur (Temperature, Top-p, Top-k)"]
I --> J["Détokeniseur"]
J -->|Réponse en streaming (Morceau)| A&lt;/div>
&lt;h3 id="31-algorithmes-de-tokenisation">3.1 Algorithmes de Tokenisation
&lt;/h3>&lt;p>Le texte saisi dans l&amp;rsquo;API est divisé en interne en unités appelées &amp;ldquo;jetons&amp;rdquo; (tokens).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>OpenAI (tiktoken)&lt;/strong> : Adopte l&amp;rsquo;encodage Byte-Pair Encoding (BPE). Il offre une compression extrêmement efficace, en particulier en anglais, mais a tendance à gonfler le nombre de jetons pour les langues non alphabétiques comme le japonais.&lt;/li>
&lt;li>&lt;strong>Google (Gemini)&lt;/strong> : Adopte SentencePiece (Unigram Language Model). Il est performant en multilingue et tend à pouvoir représenter des textes, même en japonais, avec un nombre de jetons relativement faible.&lt;/li>
&lt;li>&lt;strong>Anthropic (Claude)&lt;/strong> : Utilise une version personnalisée de BPE. Le support multilingue a été renforcé, et depuis Claude 3, l&amp;rsquo;efficacité des jetons pour le japonais a également été considérablement améliorée.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="4-analyse-mathématique-de-la-latence-et-des-performances">4. Analyse mathématique de la latence et des performances
&lt;/h2>&lt;p>Dans les applications en temps réel, la latence affecte directement l&amp;rsquo;expérience utilisateur (UX). La latence d&amp;rsquo;une API LLM, $T_{total}$, peut être modélisée mathématiquement de la manière suivante.&lt;/p>
$$ T_{total} = T_{network} + T_{TTFT} + (N \times T_{TPOT}) $$
&lt;p>Ici, chaque variable a la signification suivante :&lt;/p>
&lt;ul>
&lt;li>$T_{network}$ : Temps d&amp;rsquo;aller-retour du réseau (RTT).&lt;/li>
&lt;li>$T_{TTFT}$ (Time To First Token) : Temps nécessaire pour générer le premier jeton. Dépend fortement du coût de calcul de l&amp;rsquo;attention, qui est proportionnel au carré de la longueur du prompt (nombre de jetons d&amp;rsquo;entrée).&lt;/li>
&lt;li>$N$ : Nombre total de jetons de sortie.&lt;/li>
&lt;li>$T_{TPOT}$ (Time Per Output Token) : Temps de génération par jeton. Étant un modèle autorégressif, il est calculé en série en fonction des sorties précédentes.&lt;/li>
&lt;/ul>
&lt;h3 id="41-complexité-du-mécanisme-dauto-attention">4.1 Complexité du mécanisme d&amp;rsquo;auto-attention
&lt;/h3>&lt;p>La complexité de calcul de l&amp;rsquo;auto-attention (Self-Attention) dans l&amp;rsquo;architecture Transformer augmente de manière quadratique par rapport à la longueur de la séquence d&amp;rsquo;entrée $L$.&lt;/p>
$$ \text{Complexity} = O(L^2 \cdot d) $$
&lt;p>Ici, $d$ est la dimension du vecteur de plongement (embedding). En raison de cette contrainte, $T_{TTFT}$ se dégrade généralement très rapidement lorsque le prompt s&amp;rsquo;allonge.
Cependant, Gemini 1.5 de Google adopte des architectures d&amp;rsquo;optimisation innovantes telles que &amp;ldquo;Ring Attention&amp;rdquo; et &amp;ldquo;Block-wise Compute&amp;rdquo;, réussissant à générer le premier jeton en un temps raisonnable (de quelques secondes à quelques dizaines de secondes) même avec une entrée massive de 2 millions de jetons.&lt;/p>
&lt;hr>
&lt;h2 id="5-structure-tarifaire-et-stratégies-doptimisation-des-coûts">5. Structure tarifaire et stratégies d&amp;rsquo;optimisation des coûts
&lt;/h2>&lt;p>Le coût de l&amp;rsquo;API est essentiellement calculé en fonction du nombre de jetons d&amp;rsquo;entrée et de sortie.&lt;/p>
$$ Cost = (Tokens_{in} \times Rate_{in}) + (Tokens_{out} \times Rate_{out}) $$
&lt;p>Toutefois, de nouveaux mécanismes ont été introduits dans les API récentes pour réduire considérablement les coûts.&lt;/p>
&lt;h3 id="51-cache-de-prompts-prompt-caching">5.1 Cache de prompts (Prompt Caching)
&lt;/h3>&lt;p>L&amp;rsquo;envoi de très longs prompts système ou d&amp;rsquo;une grande quantité de documents récupérés par RAG à chaque fois entraîne des coûts énormes. Pour y remédier, chaque entreprise propose une fonction de mise en cache.&lt;/p>
&lt;p>Avec Anthropic (Claude) et Google (Gemini), il est possible de réduire considérablement les coûts d&amp;rsquo;entrée (jusqu&amp;rsquo;à 90 %) en mettant en cache des blocs de texte spécifiques.&lt;/p>
&lt;p>Le modèle de coût lors de l&amp;rsquo;utilisation du cache est le suivant :&lt;/p>
$$ Cost_{cached} = (Tokens_{cache\_write} \times Rate_{cache\_write}) + (Tokens_{cache\_read} \times Rate_{cache\_read}) + (Tokens_{out} \times Rate_{out}) $$
&lt;p>Ici, $Rate_{cache\_read}$ est fixé à environ 10 % à 25 % du $Rate_{in}$ habituel. Cela permet d&amp;rsquo;exploiter un chatbot à moindre coût tout en maintenant en permanence une base de code de plusieurs dizaines de milliers de lignes en tant que connaissances contextuelles.&lt;/p>
&lt;h3 id="52-api-par-lots-batch-api">5.2 API par lots (Batch API)
&lt;/h3>&lt;p>Pour les tâches ne nécessitant pas de temps réel (analyse de journaux, classification de grandes quantités de données, etc.), OpenAI et Anthropic fournissent une API par lots (Batch API). C&amp;rsquo;est un mécanisme puissant qui permet d&amp;rsquo;envoyer des requêtes en groupe et de recevoir les résultats dans les 24 heures, à la moitié du prix normal de l&amp;rsquo;API (50 % de réduction).&lt;/p>
&lt;hr>
&lt;h2 id="6-comparaison-de-lexpérience-développeur-dx-et-des-sdk">6. Comparaison de l&amp;rsquo;expérience développeur (DX) et des SDK
&lt;/h2>&lt;p>Du point de vue de l&amp;rsquo;efficacité du développement, nous comparons les SDK (Software Development Kit) fournis par chaque entreprise.&lt;/p>
&lt;h3 id="61-api-openai">6.1 API OpenAI
&lt;/h3>&lt;p>C&amp;rsquo;est la plus largement utilisée et la prise en charge par les bibliothèques tierces (LangChain, LlamaIndex, etc.) est la plus rapide. De plus, la fonctionnalité de sorties structurées (Structured Outputs) garantit le retour de réponses respectant à 100 % le schéma JSON, ce qui facilite grandement l&amp;rsquo;intégration des systèmes.&lt;/p>
&lt;h3 id="62-api-anthropic-claude">6.2 API Anthropic (Claude)
&lt;/h3>&lt;p>L&amp;rsquo;interface de son SDK est raffinée et réputée très facile à utiliser, notamment au niveau des définitions de types TypeScript. La structure de l&amp;rsquo;API Message est particulièrement intuitive, permettant d&amp;rsquo;écrire simplement des requêtes multimodales incluant plusieurs images.&lt;/p>
&lt;h3 id="63-api-google-gemini">6.3 API Google Gemini
&lt;/h3>&lt;p>Il existe deux types d&amp;rsquo;accès : via Google Cloud Vertex AI et via AI Studio (Google Gen AI SDK), ce qui peut sembler un peu confus pour les débutants. Cependant, le SDK Vertex AI destiné aux entreprises est entièrement intégré au système de gestion des identités et des accès (IAM) de GCP, permettant de mettre en place un environnement de développement sécurisé.&lt;/p>
&lt;hr>
&lt;h2 id="7-pratique--implémentation-dun-test-dintégration-de-plusieurs-api-avec-python">7. Pratique ! Implémentation d&amp;rsquo;un test d&amp;rsquo;intégration de plusieurs API avec Python
&lt;/h2>&lt;p>Ici, nous allons utiliser Python pour implémenter un script qui envoie des requêtes asynchrones simultanées aux trois API (OpenAI, Anthropic, Gemini) et compare leurs latences.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">asyncio&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">openai&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AsyncOpenAI&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">anthropic&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">AsyncAnthropic&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">google.generativeai&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">genai&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Initialisation des clients&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">openai_client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AsyncOpenAI&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;OPENAI_API_KEY&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">anthropic_client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">AsyncAnthropic&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;ANTHROPIC_API_KEY&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">genai&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">configure&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">environ&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;GEMINI_API_KEY&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Veuillez expliquer de manière simple pour les débutants les bases de l&amp;#39;informatique quantique et son impact sur la cryptographie actuelle.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_openai&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">openai_client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">chat&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">completions&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;gpt-4o&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[{&lt;/span>&lt;span class="s2">&amp;#34;role&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;content&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_tokens&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;OpenAI (GPT-4o)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elapsed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">choices&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">content&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_anthropic&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">anthropic_client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">messages&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;claude-3-5-sonnet-20240620&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">messages&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">[{&lt;/span>&lt;span class="s2">&amp;#34;role&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;content&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">prompt&lt;/span>&lt;span class="p">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">max_tokens&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">1024&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;Anthropic (Claude 3.5 Sonnet)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elapsed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">content&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_gemini&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">start_time&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">genai&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">GenerativeModel&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;gemini-1.5-pro&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Utilisation de la méthode asynchrone du SDK Python Gemini&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">model&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">generate_content_async&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prompt&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">elapsed&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">time&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">time&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start_time&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s2">&amp;#34;Google (Gemini 1.5 Pro)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">elapsed&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">response&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">text&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">async&lt;/span> &lt;span class="k">def&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Envoi de requêtes à chaque API LLM...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Exécution des 3 API en parallèle&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">results&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">gather&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fetch_openai&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fetch_anthropic&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">fetch_gemini&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">for&lt;/span> &lt;span class="n">provider&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">latency&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">text&lt;/span> &lt;span class="ow">in&lt;/span> &lt;span class="n">results&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;--- &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">provider&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> ---&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Latency: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">latency&lt;/span>&lt;span class="si">:&lt;/span>&lt;span class="s2">.2f&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> seconds&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Response (Excerpt): &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">text&lt;/span>&lt;span class="p">[:&lt;/span>&lt;span class="mi">100&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">...&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">asyncio&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">main&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En exécutant ce script, vous pouvez facilement mesurer quel modèle répond le plus rapidement (en minimisant $T_{total}$) dans un environnement réseau réel.&lt;/p>
&lt;hr>
&lt;h2 id="8-implémentation-du-tool-calling-function-calling-avec-nodejs">8. Implémentation du Tool Calling (Function Calling) avec Node.js
&lt;/h2>&lt;p>Pour qu&amp;rsquo;un LLM fonctionne non pas comme un simple chatbot, mais comme un &amp;ldquo;agent IA&amp;rdquo; qui interagit avec des systèmes externes, le Tool Calling (ou Function Calling) est indispensable. Voici un exemple en Node.js (TypeScript) où l&amp;rsquo;API OpenAI est invitée à appeler une API météo.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-typescript" data-lang="typescript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">import&lt;/span> &lt;span class="nx">OpenAI&lt;/span> &lt;span class="kr">from&lt;/span> &lt;span class="s2">&amp;#34;openai&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">openai&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="nx">OpenAI&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">apiKey&lt;/span>: &lt;span class="kt">process.env.OPENAI_API_KEY&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">async&lt;/span> &lt;span class="kd">function&lt;/span> &lt;span class="nx">runAgent() {&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">tools&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">type&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;function&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">function&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">name&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;get_weather&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">description&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Obtient la météo actuelle pour la ville spécifiée.&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">parameters&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">type&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;object&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">properties&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">location&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">type&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">description&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Nom de la ville (ex: Tokyo, New York)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">required&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;location&amp;#34;&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">response&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="nx">openai&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">chat&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">completions&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">create&lt;/span>&lt;span class="p">({&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">model&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;gpt-4o&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">messages&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="p">[{&lt;/span> &lt;span class="nx">role&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;content&amp;#34;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;Quel temps fait-il à Tokyo aujourd&amp;#39;hui ? Aurai-je besoin d&amp;#39;un parapluie ?&amp;#34;&lt;/span> &lt;span class="p">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tools&lt;/span>: &lt;span class="kt">tools&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">tool_choice&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;auto&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">response&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">choices&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">].&lt;/span>&lt;span class="nx">message&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nx">message&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">tool_calls&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">toolCall&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">message&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">tool_calls&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sb">`Le LLM a demandé un appel d&amp;#39;outil : Nom de la fonction = &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">toolCall&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">name&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">const&lt;/span> &lt;span class="nx">args&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">JSON&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">parse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">toolCall&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="kd">function&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">arguments&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">log&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sb">`Arguments : &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nx">args&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">location&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="sb">`&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Implémentez ici la logique pour appeler l&amp;#39;API météo réelle (ex: OpenWeatherMap)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// const weather = await fetchWeatherFromAPI(args.location);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Vous pouvez passer le résultat obtenu au LLM pour générer la réponse finale
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">runAgent&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="k">catch&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">error&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Claude 3.5 Sonnet et Gemini 1.5 Pro disposent également de fonctionnalités de Tool Calling équivalentes. Bien qu&amp;rsquo;il y ait quelques différences dans la façon dont les schémas sont définis, le flux de base est commun.&lt;/p>
&lt;hr>
&lt;h2 id="9-rag-vs-fenêtre-de-contexte-étendue--que-faut-il-adopter-">9. RAG vs Fenêtre de contexte étendue : Que faut-il adopter ?
&lt;/h2>&lt;p>Actuellement, l&amp;rsquo;un des plus grands débats en matière d&amp;rsquo;architecture d&amp;rsquo;IA d&amp;rsquo;entreprise est de savoir s&amp;rsquo;il faut &amp;ldquo;utiliser RAG (génération augmentée par la recherche) pour intégrer des connaissances externes, ou tout confier à une fenêtre de contexte massive (Long Context)&amp;rdquo;.&lt;/p>
&lt;h3 id="avantages-et-défis-de-rag-retrieval-augmented-generation">Avantages et défis de RAG (Retrieval-Augmented Generation)
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Avantages&lt;/strong> : Faible coût (car seuls les morceaux nécessaires sont placés dans le prompt), facilité d&amp;rsquo;identification des preuves (sources) de la réponse.&lt;/li>
&lt;li>&lt;strong>Défis&lt;/strong> : Comme cela dépend de la précision de la recherche sémantique, cette méthode n&amp;rsquo;est pas adaptée aux tâches de raisonnement complexe où le contexte est dispersé dans plusieurs documents (par exemple : &amp;ldquo;Analysez chronologiquement la cause fondamentale du retard du projet A à partir des procès-verbaux de toutes les réunions de l&amp;rsquo;année dernière&amp;rdquo;).&lt;/li>
&lt;/ul>
&lt;h3 id="contexte-étendu-long-context-comme-les-2-millions-de-jetons-de-gemini-15-pro">Contexte étendu (Long Context, comme les 2 millions de jetons de Gemini 1.5 Pro)
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Avantages&lt;/strong> : Aucune perte d&amp;rsquo;information due à la recherche. Même dans le test de &amp;ldquo;chercher une aiguille dans une botte de foin&amp;rdquo; (Needle In A Haystack : NIAH), Gemini 1.5 Pro et Claude 3.5 Sonnet peuvent extraire des informations avec une précision de plus de 99 %.&lt;/li>
&lt;li>&lt;strong>Défis&lt;/strong> : La consommation de jetons devient massive et fait grimper les coûts, et la latence ($T_{TTFT}$) augmente.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Conclusion&lt;/strong> : La meilleure pratique en 2026 est l&amp;rsquo;&lt;strong>&amp;ldquo;approche hybride&amp;rdquo;&lt;/strong>. La conception dominante consiste à utiliser le RAG avec une base de données vectorielle pour les questions-réponses quotidiennes, et à utiliser un contexte étendu avec cache de prompts pour les tâches spécialisées nécessitant une analyse complexe ou la révision d&amp;rsquo;un code complet.&lt;/p>
&lt;hr>
&lt;h2 id="10-comparaison-des-capacités-de-traitement-multimodal">10. Comparaison des capacités de traitement multimodal
&lt;/h2>&lt;p>Dans les applications d&amp;rsquo;IA de nouvelle génération, il est nécessaire de comprendre directement non seulement le texte, mais aussi les images, le son et les vidéos.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant User as "Utilisateur"
participant Client as "Application Frontend"
participant API as "API LLM (Multimodal)"
User->>Client: Téléchargement Vidéo &amp; Prompt Texte
Client->>API: Envoi d'Octets Vidéo/URI + Texte
Note over API: Découpage vidéo &amp; séparation audio
Note over API: Modèle d'Embedding Multimodal
API-->>Client: Retour de Résumé Textuel &amp; Horodatages
Client-->>User: Affichage des Insights&lt;/div>
&lt;ul>
&lt;li>&lt;strong>OpenAI (GPT-4o)&lt;/strong> : La précision de la reconnaissance d&amp;rsquo;images est extrêmement élevée et elle excelle dans la lecture de dessins manuscrits ou de graphiques complexes. En outre, la conversation vocale native à très faible latence (quelques centaines de millisecondes) à l&amp;rsquo;aide de l&amp;rsquo;API Realtime est également très puissante.&lt;/li>
&lt;li>&lt;strong>Google (Gemini 1.5 Pro)&lt;/strong> : &lt;strong>Surpasse les autres en matière d&amp;rsquo;analyse vidéo.&lt;/strong> Vous pouvez insérer directement un fichier vidéo d&amp;rsquo;une heure (images + audio) et il est capable de répondre à des questions précises telles que &amp;ldquo;Quel est le titre du document tenu par la personne visible sur le bord droit de l&amp;rsquo;écran à 12 minutes 45 secondes ?&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>Anthropic (Claude 3.5 Sonnet)&lt;/strong> : Ses capacités de reconnaissance d&amp;rsquo;images (Vision) sont au même niveau que GPT-4o et très remarquables. Il fait preuve d&amp;rsquo;une force inégalée dans l&amp;rsquo;aide au développement frontend, par exemple en lui donnant une capture d&amp;rsquo;écran de l&amp;rsquo;interface utilisateur et en demandant : &amp;ldquo;Générez le code du composant React pour cet écran&amp;rdquo;.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="11-sécurité-et-conformité-de-niveau-entreprise">11. Sécurité et conformité de niveau entreprise
&lt;/h2>&lt;p>Lorsque les entreprises utilisent des API LLM dans un environnement de production, leurs principales préoccupations sont &amp;ldquo;nos données seront-elles utilisées pour former l&amp;rsquo;IA ?&amp;rdquo; et &amp;ldquo;répondent-elles aux exigences de conformité ?&amp;rdquo;.&lt;/p>
&lt;p>Les trois sociétés déclarent explicitement qu&amp;rsquo;elles &lt;strong>n&amp;rsquo;utilisent pas les données (prompts et réponses) envoyées via l&amp;rsquo;API pour former leurs modèles (Zero Data Retention / No Training on Customer Data)&lt;/strong> (*cela diffère pour les interfaces de discussion Web gratuites destinées aux consommateurs).&lt;/p>
&lt;p>Si un niveau de sécurité encore plus élevé est requis :&lt;/p>
&lt;ul>
&lt;li>&lt;strong>OpenAI&lt;/strong> : En passant par Azure OpenAI Service, vous pouvez bénéficier de la sécurité de niveau entreprise de Microsoft, de son SLA et d&amp;rsquo;une connexion réseau fermée via Azure Private Link.&lt;/li>
&lt;li>&lt;strong>Google&lt;/strong> : En passant par Google Cloud Vertex AI, il est possible d&amp;rsquo;avoir une isolation réseau stricte en utilisant VPC Service Controls et une protection des données via CMEK (clés de chiffrement gérées par le client).&lt;/li>
&lt;li>&lt;strong>Anthropic&lt;/strong> : En l&amp;rsquo;utilisant via AWS Bedrock ou Google Cloud Vertex AI, vous pouvez vous appuyer sur l&amp;rsquo;infrastructure de sécurité robuste de ces fournisseurs de cloud.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="12-conclusion--le-guide-de-sélection-ultime-par-cas-dutilisation">12. Conclusion : Le guide de sélection ultime par cas d&amp;rsquo;utilisation
&lt;/h2>&lt;p>Bien que nous ayons effectué une comparaison sous plusieurs angles jusqu&amp;rsquo;à présent, la conclusion finale à la question &amp;ldquo;laquelle choisir ?&amp;rdquo; dépend de votre cas d&amp;rsquo;utilisation.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Développement de logiciels complexes, génération de code et raisonnement avancé&lt;/strong> :
&lt;strong>👑 Gagnant : Claude 3.5 Sonnet (Anthropic)&lt;/strong>
Il offre actuellement les meilleures performances dans la compréhension du contexte du code, la refactorisation et la création de textes naturels et humains. La facilité d&amp;rsquo;utilisation de l&amp;rsquo;API et l&amp;rsquo;efficacité de ses coûts grâce au cache de prompts sont également exceptionnelles.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Analyse de documents ultra-longs et traitement par lots de vidéo/audio&lt;/strong> :
&lt;strong>👑 Gagnant : Gemini 1.5 Pro (Google)&lt;/strong>
La fenêtre de contexte de 2 millions de jetons est une arme unique. Il n&amp;rsquo;y a pas de meilleur choix que Gemini pour les tâches nécessitant une vue d&amp;rsquo;ensemble des données, telles que l&amp;rsquo;analyse d&amp;rsquo;un manuel PDF de plusieurs centaines de pages ou le résumé d&amp;rsquo;un long enregistrement de réunion.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Polyvalence, vitesse d&amp;rsquo;exécution et sorties structurées stables (JSON)&lt;/strong> :
&lt;strong>👑 Gagnant : GPT-4o / GPT-4o-mini (OpenAI)&lt;/strong>
Il accomplit toutes sortes de tâches sans difficulté et bénéficie de la prise en charge d&amp;rsquo;outils tiers la plus abondante. L&amp;rsquo;écosystème OpenAI est indispensable lorsque vous avez besoin d&amp;rsquo;un parsing JSON infaillible utilisant les sorties structurées (Structured Outputs) ou d&amp;rsquo;un raisonnement logique très avancé avec le modèle o1.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h3 id="recommandation-pour-le-routage-multi-modèles">Recommandation pour le routage multi-modèles
&lt;/h3>&lt;p>Plutôt que de s&amp;rsquo;appuyer sur une seule API (vendor lock-in), la tendance future est l&amp;rsquo;architecture de &lt;strong>&amp;ldquo;routage LLM&amp;rdquo;&lt;/strong> qui bascule dynamiquement d&amp;rsquo;un modèle à l&amp;rsquo;autre en fonction de la difficulté et de l&amp;rsquo;importance de la tâche.
Par exemple, vous pouvez répondre aux questions simples des utilisateurs avec des modèles peu coûteux et rapides comme &lt;code>GPT-4o-mini&lt;/code> ou &lt;code>Gemini 1.5 Flash&lt;/code>, et ne basculer la tâche sur &lt;code>Claude 3.5 Sonnet&lt;/code> que si un traitement complexe est jugé nécessaire, permettant d&amp;rsquo;atteindre un équilibre optimal entre coût et performances.&lt;/p>
&lt;p>L&amp;rsquo;évolution de l&amp;rsquo;IA ne s&amp;rsquo;arrête jamais. Comprenez profondément les forces et faiblesses de chaque API ainsi que les caractéristiques de leur architecture, et construisez des applications d&amp;rsquo;IA flexibles et évolutives.&lt;/p></description></item><item><title>Comment utiliser llama.cpp et introduction à la personnalisation en C++</title><link>http://kenji.blog/fr/p/llama-cpp-cxx-customization/</link><pubDate>Fri, 11 Sep 2026 11:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/llama-cpp-cxx-customization/</guid><description>&lt;img src="http://kenji.blog/p/llama-cpp-cxx-customization/img/eyecatch.jpg" alt="Featured image of post Comment utiliser llama.cpp et introduction à la personnalisation en C++" />&lt;p>Ces dernières années, l&amp;rsquo;évolution des grands modèles de langage (LLM) a été fulgurante et leur champ d&amp;rsquo;application s&amp;rsquo;élargit chaque jour. Cependant, faire tourner localement des modèles avec des milliards, voire des dizaines de milliards de paramètres, nécessite généralement des GPU haut de gamme dotés d&amp;rsquo;une énorme quantité de VRAM. C&amp;rsquo;est &lt;strong>llama.cpp&lt;/strong> qui a brisé ce « mur matériel » et a rendu possible l&amp;rsquo;inférence pratique des LLM sur des PC classiques, des Mac, ou encore des appareils comme le Raspberry Pi.&lt;/p>
&lt;p>Dans cet article, nous irons au-delà de la simple utilisation de l&amp;rsquo;outil en ligne de commande. Nous expliquerons en détail, pour les ingénieurs, l&amp;rsquo;architecture de &lt;code>ggml&lt;/code> (sa technologie sous-jacente), le contexte mathématique des Transformers et de la quantification, ainsi que les méthodes pour intégrer et personnaliser des LLM dans vos propres applications en utilisant l&amp;rsquo;API C++.&lt;/p>
&lt;hr>
&lt;h2 id="1-vue-densemble-de-llamacpp-et-ggml">1. Vue d&amp;rsquo;ensemble de llama.cpp et ggml
&lt;/h2>&lt;p>&lt;code>llama.cpp&lt;/code> est un moteur d&amp;rsquo;inférence LLM léger écrit en C/C++ et développé par Georgi Gerganov. À l&amp;rsquo;origine, il a été créé dans le but de faire fonctionner rapidement le modèle LLaMA de Meta sur Apple Silicon (Mac M1/M2), mais il prend aujourd&amp;rsquo;hui en charge une grande variété d&amp;rsquo;architectures et de modèles.&lt;/p>
&lt;p>Sa plus grande caractéristique est d&amp;rsquo;être &lt;strong>une implémentation pure en C/C++ sans dépendances externes&lt;/strong>. Il ne nécessite pas d&amp;rsquo;écosystèmes massifs comme Python ou PyTorch et peut être compilé en un seul fichier exécutable, ce qui rend son déploiement extrêmement facile.&lt;/p>
&lt;p>Le cœur de &lt;code>llama.cpp&lt;/code> est la bibliothèque de calcul tensoriel &lt;strong>ggml&lt;/strong>. ggml a été conçue de zéro pour optimiser à l&amp;rsquo;extrême les opérations matricielles en apprentissage automatique sur CPU (et partiellement sur GPU).&lt;/p>
&lt;h3 id="11-pourquoi-llamacpp-est-il-si-rapide-">1.1 Pourquoi llama.cpp est-il si rapide ?
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>Utilisation du memory mapping (mmap)&lt;/strong> : Lors du chargement des poids du modèle en mémoire, l&amp;rsquo;utilisation de &lt;code>mmap&lt;/code> du système d&amp;rsquo;exploitation permet d&amp;rsquo;éviter un chargement complet en RAM, assurant ainsi un démarrage rapide et une économie de mémoire.&lt;/li>
&lt;li>&lt;strong>Optimisation exhaustive des instructions SIMD&lt;/strong> : Il tire parti des jeux d&amp;rsquo;instructions spécifiques aux processeurs, tels que AVX2, AVX-512, ARM NEON, et Apple AMX, pour accélérer considérablement les multiplications matricielles.&lt;/li>
&lt;li>&lt;strong>Quantification (Quantization)&lt;/strong> : Les poids en nombres à virgule flottante 16 bits (FP16) sont compressés en entiers de 4, 5 ou 8 bits, ce qui élimine les goulots d&amp;rsquo;étranglement liés à la bande passante de la mémoire (les détails seront abordés plus loin).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="2-contexte-mathématique--transformer-et-quantification-quantization">2. Contexte mathématique : Transformer et Quantification (Quantization)
&lt;/h2>&lt;p>Pour comprendre profondément llama.cpp, il est nécessaire de connaître les formules mathématiques qu&amp;rsquo;il calcule et la manière dont il approche ces calculs.&lt;/p>
&lt;h3 id="21-processus-dinférence-des-transformers">2.1 Processus d&amp;rsquo;inférence des Transformers
&lt;/h3>&lt;p>Les modèles comme LLaMA adoptent une architecture de décodeur Transformer de type autorégressif (Auto-regressive). Le cœur de la génération de texte est le mécanisme de &lt;strong>Self-Attention&lt;/strong>.&lt;/p>
&lt;p>Pour la matrice des états cachés d&amp;rsquo;entrée $X \in \mathbb{R}^{N \times d}$, les requêtes $Q$, les clés $K$ et les valeurs $V$ sont calculés par le produit avec des matrices de poids.&lt;/p>
$$
Q = X W_Q, \quad K = X W_K, \quad V = X W_V
$$
&lt;p>Ici, la sortie de l&amp;rsquo;Attention est définie comme suit :&lt;/p>
$$
\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
$$
&lt;p>Dans la boucle d&amp;rsquo;inférence de llama.cpp, le goulot d&amp;rsquo;étranglement réside dans le produit de ces immenses matrices $W_Q, W_K, W_V$ et des matrices de poids du réseau feed-forward (FFN) avec le vecteur $X$ (lors de la phase de génération, un seul jeton est traité à la fois, donc $N=1$). C&amp;rsquo;est ce qu&amp;rsquo;on appelle la &lt;strong>GEMV (General Matrix-Vector Multiplication)&lt;/strong>.&lt;/p>
&lt;h3 id="22-bases-mathématiques-de-la-quantification-quantization">2.2 Bases mathématiques de la quantification (Quantization)
&lt;/h3>&lt;p>Dans les inférences où la bande passante de l&amp;rsquo;accès à la mémoire devient un goulot d&amp;rsquo;étranglement, la quantification, qui représente les paramètres de poids avec un petit nombre de bits, est indispensable. Voici le principe de base de la quantification par blocs (par exemple &lt;code>Q4_K&lt;/code> ou &lt;code>Q4_0&lt;/code>) largement utilisée dans llama.cpp.&lt;/p>
&lt;p>Par exemple, considérons un bloc $w = [w_1, w_2, \dots, w_B]$ de longueur $B$ (généralement 32 ou 64) faisant partie d&amp;rsquo;une matrice de poids $W$ en FP16. Ce bloc est approximé par des entiers de 4 bits $q_i \in [-8, 7]$ et un facteur d&amp;rsquo;échelle unique $\Delta$ (FP16 ou FP32).&lt;/p>
$$
w_i \approx \Delta \times q_i
$$
&lt;p>$\Delta$ est déterminé en fonction de la valeur absolue maximale dans le bloc.&lt;/p>
$$
\Delta = \frac{\max_i |w_i|}{7}
$$
&lt;p>Lors du calcul du produit scalaire $y = w \cdot x$ en utilisant les poids quantifiés, si le vecteur d&amp;rsquo;entrée $x$ est également quantifié de la même manière tel que $x_i \approx \Delta_x \times q_{x, i}$, on obtient :&lt;/p>
$$
y = \sum_{i=1}^{B} w_i x_i \approx \Delta \Delta_x \sum_{i=1}^{B} q_i q_{x, i}
$$
&lt;p>Cette partie $\sum q_i q_{x, i}$ devient &lt;strong>une opération purement entière&lt;/strong>, ce qui permet de la calculer en parallèle de manière extrêmement rapide en utilisant des instructions SIMD. C&amp;rsquo;est le secret mathématique qui permet à llama.cpp d&amp;rsquo;atteindre des vitesses impressionnantes sur CPU.&lt;/p>
&lt;hr>
&lt;h2 id="3-architecture-et-flux-dinférence">3. Architecture et flux d&amp;rsquo;inférence
&lt;/h2>&lt;p>Pour comprendre le fonctionnement interne de llama.cpp, le diagramme Mermaid ci-dessous illustre l&amp;rsquo;architecture globale du système et le flux de données.&lt;/p>
&lt;div class="mermaid">graph TD
A["Entrée utilisateur (Chaîne de caractères)"] --> B["Tokenizer llama.cpp"]
B --> C["IDs de jetons (tableau int32)"]
C --> D["Tampon de contexte (Cache KV)"]
D --> E["Graphe de calcul ggml"]
E --> F["Couches Transformer"]
subgraph "Moteur ggml"
F --> G["Self-Attention (RoPE)"]
G --> H["Réseau Feed Forward"]
H --> F
end
F --> I["Logits (Taille du vocabulaire)"]
I --> J["Échantillonneur (Température, Top-K, Top-P)"]
J --> K["ID de jeton sélectionné"]
K --> L["Detokenizer llama.cpp"]
L --> M["Chaîne de caractères de sortie"]
K -. "Boucle auto-régressive" .-> D&lt;/div>
&lt;p>La génération de texte est une boucle auto-régressive où chaque jeton généré est ajouté au cache KV comme entrée suivante, puis passe à nouveau par le graphe de calcul.&lt;/p>
&lt;hr>
&lt;h2 id="4-configuration-de-lenvironnement-et-méthodes-de-build">4. Configuration de l&amp;rsquo;environnement et méthodes de build
&lt;/h2>&lt;p>Avant d&amp;rsquo;intégrer llama.cpp dans un projet C++, commençons par compiler le code source.&lt;/p>
&lt;h3 id="41-clonage-du-dépôt">4.1 Clonage du dépôt
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git clone https://github.com/ggerganov/llama.cpp.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> llama.cpp
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="42-compilation-avec-cmake">4.2 Compilation avec CMake
&lt;/h3>&lt;p>Pour l&amp;rsquo;intégrer en tant que projet C++ dans d&amp;rsquo;autres applications, l&amp;rsquo;utilisation de CMake est la méthode la plus standard. En activant les accélérateurs (backends) spécifiques à chaque plateforme, vous pouvez accélérer les calculs.&lt;/p>
&lt;p>&lt;strong>CPU uniquement (Compilation de base) :&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake ..
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>En cas d&amp;rsquo;utilisation d&amp;rsquo;un GPU NVIDIA (CUDA) :&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake .. -DGGML_CUDA&lt;span class="o">=&lt;/span>ON
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>En cas d&amp;rsquo;utilisation d&amp;rsquo;Apple Silicon (Metal) :&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">mkdir build &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake .. -DGGML_METAL&lt;span class="o">=&lt;/span>ON
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build . --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Une fois la compilation réussie, des exécutables comme &lt;code>llama-cli&lt;/code> ainsi que la bibliothèque &lt;code>llama&lt;/code> (et la bibliothèque &lt;code>ggml&lt;/code>) à lier avec l&amp;rsquo;API C++ expliquée plus loin seront générés dans le répertoire &lt;code>build/bin/&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="5-introduction-à-la-personnalisation-en-c--utilisation-de-lapi-llamacpp">5. Introduction à la personnalisation en C++ : Utilisation de l&amp;rsquo;API llama.cpp
&lt;/h2>&lt;p>À partir d&amp;rsquo;ici, nous allons aborder le cœur du sujet : le contrôle de llama.cpp depuis du code C++.
Pour intégrer un LLM dans vos propres applications (par exemple, un moteur de jeu, une application de bureau, ou un système embarqué) au lieu de se contenter de l&amp;rsquo;outil en ligne de commande, il est nécessaire d&amp;rsquo;appeler directement l&amp;rsquo;API C++.&lt;/p>
&lt;p>llama.cpp fournit principalement une interface en langage C via le fichier d&amp;rsquo;en-tête &lt;code>llama.h&lt;/code>. Vous utiliserez également cette interface lors de l&amp;rsquo;appel depuis C++.&lt;/p>
&lt;h3 id="51-inclusions-et-configurations-minimales-requises">5.1 Inclusions et configurations minimales requises
&lt;/h3>&lt;p>Pour utiliser llama.cpp dans votre projet, incluez ce qui suit :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;#34;llama.h&amp;#34;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;stdexcept&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Macros pour la gestion des erreurs
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#define LLAMA_ASSERT(x) \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> do { \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> if (!(x)) { \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> std::cerr &amp;lt;&amp;lt; &amp;#34;Assertion failed: &amp;#34; &amp;lt;&amp;lt; #x &amp;lt;&amp;lt; std::endl; \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> std::terminate(); \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> } \
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp"> } while (0)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="52-chargement-du-modèle-et-initialisation-du-contexte">5.2 Chargement du modèle et initialisation du contexte
&lt;/h3>&lt;p>Tout d&amp;rsquo;abord, vous chargez un fichier de modèle au format &lt;code>.gguf&lt;/code> et allouez le contexte pour l&amp;rsquo;inférence (espace mémoire et cache KV).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">argc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">char&lt;/span> &lt;span class="o">**&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">argc&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Usage: &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34; &amp;lt;model.gguf&amp;gt;&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">model_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">argv&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. Initialisation du backend (Configuration de l&amp;#39;environnement CPU/GPU, etc.)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_backend_init&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. Obtention des paramètres par défaut du modèle
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_model_params&lt;/span> &lt;span class="n">model_params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_model_default_params&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_gpu_layers&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">35&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Nombre de couches à décharger sur le GPU
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. Chargement du modèle
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_model&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">model&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_load_model_from_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model_path&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">model_params&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to load model&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 4. Configuration des paramètres du contexte
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_context_params&lt;/span> &lt;span class="n">ctx_params&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_context_default_params&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ctx_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_ctx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">2048&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Taille maximale du contexte (nombre de jetons)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">ctx_params&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_threads&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">8&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Nombre de threads CPU utilisés pour l&amp;#39;inférence
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 5. Création du contexte
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_context&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">ctx&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_new_context_with_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ctx_params&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to create context&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Model and context loaded successfully!&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ... Suite du traitement
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="53-tokenisation-du-prompt-tokenization">5.3 Tokenisation du prompt (Tokenization)
&lt;/h3>&lt;p>Les LLM ne comprennent pas directement le texte, mais le traitent comme une séquence d&amp;rsquo;identifiants entiers (jetons). Il est nécessaire de convertir la chaîne d&amp;rsquo;entrée en jetons.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">prompt&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;Q: Quelle est la capitale du Japon ?&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">A:&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">llama_token&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">resize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">prompt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="mi">4&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Taille du tampon avec une marge
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Faut-il ajouter un jeton spécial (comme BOS : Begin of Sequence) au début ?
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="n">add_special&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Convertir la chaîne en un tableau d&amp;#39;IDs de jetons
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_tokenize&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">prompt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">add_special&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">false&lt;/span> &lt;span class="c1">// parse_special
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n_tokens&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// En cas de tampon insuffisant, une réallocation et un nouvel essai sont nécessaires (omis pour simplifier)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to tokenize prompt&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">resize&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n_tokens&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="54-boucle-dinférence-et-échantillonnage">5.4 Boucle d&amp;rsquo;inférence et échantillonnage
&lt;/h3>&lt;p>On construit une boucle qui fournit les jetons au modèle, obtient la distribution de probabilité des prochains jetons (Logits), puis effectue un échantillonnage pour déterminer le jeton suivant.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Nombre maximum de jetons à générer
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">max_gen_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">100&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Initialisation de la structure pour l&amp;#39;évaluation par lot (batch)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_batch&lt;/span> &lt;span class="n">batch&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_batch_init&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">512&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Ajout des jetons du prompt au lot
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">size_t&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tokens_list&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">i&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="p">},&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Configurer pour n&amp;#39;émettre des logits (résultats de prédiction) que pour le dernier jeton du prompt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">logits&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Première évaluation (fournir le prompt au modèle)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;llama_decode() failed&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_cur&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Longueur actuelle du contexte
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_decode&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">Output: &amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Initialisation du contexte de l&amp;#39;échantillonneur (Configuration de la Température, Top-K, Top-P, etc.)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_sampler&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">smpl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_sampler_chain_init&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">llama_sampler_chain_default_params&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_top_k&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">40&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_top_p&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.9f&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_temp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">0.7f&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_sampler_chain_add_dist&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1234&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Graine aléatoire (seed)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n_decode&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">max_gen_tokens&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. Échantillonnage : Prédire le prochain jeton basé sur le contexte actuel
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_token&lt;/span> &lt;span class="n">new_token_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_sampler_sample&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. Si le jeton est EOS (End of Sequence), terminer la boucle
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_token_is_eog&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_token_id&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. Décoder le jeton en chaîne de caractères (texte) et l&amp;#39;afficher
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">char&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">128&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">n_chars&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_token_to_piece&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_token_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">buf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">n_chars&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_chars&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">flush&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 4. Préparer le jeton nouvellement généré comme le prochain lot
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_batch_clear&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_token_id&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">n_cur&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">0&lt;/span> &lt;span class="p">},&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 5. Évaluation du modèle (Mettre à jour le cache KV et prédire la suite)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_decode&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cerr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Failed to evaluate&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n_cur&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">n_decode&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Nettoyage
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">llama_sampler_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">smpl&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_batch_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">batch&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_free_model&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">llama_backend_free&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ce code implémente une boucle d&amp;rsquo;inférence personnalisée en utilisant l&amp;rsquo;API de base de llama.cpp.
Il utilise la structure &lt;code>llama_batch&lt;/code> pour gérer un ensemble de jetons et exécute la passe avant (forward pass) du réseau neuronal avec &lt;code>llama_decode&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="6-cas-de-personnalisation-avancée--manipulation-des-logits-et-contrôle-des-pénalités-en-c">6. Cas de personnalisation avancée : Manipulation des logits et contrôle des pénalités en C++
&lt;/h2>&lt;p>Si vous souhaitez aller au-delà de la simple génération de texte et forcer la sortie dans un format spécifique (par exemple, uniquement du JSON), ou contrôler la sortie pour empêcher certains mots interdits, vous manipulerez directement les &lt;strong>logits&lt;/strong> avant l&amp;rsquo;échantillonnage du côté C++.&lt;/p>
&lt;p>Vous pouvez obtenir le tableau des scores bruts (les valeurs avant conversion en probabilités) juste avant que le modèle ne sorte chaque jeton.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Obtenir le tableau des logits bruts juste après l&amp;#39;inférence et avant l&amp;#39;échantillonnage
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">float&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="n">logits&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_get_logits_ith&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ctx&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">batch&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">n_tokens&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="n">n_vocab&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">llama_n_vocab&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">model&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Liste des IDs des jetons interdits (par exemple 1234, 5678)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">llama_token&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">forbidden_tokens&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="mi">1234&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">5678&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Mettre la probabilité d&amp;#39;apparition des jetons interdits à 0 (Logit à moins l&amp;#39;infini)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">llama_token&lt;/span> &lt;span class="nl">bad_tok&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">forbidden_tokens&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logits&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">bad_tok&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="o">-&lt;/span>&lt;span class="n">INFINITY&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>De cette façon, la manipulation directe de l&amp;rsquo;API C++ rend possible une &lt;strong>&amp;ldquo;intervention à la microseconde pour chaque cycle d&amp;rsquo;inférence&amp;rdquo;&lt;/strong>, ce qui serait difficile ou entraînerait une forte surcharge via LangChain ou Python.&lt;/p>
&lt;hr>
&lt;h2 id="7-les-secrets-du-réglage-des-performances-performance-tuning">7. Les secrets du réglage des performances (Performance Tuning)
&lt;/h2>&lt;p>Une fois l&amp;rsquo;implémentation en C++ terminée, voici quelques points de contrôle pour maximiser la vitesse en vue d&amp;rsquo;une utilisation en production.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Optimisation du traitement par lots (Batching) :&lt;/strong> Si vous traitez simultanément les requêtes de plusieurs utilisateurs, incluez plusieurs séquences dans &lt;code>llama_batch&lt;/code> et appelez &lt;code>llama_decode&lt;/code> en une seule fois (Continuous Batching). Cela permet de mutualiser les accès mémoire et d&amp;rsquo;améliorer considérablement le débit.&lt;/li>
&lt;li>&lt;strong>Activation de Flash Attention :&lt;/strong>
En configurant &lt;code>ctx_params.flash_attn = true;&lt;/code> dans les paramètres du contexte, vous pouvez accélérer le calcul de l&amp;rsquo;Attention tout en réduisant l&amp;rsquo;utilisation de la mémoire. C&amp;rsquo;est un paramètre indispensable lorsque vous manipulez de longs contextes (des dizaines de milliers de jetons).&lt;/li>
&lt;li>&lt;strong>Prise en charge NUMA :&lt;/strong>
Dans un environnement de serveur multiprocesseur (multi-socket), configurer correctement NUMA avant &lt;code>llama_backend_init()&lt;/code> permet de réduire la latence d&amp;rsquo;accès à la mémoire.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="8-conclusion">8. Conclusion
&lt;/h2>&lt;p>Dans cet article, nous avons détaillé les bases mathématiques de &lt;code>llama.cpp&lt;/code>, expliqué son architecture et montré comment construire un moteur d&amp;rsquo;inférence personnalisé en exploitant l&amp;rsquo;API C++.&lt;/p>
&lt;p>Si l&amp;rsquo;écosystème Python est extrêmement pratique pour le prototypage, le contrôle direct via &lt;code>llama.cpp&lt;/code> en C/C++ montre une puissance écrasante dans des environnements de production nécessitant un déploiement sur des appareils Edge, une intégration dans des jeux ou un traitement en temps réel.&lt;/p>
&lt;p>N&amp;rsquo;hésitez pas à écrire vous-même du code C++ et à faire l&amp;rsquo;expérience du plaisir de manipuler librement des LLM dans votre propre environnement local.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Liens de référence&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/llama.cpp" target="_blank" rel="noopener"
>llama.cpp Official Repository&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://github.com/ggerganov/ggml" target="_blank" rel="noopener"
>ggml - Tensor Library&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://arxiv.org/abs/1706.03762" target="_blank" rel="noopener"
>Attention Is All You Need (Vaswani et al., 2017)&lt;/a>&lt;/li>
&lt;/ul>
&lt;/blockquote></description></item><item><title>【Dernière version 2026】Guide complet pour exécuter un LLM local sous Windows</title><link>http://kenji.blog/fr/p/local-llm-windows-2026/</link><pubDate>Fri, 11 Sep 2026 10:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/local-llm-windows-2026/</guid><description>&lt;img src="http://kenji.blog/p/local-llm-windows-2026/img/eyecatch.jpg" alt="Featured image of post 【Dernière version 2026】Guide complet pour exécuter un LLM local sous Windows" />&lt;h1 id="1-introduction--pourquoi-un-llm-local-sous-windows-aujourdhui-">1. Introduction : Pourquoi un LLM local sous Windows aujourd&amp;rsquo;hui ?
&lt;/h1>&lt;p>En 2026, l&amp;rsquo;évolution de l&amp;rsquo;IA générative et des grands modèles linguistiques (LLM) montre un changement de paradigme majeur, passant des services API massifs sur le cloud aux &amp;ldquo;LLM locaux&amp;rdquo; fonctionnant sur des PC personnels ou dans des environnements sur site. Les IA cloud comme GPT-5 d&amp;rsquo;OpenAI ou Claude 3.5 d&amp;rsquo;Anthropic sont extrêmement puissantes, mais les entreprises et les particuliers ne peuvent pas toujours envoyer toutes leurs données sur le cloud. Du point de vue de la confidentialité, de la sécurité, de la latence et des coûts à long terme et durables, la demande de LLM locaux a explosé comme jamais auparavant.&lt;/p>
&lt;p>L&amp;rsquo;évolution de l&amp;rsquo;écosystème des LLM locaux, en particulier dans l&amp;rsquo;environnement Windows, est remarquable. Il y a quelques années, il était de notoriété publique que &amp;ldquo;le développement et l&amp;rsquo;exécution de l&amp;rsquo;IA se font sous Linux&amp;rdquo;, mais en 2026, Windows s&amp;rsquo;est transformé en une plateforme d&amp;rsquo;IA extrêmement puissante et facile d&amp;rsquo;accès.&lt;/p>
&lt;p>Cet article fournit un guide complet pour configurer, exploiter et optimiser les LLM locaux dans un environnement Windows, sur la base des dernières tendances technologiques de 2026. Nous expliquerons tout en détail avec un volume impressionnant, de la configuration facile avec Ollama pour les débutants, à l&amp;rsquo;optimisation extrême utilisant llama.cpp pour les utilisateurs avancés, en passant par l&amp;rsquo;approche mathématique des calculs VRAM, la compréhension approfondie de l&amp;rsquo;architecture et le fine-tuning (ajustement fin) en local.&lt;/p>
&lt;h2 id="11-tendances-technologiques-entourant-les-llm-locaux-en-2026">1.1 Tendances technologiques entourant les LLM locaux en 2026
&lt;/h2>&lt;p>Les principales tendances qui façonnent l&amp;rsquo;écosystème actuel des LLM locaux sont les suivantes :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Adoption complète du format GGUF&lt;/strong> : GGUF (GPT-Generated Unified Format), qui intègre les métadonnées et les tenseurs dans un seul fichier, est devenu le standard de facto absolu. Ainsi, en téléchargeant un seul fichier depuis Hugging Face, il peut être exécuté dans n&amp;rsquo;importe quel environnement.&lt;/li>
&lt;li>&lt;strong>Démocratisation de l&amp;rsquo;architecture MoE (Mixture of Experts)&lt;/strong> : De nombreux modèles MoE, petits mais performants, ont été publiés. En activant seulement certains experts lors de l&amp;rsquo;inférence, ils atteignent des performances comparables aux modèles géants tout en réduisant la charge de calcul sur les PC grand public.&lt;/li>
&lt;li>&lt;strong>Abstraction et optimisation avancées des moteurs d&amp;rsquo;inférence&lt;/strong> : Des outils comme Ollama, LM Studio et AnythingLLM ont été affinés, éliminant le besoin pour les utilisateurs de se soucier des dépendances complexes telles que l&amp;rsquo;installation des pilotes CUDA. De plus, la prise en charge native de FlashAttention 3 sous Windows a considérablement amélioré la vitesse d&amp;rsquo;inférence.&lt;/li>
&lt;li>&lt;strong>Utilisation des NPU et essor des PC Windows Copilot+&lt;/strong> : La technologie permettant d&amp;rsquo;exécuter de petits LLM (SLM : Small Language Models) avec une faible consommation d&amp;rsquo;énergie en utilisant le NPU (Neural Processing Unit) intégré, même sur les ordinateurs portables sans GPU, est entrée dans la phase pratique.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="2-exigences-matérielles-et-préparation-du-système-dexploitation">2. Exigences matérielles et préparation du système d&amp;rsquo;exploitation
&lt;/h1>&lt;p>Pour qu&amp;rsquo;un LLM local fonctionne à une vitesse pratique (15 à 30 tokens ou plus par seconde), le choix du matériel est le plus important.&lt;/p>
&lt;h2 id="21-configuration-matérielle-recommandée">2.1 Configuration matérielle recommandée
&lt;/h2>&lt;p>Avec l&amp;rsquo;évolution des PC IA, les spécifications requises évoluent également.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Système d&amp;rsquo;exploitation (OS)&lt;/strong> : Windows 11 Pro (24H2 ou ultérieur). Indispensable pour utiliser toutes les fonctionnalités de WSL2, la gestion avancée de la mémoire, ainsi que les dernières API de DirectML.&lt;/li>
&lt;li>&lt;strong>CPU&lt;/strong> : Intel Core Ultra série 200 ou supérieur, ou AMD Ryzen série 9000 ou supérieur. Lors de l&amp;rsquo;utilisation conjointe de l&amp;rsquo;inférence CPU, une communication mémoire à large bande passante est essentielle.&lt;/li>
&lt;li>&lt;strong>RAM&lt;/strong> : Minimum 32 Go, 64 Go ou plus recommandés. La bande passante de la mémoire principale (Mo/s) devient un goulot d&amp;rsquo;étranglement décisif lors de l&amp;rsquo;inférence CPU ou du déchargement. Une mémoire rapide DDR5-6000 ou supérieure est idéale.&lt;/li>
&lt;li>&lt;strong>GPU&lt;/strong> : Séries NVIDIA RTX 4000/5000. Pour les LLM locaux, le plus important n&amp;rsquo;est pas la puissance de calcul, mais la &amp;ldquo;capacité de la VRAM&amp;rdquo;.
&lt;ul>
&lt;li>&lt;strong>Entrée de gamme&lt;/strong> : RTX 4060 Ti (version 16 Go) - Le meilleur rapport qualité-prix. Idéal pour les modèles de la classe 8B à 14B.&lt;/li>
&lt;li>&lt;strong>Milieu de gamme&lt;/strong> : RTX 4070 Ti SUPER (16 Go) / RTX 4080 SUPER (16 Go)&lt;/li>
&lt;li>&lt;strong>Haut de gamme&lt;/strong> : RTX 4090 (24 Go) / RTX 5090 (32 Go) - Nécessaire pour exécuter des modèles quantifiés de la classe 30B à 70B.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Stockage&lt;/strong> : SSD NVMe PCIe Gen4 ou Gen5. Réduit considérablement le temps de chargement des modèles de plusieurs dizaines de gigaoctets.&lt;/li>
&lt;/ul>
&lt;h2 id="22-configuration-de-wsl2-windows-subsystem-for-linux-2">2.2 Configuration de WSL2 (Windows Subsystem for Linux 2)
&lt;/h2>&lt;p>Bien que de nombreux outils GUI fonctionnent nativement sous Windows, WSL2 est très pratique pour le développement avec Python, la compilation des derniers outils et le fine-tuning LoRA décrit plus loin. Dans les environnements Windows 11 récents, en installant simplement le pilote NVIDIA sur l&amp;rsquo;hôte, le GPU (CUDA) peut être utilisé de manière transparente depuis WSL2.&lt;/p>
&lt;p>Ouvrez PowerShell avec les droits d&amp;rsquo;administrateur et exécutez ce qui suit :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Installation de WSL2 et du dernier Ubuntu&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-install&lt;/span> &lt;span class="n">-d&lt;/span> &lt;span class="n">Ubuntu&lt;/span>&lt;span class="p">-&lt;/span>&lt;span class="mf">24.04&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Mise à jour du noyau&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-update&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Après l&amp;rsquo;installation, exécutez &lt;code>nvidia-smi&lt;/code> dans le terminal WSL2. Si le GPU est correctement reconnu, c&amp;rsquo;est un succès.&lt;/p>
&lt;hr>
&lt;h1 id="3-architecture-et-mécanisme-dinférence-des-llm-locaux">3. Architecture et mécanisme d&amp;rsquo;inférence des LLM locaux
&lt;/h1>&lt;p>Comprendre la structure interne, c&amp;rsquo;est-à-dire la manière dont les modèles génèrent du texte dans un environnement local, est extrêmement utile pour le dépannage et l&amp;rsquo;optimisation.&lt;/p>
&lt;p>Le diagramme Mermaid suivant montre le pipeline d&amp;rsquo;inférence typique d&amp;rsquo;un LLM local.&lt;/p>
&lt;div class="mermaid">graph TD
User["Entrée utilisateur (Prompt)"] --> Tokenizer["Tokeniseur (Tokenizer)"]
Tokenizer --> Embedding["Couche de plongement (Embedding)"]
subgraph "Transformer Block (x Layers)"
Embedding --> Attn["Auto-attention (Self-Attention)"]
Attn --> KVCache["Cache KV (Maintien Key/Value)"]
Attn --> FFN["Réseau Feed-Forward (FFN)"]
end
FFN --> Logits["Calcul des Logits (Logits)"]
Logits --> Sampler["Échantillonneur (Temperature, Top-K, Top-P)"]
Sampler --> OutputToken["Token de sortie"]
OutputToken --> |"Génération autorégressive"| Tokenizer
OutputToken --> Decoder["Détokeniseur (Detokenizer)"]
Decoder --> FinalOutput["Texte de sortie final"]&lt;/div>
&lt;h2 id="31-deux-phases--prefill-et-decode">3.1 Deux phases : Prefill et Decode
&lt;/h2>&lt;p>La génération de texte des LLM est divisée en deux phases aux caractéristiques de calcul différentes.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Phase de Prefill (traitement du prompt)&lt;/strong> : C&amp;rsquo;est la phase où l&amp;rsquo;ensemble du prompt entré est traité et compris en une seule fois. Étant donné que le calcul parallèle est possible, la capacité de calcul (FLOPS) du GPU est directement liée à la vitesse. Si le prompt est long, cette phase peut prendre plusieurs secondes.&lt;/li>
&lt;li>&lt;strong>Phase de Decode (génération de tokens)&lt;/strong> : C&amp;rsquo;est la phase de prédiction token par token, en transmettant à l&amp;rsquo;entrée suivante (autorégressif). Comme le calcul parallèle est limité dans cette phase, la bande passante de la VRAM du GPU (Memory Bandwidth) devient le goulot d&amp;rsquo;étranglement décisif.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h1 id="4-calcul-de-la-consommation-de-vram-et-compréhension-mathématique-de-la-taille-du-modèle">4. Calcul de la consommation de VRAM et compréhension mathématique de la taille du modèle
&lt;/h1>&lt;p>Pour juger correctement de &amp;ldquo;quel modèle fonctionnera sur mon PC ?&amp;rdquo;, il est nécessaire de comprendre la formule de calcul de la VRAM. Lorsqu&amp;rsquo;un repli sur la mémoire système (RAM) se produit en raison d&amp;rsquo;un manque de VRAM, la vitesse d&amp;rsquo;inférence devient 10 à 100 fois plus lente.&lt;/p>
&lt;h2 id="41-vram-de-base-basée-sur-la-taille-des-paramètres">4.1 VRAM de base basée sur la taille des paramètres
&lt;/h2>&lt;p>Il s&amp;rsquo;agit de la quantité de mémoire nécessaire pour charger les poids (weights) du modèle dans la VRAM.
Elle se calcule à l&amp;rsquo;aide de la taille du modèle $P$ (nombre de paramètres, unité : 1 milliard = 1B) et du nombre d&amp;rsquo;octets par paramètre $B$.&lt;/p>
$$
V_{base} = P \times B \quad \text{(GB)}
$$
&lt;p>Par exemple, pour charger un modèle de 8B (8 milliards) de paramètres en FP16 (virgule flottante demi-précision, 16 bits = 2 octets) :&lt;/p>
$$
V_{base} = 8 \times 2 = 16 \text{ GB}
$$
&lt;p>En d&amp;rsquo;autres termes, même avec un GPU doté de 16 Go de VRAM, on atteint presque la limite rien qu&amp;rsquo;en chargeant le modèle.&lt;/p>
&lt;h2 id="42-la-magie-de-la-quantification-quantization">4.2 La magie de la quantification (Quantization)
&lt;/h2>&lt;p>C&amp;rsquo;est là qu&amp;rsquo;intervient la &amp;ldquo;quantification&amp;rdquo;. En réduisant la précision des paramètres, la taille du modèle est considérablement réduite. Dans le cas de la quantification 4 bits la plus courante (ex: Q4_K_M), la moyenne est d&amp;rsquo;environ 0,55 octet par paramètre.&lt;/p>
$$
V_{base\_4bit} = 8 \times 0.55 = 4.4 \text{ GB}
$$
&lt;p>Grâce à cela, si vous avez 16 Go de VRAM, vous pouvez exécuter un modèle 8B avec une marge suffisante.&lt;/p>
&lt;h2 id="43-calcul-du-cache-kv-version-compatible-gqa">4.3 Calcul du cache KV (Version compatible GQA)
&lt;/h2>&lt;p>Lors de l&amp;rsquo;inférence, le &amp;ldquo;cache KV&amp;rdquo; utilisé pour conserver le contexte passé consomme de la VRAM. Dans les modèles récents comme Llama 3, la GQA (Grouped Query Attention) est adoptée pour économiser de la mémoire.&lt;/p>
&lt;p>La consommation du cache KV $V_{kv}$ (en gigaoctets) est exprimée par la formule mathématique suivante :&lt;/p>
$$
V_{kv} = 2 \times b \times s \times l \times \left( \frac{h_{kv}}{h_q} \right) \times h_q \times d \times B_{kv} \div 10^9
$$
&lt;p>En simplifiant, cela peut être calculé facilement à l&amp;rsquo;aide du nombre de têtes clés et valeurs $h_{kv}$.&lt;/p>
$$
V_{kv} = 2 \times b \times s \times l \times h_{kv} \times d \times B_{kv} \div 10^9
$$
&lt;p>Où :&lt;/p>
&lt;ul>
&lt;li>$b$ : Taille du lot (généralement 1 pour un usage local individuel)&lt;/li>
&lt;li>$s$ : Longueur de séquence (longueur du contexte, ex: 8192)&lt;/li>
&lt;li>$l$ : Nombre de couches (ex: 32)&lt;/li>
&lt;li>$h_{kv}$ : Nombre de têtes KV (ex: 8)&lt;/li>
&lt;li>$d$ : Nombre de dimensions par tête (ex: 128)&lt;/li>
&lt;li>$B_{kv}$ : Nombre d&amp;rsquo;octets du cache KV (2 pour FP16)&lt;/li>
&lt;/ul>
&lt;p>Exemple de calcul (Llama 3 8B, contexte 8192, cache FP16) :
$V_{kv} = 2 \times 1 \times 8192 \times 32 \times 8 \times 128 \times 2 \div 10^9 \approx 1.07 \text{ GB}$&lt;/p>
&lt;p>Veuillez noter que plus la longueur du contexte $s$ est longue, plus la VRAM requise augmente linéairement.&lt;/p>
&lt;hr>
&lt;h1 id="5-pratique-1--configuration-la-plus-rapide-et-la-plus-courte-avec-ollama">5. Pratique 1 : Configuration la plus rapide et la plus courte avec Ollama
&lt;/h1>&lt;p>Maintenant que vous comprenez la théorie, essayons de faire fonctionner un LLM dans un environnement Windows.
En 2026, l&amp;rsquo;outil le plus convivial est &amp;ldquo;Ollama&amp;rdquo;. Il fournit une CLI intuitive de type Docker.&lt;/p>
&lt;h2 id="51-installation-et-exécution">5.1 Installation et exécution
&lt;/h2>&lt;ol>
&lt;li>Téléchargez et exécutez le programme d&amp;rsquo;installation Windows depuis le &lt;a class="link" href="https://ollama.com/" target="_blank" rel="noopener"
>site officiel d&amp;rsquo;Ollama&lt;/a>.&lt;/li>
&lt;li>Ouvrez PowerShell et entrez la commande suivante. Ici, nous utiliserons &lt;code>llama3:8b&lt;/code>, qui prend en charge le japonais (et le français).&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">ollama&lt;/span> &lt;span class="n">run&lt;/span> &lt;span class="n">llama3&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="n">8b&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Lors de la première exécution, le modèle sera téléchargé. Une fois terminé, vous pouvez interagir directement dans le terminal.&lt;/p>
&lt;h2 id="52-création-dune-ia-personnalisée-avec-modelfile">5.2 Création d&amp;rsquo;une IA personnalisée avec Modelfile
&lt;/h2>&lt;p>Vous pouvez facilement créer une IA avec un persona spécifique. Créez un fichier &lt;code>Modelfile&lt;/code> à l&amp;rsquo;emplacement de votre choix.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">FROM llama3:8b
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">SYSTEM &amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Vous êtes un ingénieur logiciel senior extrêmement compétent.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Répondez toujours aux questions des utilisateurs de manière logique et concise, en incluant des exemples de code.
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">PARAMETER temperature 0.3
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">PARAMETER num_ctx 8192
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Construisez et exécutez votre propre modèle avec les commandes suivantes :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">ollama&lt;/span> &lt;span class="n">create&lt;/span> &lt;span class="n">SeniorDev&lt;/span> &lt;span class="o">-f&lt;/span> &lt;span class="p">./&lt;/span>&lt;span class="n">Modelfile&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ollama&lt;/span> &lt;span class="n">run&lt;/span> &lt;span class="n">SeniorDev&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="53-utilisation-depuis-des-applications-externes-éditeurs-ia">5.3 Utilisation depuis des applications externes (Éditeurs IA)
&lt;/h2>&lt;p>Ollama expose un point de terminaison API compatible OpenAI sur &lt;code>http://localhost:11434&lt;/code>.
En spécifiant simplement cette URL dans les paramètres de backend d&amp;rsquo;extensions VS Code comme Cursor ou Continue.dev, et en définissant le nom du modèle sur &lt;code>SeniorDev&lt;/code>, etc., vous obtenez un puissant assistant de codage local gratuit.&lt;/p>
&lt;hr>
&lt;h1 id="6-pratique-2--optimisation-extrême-des-performances-avec-llamacpp">6. Pratique 2 : Optimisation extrême des performances avec llama.cpp
&lt;/h1>&lt;p>Si vous souhaitez gérer la mémoire en détail ou être le premier à essayer les derniers formats (EXL2, quantification IQ, etc.), vous pouvez manipuler directement le moteur de base &lt;code>llama.cpp&lt;/code>.&lt;/p>
&lt;h2 id="61-procédure-de-compilation-de-llamacpp">6.1 Procédure de compilation de llama.cpp
&lt;/h2>&lt;p>Dans un environnement Windows, il est préférable de compiler à partir des sources en utilisant CUDA Toolkit et CMake.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">git&lt;/span> &lt;span class="n">clone&lt;/span> &lt;span class="n">https&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="p">//&lt;/span>&lt;span class="n">github&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">com&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">ggerganov&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">llama&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd &lt;/span>&lt;span class="n">llama&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nb">cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">&lt;/span>&lt;span class="n">mkdir&lt;/span> &lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd &lt;/span>&lt;span class="n">build&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Configuration et compilation avec prise en charge de CUDA&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">..&lt;/span> &lt;span class="n">-DLLAMA_CUBLAS&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="n">ON&lt;/span> &lt;span class="n">-DBUILD_SHARED_LIBS&lt;/span>&lt;span class="p">=&lt;/span>&lt;span class="n">OFF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmake&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-build&lt;/span> &lt;span class="p">.&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-config&lt;/span> &lt;span class="n">Release&lt;/span> &lt;span class="n">-j&lt;/span> &lt;span class="mf">16&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="62-lancement-avancé-en-mode-serveur">6.2 Lancement avancé en mode serveur
&lt;/h2>&lt;p>Utilisez &lt;code>llama-server.exe&lt;/code> compilé pour héberger le modèle.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="p">.\&lt;/span>&lt;span class="n">bin&lt;/span>&lt;span class="p">\&lt;/span>&lt;span class="n">Release&lt;/span>&lt;span class="p">\&lt;/span>&lt;span class="nb">llama-server&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">exe&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-model&lt;/span> &lt;span class="s2">&amp;#34;C:\models\Llama-3-8B-Instruct.Q4_K_M.gguf&amp;#34;&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-ctx-size&lt;/span> &lt;span class="mf">8192&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-n-gpu-layers&lt;/span> &lt;span class="mf">99&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-threads&lt;/span> &lt;span class="mf">8&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-flash-attn&lt;/span> &lt;span class="p">`&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">-&lt;/span>&lt;span class="n">-port&lt;/span> &lt;span class="mf">8080&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ul>
&lt;li>&lt;code>--n-gpu-layers 99&lt;/code> : Décharge autant de couches que possible vers la VRAM du GPU.&lt;/li>
&lt;li>&lt;code>--flash-attn&lt;/code> : Active FlashAttention 3, permettant d&amp;rsquo;améliorer la vitesse d&amp;rsquo;inférence et de réduire la consommation VRAM du cache KV.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="7-front-end-gui--lm-studio-et-construction-dun-rag-local">7. Front-end GUI : LM Studio et construction d&amp;rsquo;un RAG local
&lt;/h1>&lt;p>Si vous êtes réticent à utiliser la ligne de commande ou si vous souhaitez effectuer un RAG (Génération Augmentée par la Recherche) de manière intuitive, utilisez une interface graphique (GUI).&lt;/p>
&lt;h2 id="71-lm-studio">7.1 LM Studio
&lt;/h2>&lt;p>LM Studio est une excellente application qui regroupe la recherche de modèles, le téléchargement, la vérification préalable des exigences système et une interface utilisateur de chat en un seul endroit. En appuyant simplement sur le bouton &amp;ldquo;Local Server&amp;rdquo; dans l&amp;rsquo;application, une API compatible OpenAI démarre.&lt;/p>
&lt;h2 id="72-architecture-rag-à-laide-danythingllm">7.2 Architecture RAG à l&amp;rsquo;aide d&amp;rsquo;AnythingLLM
&lt;/h2>&lt;p>Voici un diagramme de l&amp;rsquo;architecture d&amp;rsquo;un environnement RAG permettant d&amp;rsquo;importer des documents d&amp;rsquo;entreprise ou des notes personnelles.&lt;/p>
&lt;div class="mermaid">graph LR
Document["Document (PDF, MD)"] --> Chunking["Découpage en morceaux"]
Chunking --> EmbedModel["Modèle de plongement"]
EmbedModel --> VectorDB["Base de données vectorielle"]
UserQuery["Question de l'utilisateur"] --> EmbedQuery["Plongement de la question"]
EmbedQuery --> VectorDB
VectorDB --> |"Recherche de similarité"| RetrievedDocs["Extraction de documents pertinents"]
UserQuery --> PromptBuilder["Génération du prompt"]
RetrievedDocs --> PromptBuilder
PromptBuilder --> LocalLLM["LLM local"]
LocalLLM --> Answer["Réponse finale"]&lt;/div>
&lt;p>Avec la version de bureau d&amp;rsquo;AnythingLLM (Windows), il suffit de spécifier Ollama (LLM et Embedding) dans l&amp;rsquo;écran des paramètres et de configurer l&amp;rsquo;utilisation d&amp;rsquo;une base de données vectorielle locale (LanceDB) pour compléter cette architecture en quelques minutes. C&amp;rsquo;est la naissance d&amp;rsquo;une IA privée qui n&amp;rsquo;envoie aucune donnée à l&amp;rsquo;extérieur.&lt;/p>
&lt;hr>
&lt;h1 id="8-fine-tuning-sur-windows-wsl2-lora">8. Fine-tuning sur Windows WSL2 (LoRA)
&lt;/h1>&lt;p>Si vous ne voulez pas seulement l&amp;rsquo;exécuter localement, mais aussi rendre le modèle plus intelligent avec vos propres données, un fine-tuning à l&amp;rsquo;aide de LoRA (Low-Rank Adaptation) est possible. En 2026, grâce à une bibliothèque appelée &amp;ldquo;Unsloth&amp;rdquo;, l&amp;rsquo;apprentissage d&amp;rsquo;un modèle 8B peut être achevé en quelques heures dans un environnement Windows WSL2, même avec 16 Go de VRAM.&lt;/p>
&lt;p>Exécutez ce qui suit dans Ubuntu sur WSL2 pour configurer l&amp;rsquo;environnement :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">conda create --name unsloth_env &lt;span class="nv">python&lt;/span>&lt;span class="o">=&lt;/span>3.11
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">conda activate unsloth_env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install &lt;span class="s2">&amp;#34;unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pip install --no-deps trl peft accelerate bitsandbytes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Unsloth optimise les noyaux CUDA à l&amp;rsquo;extrême, rendant la vitesse d&amp;rsquo;apprentissage environ deux fois plus rapide et la consommation de VRAM réduite de moitié par rapport à la bibliothèque standard Hugging Face. En lançant simplement un Jupyter Notebook et en chargeant un jeu de données (format JSONL), l&amp;rsquo;apprentissage sur plusieurs époques est possible même avec une RTX 4060 Ti dotée de 12 à 16 Go de VRAM.&lt;/p>
&lt;hr>
&lt;h1 id="9-dépannage-des-performances">9. Dépannage des performances
&lt;/h1>&lt;p>Voici les problèmes fréquemment rencontrés et leurs solutions.&lt;/p>
&lt;h3 id="1-la-vitesse-dinférence-est-extrêmement-lente-1-à-2-tokenss">1. La vitesse d&amp;rsquo;inférence est extrêmement lente (1 à 2 tokens/s)
&lt;/h3>&lt;p>&lt;strong>Cause&lt;/strong> : Le modèle ne rentre pas dans la VRAM et est déchargé sur la mémoire système (RAM).
&lt;strong>Solution&lt;/strong> : Vérifiez la &amp;ldquo;Mémoire GPU dédiée&amp;rdquo; dans le Gestionnaire des tâches. Si elle atteint sa limite, réduisez la taille du contexte (&lt;code>-c&lt;/code>) ou utilisez un modèle avec un niveau de quantification inférieur (comme Q4_K_M).&lt;/p>
&lt;h3 id="2-erreur-cuda-out-of-memory">2. Erreur &amp;ldquo;CUDA out of memory&amp;rdquo;
&lt;/h3>&lt;p>&lt;strong>Cause&lt;/strong> : La VRAM est complètement épuisée. Cela se produit notamment lorsque la conversation se prolonge et que le cache KV augmente de manière excessive.
&lt;strong>Solution&lt;/strong> : Limitez intentionnellement la valeur de &lt;code>num_ctx&lt;/code> pour Ollama, ou &lt;code>-c&lt;/code> pour llama.cpp.&lt;/p>
&lt;h3 id="3-la-génération-du-japonais-est-étrange">3. La génération du japonais est étrange
&lt;/h3>&lt;p>&lt;strong>Cause&lt;/strong> : Incohérence dans le modèle de prompt, ou modèle non compatible.
&lt;strong>Solution&lt;/strong> : Utilisez un modèle dont le nom inclut &lt;code>Instruct&lt;/code> et assurez-vous que le modèle de prompt correct (format ChatML, format Llama3, etc.) spécifié par le créateur du modèle est sélectionné du côté de l&amp;rsquo;outil.&lt;/p>
&lt;hr>
&lt;h1 id="10-conclusion-et-perspectives-davenir">10. Conclusion et perspectives d&amp;rsquo;avenir
&lt;/h1>&lt;p>En 2026, la mise en place d&amp;rsquo;un LLM local dans un environnement Windows n&amp;rsquo;est plus un privilège réservé à une poignée d&amp;rsquo;ingénieurs. Avec l&amp;rsquo;adoption généralisée du format GGUF, l&amp;rsquo;émergence d&amp;rsquo;écosystèmes raffinés comme Ollama et LM Studio, ainsi que les optimisations matérielles telles que FlashAttention, n&amp;rsquo;importe qui peut facilement obtenir un environnement d&amp;rsquo;IA de niveau entreprise.&lt;/p>
&lt;p>N&amp;rsquo;hésitez pas à tirer parti des points expliqués dans cet article :&lt;/p>
&lt;ol>
&lt;li>Utiliser le &lt;strong>calcul mathématique de la VRAM&lt;/strong> pour choisir logiquement la taille de modèle et le niveau de quantification optimaux pour les spécifications de votre PC.&lt;/li>
&lt;li>Utiliser &lt;strong>Ollama&lt;/strong> pour configurer l&amp;rsquo;environnement le plus rapidement possible et l&amp;rsquo;intégrer à un éditeur d&amp;rsquo;IA pour améliorer considérablement la productivité.&lt;/li>
&lt;li>Exploiter les limites de performance du matériel avec le contrôle avancé des paramètres de &lt;strong>llama.cpp&lt;/strong>.&lt;/li>
&lt;li>Construire un système RAG local sécurisé qui gère les données confidentielles avec &lt;strong>AnythingLLM&lt;/strong>.&lt;/li>
&lt;li>Tirer parti d&amp;rsquo;&lt;strong>Unsloth (WSL2)&lt;/strong> pour développer une IA personnalisée avec votre propre expertise.&lt;/li>
&lt;/ol>
&lt;p>La &amp;ldquo;démocratisation&amp;rdquo; de l&amp;rsquo;IA n&amp;rsquo;est plus un buzzword, mais un système réel fonctionnant sur votre bureau Windows. Libérez-vous des coûts d&amp;rsquo;utilisation des API cloud et des risques de fuite d&amp;rsquo;informations, et entrez dès maintenant dans le monde libre et puissant de l&amp;rsquo;IA privée.&lt;/p></description></item></channel></rss>