<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Programming &#8211; Smals Research</title>
	<atom:link href="https://www.smalsresearch.be/tag/programming/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.smalsresearch.be</link>
	<description></description>
	<lastBuildDate>Thu, 09 Apr 2026 12:04:16 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://www.smalsresearch.be/wp-content/uploads/2026/01/cropped-cropped-Smals_Research-32x32.png</url>
	<title>Programming &#8211; Smals Research</title>
	<link>https://www.smalsresearch.be</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Les assistants de codage open source à l&#8217;ouvrage </title>
		<link>https://www.smalsresearch.be/opensource-coding-assistants-fr/</link>
		
		<dc:creator><![CDATA[Joachim Ganseman]]></dc:creator>
		<pubDate>Thu, 28 Mar 2024 09:37:20 +0000</pubDate>
				<category><![CDATA[[FR]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[Artificial intelligence]]></category>
		<category><![CDATA[chatbot]]></category>
		<category><![CDATA[computational creativity]]></category>
		<category><![CDATA[egov]]></category>
		<category><![CDATA[Natural Language Processing]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Programming]]></category>
		<guid isPermaLink="false">/?p=20319</guid>

					<description><![CDATA[Un assistant de codage respectueux de la vie privée pour un IDE avec des outils open source - comment faire ? ]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>Cet article est aussi disponible <a href="/opensource-coding-assistants/">en néerlandais</a>.</em></p>



<p class="wp-block-paragraph">Comme outil de génération de code pour les développeurs de logiciels, <a href="https://github.com/features/copilot" target="_blank" rel="noreferrer noopener">Github Copilot</a> domine le marché aujourd&#8217;hui. Cette situation devrait perdurer, d&#8217;autant plus que l&#8217;outil s&#8217;est enrichi d&#8217;une fonctionnalité de messagerie instantanée à la ChatGPT. Propriété de Microsoft, Github bénéficie d&#8217;une ligne directe avec OpenAI, et est donc le premier à profiter du rôle de pionnier que cette société continue de jouer dans le développement de <a href="https://fr.wikipedia.org/wiki/Grand_mod%C3%A8le_de_langage">grands modèles de langage</a> (abrégé <a href="https://en.wikipedia.org/wiki/Large_language_model" target="_blank" rel="noreferrer noopener">LLM en anglais)</a>&nbsp;</p>



<p class="wp-block-paragraph">On en oublierait presque qu&#8217;il existe d&#8217;autres options. La première alternative à grande échelle construite sur une base open source, incluant des <a href="https://huggingface.co/datasets/bigcode/the-stack">jeux de données d&#8217;apprentissage ouverts</a>, est <a href="https://huggingface.co/blog/starcoder" target="_blank" rel="noreferrer noopener">StarCoder</a>, dont une <a href="https://github.com/bigcode-project/starcoder2" target="_blank" rel="noreferrer noopener">version 2</a> a récemment vu le jour. Elle est développée dans le cadre de l&#8217;<a href="https://www.bigcode-project.org/" target="_blank" rel="noreferrer noopener">initiative BigCode</a> de ServiceNow et de HuggingFace. L&#8217;<a href="https://arxiv.org/abs/2305.06161" target="_blank" rel="noreferrer noopener">article qui l&#8217;accompagne</a> offre un aperçu fascinant de la construction d&#8217;un modèle de langage pour la génération de code. Peu après StarCoder, <a href="https://arxiv.org/abs/2306.08568" target="_blank" rel="noreferrer noopener">WizardCoder</a>, <a href="https://arxiv.org/abs/2308.12950" target="_blank" rel="noreferrer noopener">CodeLLama</a>, <a href="https://github.com/deepseek-ai/DeepSeek-Coder" target="_blank" rel="noreferrer noopener">DeepSeekCoder</a> et quelques autres sont apparus sur la scène, pas tous fondés sur un ensemble de données ouvertes, mais librement accessibles et réutilisables via <a href="https://huggingface.co/" target="_blank" rel="noreferrer noopener">HuggingFace</a>. &nbsp;</p>



<p class="wp-block-paragraph">Aujourd’hui, il existe aussi suffisamment d&#8217;outils pour faciliter l&#8217;exécution de ces modèles sur votre propre machine. Vous pouvez donc avoir votre propre assistant de codage personnel, hébergé par vous-même et entièrement privé. Pour cela, il vous faut un matériel suffisamment puissant, un LLM axé sur les tâches de <em>code completion</em> ou sur les conversations concernant le code, et une extension pour l&#8217;environnement de développement (IDE). Le LLM et l’extension de l’IDE communiquent entre eux via une API, qui peut être compatible ou non avec celle d&#8217;OpenAI, ce qui permet de passer facilement d&#8217;un modèle commercial (OpenAI) à un modèle open source le cas échéant.&nbsp;</p>



<h2 class="wp-block-heading"><strong>Extensions pour IDE</strong></h2>



<p class="wp-block-paragraph">L&#8217;installation d&#8217;une extension est simple en soi. Github Copilot existe depuis longtemps en tant qu&#8217;<a href="https://code.visualstudio.com/docs/editor/github-copilot" target="_blank" rel="noreferrer noopener">extension pour VSCode</a> et aujourd&#8217;hui également pour <a href="https://plugins.jetbrains.com/plugin/17718-github-copilot" target="_blank" rel="noreferrer noopener">IntelliJ IDEA</a> &#8211; même si au moment de la rédaction de cet article, la version d’IntelliJ contient encore un peu moins de fonctionnalités.&nbsp;&nbsp;</p>



<p class="wp-block-paragraph">Parmi les alternatives open source, <a href="https://continue.dev/" target="_blank" rel="noreferrer noopener">Continue</a> figure probablement parmi les meilleures à ce jour. Il en existe d&#8217;autres &#8211; Huggingface a développé <a href="https://github.com/huggingface/llm-vscode?tab=readme-ov-file" target="_blank" rel="noreferrer noopener">llm-vscode</a> par exemple &#8211; et il ne fait aucun doute que d&#8217;autres viendront s&#8217;ajouter. Tout comme Github Copilot, Continue existe également sous forme d&#8217;<a href="https://marketplace.visualstudio.com/items?itemName=Continue.continue" target="_blank" rel="noreferrer noopener">extension pour VSCode</a> ou <a href="https://plugins.jetbrains.com/plugin/22707-continue" target="_blank" rel="noreferrer noopener">IntelliJ</a>. L&#8217;outil peut utiliser à la fois des générateurs commerciaux basés sur le cloud (notamment GPT-4) et des solutions open source auto-hébergées, qui ne doivent pas nécessairement émuler l&#8217;API d&#8217;OpenAI et autorisent de nombreuses personnalisations.&nbsp;</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/2024-03-11_14h59_32.png"><img fetchpriority="high" decoding="async" width="1024" height="410" src="/wp-content/uploads/2024/03/2024-03-11_14h59_32-1024x410.png" alt="" class="wp-image-20216" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_14h59_32-1024x410.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_14h59_32-300x120.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_14h59_32-768x308.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_14h59_32-1536x615.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_14h59_32.png 1858w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Capture d’écran de l&#8217;extension Continue dans Visual Studio Code&nbsp;</figcaption></figure>



<p class="wp-block-paragraph">Il demeure important de prendre le temps de se familiariser avec l’extension. La <a href="https://continue.dev/docs/intro" target="_blank" rel="noreferrer noopener">documentation de Continue</a> constitue une bonne base à cet effet. Pour chaque <a href="https://continue.dev/docs/model-setup/select-provider" target="_blank" rel="noreferrer noopener">serveur</a> et chaque <a href="https://continue.dev/docs/model-setup/select-model" target="_blank" rel="noreferrer noopener">LLM</a>, il se peut que vous deviez définir différentes options de configuration et que vous souhaitiez apporter des modifications à <a href="https://continue.dev/docs/model-setup/configuration" target="_blank" rel="noreferrer noopener">l&#8217;invite de commande</a> sous-jacente. Il convient également de savoir comment activer et désactiver l&#8217;extension dans l&#8217;IDE et de connaître les raccourcis et <a href="https://continue.dev/docs/customization/slash-commands" target="_blank" rel="noreferrer noopener">commandes</a> disponibles. <a href="https://www.youtube.com/results?search_query=continue+ai" target="_blank" rel="noreferrer noopener">YouTube</a> peut être un bon point de départ pour trouver des tutoriels et des exemples d&#8217;autres utilisateurs.&nbsp;</p>



<h2 class="wp-block-heading"><strong>Un LLM sur votre ordinateur portable</strong>&nbsp;</h2>



<p class="wp-block-paragraph">Notamment sous l&#8217;impulsion du projet open source <a href="https://github.com/ggerganov/llama.cpp" target="_blank" rel="noreferrer noopener">llama.cpp</a>, des efforts considérables ont été faits au cours de l&#8217;année écoulée pour faire en sorte que les LLM puissent également être déployés sur du matériel informatique grand public. Un processeur graphique (GPU) au coût prohibitif n&#8217;est plus nécessaire, même s&#8217;il offre un gain de temps considérable. Globalement, <a href="https://github.com/ggerganov/llama.cpp" target="_blank" rel="noreferrer noopener">llama.cpp</a> permet de reconditionner un modèle au format GGUF (GPT-Generated Unified Format). Il s&#8217;agit ici d&#8217;appliquer un maximum d&#8217;optimisations :&nbsp;</p>



<p class="wp-block-paragraph"></p>



<ul class="wp-block-list">
<li>l&#8217;utilisation de jeux d&#8217;instructions du processeur (<s> </s>CPU) efficaces tels que&nbsp; <a href="https://en.wikipedia.org/wiki/AVX-512" target="_blank" rel="noreferrer noopener">AVX-512</a> &#8211; il va sans dire que le matériel sur lequel le modèle fonctionnera plus tard doit également prendre en charge ces jeux d&#8217;instructions ;&nbsp;</li>



<li>l&#8217;utilisation de bibliothèques hautement optimisées pour les calculs sous-jacents, telles que <a href="https://github.com/OpenMathLib/OpenBLAS" target="_blank" rel="noreferrer noopener">openBLAS</a> ou <a href="https://developer.apple.com/documentation/accelerate" target="_blank" rel="noreferrer noopener">Accelerate</a> et <a href="https://developer.apple.com/metal/" target="_blank" rel="noreferrer noopener">Metal</a> d&#8217;Apple ;&nbsp;</li>



<li>la <em>quantification </em>du modèle, par la réduction de la <a href="https://en.wikipedia.org/wiki/Precision_(computer_science)" target="_blank" rel="noreferrer noopener">précision</a> des poids dans les couches des réseaux neuronaux. Les nombres (à virgule flottante) de 16 ou 32 bits du modèle original sont ici convertis en nombres entiers de 8 bits, voire de 6 bits ou même de 4 bits. Cela permet d&#8217;économiser de la mémoire et d&#8217;accélérer les calculs, au prix d&#8217;une perte de qualité relativement faible.&nbsp;</li>
</ul>



<p class="wp-block-paragraph">L&#8217;hébergement local d&#8217;un LLM peut être réalisé à l&#8217;aide d&#8217;outils tels que <a href="https://lmstudio.ai/" target="_blank" rel="noreferrer noopener">LM Studio</a>. Ceux-ci vous permettent de télécharger différents modèles au format GGUF. Un onglet séparé dans l&#8217;application vous permet de démarrer un serveur d&#8217;inférence utilisant le protocole HTTP autour d&#8217;un modèle téléchargé et activé, qui simule l&#8217;API d&#8217;OpenAI. Une fois ce serveur mis en place, par exemple sur le port 1234, le modèle est accessible via un appel à <code>http://localhost:1234/v1/chat/completions</code> . </p>



<p class="wp-block-paragraph">Cette configuration dans l&#8217;extension Continue se fait par l&#8217;ajout du LLM au fichier <code>.continue/config.json</code>, suivant <a href="https://docs.continue.dev/customize/overview" target="_blank" rel="noreferrer noopener">ces instructions</a> et selon les directives pour <a href="https://docs.continue.dev/customize/model-providers/more/lmstudio" target="_blank" rel="noreferrer noopener">LM Studio en tant que fournisseur de modèle</a>. Vous pouvez adapter le titre et le modèle comme bon vous semble, et il vous suffit d&#8217;ajouter la ligne <code>"apiBase":"http://127.0.0.1:1234/v1"</code> Dans l&#8217;extension, vous verrez alors apparaître une nouvelle option, et vous pourrez commencer à l&#8217;utiliser. </p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/2024-03-11_15h06_39.png"><img decoding="async" width="1024" height="550" src="/wp-content/uploads/2024/03/2024-03-11_15h06_39-1024x550.png" alt="" class="wp-image-20217" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_15h06_39-1024x550.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_15h06_39-300x161.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_15h06_39-768x412.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_15h06_39-1536x825.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_15h06_39.png 1918w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">LM Studio, avec le modèle CodeNinja chargé, répond à une requête via le serveur intégré actif sur le port 1234.&nbsp;</figcaption></figure>



<h2 class="wp-block-heading"><strong>Interlude&nbsp;: à propos du matériel</strong></h2>



<p class="wp-block-paragraph">La gestion des GPU n&#8217;est déjà pas une partie de plaisir pour un développeur sur une seule machine. Les problèmes d&#8217;incompatibilité entre les différentes versions de toutes sortes de bibliothèques logicielles et de pilotes de GPU peuvent prendre des jours à résoudre. L&#8217;<a href="https://www.nvidia.com/en-us/data-center/products/" target="_blank" rel="noreferrer noopener">offre du marché des GPUs pour data centers</a>, dominée par le monopole de nVIDIA, reste d&#8217;un coût prohibitif. À cela s&#8217;ajoute le coût de l&#8217;acquisition des connaissances très spécialisées nécessaires au fonctionnement de ces systèmes. Le matériel que vous choisirez sera probablement complètement obsolète dans quelques années. Un nouveau matériel, conçu spécifiquement pour accélérer le type de calculs des modèles d&#8217;IA, fait l&#8217;objet d&#8217;un travail acharné. Google a déjà présenté le <a href="https://en.wikipedia.org/wiki/Tensor_Processing_Unit" target="_blank" rel="noreferrer noopener">TPU</a>, mais d&#8217;autres fabricants se concentrent aujourd&#8217;hui pleinement sur les <a href="https://www.techradar.com/computing/cpu/what-is-an-npu" target="_blank" rel="noreferrer noopener">NPU (Neural Processing Units)</a>, et certains osent entrer en <a href="https://www.cerebras.net/" target="_blank" rel="noreferrer noopener">concurrence directe</a> avec nVIDIA.&nbsp;&nbsp;</p>



<p class="wp-block-paragraph">Si vous n&#8217;avez pas le temps de vous occuper des pilotes de GPU et que vous n&#8217;avez pas l&#8217;ambition d&#8217;entraîner les modèles vous-même, la possibilité de les utiliser sur un CPU ordinaire est plus que bienvenue. Bien sûr, vous êtes alors limité aux LLM ou aux modèles d&#8217;IA dont la taille le permet. Les LLM &#8220;domestiques&#8221; typiques ont 3, 7 ou 13 milliards de paramètres ; les modèles plus grands sont <a href="https://github.com/ggerganov/llama.cpp#memorydisk-requirements" target="_blank" rel="noreferrer noopener">agressivement quantifiés</a> pour économiser de l&#8217;espace sur le disque et la mémoire.&nbsp; Ils ne seront pas en mesure d&#8217;égaler la qualité de GPT-4 aujourd&#8217;hui, mais heureusement, des classements existent pour aider à opérer un choix &#8211; pour <a href="https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard" target="_blank" rel="noreferrer noopener">les LLM ouverts en général</a>, spécifiquement avec <a href="https://huggingface.co/spaces/optimum/llm-perf-leaderboard" target="_blank" rel="noreferrer noopener">des benchmarks de vitesse (débit)</a>, ou pour <a href="https://huggingface.co/spaces/bigcode/bigcode-models-leaderboard" target="_blank" rel="noreferrer noopener">les LLM générateurs de code</a> en particulier.&nbsp;</p>



<p class="wp-block-paragraph">Plus les LLM sont grands, plus la qualité du résultat est élevée (en général), mais plus la mémoire et la puissance de traitement requises sont importantes. Un LLM doit de préférence pouvoir être entièrement chargé dans la mémoire, de sorte que 16 GB de RAM n&#8217;est pas un luxe &#8211; plus c&#8217;est encore mieux, surtout si vous voulez faire fonctionner un IDE sur la même machine. Pour fournir une réponse, le modèle complet doit souvent être exécuté plusieurs fois. Par conséquent, le goulot d&#8217;étranglement est souvent la bande passante entre le CPU et la RAM. Les CPU dotés d&#8217;une grande mémoire cache interne semblent avoir une longueur d&#8217;avance (voir également les benchmarks spécifiques à l&#8217;IA [<a href="https://www.anandtech.com/show/21084/intel-core-i9-14900k-core-i7-14700k-and-core-i5-14600k-review-raptor-lake-refreshed/10" target="_blank" rel="noreferrer noopener">1</a>,<a href="https://www.anandtech.com/show/21242/amd-ryzen-7-8700g-and-ryzen-5-8600g-review/8" target="_blank" rel="noreferrer noopener">2</a>] d&#8217;Anandtech). Lors du choix du reste du matériel, la bande passante de la mémoire devrait certainement entrer en ligne de compte. Même ceux choisissant un GPU pourraient préférer considérer cette bande passante plutôt que le nombre de cœurs du GPU. Enfin, dans les environnements virtualisés (VM, VPS), il est important que le CPU virtuel prenne en charge les mêmes jeux d&#8217;instructions avancés, tels que <a href="https://en.wikipedia.org/wiki/AVX-512#CPUs_with_AVX-512" target="_blank" rel="noreferrer noopener">AVX-512</a>.&nbsp;</p>



<h2 class="wp-block-heading"><strong>Un LLM sur votre serveur</strong>&nbsp;</h2>



<p class="wp-block-paragraph">Si vous disposez d&#8217;une machine plus puissante, il peut être intéressant d&#8217;y exécuter le LLM. <a href="https://ollama.com/" target="_blank" rel="noreferrer noopener">ollama</a> est probablement l&#8217;outil le plus populaire pour héberger des modèles sur Mac ou Linux sans trop de difficultés, et depuis peu également sur Windows. <a href="https://localai.io/" target="_blank" rel="noreferrer noopener">LocalAI</a> est toutefois une option tout aussi intéressante dans la liste des <a href="https://continue.dev/docs/model-setup/select-provider" target="_blank" rel="noreferrer noopener">fournisseurs de LLM pour Continue</a>, car il propose des conteneurs Docker, avec ou sans support GPU. Sur une machine Linux équipée de Docker, un <a href="https://localai.io/basics/getting_started/" target="_blank" rel="noreferrer noopener">one-liner</a> dans le terminal suffit pour télécharger le modèle CodeLlama open source et l&#8217;héberger sur le port 1234 :&nbsp;</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="docker run -ti -p 1234:8080 localai/localai:v2.7.0-ffmpeg-core codellama-7b-gguf " style="color:#000000;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #795E26">docker</span><span style="color: #000000"> </span><span style="color: #A31515">run</span><span style="color: #000000"> </span><span style="color: #0000FF">-ti</span><span style="color: #000000"> </span><span style="color: #0000FF">-p</span><span style="color: #000000"> </span><span style="color: #098658">1234</span><span style="color: #A31515">:8080</span><span style="color: #000000"> </span><span style="color: #A31515">localai/localai:v2.7.0-ffmpeg-core</span><span style="color: #000000"> </span><span style="color: #A31515">codellama-7b-gguf</span><span style="color: #000000"> </span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Cependant, son démarrage prend un certain temps, car le modèle est téléchargé dans le conteneur. Il est plus intéressant de stocker soi-même une série de modèles dans un répertoire local et d&#8217;y associer une API à l&#8217;aide d&#8217;un conteneur LocalAI. Des <a href="https://localai.io/docs/getting-started/models/" target="_blank" rel="noreferrer noopener">instructions</a> relativement simples sont disponibles pour cela aussi. Nous pouvons par exemple les appliquer au LLM <a href="https://huggingface.co/TheBloke/deepseek-coder-6.7B-instruct-GGUF" target="_blank" rel="noreferrer noopener">LLM DeepSeek de 6,7 milliards de paramètres, quantifiés à 4 bits</a>. Il peut être téléchargé directement depuis Huggingface dans le répertoire local ./models-gguf à l&#8217;aide d&#8217;une commande wget du type : </p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="wget https://huggingface.co/TheBloke/deepseek-coder-6.7B-instruct-GGUF/resolve/main/deepseek-coder-6.7b-instruct.Q4_K_M.gguf -O ./models-gguf/deepseek-6.7b-instruct-Q4" style="color:#000000;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #795E26">wget</span><span style="color: #000000"> </span><span style="color: #A31515">https://huggingface.co/TheBloke/deepseek-coder-6.7B-instruct-GGUF/resolve/main/deepseek-coder-6.7b-instruct.Q4_K_M.gguf</span><span style="color: #000000"> </span><span style="color: #0000FF">-O</span><span style="color: #000000"> </span><span style="color: #A31515">./models-gguf/deepseek-6.7b-instruct-Q4</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Démarrer une API autour des modèles de ce répertoire sur le port 8001 (vous pouvez aussi placer plusieurs modèles dans le même répertoire et les héberger simultanément), peut alors se faire avec la commande suivante . Ajoutez éventuellement <em><code>-d</code></em> pour qu&#8217;elle s&#8217;exécute en arrière-plan, et n&#8217;hésitez pas à expérimenter les paramètres <em><code>context-size</code></em> et <em><code>threads</code> </em>en fonction de la puissance de votre serveur&nbsp;: </p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="docker run -p 8001:8080 -v $PWD/models-gguf:/models -ti --rm quay.io/go-skynet/local-ai:v2.7.0-ffmpeg-core --models-path /models --context-size 1600 --threads 16" style="color:#000000;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #795E26">docker</span><span style="color: #000000"> </span><span style="color: #A31515">run</span><span style="color: #000000"> </span><span style="color: #0000FF">-p</span><span style="color: #000000"> </span><span style="color: #098658">8001</span><span style="color: #A31515">:8080</span><span style="color: #000000"> </span><span style="color: #0000FF">-v</span><span style="color: #000000"> </span><span style="color: #001080">$PWD</span><span style="color: #A31515">/models-gguf:/models</span><span style="color: #000000"> </span><span style="color: #0000FF">-ti</span><span style="color: #000000"> </span><span style="color: #0000FF">--rm</span><span style="color: #000000"> </span><span style="color: #A31515">quay.io/go-skynet/local-ai:v2.7.0-ffmpeg-core</span><span style="color: #000000"> </span><span style="color: #0000FF">--models-path</span><span style="color: #000000"> </span><span style="color: #A31515">/models</span><span style="color: #000000"> </span><span style="color: #0000FF">--context-size</span><span style="color: #000000"> </span><span style="color: #098658">1600</span><span style="color: #000000"> </span><span style="color: #0000FF">--threads</span><span style="color: #000000"> </span><span style="color: #098658">16</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Exemple</h2>



<p class="wp-block-paragraph">Nous pouvons maintenant comparer différents LLM pour le code. Nous nous en tiendrons ici à l&#8217;anecdote et prendrons l&#8217;écriture d&#8217;un script shell <em>bash</em> comme exemple simple. Nous partons du problème suivant&nbsp;: une routine de sauvegarde a effectué des sauvegardes nocturnes d&#8217;un système pendant des années. Pour libérer de l&#8217;espace disque, nous voulons supprimer toutes les sauvegardes qui ne diffèrent pas des précédentes. Nous lançons la commande suivante, en décrivant la tâche le plus précisément possible afin d’obtenir les meilleurs résultats&nbsp;: <em>&#8220;Write a bash script that, given a directory, iterates over all its files in order of date of creation. For each file, if the filesize is equal to the filesize of the previous file, the file has to be deleted.&#8221;</em>&nbsp;</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Le fichier <code>.continue/config.json</code> de notre extension Continue contient la liste suivante de modèles : un sur le propre ordinateur portable dans LM Studio chargé sur le port 1234, et deux sur un serveur séparé, mais sur le même réseau local, hébergé par LocalAI sur le port 8001.&nbsp;</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="    {
      &quot;title&quot;: &quot;myLaptop-LMStudio&quot;,
      &quot;model&quot;: &quot;whatever is loaded in LMstudio&quot;,
      &quot;apiBase&quot;: &quot;http://127.0.0.1:1234/v1&quot;,
      &quot;completionOptions&quot;: {},
      &quot;provider&quot;: &quot;lmstudio&quot;
    },       
    {
      &quot;title&quot;: &quot;localAI-mistral&quot;,
      &quot;model&quot;: &quot;mistral-7b-code16kqlora-Q4&quot;,
      &quot;apiBase&quot;: &quot;https://192.168.0.100:8001/v1&quot;,
      &quot;apiKey&quot;: &quot;&quot;,      
      &quot;completionOptions&quot;: {},
      &quot;provider&quot;: &quot;openai&quot;
    },
    {
      &quot;title&quot;: &quot;localAI-deepseek&quot;,
      &quot;model&quot;: &quot;deepseek-6.7b-instruct-Q4&quot;,
      &quot;apiBase&quot;: &quot;https://192.168.0.100:8001/v1&quot;,
      &quot;apiKey&quot;: &quot;&quot;,
      &quot;completionOptions&quot;: {},
      &quot;provider&quot;: &quot;openai&quot;
    }," style="color:#24292e;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki github-light" style="background-color: #fff" tabindex="0"><code><span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;title&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;myLaptop-LMStudio&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;model&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;whatever is loaded in LMstudio&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;apiBase&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;http://127.0.0.1:1234/v1&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;completionOptions&quot;</span><span style="color: #24292E">: {},</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;provider&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;lmstudio&quot;</span></span>
