<?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>Open Source &#8211; Smals Research</title>
	<atom:link href="https://www.smalsresearch.be/tag/open-source/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.smalsresearch.be</link>
	<description></description>
	<lastBuildDate>Thu, 09 Apr 2026 12:23:58 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.smalsresearch.be/wp-content/uploads/2026/01/cropped-cropped-Smals_Research-32x32.png</url>
	<title>Open Source &#8211; Smals Research</title>
	<link>https://www.smalsresearch.be</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Souveraineté numérique</title>
		<link>https://www.smalsresearch.be/souverainete-numerique/</link>
					<comments>https://www.smalsresearch.be/souverainete-numerique/#comments</comments>
		
		<dc:creator><![CDATA[Joachim Ganseman]]></dc:creator>
		<pubDate>Fri, 18 Apr 2025 12:00:27 +0000</pubDate>
				<category><![CDATA[[FR]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[audit]]></category>
		<category><![CDATA[cloud computing]]></category>
		<category><![CDATA[confidentiality]]></category>
		<category><![CDATA[data center]]></category>
		<category><![CDATA[egov]]></category>
		<category><![CDATA[G-Cloud]]></category>
		<category><![CDATA[government]]></category>
		<category><![CDATA[interoperability]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[open standards]]></category>
		<category><![CDATA[Privacy]]></category>
		<category><![CDATA[Resilience]]></category>
		<category><![CDATA[Risk Management]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Society]]></category>
		<guid isPermaLink="false">/?p=22369</guid>

					<description><![CDATA[Nous assistons une fois de plus à l’émergence de questions fondamentales d’indépendance, de sécurité et d’autonomie stratégique : la souveraineté numérique est tendance.]]></description>
										<content:encoded><![CDATA[
<p><em><em>Dit artikel is ook beschikbaar in het</em> <a href="/digitale-soevereiniteit/">Nederlands</a>.</em></p>



<p>Les services numériques doivent non seulement être rentables, mais également robustes&nbsp;: ils doivent continuer à fonctionner si certains fournisseurs ou éléments de base font défaut pour une raison quelconque. Il ne s’agit pas uniquement d’une question purement technique, d’un enfermement propriétaire (<a href="https://fr.wikipedia.org/wiki/Enfermement_propri%C3%A9taire">vendor lock-in</a>) ou d’<a href="https://www.ibm.com/think/topics/multicloud">architecture multicloud</a>. Nous assistons une fois de plus à <a href="https://foreignpolicy.com/2025/03/31/europe-digital-sovereignty-colony-trump-asml-ai-eurostack/">l’émergence de questions fondamentales </a>d’indépendance, de sécurité et d’autonomie stratégique&nbsp;: la <em>souveraineté numérique</em> est tendance.</p>



<p>On comprend aisément pourquoi&nbsp;: avec un revirement politique d’une ampleur sans précédent, la réputation des États-Unis en tant que partenaire commercial fiable s’est volatilisée en un temps record. Du jour au lendemain, un <a href="https://www.reuters.com/world/us-aerospace-firm-maxar-disables-satellite-photos-ukraine-2025-03-07/">service peut être interrompu</a> ou des <a href="https://www.reuters.com/world/us/trump-tariffs-updates-world-braces-us-announce-duties-2025-04-01/">droits de douane peuvent être introduits</a> sans raison valable. Quiconque développe ou gère des infrastructures IT critiques en tremble rien qu’à l’idée. Et l’autonomie vaut soudain à nouveau son pesant d’or.</p>



<h2 class="wp-block-heading">Piliers stratégiques</h2>



<p>Le cœur de la souveraineté numérique réside dans la capacité à choisir, déployer et gérer des solutions technologiques sans dépendances externes étendues. Ces dépendances sont souvent plus profondes que nous ne le pensons, comme l’a démontré une expérience intéressante du<a href="https://www.youtube.com/watch?v=Rxuf1598bjc"> journaliste de Gizmodo, Kashmir Hill</a>, il y a quelques années. La dépendance technologique représente toujours un risque. Afin de le minimiser, nous pouvons entre autres&nbsp;:</p>



<ul class="wp-block-list">
<li>Investir dans le développement local et <em>open source</em> des technologies</li>



<li>Construire nous-même des infrastructures robustes et décentralisées</li>



<li>Développer nos propres compétences et capacités technologiques</li>



<li>Inclure des conditions d’interopérabilité, de migration de données, de flexibilité, d’interruption, etc. dans des clauses contractuelles et les marchés publics.</li>



<li>&#8230;</li>
</ul>



<p>En matière de développement logiciel pratique également, les choix qui favorisent l’agilité technologique présentent un avantage&nbsp;:</p>



<ul class="wp-block-list">
<li>Choisir des normes ouvertes et des API robustes et standardisées</li>



<li>Développer des solutions non seulement modulaires et évolutives, mais également agnostiques vis-à-vis du cloud</li>



<li>Implémenter des middleware capables de relier différentes technologies</li>



<li>Prêter attention à la portabilité, à la compatibilité multiplateforme et à la compatibilité entre navigateurs</li>



<li>…</li>
</ul>



<p><a href="https://publications.jrc.ec.europa.eu/repository/handle/JRC138657">La souveraineté sur les données</a> est également très importante. Une souveraineté numérique exige de conserver un contrôle maximal sur la collecte, le stockage, le traitement et la protection des données. Cela peut se faire en organisant le stockage et le traitement des données localement, de préférence en appliquant des mécanismes solides de <a href="https://fr.wikipedia.org/wiki/Gouvernance_des_donn%C3%A9es">gouvernance des données</a>, ou en les confiant à un tiers qui offre les garanties nécessaires et opère dans le cadre d’une <a href="https://commission.europa.eu/law/law-topic/data-protection/international-dimension-data-protection/adequacy-decisions_en">législation compatible</a>.</p>



<p>La Belgique se débrouille plutôt bien en matière d’autonomie infrastructurelle, avec le <a href="https://gcloud.belgium.be">cloud gouvernemental G-Cloud</a> et le réseau <a href="https://www.belnet.be/">Belnet</a>, entre autres.</p>



<h2 class="wp-block-heading">Le rôle de l’<em>open source</em></h2>



<p>Les technologies <em>open source</em>, en tant que <em>vecteurs</em> d’indépendance technologique, sont des éléments fondamentaux de la souveraineté numérique. Elles offrent une totale transparence du code, permettent la modification ou le propre développement, et diminuent la dépendance vis-à-vis des géants technologiques étrangers.</p>



<p>Cependant, cela a également un coût. L’utilisation de logiciels <em>open source</em> et de normes ouvertes implique de fournir soi-même l’ensemble du support, de la formation, des mises-à-jour, de la compatibilité, du débogage, etc. En échange de l’autonomie, il faut inclure un éventail de tâches connexes. Cela implique notamment un investissement dans la gestion active, ainsi que la maintenance et le développement des connaissances. Les acteurs commerciaux proposant des solutions propriétaires s’en chargent généralement.</p>



<p>Devenir totalement autonome est donc généralement impossible. Il existe un cas d’étude bien connu, celui de la ville de Munich, qui a ambitieusement <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/document/munichs-long-history-open-source-public-administration">basculé en 2006 vers un environnement Linux développé en interne</a>, mais qui, en raison de problèmes persistants de compatibilité et de l’augmentation des coûts de gestion qui en découle, a mis fin au programme en 2017 pour revenir à un environnement Microsoft standardisé.</p>



<h2 class="wp-block-heading">Chez nos voisins</h2>



<p>L’Allemagne est une fervente partisane de la souveraineté numérique depuis longtemps. L’<em><a href="https://osb-alliance.de/ueber-uns/was-ist-die-osb-alliance">Open Source Business Alliance</a></em> allemande utilise même le terme dans son slogan. L’expérience munichoise a donné naissance à l’actuel <em><a href="https://opensource.muenchen.de/">Open Source Programme Office</a></em> de la ville. Le niveau fédéral allemand encourage également l’indépendance technique, notamment&nbsp;:</p>



<ul class="wp-block-list">
<li>Des projets propres tels que <em><a href="https://scs.community/">Sovereign Cloud Stack</a></em> (actuellement <a href="https://www.sovereigncloudstack.org/">en transformation</a> après la fin du financement),</li>



<li>Le <em><a href="https://www.sovereign.tech/">Sovereign Tech Fund</a></em>, qui fournit des fonds pour maintenir les composants <em>open source</em> essentiels,</li>



<li>Le <em><a href="https://zendis.de/">Zentrum Digitale Souveränität</a></em> (ZenDis), qui aide les gouvernements à réduire leurs dépendances technologiques.</li>
</ul>



<p>Ce dernier investit également avec succès dans deux projets propres&nbsp;:</p>



<ul class="wp-block-list">
<li>La plateforme <a href="https://opencode.de/">OpenCode</a>, où les services publics peuvent publier et partager leur code avec d’autres,</li>



<li>L’environnement de travail administratif <a href="https://opendesk.eu/en/">OpenDesk</a>, qui inclut également des options typiques pour les entreprises telles que l’authentification unique et les intégrations entre les réunions, les «&nbsp;chats&nbsp;», le calendrier et les courriers électroniques.<br></li>
</ul>



<p>La France n’est pas en reste non plus. Plusieurs initiatives en faveur de la souveraineté numérique sont menées par la Direction interministérielle du Numérique (<a href="https://www.numerique.gouv.fr/dinum/">DINUM</a>). Ils comptent également leur propre dépôt sous la forme de <a href="https://code.gouv.fr/fr/">code.gouv.fr</a>. En outre, ils développent de manière proactive de nouvelles applications dans leur propre <a href="https://beta.gouv.fr/">incubateur</a>. Cela a donné naissance à des projets tels que <a href="https://lasuite.numerique.gouv.fr">La Suite Numérique</a>, une suite <em>enterprise level</em> de bureautique qui offre des fonctionnalités telles que le chat vidéo, les webinaires et le transfert de fichiers, et qui est en cours d’extension pour inclure des traitements de texte et des tableurs. La France s’est également engagée dans une <a href="https://www.economie.gouv.fr/securite-performance-souverainete-strategie-cloud">stratégie de cloud computing la plus indépendante possible</a> et, tout aussi important, elle s’efforce de motiver et de former ses fonctionnaires par le biais de la <a href="https://code.gouv.fr/fr/bluehats/">communauté des Blue Hats</a>. Du côté des entreprises, l’union des entreprises du logiciel libre et du numérique ouvert (<a href="https://cnll.fr/">CNLL</a>) s’est engagé en faveur de la souveraineté numérique.</p>



<p>Ce qui est frappant à la fois avec l’<a href="https://opendesk.eu/">OpenDesk</a> allemand et <a href="https://lasuite.numerique.gouv.fr">La Suite Numérique</a> française, c’est qu’ils sont tous deux également disponibles en anglais. Même dans le contexte gouvernemental, on prend de plus en plus conscience que les initiatives <em>open source</em> ont de meilleures chances de succès si l’on investit de manière proactive dans l’internationalisation. Plus prometteur encore, <a href="https://www.numerique.gouv.fr/dinum/">DINUM</a> et <a href="https://zendis.de/">ZenDis</a> ont commencé une collaboration concrète avec une <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-6403-note-worthy-collaboration-co-developing-a-note-taking-application/">application de prise de notes développée conjointement</a>. Cette dernière a été présentée lors du dernier <a href="https://fosdem.org/">FOSDEM</a>, la grand-messe annuelle des développeurs <em>open source</em> à Bruxelles, où les <a href="https://fosdem.org/2025/schedule/track/government-collaboration/">collaborations gouvernementales étaient à l’honneur</a>.</p>



<p>Le tandem franco-allemand est un signe prometteur de la volonté de l’Europe de s’unir pour promouvoir la souveraineté numérique. Nous savons déjà que les <a href="https://www.numerique.gouv.fr/espace-presse/premiers-succes-cooperation-franco-allemande-administration-numerique-souveraine-collaboration-trilaterale-avec-royaume-des-pays-bas-signature-nouvelle-declaration-dintention-commune/">Pays-Bas souhaitent se joindre</a> à cette collaboration. En effet, le <a href="https://ibestuur.nl/artikel/actie-nodig-om-de-digitale-soevereiniteit-van-nederland-en-europa-te-versterken/">débat social</a> y est également bien vivant, même à la Seconde Chambre, avec des discussions sur les <a href="https://ecp.nl/argumentenkaart-niet-europese-clouddiensten-overhandigd-aan-tweede-kamer/">services cloud</a> ou le <a href="https://tweakers.net/nieuws/233008/tweede-kamer-wil-unaniem-dat-sidn-nl-domeininfrastructuur-niet-naar-aws-overzet.html">DNS</a>. L’Organisation néerlandaise pour la recherche scientifique appliquée (<a href="https://www.tno.nl/en/importance-digital-sovereignty/">TNO</a>) a publié un <a href="https://publications.tno.nl/publication/34642268/o5remY/TNO-2024-R10300.pdf">long rapport sur la souveraineté numérique</a>, les <a href="https://www.uu.nl/sites/default/files/Moerel%2C%20Timmers%20%282.0%29%20-%20Preadvies%20Staatsrechtconferentie%202020.pdf">universités en font un sujet de discussion</a> et le <a href="https://dutchcloudcommunity.nl/digitale-soevereiniteit/">monde des affaires</a> y prête également attention. La souveraineté numérique est à l’ordre du jour à <a href="https://www.binnenlandsbestuur.nl/digitaal/experts-slaan-alarm-over-soevereiniteit">tous les niveaux de gouvernement</a>.</p>



<h2 class="wp-block-heading">Le rôle de l’Europe</h2>



<p>L’Union européenne a un intérêt stratégique évident dans la souveraineté (numérique). Les éléments clés à cet égard sont le récent <a href="https://digital-markets-act.ec.europa.eu/index_en">Digital Markets Act (DMA)</a> et le <a href="https://digital-strategy.ec.europa.eu/en/policies/digital-services-act-package">Digital Services Act (DSA)</a>. Ces deux cadres législatifs visent à limiter le pouvoir des géants technologiques étrangers et à rendre le «&nbsp;terrain de jeu&nbsp;» plus équitable et transparent pour les entreprises européennes. L’UE souhaite ainsi renforcer son autonomie stratégique en établissant des règles claires en matière de gestion des données et des plateformes, rendant les États membres européens moins vulnérables aux dépendances extérieures. Le <a href="https://digital-strategy.ec.europa.eu/en/policies/cybersecurity-act">Cybersecurity Act</a> et la <a href="https://eur-lex.europa.eu/eli/dir/2022/2555/oj/">directive NIS2</a> devraient garantir que la sécurité et la fiabilité ne soient pas compromises.</p>



<p class="has-text-align-left">L’UE entreprend également de <a href="https://www.europarl.europa.eu/RegData/etudes/BRIE/2020/651992/EPRS_BRI(2020)651992_EN.pdf">nombreuses initiatives pertinentes</a>, mais toutes ne décollent pas tout aussi facilement. La fragmentation européenne est une vieille plaie. Les petits projets restent souvent petits et, une fois le financement terminé, ils se transforment en <em><a href="https://fr.wikipedia.org/wiki/Logiciel_abandonn%C3%A9">abandonware</a></em>. Par exemple, il est impossible de savoir si la nouvelle <em><a href="https://europeanopensource.academy/">European Open Source Academy</a></em> survivra à la fin de son cycle de financement en 2027. D’autre part, les consortiums à grande échelle ont de nombreux problèmes de coordination et de contrôle. Le projet <a href="https://gaia-x.eu/">GAIA-X</a> a ainsi acquis la réputation d’être <a href="https://blog.okfn.org/2025/02/11/open-source-policy-and-europes-digital-sovereignty-key-takeaways-from-the-eu-open-source-policy-summit/">plus une histoire de mémos que de démos</a>, si bien que les nouveaux projets tels qu’<a href="https://openeurollm.eu/">OpenEuroLLM</a> sont également accueillis avec un certain scepticisme. Le déploiement des <em><a href="https://digital-strategy.ec.europa.eu/en/policies/data-spaces">European Data Spaces</a></em> dans divers domaines devrait favoriser la souveraineté sur les données. Cela <a href="https://health.ec.europa.eu/ehealth-digital-health-and-care/european-health-data-space-regulation-ehds_en">deviendra obligatoire</a> pour la santé (EHDS), qui pourrait insuffler un nouvel élan. Cela ne suffit cependant pas à apaiser les inquiétudes&nbsp;: le <a href="https://www.euro-stack.info/">rapport complet EuroStack</a> de la <em>Bertelsmann Stiftung</em> présente même à l’UE une vision plus ambitieuse sur un plateau d’argent.</p>



<p>Sous l’égide de l’<a href="https://interoperable-europe.ec.europa.eu/">Europe Interopérable</a>, on retrouve l’<em>Open Source Observatory and Repository</em> (<a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor">OSOR</a>), en plus de <em><a href="https://interoperable-europe.ec.europa.eu/collection/public-sector-tech-watch">Public Sector Techwatch</a></em> et <em><a href="https://interoperable-europe.ec.europa.eu/collection/govtechconnect/">GovTech Connect</a></em>. Ils surveillent l’utilisation de l’<em>open source</em> dans les administrations gouvernementales européennes depuis plus de 15 ans maintenant, et encouragent les partenariats et la réutilisation. L’<em><a href="https://interoperable-europe.ec.europa.eu/eu-oss-catalogue/solutions">Open Source Solutions Catalogue</a></em> récemment lancé devrait permettre aux pays de réutiliser plus facilement les solutions des uns et des autres. Ils publient également des <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/reports-and-guidelines">rapports</a>, des <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/case-studies">études de cas</a>, des <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/oss-repositories">catalogues nationaux</a> (dans lesquels nous trouvons <a href="https://www.ict-reuse.be/">ict-reuse.be</a>) et une <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/osor-newsletters">lettre d’information</a>. Les gouvernements qui souhaitent mettre en place leur propre <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/ospos-oss-governance"><em>Open Source Program Office</em> (OSPO)</a> afin de contribuer activement aux projets <em>open source</em> tels que <a href="https://interoperable-europe.ec.europa.eu/collection/ec-ospo">celui de l’UE</a>, y trouvent le soutien nécessaire. Les <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/news/dutch-digitalisation-minister-announces-ospo-creation">Pays-Bas</a> sont déjà convaincus. Si les autorités belges veulent contribuer visiblement à la souveraineté numérique, voilà une excellente occasion.</p>



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



<p>La souveraineté numérique est plus qu’un choix technique. C’est une stratégie continue pour retrouver un pouvoir d’agir dans un monde numérique hautement interconnecté où les éléments fondamentaux peuvent soudainement changer. Nous ne voulons pas nous contenter de consommer la technologie, mais aussi la façonner, la comprendre et la contrôler activement. Cela nous permettrait de réduire les dépendances externes et les risques qui en découlent. La pensée et la coopération européennes offrent des possibilités de synergies.</p>



<p><a id="_msocom_1"></a>L’autonomie technologique nécessite un écosystème technologique sain. Une attention constante au capital humain et au développement des connaissances est indispensable. Pour y parvenir de manière durable, les initiatives de soutien doivent bénéficier des ressources nécessaires&nbsp;:</p>



<ul class="wp-block-list">
<li>Développer de manière proactive des alternatives technologiques, qui anticipent la demande,</li>



<li>Participer à l’échange de connaissances, à des évènements et réseauter, avec des pairs, des institutions du savoir, des pays voisins, avec l’UE, etc.</li>



<li>Investir ou participer activement aux solutions <em>open source</em> existantes que l’on réutilise,</li>



<li>Construire des communautés autour de projets propres,</li>



<li>Investir dans un design attrayant et l’intuitivité des solutions propres,</li>



<li>Rendre sa propre solution disponible en dehors de ses murs&nbsp;: publier en <em>open source</em>, <a href="https://yml.publiccode.tools">intégrer dans des catalogues</a>, ajouter une documentation et une traduction anglaise, etc.</li>



<li>Travailler sur la notoriété de la marque&nbsp;: sites web, promotion, marketing, salons professionnels, médias (sociaux), etc.</li>



<li>&#8230;</li>
</ul>



<p>Les personnes intéressées par ce thème peuvent suivre les organisations et les initiatives mentionnées dans cet article sur les médias sociaux ou à travers leurs lettres d’information. Pour une analyse approfondie, le <a href="https://www.euro-stack.info/">rapport EuroStack</a> mentionné ci-dessus est intéressant. Si vous cherchez des alternatives pour les dépendances dans vos propres projets, <a href="https://european-alternatives.eu/">european-alternatives.eu</a>, <a href="https://euro-stack.com/">euro-stack.com</a> ou <a href="https://alternativeto.net/">alternativeto.net</a> sont de bons points de départ. Enfin, la souveraineté numérique est un effort d’équipe, n’hésitez donc surtout pas à partager d’autres sources, projets ou liens intéressants dans les commentaires ci-dessous&nbsp;!</p>



<p>______________________</p>



<p><em>Ce post est une contribution de Joachim Ganseman, consultant IT chez Smals Research. Cet article est écrit en son nom propre et n’impacte en rien le point de vue de Smals.</em></p>


]]></content:encoded>
					
					<wfw:commentRss>https://www.smalsresearch.be/souverainete-numerique/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Digitale Soevereiniteit</title>
		<link>https://www.smalsresearch.be/digitale-soevereiniteit/</link>
		
		<dc:creator><![CDATA[Joachim Ganseman]]></dc:creator>
		<pubDate>Fri, 04 Apr 2025 14:39:21 +0000</pubDate>
				<category><![CDATA[[NL]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[audit]]></category>
		<category><![CDATA[cloud computing]]></category>
		<category><![CDATA[confidentiality]]></category>
		<category><![CDATA[data center]]></category>
		<category><![CDATA[egov]]></category>
		<category><![CDATA[G-Cloud]]></category>
		<category><![CDATA[government]]></category>
		<category><![CDATA[interoperability]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[open standards]]></category>
		<category><![CDATA[Privacy]]></category>
		<category><![CDATA[Resilience]]></category>
		<category><![CDATA[Risk Management]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Society]]></category>
		<guid isPermaLink="false">/?p=22224</guid>

					<description><![CDATA[We zien vandaag fundamentele kwesties rond onafhankelijkheid, veiligheid en strategische autonomie opnieuw ter sprake komen: Digitale Soevereiniteit is hot.]]></description>
										<content:encoded><![CDATA[
<p><em>Cet article est aussi disponible <a href="/souverainete-numerique/">en français</a>.</em></p>



<p>Digitale dienstverlening moet niet alleen kostenefficiënt zijn, maar ook robuust: het moet blijven werken als bepaalde toeleveranciers of bouwblokken het laten afweten, om welke reden dan ook. Dat is niet alleen een louter technisch vraagstuk van <a href="https://nl.wikipedia.org/wiki/Vendor_lock-in">vendor lock-in</a> of <a href="https://www.ibm.com/think/topics/multicloud">multicloud architectuur</a>. We zien fundamentele kwesties rond onafhankelijkheid, veiligheid en strategische autonomie <a href="https://foreignpolicy.com/2025/03/31/europe-digital-sovereignty-colony-trump-asml-ai-eurostack/">opnieuw ter sprake komen</a>: <em>Digitale Soevereiniteit</em> is hot.</p>



<p>De aanleiding is niet ver te zoeken: met een beleidsomslag van jewelste is de reputatie van de VS als betrouwbare handelspartner in recordtempo verdampt. Zonder aanleiding kan van de ene dag op de andere een <a href="https://www.reuters.com/world/us-aerospace-firm-maxar-disables-satellite-photos-ukraine-2025-03-07/">dienstverlening stopgezet</a>, of een <a href="https://www.reuters.com/world/us/trump-tariffs-updates-world-braces-us-announce-duties-2025-04-01/">handelstarief ingevoerd</a> worden. Wie kritische infrastructuur en IT ontwikkelt of beheert, trekt lijkbleek weg van het idee alleen al. En zo is zelfredzaamheid plots weer goud waard.</p>



<h2 class="wp-block-heading">Strategische pijlers</h2>



<p>De kern van digitale soevereiniteit ligt in het kunnen kiezen, implementeren en beheren van technologische oplossingen zonder verregaande externe afhankelijkheden. Die afhankelijkheden zitten dieper dan we vaak denken, zoals enkele jaren geleden nog gedemonstreerd in een interessant <a href="https://www.youtube.com/watch?v=Rxuf1598bjc">experiment van Gizmodo journaliste Kashmir Hill</a>. Technologische afhankelijkheid vormt altijd een risico. Om dat te minimaliseren kunnen we onder andere:</p>



<ul class="wp-block-list">
<li>Investeren in lokale en open-source technologie-ontwikkeling</li>



<li>Zelf robuuste, gedecentraliseerde infrastructuren opbouwen</li>



<li>Eigen technologische vaardigheden en capaciteiten uitbouwen</li>



<li>Voorwaarden qua interoperabiliteit, data-migratie, flexibiliteit, stopzetting, … opnemen in contractuele clausules en openbare aanbestedingen</li>



<li>&#8230;</li>
</ul>



<p>Ook bij praktische software-ontwikkeling hebben keuzes die technologische wendbaarheid bevorderen een streepje voor:</p>



<ul class="wp-block-list">
<li>Verkies open standaarden en robuuste, gestandaardiseerde APIs</li>



<li>Ontwikkel niet alleen modulair en schaalbaar maar ook cloud-agnostisch</li>



<li>Implementeer eventueel middleware die verschillende technologieën kan overbruggen</li>



<li>Besteed aandacht aan portabiliteit, cross-platform en cross-browser compatibiliteit</li>



<li>…</li>
</ul>



<p>Daarnaast is ook <a href="https://publications.jrc.ec.europa.eu/repository/handle/JRC138657">data-autonomie</a> van groot belang. Zo vereist digitale soevereiniteit dat men maximale controle over data-verzameling, -opslag, -verwerking en -bescherming behoudt. Dat kan door de data-opslag en -verwerking lokaal te organiseren, liefst met toepassing van degelijke <a href="https://en.wikipedia.org/wiki/Data_governance">data governance</a> mechanismes, of door ze bij een derde partij onder te brengen die de nodige garanties biedt en tenminste onder een <a href="https://commission.europa.eu/law/law-topic/data-protection/international-dimension-data-protection/adequacy-decisions_en">compatibele wetgeving</a> opereert.</p>



<p>Het mag gerust gezegd worden dat België het op het vlak van infrastructurele autonomie, met onder andere de <a href="https://gcloud.belgium.be">overheidscloud Gcloud</a> en <a href="https://www.belnet.be/">Belnet</a>, best goed doet.</p>



<h2 class="wp-block-heading">De rol van open-source</h2>



<p>Open-source technologieën zijn, als <em>enablers</em> van technologische onafhankelijkheid, fundamentele bouwstenen voor digitale soevereiniteit. Ze bieden volledige transparantie van code, geven de mogelijkheid tot aanpassing of eigen ontwikkeling, en ze verminderen de afhankelijkheid van buitenlandse technologiereuzen.</p>



<p>Dat heeft echter ook een kostenplaatje. Wie in eigen beheer open-source software en open standaarden wil aanwenden, moet ook zelf voorzien in alle ondersteuning, opleiding, upgrades, compatibiliteit, eventueel debuggen, etc. In ruil voor autonomie moet je een heel takenpakket mee opnemen in de marge. Dat impliceert dat je moet willen investeren in actief beheer, onderhoud en kennisopbouw. Commerciële spelers met bedrijfseigen oplossingen ontzorgen je daar meestal van.</p>



<p>“All the way” zelfvoorzienend worden is daarom meestal onhoudbaar. Een bekende case studie is die van de stad München, die vanaf 2006 ambitieus <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/document/munichs-long-history-open-source-public-administration">overschakelde naar een zelf ontwikkelde Linux-omgeving</a>, maar omwille van aanslepende compatibiliteitsproblemen en de daarmee gepaard gaande oplopende beheerskosten, in 2017 de stekker uit het programma trok en opnieuw voor een gestandaardiseerde Microsoft-omgeving koos.</p>



<h2 class="wp-block-heading">In de buurlanden</h2>



<p>Duitsland draagt het idee van digitale soevereiniteit dus al langer een warm hart toe. De Duitse <a href="https://osb-alliance.de/ueber-uns/was-ist-die-osb-alliance">Open Source Business Alliance</a> zet de term zelfs in hun slogan. De ervaring van München evolueerde naar het huidige <a href="https://opensource.muenchen.de/">Open Source Programme Office</a> van de stad. Het Duitse federale niveau moedigt technische onafhankelijkheid ook aan, met onder andere:</p>



<ul class="wp-block-list">
<li>Eigen projecten zoals <a href="https://scs.community/">Sovereign Cloud Stack</a> (lijkt momenteel <a href="https://www.sovereigncloudstack.org/">in transformatie</a> na afloop financiering),</li>



<li>Het <a href="https://www.sovereign.tech/">Sovereign Tech Fund</a>, dat financiering voorziet om kritische open-source componenten te onderhouden,</li>



<li>Het <a href="https://zendis.de/">Zentrum Digitale Souveränität</a> (ZenDis), dat overheden ondersteunt bij de afbouw van technologische afhankelijkheden.</li>
</ul>



<p>Die laatste investeert ook met succes in 2 eigen projecten:</p>



<ul class="wp-block-list">
<li>Het platform <a href="https://opencode.de/">OpenCode</a> waar overheidsdiensten hun code kunnen publiceren en delen met anderen,</li>



<li>De administratieve werkomgeving <a href="https://opendesk.eu/en/">OpenDesk</a> , die ook typische enterprise-opties omvat zoals Single Sign-on en integraties tussen meetings, chats, kalender, en email.</li>
</ul>



<p>Frankrijk zit evenmin stil. Verschillende initiatieven voor digitale soevereiniteit worden bij onze zuiderburen getrokken door <a href="https://www.numerique.gouv.fr/dinum/">DINUM</a>, de centrale interministeriële dienst voor digitalisering. Met <a href="https://code.gouv.fr/fr/">code.gouv.fr</a> hebben zij ook hun eigen code repository. Daarnaast ontwikkelen ze zelf proactief nieuwe toepassingen in een eigen <a href="https://beta.gouv.fr/">incubator</a>. Dat resulteerde onder andere in <a href="https://lasuite.numerique.gouv.fr/en">La Suite Numérique</a>, een <em>enterprise-level</em> kantoorsuite die functionaliteiten zoals videochat, webinars, en file transfer aanbiedt, en nu wordt uitgebreid met tekstverwerkers en spreadsheets. Frankrijk zet eveneens in op een <a href="https://www.economie.gouv.fr/securite-performance-souverainete-strategie-cloud">maximaal onafhankelijke cloud-strategie</a>, en minstens zo belangrijk, werken ze aan motivatie en kennis bij hun overheidsmedewerkers via de <a href="https://code.gouv.fr/fr/bluehats/">Blue Hats community</a>. Vanuit het bedrijfsleven zet <a href="https://cnll.fr/">CNLL</a> zich in voor digitale soevereiniteit.</p>



<p>Opvallend aan zowel het Duitse <a href="https://opendesk.eu/">OpenDesk</a> als het Franse <a href="https://lasuite.numerique.gouv.fr/en">La Suite Numérique</a>, is dat beide ook beschikbaar zijn in het Engels. Zelfs in overheidscontext is dus ondertussen het bewustzijn gegroeid dat open-source initiatieven betere slaagkansen hebben als men proactief investeert in internationalisering. Nog hoopgevender is dat <a href="https://www.numerique.gouv.fr/dinum/">DINUM</a> en <a href="https://zendis.de/">ZenDis</a> concreet zijn beginnen samenwerken. Op het laatste <a href="https://fosdem.org/">FOSDEM</a> evenement, de jaarlijks weerkerende hoogmis voor open-source developers in Brussel, stonden <a href="https://fosdem.org/2025/schedule/track/government-collaboration/">overheidssamenwerkingen in de kijker</a> en presenteerden ze een <a href="https://fosdem.org/2025/schedule/event/fosdem-2025-6403-note-worthy-collaboration-co-developing-a-note-taking-application/">tesamen ontwikkelde notitie-app</a>.</p>



<p>Deze Duits-Franse tandem is een veelbelovend teken dat, als het gaat over het bevorderen van digitale soevereiniteit, de wil alleszins bestaat om Europese krachten wat te bundelen. Er is alvast bekend dat <a href="https://www.numerique.gouv.fr/espace-presse/les-premiers-succ%C3%A8s-de-la-coop%C3%A9ration-franco-allemande-en-faveur-dune-administration-num%C3%A9rique-souveraine-ouvrent-la-voie-%C3%A0-une-collaboration-trilat%C3%A9rale-avec-le-royaume-des-pays-bas-%C3%A0-travers-la-signature-dune-nouvelle-d%C3%A9claration-dintention-commune/">Nederland wil aansluiten</a> bij hun samenwerking. Daar leeft de <a href="https://ibestuur.nl/artikel/actie-nodig-om-de-digitale-soevereiniteit-van-nederland-en-europa-te-versterken/">maatschappelijke discussie</a> immers ook, tot in de Tweede Kamer, met debatten over <a href="https://ecp.nl/argumentenkaart-niet-europese-clouddiensten-overhandigd-aan-tweede-kamer/">clouddiensten</a> of <a href="https://tweakers.net/nieuws/233008/tweede-kamer-wil-unaniem-dat-sidn-nl-domeininfrastructuur-niet-naar-aws-overzet.html">DNS</a>. Het onderzoeksinstituut <a href="https://www.tno.nl/nl/digitale-soevereiniteit/">TNO</a> publiceerde er een <a href="https://publications.tno.nl/publication/34642268/o5remY/TNO-2024-R10300.pdf">lijvig rapport over digitale soevereiniteit</a>, de <a href="https://www.uu.nl/sites/default/files/Moerel%2C%20Timmers%20%282.0%29%20-%20Preadvies%20Staatsrechtconferentie%202020.pdf">universiteiten agenderen het</a>, en ook het <a href="https://dutchcloudcommunity.nl/digitale-soevereiniteit/">bedrijfsleven</a> besteedt er aandacht aan. Op <a href="https://www.binnenlandsbestuur.nl/digitaal/experts-slaan-alarm-over-soevereiniteit">alle bestuursniveaus</a> ligt digitale soevereiniteit er op tafel.</p>



<h2 class="wp-block-heading">De rol van Europa</h2>



<p>De EU heeft een evident strategisch belang bij (digitale) soevereiniteit. Centrale elementen hierin zijn de recente <a href="https://digital-markets-act.ec.europa.eu/index_en">Digital Markets Act (DMA)</a> en <a href="https://digital-strategy.ec.europa.eu/en/policies/digital-services-act-package">Digital Services Act (DSA)</a>. Beide wetgevende kaders hebben tot doel om de macht van buitenlandse technologiereuzen te beperken en het speelveld voor Europese bedrijven gelijkwaardiger en transparanter te maken. Hiermee wil Europa haar strategische autonomie versterken door duidelijke regels te stellen rondom data- en platformbeheer, waardoor Europese lidstaten minder kwetsbaar worden voor externe afhankelijkheden. De <a href="https://digital-strategy.ec.europa.eu/en/policies/cybersecurity-act">Cybersecurity Act</a> en de <a href="https://eur-lex.europa.eu/eli/dir/2022/2555/oj/">NIS2-richtlijn</a> moeten erover waken dat daarbij niet aan veiligheid en betrouwbaarheid wordt ingeboet.</p>



<p class="has-text-align-left">Ze onderneemt daarnaast <a href="https://www.europarl.europa.eu/RegData/etudes/BRIE/2020/651992/EPRS_BRI(2020)651992_EN.pdf">tal van relevante initiatieven</a>, maar die komen niet allemaal even vlot van de grond. De Europese versnippering is een oud zeer. Kleine projecten blijven vaak klein, en eens de financiering afloopt, verworden ze tot <a href="https://en.wikipedia.org/wiki/Abandonware">abandonware</a>. Zo is het onvoorspelbaar of het net gestarte <a href="https://europeanopensource.academy/">European Open Source Academy</a> het einde van haar financieringsronde in 2027 zal overleven. Grootschalige consortia kennen dan weer heel wat problemen met coördinatie en sturing. Het <a href="https://gaia-x.eu/">GAIA-X</a> project heeft zo enigszins de reputatie gekregen als een verhaal van <a href="https://blog.okfn.org/2025/02/11/open-source-policy-and-europes-digital-sovereignty-key-takeaways-from-the-eu-open-source-policy-summit/">meer memo&#8217;s dan demo&#8217;s</a>, wat maakt dat ook nieuwe projecten zoals <a href="https://openeurollm.eu/">OpenEuroLLM</a> met enige scepsis onthaald worden. De uitrol van de <a href="https://digital-strategy.ec.europa.eu/en/policies/data-spaces">Europese Data Spaces</a> in verschillende domeinen moet data-autonomie bevorderen. Voor gezondheid (EHDS) <a href="https://health.ec.europa.eu/ehealth-digital-health-and-care/european-health-data-space-regulation-ehds_en">wordt deze verplicht</a>, wat misschien voor nieuw momentum kan zorgen. Maar dat is niet genoeg om de bezorgdheden weg te nemen: het lijvige <a href="https://www.euro-stack.info/">EuroStack rapport</a> van de Bertelsmann Stiftung stelt de EU zelfs op een dienblaadje een ambitieuzere visie voor.</p>



<p>Onder de paraplu van <a href="https://interoperable-europe.ec.europa.eu/">Interoperable Europe</a> vinden we naast <a href="https://interoperable-europe.ec.europa.eu/collection/public-sector-tech-watch">Public Sector Techwatch</a> en <a href="https://interoperable-europe.ec.europa.eu/collection/govtechconnect/">GovTech Connect</a> ook <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor">OSOR</a>, het Open Source Observatory and Repository, terug. Zij monitoren ondertussen al meer dan 15 jaar het gebruik van open-source in Europese overheidsadministraties, en moedigen samenwerkingsverbanden en hergebruik aan. Met de recent gelanceerde <a href="https://interoperable-europe.ec.europa.eu/eu-oss-catalogue/solutions">Open Source Solutions Catalogue</a> moet het gemakkelijker worden voor landen om elkaars oplossingen te hergebruiken. Daarnaast publiceren ze <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/reports-and-guidelines">rapporten</a>, <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/case-studies">case studies</a>, <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/oss-repositories">nationale catalogi</a> (waarin we <a href="https://www.ict-reuse.be/">ict-reuse.be</a> terugvinden) en een <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/osor-newsletters">nieuwsbrief</a>. Overheden die zelf een <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/ospos-oss-governance">Open Source Program Office (OSPO)</a> willen oprichten om actief bij te dragen aan open-source projecten, net zoals de <a href="https://interoperable-europe.ec.europa.eu/collection/ec-ospo">EU er een heeft</a>, vinden bij hen steun. <a href="https://interoperable-europe.ec.europa.eu/collection/open-source-observatory-osor/news/dutch-digitalisation-minister-announces-ospo-creation">Nederland</a> is alvast overtuigd. Als Belgische overheden zichtbaar willen bijdragen aan digitale soevereiniteit, ligt hier nog een uitgelezen kans.</p>



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



<p>Digitale soevereiniteit is meer dan een technische keuze. Het is een continue strategie om <em>agency </em>terug te winnen in een sterk geïnterconnecteerde digitale wereld waarvan fundamentele bouwblokken plots kunnen verschuiven. We willen niet alleen technologie consumeren, maar deze ook actief vormgeven, begrijpen en controleren. Zo beperken we externe afhankelijkheden en de risico&#8217;s die daarmee gepaard gaan. Europees denken en samenwerken biedt daarbij opportuniteiten voor synergieën.</p>



<p>Technologische autonomie vereist een gezond technologisch ecosysteem. Permanente aandacht voor menselijk kapitaal en kennisopbouw zijn een must. Om dat te doen slagen op een duurzame manier, verdienen ondersteunende initiatieven de nodige middelen:</p>



<ul class="wp-block-list">
<li>Proactief technologische alternatieven ontwikkelen, anticiperend op de vraag,</li>



<li>Participeren in kennisuitwisseling, evenementen en netwerken, met vakgenoten, kennisinstellingen, buurlanden, EU, &#8230;</li>



<li>Actief meewerken aan, of investeren in, bestaande open-source oplossingen die je zelf hergebruikt,</li>



<li>Communities uitbouwen rondom eigen projecten,</li>



<li>Investeren in aantrekkelijke vormgeving en gebruiksgemak van de eigen oplossingen,</li>



<li>Eigen oplossingen inzetbaar maken buiten de eigen muren: publiceren als open-source, <a href="https://yml.publiccode.tools">integreren in catalogi</a>, een Engelse vertaling en documentatie toevoegen,</li>



<li>Werken aan naambekendheid: websites, promotie, marketing, vakbeurzen, (social) media, &#8230;</li>



<li>&#8230;</li>
</ul>



<p>Wie interesse heeft om dit thema verder op te volgen, kan de in dit artikel vermelde organisaties en initiatieven volgen op sociale media of via hun nieuwsbrieven. Voor een <em>deep dive</em> is het bovenvermelde <a href="https://www.euro-stack.info/">EuroStack rapport</a> interessant. Om alternatieven te zoeken voor afhankelijkheden in je eigen projecten, zijn <a href="https://european-alternatives.eu/">european-alternatives.eu</a>, <a href="https://euro-stack.com/">euro-stack.com</a>, of <a href="https://alternativeto.net/">alternativeto.net</a> goede startpunten. Tot slot: digitale soevereiniteit is een <em>team effort</em>, voel je daarom vrij om andere bronnen, projecten, of interessante links te delen in de commentaren hieronder!</p>



<p>______________________</p>



<p><em>Dit is een ingezonden bijdrage van Joachim Ganseman, IT consultant bij Smals Research. Dit artikel werd geschreven in eigen naam en neemt geen standpunt in namens Smals.</em></p>


]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Data quality en geografische gegevens</title>
		<link>https://www.smalsresearch.be/data-quality-en-geografische-gegevens/</link>
		
		<dc:creator><![CDATA[Vandy Berten]]></dc:creator>
		<pubDate>Mon, 09 Dec 2024 09:03:13 +0000</pubDate>
				<category><![CDATA[[NL]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[data quality]]></category>
		<category><![CDATA[GIS]]></category>
		<category><![CDATA[methodology]]></category>
		<category><![CDATA[Open Source]]></category>
		<guid isPermaLink="false">/?p=21631</guid>

					<description><![CDATA[Geografische gegevens gebruiken stelt ons in staat om de analyse van gegevenskwaliteit te verbeteren. Een voorbeeld met BeSt Address]]></description>
										<content:encoded><![CDATA[
<p><a href="/qualite-de-donnees-et-donnees-geographiques/">Version en français</a></p>



<p>Data quality management, regelmatig besproken in deze blog, bestaat vaak uit het verwerken (vergelijken, vergemakkelijken, transformeren, “fonetiseren”, enz.) van karakterketens: namen van mensen, ondernemingen, steden, straten, telefoonnummers, e-mailadressen, &#8230;</p>



<p>In deze blogpost nemen we een kijkje naar het soort problemen dat kan worden opgespoord wanneer data gekoppeld raken met geografische coördinaten (breedtegraden, lengtegraden), rekening houdend met open data van het project <a href="https://opendata.bosa.be/index.nl.html">BeSt Address</a> (Belgian Street Address), van de FOD BOSA, authentieke bron voor adressen in België. Dit project verzamelt en consolideert gegevens van de gewesten (<a href="https://datastore.brussels/web/urbis-download">UrbiS</a> voor het Brussels Gewest, het <a href="https://www.vlaanderen.be/digitaal-vlaanderen/onze-diensten-en-platformen/gebouwen-en-adressenregister">Adressenregister</a> voor Vlaanderen en <a href="https://geoportail.wallonie.be/catalogue/2998bccd-dae4-49fb-b6a5-867e6c37680f.html">ICAR</a> voor Wallonië), die op hun beurt adresgegevens ophalen die verzameld zijn door elke gemeente, de instantie die verantwoordelijk is voor de toewijzing van adressen. Een reeks CSV- of XML-bestanden kan hier worden gedownload met de officiële spelling en geografische coördinaten van elk adres in België.</p>



<p>Onze ervaring heeft ons geleerd dat de BeSt Address data veruit de meest kwalitatieve zijn in vergelijking met andere officiële bronnen die adressen bevatten (Rijksregister, Werkgeversregister, Kruispuntbank van Ondernemingen, enz.), ten minste de klassieke aspecten van datakwaliteit (consistentie van namen, afwezigheid van afkortingen, enz.), het resultaat van de enorme inspanningen van de teams in de gewesten en de FOD BOSA. Toch konden we een aantal anomalieën vinden die alleen geïdentificeerd konden worden door naar de geografische gegevens en ruimtelijke analyses te kijken.</p>



<p>De meeste geïdentificeerde anomalieën komen overeen met verkeerd geplaatste adressen (verkeerde coördinaten) of problematische postcodes. Opschoning kan alleen worden uitgevoerd door de entiteiten op het terrein, d.w.z. de gemeenten.</p>



<p>Merk op dat de anomalieën die hieronder worden gepresenteerd het resultaat zijn van een “academische” analyse. Deze is al besproken met een aantal mensen van de relevante instanties (gewesten, rijksregister, FOD BOSA, NGI, etc.), en sommige van deze afwijkingen worden aanvaardbaar geacht. Deze blogpost wil geen kritiek uiten op de kwaliteit van de data, maar simpelweg een methodologie presenteren en deze illustreren met een relevante databron.</p>



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



<p>Zoals in een <a href="/la-jointure-spatiale-la-cle-de-lanalytique-geographique/">vorige blogpost</a> is beschreven, bestaat België op het moment van schrijven uit 581 gemeenten (dit aantal zal de komende maanden afnemen na een reeks fusies van gemeenten). Elk van deze gemeenten bestaat uit een of meer postcodes (verbonden met een naam in Brussel en Vlaanderen), en elk van deze postcodes kan een of meer deelgemeenten of lokaliteiten bevatten (part of municipality in Wallonië, in BeSt Address-jargon).</p>



<p>Voor de onderstaande analyse baseerden we ons op de CSV-bestanden die beschikbaar zijn op <a href="https://opendata.bosa.be/">https://opendata.bosa.be/</a>, en voerden we vier soorten analyses uit:&nbsp;</p>



<ul class="wp-block-list">
<li>In de eerste analyse kijken we of alle busnummers op hetzelfde adres dicht bij elkaar liggen;</li>



<li>In de tweede vergelijken we de grenzen van de postcodes gedefinieerd door bpost (de Belgische postdienst) met de postcodes van adressn uit BeSt Adress;</li>



<li>In de derde analyse gaan we op zoek naar inconsistenties in straatnamen die geografisch dicht bij elkaar liggen (bv. een ‘rue Roi Albert I‘ naast een ’rue <strong>du</strong> Roi Albert I’);</li>



<li>In de vierde zoeken we naar geometrische afwijkingen in de vorm van een straat.</li>
</ul>



<h2 class="wp-block-heading">Inconsistentie van bussen</h2>



<p>Zoals <a href="/waarom-is-een-belgisch-adres-ingewikkeld/">eerder beschreven</a> bevat een adres altijd een &#8216;huisnummer&#8217;, dat verwijst naar het gebouw, en soms een &#8216; busnummer&#8217;, dat verwijst naar de wooneenheid binnen dat gebouw. In BeSt Address vinden we voor elk adres met een bus altijd een gelijkwaardig basisadres (zelfde straat, postcode, nummer) zonder bus. Laten we bijvoorbeeld zeggen dat de Fonsnylaan 20 twee bussen heeft, ‘bus 1’ en ‘bus 2’: we vinden drie items in BeSt Address: ‘Fonsnylaan 20’; ‘Fonsnylaan 20 bus 1’ en ‘Fonsnylaan 20 bus 2’. </p>



<p>Voor elk adres (straat, postcode, nummer) hebben we gecontroleerd of de coördinaten die bij de bussen horen niet abnormaal ver uit elkaar liggen. In de overgrote meerderheid van de gevallen hebben de verschillende bussen met hetzelfde nummer allemaal dezelfde coördinaten, maar dit is niet altijd het geval.</p>



<figure class="wp-block-image alignright"><a href="/wp-content/uploads/2024/11/2024-11-08_11h27_57.png"><img decoding="async" width="150" height="150" src="/wp-content/uploads/2024/11/2024-11-08_11h27_57-150x150.png" alt="" class="wp-image-21388"/></a></figure>



<p>Voor elk adres met busnummers schetsen we de ‘<em>minimum rotated rectangle</em>’ , d.w.z. de rechthoek met de minimale oppervlakte die alle punten omvat (de coördinaten van het ‘basis’-adres, voorgesteld door ‘/’, en die van elk van de bussen), waarbij elke rotatie van de rechthoek mogelijk is. Zo&#8217;n rechthoek die twee punten omvat zal een breedte van nul hebben en een lengte gelijk aan de afstand tussen de punten. In het geval van meerdere niet-uitgelijnde punten zullen beide afmetingen positief zijn.</p>



<p>De anomalieën werden voornamelijk gedetecteerd in Vlaanderen, met meer dan 100 gevallen. In Wallonië zijn de coördinaten van de verschillende bussen steeds gelijk aan de coördinaten van het basisadres. In Brussel werden slechts twee afwijkingen vastgesteld.</p>



<p>Om dit te illustreren nemen we twee voorbeelden, weergegeven in de figuur hieronder. Het eerste voorbeeld (Abdijstraat, 41 te 9140 Stekene) toont aan dat het basisadres (Abdijstraat, 41, voorgesteld door een ‘/’) zich op 11 kilometer van Abdijstraat, 41 bus 12 bevindt. We vonden bijna honderd zeer vergelijkbare voorbeelden.</p>



<p>Het tweede is een gevolg van het probleem dat in <a href="/waarom-is-een-belgisch-adres-ingewikkeld/">ons vorige artikel</a> werd geïllustreerd: om adressen tussen ‘1’ en ‘3’ te maken, kun je ze maken met huisnummers ‘1A’, ‘1B’, ‘1C’&#8230; (zonder busnummer), of ze allemaal ‘nummer 1’ noemen, maar met een busnummer ‘A’, ‘B’, ‘C’&#8230; In de ‘Diamantstraat’ in Diksmuide is (ongetwijfeld per ongeluk) een hybride keuze gemaakt: naast de 1 vinden we ‘1A’, ‘1B’, &#8230; ‘1F’, dan &#8230; ‘1 bus G’! Dit creëert een grote afstand tussen de 1 (basisadres) en de 1 (bus G).</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_12h48_05.png" target="_blank" rel="noopener"><img fetchpriority="high" decoding="async" width="1024" height="758" data-id="21346" src="/wp-content/uploads/2024/11/2024-11-07_12h48_05-1024x758.png" alt="" class="wp-image-21346" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h48_05-1024x758.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h48_05-300x222.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h48_05-768x568.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h48_05.png 1195w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_12h47_52-1.png" target="_blank" rel="noopener"><img decoding="async" width="1024" height="759" data-id="21347" src="/wp-content/uploads/2024/11/2024-11-07_12h47_52-1-1024x759.png" alt="" class="wp-image-21347" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h47_52-1-1024x759.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h47_52-1-300x222.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h47_52-1-768x569.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h47_52-1.png 1195w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>
</figure>



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



<p>In deze analyse vergelijken we <a href="https://bgu.bpost.be/assets/9738c7c0-5255-11ea-8895-34e12d0f0423_x-shapefile_3812.zip">de door bpost gedefinieerde postcodegrenzen</a>. Om dit te doen, kijken we voor elk BeSt-adres in welke bpost-polygoon het valt en selecteren we de adressen waarvoor er een inconsistentie is tussen de BeSt-postcode en de bpost-postcode.</p>



<p>Om nauwkeurigheidsproblemen van een punt dat precies op de grens ligt te voorkomen, verwijderen we een strook van 50 meter uit de contouren in de postcodes die door bpost zijn gedefinieerd.&nbsp;Een inconsistentie wordt daarom slechts geïdentificeerd wanneer een adres in een P1 postcode (volgens BeSt) eigenlijk in de polygoon van een P2 postcode (volgens bpost) ligt, met P1 ≠ P2.</p>



<p>In de onderstaande afbeeldingen kunnen we enkele van de geïdentificeerde voorbeelden zien. De rode lijn stelt de grens voor die overeenkomt met de postcode in kwestie, volgens bpost (6700 voor het hoofdvoorbeeld). Binnen deze lijn bevinden zich een groot aantal BeSt-adressen die bij dezelfde postcode horen. Deze adressen worden hier niet getoond om het beeld niet te overladen. De gekleurde stippen buiten de rode omlijning zijn dus adressen die BeSt associeert met de code in de titel, maar die volgens het postkantoor de postcode hebben uit de legende (6704 in het blauw, 6706 in het oranje voor de 1<sup>e</sup> voorbeeld).</p>



<p>Merk op dat de geregistreerde &#8216;uitwisselingen&#8217; altijd binnen dezelfde gemeente liggen (Aarlen voor het voorbeeld). Terwijl BeSt ervan uitgaat dat alle adressen in de gemeente Aarlen op 6700 liggen, gaat bpost er wel van uit dat een deel van het grondgebied op 6704 (Guirsch) of 6706 (Autelbas-Barnich) ligt, twee postcodes die BeSt niet kent.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_15h49_43.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="728" data-id="21353" src="/wp-content/uploads/2024/11/2024-11-07_15h49_43-1024x728.png" alt="" class="wp-image-21353" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h49_43-1024x728.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h49_43-300x213.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h49_43-768x546.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h49_43.png 1235w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_15h48_10-1.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="728" data-id="21354" src="/wp-content/uploads/2024/11/2024-11-07_15h48_10-1-1024x728.png" alt="" class="wp-image-21354" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h48_10-1-1024x728.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h48_10-1-300x213.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h48_10-1-768x546.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h48_10-1.png 1242w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_15h47_20.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="732" data-id="21352" src="/wp-content/uploads/2024/11/2024-11-07_15h47_20-1024x732.png" alt="" class="wp-image-21352" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h47_20-1024x732.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h47_20-300x214.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h47_20-768x549.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h47_20.png 1250w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_15h50_50.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="727" data-id="21350" src="/wp-content/uploads/2024/11/2024-11-07_15h50_50-1024x727.png" alt="" class="wp-image-21350" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h50_50-1024x727.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h50_50-300x213.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h50_50-768x545.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h50_50.png 1243w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>
</figure>



<p>Dit is niet alleen een kwestie van een bestand (Shapefile) dat niet up-to-date is op de website van de Post: de online <a href="https://www.bpost.be/nl/adresvalidatie-tool">adresvalidatietool van bpost</a> is consistent met de getoonde postcodes.</p>



<p>Tijdens sommige gesprekken kregen we te horen dat gemeenten de vrijheid hebben om de toewijzing van postcodes op hun grondgebied te wijzigen. Hierover bestaat echter geen consensus: in de “<a href="https://www.belgif.be/downloads/best/20211019_Gids_voor_het_vaststellen_en_toekennen_van_adressen.pdf">Gids voor het vaststellen en toekennen van adressen</a>”, staat dat “Postcodes en hun systematisering zijn echter eigendom van de dienstverlener van de universele postdienst, in voorkomend geval (&#8230;) bpost. Ze kunnen alleen worden toegekend en gewijzigd op basis van een voorstel van bpost en na een gemotiveerd advies van het BIPT en de goedkeuring van de minister overeenkomstig artikel 135 van de wet van 21 maart 1991. (Artikel 22)”.</p>



<p>We troffen iets meer dan 8000 anomalieën aan in Wallonië (op een totaal van 1,85 miljoen relevante adressen), ~ 11&nbsp;000 in Vlaanderen (op 3,83 miljoen) en een marginaal aantal in Brussel (op 860 000). Merk op dat sommige afwijkingen aanvaardbaar zijn, zoals gebouwen (kastelen, boerderijen, enz.) die ver van de voordeur liggen. BeSt lokaliseert het gebouw, maar de postcode komt overeen met die van de ingang.</p>



<h2 class="wp-block-heading">Inconsistentie van namen</h2>



<p>Voor deze analyse gaan we een &#8216;klassieke&#8217; benadering op basis van karakterketen combineren met een geografische benadering. We starten met het identificeren van de lijst van alle paren van aangrenzende straten (d.w.z. de ene heeft een adres op minder dan 100 meter van de andere). Vervolgens controleren we op kleine verschillen in straatnamen. We zien meestal twee situaties:</p>



<ul class="wp-block-list">
<li>Straten die verschillende gemeenten doorkruisen en in elke gemeente een andere schrijfwijze hebben: ‘Rue&nbsp;<strong>de</strong>&nbsp;Monténégro, 1060’, vs ‘Rue&nbsp;<strong>du</strong>&nbsp;Monténégro, 1190’;</li>



<li>Straten met twee verschillende schrijfwijzen binnen dezelfde gemeente: ‘Chaussée Brunehau<strong>lt</strong>’ of ‘Chaussée Brunehau<strong>t</strong>’, in 4452 in beide gevallen.</li>
</ul>



<p>Er zijn ook een paar fout-positieven: ‘Rue de Mars’ vs ‘Rue de Mai’.&nbsp;We schrappen namen uit onze vergelijkingen die identiek zijn op een geïsoleerde laatste letter na (“Hensellaan A” vs “Hensellaan B”), evenals namen waarbij slechts een cijfer verandert (‘5de Zijweg’ vs ‘6de Zijweg’).</p>



<p>Met betrekking tot de eerste situatie, waarbij de naam verandert wanneer men van de ene gemeente naar de andere gaat, is het betreurenswaardig dat er een gebrek aan consistentie is, wat in strijd is met artikel 5 van de <a href="https://www.ibz.rrn.fgov.be/fileadmin/user_upload/fr/rn/circulaires/BeSt_20201104_F.pdf">hierboven beschreven richtlijn</a>, waarin staat dat “[a]ls een weg zich uitstrekt over het grondgebied van meerdere gemeenten en die weg dezelfde naam behoudt, dan moeten die gemeenten erop toezien dat de spelling van die straatnaam in alle betrokken gemeenten dezelfde is”. De richtlijn is echter niet bindend, gemeenten kunnen dus een eigen spelling behouden.</p>



<figure class="wp-block-image alignright"><a href="/wp-content/uploads/2024/11/2024-11-08_09h31_07.png"><img loading="lazy" decoding="async" width="150" height="150" src="/wp-content/uploads/2024/11/2024-11-08_09h31_07-150x150.png" alt="" class="wp-image-21360"/></a><figcaption class="wp-element-caption"><span style="color: #999999;">Credit: Google StreetView</span></figcaption></figure>



<p>Het is echter de moeite waard om je af te vragen of de spelling die in BeSt wordt gebruikt (zoals doorgegeven door de gemeenten) echt de juiste is. Bijvoorbeeld, ‘Rue Walckiers’ in 1030 Schaarbeek is een uitbreiding van ‘Rue Walkiers’ in 1140 Evere. Het (enige) Schaarbeekse bord voor deze straat schrijft het echter als &#8230; ‘Rue Walkiers’! Hetzelfde geldt voor het (kleine) deel van de Tervuerenlaan in Oudergem, dat als dusdanig gespeld wordt in Sint-Pieters-Woluwe en op de straatnaambordjes in Oudergem, maar in Oudergem vermeld staat als ‘Tervurenlaan’. Er zijn nog veel meer voorbeelden.</p>



<p>De situatie waarin, binnen dezelfde gemeente, soms zelfs voor dezelfde postcode, twee straatsecties niet op dezelfde manier worden gespeld, is een duidelijke indicatie van een probleem met de kwaliteit van de gegevens. We hebben tientallen van dergelijke gevallen geïdentificeerd, voornamelijk in Wallonië, en noemen er hier slechts enkele ter illustratie.&nbsp;</p>



<figure class="wp-block-gallery has-nested-images columns-4 is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h54_11.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="684" data-id="21362" src="/wp-content/uploads/2024/11/2024-11-08_09h54_11-1024x684.png" alt="" class="wp-image-21362" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_11-1024x684.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_11-300x200.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_11-768x513.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_11.png 1309w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h54_26.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="687" data-id="21363" src="/wp-content/uploads/2024/11/2024-11-08_09h54_26-1024x687.png" alt="" class="wp-image-21363" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_26-1024x687.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_26-300x201.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_26-768x515.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_26.png 1306w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h57_37.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="684" data-id="21361" src="/wp-content/uploads/2024/11/2024-11-08_09h57_37-1024x684.png" alt="" class="wp-image-21361" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h57_37-1024x684.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h57_37-300x201.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h57_37-768x513.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h57_37.png 1312w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h55_12.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="683" data-id="21364" src="/wp-content/uploads/2024/11/2024-11-08_09h55_12-1024x683.png" alt="" class="wp-image-21364" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_12-1024x683.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_12-300x200.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_12-768x512.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_12.png 1310w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h55_28.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="683" data-id="21365" src="/wp-content/uploads/2024/11/2024-11-08_09h55_28-1024x683.png" alt="" class="wp-image-21365" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_28-1024x683.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_28-300x200.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_28-768x512.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_28.png 1306w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h55_50.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="684" data-id="21366" src="/wp-content/uploads/2024/11/2024-11-08_09h55_50-1024x684.png" alt="" class="wp-image-21366" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_50-1024x684.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_50-300x201.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_50-768x513.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_50.png 1312w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h56_23.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="684" data-id="21367" src="/wp-content/uploads/2024/11/2024-11-08_09h56_23-1024x684.png" alt="" class="wp-image-21367" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h56_23-1024x684.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h56_23-300x200.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h56_23-768x513.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h56_23.png 1307w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h00_31.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="685" data-id="21368" src="/wp-content/uploads/2024/11/2024-11-08_10h00_31-1024x685.png" alt="" class="wp-image-21368" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h00_31-1024x685.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h00_31-300x201.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h00_31-768x514.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h00_31.png 1311w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>
</figure>



<h2 class="wp-block-heading">Inconsistente geometrie</h2>



<p>Hier bekijken we de geometrische vorm die bestaat uit de opeenvolging van punten van adressen met dezelfde pariteit, voor dezelfde straat en postcode. Vervolgens berekenen we een aantal metrieken op deze lijn, ervan uitgaande dat de hoogste waarden duiden op een afwijking.</p>



<p>We hebben op experimentele basis een aantal metrieken gedefinieerd. We zullen er slechts twee nader toelichten waarvan we vonden dat ze het meest relevant waren voor de analyse. In een diepgaande analyse moeten ze echter worden gecombineerd met andere:&nbsp;</p>



<ul class="wp-block-list">
<li>delta_ratio: voor elk paar adressen in dezelfde straat en van dezelfde pariteit berekenen we de verhouding van het verschil tussen het numerieke deel van de huisnummers en de afstand. Een hoge waarde geeft aan dat twee huizen met zeer verschillende huisnummers abnormaal dicht bij elkaar liggen. Dit is vaak te verklaren door twee verschillende fenomenen:
<ul class="wp-block-list">
<li>Normale situatie: een “cirkelvormige” straat, waarin het laatste nummer naast het eerste staat,</li>



<li>Abnormale situatie: op de hoek tussen twee straten is een gebouw toegewezen aan de verkeerde straat. Of, meer algemeen, een inversie tussen twee nummers;</li>
</ul>
</li>



<li>prev_to_prev²_ratio: over het algemeen wordt verwacht dat een getal dichter bij het volgende getal (van dezelfde pariteit) ligt dan het getal dat daarop volgt. Indien nummer 2 veel dichter bij nummer 6 ligt dan bij nummer 4, is het waarschijnlijk dat nummer 4 op de verkeerde plaats staat. Hier berekenen we de ratio tussen de afstand tussen een nummer en het vorige nummer (bijvoorbeeld tussen 4 en 6) en de afstand tussen dat nummer en het nummer ervoor (bijvoorbeeld tussen 2 en 6). Een waarde van 100 geeft dus aan dat een getal (aangegeven met een &#8216;hn:&#8230;&#8217; in de titel van de grafiek) 100 keer dichter bij twee nummers achter ligt dan bij het vorige nummer.</li>
</ul>



<p>De eerste metriek zal adressen uitlichten die zich in de juiste straat bevinden, maar niet op de juiste plaats. De tweede geeft adressen aan die ver verwijderd zijn van andere nummers in dezelfde straat.</p>



<p>In de volgende illustraties zijn de stippen opeenvolgend gekleurd volgens de numerieke waarde van het huisnummer, gaande van paars voor de laagste waarde tot geel voor de hoogste. Een lijn verbindt deze stippen in numerieke volgorde.&nbsp;</p>



<figure class="wp-block-gallery has-nested-images columns-4 is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h24_00.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="738" data-id="21376" src="/wp-content/uploads/2024/11/2024-11-08_10h24_00-1024x738.png" alt="" class="wp-image-21376" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h24_00-1024x738.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h24_00-300x216.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h24_00-768x553.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h24_00.png 1244w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">16 vlak naast 116</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h26_37.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="734" data-id="21375" src="/wp-content/uploads/2024/11/2024-11-08_10h26_37-1024x734.png" alt="" class="wp-image-21375" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h26_37-1024x734.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h26_37-300x215.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h26_37-768x551.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h26_37.png 1248w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">4547 vlak naast 27</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h28_06.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="735" data-id="21377" src="/wp-content/uploads/2024/11/2024-11-08_10h28_06-1024x735.png" alt="" class="wp-image-21377" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h28_06-1024x735.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h28_06-300x215.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h28_06-768x551.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h28_06.png 1249w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Cirkelvormige straat (geen afwijkingen)</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h29_12.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="742" data-id="21374" src="/wp-content/uploads/2024/11/2024-11-08_10h29_12-1024x742.png" alt="" class="wp-image-21374" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h29_12-1024x742.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h29_12-300x217.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h29_12-768x557.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h29_12.png 1242w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">1179 vlak naast 117</figcaption></figure>
<figcaption class="blocks-gallery-caption wp-element-caption">delta ratio</figcaption></figure>



<figure class="wp-block-gallery has-nested-images columns-4 is-cropped wp-block-gallery-5 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h33_38.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="737" data-id="21378" src="/wp-content/uploads/2024/11/2024-11-08_10h33_38-1024x737.png" alt="" class="wp-image-21378" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h33_38-1024x737.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h33_38-300x216.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h33_38-768x553.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h33_38.png 1244w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">18 misplaatst</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h34_32.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="737" data-id="21381" src="/wp-content/uploads/2024/11/2024-11-08_10h34_32-1024x737.png" alt="" class="wp-image-21381" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_32-1024x737.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_32-300x216.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_32-768x553.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_32.png 1252w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">40 misplaatst</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h34_49.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="734" data-id="21379" src="/wp-content/uploads/2024/11/2024-11-08_10h34_49-1024x734.png" alt="" class="wp-image-21379" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_49-1024x734.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_49-300x215.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_49-768x550.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_49.png 1248w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">verschillende misplaatste nummers</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h38_29.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="736" data-id="21380" src="/wp-content/uploads/2024/11/2024-11-08_10h38_29-1024x736.png" alt="" class="wp-image-21380" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h38_29-1024x736.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h38_29-300x216.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h38_29-768x552.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h38_29.png 1253w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">339 misplaatst</figcaption></figure>
<figcaption class="blocks-gallery-caption wp-element-caption">prev to prev² ratio</figcaption></figure>



<p>De analyse van deze anomalieën moet vaak van geval tot geval worden bekeken, om te bepalen of het om een duidelijke fout gaat of om de weerspiegeling van een enigszins ongebruikelijke bepaling. Dit werk kan enkel uitgevoerd worden door de lokale overheden, die de informatie doorgeven aan de gewesten en vervolgens aan het FOD BOSA.</p>



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



<p>De code (Python-notebook) waarmee we al deze anomalieën hebben geïdentificeerd, is <a href="https://github.com/SmalsResearch/GISAnalytics/blob/main/BestAddressAnomalies.ipynb">beschikbaar op Github</a> en biedt een interactieve weergave van alle kaarten die hierboven zijn gepresenteerd. Het is niet aan ons om voor elk van de anomalieën te bepalen of het werkelijk een fout is (er zullen veel fout-positieven zijn), en zo ja, op welk niveau het zich voordoet: de gemeente, de consolidatie door de regio&#8217;s of het FOD BOSA, bpost, het straatnaambord, enz.&nbsp;</p>



<p>Bovendien blijft het aantal probleemgevallen klein in vergelijking met de 6,5 miljoen adressen in BeSt Address. Toch vonden we de methodologie interessant genoeg om te publiceren. Ze zou ook kunnen worden toegepast op andere datasets, zoals OpenStreetMap of andere open bronnen. </p>



<p>Hoe een databank ook wordt gevuld, er sluipen altijd fouten in. De gewesten en de FOD BOSA verrichten al bergen werk om ervoor te zorgen dat de gegevens van zeer hoge kwaliteit zijn. Het zal echter altijd mogelijk zijn om nieuwe problemen op te sporen. Met dit artikel hopen we zelf een klein steentje bij te dragen.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p><span style="color: #999999;">Deze post is een individuele bijdrage van Vandy Berten, gespecialiseerd in data science bij Smals Research. Dit artikel is geschreven onder zijn eigen naam en weerspiegelt op geen enkele wijze de standpunten van Smals.</span></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Qualité de données et données géographiques</title>
		<link>https://www.smalsresearch.be/qualite-de-donnees-et-donnees-geographiques/</link>
		
		<dc:creator><![CDATA[Vandy Berten]]></dc:creator>
		<pubDate>Wed, 27 Nov 2024 08:00:00 +0000</pubDate>
				<category><![CDATA[[FR]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[data quality]]></category>
		<category><![CDATA[GIS]]></category>
		<category><![CDATA[methodology]]></category>
		<category><![CDATA[Open Source]]></category>
		<guid isPermaLink="false">/?p=21336</guid>

					<description><![CDATA[Utiliser des données géographiques permet d'améliorer l'analyse de la qualité des données. Un exemple avec BeSt Address]]></description>
										<content:encoded><![CDATA[
<p><a href="/data-quality-en-geografische-gegevens/" data-type="post" data-id="21631"><em>Nederlandstalige versie</em></a></p>



<p>La gestion de la qualité de données (Data Quality), régulièrement abordée dans ce blog, consiste souvent à traiter (comparer, simplifier, transformer, &#8220;phonétiser&#8221;&#8230;) des chaînes de caractères&nbsp;: des noms de personnes, d&#8217;entreprises, de villes, de rues, numéros de téléphones, adresses email&#8230;</p>



<p>Dans cet article, nous allons considérer le genre de problèmes que l&#8217;on peut détecter lorsque les données sont associées à des coordonnées géographiques (latitudes, longitudes), en considérant les données ouvertes du projet &#8220;<a href="https://opendata.bosa.be/index.fr.html">BeSt Address</a>&#8221; (pour &#8220;Belgian Street Address&#8221;), du SPF BOSA (Service Public Fédéral Stratégie &amp; Appui), source authentique des adresses en Belgique. Ce projet agrège et consolide les données des régions (<a href="https://datastore.brussels/web/urbis-download">UrbiS</a> pour la région bruxelloise, le <a href="https://www.vlaanderen.be/digitaal-vlaanderen/onze-diensten-en-platformen/gebouwen-en-adressenregister">Adressenregister</a> pour la Flandre et <a href="https://geoportail.wallonie.be/catalogue/2998bccd-dae4-49fb-b6a5-867e6c37680f.html">ICAR</a> pour la Wallonie), qui elles-mêmes récupèrent les données d&#8217;adresses collectées par chaque commune, autorité responsable de l&#8217;attribution des adresses. On peut y télécharger une série de fichiers CSV ou XML, permettant, pour chaque adresse en Belgique, d&#8217;en connaitre l&#8217;orthographe officielle ainsi que les coordonnées géographiques.</p>



<p>Notre expérience nous a montré que les données des BeSt Address sont de loin les données de la meilleure qualité par rapport à d&#8217;autres sources officielles contenant des adresses (Registre national, Répertoire des employeurs, Banque Carrefour des Entreprises&#8230;), à tout le moins sur les aspects classiques de la qualité de données (cohérence des noms, absence d&#8217;abréviation&#8230;), résultat de l&#8217;énorme travail réalisé par les équipes des régions et du SPF BOSA. Néanmoins, nous avons pu y trouver un certain nombre d&#8217;anomalies identifiables uniquement en considérant les données géographiques et des analyses spatiales.</p>



<p>Les anomalies identifiées correspondent en grande majorité à des adresses mal placées (mauvaises coordonnées), ou à des codes postaux problématiques. Le nettoyage ne pourra être fait que par les entités sur le terrain, à savoir les communes.</p>



<p>Notons que les anomalies présentées ci-dessous sont issues d&#8217;une analyse &#8220;académique&#8221;. Celle-ci a déjà été discutée avec un certain nombre de personnes des instances concernées (régions, registre national, SPF BOSA, IGN&#8230;), et certaines de ces anomalies sont considérées comme acceptables. Le but de cet article n&#8217;est pas de critiquer la qualité des données, mais simplement de présenter une méthodologie, en l&#8217;illustrant avec une source de données pertinentes.</p>



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



<p>Comme déjà expliqué dans&nbsp;<a href="/la-jointure-spatiale-la-cle-de-lanalytique-geographique/">un article précédent</a>, la Belgique est composée, à l’heure d’écrire ces lignes, de 581 communes (ce nombre diminuera dans les prochains mois, suite à une série de fusions de communes). Chacune de celles-ci est composée d&#8217;un ou plusieurs codes postaux (associés à un nom à Bruxelles et en Flandre), et chacun de ces codes postaux peut contenir une ou plusieurs sous-communes, ou localités (part of municipality en Wallonie, dans le jargon BeSt Address).</p>



<p>Pour l&#8217;analyse ci-dessous, nous sommes partis des fichiers CSV disponibles sur<a href="https://opendata.bosa.be/" rel="nofollow"> https://opendata.bosa.be/</a>, et avons mené quatre types d&#8217;analyse&nbsp;:&nbsp;</p>



<ul class="wp-block-list">
<li>Dans la première, nous regardons si tous les numéros de boite d&#8217;une même adresse sont bien localisés proches les uns des autres ;</li>



<li>Dans la deuxième, nous comparons les frontières des codes postaux définis par bpost (la poste belge) avec les codes postaux des adresses BeSt Address ;</li>



<li>Dans la troisième, nous recherchons des incohérences sur des noms de rues géographiquement proches (par exemple une &#8220;Rue Roi Albert I&#8221; juste à côté d&#8217;une &#8220;Rue <strong>du</strong> Roi Albert I&#8221;) ;</li>



<li>Dans la quatrième, nous recherchons des anomalies géométriques dans la forme d&#8217;une rue.</li>
</ul>



<h2 class="wp-block-heading">Incohérence de boites</h2>



<p>Comme <a href="/pourquoi-une-adresse-belge-cest-complique/">détaillé précédemment</a>, une adresse contient toujours un &#8220;numéro de police&#8221;, ou numéro de maison, qui désigne le bâtiment, et, parfois, un &#8220;numéro de boite&#8221;, qui désigne l&#8217;unité d&#8217;habitation au sein de ce bâtiment. Dans BeSt Address, pour chaque adresse avec une boite, nous trouvons toujours une adresse équivalente de base (même rue, code postal, numéro) sans boite. Imaginons qu&#8217;au 20 de l&#8217;avenue Fonsny, on trouve deux boites, &#8220;boite 1&#8221; et &#8220;boite 2&#8221;&nbsp;: on trouvera trois items dans BeSt Address&nbsp;: &#8220;Avenue Fonsny 20&#8221; ; &#8220;Avenue Fonsny 20 boite 1&#8221; et &#8220;Avenue Fonsny 20 boite 2&#8221;.&nbsp;</p>



<p>Nous avons regardé pour chaque adresse (rue, code postal, numéro) si les coordonnées associées aux boites ne sont pas anormalement éloignées. Dans une grande majorité des cas, les différentes boites d&#8217;un même numéro auront toutes les mêmes coordonnées, mais ça n&#8217;est pas toujours le cas.</p>



<figure class="wp-block-image alignright"><a href="/wp-content/uploads/2024/11/2024-11-08_11h27_57.png"><img loading="lazy" decoding="async" width="150" height="150" src="/wp-content/uploads/2024/11/2024-11-08_11h27_57-150x150.png" alt="" class="wp-image-21388"/></a></figure>



<p>Pour chaque adresse ayant des numéros de boite, nous construisons pour ce faire le &#8220;rectangle orienté minimum&#8221; (<em>minimum rotated rectangle</em>), à savoir le rectangle de surface minimale englobant l&#8217;ensemble des points (les coordonnées de l&#8217;adresse &#8220;de base&#8221;, représentée par &#8220;/&#8221;, ainsi que celles de chacune des boites), en autorisant toute rotation du rectangle. Un tel rectangle englobant deux points aura une largeur nulle et une longueur équivalente à la distance entre les points. En cas de points multiples non alignés, les deux dimensions seront positives.</p>



<p>Les anomalies ont essentiellement été détectées en Flandre, avec plus de 100 cas. En Wallonie, les coordonnées des différentes boites sont toujours égales aux coordonnées de l&#8217;adresse de base. À Bruxelles, seules deux anomalies ont été détectées.</p>



<p>Pour illustrer ceci, prenons deux exemples, représentés dans la figure ci-dessous. Le premier exemple (Abdijstraat, 41 à 9140 Stekene) montre que l&#8217;adresse de base (Abdijstraat, 41, représenté par un &#8220;/&#8221;) est située à 11 kilomètres de Abdijstraat, 41 bus 12. Nous avons trouvé près d&#8217;une centaine d&#8217;exemples très similaires.</p>



<p>Le second est une conséquence du problème illustré dans <a href="/pourquoi-une-adresse-belge-cest-complique/">notre article précédent</a>&nbsp;: pour créer des adresses entre le &#8220;1&#8221; et le &#8220;3&#8221;, on peut soit créer les numéros de maison &#8220;1A&#8221;, &#8220;1B&#8221;, &#8220;1C&#8221;&#8230; (sans numéro de boite), soit toutes les appeler &#8220;numéro 1&#8221;, mais avec un numéro de boite &#8220;A&#8221;, &#8220;B&#8221;, &#8220;C&#8221;&#8230; Dans la &#8220;Diamantstraat&#8221; à Dixmude, un choix hybride (sans doute par erreur) a été fait&nbsp;: à côté du 1, on retrouve bien le &#8220;1A&#8221;, &#8220;1B&#8221;, &#8230; &#8220;1F&#8221;, puis &#8230; &#8220;1 boite G&#8221;&nbsp;! Ceci génère une grande distance entre le 1 (adresse de base) et le 1 (boite G).&nbsp;</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-6 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_12h48_05.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="758" data-id="21346" src="/wp-content/uploads/2024/11/2024-11-07_12h48_05-1024x758.png" alt="" class="wp-image-21346" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h48_05-1024x758.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h48_05-300x222.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h48_05-768x568.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h48_05.png 1195w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_12h47_52-1.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="759" data-id="21347" src="/wp-content/uploads/2024/11/2024-11-07_12h47_52-1-1024x759.png" alt="" class="wp-image-21347" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h47_52-1-1024x759.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h47_52-1-300x222.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h47_52-1-768x569.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_12h47_52-1.png 1195w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>
</figure>



<h2 class="wp-block-heading">Frontières postales</h2>



<p>Dans cette analyse, nous comparons <a href="https://bgu.bpost.be/assets/9738c7c0-5255-11ea-8895-34e12d0f0423_x-shapefile_3812.zip">les frontières des codes postaux définies par bpost</a>. Pour ce faire, pour chaque adresse de BeSt, nous regardons dans quel polygone de bpost elle tombe et on retient celles pour lesquelles il y a une inconsistance entre le code postal de BeSt et celui de bpost.</p>



<p>Pour éviter les problèmes de précision d&#8217;un point qui serait juste à la frontière, on supprime un ruban de 50 mètres des contours dans les codes postaux définis par bpost . On identifie donc une inconsistance uniquement quand une adresse d&#8217;un code postal P1 (selon BeSt) est réellement dans le polygone d&#8217;un code postal P2 (selon bpost), avec P1 ≠ P2.</p>



<p>Dans les images ci-dessous, on peut voir quelques-uns des exemples identifiés. La ligne rouge représente la limite correspondant au code postal en titre, selon bpost (6700 pour l&#8217;exemple principal). À l&#8217;intérieur de cette ligne sont localisées un grand nombre d&#8217;adresses de BeSt, associées au même code postal, que nous ne représentons pas ici pour ne pas surcharger l&#8217;image. Les points de couleurs en dehors du contour rouge sont donc des adresses que BeSt associe au code en titre, mais qui, selon la poste, sont du code postal indiqué dans la légende (6704 en bleu, 6706 en orange pour le 1er exemple).</p>



<p>Notons que les &#8220;échanges&#8221; relevés se font toujours au sein d&#8217;une même commune (Arlon pour l&#8217;exemple). Mais alors que BeSt considère que toutes les adresses de la commune d&#8217;Arlon sont sur 6700, bpost considère qu&#8217;une partie du territoire est sur 6704 (Guirsch) ou 6706 (Autelbas-Barnich), deux codes postaux inconnus de BeSt.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-7 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_15h49_43.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="728" data-id="21353" src="/wp-content/uploads/2024/11/2024-11-07_15h49_43-1024x728.png" alt="" class="wp-image-21353" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h49_43-1024x728.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h49_43-300x213.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h49_43-768x546.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h49_43.png 1235w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_15h48_10-1.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="728" data-id="21354" src="/wp-content/uploads/2024/11/2024-11-07_15h48_10-1-1024x728.png" alt="" class="wp-image-21354" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h48_10-1-1024x728.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h48_10-1-300x213.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h48_10-1-768x546.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h48_10-1.png 1242w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_15h47_20.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="732" data-id="21352" src="/wp-content/uploads/2024/11/2024-11-07_15h47_20-1024x732.png" alt="" class="wp-image-21352" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h47_20-1024x732.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h47_20-300x214.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h47_20-768x549.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h47_20.png 1250w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-07_15h50_50.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="727" data-id="21350" src="/wp-content/uploads/2024/11/2024-11-07_15h50_50-1024x727.png" alt="" class="wp-image-21350" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h50_50-1024x727.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h50_50-300x213.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h50_50-768x545.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-07_15h50_50.png 1243w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>
</figure>



<p>Il ne s&#8217;agit pas uniquement d&#8217;une question d&#8217;un fichier (Shapefile) qui ne serait pas à jour sur le site de bpost&nbsp;: l&#8217;outil en ligne de <a href="https://www.bpost.be/fr/outil-de-validation-des-adresses">validation d&#8217;adresse de bpost</a> est bien cohérent avec les codes postaux présentés.</p>



<p>Lors de certaines discussions, il nous a été répondu que les communes avaient la liberté de modifier, au sein de leur territoire, l&#8217;attribution des codes postaux. Mais il n&#8217;y a pas de consensus là-dessus&nbsp;: dans le &#8220;<a href="https://www.belgif.be/downloads/best/20211019_Guide_en_mati%C3%A8re_de_constatation_et_attribution_d_adresses.pdf">Guide en matière de constatation et attribution d’adresses</a>&#8220;, il est dit que &#8220;(…) les codes postaux et leur systématisation sont la propriété du prestataire du service postal universel, en l’occurrence (&#8230;) bpost. Ils ne peuvent être attribués et modifiés que sur proposition de bpost, et après avis motivé de l’IBPT et l’approbation du ministre conformément à l’article 135 de la loi du 21 mars 1991. (Article 22)&#8221;.</p>



<p>Nous avons trouvé un peu plus de 8.000 anomalies en Wallonie (sur un total de 1.85 M adresses pertinentes), ~11.000 en Flandre (sur 3.83 M), et un nombre marginal à Bruxelles (sur 860.000). Notons que certaines anomalies sont acceptables, comme par exemple le cas de bâtiments (château, ferme…) loin de la porte d&#8217;entrée. BeSt localise le bâtiment, mais son code postal correspond à celui de son entrée.</p>



<h2 class="wp-block-heading">Incohérence de noms</h2>



<p>Pour cette analyse, nous allons combiner une approche &#8220;classique&#8221; basée sur des comparaisons de chaînes de caractères, et une approche géographique. Nous commençons par identifier la liste de tous les couples de rues adjacentes (c&#8217;est-à-dire que l&#8217;une a une adresse distante de moins de 100 mètres d&#8217;une adresse de l&#8217;autre). On regarde ensuite si l&#8217;on ne trouve pas de petites différences dans les noms de rue. Nous rencontrons typiquement deux situations&nbsp;:</p>



<ul class="wp-block-list">
<li>Des rues traversant plusieurs communes avec une orthographe différente dans chacune d&#8217;elle&nbsp;: &#8220;Rue <strong>de</strong> Monténégro, 1060&#8243;, vs &#8220;Rue <strong>du</strong> Monténégro, 1190&#8243; ;</li>



<li>Des rues avec deux orthographes différentes au sein de la même commune&nbsp;: &#8220;Chaussée Brunehau<strong>lt</strong>&#8221; ou &#8220;Chaussée Brunehau<strong>t</strong>&#8220;, à 4452 dans les 2 cas.</li>
</ul>



<p>On trouvera également quelques faux positifs&nbsp;: &#8220;Rue de Mars&#8221; vs &#8220;Rue de Mai&#8221;. On élimine de nos comparaisons les noms identiques à part une dernière lettre isolée (&#8220;Hensel laan A&#8221; vs &#8220;Hensel laan B&#8221;), ainsi que les noms où seul un chiffre change (&#8220;5de Zijweg&#8221; vs &#8220;6de Zijweg&#8221;).</p>



<p>Concernant la première situation, où le changement de nom arrive au passage d&#8217;une commune à l&#8217;autre, on peut regretter le manque de cohérence qui va à l&#8217;encontre de l&#8217;article 5 de la <a href="https://www.ibz.rrn.fgov.be/fileadmin/user_upload/fr/rn/circulaires/BeSt_20201104_F.pdf">directive décrite plus haut</a>, qui dit que &#8220;[d]ans l’hypothèse où une voie s’étend sur le territoire de plusieurs communes, et que cette voie garde le même nom, ces communes doivent s’assurer que l’orthographe de ce nom de rue soit identique dans toutes les communes concernées&#8221;. La directive n&#8217;est cependant pas contraignante, les communes sont donc libres de garder leur orthographe propre.</p>



<figure class="wp-block-image alignright"><a href="/wp-content/uploads/2024/11/2024-11-08_09h31_07.png"><img loading="lazy" decoding="async" width="150" height="150" src="/wp-content/uploads/2024/11/2024-11-08_09h31_07-150x150.png" alt="" class="wp-image-21360"/></a><figcaption class="wp-element-caption"><span style="color: #999999;">Credit: Google StreetView</span></figcaption></figure>



<p>Il est cependant pertinent de se demander si l&#8217;orthographe présente dans BeSt (transmise par les communes) est réellement la bonne. On peut par exemple citer la &#8220;Rue Wal<strong>ck</strong>iers&#8221; à 1030 Schaerbeek, qui prolonge la &#8220;Rue Wal<strong>k</strong>iers&#8221; à 1140 Evere. Or, la (seule) plaque schaerbeekoise de la rue l&#8217;orthographie &#8230; &#8220;Rue Wal<strong>k</strong>iers&#8221;&nbsp;! Il en va de même pour la (petite) portion auderghemoise de l&#8217;avenue de Terv<strong>uer</strong>en, orthographiée comme telle à Woluwé-Saint-Pierre, ainsi que sur les plaques de rue à Auderghem, mais reprise dans BeSt comme &#8220;Avenue de Ter<strong>vur</strong>en&#8221; à Auderghem. Nous pourrions citer bien d&#8217;autres exemples.</p>



<p>La situation où, au sein d&#8217;une même commune, parfois même pour un même code postal, deux portions de rue n&#8217;ont pas la même orthographe, dénote de façon plus évidente d&#8217;un problème de qualité de données. Nous en avons identifié des dizaines, principalement en Wallonie, nous n&#8217;en reprenons ici que quelques-uns pour illustration.&nbsp;</p>



<figure class="wp-block-gallery has-nested-images columns-4 is-cropped wp-block-gallery-8 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h54_11.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="684" data-id="21362" src="/wp-content/uploads/2024/11/2024-11-08_09h54_11-1024x684.png" alt="" class="wp-image-21362" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_11-1024x684.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_11-300x200.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_11-768x513.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_11.png 1309w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h54_26.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="687" data-id="21363" src="/wp-content/uploads/2024/11/2024-11-08_09h54_26-1024x687.png" alt="" class="wp-image-21363" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_26-1024x687.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_26-300x201.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_26-768x515.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h54_26.png 1306w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h57_37.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="684" data-id="21361" src="/wp-content/uploads/2024/11/2024-11-08_09h57_37-1024x684.png" alt="" class="wp-image-21361" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h57_37-1024x684.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h57_37-300x201.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h57_37-768x513.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h57_37.png 1312w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h55_12.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="683" data-id="21364" src="/wp-content/uploads/2024/11/2024-11-08_09h55_12-1024x683.png" alt="" class="wp-image-21364" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_12-1024x683.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_12-300x200.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_12-768x512.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_12.png 1310w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h55_28.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="683" data-id="21365" src="/wp-content/uploads/2024/11/2024-11-08_09h55_28-1024x683.png" alt="" class="wp-image-21365" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_28-1024x683.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_28-300x200.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_28-768x512.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_28.png 1306w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h55_50.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="684" data-id="21366" src="/wp-content/uploads/2024/11/2024-11-08_09h55_50-1024x684.png" alt="" class="wp-image-21366" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_50-1024x684.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_50-300x201.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_50-768x513.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h55_50.png 1312w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_09h56_23.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="684" data-id="21367" src="/wp-content/uploads/2024/11/2024-11-08_09h56_23-1024x684.png" alt="" class="wp-image-21367" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h56_23-1024x684.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h56_23-300x200.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h56_23-768x513.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_09h56_23.png 1307w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h00_31.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="685" data-id="21368" src="/wp-content/uploads/2024/11/2024-11-08_10h00_31-1024x685.png" alt="" class="wp-image-21368" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h00_31-1024x685.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h00_31-300x201.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h00_31-768x514.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h00_31.png 1311w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>
</figure>



<h2 class="wp-block-heading">Géométrie incohérente</h2>



<p>Nous considérons ici la forme géométrique composée de la séquence de points des adresses de même parité, pour une même rue et un même code postal. Sur cette ligne, nous calculons ensuite un certain nombre de métriques, en supposant que les valeurs les plus élevées dénotent d&#8217;une anomalie.</p>



<p>Nous avons défini de façon expérimentale un certain nombre de métriques. Nous allons juste en détailler deux qui nous ont paru les plus pertinentes à l&#8217;analyse. Mais dans une analyse approfondie, il conviendra de les combiner avec d&#8217;autres&nbsp;:&nbsp;</p>



<ul class="wp-block-list">
<li>delta_ratio&nbsp;: pour chaque couple d&#8217;adresses d&#8217;une même rue et de même parité, on calcule le ratio de la différence entre la partie numérique des numéros de maison et la distance. Une valeur élevée indique que deux maisons de numéros très distants sont anormalement proches. Ceci s&#8217;explique souvent par deux phénomènes distincts&nbsp;:
<ul class="wp-block-list">
<li><p>Situation normale&nbsp;: une rue &#8220;circulaire&#8221;, dans laquelle le dernier numéro se situe à côté du premier,</p></li>



<li><p><span style="color: initial;">Situation anormale&nbsp;: sur le coin entre deux rues, un bâtiment a été assigné à la mauvaise rue. Ou plus généralement, une inversion entre deux numéros ;</span></p></li>
</ul>
</li>



<li>prev_to_prev²_ratio&nbsp;: on s&#8217;attend en général à ce qu&#8217;un numéro soit plus proche du numéro suivant (de même parité) que de celui d&#8217;encore après. Si le numéro 2 est beaucoup plus proche du 6 que du 4, il est probable que le 4 soit mal placé. On calcule ici le ratio de la distance d&#8217;un numéro au numéro précédent (par ex. entre 4 et 6) sur la distance entre ce numéro et celui qui précède le précédent (par ex. entre 2 et 6). Une valeur de 100 indique donc qu&#8217;un numéro (indiqué un &#8216;hn:&#8230;&#8217; dans le titre du graphique) est 100 fois plus proche de deux numéros en arrière que du numéro précédent.</li>
</ul>



<p>La première métrique mettra en évidence des adresses qui ont été localisées dans la bonne rue, mais pas au bon endroit. La seconde fera ressortir des adresses qui ont été localisées très loin des autres numéros de la même rue.</p>



<p>Dans les illustrations suivantes, les points sont colorés séquentiellement selon la valeur numérique du numéro de police, allant de mauve pour la plus petite valeur à jaune pour la plus grande. Une ligne relie ces points dans l&#8217;ordre numérique.&nbsp;</p>



<figure class="wp-block-gallery has-nested-images columns-4 is-cropped wp-block-gallery-9 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h24_00.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="738" data-id="21376" src="/wp-content/uploads/2024/11/2024-11-08_10h24_00-1024x738.png" alt="" class="wp-image-21376" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h24_00-1024x738.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h24_00-300x216.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h24_00-768x553.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h24_00.png 1244w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">16 juste à côté du 116</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h26_37.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="734" data-id="21375" src="/wp-content/uploads/2024/11/2024-11-08_10h26_37-1024x734.png" alt="" class="wp-image-21375" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h26_37-1024x734.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h26_37-300x215.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h26_37-768x551.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h26_37.png 1248w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">4547 juste à côté du 27</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h28_06.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="735" data-id="21377" src="/wp-content/uploads/2024/11/2024-11-08_10h28_06-1024x735.png" alt="" class="wp-image-21377" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h28_06-1024x735.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h28_06-300x215.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h28_06-768x551.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h28_06.png 1249w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Rue circulaire (pas d&#8217;anomalie)</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h29_12.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="742" data-id="21374" src="/wp-content/uploads/2024/11/2024-11-08_10h29_12-1024x742.png" alt="" class="wp-image-21374" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h29_12-1024x742.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h29_12-300x217.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h29_12-768x557.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h29_12.png 1242w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">1179 juste à côté du 117</figcaption></figure>
<figcaption class="blocks-gallery-caption wp-element-caption">delta ratio</figcaption></figure>



<figure class="wp-block-gallery has-nested-images columns-4 is-cropped wp-block-gallery-10 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h33_38.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="737" data-id="21378" src="/wp-content/uploads/2024/11/2024-11-08_10h33_38-1024x737.png" alt="" class="wp-image-21378" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h33_38-1024x737.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h33_38-300x216.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h33_38-768x553.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h33_38.png 1244w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">18 mal placé</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h34_32.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="737" data-id="21381" src="/wp-content/uploads/2024/11/2024-11-08_10h34_32-1024x737.png" alt="" class="wp-image-21381" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_32-1024x737.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_32-300x216.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_32-768x553.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_32.png 1252w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">40 mal placé</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h34_49.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="734" data-id="21379" src="/wp-content/uploads/2024/11/2024-11-08_10h34_49-1024x734.png" alt="" class="wp-image-21379" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_49-1024x734.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_49-300x215.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_49-768x550.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h34_49.png 1248w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">plusieurs mal placés</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/2024-11-08_10h38_29.png" target="_blank" rel="noopener"><img loading="lazy" decoding="async" width="1024" height="736" data-id="21380" src="/wp-content/uploads/2024/11/2024-11-08_10h38_29-1024x736.png" alt="" class="wp-image-21380" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h38_29-1024x736.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h38_29-300x216.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h38_29-768x552.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/2024-11-08_10h38_29.png 1253w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">339 mal placé</figcaption></figure>
<figcaption class="blocks-gallery-caption wp-element-caption">prev to prev² ratio</figcaption></figure>



<p>L&#8217;analyse de ces anomalies nécessite souvent une attention au cas par cas, pour savoir s&#8217;il s&#8217;agit d&#8217;une erreur manifeste, ou du reflet d&#8217;une disposition un peu particulière. Ce travail ne peut être fait que par des instances de terrain, à savoir les communes, qui transmettent ces informations aux régions puis au SPF BOSA.</p>



<h2 class="wp-block-heading">Le mot de la fin</h2>



<p>Le code (notebook Python) qui nous a permis d&#8217;identifier toutes ces anomalies est <a href="https://github.com/SmalsResearch/GISAnalytics/blob/main/BestAddressAnomalies.ipynb">disponible sur Github</a>, et permet entre autres une vue interactive de toutes les cartes présentées ci-dessus. Pour chacune des anomalies, il ne nous revient pas de déterminer s&#8217;il s&#8217;agit réellement d&#8217;une erreur (il y aura beaucoup de faux positifs), et, le cas échéant, à quel niveau elle se situe&nbsp;: la commune, la consolidation par les régions ou le SPF BOSA, bpost, la plaque de rue&#8230;&nbsp;</p>



<p>Par ailleurs, le nombre de cas problématiques reste faible par rapport aux 6,5 millions d&#8217;adresses que contient BeSt Address. Mais la méthodologie nous paraissait suffisamment intéressante pour la publier. On pourrait par ailleurs l&#8217;appliquer à d&#8217;autres jeux de données, comme par exemple OpenStreetMap, ou d&#8217;autres sources ouvertes.</p>



<p>Quelle que soit la façon dont est alimentée une base de données, des erreurs s&#8217;y introduisent. Les régions et le SFP BOSA font déjà un travail considérable pour garantir des données d&#8217;une très bonne qualité. Mais il sera toujours possible de détecter des nouveaux problèmes. Par cet article, nous espérons apporter notre modeste contribution à l&#8217;édifice.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p><span style="color: #999999;"><em>Ce post est une contribution individuelle de Vandy Berten, spécialisé&nbsp;</em>en<em>&nbsp;data science&nbsp;chez Smals Research. Cet article est écrit en son nom propre et n’impacte en rien le point de vue de Smals.</em></span></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>bePelias, een lokale geocoder gebaseerd op BeSt Address</title>
		<link>https://www.smalsresearch.be/bepelias-een-lokale-geocoder-gebaseerd-op-best-address/</link>
		
		<dc:creator><![CDATA[Vandy Berten]]></dc:creator>
		<pubDate>Fri, 26 Apr 2024 09:35:28 +0000</pubDate>
				<category><![CDATA[[NL]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[geocoding]]></category>
		<category><![CDATA[GIS]]></category>
		<category><![CDATA[Open Source]]></category>
		<guid isPermaLink="false">/?p=20443</guid>

					<description><![CDATA[Geocodering is de bewerking waarbij een tekstueel postadres (‘Fonsnyln 20, 1060 Brussel’) omgevormd wordt tot een in componenten opgesplitste en gestandaardiseerde versie, gelinkt aan een geografische locatie]]></description>
										<content:encoded><![CDATA[
<p><em><a href="/bepelias-un-geocodeur-local-base-sur-best-address/" data-type="post" data-id="20294">Version en français</a></em></p>



<p>Geocodering is de bewerking waarbij een tekstueel postadres (‘Fonsnyln 20, 1060 Brussel’) omgevormd wordt tot een in componenten opgesplitste en gestandaardiseerde versie, gelinkt aan een geografische locatie1<sup data-fn="b7665c04-0011-4cad-a98a-5e516f4a994c" class="fn"><a href="#b7665c04-0011-4cad-a98a-5e516f4a994c" id="b7665c04-0011-4cad-a98a-5e516f4a994c-link">1</a></sup>&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)"><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #000000">{</span><span style="color: #0451A5">&quot;street&quot;</span><span style="color: #000000">:  </span><span style="color: #A31515">&quot;Fonslylaan&quot;</span><span style="color: #000000">, </span></span>
<span class="line"><span style="color: #000000"> </span><span style="color: #0451A5">&quot;number&quot;</span><span style="color: #000000">:  </span><span style="color: #098658">20</span><span style="color: #000000">, </span></span>
<span class="line"><span style="color: #000000"> </span><span style="color: #0451A5">&quot;zipcode&quot;</span><span style="color: #000000">: </span><span style="color: #098658">1060</span><span style="color: #000000">,  </span></span>
<span class="line"><span style="color: #000000"> </span><span style="color: #0451A5">&quot;city&quot;</span><span style="color: #000000">:    </span><span style="color: #A31515">&quot;Sint-Gillis&quot;</span><span style="color: #000000">,</span></span>
<span class="line"><span style="color: #000000"> </span><span style="color: #0451A5">&quot;lat&quot;</span><span style="color: #000000">:     </span><span style="color: #098658">50.8358216</span><span style="color: #000000">, </span></span>
<span class="line"><span style="color: #000000"> </span><span style="color: #0451A5">&quot;lon&quot;</span><span style="color: #000000">:     </span><span style="color: #098658">4.3386884</span><span style="color: #000000">}</span></span></code></pre></div>



<p>In een&nbsp;<a href="/geocode-welke-tool-voor-welke-behoefte/">vorig artikel</a> hebben we aangetoond dat er een aantal tools bestaan om deze bewerking uit te voeren en dat het, onder bepaalde omstandigheden, nodig is om over een on-site (on-premise) of lokale tool te beschikken. We zetten eerder al&nbsp;<a href="/geocodage-contourner-les-lacunes-dopenstreetmap-partie-2/">NominatimWrapper</a> in de kijker, een oplossing die we ontwikkeld hebben op basis van <a href="https://openstreetmap.org/">OpenStreetMap</a>.</p>



<p>In België beheert de federale overheidsdienst&nbsp;<a href="https://bosa.belgium.be/nl">“Strategie en Ondersteuning” (BOSA)</a>&nbsp;<a href="https://opendata.bosa.be/index.fr.html">BeSt Address</a>, de authentieke bron voor Belgische adressen. Ze zijn beschikbaar als open data in verschillende formaten. In dit artikel stellen gaan we dieper in op de volgende vraag: <em>is het mogelijk om een lokale geocoder op te stellen gebaseerd op deze gegevens</em>? Het antwoord vergt zekere nuance: Ja, maar&#8230;</p>



<p>Ten eerste stelt BOSA <a href="https://bosa.belgium.be/nl/services/best-address-services">een aantal webservices</a> ter beschikking maar met twee beperkingen:</p>



<ul class="wp-block-list">
<li>Deze zijn enkel beschikbaar voor overheidsdiensten, niet voor bedrijven of burgers.</li>



<li>Ze bieden geen ‘standaardisatie’: je moet de juiste schrijfwijze van een straat of (deel)gemeente kennen om het te gebruiken.</li>
</ul>



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



<p>Met het opensourceproject&nbsp;<a href="https://pelias.io/">Pelias</a>&nbsp;kan een geocoder opgezet worden op basis van je eigen gegevens. In combinatie met <a href="https://openaddresses.io/">OpenAddresses.io</a>, een project dat open adresgegevens samenbrengt, is het mogelijk om Pelias in te zetten voor een reeks landen of steden, <a href="https://github.com/pelias/docker/tree/master/projects/belgium">waaronder België met BeSt Address (in combinatie met OpenStreetMap)</a>.</p>



<p>Hoewel het eenvoudig is om een geocoder op te zetten die Pelias en BeSt Address combineert en die goed lijkt te werken wanneer je hem test op een paar adressen, raak je al snel teleurgesteld wanneer je probeert naar een hogere versnelling te schakelen en hem datasets stuurt van de (Belgische) <a href="https://kbopub.economie.fgov.be/kbo-open-data/login?lang=nl">Kruispuntbank van Ondernemingen</a>, het <a href="https://employer-identification-consult.prd.pub.socialsecurity.be/">werkgeversrepertorium</a> (RSZ) of het rijksregister.</p>



<p>Met Pelias zijn er twee vraagmodi: gestructureerd ({“address”: “Fonsnylaan 20”, “postalcode”: 1060, “locality”: “Sint-Gillis”}) of ongestructureerd ({“query”: “Fonsnylaan 20, 1060 Sint-Gillis”}). Van de gegevens die we gestructureerd (cfr. “pelias_struct” in de grafiek hieronder) getest hebben (10 000 adressen afkomstig van verschillende bronnen in onderstaande legende), was Pelias slechts in staat om 55 % van de adressen exact te lokaliseren. Enkele percentages (1-2) zijn gelokaliseerd wat betreft de straat en in +/- 35% van de gevallen vond Pelias enkel de stad&#8230; met andere woorden niks bruikbaars. En in 7-10 % krijgen we zelfs geen enkel resultaat.&nbsp; &nbsp;</p>



<p>Pelias doet iets beter ‘ongestructureerd’ (pelias), aangezien hij bijna altijd in staat is om een resultaat te verschaffen, en 11 % bijkomende adressen worden exact gelokaliseerd.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-11 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_rrn_10000.png"><img loading="lazy" decoding="async" width="1024" height="594" data-id="20335" src="/wp-content/uploads/2024/03/matching_rate_rrn_10000-1024x594.png" alt="" class="wp-image-20335" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000-1024x594.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000-300x174.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000-768x445.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000-1536x891.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000.png 1843w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Registre National</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_rep_10000.png"><img loading="lazy" decoding="async" width="1024" height="594" data-id="20334" src="/wp-content/uploads/2024/03/matching_rate_rep_10000-1024x594.png" alt="" class="wp-image-20334" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rep_10000-1024x594.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rep_10000-300x174.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rep_10000-768x445.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rep_10000-1536x891.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rep_10000.png 1843w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Répertoire des Employeurs</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_best_10000.png"><img loading="lazy" decoding="async" width="1024" height="594" data-id="20332" src="/wp-content/uploads/2024/03/matching_rate_best_10000-1024x594.png" alt="" class="wp-image-20332" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_best_10000-1024x594.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_best_10000-300x174.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_best_10000-768x445.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_best_10000-1536x891.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_best_10000.png 1843w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">BeSt Addresses</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_kbo_10000.png"><img loading="lazy" decoding="async" width="1024" height="594" data-id="20333" src="/wp-content/uploads/2024/03/matching_rate_kbo_10000-1024x594.png" alt="" class="wp-image-20333" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000-1024x594.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000-300x174.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000-768x445.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000-1536x891.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000.png 1843w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Banque Carrefour des Entreprises</figcaption></figure>
</figure>



<p>Het is interessant om een paar zaken op te merken:</p>



<ul class="wp-block-list">
<li>Wanneer het resultaat niet exact is, bevat het resultaat geen gegevens van BeSt Address, maar van OpenStreetMap (niveau &#8216;street&#8217;) of WhosOnFirst (niveau &#8216;city&#8217;);</li>



<li>Soms geeft een adres geen resultaat in &#8216;gestructureerde&#8217; modus, maar wel in &#8216;ongestructureerde&#8217; modus, en omgekeerd;</li>



<li>In gestructureerde modus lijkt Pelias vaak in de war te raken door de aanwezigheid van de parameter ‘locality’ naast de ‘postalcode’. Vaak geeft een adres een resultaat op niveau ‘city’ wanneer deze parameter wordt opgegeven, maar een resultaat op niveau ‘building’ wanneer alleen de postcode wordt opgegeven (naast de straat en het nummer). Je kunt het verschil zien in de grafiek op de regel “pelias_struc_noloc”, waar het precies gelokaliseerde deel (‘building’, in groen) met bijna 25% toeneemt. Aan de andere kant verdwijnt het deel gelokaliseerd op stadsniveau, dat grotendeels gebaseerd is op dit ‘locality’-argument, zo goed als;</li>



<li>Het door Pelias geleverde resultaat bevat geen ‘BeSt id’ die het mogelijk zou maken om de unieke en authentieke identificatie van een adres te verkrijgen;</li>



<li>Noch de Franstalige adressen van de Vlaamse faciliteitengemeenten (en vice-versa), noch de Duitstalige adressen van de Oostkantons worden geïmporteerd.</li>
</ul>



<p>Maar op het moment van schrijven is er een nog groter probleem: de gegevens die Pelias gebruikt, dateren van midden 2021, om twee redenen:&nbsp;</p>



<ul class="wp-block-list">
<li>Het door OpenAddresses erkende formaat veranderde rond oktober 2021 en is niet langer compatibel met de door Bosa beschikbaar gestelde bestanden;</li>



<li>OpenAddresses veranderde zijn ‘dataflow’ midden 2021: de voorbereide gegevens werden eerst ter beschikking gesteld op het adres&nbsp;<a href="https://results.openaddresses.io/">https://results.openaddresses.io/</a> dat nog steeds beschikbaar is maar waarvan de gegevens niet meer up-to-date zijn; ze zijn wel up-to-date op&nbsp;<a href="https://batch.openaddresses.io/data">https://batch.openaddresses.io/data</a>. Pelias werd echter niet aangepast en blijft de gegevens van het oude systeem downloaden.</li>
</ul>



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



<p>Het lijkt dus duidelijk dat Pelias in zijn huidige vorm geen serieuze kandidaat is voor een toepassing die geocodering van adressen in België vereist. Zowel de geïmporteerde gegevens (te oud, geen ID, geen gegevens op straatniveau als een nummer niet geïdentificeerd is) als de robuustheid ontbreken. Maar het leek ons dat het potentieel aanwezig was en we gingen aan de slag om het te verbeteren. Er waren twee mogelijkheden:&nbsp;</p>



<ul class="wp-block-list">
<li>Een &#8216;kloon&#8217; van Pelias maken door de code aan te passen. Met het risico om wijzigingen aan te brengen die niet compatibel zouden zijn met de toekomstige ontwikkelingen van Pelias, en een grote inspanning op het vlak van begrip en ontwikkeling;</li>



<li>Een ‘extra laag’ toevoegen, zoals we al met succes hebben gedaan met <a href="https://github.com/SmalsResearch/NominatimWrapper">NominatimWrapper</a>, om de tekortkomingen van Pelias te compenseren. Het is deze tweede optie die we hebben gekozen.</li>
</ul>



<p>Deze tool die we ‘<em>bePelias</em>’ hebben genoemd en die we open source ter beschikking stellen (<a href="https://github.com/SmalsResearch/bePelias">https://github.com/SmalsResearch/bePelias</a>) doet hoofdzakelijk twee dingen:</p>



<figure class="wp-block-image alignright size-full is-resized"><a href="/wp-content/uploads/2024/04/bepelias_archi.png"><img loading="lazy" decoding="async" width="672" height="381" src="/wp-content/uploads/2024/04/bepelias_archi.png" alt="" class="wp-image-20365" style="width:399px;height:auto" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/04/bepelias_archi.png 672w, https://www.smalsresearch.be/wp-content/uploads/2024/04/bepelias_archi-300x170.png 300w" sizes="auto, (max-width: 672px) 100vw, 672px" /></a></figure>



<ul class="wp-block-list">
<li>Een meer volledige voorbereiding van de ‘BeSt Address-’gegevens, inclusief een reeks aanvullende gegevens (adres- en straatidentificatienummers, NIS-codes voor gemeenten, enz.), die het meertalige aspect vervolledigen en identificatie op straatniveau mogelijk maken wanneer het nummer niet bekend is. We hebben Pelias ook geconfigureerd om interpolatie mogelijk te maken (ervan uitgaande dat de &#8216;8&#8217; van een straat, indien niet bekend, tussen de &#8216;6&#8217; en de &#8217;10&#8217; ligt).</li>



<li>Een tussenlaag tussen Pelias en de client, in de vorm van een REST API, om een reeks varianten van een adres uit te proberen. Een reeks combinaties van de volgende varianten wordt getest, totdat er één een bevredigend resultaat geeft:
<ul class="wp-block-list">
<li>Gestructureerde of ongestructureerde versie van de oproep tot Pelias;</li>



<li><span style="color: initial;">Met de lokaliteit (plaats), of alleen de postcode;</span></li>



<li><span style="color: initial;">Met een reeks reguliere expressies om de straat- of plaatsnaam op te schonen. Meestal zullen we alle tekst tussen haakjes verwijderen, wat heel gebruikelijk is in straatnamen om een opmerking of de naam van de deelgemeente te specificeren;</span></li>



<li>Door het huisnummer op te schonen, dat heel vaak ook een busnummer bevat, wat in de meeste gevallen de locatie niet verandert.</li>
</ul>
</li>
</ul>



<figure class="wp-block-image alignleft size-full is-resized"><a href="/wp-content/uploads/2024/04/transformers.png"><img loading="lazy" decoding="async" width="631" height="409" src="/wp-content/uploads/2024/04/transformers.png" alt="" class="wp-image-20360" style="width:487px;height:auto" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/04/transformers.png 631w, https://www.smalsresearch.be/wp-content/uploads/2024/04/transformers-300x194.png 300w" sizes="auto, (max-width: 631px) 100vw, 631px" /></a></figure>



<p>In de praktijk zien we dat de ‘basis’ gestructureerde versie (zonder opschoning of selectie) een resultaat geeft voor +/- 53 % van de adressen (voor KBO-gegevens, zie bijgevoegde figuur). Dit wordt gevolgd door 20 % na verwijdering van de lokaliteit, nog steeds in gestructureerde vorm, dan 11% in ongestructureerde vorm, 8% na opschoning in gestructureerde vorm, en dan een reeks andere combinaties voor een klein aantal adressen. Bijna alle combinaties zijn op een bepaald moment bruikbaar.</p>



<h2 class="wp-block-heading"><strong>Resultaten</strong></h2>



<p>Het resultaat is zichtbaar in onderstaande grafieken. De bePelias-oplossing is bijna net zo efficiënt als Here WeGo (here in de grafieken) of Microsofts Bing Maps (bing); beter dan Google Maps (google), dat vrij gevoelig is voor ruis in adressen, zoals tekst tussen haakjes, en NominatimWrapper, dat enkel de straten lokaliseert voor een groot deel van de adressen.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-12 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/04/matching_rate_rep_10000.png"><img loading="lazy" decoding="async" width="1024" height="587" data-id="20449" src="/wp-content/uploads/2024/04/matching_rate_rep_10000-1024x587.png" alt="" class="wp-image-20449" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_rep_10000-1024x587.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_rep_10000-300x172.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_rep_10000-768x440.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_rep_10000-1536x880.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_rep_10000.png 1866w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_rrn_10000_2.png"><img loading="lazy" decoding="async" width="1024" height="587" data-id="20351" src="/wp-content/uploads/2024/03/matching_rate_rrn_10000_2-1024x587.png" alt="" class="wp-image-20351" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000_2-1024x587.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000_2-300x172.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000_2-768x440.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000_2-1536x880.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000_2.png 1866w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/04/matching_rate_best_10000_2.png"><img loading="lazy" decoding="async" width="1024" height="587" data-id="20358" src="/wp-content/uploads/2024/04/matching_rate_best_10000_2-1024x587.png" alt="" class="wp-image-20358" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_best_10000_2-1024x587.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_best_10000_2-300x172.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_best_10000_2-768x440.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_best_10000_2-1536x880.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_best_10000_2.png 1866w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_kbo_10000_2.png"><img loading="lazy" decoding="async" width="1024" height="587" data-id="20349" src="/wp-content/uploads/2024/03/matching_rate_kbo_10000_2-1024x587.png" alt="" class="wp-image-20349" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000_2-1024x587.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000_2-300x172.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000_2-768x440.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000_2-1536x880.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000_2.png 1866w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>
</figure>



<p>We hebben ook de nauwkeurigheid van de bePelias-resultaten getest met behulp van een &#8216;majority voting&#8217;-methodologie door dezelfde dataset naar verschillende geocoders te sturen. We presenteerden de resultaten in <a href="/webinar-geocoding-follow-up/">een recent webinar</a>, waaruit bleek dat de prestaties zeer vergelijkbaar zijn met die van Here WeGo of Bing Maps, en opnieuw aanzienlijk beter dan Google Maps, dat naast het feit dat het vaak alleen de straat lokaliseert, een vervelende neiging heeft om te hallucineren en resultaten biedt die duizenden kilometers verwijderd zijn van het juiste antwoord.</p>



<p>Wat snelheid betreft, geeft het feit dat de oplossing lokaal draait een aanzienlijk voordeel, namelijk twee keer zo snel als Google Maps of 5 keer zo snel als Bing Maps. Hiervoor moet de geocoder natuurlijk zo dicht mogelijk bij de toepassing die hem nodig heeft worden geïnstalleerd.</p>



<h2 class="wp-block-heading"><strong>Conclusies: tool bePelias</strong> </h2>



<p>Op basis van bovenstaande stellen wij een werkende oplossing, bePelias, ter beschikking, die je in staat stelt om lokaal een geocoder te instantiëren, met behulp van Docker, uitsluitend gebaseerd op open source code (Pelias) en open data (voornamelijk BeSt Address), met nauwelijks een paar duizend regels extra code in Python of Bash.</p>



<p>Onze oplossing heeft natuurlijk niet alleen maar voordelen:</p>



<ul class="wp-block-list">
<li>bePelias werkt alleen voor België;</li>



<li>bePelias werkt alleen voor adressen. Je krijgt geen antwoord op ‘Smals, Sint-Gillis’ of ‘Bakker, Namen’;</li>



<li>bePelias vereist de installatie, het beheer en het onderhoud (updaten van de server, bePelias en ‘BeSt Address’-gegevens) van een server met ongeveer 15 GB schijfruimte en minstens 8 GB RAM geheugen, wat, afhankelijk van het project, een hogere kost kan betekenen dan het gebruik van een commerciële <em>cloud</em>-oplossing;</li>



<li>In dit stadium is dit nog een onderzoeksproject dat zich moet bewijzen in een industriële omgeving.</li>
</ul>



<p>Daar staat tegenover dat:</p>



<ul class="wp-block-list">
<li>bePelias vergelijkbare prestaties biedt met de grote commerciële spelers in de sector;</li>



<li>bePelias on-premise werkt, wat de problemen van vertrouwelijkheid en GDPR oplost;</li>



<li>bePelias gebaseerd is op BeSt Address, de (recente) authentieke bron van adressen in België. Het verkrijgen van een ‘BeSt id’ maakt het gemakkelijker om te communiceren met een reeks webservices die deze bron hebben geïntegreerd.</li>
</ul>



<p>Feedback is zeer welkom en zal helpen om deze tool, die klaar staat om gebruikt te worden, te verbeteren!</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>


<ol class="wp-block-footnotes"><li id="b7665c04-0011-4cad-a98a-5e516f4a994c">Dit is een vereenvoudigd illustratief voorbeeld, waarvan de syntaxis niet overeenkomt met een bekende tool. <a href="#b7665c04-0011-4cad-a98a-5e516f4a994c-link" aria-label="Jump to footnote reference 1"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></li></ol>


<p class="has-cyan-bluish-gray-color has-text-color has-link-color wp-elements-c41eb3572da4d9702c8d124766adb49c">Deze post is een individuele bijdrage van Vandy Berten, gespecialiseerd in data science bij Smals Research. Dit artikel is geschreven onder zijn eigen naam en weerspiegelt op geen enkele wijze de standpunten van Smals.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>bePelias, un géocodeur local basé sur BeSt Address</title>
		<link>https://www.smalsresearch.be/bepelias-un-geocodeur-local-base-sur-best-address/</link>
		
		<dc:creator><![CDATA[Vandy Berten]]></dc:creator>
		<pubDate>Tue, 23 Apr 2024 07:00:00 +0000</pubDate>
				<category><![CDATA[[FR]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[geocoding]]></category>
		<category><![CDATA[GIS]]></category>
		<category><![CDATA[Open Source]]></category>
		<guid isPermaLink="false">/?p=20294</guid>

					<description><![CDATA[Le géocodage est l'opération qui permet de transformer une adresse postale textuelle ("av. Fonsny 20, 1060 Bruxelles") en une version décomposée et standardisée, associée à une localisation géographique]]></description>
										<content:encoded><![CDATA[
<p><em><a href="/bepelias-een-lokale-geocoder-gebaseerd-op-best-address/" data-type="post" data-id="20443">Nederlandstalige versie</a></em></p>



<p>Le géocodage est l&#8217;opération qui permet de transformer une adresse postale textuelle (&#8220;av. Fonsny 20, 1060 Bruxelles&#8221;) en une version décomposée et standardisée, associée à une localisation géographique<sup data-fn="b7665c04-0011-4cad-a98a-5e516f4a994c" class="fn"><a href="#b7665c04-0011-4cad-a98a-5e516f4a994c" id="b7665c04-0011-4cad-a98a-5e516f4a994c-link">1</a></sup>&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)"><pre class="shiki light-plus" style="background-color: #FFFFFF" tabindex="0"><code><span class="line"><span style="color: #000000">{</span><span style="color: #0451A5">&quot;street&quot;</span><span style="color: #000000">:  </span><span style="color: #A31515">&quot;Avenue Fonsny&quot;</span><span style="color: #000000">, </span></span>
<span class="line"><span style="color: #000000"> </span><span style="color: #0451A5">&quot;number&quot;</span><span style="color: #000000">:  </span><span style="color: #098658">20</span><span style="color: #000000">, </span></span>
<span class="line"><span style="color: #000000"> </span><span style="color: #0451A5">&quot;zipcode&quot;</span><span style="color: #000000">: </span><span style="color: #098658">1060</span><span style="color: #000000">,  </span></span>
<span class="line"><span style="color: #000000"> </span><span style="color: #0451A5">&quot;city&quot;</span><span style="color: #000000">:    </span><span style="color: #A31515">&quot;Saint-Gilles&quot;</span><span style="color: #000000">,</span></span>
<span class="line"><span style="color: #000000"> </span><span style="color: #0451A5">&quot;lat&quot;</span><span style="color: #000000">:     </span><span style="color: #098658">50.8358216</span><span style="color: #000000">, </span></span>
<span class="line"><span style="color: #000000"> </span><span style="color: #0451A5">&quot;lon&quot;</span><span style="color: #000000">:     </span><span style="color: #098658">4.3386884</span><span style="color: #000000">}</span></span></code></pre></div>



<p>Dans un <a href="/geocodage-quel-outil-pour-quel-besoin/">article précédent</a>, nous avons montré qu&#8217;il existe une série d&#8217;outils pour réaliser cette opération et que, dans certaines circonstances, il est nécessaire de disposer d&#8217;un outil sur site (on-premise), ou local. Nous avons déjà mis en avant <a href="/geocodage-contourner-les-lacunes-dopenstreetmap-partie-2/">NominatimWrapper</a>, une solution que nous avons développée, basée sur <a href="https://openstreetmap.org/">OpenStreetMap</a>.</p>



<p>En Belgique, le service public fédéral <a href="https://bosa.belgium.be/fr">&#8220;Stratégie et Appui&#8221; (BOSA)</a> gère <a href="https://opendata.bosa.be/index.fr.html">BeSt Address</a>, la source authentique des adresses belges. Elles sont disponibles en open data dans différents formats. Dans cet article, nous allons nous pencher sur la question suivante&nbsp;: <em>est-il possible de mettre en place un géocodeur local basé sur ces données</em>&nbsp;? La réponse nécessite une certaine nuance&nbsp;: Oui, mais&#8230;</p>



<p>Précisons d&#8217;abord que BOSA met à disposition <a href="https://bosa.belgium.be/fr/services/best-address-services">une série de web services</a>, mais avec deux limitations&nbsp;: </p>



<ul class="wp-block-list">
<li>Ceux-ci sont uniquement disponibles pour les services publics, pas pour les entreprises ou les citoyens ;</li>



<li>Ils n&#8217;offrent pas l&#8217;aspect &#8220;standardisation&#8221;&nbsp;: il est nécessaire de connaitre l&#8217;orthographe (quasi) exacte d&#8217;une rue ou d&#8217;une (sous-)commune pour l&#8217;utiliser. </li>
</ul>



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



<p>Le projet open source <a href="https://pelias.io/">Pelias</a> permet de mettre en place un géocodeur basé sur ses propres données. En combinaison avec <a href="https://openaddresses.io/">OpenAddresses.io</a>, un projet rassemblant des données d&#8217;adresses ouvertes, il est possible de déployer Pelias pour une série de pays ou de villes, <a href="https://github.com/pelias/docker/tree/master/projects/belgium">dont la Belgique avec BeSt Address (en combinaison avec OpenStreetMap)</a>.</p>



<p>S&#8217;il est facile de mettre en place un géocodeur combinant Pelias et BeSt Address qui semble bien marcher quand on le teste sur quelques adresses, on déchante vite quand on tente de passer à la vitesse supérieure, en lui envoyant des ensembles de données venant de la <a href="https://kbopub.economie.fgov.be/kbo-open-data/login?lang=fr">Banque Carrefour des Entreprises</a> (belge), du <a href="https://employer-identification-consult.prd.pub.socialsecurity.be/">répertoire des employeurs</a> (ONSS) ou encore du registre national. </p>



<p>Pelias permet deux modes d&#8217;interrogation&nbsp;: structuré ({&#8220;address&#8221;: &#8220;Avenue Fonsnsy 20&#8221;, &#8220;postalcode&#8221;: 1060, &#8220;locality&#8221;: &#8220;Saint-Gilles&#8221;}) ou non structuré ({&#8220;query&#8221;: &#8220;Avenue Fonsnsy 20, 1060 Saint-Gilles&#8221;}). Sur les données que nous avons testées (10.000 adresses provenant de diverses sources en légende ci-dessous) en mode structuré (cf. &#8220;pelias_struct&#8221; dans le graphique ci-dessous), Pelias n&#8217;a été capable de localiser précisément que de l&#8217;ordre de 55 % des adresses. Quelques pour cents (1-2) sont localisés au niveau de la rue, et dans +/- 35 % des cas, Pelias n&#8217;a trouvé que la ville &#8230; autant dire, rien d&#8217;exploitable. Et dans 7-10 %, on ne reçoit même aucun résultat.&nbsp; &nbsp;</p>



<p>Pelias fait un petit peu mieux en mode &#8220;non-structuré&#8221; (pelias), puisqu&#8217;il sera presque toujours capable de fournir un résultat, et 11 % des adresses supplémentaires sont localisées précisément.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-13 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_rrn_10000.png"><img loading="lazy" decoding="async" width="1024" height="594" data-id="20335" src="/wp-content/uploads/2024/03/matching_rate_rrn_10000-1024x594.png" alt="" class="wp-image-20335" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000-1024x594.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000-300x174.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000-768x445.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000-1536x891.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000.png 1843w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Registre National</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_rep_10000.png"><img loading="lazy" decoding="async" width="1024" height="594" data-id="20334" src="/wp-content/uploads/2024/03/matching_rate_rep_10000-1024x594.png" alt="" class="wp-image-20334" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rep_10000-1024x594.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rep_10000-300x174.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rep_10000-768x445.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rep_10000-1536x891.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rep_10000.png 1843w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Répertoire des Employeurs</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_best_10000.png"><img loading="lazy" decoding="async" width="1024" height="594" data-id="20332" src="/wp-content/uploads/2024/03/matching_rate_best_10000-1024x594.png" alt="" class="wp-image-20332" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_best_10000-1024x594.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_best_10000-300x174.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_best_10000-768x445.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_best_10000-1536x891.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_best_10000.png 1843w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">BeSt Addresses</figcaption></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_kbo_10000.png"><img loading="lazy" decoding="async" width="1024" height="594" data-id="20333" src="/wp-content/uploads/2024/03/matching_rate_kbo_10000-1024x594.png" alt="" class="wp-image-20333" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000-1024x594.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000-300x174.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000-768x445.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000-1536x891.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000.png 1843w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Banque Carrefour des Entreprises</figcaption></figure>
</figure>



<p>Il est intéressant de remarquer quelques éléments&nbsp;: </p>



<ul class="wp-block-list">
<li>Quand le résultat n&#8217;est pas précis, le résultat ne contient pas de données provenant de BeSt Address, mais d&#8217;OpenStreetMap (niveau &#8220;street&#8221;) ou WhosOnFirst (niveau &#8220;city&#8221;) ;</li>



<li>Il arrive qu&#8217;une adresse ne donne pas de résultat en mode &#8220;structuré&#8221;, mais en donne en &#8220;non-structuré&#8221;, et vice-versa ;</li>



<li>En mode structuré, Pelias semble fréquemment perturbé par la présence du paramètre &#8220;locality&#8221; en addition du &#8220;postalcode&#8221;. Souvent, une adresse donne un résultat de niveau &#8220;city&#8221; quand on lui fournit ce paramètre, mais de niveau &#8220;building&#8221; quand on lui fournit uniquement le code postal (en plus de la rue et du numéro). On peut voir la différence dans le graphique sur la ligne &#8220;pelias_struc_noloc&#8221;, où la partie localisée précisément (&#8220;building&#8221;, en vert) augmente de près de 25 %. En contrepartie, la partie localisée au niveau de la ville, grandement basée sur cet argument &#8220;locality&#8221;, disparaît quasiment ;</li>



<li>Le résultat fourni par Pelias ne contient pas de &#8220;BeSt id&#8221;, qui permettrait d&#8217;obtenir l&#8217;identifiant unique et authentique d&#8217;une adresse ;</li>



<li>Ni les adresses en français des communes flamandes à facilités (et vice-versa) ni les adresses germanophones des cantons de l&#8217;Est ne sont importées.</li>
</ul>



<p>Mais il y a à l&#8217;heure d&#8217;écrire ces lignes un problème encore plus important&nbsp;: les données utilisées par Pelias datent de mi-2021, et ce pour deux raisons&nbsp;:&nbsp;</p>



<ul class="wp-block-list">
<li>Le format reconnu par OpenAddresses a changé vers octobre 2021 et n&#8217;est plus compatible avec les fichiers mis à disposition par Bosa ;</li>



<li>OpenAddresses a changé son flux de données mi-2021&nbsp;: au préalable, les données préparées étaient mises à disposition à l&#8217;adresse <a href="https://results.openaddresses.io/">https://results.openaddresses.io/</a>, qui est toujours disponible mais dont les données ne sont plus mises à jour ; elles le sont maintenant sur <a href="https://batch.openaddresses.io/data">https://batch.openaddresses.io/data</a>. Mais Pelias n&#8217;a pas été adapté et continue à télécharger les données sur l&#8217;ancien système.</li>
</ul>



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



<p>Il semble donc assez clair que Pelias n&#8217;est en l&#8217;état, pas un candidat sérieux pour une application nécessitant de géocoder des adresses en Belgique. Tant les données importées (trop anciennes, sans ID, sans données au niveau des rues si un numéro n&#8217;est pas identifié) que la robustesse font défaut. Mais il nous semblait que le potentiel était là et avons cherché à l&#8217;améliorer. Il y avait deux pistes&nbsp;:&nbsp;</p>



<ul class="wp-block-list">
<li>Créer un &#8220;clone&#8221; de Pelias, en modifiant son code. Avec le risque de faire des changements qui ne soient pas compatibles avec les futures évolutions de Pelias, et un effort de compréhension et de développement important ;</li>



<li>Rajouter une &#8220;sur-couche&#8221;, comme nous l&#8217;avons déjà fait avec succès dans <a href="https://github.com/SmalsResearch/NominatimWrapper">NominatimWrapper</a>, pour pallier les défaut de Pelias. C&#8217;est cette seconde voie que nous avons choisie.</li>
</ul>



<p>Cet outil, que nous avons appelé &#8220;<em>bePelias</em>&#8221; et que nous mettons à disposition en open source (<a href="https://github.com/SmalsResearch/bePelias">https://github.com/SmalsResearch/bePelias</a>), fait principalement deux choses&nbsp;:</p>



<figure class="wp-block-image alignright size-full is-resized"><a href="/wp-content/uploads/2024/04/bepelias_archi.png"><img loading="lazy" decoding="async" width="672" height="381" src="/wp-content/uploads/2024/04/bepelias_archi.png" alt="" class="wp-image-20365" style="width:399px;height:auto" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/04/bepelias_archi.png 672w, https://www.smalsresearch.be/wp-content/uploads/2024/04/bepelias_archi-300x170.png 300w" sizes="auto, (max-width: 672px) 100vw, 672px" /></a></figure>



<ul class="wp-block-list">
<li>Une préparation plus complète des données de BeSt Address, incluant une série de données additionnelles (id des adresses, des rues, codes NIS des communes&#8230;), complétant l&#8217;aspect multilingue et permettant l&#8217;identification au niveau de la rue quand le numéro n&#8217;est pas connu. Nous avons par ailleurs configuré Pelias pour permettre l&#8217;interpolation (supposant que le &#8220;8&#8221; d&#8217;une rue, s&#8217;il n&#8217;est pas connu, se situe entre le &#8220;6&#8221; et le &#8220;10&#8221;).</li>



<li>Une couche intermédiaire entre Pelias et le client, sous forme de REST API, pour tenter une série de variantes d&#8217;une adresse. On testera une série de combinaisons des variantes suivantes, jusqu&#8217;à ce qu&#8217;une donne un résultat satisfaisant&nbsp;: 
<ul class="wp-block-list">
<li>Version structurée ou non-structurée de l&#8217;appel à Pelias ;</li>



<li>Avec la localité, ou uniquement le code postal ;</li>



<li>En nettoyant, avec une série d&#8217;expressions régulières, le nom de rue ou de localité. Typiquement, on enlèvera tout texte entre parenthèses, très fréquent dans les noms de rue pour préciser un commentaire ou le nom de la sous-commune ;</li>



<li>En nettoyant le numéro de maison, qui contient très souvent également un numéro de boite, ce qui ne change pas la localisation dans la plupart des cas.</li>
</ul>
</li>
</ul>



<figure class="wp-block-image alignleft size-full is-resized"><a href="/wp-content/uploads/2024/04/transformers.png"><img loading="lazy" decoding="async" width="631" height="409" src="/wp-content/uploads/2024/04/transformers.png" alt="" class="wp-image-20360" style="width:487px;height:auto" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/04/transformers.png 631w, https://www.smalsresearch.be/wp-content/uploads/2024/04/transformers-300x194.png 300w" sizes="auto, (max-width: 631px) 100vw, 631px" /></a></figure>



<p>Dans la pratique, on constate que la version structurée &#8220;de base&#8221; (sans nettoyage ou sélection) donne un résultat dans +/- 50 % des adresses (pour les données KBO, cf. figure ci-jointe). Viennent ensuite 20 % après suppression de la localité, toujours en structuré, puis 11 % en non structuré, 8 % après nettoyage en structuré, puis une série d&#8217;autres combinaisons pour un petit nombre d&#8217;adresses. Quasiment toutes les combinaisons sont utiles à un moment.</p>



<h2 class="wp-block-heading">Résultats</h2>



<p>Le résultat est visible dans les graphiques ci-dessous. La solution bePelias est quasiment aussi efficace que Here WeGo (here dans les graphiques) ou Bing Maps de Microsoft (bing); meilleure que Google Maps (google), qui s&#8217;avère assez sensible au bruit dans les adresses, comme du texte entre parenthèse, ainsi que NominatimWrapper, qui localise uniquement les rues d&#8217;une grande proportion d&#8217;adresses.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-14 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/04/matching_rate_rep_10000.png"><img loading="lazy" decoding="async" width="1024" height="587" data-id="20449" src="/wp-content/uploads/2024/04/matching_rate_rep_10000-1024x587.png" alt="" class="wp-image-20449" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_rep_10000-1024x587.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_rep_10000-300x172.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_rep_10000-768x440.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_rep_10000-1536x880.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_rep_10000.png 1866w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_rrn_10000_2.png"><img loading="lazy" decoding="async" width="1024" height="587" data-id="20351" src="/wp-content/uploads/2024/03/matching_rate_rrn_10000_2-1024x587.png" alt="" class="wp-image-20351" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000_2-1024x587.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000_2-300x172.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000_2-768x440.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000_2-1536x880.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_rrn_10000_2.png 1866w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/04/matching_rate_best_10000_2.png"><img loading="lazy" decoding="async" width="1024" height="587" data-id="20358" src="/wp-content/uploads/2024/04/matching_rate_best_10000_2-1024x587.png" alt="" class="wp-image-20358" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_best_10000_2-1024x587.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_best_10000_2-300x172.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_best_10000_2-768x440.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_best_10000_2-1536x880.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/04/matching_rate_best_10000_2.png 1866w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/03/matching_rate_kbo_10000_2.png"><img loading="lazy" decoding="async" width="1024" height="587" data-id="20349" src="/wp-content/uploads/2024/03/matching_rate_kbo_10000_2-1024x587.png" alt="" class="wp-image-20349" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000_2-1024x587.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000_2-300x172.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000_2-768x440.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000_2-1536x880.png 1536w, https://www.smalsresearch.be/wp-content/uploads/2024/03/matching_rate_kbo_10000_2.png 1866w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a></figure>
</figure>



<p>Nous avons également testé l&#8217;exactitude des résultats de bePelias selon une méthodologie de vote par majorité en envoyant un même ensemble de données à plusieurs géocodeurs. Nous avons présenté les résultats lors d&#8217;<a href="/webinar-geocoding-follow-up/">un récent webinaire</a>, qui nous montrent des performances très proches de Here WeGo ou Bing Maps, et, à nouveau, sensiblement meilleures que Google Maps, qui outre le fait qu&#8217;il ne situe fréquemment que la rue, a une fâcheuse à l&#8217;hallucination, en proposant des résultats à des milliers de kilomètres de la bonne réponse.</p>



<p>En termes de vitesse, le fait que la solution soit sur site lui donne un avantage non-négligeable, en étant deux fois plus rapide que Google Maps ou 5 fois que Bing Maps. Ceci nécessitera bien sûr d&#8217;installer le géocodeur au plus près de l&#8217;application qui en a besoin.</p>



<h2 class="wp-block-heading">Conclusions&nbsp;: outil bePelias</h2>



<p>Sur base de ce qui précède, nous proposons une solution fonctionnelle, bePelias, qui permet d&#8217;instancier un géocodeur localement. Ceci se fait à l&#8217;aide de Docker, est basé uniquement sur du code source ouvert (Pelias) et de données ouvertes (principalement BeSt Address), avec à peine un gros milliers de lignes de code additionnel en Python ou Bash.</p>



<p>Elle n&#8217;a bien sûr pas que des avantages&nbsp;:</p>



<ul class="wp-block-list">
<li>Elle ne marche que pour la Belgique ;</li>



<li>Elle ne marche que pour des adresses. Vous n&#8217;aurez pas de réponse à &#8220;Smals, Saint-Gilles&#8221;, ou &#8220;Boulangerie, Namur&#8221; ;</li>



<li>Elle nécessite la mise en place, la gestion et la maintenance (mise à jour du serveur, de bePelias et des données de BeSt Address) d&#8217;un serveur avec une quinzaine de GB de disque et au moins 8 GB de mémoire RAM, ce qui, en fonction du projet, peut représenter un coût supérieur à l&#8217;utilisation d&#8217;une solution <em>cloud</em> commerciale ;</li>



<li>Il s&#8217;agit encore à ce stade d&#8217;un projet de recherche qui doit faire ses preuves dans un environnement industriel.</li>
</ul>



<p>Mais en contrepartie&nbsp;:</p>



<ul class="wp-block-list">
<li>Elle offre des performances comparables aux grands acteurs commerciaux du secteur ;</li>



<li>Elle est on-premise, ce qui règle des problèmes de confidentialité ou liés aux RGPD ;</li>



<li>Elle est basée sur BeSt Address, c&#8217;est-à-dire la (récente) source authentique des adresses en Belgique. L&#8217;obtention d&#8217;un &#8220;BeSt id&#8221; permettra d&#8217;interagir plus facilement avec une série de webservices qui auront intégré cette source.</li>
</ul>



<p>Des retours d&#8217;expérience sont bienvenus et aideront à faire progresser cet outil qui ne demande qu&#8217;à être utilisé&nbsp;!</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>


<ol class="wp-block-footnotes"><li id="b7665c04-0011-4cad-a98a-5e516f4a994c">Il s&#8217;agit d&#8217;un exemple illustratif simplifié, dont la syntaxe ne correspond à aucun outil connu. <a href="#b7665c04-0011-4cad-a98a-5e516f4a994c-link" aria-label="Jump to footnote reference 1"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></li></ol>


<p><span style="color: #999999;"><em>Ce post est une contribution individuelle de Vandy Berten, spécialisé&nbsp;</em>en<em>&nbsp;data science&nbsp;chez Smals Research. Cet article est écrit en son nom propre et n’impacte en rien le point de vue de Smals.</em></span></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Évaluation d&#8217;un système génératif de questions-réponses</title>
		<link>https://www.smalsresearch.be/evaluation-dun-systeme-generatif-de-questions-reponses/</link>
		
		<dc:creator><![CDATA[Bert Vanhalst]]></dc:creator>
		<pubDate>Fri, 19 Apr 2024 14:12:45 +0000</pubDate>
				<category><![CDATA[[FR]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[cloud computing]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[software engineering]]></category>
		<guid isPermaLink="false">/?p=20428</guid>

					<description><![CDATA[Les frameworks d'évaluation des applications RAG permettent une évaluation systématique de la qualité des systèmes génératifs de questions-réponses. Ils permettent de mesurer différents aspects, tels que la capacité à récupérer des informations pertinentes (retrieval) et la qualité des réponses générées. Ces métriques sont essentielles pour comprendre les faiblesses d'un système RAG et apporter les ajustements nécessaires.]]></description>
										<content:encoded><![CDATA[
<p><a href="/evalueren-van-een-generatief-vraag-antwoordsysteem/"><em>Nederlandstalige versie</em></a></p>
<p>Dans un <a href="/qualite-dun-systeme-generatif-de-questions-reponses/">précédent article de blog</a>, nous avons décrit quelques techniques permettant d&#8217;améliorer la qualité des réponses dans un <a href="/un-propre-systeme-de-questions-reponses-base-sur-des-modeles-de-langue/">système génératif de questions-réponses</a>.</p>
<p>Pour rappel, RAG (<em>Retrieval Augmented Generation</em>) est l&#8217;architecture appropriée pour éviter les <a href="https://fr.wikipedia.org/wiki/Hallucination_(intelligence_artificielle)">hallucinations</a> en fournissant aux modèles de langage un contexte. Avant que le modèle de langage ne génère une réponse, il récupère d&#8217;abord les informations les plus pertinentes pour la question (<em>retrieval</em>). Ces informations sont ensuite fournies en tant que contexte au modèle de langage, qui a pour mission de générer une réponse sur la base de ce contexte (<em>generation</em>). Des erreurs peuvent se produire à la fois lors de l&#8217;étape dite du <em>retrieval</em> et lors de l&#8217;étape dite de la <em>generation</em>. Il est donc nécessaire de surveiller la qualité.</p>
<figure id="attachment_19945" aria-describedby="caption-attachment-19945" style="width: 1270px" class="wp-caption aligncenter"><a href="/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN.png"><img loading="lazy" decoding="async" class="size-full wp-image-19945" src="/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN.png" alt="Uitvoeringsfase van een RAG pipeline" width="1270" height="530" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN.png 1270w, https://www.smalsresearch.be/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN-300x125.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN-768x321.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN-1024x427.png 1024w" sizes="auto, (max-width: 1270px) 100vw, 1270px" /></a><figcaption id="caption-attachment-19945" class="wp-caption-text">Illustration 1&nbsp;: Phase d&#8217;exécution d&#8217;un pipeline RAG</figcaption></figure>
<p>Dans cet article, nous examinons l&#8217;importance de mesurer la qualité d&#8217;un système RAG, les défis à relever, les mesures que nous pouvons appliquer et les outils et cadres qui peuvent nous aider à le faire.</p>



<h2 class="wp-block-heading">L&#8217;importance de l’évaluation</h2>



<p>Avant de décrire comment évaluer un système génératif de réponse aux questions, prenons le temps de réfléchir aux raisons de cette évaluation.</p>
<p>Un système génératif de réponse aux questions est intrinsèquement sujet à des erreurs (hallucinations, imprécisions). Il est donc important de connaître la qualité des résultats afin d&#8217;identifier les points de friction et d&#8217;être en mesure d&#8217;améliorer la qualité de manière ciblée.</p>
<p>Les évaluations permettent d&#8217;établir un benchmark d&#8217;une première version du système de questions-réponses. La qualité des nouvelles versions du système peut ensuite être comparée à ce baseline ou aux versions précédentes. Ainsi, l&#8217;impact des changements peut être mesuré, comme l&#8217;amélioration de la composante de retrieval, le déploiement d&#8217;un modèle de langage différent ou la modification du prompt.</p>
<p>Les évaluations peuvent aider à décider si le système doit être mis en production ou non. Elles peuvent renforcer la confiance dans le système en démontrant qu&#8217;il est précis et fiable.</p>



<h2 class="wp-block-heading">Les défis de l&#8217;évaluation</h2>



<p><em>Métriques </em>&#8211; Contrairement aux logiciels traditionnels, l&#8217;output des applications LLM n&#8217;est pas déterministe&nbsp;: une entrée spécifique peut conduire à de multiples outputs corrects (ou erronés). L&#8217;output peut être subjectif. Par conséquent, nous ne pouvons pas simplement utiliser &#8220;vrai ou faux&#8221; comme critère d&#8217;évaluation, nous devons recourir à d&#8217;autres critères. Comparons cela à l&#8217;évaluation d&#8217;une dissertation (non déterministe) par rapport à l&#8217;évaluation de réponses à des questions à choix multiples (déterministe).</p>
<p><em>Scalabilité </em>&#8211; Pour avoir une première impression rapide de la qualité d&#8217;un système génératif de questions-réponses, vous pouvez effectuer des tests manuellement, par exemple en posant une vingtaine de questions et en évaluant manuellement la qualité des réponses générées. Mais cette méthode est difficile à maintenir si vous souhaitez effectuer une évaluation à plus grande échelle, avec un set de test plus important ou lorsque toutes les réponses sont évaluées alors que le système fonctionne en production. Dans ce cas, il est intéressant d&#8217;effectuer des évaluations automatiques. Cela implique l&#8217;utilisation d&#8217;un modèle de langage pour évaluer un aspect particulier. On parle alors de &#8220;<em>LLM-as-judge</em>&#8220;.</p>
<p><em>Qualité </em>&#8211; L&#8217;utilisation de modèles de langage pour évaluer les résultats des modèles de langage est quelque peu surprenante. De telles évaluations automatiques peuvent elles-mêmes contenir des erreurs ; nous devons être vigilants quant à leur qualité.</p>
<p><em>Rentabilité</em> &#8211; L&#8217;exécution d&#8217;évaluations automatiques basées sur des modèles de langage implique des coûts pour l&#8217;utilisation de ces LLM typiquement offerts comme un service API dans le cloud. Si nous ne faisons pas attention, le coût de ces évaluations peut augmenter considérablement et même dépasser le coût de traitement des requêtes des utilisateurs finaux.</p>
<p><em>Confidentialité </em>&#8211; La réalisation d&#8217;évaluations basées sur les LLM peut exposer des informations confidentielles aux fournisseurs de services LLM basés sur le cloud.</p>
<p><em>Granularité </em>&#8211; Vous voulez non seulement connaître le degré de précision de la réponse générée, mais aussi découvrir la cause de toute erreur ou inexactitude. Pour ce faire, vous devez conserver des<em> log traces</em> détaillés.</p>
<p>Il est évidemment important d&#8217;interpréter ce qui a été mesuré par une métrique particulière. Ci-dessous, nous essayons d&#8217;expliquer clairement les métriques les plus couramment utilisées.</p>



<h2 class="wp-block-heading">Métriques d&#8217;évaluation</h2>



<p>Bien qu&#8217;il n&#8217;y ait pas encore de normalisation des métriques, des initiatives émergent qui peuvent fournir des orientations importantes. Par exemple, la <a href="https://truera.com/ai-quality-education/generative-ai-rags/what-is-the-rag-triad/">RAG triad</a> de TruEra décrit trois métriques liées à la requête de l&#8217;utilisateur final (<em>query</em>), au contexte récupéré par le <em>retrieval system</em> (<em>context</em>) et à la réponse éventuellement générée par le modèle de langage (<em>response</em>).</p>
<figure id="attachment_20387" aria-describedby="caption-attachment-20387" style="width: 1024px" class="wp-caption aligncenter"><a href="/wp-content/uploads/2024/04/RAG_triad.png"><img loading="lazy" decoding="async" class="size-full wp-image-20387" src="/wp-content/uploads/2024/04/RAG_triad.png" alt="RAG triad" width="1024" height="634" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/04/RAG_triad.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/04/RAG_triad-300x186.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/04/RAG_triad-768x476.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption id="caption-attachment-20387" class="wp-caption-text">Illustration 2&nbsp;: RAG triad (source : <a href="https://truera.com/ai-quality-education/generative-ai-rags/what-is-the-rag-triad/">https://truera.com/ai-quality-education/generative-ai-rags/what-is-the-rag-triad/</a>)</figcaption></figure>
<ul>
<li><strong><em>Context relevance</em></strong> indique le degré de pertinence du contexte par rapport à la question posée. Le contexte récupéré lors de l&#8217;étape <em>retrieval</em> est basé sur une recherche sémantique (<em>similarity search</em>), ce qui ne signifie pas nécessairement que ce contexte est pertinent par rapport à la question posée. Cette métrique permet d&#8217;identifier les problèmes éventuels lors de l&#8217;étape de<em> retrieval</em>.</li>
<li><strong><em>Groundedness</em></strong> indique dans quelle mesure la réponse est étayée par le contexte. Même si tout le contexte pertinent est fourni au modèle de langage, ce dernier peut toujours inventer (une partie de) la réponse. Cette métrique vérifie si (les différentes parties de) la réponse peuvent être retracées jusqu&#8217;aux <em>statements</em> du contexte. En d&#8217;autres termes, peut-on trouver des preuves de la réponse dans le contexte fourni ? Si le score <em>groundedness</em> n&#8217;est pas assez élevé, la réponse générée peut ne pas être transmise à l&#8217;utilisateur, mais plutôt indiquer qu&#8217;il n&#8217;y a pas assez d&#8217;informations disponibles pour répondre à la question.</li>
<li><strong><em>Answer relevance</em></strong> indique dans quelle mesure la réponse est effectivement une réponse à la question posée. La réponse peut être correcte sur le plan factuel et étayée par le contexte, sans pour autant constituer une réponse à la question posée. Cette métrique ne tient pas compte de l&#8217;exactitude factuelle de la réponse, mais pénalise les réponses incomplètes ou redondantes</li>
</ul>
<p>Outre ces trois métriques, la réponse peut également être comparée à une réponse de référence (<em>ground truth</em> ou réponse d&#8217;un expert considérée comme correcte), comme les métriques du <a href="https://docs.ragas.io/en/stable/concepts/metrics/index.html">framework Ragas</a> :</p>
<ul>
<li><strong><em>Answer semantic similarity</em></strong> donne une évaluation de la similarité sémantique entre la réponse générée et la réponse de référence.</li>
<li><strong><em>Answer correctness</em></strong>: il s&#8217;agit d&#8217;une combinaison de l<em>&#8216;answer semantic similarity</em> et de l&#8217;<em>answer factual similarity</em>. L&#8217;idée de la<em> factual similarity</em> est de mesurer la pertinence des énoncés de la réponse générée par rapport à ceux de la réponse de référence.</li>
</ul>
<p>En outre, il existe également des métriques permettant d&#8217;évaluer la <a href="https://www.rungalileo.io/blog/mastering-rag-advanced-chunking-techniques-for-llm-applications">stratégie de chunking</a>, telles que celle proposée par <a href="https://www.rungalileo.io/blog/mastering-rag-advanced-chunking-techniques-for-llm-applications">Galileo</a> :</p>
<ul>
<li><strong><em>Chunk attribution</em></strong> indique combien de chunks et quels chunks ont été utilisés pour générer la réponse. L&#8217;extraction d&#8217;un trop grand nombre de chunks qui ne contribuent pas à la réponse diminue la qualité du système et entraîne des coûts plus élevés parce que de nombreux tokens sont envoyés inutilement au modèle de langage.</li>
<li><strong><em>Chunk utilization</em></strong> mesure, pour un chunk donné, la part de celui-ci qui a été effectivement utilisée pour générer la réponse. Un score faible signifie qu&#8217;une grande partie du chunk n&#8217;est pas pertinente pour répondre à la question. Un ajustement de la taille des chunks peut permettre d&#8217;optimiser le système.</li>
</ul>
<p>Ces deux métriques peuvent être utilisées pour optimiser la stratégie de chunking. Des valeurs optimales pour ces métriques signifient que moins d&#8217;informations non pertinentes sont fournies au modèle de langage, ce qui réduit les coûts et aide le modèle à rester concentré.</p>
<p>Pour toutes les métriques susmentionnées, l&#8217;accent est mis sur la qualité des réponses ou sur les éléments qui y contribuent. En outre, les métriques peuvent également être évaluées pour vérifier si les réponses sont nuisibles (contenu nuisible ou inapproprié, jailbreaks, etc.), ou si elles ont la bonne forme (cohérentes, concises, le bon ton, etc.). Les aspects non fonctionnels peuvent également être pris en compte, tels que la latence et le coût.</p>
<p>Enfin, il est important de mentionner que les métriques basées sur le LLM ne sont pas définies à l&#8217;aide de formules mathématiques. Des erreurs sont possibles et le résultat de la mesure doit être considéré comme une indication approximative. Par conséquent, l&#8217;évaluation par des experts business reste indispensable.</p>
<p>Dans ce contexte, on parle d&#8217;alignement&nbsp;: il s&#8217;agit de s&#8217;assurer que l&#8217;application d&#8217;IA générative répond aux attentes du business.</p>



<h2 class="wp-block-heading">Quand évaluer&nbsp;?</h2>



<p>Les évaluations peuvent en principe être effectuées à chaque étape du cycle de vie d&#8217;une application : à chaque correction de bogue ou mise à jour de fonctionnalité, à chaque déploiement et une fois que l&#8217;application est opérationnelle.</p>
<p>Il existe des moyens d&#8217;intégrer des évaluations automatiques dans le pipeline CI, par exemple pre-commit ou pre-release. Des outils comme <a href="https://circleci.com/ai-llm/">CircleCI</a> misent sur ce type de support.</p>
<p>Afin de mesurer l&#8217;évolution de la qualité entre les différentes itérations du système, il est important de mettre en place un set de test fixe avec un certain nombre de questions et les réponses de référence correspondantes. Les questions doivent être aussi représentatives que possible du type de questions qui seront effectivement posées par les utilisateurs finaux.</p>
<p>Les métriques utilisées pour améliorer le système avant sa mise en production peuvent également être utilisées pendant la phase de production pour vérifier si les réponses aux questions réelles des utilisateurs finaux sont suffisamment précises. Comme indiqué précédemment, le coût de l&#8217;utilisation de modèles de langage en tant qu&#8217;évaluateur doit être pris en compte afin de ne pas faire dérailler les coûts.</p>



<h2 class="wp-block-heading">Outils et frameworks</h2>



<p>Sans vouloir être exhaustifs, voici quelques outils et cadres qui peuvent fortement appuyer la conduite des évaluations :</p>
<ul>
<li><a href="https://www.rungalileo.io/"><strong>Galileo</strong></a> est une plateforme d’évaluation et de suivi des applications d’IA générative. Elle fournit des métriques spécifiques pour l&#8217;optimisation de la stratégie de chunking (<em>chunk attribution</em> et <em>chunk utilisation</em>, voir ci-dessus). Il est également possible d&#8217;appliquer des guardrails en temps réel : la réponse peut être ajustée, par exemple en cas d&#8217;hallucinations ou de contenu nuisible. Les résultats des évaluations peuvent être inspectés visuellement dans une console qui est basée sur le cloud par défaut, mais qui peut également être hébergée sur une infrastructure interne. Enfin, pour réduire le coût des évaluations et préserver la confidentialité des données, Galileo travaille sur une solution basée sur des modèles plus légers qui peuvent être exécutés localement.</li>
<li><a href="https://ragas.io/"><strong>Ragas</strong></a> est un framework open source pour évaluer les applications basées sur RAG. Il fournit un ensemble complet de métriques qui évaluent l&#8217;ensemble du système. Il s&#8217;agit notamment de mesures qui comparent la réponse générée à une réponse de référence (<em>answer semantic similarity</em> et <em>answer correctness</em>).</li>
<li><a href="https://www.trulens.org/"><strong>TruLens</strong></a> est un projet communautaire open source sous l&#8217;égide de <a href="https://truera.com/ai-quality-education/generative-ai-rags/what-is-the-rag-triad/">TruEra</a>. TruEra a inventé le terme &#8220;RAG triad&#8221; qui combine 3 métriques pour évaluer les hallucinations dans les applications basées sur le LLM.</li>
</ul>



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



<p>Les frameworks d&#8217;évaluation des applications RAG permettent un suivi et une évaluation systématiques de la qualité des systèmes génératifs de questions-réponses. Ils permettent de mesurer différents aspects, tels que la capacité à récupérer des informations pertinentes (<em>retrieval</em>) et la qualité des réponses générées. Ces métriques sont essentielles pour comprendre les faiblesses d&#8217;un système RAG et apporter les ajustements nécessaires.</p>
<p>L&#8217;utilisation d&#8217;un LLM peut automatiser l&#8217;exécution des évaluations et rendre les tests évolutifs. Cependant, il faut faire attention aux coûts que cela peut engendrer. Un modèle de langage en tant qu&#8217;évaluateur n&#8217;est pas exempt d&#8217;erreurs, mais il peut fournir un aperçu suffisant des domaines d&#8217;amélioration possibles d&#8217;un système génératif de questions-réponses. Toutefois, les résultats des mesures doivent être considérés comme une indication approximative ; nous ne pouvons pas nous y fier aveuglément. Par conséquent, l&#8217;évaluation par des experts business reste indispensable.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p><em>Ce post est une contribution individuelle de Bert Vanhalst, IT consultant chez Smals Research. Cet article est écrit en son nom propre et n’impacte en rien le point de vue de Smals.</em></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Evalueren van een generatief vraag-antwoordsysteem</title>
		<link>https://www.smalsresearch.be/evalueren-van-een-generatief-vraag-antwoordsysteem/</link>
		
		<dc:creator><![CDATA[Bert Vanhalst]]></dc:creator>
		<pubDate>Fri, 12 Apr 2024 17:05:02 +0000</pubDate>
				<category><![CDATA[[NL]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[cloud computing]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[software engineering]]></category>
		<guid isPermaLink="false">/?p=20385</guid>

					<description><![CDATA[Frameworks voor het evalueren van RAG toepassingen laten toe om de kwaliteit van generatieve vraag-antwoordsystemen systematisch te beoordelen. Ze voorzien een manier om verschillende aspecten te meten, zoals het vermogen om relevante informatie op te halen (retrieval) en de kwaliteit van de gegenereerde antwoorden. Dergelijke metrieken zijn cruciaal om inzicht te krijgen in de eventuele zwakke punten van een RAG systeem en waar nodig te kunnen bijsturen.]]></description>
										<content:encoded><![CDATA[
<p><a href="/evaluation-dun-systeme-generatif-de-questions-reponses/"><em>Version en français</em></a></p>
<p>In een <a href="/kwaliteit-van-een-generatief-vraag-antwoordsysteem/">vorige blogpost</a> hebben we een aantal technieken beschreven voor het verbeteren van de kwaliteit van de antwoorden in een <a href="/een-eigen-vraag-en-antwoordsysteem-op-basis-van-taalmodellen/">generatief vraag-antwoordsysteem</a>.</p>
<p>Ter herinnering, RAG (<em>Retrieval Augmented Generation</em>) is de aangewezen architectuur om <a href="https://nl.wikipedia.org/wiki/Hallucinatie_(kunstmatige_intelligentie)">hallucinaties</a> te vermijden door taalmodellen van context te voorzien. Vooraleer het taalmodel een antwoord genereert, wordt eerst de meest relevante informatie voor de vraag opgezocht (<em>retrieval</em>). Die informatie wordt dan als context meegegeven aan het taalmodel met als opdracht om een antwoord te genereren op basis van die meegeleverde context (<em>generation</em>). Zowel bij de retrieval-stap als bij de generatie-stap kunnen er fouten optreden. Daarom is het nodig om de vinger aan de pols te houden om de kwaliteit te bewaken.</p>
<figure id="attachment_19945" aria-describedby="caption-attachment-19945" style="width: 1270px" class="wp-caption aligncenter"><a href="/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN.png"><img loading="lazy" decoding="async" class="size-full wp-image-19945" src="/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN.png" alt="Uitvoeringsfase van een RAG pipeline" width="1270" height="530" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN.png 1270w, https://www.smalsresearch.be/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN-300x125.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN-768x321.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/02/RAG_uitvoeringsfase_EN-1024x427.png 1024w" sizes="auto, (max-width: 1270px) 100vw, 1270px" /></a><figcaption id="caption-attachment-19945" class="wp-caption-text">Figuur 1: Uitvoeringsfase van een RAG pipeline</figcaption></figure>
<p>In dit artikel bespreken we het belang van het meten van de kwaliteit van een RAG systeem, de uitdagingen die zich stellen, de metrieken die we kunnen toepassen en de tools en frameworks die ons daarbij kunnen ondersteunen.</p>



<h2 class="wp-block-heading">Het belang van evalueren</h2>



<p>Vooraleer we aangeven hoé we een generatief vraag-antwoordsysteem kunnen evalueren, staan we toch even stil bij het waarom.</p>
<p>Een generatief vraag-antwoordsysteem is inherent onderhevig aan fouten (hallucinaties, onnauwkeurigheden). Het is daarom belangrijk om de kwaliteit te kennen van de output om pijnpunten bloot te leggen en de kwaliteit gericht te kunnen verbeteren.</p>
<p>Evaluaties laten toe om een benchmark op te stellen van een eerste versie van het vraag-antwoordsysteem. De kwaliteit van nieuwere versies van het systeem kan dan vergeleken worden met deze baseline of vorige versies. Zo kan de impact van veranderingen gemeten worden, zoals het verbeteren van de retrieval component, het inzetten van een ander taalmodel of een aanpassing van de prompt.</p>
<p>Evaluaties kunnen helpen bij het nemen van de beslissing om het systeem al dan niet in productie te nemen. Ze kunnen het vertrouwen in het systeem vergroten door aan te tonen dat het nauwkeurig en betrouwbaar is.</p>



<h2 class="wp-block-heading">De uitdagingen bij evalueren</h2>



<p><em>Metrieken </em>&#8211; In tegenstelling tot traditionele software, is de output van LLM-gebaseerde toepassingen niet deterministisch: een specifieke input kan leiden tot meerdere correcte (of foutieve) outputs. De output kan subjectief zijn. Daarom kunnen we als evaluatiecriterium niet eenvoudig &#8220;juist of fout&#8221; gebruiken en moeten we onze toevlucht nemen tot andere criteria. Vergelijk het met het evalueren van een opstel (niet deterministisch) versus het evalueren van antwoorden op meerkeuzevragen (wel deterministisch).</p>
<p><em>Schaalbaarheid </em>– Om snel een eerste indruk te krijgen van de kwaliteit van een generatief vraag-antwoordsysteem kan je manueel enkele testen uitvoeren, bijvoorbeeld een 20-tal vragen stellen en de kwaliteit van de gegenereerde antwoorden manueel evalueren. Maar dit is moeilijk vol te houden als je op grotere schaal wil evalueren, bij een grotere testset of bij het evalueren van alle antwoorden als het systeem in productie draait. In dat geval loont het de moeite om automatische evaluaties uit te voeren. Daarbij wordt een taalmodel ingezet om een bepaald aspect te beoordelen. Er wordt gesproken van “<em>LLM-as-judge</em>”.</p>
<p><em>Kwaliteit </em>– Het gebruik van taalmodellen voor het evalueren van de output van … taalmodellen is enigszins verrassend. Dergelijke automatische evaluaties kunnen op zich ook fouten bevatten; we moeten waakzaam zijn over de kwaliteit ervan.</p>
<p><em>Kostenefficiëntie </em>–Het uitvoeren van automatische evaluaties op basis van taalmodellen brengt kosten met zich mee voor het gebruik van die LLM’s die typisch als API service in de cloud aangeboden worden. Als we niet opletten kan de kost voor die evaluaties fors oplopen en de kost van het afhandelen van de vragen van eindgebruikers zelfs overstijgen.</p>
<p><em>Vertrouwelijkheid </em>– Bij het uitvoeren van evaluaties op basis van LLM’s kan vertrouwelijke informatie blootgesteld worden aan de leveranciers van cloudgebaseerde LLM diensten.</p>
<p><em>Granulariteit </em>– Je wil niet alleen weten hoe nauwkeurig het gegenereerde antwoord is, maar je wil ook de oorzaak achterhalen van eventuele fouten of onnauwkeurigheden. Daarvoor is het nodig om gedetailleerde log traces bij te houden.</p>
<p>Het interpreteren van wat nu precies gemeten werd met een bepaalde metriek is uiteraard belangrijk. Hierna trachten we de meestgebruikte metrieken duidelijk toe te lichten.</p>



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



<p>Alhoewel er nog geen standaardisatie is van metrieken, duiken er toch initiatieven op die een belangrijk houvast kunnen bieden. Zo beschrijft de <a href="https://truera.com/ai-quality-education/generative-ai-rags/what-is-the-rag-triad/">RAG triad</a> van TruEra 3 metrieken die verband houden met de vraag van de eindgebruiker (<em>query</em>), de context opgehaald door het retrieval systeem (<em>context</em>) en het antwoord dat uiteindelijk gegenereerd wordt door het taalmodel (<em>response</em>).</p>
<figure id="attachment_20387" aria-describedby="caption-attachment-20387" style="width: 1024px" class="wp-caption aligncenter"><a href="/wp-content/uploads/2024/04/RAG_triad.png"><img loading="lazy" decoding="async" class="size-full wp-image-20387" src="/wp-content/uploads/2024/04/RAG_triad.png" alt="RAG triad" width="1024" height="634" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/04/RAG_triad.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/04/RAG_triad-300x186.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/04/RAG_triad-768x476.png 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption id="caption-attachment-20387" class="wp-caption-text">Figuur 2: De RAG triad (bron: <a href="https://truera.com/ai-quality-education/generative-ai-rags/what-is-the-rag-triad/">https://truera.com/ai-quality-education/generative-ai-rags/what-is-the-rag-triad/</a>)</figcaption></figure>
<ul>
<li><strong>Context relevance</strong> geeft aan hoe relevant de context is voor de gestelde vraag. De context die opgehaald wordt in de retrieval stap is gebaseerd op een semantische zoekopdracht (similarity search), wat niet noodzakelijk betekent dat die context relevant is voor de gestelde vraag. Deze metriek helpt om eventuele problemen te identificeren in de retrieval stap.</li>
<li><strong>Groundedness</strong> geeft aan in hoeverre het antwoord ondersteund wordt door de context. Zelfs indien alle relevante context aangeleverd wordt aan het taalmodel, kan het taalmodel nog altijd een (deel van het) antwoord verzinnen. Deze metriek checkt of (de verschillende delen van) het antwoord teruggeleid kunnen worden tot statements in de context. Met andere woorden: is er voor het antwoord bewijs terug te vinden in de aangeleverde context? Indien de <em>groundedness</em> score niet hoog genoeg is kan ervoor gekozen worden om het gegenereerde antwoord niet door te geven aan de gebruiker, maar eerder aan te geven dat er niet genoeg informatie beschikbaar is om de vraag te beantwoorden.</li>
<li><strong>Answer relevance</strong> geeft aan in hoeverre het antwoord effectief een antwoord is op de gestelde vraag. Het antwoord kan feitelijk correct zijn en ondersteund zijn door de context, maar toch geen antwoord zijn op de gestelde vraag. Deze metriek houdt geen rekening met de feitelijke correctheid van het antwoord, maar straft wel onvolledige of redundante antwoorden af.</li>
</ul>
<p>Naast deze 3 metrieken kan het antwoord ook vergeleken worden met een referentie-antwoord (<em>ground truth</em>, of expert-antwoord dat als correct beschouwd wordt), zoals deze metrieken uit het <a href="https://docs.ragas.io/en/stable/concepts/metrics/index.html">Ragas framework</a>:</p>
<ul>
<li><strong>Answer semantic similarity</strong> geeft een beoordeling van de semantische overeenkomst tussen het gegenereerde antwoord en het referentie-antwoord.</li>
<li><strong>Answer correctness</strong>: dit is een combinatie van <em>semantic similarity</em> en <em>factual similarity</em>. Het idee van <em>factual similarity</em> is om te meten in hoeverre de beweringen in het gegenereerde antwoord overeenkomen met die in het referentie-antwoord.</li>
</ul>
<p>Verder zijn er ook metrieken om de <a href="https://www.rungalileo.io/blog/mastering-rag-advanced-chunking-techniques-for-llm-applications">chunking strategie te evalueren</a>, zoals deze van <a href="https://www.rungalileo.io/blog/mastering-rag-advanced-chunking-techniques-for-llm-applications">Galileo</a>:</p>
<ul>
<li><strong>Chunk attribution</strong> geeft aan hoeveel chunks en welke chunks gebruikt werden voor het genereren van het antwoord. Teveel chunks ophalen die niet bijdragen tot het antwoord verlaagt de kwaliteit van het systeem en leidt tot hogere kosten omdat er onnodig veel tokens naar het taalmodel worden gestuurd.</li>
<li><strong>Chunk utilization</strong> meet voor een bepaalde chunk hoeveel ervan effectief gebruikt werd voor het genereren van het antwoord. Een lage score betekent dat een groot deel van de chunk niet relevant is voor het beantwoorden van de vraag. Een bijsturing van de grootte van de chunks kan het systeem optimaliseren.</li>
</ul>
<p>Deze beide metrieken kunnen gebruikt worden om de chunking strategie te optimaliseren. Optimale waarden voor deze metrieken betekent dat er minder irrelevante informatie aangeleverd wordt aan het taalmodel, wat de kosten beperkt en het model helpt om de focus te behouden.</p>
<p>Bij alle bovenvermelde metrieken ligt de focus op de kwaliteit van de antwoorden of zaken die daartoe bijdragen. Daarnaast kunnen ook metrieken geëvalueerd worden om na te gaan of de antwoorden schadelijk zijn (schadelijke of ongepaste inhoud, jailbreaks, etc), of de juiste vorm hebben (coherent, beknopt, de juiste toon, etc). Ook non-functionals kunnen meegenomen worden zoals latency en kost.</p>
<p>Tot slot is het belangrijk om te vermelden dat LLM-gebaseerde metrieken niet met behulp van wiskundige formules gedefinieerd zijn. Fouten zijn mogelijk en het meetresultaat moet gezien worden als een approximatieve indicatie. Daarom blijft een evaluatie door business experten onmisbaar.</p>
<p>Men spreekt in deze context over <em>alignment</em>: ervoor zorgen dat de generatieve AI toepassing antwoordt volgens de verwachtingen van de business.</p>



<h2 class="wp-block-heading">Wanneer evalueren?</h2>



<p>Evaluaties kunnen in principe uitgevoerd worden bij elke fase van de levenscyclus van een toepassing: bij elke bugfix of feature update, bij elke deployment, en eens de toepassing operationeel is.</p>
<p>Er zijn mogelijkheden om automatische evaluaties te integreren in de CI pipeline, bijvoorbeeld pre-commit of pre-release. Tools als <a href="https://circleci.com/ai-llm/">CircleCI</a> zetten in op dergelijke ondersteuning.</p>
<p>Om de verandering van de kwaliteit te kunnen meten over verschillende iteraties van het systeem heen is het belangrijk om een vaste testset op te stellen met een aantal vragen en overeenkomstige referentie-antwoorden. De vragen zijn best zo representatief mogelijk voor het soort vragen die effectief zullen gesteld worden door eindgebruikers.</p>
<p>De metrieken die gebruikt worden om het systeem te verbeteren vóór de inproductiestelling kunnen ook gebruikt worden tijdens de productiefase om na te gaan of échte vragen van eindgebruikers nauwkeurig genoeg beantwoord worden. Zoals eerder vermeld moet hier zeker de kost in overweging genomen worden voor het gebruik van taalmodellen als evaluator zodat de kosten niet ontsporen.</p>



<h2 class="wp-block-heading">Tools en frameworks</h2>



<p>Zonder exhaustief te willen zijn, zijn hieronder enkele tools en frameworks aangegeven die het uitvoeren van evaluaties sterk kunnen ondersteunen:</p>
<ul>
<li><a href="https://www.rungalileo.io/"><strong>Galileo</strong></a> is een platform voor het evalueren en monitoren van generatieve AI toepassingen. Het biedt specifieke metrieken voor het optimaliseren van de chunking strategie (<em>chunk attribution</em> en <em>chunk utilization</em>, zie hierboven). Er is ook de mogelijkheid om in realtime guardrails toe te passen: het antwoord kan bijgestuurd worden, bijvoorbeeld in het geval van hallucinaties of schadelijk content. De resultaten van de evaluaties zijn visueel te inspecteren in een console die standaard cloudgebaseerd is, maar ook op eigen infrastructuur kan gehost worden. Om de kost van evaluaties te drukken en gegevens vertrouwelijk te houden werkt Galileo tenslotte aan een oplossing op basis van lichtere modellen die lokaal kunnen draaien.</li>
<li><a href="https://ragas.io/"><strong>Ragas</strong></a> is een open source framework voor het evalueren van RAG-gebaseerde toepassingen. Het biedt een uitgebreide set aan metrieken die het gehele systeem evalueren. Zo zijn er ook metrieken die het gegenereerde antwoord vergelijken met een referentie-antwoord (<em>answer semantic similarity</em> en <em>answer correctness</em>).</li>
<li><a href="https://www.trulens.org/"><strong>TruLens</strong></a> is een open source community project onder de vleugels van <a href="https://truera.com/ai-quality-education/generative-ai-rags/what-is-the-rag-triad/">TruEra</a>. TruEra bedacht de term “RAG triad” die 3 metrieken combineert voor het evalueren van hallucinaties in LLM-gebaseerde toepassingen.</li>
</ul>



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



<p>Frameworks voor het evalueren van RAG toepassingen laten toe om de kwaliteit van generatieve vraag-antwoordsystemen systematisch te beoordelen en op te volgen. Ze voorzien een manier om verschillende aspecten te meten, zoals het vermogen om relevante informatie op te halen (<em>retrieval</em>) en de kwaliteit van de gegenereerde antwoorden. Dergelijke metrieken zijn cruciaal om inzicht te krijgen in de eventuele zwakke punten van een RAG systeem en waar nodig te kunnen bijsturen.</p>
<p>Het gebruik van een LLM kan het uitvoeren van evaluaties automatiseren en het uitvoeren van testen schaalbaar maken. Het is wel opletten met de kosten die dit teweeg kan brengen. Een taalmodel als evaluator is bovendien niet vrij van fouten, maar ze kunnen voldoende inzicht bieden in de mogelijke verbeterpunten van een generatief vraag-antwoordsysteem. De meetresultaten moeten echter gezien worden als een approximatieve indicatie, we kunnen er niet blind op vertrouwen. Daarom blijft een evaluatie door business experten onmisbaar.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p><em data-rich-text-format-boundary="true">Dit is een ingezonden bijdrage van Bert Vanhalst, IT consultant bij Smals Research. Dit artikel werd geschreven in eigen naam en neemt geen standpunt in namens Smals.</em></p>
]]></content:encoded>
					
		
		
			</item>
		<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><em>Cet article est aussi disponible <a href="/opensource-coding-assistants/">en néerlandais</a>.</em></p>



<p>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>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>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>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>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 loading="lazy" 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="auto, (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>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>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></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>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>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 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, 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>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>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>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>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></p>



<p>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></p>



<p>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></p>



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



<p>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></p>



<p></p>



<p>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></p>



<p>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></p>



<p>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></p>



<p>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></p>



<p>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></p>



<p>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>À 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>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>______________________</p>



<p><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><em>Cet article est aussi disponible <a href="/opensource-coding-assistants-fr/">en français</a>.</em></p>



<p>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>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>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>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>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 loading="lazy" 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="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Screenshot van de Continue plugin in Visual Studio Code</figcaption></figure>



<p>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>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>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>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>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>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>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>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></p>



<p>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></p>



<p>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></p>



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



<p>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>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></p>



<p>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></p>



<p>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></p>



<p>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></p>



<p>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></p>



<p>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>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>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>______________________</p>



<p><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>
	</channel>
</rss>