<span class="line"><span style="color: #24292E">    },       </span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;title&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;localAI-mistral&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;model&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;mistral-7b-code16kqlora-Q4&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;apiBase&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;https://192.168.0.100:8001/v1&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;apiKey&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;&quot;</span><span style="color: #24292E">,      </span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;completionOptions&quot;</span><span style="color: #24292E">: {},</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;provider&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;openai&quot;</span></span>
<span class="line"><span style="color: #24292E">    },</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;title&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;localAI-deepseek&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;model&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;deepseek-6.7b-instruct-Q4&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;apiBase&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;https://192.168.0.100:8001/v1&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;apiKey&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;completionOptions&quot;</span><span style="color: #24292E">: {},</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;provider&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;openai&quot;</span></span>
<span class="line"><span style="color: #24292E">    },</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Comme référence, nous prenons <a href="https://chat.openai.com/" target="_blank" rel="noreferrer noopener">ChatGPT</a>, qui propose la solution (correcte) suivante. &nbsp;<br>En outre, elle est également suivie d&#8217;une explication détaillée de la signification des différentes parties (non présentée ici) :&nbsp;</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="#!/bin/bash

# Directory containing the files
DIR=&quot;/path/to/your/directory&quot;

# Variable to hold the size of the previous file. Initialized to 0.
prev_size=0

# List all files in the directory, sorted by creation date
# Note: '%T@' sorts by creation time, '%p' prints the file's name
# 'sort -n' ensures the list is sorted numerically
# Note that creation time sorting may depend on filesystem and OS support
files=$(find &quot;$DIR&quot; -type f -printf &quot;%T@ %p\n&quot; | sort -n | cut -d ' ' -f 2-)

# Iterate over the sorted list of files
for file in $files; do
  # Get current file size
  current_size=$(stat -c %s &quot;$file&quot;)
  
  # Check if current file size is equal to the previous file's size
  if [ &quot;$current_size&quot; -eq &quot;$prev_size&quot; ]; then
    # Sizes are equal, delete the current file
    echo &quot;Deleting file: $file&quot;
    rm &quot;$file&quot;
  fi
  
  # Update previous size to current file's size
  prev_size=$current_size
done" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">#!/bin/bash</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Directory containing the files</span></span>
<span class="line"><span style="color: #9CDCFE">DIR</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;/path/to/your/directory&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Variable to hold the size of the previous file. Initialized to 0.</span></span>
<span class="line"><span style="color: #9CDCFE">prev_size</span><span style="color: #D4D4D4">=</span><span style="color: #B5CEA8">0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># List all files in the directory, sorted by creation date</span></span>
<span class="line"><span style="color: #6A9955"># Note: &#39;%T@&#39; sorts by creation time, &#39;%p&#39; prints the file&#39;s name</span></span>
<span class="line"><span style="color: #6A9955"># &#39;sort -n&#39; ensures the list is sorted numerically</span></span>
<span class="line"><span style="color: #6A9955"># Note that creation time sorting may depend on filesystem and OS support</span></span>
<span class="line"><span style="color: #9CDCFE">files</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">find</span><span style="color: #CE9178"> &quot;</span><span style="color: #9CDCFE">$DIR</span><span style="color: #CE9178">&quot; </span><span style="color: #569CD6">-type</span><span style="color: #CE9178"> f </span><span style="color: #569CD6">-printf</span><span style="color: #CE9178"> &quot;%T@ %p\n&quot; </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">sort</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-n</span><span style="color: #CE9178"> </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">cut</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-d</span><span style="color: #CE9178"> &#39; &#39; </span><span style="color: #569CD6">-f</span><span style="color: #CE9178"> </span><span style="color: #B5CEA8">2</span><span style="color: #CE9178">-)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Iterate over the sorted list of files</span></span>
<span class="line"><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">file</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$files</span><span style="color: #D4D4D4">; </span><span style="color: #C586C0">do</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955"># Get current file size</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">current_size</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">stat</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-c</span><span style="color: #CE9178"> %s &quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;)</span></span>
<span class="line"><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955"># Check if current file size is equal to the previous file&#39;s size</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [ </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$current_size</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> -eq </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$prev_size</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> ]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># Sizes are equal, delete the current file</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Deleting file: </span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">rm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955"># Update previous size to current file&#39;s size</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">prev_size</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">$current_size</span></span>
<span class="line"><span style="color: #C586C0">done</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Dans LMStudio, nous chargeons le modèle &#8220;<a href="https://huggingface.co/TheBloke/CodeNinja-1.0-OpenChat-7B-GGUF" target="_blank" rel="noreferrer noopener">CodeNinja 1.0 openchat 7B Q4_K_M</a>&#8220;. Il faut plus d&#8217;une minute pour générer la réponse à la même question&nbsp;: 20 secondes d&#8217;attente pour l&#8217;apparition de la première lettre de la réponse, puis environ 2 secondes par ligne (bien sûr, notre ordinateur portable n&#8217;est pas très puissant&nbsp;: un CPU Core i7-10610U avec 32GB de RAM). Le résultat se présente comme suit :&nbsp;</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="#!/bin/bash

for f in $(ls -t -l --time-style=full /path/to/directory)
do
  if [[ $f == &quot;total&quot;* ]]; then
        continue;
    fi
    filename=$(basename &quot;${f% *}&quot;)

    # Checks whether the file is already deleted. If not, compares it with the previous file:
    prev_file=&quot;&quot;
    while IFS= read -r line; do
        if [[ $line == $filename ]]; then
            prev_file=$line
            break;
        fi
    done &lt;&lt;&lt;&quot;$(ls -l /path/to/directory | tail -n 2)&quot;

    if [[ -z $prev_file || &quot;$f&quot; = &quot;${prev_file}&quot; ]]; then
        # If the file is deleted, nothing to do. If not, deletes it:
        if [[ -z $prev_file ]] || [[ &quot;$(stat -c %s ${filename})&quot; == &quot;$(stat -c %s ${prev_file})&quot; ]]; then
            rm /path/to/directory/$filename
        fi
    fi
done" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">#!/bin/bash</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">f</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">ls</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-t</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-l</span><span style="color: #CE9178"> </span><span style="color: #569CD6">--time-style=full</span><span style="color: #CE9178"> /path/to/directory)</span></span>
<span class="line"><span style="color: #C586C0">do</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [[ </span><span style="color: #9CDCFE">$f</span><span style="color: #D4D4D4"> == </span><span style="color: #CE9178">&quot;total&quot;</span><span style="color: #D4D4D4">* ]]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">continue</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">filename</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">basename</span><span style="color: #CE9178"> &quot;${</span><span style="color: #9CDCFE">f</span><span style="color: #D4D4D4">%</span><span style="color: #CE9178"> </span><span style="color: #D4D4D4">*</span><span style="color: #CE9178">}&quot;)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># Checks whether the file is already deleted. If not, compares it with the previous file:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">prev_file</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">while</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IFS</span><span style="color: #D4D4D4">= </span><span style="color: #DCDCAA">read</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-r</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">line</span><span style="color: #D4D4D4">; </span><span style="color: #C586C0">do</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [[ </span><span style="color: #9CDCFE">$line</span><span style="color: #D4D4D4"> == </span><span style="color: #9CDCFE">$filename</span><span style="color: #D4D4D4"> ]]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">prev_file</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">$line</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">break</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">done</span><span style="color: #D4D4D4"> &lt;&lt;&lt;</span><span style="color: #CE9178">&quot;$(</span><span style="color: #DCDCAA">ls</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-l</span><span style="color: #CE9178"> /path/to/directory </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">tail</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-n</span><span style="color: #CE9178"> </span><span style="color: #B5CEA8">2</span><span style="color: #CE9178">)&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [[ -z </span><span style="color: #9CDCFE">$prev_file</span><span style="color: #D4D4D4"> || </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$f</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;${</span><span style="color: #9CDCFE">prev_file</span><span style="color: #CE9178">}&quot;</span><span style="color: #D4D4D4"> ]]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955"># If the file is deleted, nothing to do. If not, deletes it:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [[ -z </span><span style="color: #9CDCFE">$prev_file</span><span style="color: #D4D4D4"> ]] || [[ </span><span style="color: #CE9178">&quot;$(</span><span style="color: #DCDCAA">stat</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-c</span><span style="color: #CE9178"> %s ${</span><span style="color: #9CDCFE">filename</span><span style="color: #CE9178">})&quot;</span><span style="color: #D4D4D4"> == </span><span style="color: #CE9178">&quot;$(</span><span style="color: #DCDCAA">stat</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-c</span><span style="color: #CE9178"> %s ${</span><span style="color: #9CDCFE">prev_file</span><span style="color: #CE9178">})&quot;</span><span style="color: #D4D4D4"> ]]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">rm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">/path/to/directory/</span><span style="color: #9CDCFE">$filename</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #C586C0">done</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Nous chargeons le <a href="https://huggingface.co/TheBloke/deepseek-coder-6.7B-instruct-GGUF" target="_blank" rel="noreferrer noopener">modèle DeepSeek de 6,7 milliards de paramètres</a> dans LocalAI sur une VM Debian dans Proxmox. La VM se voit allouer beaucoup de mémoire vive et 12 cœurs du micro-processeur AMD Threadripper 3960X sous-jacent (24 cœurs au total mais pas de support AVX-512). Nous créons ainsi à un rythme d&#8217;environ 3 lignes par seconde le résultat suivant :&nbsp;</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="#!/bin/bash

# Check if directory is provided
if [ $# -ne 1 ]; then
  echo &quot;Usage: $0 directory&quot;
    exit 1
fi

# Check if directory exists
if [&nbsp;! -d &quot;$1&quot; ]; then
    echo &quot;Directory $1 does not exist&quot;
    exit 1
fi

# Change to the directory
cd &quot;$1&quot;

# Get the list of files in order of creation date
files=$(ls -t)

# Initialize previous_size to 0
previous_size=0

# Iterate over the files
for file in $files; do
    # Get the size of the file
    size=$(stat -c%s &quot;$file&quot;)

    # If the size is equal to the previous size, delete the file
    if [ $size -eq $previous_size ]; then
        rm &quot;$file&quot;
        echo &quot;Deleted $file&quot;
    fi

    # Update previous_size
    previous_size=$size
done" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">#!/bin/bash</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Check if directory is provided</span></span>
<span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [ </span><span style="color: #569CD6">$#</span><span style="color: #D4D4D4"> -ne </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4"> ]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Usage: </span><span style="color: #9CDCFE">$0</span><span style="color: #CE9178"> directory&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">exit</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1</span></span>
<span class="line"><span style="color: #C586C0">fi</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Check if directory exists</span></span>
<span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [&nbsp;! -d </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$1</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> ]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Directory </span><span style="color: #9CDCFE">$1</span><span style="color: #CE9178"> does not exist&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">exit</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1</span></span>
<span class="line"><span style="color: #C586C0">fi</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Change to the directory</span></span>
<span class="line"><span style="color: #DCDCAA">cd</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$1</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Get the list of files in order of creation date</span></span>
<span class="line"><span style="color: #9CDCFE">files</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">ls</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-t</span><span style="color: #CE9178">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Initialize previous_size to 0</span></span>
<span class="line"><span style="color: #9CDCFE">previous_size</span><span style="color: #D4D4D4">=</span><span style="color: #B5CEA8">0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Iterate over the files</span></span>
<span class="line"><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">file</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$files</span><span style="color: #D4D4D4">; </span><span style="color: #C586C0">do</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># Get the size of the file</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">size</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">stat</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-c%s</span><span style="color: #CE9178"> &quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># If the size is equal to the previous size, delete the file</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [ </span><span style="color: #9CDCFE">$size</span><span style="color: #D4D4D4"> -eq </span><span style="color: #9CDCFE">$previous_size</span><span style="color: #D4D4D4"> ]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">rm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Deleted </span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">fi</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># Update previous_size</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">previous_size</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">$size</span></span>
<span class="line"><span style="color: #C586C0">done</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Enfin, sur la même VM, nous pouvons également essayer Mistral, pour lequel nous choisissons au hasard la version <a href="https://huggingface.co/TheBloke/Mistral-7B-Code-16K-qlora-GGUF" target="_blank" rel="noreferrer noopener">mistral-7B-code-16K-qlora</a> qui a été légèrement adaptée par <em>fine-tuning</em> pour le code par un internaute. Il s&#8217;avère que sa réponse est rapide, générant le résultat compact suivant en quelque 2 secondes (malheureusement sans documentation, et en proposant la commande complexe <em>awk</em> ) :&nbsp;</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="for file in $(find directory -type f -exec du -sh {} + | sort -h | awk '{print NR &quot;:\t&quot; $1}'); do
    size=$(du -sh &quot;$file&quot; | awk '{print $1}')
    if [[ $size == $previous_size ]]; then
      rm &quot;$file&quot;
    fi
    previous_size=$size
done" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">file</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">find</span><span style="color: #CE9178"> directory </span><span style="color: #569CD6">-type</span><span style="color: #CE9178"> f </span><span style="color: #569CD6">-exec</span><span style="color: #CE9178"> du </span><span style="color: #569CD6">-sh</span><span style="color: #CE9178"> {} + </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">sort</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-h</span><span style="color: #CE9178"> </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">awk</span><span style="color: #CE9178"> &#39;{print NR &quot;:\t&quot; $1}&#39;)</span><span style="color: #D4D4D4">; </span><span style="color: #C586C0">do</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">size</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">du</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-sh</span><span style="color: #CE9178"> &quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot; </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">awk</span><span style="color: #CE9178"> &#39;{print $1}&#39;)</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [[ </span><span style="color: #9CDCFE">$size</span><span style="color: #D4D4D4"> == </span><span style="color: #9CDCFE">$previous_size</span><span style="color: #D4D4D4"> ]]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #DCDCAA">rm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">previous_size</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">$size</span></span>
<span class="line"><span style="color: #C586C0">done</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Je laisse volontiers au lecteur le soin de procéder à une comparaison plus approfondie de ces résultats. Si nous devons tirer une dernière leçon de cette expérience, c&#8217;est que même si les modèles ont le même nombre de paramètres et sont entraînés dans le même but, il peut y avoir de très grandes différences de résultat et de style entre eux&nbsp;! &nbsp;</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">À la vitesse de l&#8217;éclair, toutes sortes de fonctions alimentées par l&#8217;IA trouvent leur place dans l&#8217;IDE. Les <a href="https://code.visualstudio.com/updates/v1_87" target="_blank" rel="noreferrer noopener">dernières notes de mises à jour de Visual Studio Code</a> mentionnent, par exemple, la prise en charge de la reconnaissance vocale dans plusieurs langues, en plus de plusieurs fonctionnalités de CoPilot. En tant que développeur, il est inévitable que vous soyez confronté à cette situation. Les développeurs qui travaillent avec des données sensibles ou du code protégé par des droits d&#8217;auteur doivent se méfier à juste titre de ces outils qui envoient le contenu de leur IDE à un service cloud tiers pour proposer des suggestions.&nbsp;&nbsp;</p>



<p class="wp-block-paragraph">Grâce notamment au projet <a href="https://github.com/ggerganov/llama.cpp" target="_blank" rel="noreferrer noopener">llama.cpp</a>, une voie alternative open source a récemment vu le jour, qui permet de mettre en place et d&#8217;exploiter soi-même une telle assistance au codage avec des LLM. Les modèles plus petits qui peuvent fonctionner sur du matériel grand public n&#8217;offrent actuellement pas la même qualité et la même vitesse que Github CoPilot ou ChatGPT. Toutefois, de nouvelles améliorations apparaîtront régulièrement au cours des prochaines années, de sorte que la voie à suivre semble prometteuse à tous points de vue.&nbsp;&nbsp;</p>



<p class="wp-block-paragraph">______________________</p>



<p class="wp-block-paragraph"><em><em>Ce post est une contribution individuelle de Joachim Ganseman, spécialisée en intelligence artificielle chez Smals Research. Cet article est écrit en son nom propre et n’impacte en rien le point de vue de Smals.</em></em></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Aan de slag met open source coding assistants</title>
		<link>https://www.smalsresearch.be/opensource-coding-assistants/</link>
		
		<dc:creator><![CDATA[Joachim Ganseman]]></dc:creator>
		<pubDate>Mon, 11 Mar 2024 15:42:44 +0000</pubDate>
				<category><![CDATA[[NL]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[Artificial intelligence]]></category>
		<category><![CDATA[chatbot]]></category>
		<category><![CDATA[computational creativity]]></category>
		<category><![CDATA[egov]]></category>
		<category><![CDATA[Natural Language Processing]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Programming]]></category>
		<guid isPermaLink="false">/?p=20178</guid>

					<description><![CDATA[Een privacyvriendelijke coding assistant voor een IDE met open source tools - hoe doe je dat?]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>Cet article est aussi disponible <a href="/opensource-coding-assistants-fr/">en français</a>.</em></p>



<p class="wp-block-paragraph">Als code-genererend hulpmiddel voor softwareontwikkelaars domineert <a href="https://github.com/features/copilot">Github Copilot</a> vandaag de markt. Dat zal wellicht nog wel even aanhouden, zeker nu de tool ook wordt uitgebreid met chatfunctionaliteit à la ChatGPT. Als eigendom van Microsoft, geniet Github van een directe lijn met OpenAI en zo kan het als eerste meegenieten van de voortrekkersrol die dat bedrijf blijft spelen inzake de ontwikkeling van <a href="https://en.wikipedia.org/wiki/Large_language_model">Large Language Models (LLMs)</a>.</p>



<p class="wp-block-paragraph">Men zou haast vergeten dat er ook andere mogelijkheden zijn. Het eerste grootschalige alternatief dat van de grond af open-source was opgebouwd, inclusief <a href="https://huggingface.co/datasets/bigcode/the-stack">open trainingsdata</a>, is <a href="https://huggingface.co/blog/starcoder">StarCoder</a>, waar sinds kort ook een <a href="https://github.com/bigcode-project/starcoder2">versie 2</a> van is uitgekomen. Het wordt ontwikkeld onder het <a href="https://www.bigcode-project.org/">BigCode initiatief</a> van ServiceNow en HuggingFace. De <a href="https://arxiv.org/abs/2305.06161">bijhorende paper </a>geeft een fascinerende inkijk in de opbouw van een taalmodel voor het genereren van code. Kort na StarCoder verschenen <a href="https://arxiv.org/abs/2306.08568">WizardCoder</a>, <a href="https://arxiv.org/abs/2308.12950">CodeLLama</a>, <a href="https://github.com/deepseek-ai/DeepSeek-Coder">DeepSeekCoder</a> en nog enkele anderen ten tonele &#8211; niet allemaal met een open dataset erachter, maar wel vrij toegankelijk en herbruikbaar via <a href="https://huggingface.co/">HuggingFace</a>. </p>



<p class="wp-block-paragraph">Ondertussen is er voldoende tooling beschikbaar om deze modellen gemakkelijker op een eigen machine te draaien. &#8220;Your Own Personal Coding Assistant&#8221;, self-hosted en volledig privaat, is vandaag haalbare kaart. We hebben daarvoor nodig: voldoende krachtige hardware, een LLM toegespitst op <em>code completion</em> taken of op conversaties over code, en een plugin voor de IDE. LLM en IDE plugin spreken met elkaar via een API, die al dan niet compatibel kan zijn met die van OpenAI &#8211; wat desgewenst toelaat gemakkelijk te wisselen tussen commerciële (OpenAI) en open source modellen.</p>



<h2 class="wp-block-heading">IDE plugins</h2>



<p class="wp-block-paragraph">Een plugin installeren is op zich gemakkelijk. Github Copilot bestaat al langer als <a href="https://code.visualstudio.com/docs/editor/github-copilot">plugin voor VSCode</a> en vandaag ook voor <a href="https://plugins.jetbrains.com/plugin/17718-github-copilot">IntelliJ IDEA</a> &#8211; al bevat de IntelliJ versie op moment van schrijven nog wat minder  functionaliteit. </p>



<p class="wp-block-paragraph">Onder de open-source alternatieven hoort <a href="https://continue.dev/">Continue</a> momenteel waarschijnlijk bij de top. Er zijn er andere – Huggingface zelf heeft bijvoorbeeld <a href="https://github.com/huggingface/llm-vscode?tab=readme-ov-file">llm-vscode</a> ontwikkeld – en ongetwijfeld zullen er nog bijkomen. Net zoals Github Copilot bestaat Continue ook als <a href="https://marketplace.visualstudio.com/items?itemName=Continue.continue">plugin voor VSCode</a> of <a href="https://plugins.jetbrains.com/plugin/22707-continue">IntelliJ</a>. Het kan zowel gebruikmaken van commerciële cloud-based generatoren (waaronder GPT-4) als van zelf gehoste open-source oplossingen. Die hoeven niet noodzakelijk de OpenAI API na te volgen, en er is veel customizatie mogelijk.</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/2024-03-11_14h59_32.png"><img decoding="async" width="1024" height="410" src="/wp-content/uploads/2024/03/2024-03-11_14h59_32-1024x410.png" alt="" class="wp-image-20216" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_14h59_32-1024x410.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_14h59_32-300x120.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_14h59_32-768x308.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_14h59_32-1536x615.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_14h59_32.png 1858w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Screenshot van de Continue plugin in Visual Studio Code</figcaption></figure>



<p class="wp-block-paragraph">Het blijft belangrijk om tijd te investeren om met de plugin te leren werken. De <a href="https://continue.dev/docs/intro">documentatie van Continue</a> is een goed startpunt. Voor elke <a href="https://continue.dev/docs/model-setup/select-provider">server</a> en elke <a href="https://continue.dev/docs/model-setup/select-model">LLM</a> kunnen er andere configuratieopties zijn die ingesteld moeten worden, en misschien wil je custom aanpassingen maken aan de achterliggende <a href="https://continue.dev/docs/model-setup/configuration">prompt</a>. Daarnaast is het nodig om te weten hoe de plugin geactiveerd en gedeactiveerd kan worden in de IDE, en welke shortcuts en <a href="https://continue.dev/docs/customization/slash-commands">commando&#8217;s</a> er bestaan. <a href="https://www.youtube.com/results?search_query=continue+ai">YouTube</a> kan een goed startpunt zijn om tutorials en voorbeelden van andere gebruikers te vinden.</p>



<h2 class="wp-block-heading">Een LLM op je laptop</h2>



<p class="wp-block-paragraph">Vooral onder impuls van het open-source project <a href="https://github.com/ggerganov/llama.cpp">llama.cpp</a>, zijn er het afgelopen jaar enorme inspanningen gebeurd om LLMs ook inzetbaar te maken op gewone consumentenhardware. Een peperdure GPU is niet meer noodzakelijk, al gaat het met GPU wel nog steeds sneller. In grote lijnen laat <a href="https://github.com/ggerganov/llama.cpp">llama.cpp</a> toe om een model te herverpakken in het GGUF formaat (GPT-Generated Unified Format). Daarbij worden zoveel mogelijk optimalisaties toegepast:</p>



<ul class="wp-block-list">
<li>gebruik van efficiënte CPU-instructiesets zoals <a href="https://en.wikipedia.org/wiki/AVX-512">AVX-512</a> &#8211; het spreekt voor zich dat de hardware waarop het model later moet draaien, deze instructiesets ook moet ondersteunen,</li>



<li>gebruik van sterk geoptimaliseerde high-performance libraries voor de achterliggende berekeningen, zoals <a href="https://github.com/OpenMathLib/OpenBLAS">openBLAS</a> of Apples <a href="https://developer.apple.com/documentation/accelerate">Accelerate</a> en <a href="https://developer.apple.com/metal/">Metal</a>,</li>



<li>het <em>kwantiseren </em>van het model, door het reduceren van de <a href="https://en.wikipedia.org/wiki/Precision_(computer_science)">precisie</a> van de gewichten in de lagen van de neurale netwerken. De 16-bit of 32-bit (komma)getallen uit het originele model worden daarbij omgezet naar gehele getallen (integers) van 8-bit, zelfs 6-bit of 4-bit. Dit bespaart geheugen en versnelt de berekeningen, ten koste van een relatief klein kwaliteitsverlies.</li>
</ul>



<p class="wp-block-paragraph">Lokaal een LLM hosten kan met tools zoals <a href="https://lmstudio.ai/">LM Studio</a>. Die geven je de mogelijkheid om verschillende modellen te downloaden in GGUF formaat. Een apart tabblad in de applicatie laat toe om een HTTP Inference server rond een gedownload en ingeladen model op te starten, die de API van OpenAI simuleert. Eens deze opgezet is, bijvoorbeeld op poort 1234, is het model aanspreekbaar via een call naar  <code>http://localhost:1234/v1/chat/completions</code> . </p>



<p class="wp-block-paragraph">Dit instellen in de Continue plugin gebeurt door de LLM toe te voegen aan het bestand <code>.continue/config.json</code> , volgens <a href="https://docs.continue.dev/customize">deze instructies</a> en volgens de richtlijnen voor <a href="https://docs.continue.dev/customize/model-providers/more/lmstudio">LM Studio als model provider</a>. Daarbij kan je de titel en het model aanpassen naar eigen goeddunken, en hoef je enkel nog de lijn <code>"apiBase":"http://127.0.0.1:1234/v1"</code> toe te voegen. In de plugin zal je dit dan als nieuwe keuzemogelijkheid zien verschijnen, en kan je ermee aan de slag.</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/2024-03-11_15h06_39.png"><img loading="lazy" decoding="async" width="1024" height="550" src="/wp-content/uploads/2024/03/2024-03-11_15h06_39-1024x550.png" alt="" class="wp-image-20217" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_15h06_39-1024x550.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_15h06_39-300x161.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_15h06_39-768x412.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_15h06_39-1536x825.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/2024-03-11_15h06_39.png 1918w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">LM Studio, met het CodeNinja model ingeladen, beantwoordt een query via de ingebouwde server die actief is op poort 1234. </figcaption></figure>



<h2 class="wp-block-heading">Intermezzo: over hardware</h2>



<p class="wp-block-paragraph">Het beheer van GPU&#8217;s is al geen pretje voor 1 developer aan 1 machine. Incompatibiliteitsproblemen tussen verschillende versies van allerlei software libraries en GPU-drivers kunnen dagen duren om op te lossen. Het <a href="https://www.nvidia.com/en-us/data-center/products/">marktaanbod van GPUs voor datacenters</a>, gedomineerd door nVIDIA in een monopoliepositie, is onnoemelijk duur. Daarbij komt nog de kost van het opbouwen van de heel gespecialiseerde kennis die nodig is om die systemen draaiende te houden. Eender wat je kiest van hardware is over 4 jaar waarschijnlijk al helemaal verouderd. Er wordt hard gewerkt aan nieuwe hardware, specifiek gemaakt om het soort berekeningen van AI-modellen te versnellen &#8211; Google kwam eerder al met de <a href="https://en.wikipedia.org/wiki/Tensor_Processing_Unit">TPU</a>, maar andere fabrikanten zetten nu ook hard in op <a href="https://www.techradar.com/computing/cpu/what-is-an-npu">NPUs (Neural Processing Units)</a>, en sommigen durven <a href="https://www.cerebras.net/">directe concurrentie</a> aan met nVIDIA. </p>



<p class="wp-block-paragraph">Als je geen tijd hebt om te knoeien met GPU-drivers en niet de ambitie hebt om zelf modellen te trainen, dan is de mogelijkheid om ze te gebruiken op een gewone CPU meer dan welkom. Uiteraard ben je dan wel beperkt tot die LLMs of AI-modellen waarvan de grootte dat ook toelaat. Typische LLMs voor &#8220;thuisgebruik&#8221; hebben 3, 7 of 13 miljard parameters; grotere modellen worden <a href="https://github.com/ggerganov/llama.cpp#memorydisk-requirements">agressief gekwantiseerd</a> om schijfruimte en geheugen te besparen. Ze gaan vandaag nog niet kunnen tippen aan de kwaliteit van GPT-4, maar er bestaan gelukkig leaderboards om te helpen een keuze te maken &#8211; voor <a href="https://huggingface.co/spaces/HuggingFaceH4/open_llm_leaderboard">open LLMs in het algemeen</a>, specifiek met <a href="https://huggingface.co/spaces/optimum/llm-perf-leaderboard">(doorvoer)snelheidsbenchmarks</a>, of voor <a href="https://huggingface.co/spaces/bigcode/bigcode-models-leaderboard">code-genererende LLMs</a> in het bijzonder.</p>



<p class="wp-block-paragraph">Hoe groter de LLMs, hoe kwaliteitsvoller het resultaat (meestal), maar ook hoe meer geheugen en rekenkracht vereist is. Een LLM moet liefst volledig in het geheugen ingeladen kunnen worden, dus 16GB RAM is geen luxe &#8211; meer is beter, zeker als je een IDE op dezelfde machine wil draaien. Om een antwoord te kunnen te geven, moet het volledige model vaak meermaals doorlopen worden. De bottleneck wordt bijgevolg vaak gevormd door de bandbreedte tussen CPU en RAM. CPUs met een grote interne cache lijken een streepje voor te hebben (zie ook AI-specifieke benchmarks [<a href="https://www.anandtech.com/show/21084/intel-core-i9-14900k-core-i7-14700k-and-core-i5-14600k-review-raptor-lake-refreshed/10">1</a>,<a href="https://www.anandtech.com/show/21242/amd-ryzen-7-8700g-and-ryzen-5-8600g-review/8">2</a>] van Anandtech). Bij de keuze van de rest van de hardware moet geheugenbandbreedte zeker meespelen. Ook wie een GPU zou willen kiezen, kijkt misschien liever naar die bandbreedte dan naar het aantal cores. Tot slot is het in gevirtualiseerde omgevingen (een VM, een VPS) belangrijk dat de virtuele CPU dezelfde geavanceerde instructiesets, zoals <a href="https://en.wikipedia.org/wiki/AVX-512#CPUs_with_AVX-512">AVX-512</a>, ondersteunt.</p>



<h2 class="wp-block-heading">Een LLM op je server</h2>



<p class="wp-block-paragraph">Als je elders een krachtigere machine hebt, kan het de moeite waard zijn om de LLM daarop te draaien. <a href="https://ollama.com/">ollama</a> is waarschijnlijk de populairste tool om zonder veel poespas modellen te hosten op Mac of Linux, sinds kort ook Windows. <a href="https://localai.io/">LocalAI</a> is echter een zeker zo interessante optie uit de lijst van mogelijke <a href="https://continue.dev/docs/model-setup/select-provider">LLM providers voor Continue</a>, want het biedt Docker containers aan, met of zonder GPU ondersteuning. Op een Linux machine die is uitgerust met Docker, is <a href="https://localai.io/basics/getting_started/">een oneliner</a> in de terminal voldoende om het open-source CodeLlama model te downloaden en te beginnen hosten op poort 1234:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="docker run -ti -p 1234:8080 localai/localai:v2.7.0-ffmpeg-core codellama-7b-gguf " style="color:#000000;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #795E26">docker</span><span style="color: #000000"> </span><span style="color: #A31515">run</span><span style="color: #000000"> </span><span style="color: #0000FF">-ti</span><span style="color: #000000"> </span><span style="color: #0000FF">-p</span><span style="color: #000000"> </span><span style="color: #098658">1234</span><span style="color: #A31515">:8080</span><span style="color: #000000"> </span><span style="color: #A31515">localai/localai:v2.7.0-ffmpeg-core</span><span style="color: #000000"> </span><span style="color: #A31515">codellama-7b-gguf</span><span style="color: #000000"> </span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">De opstart ervan duurt echter even, want het model wordt in de container gedownload. Interessanter is het om zelf een reeks modellen in een lokale map te bewaren, en daaromheen een API te zetten middels een LocalAI container. Ook voor die aanpak zijn relatief eenvoudige <a href="https://localai.io/docs/getting-started/models/">instructies</a> beschikbaar. We kunnen ze bijvoorbeeld toepassen op de <a href="https://huggingface.co/TheBloke/deepseek-coder-6.7B-instruct-GGUF">DeepSeek LLM van 6.7 miljard parameters, gekwantiseerd op 4 bits</a>. Deze kan rechtstreeks van Huggingface gedownload worden naar de lokale map <code>./models-gguf</code> met een <code>wget</code> commando van het type:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="wget https://huggingface.co/TheBloke/deepseek-coder-6.7B-instruct-GGUF/resolve/main/deepseek-coder-6.7b-instruct.Q4_K_M.gguf -O ./models-gguf/deepseek-6.7b-instruct-Q4" style="color:#000000;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #795E26">wget</span><span style="color: #000000"> </span><span style="color: #A31515">https://huggingface.co/TheBloke/deepseek-coder-6.7B-instruct-GGUF/resolve/main/deepseek-coder-6.7b-instruct.Q4_K_M.gguf</span><span style="color: #000000"> </span><span style="color: #0000FF">-O</span><span style="color: #000000"> </span><span style="color: #A31515">./models-gguf/deepseek-6.7b-instruct-Q4</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Een API starten rondom de modellen in die map op poort 8001 (je kan ook meerdere modellen in dezelfde map zetten en ze tegelijk hosten), kan dan met het volgende commando. Voeg eventueel <code><em>-d</em></code> toe om het in de achtergrond te laten lopen, en voel je vrij om met de parameters <code><em>context-size</em></code> en <code><em>threads </em></code>te experimenteren in functie van hoe krachtig je server is: </p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="docker run -p 8001:8080 -v $PWD/models-gguf:/models -ti --rm quay.io/go-skynet/local-ai:v2.7.0-ffmpeg-core --models-path /models --context-size 1600 --threads 16" style="color:#000000;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #795E26">docker</span><span style="color: #000000"> </span><span style="color: #A31515">run</span><span style="color: #000000"> </span><span style="color: #0000FF">-p</span><span style="color: #000000"> </span><span style="color: #098658">8001</span><span style="color: #A31515">:8080</span><span style="color: #000000"> </span><span style="color: #0000FF">-v</span><span style="color: #000000"> </span><span style="color: #001080">$PWD</span><span style="color: #A31515">/models-gguf:/models</span><span style="color: #000000"> </span><span style="color: #0000FF">-ti</span><span style="color: #000000"> </span><span style="color: #0000FF">--rm</span><span style="color: #000000"> </span><span style="color: #A31515">quay.io/go-skynet/local-ai:v2.7.0-ffmpeg-core</span><span style="color: #000000"> </span><span style="color: #0000FF">--models-path</span><span style="color: #000000"> </span><span style="color: #A31515">/models</span><span style="color: #000000"> </span><span style="color: #0000FF">--context-size</span><span style="color: #000000"> </span><span style="color: #098658">1600</span><span style="color: #000000"> </span><span style="color: #0000FF">--threads</span><span style="color: #000000"> </span><span style="color: #098658">16</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<h2 class="wp-block-heading">Voorbeeld</h2>



<p class="wp-block-paragraph">We kunnen nu verschillende LLMs voor code met elkaar vergelijken. We houden het hier louter anekdotisch, en nemen als eenvoudig voorbeeld het schrijven van een <em>bash </em>shellscript. We vertrekken van het volgende probleem: een backup-routine heeft jarenlang een nachtelijke backup genomen van een systeem. Om schijfruimte vrij te maken, willen we alle backups verwijderen die niet verschillen van de vorige. We geven de volgende opdracht, waarbij we de taak zo nauwgezet mogelijk omschrijven voor het beste resultaat: <em>&#8220;Write a bash script that, given a directory, iterates over all its files in order of date of creation. For each file, if the filesize is equal to the filesize of the previous file, the file has to be deleted.&#8221;</em></p>



<p class="wp-block-paragraph">De <code>.continue/config.json</code> file van onze Continue plugin bevat de volgende lijst modellen: eentje op de eigen laptop in LM Studio ingeladen op poort 1234, en twee op een aparte server in het lokaal netwerk, door LocalAI gehost op poort 8001.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="    {
      &quot;title&quot;: &quot;myLaptop-LMStudio&quot;,
      &quot;model&quot;: &quot;whatever is loaded in LMstudio&quot;,
      &quot;apiBase&quot;: &quot;http://127.0.0.1:1234/v1&quot;,
      &quot;completionOptions&quot;: {},
      &quot;provider&quot;: &quot;lmstudio&quot;
    },       
    {
      &quot;title&quot;: &quot;localAI-mistral&quot;,
      &quot;model&quot;: &quot;mistral-7b-code16kqlora-Q4&quot;,
      &quot;apiBase&quot;: &quot;https://192.168.0.100:8001/v1&quot;,
      &quot;apiKey&quot;: &quot;&quot;,      
      &quot;completionOptions&quot;: {},
      &quot;provider&quot;: &quot;openai&quot;
    },
    {
      &quot;title&quot;: &quot;localAI-deepseek&quot;,
      &quot;model&quot;: &quot;deepseek-6.7b-instruct-Q4&quot;,
      &quot;apiBase&quot;: &quot;https://192.168.0.100:8001/v1&quot;,
      &quot;apiKey&quot;: &quot;&quot;,
      &quot;completionOptions&quot;: {},
      &quot;provider&quot;: &quot;openai&quot;
    }," style="color:#24292e;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki github-light" style="background-color: #fff" tabindex="0"><code><span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;title&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;myLaptop-LMStudio&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;model&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;whatever is loaded in LMstudio&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;apiBase&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;http://127.0.0.1:1234/v1&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;completionOptions&quot;</span><span style="color: #24292E">: {},</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;provider&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;lmstudio&quot;</span></span>
<span class="line"><span style="color: #24292E">    },       </span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;title&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;localAI-mistral&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;model&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;mistral-7b-code16kqlora-Q4&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;apiBase&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;https://192.168.0.100:8001/v1&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;apiKey&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;&quot;</span><span style="color: #24292E">,      </span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;completionOptions&quot;</span><span style="color: #24292E">: {},</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;provider&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;openai&quot;</span></span>
<span class="line"><span style="color: #24292E">    },</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;title&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;localAI-deepseek&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;model&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;deepseek-6.7b-instruct-Q4&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;apiBase&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;https://192.168.0.100:8001/v1&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;apiKey&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;&quot;</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;completionOptions&quot;</span><span style="color: #24292E">: {},</span></span>
<span class="line"><span style="color: #24292E">      </span><span style="color: #032F62">&quot;provider&quot;</span><span style="color: #24292E">: </span><span style="color: #032F62">&quot;openai&quot;</span></span>
<span class="line"><span style="color: #24292E">    },</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Als referentie nemen we <a href="https://chat.openai.com/">ChatGPT</a>, die komt met de volgende (correcte) oplossing. Bovendien wordt ze ook gevolgd door een uitgebreide uitleg over wat de verschillende onderdelen betekenen (hier niet weergegeven):</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="#!/bin/bash

# Directory containing the files
DIR=&quot;/path/to/your/directory&quot;

# Variable to hold the size of the previous file. Initialized to 0.
prev_size=0

# List all files in the directory, sorted by creation date
# Note: '%T@' sorts by creation time, '%p' prints the file's name
# 'sort -n' ensures the list is sorted numerically
# Note that creation time sorting may depend on filesystem and OS support
files=$(find &quot;$DIR&quot; -type f -printf &quot;%T@ %p\n&quot; | sort -n | cut -d ' ' -f 2-)

# Iterate over the sorted list of files
for file in $files; do
  # Get current file size
  current_size=$(stat -c %s &quot;$file&quot;)
  
  # Check if current file size is equal to the previous file's size
  if [ &quot;$current_size&quot; -eq &quot;$prev_size&quot; ]; then
    # Sizes are equal, delete the current file
    echo &quot;Deleting file: $file&quot;
    rm &quot;$file&quot;
  fi
  
  # Update previous size to current file's size
  prev_size=$current_size
done" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">#!/bin/bash</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Directory containing the files</span></span>
<span class="line"><span style="color: #9CDCFE">DIR</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;/path/to/your/directory&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Variable to hold the size of the previous file. Initialized to 0.</span></span>
<span class="line"><span style="color: #9CDCFE">prev_size</span><span style="color: #D4D4D4">=</span><span style="color: #B5CEA8">0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># List all files in the directory, sorted by creation date</span></span>
<span class="line"><span style="color: #6A9955"># Note: &#39;%T@&#39; sorts by creation time, &#39;%p&#39; prints the file&#39;s name</span></span>
<span class="line"><span style="color: #6A9955"># &#39;sort -n&#39; ensures the list is sorted numerically</span></span>
<span class="line"><span style="color: #6A9955"># Note that creation time sorting may depend on filesystem and OS support</span></span>
<span class="line"><span style="color: #9CDCFE">files</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">find</span><span style="color: #CE9178"> &quot;</span><span style="color: #9CDCFE">$DIR</span><span style="color: #CE9178">&quot; </span><span style="color: #569CD6">-type</span><span style="color: #CE9178"> f </span><span style="color: #569CD6">-printf</span><span style="color: #CE9178"> &quot;%T@ %p\n&quot; </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">sort</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-n</span><span style="color: #CE9178"> </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">cut</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-d</span><span style="color: #CE9178"> &#39; &#39; </span><span style="color: #569CD6">-f</span><span style="color: #CE9178"> </span><span style="color: #B5CEA8">2</span><span style="color: #CE9178">-)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Iterate over the sorted list of files</span></span>
<span class="line"><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">file</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$files</span><span style="color: #D4D4D4">; </span><span style="color: #C586C0">do</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955"># Get current file size</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">current_size</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">stat</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-c</span><span style="color: #CE9178"> %s &quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;)</span></span>
<span class="line"><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955"># Check if current file size is equal to the previous file&#39;s size</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [ </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$current_size</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> -eq </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$prev_size</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> ]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># Sizes are equal, delete the current file</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Deleting file: </span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">rm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #D4D4D4">  </span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #6A9955"># Update previous size to current file&#39;s size</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #9CDCFE">prev_size</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">$current_size</span></span>
<span class="line"><span style="color: #C586C0">done</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">In LMStudio laden we het model &#8220;<a href="https://huggingface.co/TheBloke/CodeNinja-1.0-OpenChat-7B-GGUF">CodeNinja 1.0 openchat 7B Q4_K_M</a>&#8221; in. Voor het genereren van het antwoord op dezelfde vraag is ruim 1 minuut nodig: 20 seconden wachten tot de eerste letter van het antwoord verschijnt, daarna nog ongeveer 2 seconden per lijn. (Onze laptop is natuurlijk niet superkrachtig: een Core i7-10610U CPU met 32GB RAM). Het volgende komt eruit:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="#!/bin/bash

for f in $(ls -t -l --time-style=full /path/to/directory)
do
  if [[ $f == &quot;total&quot;* ]]; then
        continue;
    fi
    filename=$(basename &quot;${f% *}&quot;)

    # Checks whether the file is already deleted. If not, compares it with the previous file:
    prev_file=&quot;&quot;
    while IFS= read -r line; do
        if [[ $line == $filename ]]; then
            prev_file=$line
            break;
        fi
    done &lt;&lt;&lt;&quot;$(ls -l /path/to/directory | tail -n 2)&quot;

    if [[ -z $prev_file || &quot;$f&quot; = &quot;${prev_file}&quot; ]]; then
        # If the file is deleted, nothing to do. If not, deletes it:
        if [[ -z $prev_file ]] || [[ &quot;$(stat -c %s ${filename})&quot; == &quot;$(stat -c %s ${prev_file})&quot; ]]; then
            rm /path/to/directory/$filename
        fi
    fi
done" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">#!/bin/bash</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">f</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">ls</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-t</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-l</span><span style="color: #CE9178"> </span><span style="color: #569CD6">--time-style=full</span><span style="color: #CE9178"> /path/to/directory)</span></span>
<span class="line"><span style="color: #C586C0">do</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [[ </span><span style="color: #9CDCFE">$f</span><span style="color: #D4D4D4"> == </span><span style="color: #CE9178">&quot;total&quot;</span><span style="color: #D4D4D4">* ]]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">continue</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">filename</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">basename</span><span style="color: #CE9178"> &quot;${</span><span style="color: #9CDCFE">f</span><span style="color: #D4D4D4">%</span><span style="color: #CE9178"> </span><span style="color: #D4D4D4">*</span><span style="color: #CE9178">}&quot;)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># Checks whether the file is already deleted. If not, compares it with the previous file:</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">prev_file</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">&quot;&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">while</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">IFS</span><span style="color: #D4D4D4">= </span><span style="color: #DCDCAA">read</span><span style="color: #D4D4D4"> </span><span style="color: #569CD6">-r</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">line</span><span style="color: #D4D4D4">; </span><span style="color: #C586C0">do</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [[ </span><span style="color: #9CDCFE">$line</span><span style="color: #D4D4D4"> == </span><span style="color: #9CDCFE">$filename</span><span style="color: #D4D4D4"> ]]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #9CDCFE">prev_file</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">$line</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #C586C0">break</span><span style="color: #D4D4D4">;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">done</span><span style="color: #D4D4D4"> &lt;&lt;&lt;</span><span style="color: #CE9178">&quot;$(</span><span style="color: #DCDCAA">ls</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-l</span><span style="color: #CE9178"> /path/to/directory </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">tail</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-n</span><span style="color: #CE9178"> </span><span style="color: #B5CEA8">2</span><span style="color: #CE9178">)&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [[ -z </span><span style="color: #9CDCFE">$prev_file</span><span style="color: #D4D4D4"> || </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$f</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> = </span><span style="color: #CE9178">&quot;${</span><span style="color: #9CDCFE">prev_file</span><span style="color: #CE9178">}&quot;</span><span style="color: #D4D4D4"> ]]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #6A9955"># If the file is deleted, nothing to do. If not, deletes it:</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [[ -z </span><span style="color: #9CDCFE">$prev_file</span><span style="color: #D4D4D4"> ]] || [[ </span><span style="color: #CE9178">&quot;$(</span><span style="color: #DCDCAA">stat</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-c</span><span style="color: #CE9178"> %s ${</span><span style="color: #9CDCFE">filename</span><span style="color: #CE9178">})&quot;</span><span style="color: #D4D4D4"> == </span><span style="color: #CE9178">&quot;$(</span><span style="color: #DCDCAA">stat</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-c</span><span style="color: #CE9178"> %s ${</span><span style="color: #9CDCFE">prev_file</span><span style="color: #CE9178">})&quot;</span><span style="color: #D4D4D4"> ]]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">            </span><span style="color: #DCDCAA">rm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">/path/to/directory/</span><span style="color: #9CDCFE">$filename</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #C586C0">done</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Het <a href="https://huggingface.co/TheBloke/deepseek-coder-6.7B-instruct-GGUF">DeepSeek model van 6.7 miljard parameters</a> laden we in LocalAI op een Debian VM in Proxmox. Aan de VM is ruim voldoende RAM toegekend, en 12 cores van de onderliggende hardware, een AMD Threadripper 3960X processor (24 cores maar geen AVX-512 ondersteuning). Hiermee creëren we aan een snelheid van ongeveer 3 lijnen per seconde het volgende resultaat:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(2 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="#!/bin/bash

# Check if directory is provided
if [ $# -ne 1 ]; then
  echo &quot;Usage: $0 directory&quot;
    exit 1
fi

# Check if directory exists
if [&nbsp;! -d &quot;$1&quot; ]; then
    echo &quot;Directory $1 does not exist&quot;
    exit 1
fi

# Change to the directory
cd &quot;$1&quot;

# Get the list of files in order of creation date
files=$(ls -t)

# Initialize previous_size to 0
previous_size=0

# Iterate over the files
for file in $files; do
    # Get the size of the file
    size=$(stat -c%s &quot;$file&quot;)

    # If the size is equal to the previous size, delete the file
    if [ $size -eq $previous_size ]; then
        rm &quot;$file&quot;
        echo &quot;Deleted $file&quot;
    fi

    # Update previous_size
    previous_size=$size
done" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #6A9955">#!/bin/bash</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Check if directory is provided</span></span>
<span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [ </span><span style="color: #569CD6">$#</span><span style="color: #D4D4D4"> -ne </span><span style="color: #B5CEA8">1</span><span style="color: #D4D4D4"> ]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">  </span><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Usage: </span><span style="color: #9CDCFE">$0</span><span style="color: #CE9178"> directory&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">exit</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1</span></span>
<span class="line"><span style="color: #C586C0">fi</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Check if directory exists</span></span>
<span class="line"><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [&nbsp;! -d </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$1</span><span style="color: #CE9178">&quot;</span><span style="color: #D4D4D4"> ]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Directory </span><span style="color: #9CDCFE">$1</span><span style="color: #CE9178"> does not exist&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #DCDCAA">exit</span><span style="color: #D4D4D4"> </span><span style="color: #B5CEA8">1</span></span>
<span class="line"><span style="color: #C586C0">fi</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Change to the directory</span></span>
<span class="line"><span style="color: #DCDCAA">cd</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$1</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Get the list of files in order of creation date</span></span>
<span class="line"><span style="color: #9CDCFE">files</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">ls</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-t</span><span style="color: #CE9178">)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Initialize previous_size to 0</span></span>
<span class="line"><span style="color: #9CDCFE">previous_size</span><span style="color: #D4D4D4">=</span><span style="color: #B5CEA8">0</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6A9955"># Iterate over the files</span></span>
<span class="line"><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">file</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">$files</span><span style="color: #D4D4D4">; </span><span style="color: #C586C0">do</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># Get the size of the file</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">size</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">stat</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-c%s</span><span style="color: #CE9178"> &quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># If the size is equal to the previous size, delete the file</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [ </span><span style="color: #9CDCFE">$size</span><span style="color: #D4D4D4"> -eq </span><span style="color: #9CDCFE">$previous_size</span><span style="color: #D4D4D4"> ]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">rm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">        </span><span style="color: #DCDCAA">echo</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;Deleted </span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">fi</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #6A9955"># Update previous_size</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">previous_size</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">$size</span></span>
<span class="line"><span style="color: #C586C0">done</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Tot slot kunnen we op dezelfde VM ook het recentere Mistral uitproberen, waarvoor we op goed geluk de versie <a href="https://huggingface.co/TheBloke/Mistral-7B-Code-16K-qlora-GGUF">mistral-7B-code-16K-qlora</a> uitkiezen die door een andere gebruiker lichtjes werd bijgetraind voor code. Deze blijkt zeer snel te kunnen antwoorden, en genereert in ongeveer 2 seconden het volgende compacte resultaat (helaas zonder documentatie, en gebruikmakend van het complexe <em>awk</em> commando):</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(1 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span role="button" tabindex="0" data-code="for file in $(find directory -type f -exec du -sh {} + | sort -h | awk '{print NR &quot;:\t&quot; $1}'); do
    size=$(du -sh &quot;$file&quot; | awk '{print $1}')
    if [[ $size == $previous_size ]]; then
      rm &quot;$file&quot;
    fi
    previous_size=$size
done" style="color:#D4D4D4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki dark-plus" style="background-color: #1E1E1E" tabindex="0"><code><span class="line"><span style="color: #C586C0">for</span><span style="color: #D4D4D4"> </span><span style="color: #9CDCFE">file</span><span style="color: #D4D4D4"> </span><span style="color: #C586C0">in</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">find</span><span style="color: #CE9178"> directory </span><span style="color: #569CD6">-type</span><span style="color: #CE9178"> f </span><span style="color: #569CD6">-exec</span><span style="color: #CE9178"> du </span><span style="color: #569CD6">-sh</span><span style="color: #CE9178"> {} + </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">sort</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-h</span><span style="color: #CE9178"> </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">awk</span><span style="color: #CE9178"> &#39;{print NR &quot;:\t&quot; $1}&#39;)</span><span style="color: #D4D4D4">; </span><span style="color: #C586C0">do</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">size</span><span style="color: #D4D4D4">=</span><span style="color: #CE9178">$(</span><span style="color: #DCDCAA">du</span><span style="color: #CE9178"> </span><span style="color: #569CD6">-sh</span><span style="color: #CE9178"> &quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot; </span><span style="color: #D4D4D4">|</span><span style="color: #CE9178"> </span><span style="color: #DCDCAA">awk</span><span style="color: #CE9178"> &#39;{print $1}&#39;)</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">if</span><span style="color: #D4D4D4"> [[ </span><span style="color: #9CDCFE">$size</span><span style="color: #D4D4D4"> == </span><span style="color: #9CDCFE">$previous_size</span><span style="color: #D4D4D4"> ]]; </span><span style="color: #C586C0">then</span></span>
<span class="line"><span style="color: #D4D4D4">      </span><span style="color: #DCDCAA">rm</span><span style="color: #D4D4D4"> </span><span style="color: #CE9178">&quot;</span><span style="color: #9CDCFE">$file</span><span style="color: #CE9178">&quot;</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #C586C0">fi</span></span>
<span class="line"><span style="color: #D4D4D4">    </span><span style="color: #9CDCFE">previous_size</span><span style="color: #D4D4D4">=</span><span style="color: #9CDCFE">$size</span></span>
<span class="line"><span style="color: #C586C0">done</span></span></code></pre></div>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Ik laat de diepgaandere vergelijking van deze resultaten graag over als oefening aan de lezer. Als we hieruit nog een laatste les moeten leren, dan is het dat er ook tussen modellen onderling, zelfs al hebben ze dezelfde hoeveelheid parameters en zijn ze voor hetzelfde doel getraind, erg grote verschillen kunnen zijn qua output en stijl! </p>



<h2 class="wp-block-heading">Conclusie</h2>



<p class="wp-block-paragraph">Aan sneltempo vinden allerlei AI-powered features hun weg naar de IDE. De <a href="https://code.visualstudio.com/updates/v1_87">laatste release notes van Visual Studio Code</a> vermelden naast verschillende CoPilot features bijvoorbeeld ook ondersteuning voor spraakherkenning in meerdere talen. Het is onvermijdelijk dat je daar als developer mee in contact zal komen. Developers die werken met gevoelige data of copyrighted code, zijn terecht argwanend over het feit dat zulke tools hun IDE-inhoud naar een of andere clouddienst van een derde partij versturen, om suggesties te kunnen genereren. </p>



<p class="wp-block-paragraph">Vooral dankzij het <a href="https://github.com/ggerganov/llama.cpp">llama.cpp</a> project, is er recent een alternatieve <em>open-source</em> route ontstaan die toelaat zulke coding assistentie met LLMs zelf op te zetten en uit te baten. Kleinere modellen die op consumentenhardware kunnen draaien, leveren momenteel niet dezelfde kwaliteit en snelheid als Github CoPilot of ChatGPT. De komende jaren zullen we echter regelmatig verdere verbeteringen zien verschijnen, dus de ingezette weg oogt alleszins veelbelovend. </p>



<p class="wp-block-paragraph">______________________</p>



<p class="wp-block-paragraph"><em>Dit is een ingezonden bijdrage van Joachim Ganseman, IT consultant bij Smals Research. &nbsp;Dit artikel werd geschreven in eigen naam en neemt geen standpunt in namens Smals.</em></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Reactive: het Akka framework</title>
		<link>https://www.smalsresearch.be/reactive-het-akka-framework/</link>
		
		<dc:creator><![CDATA[Koen Vanderkimpen]]></dc:creator>
		<pubDate>Tue, 07 Sep 2021 11:59:31 +0000</pubDate>
				<category><![CDATA[[NL]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[akka]]></category>
		<category><![CDATA[aktors]]></category>
		<category><![CDATA[cloud computing]]></category>
		<category><![CDATA[EDA]]></category>
		<category><![CDATA[Event]]></category>
		<category><![CDATA[methodology]]></category>
		<category><![CDATA[multithreading]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[reactive]]></category>
		<category><![CDATA[Resilience]]></category>
		<category><![CDATA[Software architectures]]></category>
		<category><![CDATA[software engineering]]></category>
		<guid isPermaLink="false">/?p=16446</guid>

					<description><![CDATA[In een vorige blog gaven we reeds een uitvoerige inleiding van het &#8220;Reactive&#8221; paradigma. Vermits dit toch wel een belangrijke en invloedrijke zaak geworden is binnen de developer wereld, lijkt het ons nuttig om hier op terug te komen en wat dieper in te gaan op een voorbeeld van een Reactive framework: het Akka framework, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="alignleft is-resized"><img loading="lazy" decoding="async" src="/wp-content/uploads/2021/09/reactive2-edited-1.png" alt="" class="wp-image-16466" width="150" height="150" srcset="https://www.smalsresearch.be/wp-content/uploads/2021/09/reactive2-edited-1.png 155w, https://www.smalsresearch.be/wp-content/uploads/2021/09/reactive2-edited-1-150x150.png 150w" sizes="auto, (max-width: 150px) 100vw, 150px" /></figure></div>



<p class="justify-text wp-block-paragraph">In een <a href="/de-reactive-hype/" data-type="post" data-id="14280">vorige blog</a> gaven we reeds een uitvoerige inleiding van het &#8220;Reactive&#8221; paradigma. Vermits dit toch wel een belangrijke en invloedrijke zaak geworden is binnen de developer wereld, lijkt het ons nuttig om hier op terug te komen en wat dieper in te gaan op een voorbeeld van een Reactive framework: het <em>Akka framework</em>, één van de pioniers binnen de Reactive beweging.</p>



<span id="more-16446"></span>



<h2 class="wp-block-heading">Wat is Reactive alweer?</h2>



<p class="justify-text wp-block-paragraph"><a href="https://www.reactivemanifesto.org/">Reactieve systemen</a> worden gezien als één van de belangrijkste ontwikkelingen om systemen responsiever te maken voor meer veeleisende eindgebruikers, en om overweg te kunnen met de grote hoeveelheid data die moderne systemen overspoelt. Zogenaamde &#8220;wearables&#8221; en andere <a href="/er-zit-een-hacker-in-mijn-diepvries/" data-type="post" data-id="6757">IoT zaken</a> kunnen bijvoorbeeld een constante stroom aan data genereren. Wanneer men dan de data van vele honderden van zulke devices moet verwerken, komen traditionele systemen vaak in de problemen. Maar ook voor &#8216;gewone&#8217; toepassingen kan deze technologie heil brengen, doordat de responsiviteit en resiliëntie ook kunnen worden verhoogd.</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2021/09/Reactive-Manifesto.png"><img loading="lazy" decoding="async" width="1024" height="416" src="/wp-content/uploads/2021/09/Reactive-Manifesto-1024x416.png" alt="" class="wp-image-16462" srcset="https://www.smalsresearch.be/wp-content/uploads/2021/09/Reactive-Manifesto-1024x416.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2021/09/Reactive-Manifesto-300x122.png 300w, https://www.smalsresearch.be/wp-content/uploads/2021/09/Reactive-Manifesto-768x312.png 768w, https://www.smalsresearch.be/wp-content/uploads/2021/09/Reactive-Manifesto.png 1235w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>Figuur 1: De vier basiseigenschappen van Reactieve systemen en hoe ze zich tot elkaar verhouden.</figcaption></figure>



<p class="justify-text wp-block-paragraph">Aan de grondslag van Reactive ligt het feit dat het &#8220;message driven&#8221; is (Zie Fig. 1). Men zal een systeem bouwen aan de hand van een aantal met elkaar communicerende subsystemen die berichten zullen uitwisselen. Dit kan zowel rechtstreeks als via het <a href="/het-event-als-leidend-voorwerp-in-software-engineering/" data-type="post" data-id="8942">publish/subscribe mechanisme van Events</a>. Deze communicatie is altijd inherent asynchroon. Men weet niet wanneer er op een bericht zal worden gereageerd en men gaat er ook niet expliciet op wachten. Deze vorm van communicatie tussen componenten zorgt ervoor dat ze losjes gekoppeld zijn en locatietransparant. Dit &#8220;message driven&#8221; fundament leidt verder tot verschillende voordelen.</p>



<p class="justify-text wp-block-paragraph">Eerst en vooral zorgt dit voor resiliëntie. Asynchrone communicatie laat toe om componenten veel onafhankelijker van elkaar te laten opereren dan <a href="/data-centric-it-met-rest/" data-type="post" data-id="9535">synchrone communicatie</a>, wat ervoor kan zorgen dat één component verder kan indien de andere (tijdelijk) faalt. De manier waarop berichten behandeld worden bij Reactive maakt ook van foutmeldingen gewone berichten; men behandelt deze als &#8216;first class citizen&#8217;, en niet zozeer als een uitzondering. Het omgaan met fouten en met niet-werkende componenten wordt dan als van nature mee opgenomen in het programmeren van zo&#8217;n systeem.</p>



<p class="justify-text wp-block-paragraph">Ten tweede stijgt ook de elasticiteit. Bij reactieve systemen is de berichtenstroom heel belangrijk. Men kan deze gaan monitoren en ingrijpen wanneer deze sterk in volume toe- of afneemt, en snel reageren door meer componenten op te starten (of te stoppen), om deze berichten af te handelen. Ook het feit dat het systeem bestaat uit een heel aantal samenwerkende componenten, en niet afhankelijk is van een centrale bottleneck, komt de schaalbaarheid ten goede.</p>



<p class="justify-text wp-block-paragraph">Ten slotte moet dit alles samen zorgen voor een verhoogde responsiviteit. Men zorgt ervoor dat men tijdig en vooral binnen een bepaalde tijd kan reageren op alle binnenkomende berichten, voor een consistente Quality of Service.</p>



<h2 class="wp-block-heading">Het Akka raamwerk</h2>



<p class="justify-text wp-block-paragraph"><a href="https://akka.io/">Akka</a> zag het licht in 2009 als één van de eerste raamwerken die het principe van het Actor programmeermodel naar een mainstream server programmeertaal bracht. Het is beschikbaar zowel voor de programmeertaal <a href="https://www.scala-lang.org/">Scala</a> (een taal die werkt op de JVM), waar het in principe voor is gebouwd, als voor Java (waar het iets meer boilerplate code vergt). Tegenwoordig maakt het deel uit van het <a href="https://www.lightbend.com/">Lightbend</a> platform, samen met het <a href="https://www.playframework.com/">Play raamwerk</a> en de taal Scala.</p>



<p class="justify-text wp-block-paragraph">Actoren kan men zien als kleine onafhankelijke machines binnen een softwaresysteem. Ze communiceren enkel met de buitenwereld (en dus met andere actors) via asynchrone berichten. Wanneer een actor een bericht krijgt, kan deze een aantal verschillende dingen doen: lokale code uitvoeren, zijn eigen toestand veranderen, zelf berichten uitsturen, andere actoren creëren, en beslissen hoe op het volgende bericht zal worden gereageerd. Een actor leeft dus volledig binnen zijn eigen executie-stack. Men kan deze dus beschouwen als een apart proces of een aparte thread, maar in een raamwerk als Akka is het mogelijk om deze veel efficiënter te instantiëren dan dat (zelfs threads zijn nog relatieve zwaargewichten, terwijl een actor in akka maar een paar honderd bytes hoeft in te nemen; één thread zal dan ook typisch vele actors tegelijk aansturen). Daarnaast kan men er voor zorgen dat een actor een andere actor als &#8220;supervisor&#8221; krijgt. Deze zal in het oog houden of de gesuperviseerde actor faalt, en kan dus indien nodig gepast reageren.</p>



<p class="justify-text wp-block-paragraph">Eén van de meest interessante zaken aan actors is dat het voor de programmeur transparant kan gemaakt worden waar een actor zich bevindt: het kan een andere actor binnen hetzelfde proces zijn, een actor binnen een ander proces op dezelfde machine, of een actor aan de andere kant van het internet: de programmeur kan deze op dezelfde manier behandelen. Dit is één van de eigenschappen die Akka <em><a href="https://www.cncf.io/">Cloud Native</a></em> maakt: het is een technologie gebouwd vóór de Cloud, waarmee men optimaal kan gebruik maken van de eigenschappen van de Cloud.</p>



<p class="justify-text wp-block-paragraph">Naast de &#8216;core&#8217; Akka bibliotheek, bestaan er ook nog heel wat modulaire uitbreidingen, zoals b.v. voor het werken met streams, persistentie, webservers en http, en allerlei integraties, zoals b.v. met het Play framework, of met Apache Kafka. Ook RESTful APIs worden ondersteund.</p>



<h2 class="wp-block-heading">Een voorbeeld</h2>



<p class="justify-text wp-block-paragraph">In de code duiken zou een beetje te technisch worden, maar we kunnen toch illustreren wat men met deze manier van programmeren kan bereiken aan de hand van een eenvoudig voorbeeld.</p>



<p class="justify-text wp-block-paragraph">In onderstaande figuur zie je een tekening van een aantal actoren in een boekenwinkel systeem en de berichten die ze elkaar sturen: er zijn klanten, de boekenwinkel zelf, en bedienden (die boeken opsturen). Het systeem zal als volgt werken: klanten sturen bestellingen naar de winkel; deze zal de bestellingen verder doorgeven aan een bediende. Deze hebben wat tijd nodig om een bestelling af te handelen, dus er zijn er meerdere, om meer bestellingen aan te kunnen. Hoe de winkel kiest welke taak aan welke bediende te geven, zouden we op verschillende manieren kunnen oplossen (b.v. &#8220;neem een willekeurige vrije bediende&#8221;), maar zoveel detail laten we hier niet zien.</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2021/09/bookstore-default.png"><img loading="lazy" decoding="async" width="1024" height="485" src="/wp-content/uploads/2021/09/bookstore-default-1024x485.png" alt="" class="wp-image-16459" srcset="https://www.smalsresearch.be/wp-content/uploads/2021/09/bookstore-default-1024x485.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2021/09/bookstore-default-300x142.png 300w, https://www.smalsresearch.be/wp-content/uploads/2021/09/bookstore-default-768x363.png 768w, https://www.smalsresearch.be/wp-content/uploads/2021/09/bookstore-default.png 1192w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>Figuur 2: De boekenwinkel aktors. Bij de standaard werking zullen bestellingen van klanten doorgegeven worden aan een pool van bediendes. Wanneer een boek niet kan worden geleverd, krijgt de klant in de plaats ervan een cadeaubon.</figcaption></figure>



<p class="justify-text wp-block-paragraph">De bediende die een bestelling krijgt wordt &#8220;bezig&#8221; (een andere toestand dan &#8220;vrij&#8221;) en zal uiteindelijk een boek terugsturen naar de klant (in het geval van het IT systeem dat dit systeem modelleert, kan dit b.v. een bericht zijn met de tracking code van het pakket). Daarna wordt de bediende terug &#8220;vrij&#8221;.</p>



<p class="justify-text wp-block-paragraph">Soms gaat er echter iets mis met de bestelling: de bediende vindt b.v. het boek niet dat de klant wil. In dat geval stuurt deze een verontschuldigend bericht terug naar de klant, met een cadeaubon. Als er echter te vaak van deze dingen gebeuren, krijgt een bediende teveel stress en geeft deze er de brui aan (zijn actor gaat in error-modus). Dit geeft dus een foutmelding, die geëscaleerd wordt naar de supervisor van de bediende, in dit geval de winkel (zie Fig. 3). Deze zal dan moeten beslissen wat er met de fout gebeurt: we kiezen ervoor om de bestelling aan een andere bediende te geven en de gestresseerde bediende een paar dagen &#8220;verlof&#8221; te geven (waarna zijn actor terug in toestand &#8220;vrij&#8221; zal komen).</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2021/09/bookstore-error.png"><img loading="lazy" decoding="async" width="1024" height="722" src="/wp-content/uploads/2021/09/bookstore-error-1024x722.png" alt="" class="wp-image-16460" srcset="https://www.smalsresearch.be/wp-content/uploads/2021/09/bookstore-error-1024x722.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2021/09/bookstore-error-300x211.png 300w, https://www.smalsresearch.be/wp-content/uploads/2021/09/bookstore-error-768x541.png 768w, https://www.smalsresearch.be/wp-content/uploads/2021/09/bookstore-error.png 1121w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>Figuur 3: Illustratie van de verschillende toestanden waarin een bediende zich kan bevinden, plus: wat gebeurt er indien een bediende er de brui aan geeft tijdens een bestelling (Error)? De bediende krijgt verlof van de winkel en de bestelling wordt doorgegeven aan een andere bediende.</figcaption></figure>



<p class="justify-text wp-block-paragraph">Dit voorbeeld illustreert het principe van resiliëntie, gebruikmakende van actoren: de fout wordt niet speciaal als fout behandeld, maar als een bericht naar de winkel, die het probleem op dat niveau kan oplossen. Er wordt ook niet alleen gezorgd voor fout-tolerantie, maar ook voor veerkracht: uiteindelijk zal de foutieve actor worden hersteld en terug ter beschikking komen van de pool. Deze veerkracht maakt net het verschil tussen gewone fout-tolerantie en echte resiliëntie.</p>



<h2 class="wp-block-heading">Besluit</h2>



<p class="wp-block-paragraph">De meeste bestaande raamwerken voor Reactive systemen focussen zich op het gebruik van streams van berichten/events, en op hoe deze zo efficiënt mogelijk te behandelen. Een raamwerk zoals Akka doet het net iets anders, door gebruik te maken van het actor paradigma. Dit biedt een verfrissende kijk op multi-threaded programming, en kan het bouwen van sommige systemen net iets gemakkelijker maken.</p>



<p class="justify-text wp-block-paragraph">Het gebruik van actoren verhoogt in ieder geval het niveau van abstractie wanneer men over parallellisme en multi-threading probeert te redeneren, een oefening die berucht is voor zijn moeilijkheid.</p>



<p class="justify-text wp-block-paragraph">Actors lijken erg nuttig voor het modelleren van zaken die een toestand en een gedrag vertonen in de echte wereld, zoals mensen, machines, of bedrijven. In het algemeen zijn ze goed inzetbaar wanneer je systeem goed decomposeerbaar is in een set van onafhankelijke taken, of een set van taken die een bepaalde workflow volgt. Ten slotte zijn ze ook erg geschikt voor het programmeren van <a href="/geavanceerd-event-driven-engineering/" data-type="post" data-id="9041">Event Driven systemen</a>.</p>



<p class="wp-block-paragraph"></p>


]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Java 7, What&#8217;s new?</title>
		<link>https://www.smalsresearch.be/java-7-whats-new/</link>
		
		<dc:creator><![CDATA[Koen Vanderkimpen]]></dc:creator>
		<pubDate>Tue, 30 Aug 2011 11:27:38 +0000</pubDate>
				<category><![CDATA[Blog post]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java 7]]></category>
		<category><![CDATA[Language]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[software engineering]]></category>
		<category><![CDATA[Swing]]></category>
		<guid isPermaLink="false">/?p=3184</guid>

					<description><![CDATA[Sinds enige tijd is de release-versie van Java 7 op het toneel verschenen. Voor een Java-bedrijf is het zeer interessant om de nieuwe features van de taal eens te bekijken, dus een blogpost kon niet uitblijven. Waar ik het in deze post niet (verder) over zal over hebben, is het debacle dat Oracle van de [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><a href="/wp-content/uploads/2011/08/thumb-java-duke-guitar.png"><img loading="lazy" decoding="async" class="alignleft size-full wp-image-3192" title="thumb-java-duke-guitar" src="/wp-content/uploads/2011/08/thumb-java-duke-guitar.png" alt="" width="220" height="188" /></a>Sinds enige tijd is de release-versie van Java 7 op het toneel verschenen. Voor een Java-bedrijf is het zeer interessant om de nieuwe features van de taal eens te bekijken, dus een blogpost kon niet uitblijven. Waar ik het in deze post niet (verder) over zal over hebben, is het <a title="debacle dat Oracle van de lancering heeft gemaakt" href="https://blog.eisele.net/2011/07/dont-use-java-7-are-you-kidding-me.html">debacle dat Oracle van de lancering heeft gemaakt</a>: er zit een serieuze bug in de compiler-optimizaties, dus best nog even wachten met upgraden! (Toch wat weinig tijd tussen de release candidate en de echte &#8216;rush-release&#8217; gelaten, naar mijn mening.)</p>
<p>Maar goed, ter zake! Wat brengt <a title="Java 7" href="https://jdk7.java.net/">Java 7</a> ons voor vernieuwingen?</p>
<p><span id="more-3184"></span></p>
<p>Ik moet echter beginnen met een disclaimer: na jaren van ontwikkeling is er natuurlijk heel wat meer bijgekomen in de taal dan ik hier kan beschrijven. Mijn oplijsting is dus niet <a title="exhaustief" href="https://openjdk.org/projects/jdk7/features/">exhaustief</a>. Het blijkt trouwens vrij moeilijk om een perfect juist beeld bij elkaar te googlen van wat er nu precies wél of niet inzit, en daarbij ook nog eens een goede uitleg over deze zaken te krijgen (maar vandaar ook het nut van een blogpost als deze).</p>
<p><em>De vernieuwingen dan:</em></p>
<p>Eerst de zaken die we niet meteen met het blote oog kunnen zien: de virtuele machine heeft een hele evolutie doorgemaakt <a title="sinds het begin" href="https://www.oracle.com/technetwork/java/javase/overview/javahistory-timeline-198369.html">sinds het begin</a> van Java, en in versie 7 is er voor gezorgd dat er goede support is voor dynamische talen, zoals <a title="Groovy" href="https://www.groovy-lang.org/">Groovy</a>. Deze talen zullen nu quasi even performant zijn als Java zelf (<a href="https://en.wikipedia.org/wiki/Java_performance">no pun intended</a>). Verder zijn er een aantal zaken verbeterd betreffende class loaders, die voor minder bugs zorgen wanneer er meerdere van gebruikt worden, en er is nu ook een URLClassLoader.</p>
<p>Ook de ondersteuning voor parallelisme is nog wat beter geworden, met nieuwe klassen in het concurrency framework zoals de <a href="https://download.oracle.com/javase/7/docs/api/java/util/concurrent/ForkJoinPool.html">ForkJoinPool</a> en de <a href="https://download.oracle.com/javase/7/docs/api/java/util/concurrent/TransferQueue.html">TransferQueue</a>. Dit lijken mij goeie toevoegingen, maar de ondersteuning voor multithreading, met een hoog niveau van abstractie, was reeds erg goed. Ik bespreek dit raamwerk graag nog uitgebreider in een toekomstige blogpost. Multithreading zal zeker nog aan belang winnen in de toekomst, wanneer we meer en meer cores in onze computers krijgen.</p>
<p>Wat IO en netwerken betreft, zijn er voorts nog een aantal interessante toevoegingen, zoals een vernieuwing van de IO api (New IO: &#8220;NIO&#8221;), scp en sctp ondersteuning, gebruik van windows vista ipv6 en, last but not least: TLS 1.2 (ook wel SSL 3.3 genoemd).</p>
<p>Voor de security mensen: Elliptic Curve Cryptography is nu out-of-the-box beschikbaar.</p>
<p>En dan één van mijn stokpaardjes: de client, en Swing! Er is nu een nieuwe rendering-pipeline voor Java2D, waardoor een aantal features van moderne gpu&#8217;s ter beschikking komen te staan. Verder is er ondersteuning voor translucente en onregelmatig gevormde vensters, een <a href="https://download.oracle.com/javase/tutorial/uiswing/lookandfeel/nimbus.html">nieuwe Look and Feel</a>, en een nieuwe sound synthesizer. En ten slotte, zoals gewoonlijk, zijn een aantal zaken van <a title="SwingLabs" href="https://swinglabs.org/">SwingLabs</a> gemigreerd naar de standaard Swing api.</p>
<p>Tot zover de &#8216;saaiere&#8217; vernieuwingen; de echte vraag die echter op ieders lippen ligt, is natuurlijk: Wat zijn de nieuwe dingen die we kunnen doen als programmeur? <em>Give us the language features!</em></p>
<p>Een eerste kleine verbetering, is de mogelijkheid om Strings te gebruiken in een switch statement. Persoonlijk vind ik dit niet supernuttig, dus ik ga er ook geen voorbeeld van geven. Volgens mij zijn <a href="https://download.oracle.com/javase/tutorial/java/javaOO/enum.html">enums</a> veel beter geschikt om &#8216;of-of-of&#8217; constructies op poten te zetten, en is een goed uitgedacht design, gebruik makende van <a title="Polymorfisme" href="https://en.wikipedia.org/wiki/Subtyping">polymorfisme</a> en <a href="https://en.wikipedia.org/wiki/Dynamic_dispatch">dynamische binding</a>, meestal zowiezo een beter alternatief. Maar goed, het was een zinloze beperking, en het is goed dat deze nu is weggewerkt.</p>
<p>Next! Naast hexadecimale, octale en (gewone) decimale getallen, komt er nu ook een voorstellingswijze voor binaire getallen: ik moet zeggen: in quasi alle gevallen: <strong>blijf er van weg</strong>! Wat wel interessant is, is dat men nu underscores in getallen kan plaatsen om de leesbaarheid te verhogen. Zo is b.v. 1_000_000 vanaf nu een correcte en beter leesbare voorstellingswijze voor het getal 1000000. Ook in de andere voorstellingswijzen, en in floating point getallen, kan men ze gebruiken. Een getal moet wel nog altijd met een cijfer starten en eindigen.</p>
<p>Nog een kleine, eenvoudige verbetering is type inferentie bij het aanroepen van de constructor van generische klassen. Stel: je declareert een List&lt;String&gt; en je wil deze lijst initialiseren als een arraylist. Vroeger moest je dan als volgt de constructor aanroepen: new ArrayList&lt;String&gt;(). Met type inferentie wordt dit gewoon: new ArrayList&lt;&gt;(). De compiler is dus eindelijk slim genoeg geworden om te raden welk type je wou maken. Bemerk dat er nog steeds een diamandje &#8220;&lt;&gt;&#8221; nodig is, anders heb je een raw type. Vandaar dat men deze verbetering &#8220;<strong>diamond</strong>&#8221; heeft gedoopt. Eenvoudig en handig.</p>
<p>Een iets minder voor de hand liggende taaluitbreiding, is automatic resource management (ARM). De standaard manier van werken om een InputStream of File terug vrij te geven in geval van onverwachte gebeurtenissen, is dit in een finally clausule te zetten ( finally { file.close(); } ). Dit kan echter problemen opleveren wanneer je meerdere close-statements moet uitvoeren en de eerste close-methode zelf een foutmelding geeft, waardoor de erop volgende close-statements niet meer worden uitgevoerd. De nieuwe manier van werken, is de resources aan te maken in een statement, ingesloten in haakjes, volgende op het &#8216;try&#8217;-keyword. Een beetje zoals de declaratie van de teller in een for-statement. Bijgevolg krijg je dan iets als volgt: try (InputStream i = &#8230;; OutputStream o = &#8230;) {&#8230;} finally {/*niet meer nodig*/}. Achter de schermen zou dit dan werken alsof men recursieve try-finally statements gebruikt om alle mogelijke fouten op te vangen (dus de eerste close zit nog in een extra try blok, gevolgd door een finally block met daarin de tweede close; het geheel van deze try-finally zit op zijn beurt in het finally blok van de uit te voeren code). Je kan je inbeelden dat, als je dit manueel moest doen voor meer dan twee resources, er nogal wat <strong>boilerplate code</strong> aan te pas kwam; dit is dus een vrij nuttige feature.</p>
<p>De laatste taaluitbreiding die ik wil bespreken, heeft opnieuw met exception-handling te maken, ditmaal met het catch-blok. Bij het loggen van excepties die men niet onmiddellijk kan afhandelen, zal men deze vaak vangen, loggen, en dan opnieuw gooien. Vaak heeft men echter een try-blok dat verschillende soorten uitzonderingen kan gooien, waardoor men hetzelfde stukje code moet herhalen in een hele resem catch-blokken. Een superklasse gebruiken voor het catch-blok is vaak gevaarlijk, omdat er eventueel exceptie-types kunnen omvat worden waarvoor dit in eerste instantie niet de bedoeling was. Wanneer men b.v. het type &#8220;Exception&#8221; gebruikt, omvat dit alle mogelijke RuntimeExceptions, terwijl men misschien enkel een aantal niet-gerelateerde checked exceptions wou opvangen. De boilerplate code die hierbij komt kijken, kan men nu voor een deel schrappen, doordat men in de catch-expressie nu een lijst van types kan geven, gescheiden door verticale of-strepen ( &#8220;|&#8221; ). Men zou bijvoorbeeld kunnen zeggen: catch (NullPointerException | IndexOutOfBoundsException e) {log(e); throw e;}, in plaats van voor elk type uitzondering een apart catch-blok te maken. Ik had nog niet echt stilgestaan bij deze problematiek, maar ik denk wel dat het kan helpen om robuuste code te maken, voorzien van alle toeters en bellen om ze &#8220;enterprise-ready&#8221; te maken.</p>
<p>Meer uitleg betreffende de kleine, handige taaluitbreidingen, kan je vinden op de site van <a title="Project Coin" href="https://openjdk.java.net/projects/coin/">Project Coin</a>. Een aantal goeie voorbeelden kan je bekijken op een <a title="presentatie" href="https://blogs.sun.com/darcy/resource/JavaOne/J1_2010-ProjectCoin.pdf">presentatie</a> die een tijdje terug op <a title="JavaOne" href="https://www.oracle.com/javaone/index.html">JavaOne</a> is gegeven.</p>
<p>Tussen haakjes: tijdens mijn zoektocht ben ik ook de <strong>filosofie</strong> van Java nog eens tegengekomen, wat betreft het evolueren van de taal:</p>
<ul>
<li>Reading is more important than writing</li>
<li>Code should be a joy to read</li>
<li>The language should not hide what is happening</li>
<li>Code should do what it seems to do</li>
<li>Simplicity matters</li>
<li>A clear semantic model greatly boosts readability</li>
<li>Every “good” feature adds more “bad” weight</li>
<li>Sometimes it is best to leave things out</li>
</ul>
<p>Of deze principes tot nu toe trouw gevolgd zijn, laat ik over aan de lezer.</p>
<p>En als afsluiter: wat zit er niet in? Een aantal zaken zijn reeds lang in ontwikkeling, maar voorlopig blijkbaar toch nog iets te moeilijk: Doorgedreven <a title="modularisatie" href="https://www.jcp.org/en/jsr/detail?id=294">modularisatie</a> is o.a. al zeker tot Java 8 uitgesteld. Ook de veelgeplaagde, vaak gevraagde closures (<a title="Project Lambda" href="https://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html">Project Lambda</a>), zijn voorlopig nog even terug in de kast gestoken, alsook een meer directe <a title="taalondersteuning" href="https://mail.openjdk.java.net/pipermail/coin-dev/2009-March/001108.html">taalondersteuning</a> voor het collection framework. Meer geluk eind 2012?</p>
<pre></pre>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
