<?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>data ingestion &#8211; Smals Research</title>
	<atom:link href="https://www.smalsresearch.be/tag/data-ingestion/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.smalsresearch.be</link>
	<description></description>
	<lastBuildDate>Tue, 21 Apr 2026 10:42:40 +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>data ingestion &#8211; Smals Research</title>
	<link>https://www.smalsresearch.be</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Ingestion van ongestructureerde data: hoe maak je automatisch een graph op basis van tekst?</title>
		<link>https://www.smalsresearch.be/ingestion-van-ongestructureerde-data-graph/</link>
		
		<dc:creator><![CDATA[Pierre Leleux]]></dc:creator>
		<pubDate>Mon, 06 Oct 2025 09:00:00 +0000</pubDate>
				<category><![CDATA[[NL]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[Artificial intelligence]]></category>
		<category><![CDATA[data ingestion]]></category>
		<category><![CDATA[Knowledge Graph]]></category>
		<category><![CDATA[Large Language Model]]></category>
		<category><![CDATA[methodology]]></category>
		<category><![CDATA[Natural Language Processing]]></category>
		<guid isPermaLink="false">/?p=24036</guid>

					<description><![CDATA[Dit artikel gaat in op de manieren waarop een graph kan worden verkregen op basis van tekstuele data, de verschillende soorten graphs die kunnen worden geëxtraheerd en de tools die vaak worden gebruikt.]]></description>
										<content:encoded><![CDATA[
<p><a href="/ingestion-donnees-non-structurees-vers-graphe/"><em>Version en Français</em></a></p>
<p>Graphs, en meer bepaald knowledge graphs, maken het mogelijk om <a href="/graphtechnologieen-toepassingen-en-tools-2/">informatie op een gestructureerde manier weer te geven</a>. Zo krijgt een persoon een visuele samenvatting van de inhoud van een of meerdere documenten en kan een machine deze structuur gebruiken om bijvoorbeeld de inhoud ervan te analyseren (met behulp van <a href="/graphtechnologieen-toepassingen-en-tools/">graphalgoritmen</a>) en/of redeneringen te maken op basis van de graph (bijvoorbeeld in het kader van <a href="/graphrag-naar-een-knowledge-graph-augmented-generatie/">een graphRAG-toepassing</a> of om impliciete informatie te ontdekken (af te leiden)).</p>
<p>Dit artikel gaat in op de manieren waarop een graph kan worden verkregen op basis van tekstuele data, de verschillende soorten graphs die kunnen worden geëxtraheerd en de tools die vaak worden gebruikt, afhankelijk van het type extractie dat men wil uitvoeren.</p>
<p>Aangezien grote taalmodellen (LLM&#8217;s) bijzonder geschikt zijn voor tekstverwerking, zal dit artikel zich voornamelijk richten op de presentatie van LLM-gebaseerde benaderingen en vervolgens kort ingaan op verschillende alternatieve benaderingen.</p>



<h2 class="wp-block-heading">Knowledge graphs: een kort overzicht</h2>



<p>Een graph is een structuur die bestaat uit een reeks nodes en bogen (die paren van nodes met elkaar verbinden). Een knowledge graph voegt een extra semantische laag toe aan een klassieke graph, waarbij elke node een concept vertegenwoordigt (entiteit, persoon, enz.) en elke boog een relatie tussen twee concepten vertegenwoordigt (“werkt voor”, “is bevriend met”, enz.). Het is dus een weergave van kennis in de vorm van een reeks onderling verbonden entiteiten. Meer details over de verschillende soorten graphs en de bijbehorende tools vindt u <a href="/graphtechnologieen-toepassingen-en-tools/">hier</a>.</p>



<h2 class="wp-block-heading">Voorbereiding van het documentcorpus</h2>



<p>Voor de eenvoud gaan we ervan uit dat de tekstdocumenten die worden gebruikt om de graph op te bouwen, correct zijn opgeschoond. Dit artikel is namelijk niet bedoeld om de voorbewerking van tekstdocumenten (scrapen van webpagina&#8217;s, extraheren van tekst uit pdf-bestanden, enz.) te bespreken, aangezien deze voorbewerking op zich al een uitgebreid onderwerp is dat ongetwijfeld een apart artikel verdient.</p>



<h3 class="wp-block-heading">Fragmentatie van de tekst in “chunks”</h3>



<p>Een belangrijke stap in de voorbereiding van tekstdata voordat entiteiten en relaties worden geëxtraheerd, is het opsplitsen van de tekst in fragmenten (meestal ‘chunks’ genoemd). We hebben het concept van chunking al meerdere keren besproken in <a href="/databeheer-voor-generatieve-ai-toepassingen-kernbegrippen/">vorige blogposts</a>. Wanneer een document te lang is (meer dan enkele paragrafen), is het raadzaam om het op te splitsen in chunks (tekstfragmenten van redelijke omvang) die één voor één door de LLM worden verwerkt. Deze procedure maakt het mogelijk om de hoeveelheid informatie in elke chunk te beperken, zodat deze niet te veel entiteiten en relaties bevat die moeten worden geëxtraheerd. Deze opsplitsing in chunks kan op verschillende manieren gebeuren, hetzij op basis van het aantal woorden in de chunk, hetzij op basis van een vooraf gedefinieerd scheidingsteken (bijvoorbeeld een regeleinde dat het einde van de paragraaf aangeeft).</p>



<h2 class="wp-block-heading">De informatie weergeven of de structuur weergeven</h2>



<p>Laten we beginnen met de twee belangrijkste soorten graphs die kunnen worden geconstrueerd op basis van een reeks tekstdocumenten.</p>
<p>De eerste is een graph die de structuur van het document weergeeft (<em>document structure graph</em>), en niet de informatie die in de tekst staat. Bijvoorbeeld door de chunks te koppelen aan het document waaruit ze zijn gehaald en de volgorde waarin ze in het document voorkomen:</p>



<figure class="wp-block-image aligncenter size-full"><a href="/wp-content/uploads/2025/09/Document_structure_graph.png"><img fetchpriority="high" decoding="async" width="939" height="527" src="/wp-content/uploads/2025/09/Document_structure_graph.png" alt="" class="wp-image-23750" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Document_structure_graph.png 939w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Document_structure_graph-300x168.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Document_structure_graph-768x431.png 768w" sizes="(max-width: 939px) 100vw, 939px" /></a><figcaption class="wp-element-caption">Figuur 1: Graph die de structuur van een eenvoudig document weergeeft</figcaption></figure>



<p>Dit type graph kan ook worden verrijkt door relaties toe te voegen tussen semantisch vergelijkbare chunks of, indien van toepassing, door de hiërarchische organisatie van het document weer te geven in secties, subsecties, enz. Dit gebeurt via nodes die de secties/subsecties vertegenwoordigen en relaties van het type “HAS_SECTION”, “HAS_SUBSECTION”, evenals relaties die de volgorde van de secties/subsecties aangeven. Zodra de graph is opgebouwd, kan deze bijvoorbeeld worden gebruikt in RAG-toepassingen voor indexeringsdoeleinden om context te bieden aan de gebruikte chunks (zie <a href="/graphrag-naar-een-knowledge-graph-augmented-generatie/">onze blogpost over graphRAG</a>).</p>
<p>Het tweede type graph bestaat uit het opnemen van de informatie in de documenten in de vorm van nodes en relaties:</p>



<figure class="wp-block-image aligncenter size-full"><a href="/wp-content/uploads/2025/09/Domain_graph.png"><img decoding="async" width="877" height="179" src="/wp-content/uploads/2025/09/Domain_graph.png" alt="" class="wp-image-23751" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Domain_graph.png 877w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Domain_graph-300x61.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Domain_graph-768x157.png 768w" sizes="(max-width: 877px) 100vw, 877px" /></a><figcaption class="wp-element-caption">Figuur 2: Voorbeeld van informatie-extractie</figcaption></figure>



<p>In het kader van deze blogpost zullen we ons concentreren op dit tweede type graph. Merk op dat beide benaderingen elkaar niet uitsluiten. Als men voor het tweede type graph kiest, is het trouwens vaak nuttig om ook de documentstructuur weer te geven. Zo kan men indien nodig teruggaan naar de bron van de informatie in de graph.</p>



<figure class="wp-block-image aligncenter size-full"><a href="/wp-content/uploads/2025/09/Graph_combined.png"><img decoding="async" width="896" height="674" src="/wp-content/uploads/2025/09/Graph_combined.png" alt="" class="wp-image-23754" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Graph_combined.png 896w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Graph_combined-300x226.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Graph_combined-768x578.png 768w" sizes="(max-width: 896px) 100vw, 896px" /></a><figcaption class="wp-element-caption">Figuur 3: Extractie van structuur en informatie</figcaption></figure>



<h2 class="wp-block-heading">Opbouw van een knowledge graph met behulp van een LLM</h2>



<p>Eerst zullen we de algemene procedure voor het aanmaken van een knowledge graph op basis van tekstdocumenten via LLM voorstellen, alvorens te bekijken hoe deze aan de eigen behoeften kan worden aangepast.</p>
<p>LLM&#8217;s ontvangen standaard tekst als input (prompt) en sturen tekst terug als output in reactie op de prompt. Afhankelijk van de instructies bieden LLM&#8217;s echter de mogelijkheid om <strong><em>gestructureerde outputs</em></strong> te genereren, zoals JSON-bestanden. Vaak wordt deze functionaliteit gebruikt als basis voor het extraheren van kennis naar een graph, omdat deze gestructureerde output systematisch kan worden verwerkt.</p>
<p>Een script (bv. Python) haalt de chunks op en stuurt ze een voor een naar de LLM door een gestructureerd antwoord op te leggen (bv. <a href="https://python.langchain.com/docs/how_to/structured_output/">LangChain met de methode <em>llm.with_structured_output()</em></a>), met instructies over de taak, het type informatie dat in de tekst moet worden gedetecteerd en de structuur van het verwachte antwoord in de output. De gestructureerde output (meestal in JSON) wordt vervolgens eenvoudigweg ontleed in Python om de door de LLM gedetecteerde informatie (nodes/relaties) op te halen, die vervolgens rechtstreeks aan de graph kan worden toegevoegd (via een databasedriver).</p>
<p>Interessant is dat LLM&#8217;s een grote verscheidenheid aan antwoorden kunnen geven en dat het gebruik van gestructureerde output niet altijd nodig is. In sommige gevallen is het nog steeds het eenvoudigst om de LLM te vragen zijn extracties te leveren in de vorm van queries (bijvoorbeeld queries die de gedetecteerde nodes/relaties direct toevoegen), die als zodanig kunnen worden uitgevoerd, of in de vorm van RDF triples.</p>
<p>Na de algemene procedure, kijken we nu meer in detail naar de verschillende manieren om de informatie in de chunks binnen een graph te extraheren en weer te geven, te beginnen met de eenvoudigste benadering (thema-extractie) tot de meest complete (extractie van entiteiten en relaties).</p>



<h3 class="wp-block-heading">Thematische extractie</h3>



<p>In deze eerste benadering richten we ons op het opsporen en extraheren van de thema&#8217;s die in het document aan bod komen. We bouwen dus een thematische weergave van de verschillende documenten in het corpus om een structuur te verkrijgen van het type:</p>



<figure class="wp-block-image aligncenter size-full"><a href="/wp-content/uploads/2025/09/Theme_extraction.png"><img loading="lazy" decoding="async" width="872" height="178" src="/wp-content/uploads/2025/09/Theme_extraction.png" alt="" class="wp-image-23756" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Theme_extraction.png 872w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Theme_extraction-300x61.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Theme_extraction-768x157.png 768w" sizes="auto, (max-width: 872px) 100vw, 872px" /></a><figcaption class="wp-element-caption">Figuur 4: Ontologieschema van een thematische extractie</figcaption></figure>



<p>De graph heeft dus een lichte structuur en wordt gebruikt voor referentiedoeleinden, om gemakkelijk en snel documenten te identificeren die betrekking hebben op een (of meerdere) bepaald(e) onderwerp(en) van belang. Met dit type graph kunnen ook gelijkenissen tussen documenten (of tussen chunks) worden vastgesteld op basis van de gemeenschappelijke onderwerpen, of kan eenvoudigweg een schematische weergave worden gegeven van hun corpus van documenten en de thema&#8217;s die daarin aan bod komen.</p>
<p>Dit kan op een niet-gestuurde manier (de LLM vrij laten bepalen welke thema&#8217;s in de chunk aan bod komen) of op een gestuurde manier gebeuren (de LLM kiest een of meer thema&#8217;s uit een vooraf gedefinieerde lijst met thema&#8217;s die in de instructies van de prompt wordt gegeven).</p>



<h3 class="wp-block-heading">Extractie van <em>named entities</em></h3>



<p>De extractie (of herkenning) van <em>named entities</em> (<em>named-entity recognition</em>, vaak afgekort tot NER) is een bekend domein van natuurlijke taalverwerking (<em>natural language processing</em> (NLP)) dat bestaat uit het detecteren en categoriseren van entiteiten (personen, organisaties, plaatsen, enz.) die in een tekst worden genoemd. Het doel is dus vergelijkbaar met dat van thematische extractie: een graph maken door tekstfragmenten te koppelen aan de entiteiten die erin worden genoemd. We krijgen dus een graph met het volgende standaard schema:</p>



<figure class="wp-block-image aligncenter size-full"><a href="/wp-content/uploads/2025/09/Entity_extraction.png"><img loading="lazy" decoding="async" width="877" height="176" src="/wp-content/uploads/2025/09/Entity_extraction.png" alt="" class="wp-image-23752" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Entity_extraction.png 877w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Entity_extraction-300x60.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Entity_extraction-768x154.png 768w" sizes="auto, (max-width: 877px) 100vw, 877px" /></a><figcaption class="wp-element-caption">Figuur 5: Ontologieschema van een extractie van <em>named entities</em></figcaption></figure>



<p>Met dit type graph kunnen ook gelijkenissen tussen documenten (of tussen chunks) worden vastgesteld op basis van de entiteiten die ze gemeenschappelijk hebben. Het is interessant om op te merken dat deze extractie vergelijkbaar is met een volledige extractie (inclusief entiteiten en relaties, zie onderstaande paragraaf), behalve dat hier alleen de entiteiten worden geëxtraheerd en niet de relaties die ze met elkaar verbinden. Dit is een lichtere en gemakkelijker te implementeren oplossing wanneer een volledige extractie niet nodig is.</p>
<p>Dit soort extractie kan gemakkelijk worden uitgevoerd met behulp van een LLM met gestructureerde outputs. Met het <code>pydantic</code>-pakket kunnen op maat gemaakte templates worden gemaakt voor de verwachte outputstructuur. Bijvoorbeeld:</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" style="color:#000000;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from pydantic import BaseModel, Field
from typing import List
class Entity(BaseModel):
    category: str = Field(description="The category of the entity.")
    name: str = Field(description="The name of the entity.")
class Extraction(BaseModel):
    entityList: List&#91;Entity&#93; = Field(description="The list of extracted entities.")
structured_llm = llm.with_structured_output(Extraction)
extracted=structured_llm.invoke(myPrompt)</textarea></pre><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: #AF00DB">from</span><span style="color: #000000"> pydantic </span><span style="color: #AF00DB">import</span><span style="color: #000000"> BaseModel, Field</span></span>
<span class="line"><span style="color: #AF00DB">from</span><span style="color: #000000"> typing </span><span style="color: #AF00DB">import</span><span style="color: #000000"> List</span></span>
<span class="line"><span style="color: #0000FF">class</span><span style="color: #000000"> </span><span style="color: #267F99">Entity</span><span style="color: #000000">(</span><span style="color: #267F99">BaseModel</span><span style="color: #000000">):</span></span>
<span class="line"><span style="color: #000000">    category: </span><span style="color: #267F99">str</span><span style="color: #000000"> = Field(</span><span style="color: #001080">description</span><span style="color: #000000">=</span><span style="color: #A31515">&quot;The category of the entity.&quot;</span><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #000000">    name: </span><span style="color: #267F99">str</span><span style="color: #000000"> = Field(</span><span style="color: #001080">description</span><span style="color: #000000">=</span><span style="color: #A31515">&quot;The name of the entity.&quot;</span><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #0000FF">class</span><span style="color: #000000"> </span><span style="color: #267F99">Extraction</span><span style="color: #000000">(</span><span style="color: #267F99">BaseModel</span><span style="color: #000000">):</span></span>
<span class="line"><span style="color: #000000">    entityList: List&#91;Entity&#93; = Field(</span><span style="color: #001080">description</span><span style="color: #000000">=</span><span style="color: #A31515">&quot;The list of extracted entities.&quot;</span><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #000000">structured_llm = llm.with_structured_output(Extraction)</span></span>
<span class="line"><span style="color: #000000">extracted=structured_llm.invoke(myPrompt)</span></span></code></pre></div>



<p> </p>
<p>In dit eenvoudige voorbeeld wordt de LLM gevraagd om een gestructureerde output van het type “Extraction” terug te geven, met als attribuut “entityList”, een lijst van “Entity”-objecten “ die net daarvoor zijn gedefinieerd.</p>
<p>Het is interessant om op te merken dat dit type template kan worden uitgebreid wanneer we extra informatie willen extraheren of het type gedetecteerde entiteiten willen beperken. Als we bijvoorbeeld alleen entiteiten van het type “persoon” en “onderneming” willen detecteren, kan de template worden aangepast door de klassen “ Persoon” en “Onderneming&#8221; aan te maken, waarin de attributen worden opgesomd die voor elke instantie van deze entiteiten moeten worden geëxtraheerd, en door het veld ”entityList“ te vervangen door twee velden “personList” en ”enterpriseList&#8221; in het uiteindelijke object dat moet worden teruggegeven.</p>
<p>Het voordeel van het gebruik van de methode <code>with_structured_output</code> is dat LangChain automatisch controleert of de output van de LLM overeenkomt met de template.</p>



<h3 class="wp-block-heading">Extractie van entiteiten en relaties</h3>



<p>Het doel hier is het bouwen van een graph die de kennis in het document of de documenten weergeeft in de vorm van onderling verbonden entiteiten (nodes) en relaties. Dit is de meest uitgebreide (en meest ingewikkelde) taak die we in detail zullen bekijken.</p>
<p>Laten we het volgende stukje tekst nemen om te illustreren wat voor soort extractie we hier willen uitvoeren:</p>
<p><em>“The San Fransisco-based 9th U.S. Circuit Court of Appeals rejected the legal challenge by the Federal Trade Commission to Microsoft’s $69</em><em> </em><em>billion acquisition of Activision Blizzard, the developer of </em><em>“</em><em>Call of Duty.</em><em>”</em><em> A three</em><em>‑</em><em>judge panel unanimously upheld a lower court</em><em>’</em><em>s decision denying a preliminary injunction, finding that the FTC had not demonstrated a likelihood of success in proving the merger would harm competition. The acquisition, completed in late</em><em> </em><em>2023 following UK regulatory approval, is the largest ever in the video gaming industry.”<br /></em>(Source: adapted from <a href="https://www.reuters.com/legal/microsoft-wins-ftc-appeal-challenging-69-bln-activision-blizzard-deal-2025-05-07/">Reuters, 2025</a>).</p>
<p>Zodra de informatie is geëxtraheerd, is dit een voorbeeld van een graph die op basis van deze tekst kan worden gemaakt:</p>



<figure class="wp-block-image aligncenter size-large"><a href="/wp-content/uploads/2025/09/Full_Extracted_KG.png"><img loading="lazy" decoding="async" width="1024" height="537" src="/wp-content/uploads/2025/09/Full_Extracted_KG-1024x537.png" alt="" class="wp-image-23761" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Full_Extracted_KG-1024x537.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Full_Extracted_KG-300x157.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Full_Extracted_KG-768x402.png 768w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Full_Extracted_KG.png 1330w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Figuur 6: Voorbeeld van extractie uit een tekst</figcaption></figure>



<p>Dit type extractie kan op veel verschillende manieren worden uitgevoerd. Het volgende deel is speciaal gewijd aan de verschillende benaderingen om een volledige extractie uit te voeren, en aan de voor- en nadelen daarvan.</p>



<h2 class="wp-block-heading">Welke benaderingen zijn er voor het extraheren van entiteiten en relaties?</h2>



<h3 class="wp-block-heading">Handmatige extractie versus speciale tools</h3>



<p>Een dergelijke graph kan manueel worden opgebouwd volgens de techniek die in het vorige deel werd voorgesteld (een prompt met instructies en de chunk naar de LLM sturen, de gestructureerde output ophalen en ontleden, en vervolgens de graph bijwerken via queries), ofwel biedt LangChain een tool aan om deze verschillende taken te automatiseren via de <a href="https://python.langchain.com/api_reference/experimental/graph_transformers/langchain_experimental.graph_transformers.llm.LLMGraphTransformer.html">LLM Graph Transformer</a>.</p>
<p>Deze tool vereenvoudigt de procedure door de instructies aan de LLM, het opstellen van de template en de verwerking van de gestructureerde output voor zijn rekening te nemen. De tool biedt verschillende instelmogelijkheden, zoals de mogelijkheid om de soorten nodes die gedetecteerd moeten worden te beperken (bv. alleen nodes van het type “Person”, “Company” en “Location”), de soorten relaties te beperken of de instructieprompt aan te passen.</p>
<p>Bovendien geeft een <code>LLMGraphTransformer</code>-instantie een lijst terug met objecten van het type <code>GraphDocument</code>, die de gedetecteerde nodes en relaties bevat en die direct kan worden gebruikt door verschillende LangChain-drivers naar graph-gerichte databases (zoals Memgraph, TigerGraph, Neo4j, enz.), om de geëxtraheerde entiteiten en relaties direct in de graph te importeren.</p>
<p>Hieronder volgt een voorbeeld van het extraheren van data uit een lijst met chunks met behulp van de <code>LLMGraphTransformer</code>-tool, gevolgd door het importeren van de entiteiten en relaties naar Neo4j:</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" style="color:#000000;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>doc_transformer=LLMGraphTransformer(llm=llm)
graph_docs=doc_transformer.convert_to_graph_documents(listOfChunks)

from langchain_neo4j import Neo4jGraph
graph=Neo4jGraph(
    url='XXXXX',
    username='YYYYY',
    password='ZZZZZ'
)
graph.add_graph_documents(graph_docs)</textarea></pre><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: #000000">doc_transformer=LLMGraphTransformer(</span><span style="color: #001080">llm</span><span style="color: #000000">=llm)</span></span>
<span class="line"><span style="color: #000000">graph_docs=doc_transformer.convert_to_graph_documents(listOfChunks)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #AF00DB">from</span><span style="color: #000000"> langchain_neo4j </span><span style="color: #AF00DB">import</span><span style="color: #000000"> Neo4jGraph</span></span>
<span class="line"><span style="color: #000000">graph=Neo4jGraph(</span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #001080">url</span><span style="color: #000000">=</span><span style="color: #A31515">&#39;XXXXX&#39;</span><span style="color: #000000">,</span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #001080">username</span><span style="color: #000000">=</span><span style="color: #A31515">&#39;YYYYY&#39;</span><span style="color: #000000">,</span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #001080">password</span><span style="color: #000000">=</span><span style="color: #A31515">&#39;ZZZZZ&#39;</span></span>
<span class="line"><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #000000">graph.add_graph_documents(graph_docs)</span></span></code></pre></div>



<p><br />Er bestaat ook een gratis alternatief voor Neo4j, waarvoor geen programmering nodig is: de <a href="https://llm-graph-builder.neo4jlabs.com/">Neo4j LLM Knowledge Graph Builder</a>. Deze online tool neemt alle stappen voor zijn rekening, van de voorbewerking van documenten (pdf, webpagina) tot de opbouw van de resulterende knowledge graphs, en biedt tal van personaliseringsopties (het beperken van de te detecteren entiteit- en/of relatietypes, enz.). Zie <a href="https://neo4j.com/labs/genai-ecosystem/llm-graph-builder/">hier</a> voor meer details.</p>



<h3 class="wp-block-heading">Vrije extractie versus begeleide extractie</h3>



<p>Merk op dat als er met deze tools geen beperkingen (op de soorten entiteiten en relaties die moeten worden geëxtraheerd) worden gedefinieerd, ze in alle vrijheid alle informatie zullen extraheren die ze kunnen vinden. Dit soort “blinde” extractie kan eventueel worden gebruikt voor kleine documenten, of in gevallen waarin men van tevoren niet weet wat voor soort structuur men kan extraheren, maar het is over het algemeen beter om van tevoren de gewenste ontologie voor de graph vast te leggen.</p>
<p>Vrije extractie is namelijk vaak een probleem om verschillende redenen:</p>
<p><strong>Explosie van entiteitstypen en relaties </strong></p>
<p>Naarmate de omvang of het aantal documenten toeneemt, bestaat het risico dat er al snel een zeer groot aantal verschillende soorten entiteiten en relaties in de graph terechtkomen, waardoor deze moeilijk te gebruiken kan worden (bijvoorbeeld voor RAG-toepassingen).</p>
<p><strong>Inconsistentie van types</strong></p>
<p>Bij gebrek aan een ontologie die een duidelijke nomenclatuur biedt, bestaat het risico van inconsistentie in de gedetecteerde types (een bedrijf kan bijvoorbeeld worden gelabeld als “Enterprise”, een ander als “Company” en een derde als “Organization”). In de praktijk kunnen dit soort problemen achteraf worden opgelost door alle soorten nodes op te sommen en semantisch verwante soorten te groeperen.</p>
<p><strong>Problemen met reïficatie</strong></p>
<p>Per definitie verbindt een relatie in een graph een node met een ander node. Er kan een probleem ontstaan wanneer een entiteit moet worden gekoppeld aan informatie die in de vorm van een relatie is gemodelleerd. Om het probleem te illustreren, nemen we als voorbeeld de overname van Activision Blizzard door Microsoft. Stel dat een eerste stuk tekst alleen deze overname vermeldt zonder verdere details, dan wordt deze hoogstwaarschijnlijk opgeslagen in de vorm:</p>
<p><code>(Microsoft)-[ACQUIRES]-&gt;(Activision Blizzard)</code></p>
<p>Stel dat de volgende chunk de informatie “<em>The FTC challenged the acquisition&#8230;</em>” vermeldt, dan hebben we een probleem omdat het niet meer mogelijk is om</p>
<p><code>(FTC)-[CHALLENGES]-&gt;(Acquisition)</code></p>
<p>te modelleren, aangezien de overname eerder werd gemodelleerd in de vorm van een relatie en niet als een node waarnaar door een relatie kan worden verwezen.</p>
<p>In dit geval kan de relatie bijvoorbeeld worden verwijderd en vervolgens worden vervangen door een node, zodat ernaar kan worden verwezen:</p>
<p><code>(Microsoft)-[INITIATES]-&gt;(Acquisition)-[TARGETS]-&gt;(Activision Blizzard)</code></p>
<p>Dit proces, dat <strong>reïficatie</strong> wordt genoemd, verloopt niet automatisch en vereist een extra verrijkingsstap om mogelijke verwijzingen naar informatie die in de vorm van relaties is gemodelleerd, op te sporen en indien nodig te reïficeren.</p>



<h2 class="wp-block-heading">Enkele alternatieven voor LLM&#8217;s</h2>



<p>Nu we een reeks benaderingen hebben bekeken die specifiek op LLM&#8217;s zijn gebaseerd, worden in dit gedeelte enkele alternatieve tools voorgesteld die zijn gebaseerd op klassieke NLP-methoden.</p>
<p>Voor wie alleen <em>named entities</em> wil extraheren, is <a href="/named-entity-recognition-une-application-du-nlp-utile/">hier een blogpost over dit onderwerp</a> te vinden, evenals een <a href="/pii-filtering/">voorbeeld van de toepassing van NER bij PII-filtering</a>.  Er zijn tal van vooraf getrainde NER-modellen beschikbaar op platforms zoals <a href="https://huggingface.co/models">Hugging Face</a>.</p>
<p>Het extraheren van entiteiten en relaties kan doorgaans op twee verschillende manieren gebeuren:</p>



<ul class="wp-block-list">
<li><strong>Extractie in twee afzonderlijke stappen</strong>: eerst wordt een NER gebruikt voor het detecteren en categoriseren van entiteiten, gevolgd door een extractie van relaties op basis van de tekst en de gedetecteerde entiteiten, om de relaties tussen deze entiteiten te bepalen. Enkele voorbeelden van tools voor het extraheren van relaties zijn <a href="https://github.com/thunlp/OpenNRE">openNRE</a>, <a href="https://github.com/alimirzaei/spacy-relation-extraction">spacy-relation-extraction</a> en <a href="https://github.com/jackboyla/GLiREL">GliREL</a>.</li>



<li><strong>End-to-end-extractie</strong>: tools die entiteiten en relaties in één stap extraheren, zoals <a href="https://nlp.stanford.edu/software/openie.html">OpenIE</a>, <a href="https://github.com/SapienzaNLP/relik">Relik</a>, <a href="https://github.com/Babelscape/rebel">REBEL</a> of <a href="https://www.diffbot.com/products/natural-language/">Diffbot</a> (commerciële oplossing).</li>
</ul>



<h2 class="wp-block-heading">Nagaan of de gedetecteerde gegevens conform zijn</h2>



<p>De grote kracht van LLM&#8217;s voor dit soort extractietaken is hun begrip van natuurlijke taal, waardoor de extractie kan worden gepersonaliseerd door de instructieprompt aan te passen. Als er bijvoorbeeld geen outputtemplate bestaat voor het gestructureerde antwoord (waar de LLM moeite mee kan hebben als de template te ingewikkeld wordt), is het mogelijk om ontologieconforme nodes en relaties te verkrijgen door de ontologie rechtstreeks in de instructieprompt te beschrijven, maar het is belangrijk om alert te blijven voor extracties. Er is namelijk geen garantie dat de LLM geen fouten maakt en geen niet-conforme relatie/entiteit als output teruggeeft.</p>
<p>In het algemeen geldt dat wanneer een LLM (of een andere tool) wordt gebruikt om automatisch informatie uit een tekst te extraheren naar een knowledge graph, het nuttig is om te controleren of datgene dat is geëxtraheerd wel degelijk in overeenstemming is met de ontologie en trouw is aan de informatie in de bron.</p>
<ol>
<li>Controleren of de extractie voldoet aan de ontologie</li>
</ol>
<p><a href="/shacl-logische-en-vormcontroles-met-kg-technologieen/">In een vorige blogpost</a> hebben we al vermeld dat het mogelijk is om de structuur en inhoud van een knowledge graph te valideren met behulp van de SHACL-standaard. Dit is een taal die de verschillende beperkingen bevat die van toepassing zijn op een knowledge graph. Het is mogelijk om ofwel een definitieve validatie van de graph uit te voeren, om te controleren of de inhoud daadwerkelijk voldoet aan de in SHACL geformuleerde beperkingen (en de data die deze beperkingen overtreden op te sommen), ofwel deze validaties transactioneel uit te voeren bij elke nieuwe toevoeging van informatie, om elke nieuwe onrechtmatige toevoeging te weigeren. Hoewel SHACL oorspronkelijk bedoeld was voor graphs in RDF, kunnen sommige databases toch SHACL-beperkingen interpreteren en de graph valideren, zoals <a href="https://neo4j.com/labs/neosemantics/">Neo4j met het <em>neosemantics</em> package (n10s)</a>.</p>
<ol start="2">
<li>Nagaan of de extractie correct is</li>
</ol>
<p>Het risico van automatische extractie is dat informatie die in de graph wordt ingevoerd feitelijk onjuist is ten opzichte van de oorspronkelijke tekst, wat in het bijzonder problematisch kan zijn als deze graph wordt gebruikt als potentiële informatiebron (bijvoorbeeld voor een graphRAG-toepassing). Er kunnen verschillende benaderingen worden gevolgd. De eenvoudigste is een menselijke controle van de geëxtraheerde informatie, maar dit kan moeilijk of zelfs onhaalbaar worden wanneer de documenten te lang/talrijk worden. De andere aanpak bestaat erin een tweede LLM te gebruiken om te controleren wat uit elk fragment is geëxtraheerd. Zoals we <a href="/praktische-ervaringen-met-automatische-rag-evaluatie/">in de post over de evaluatie van LLM&#8217;s</a> hebben vermeld, is het voor LLM&#8217;s gemakkelijker om achteraf fouten op te sporen dan ze te vermijden.</p>



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



<p>Deze technologieën zijn weliswaar krachtig, maar nooit perfect. Behalve vrije (blinde) extractie, die kan resulteren in een moeilijk bruikbare graph, vormt het opstellen van een knowledge graph op basis van tekst een taak die veel werk vereist. En dit zowel vooraf (voorbewerking van teksten, opstellen van een ontologie voor de graph op basis van de inhoud van de tekst), als achteraf (validatie van de structuur van de graph ten opzichte van de ontologie en controle van de juistheid en betrouwbaarheid van de inhoud).</p>



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



<p><em>Dit is een ingezonden bijdrage van Pierre Leleux, data scientist et network data analyst bij Smals Research. Dit artikel werd geschreven in eigen naam en neemt geen standpunt in namens Smals.</em></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Ingestion de données non-structurées&#160;: comment créer un graphe automatiquement à partir de texte&#160;?</title>
		<link>https://www.smalsresearch.be/ingestion-donnees-non-structurees-vers-graphe/</link>
		
		<dc:creator><![CDATA[Pierre Leleux]]></dc:creator>
		<pubDate>Thu, 11 Sep 2025 09:00:00 +0000</pubDate>
				<category><![CDATA[[FR]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[Artificial intelligence]]></category>
		<category><![CDATA[data ingestion]]></category>
		<category><![CDATA[Knowledge Graph]]></category>
		<category><![CDATA[Large Language Model]]></category>
		<category><![CDATA[methodology]]></category>
		<category><![CDATA[Natural Language Processing]]></category>
		<guid isPermaLink="false">/?p=23748</guid>

					<description><![CDATA[Cet article s’intéresse aux façons dont une représentation graphe peut être obtenue à partir de données textuelles, les différents types de graphe qui peuvent être extraits, et les outils fréquemment utilisés.]]></description>
										<content:encoded><![CDATA[
<p><em><a href="/ingestion-van-ongestructureerde-data-graph/">Nederlandstalige versie</a></em></p>
<p>Les graphes, et plus particulièrement les graphes de connaissances, permettent de <a href="/graphes_applications_et_outils_2/">représenter l’information de manière structurée</a>. Cela permet, pour un humain, d’avoir une représentation (synthèse visuelle) du contenu d’un ou de plusieurs documents et, pour une machine, d’exploiter cette structure afin, par exemple, d’en analyser le contenu (via l’utilisation <a href="/graphes_applications_et_outils/">d’algorithmes de graphe</a>) et/ou de raisonner sur le graphe (par exemple dans le cadre d’une <a href="/graphrag-vers-une-generation-augmentee-par-les-graphes-de-connaissances/">application de graphRAG</a> ou pour découvrir (inférer) de l’information implicite).</p>
<p>Cet article s’intéresse aux façons dont une représentation graphe peut être obtenue à partir de données textuelles, les différents types de graphe qui peuvent être extraits, et les outils fréquemment utilisés suivant le type d’extraction que l’on souhaite effectuer.</p>
<p>Il est à noter que, puisque les grands modèles de langage (LLM) sont particulièrement adaptés pour le traitement de texte, cet article se concentrera principalement sur la présentation d’approches basées sur les LLM et discutera rapidement, dans un second temps, de différentes approches alternatives.</p>



<h2 class="wp-block-heading">Les graphes de connaissances&nbsp;: un rappel rapide</h2>



<p>Un graphe est une structure composée d’un ensemble de nœuds et d’arcs (qui lient des paires de nœuds). Un graphe de connaissances ajoute une couche sémantique supplémentaire à un graphe classique, où chaque nœud représente un concept (entité, personne, etc.) et chaque arc représente une relation entre deux concepts (« travaille pour », « est ami avec », etc.). Il s’agit donc d’une représentation de la connaissance sous forme d’un ensemble d’entités interconnectées. Plus de détails sur les différentes formes de graphes et les outils associés peuvent être trouvés <a href="/graphes_applications_et_outils/">ici</a>.</p>



<h2 class="wp-block-heading">Préparation du corpus de documents</h2>



<p>Il est à noter que, pour des raisons de simplicité, nous faisons l’hypothèse que les documents de texte utilisés pour construire le graphe ont été correctement nettoyés. En effet, cet article n’a pas pour but de discuter de l’aspect relatif au prétraitement des documents de texte (scrapping de pages web, extraction de texte à partir de fichiers pdf, etc.), car ce prétraitement est déjà, en tant que tel, un vaste sujet méritant sans doute un article dédié.</p>



<h3 class="wp-block-heading">Fragmentation du texte en « chunks »</h3>



<p>Une étape importante de la préparation des données de texte avant d’en extraire les entités et relations est la division du texte en fragments (généralement appelés « chunks »). Nous avons déjà mentionné le concept de chunking à plusieurs reprises dans <a href="/ingestion-de-donnees-pour-les-applications-d-ia-generative/">de précédents articles</a>. Si un document est trop long (plus de quelques paragraphes…) il convient de le séparer en chunks (fragments de texte de taille raisonnable) qui seront traités un à un par le LLM. Cette procédure permet de limiter la quantité d’information présente dans chaque chunk, pour éviter que celui-ci ne contienne une quantité trop importante d’entités et de relations à extraire. Cette séparation en chunks peut se faire de différentes manières, soit sur la base du nombre de mots dans le chunk, soit sur la base d’un séparateur prédéfini (par exemple&nbsp;: un passage à la ligne qui indiquerait la fin du paragraphe).</p>



<h2 class="wp-block-heading">Représenter l’information ou représenter la structure</h2>



<p>Commençons par regarder les deux principaux types de graphe qui peuvent être construits à partir d’un ensemble de documents textuels.</p>
<p>Le premier est un graphe qui va présenter la structure du document (<em>document structure graph</em>), et non pas l’information qui est contenue dans le texte. Par exemple, en reliant les chunks au document d’où ils sont tirés ainsi que l’ordre d’apparition de ceux-ci dans le document&nbsp;:</p>



<figure class="wp-block-image aligncenter size-full"><a href="/wp-content/uploads/2025/09/Document_structure_graph.png"><img loading="lazy" decoding="async" width="939" height="527" src="/wp-content/uploads/2025/09/Document_structure_graph.png" alt="" class="wp-image-23750" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Document_structure_graph.png 939w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Document_structure_graph-300x168.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Document_structure_graph-768x431.png 768w" sizes="auto, (max-width: 939px) 100vw, 939px" /></a><figcaption class="wp-element-caption">Figure 1&nbsp;: Graphe représentant la structure d’un document simple</figcaption></figure>



<p>Ce type de graphe peut aussi être enrichi en ajoutant des relations entre chunks sémantiquement similaires ou, le cas échéant, en représentant l’organisation hiérarchique du document en sections, sous-sections, etc. Cela se fait via des nœuds représentant les sections/sous-sections et des relations de type « HAS_SECTION », « HAS_SUBSECTION », ainsi que des relations indiquant l’ordre des sections/sous-sections. Une fois le graphe construit, il peut par exemple être utilisé dans des applications de RAG à des fins d’indexation pour fournir du contexte aux chunks utilisés (voir <a href="/graphrag-vers-une-generation-augmentee-par-les-graphes-de-connaissances/">notre article sur le graphRAG</a>).</p>
<p>Le second type de graphe consiste à capturer l’information contenue dans les documents sous la forme de nœuds et de relations :</p>



<figure class="wp-block-image aligncenter size-full"><a href="/wp-content/uploads/2025/09/Domain_graph.png"><img loading="lazy" decoding="async" width="877" height="179" src="/wp-content/uploads/2025/09/Domain_graph.png" alt="" class="wp-image-23751" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Domain_graph.png 877w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Domain_graph-300x61.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Domain_graph-768x157.png 768w" sizes="auto, (max-width: 877px) 100vw, 877px" /></a><figcaption class="wp-element-caption">Figure 2&nbsp;: Exemple d&#8217;extraction d&#8217;informations</figcaption></figure>



<p>Dans le cadre de cet article, nous nous concentrerons sur ce second type de graphe. Il est à noter que les deux approches ne sont pas mutuellement exclusives. D’ailleurs, il est souvent utile, si l&#8217;on souhaite opter pour le deuxième type de graphe, de représenter également la structure des documents. Cela permet, si nécessaire, de pouvoir remonter à la source des informations présentes dans le graphe.</p>



<figure class="wp-block-image aligncenter size-full"><a href="/wp-content/uploads/2025/09/Graph_combined.png"><img loading="lazy" decoding="async" width="896" height="674" src="/wp-content/uploads/2025/09/Graph_combined.png" alt="" class="wp-image-23754" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Graph_combined.png 896w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Graph_combined-300x226.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Graph_combined-768x578.png 768w" sizes="auto, (max-width: 896px) 100vw, 896px" /></a><figcaption class="wp-element-caption">Figure 3&nbsp;: Extraction de structure et d&#8217;informations</figcaption></figure>



<h2 class="wp-block-heading">Construction d’un graphe de connaissances à l’aide d’un LLM</h2>



<p>Dans un premier temps, nous allons présenter la procédure générale à suivre pour la création d’un graphe de connaissances à partir de documents textuels via LLM, avant de voir comment l’adapter suivant ses besoins.</p>
<p>Les LLMs, par défaut, reçoivent en entrée du texte (prompt) et renvoient en sortie du texte généré en réponse au prompt. Cependant, suivant les instructions, les LLM offrent la possibilité de générer des <strong><em>outputs structurés</em></strong> tels que des fichiers JSON. C’est souvent sur la base de cette fonctionnalité que se base l’extraction de connaissances vers un graphe, car cet output structuré pourra être traité de façon systématique.</p>
<p>Un script (par ex. python) va récupérer les chunks et les envoyer un à un au LLM en imposant une réponse structurée (par ex. <a href="https://python.langchain.com/docs/how_to/structured_output/">langchain avec la méthode llm.with_structured_output()</a>), avec des instructions concernant la tâche, le genre d’information à détecter dans le texte, et la structure de la réponse attendue en sortie. L’output structuré (typiquement en JSON) est ensuite simplement décomposé en python afin de récupérer les informations (nœuds/relations) détectées par le LLM, qui peuvent ensuite être directement ajoutées au graphe (via un database driver).</p>
<p>Il est intéressant de noter que les LLM peuvent fournir une grande diversité de réponses, et l’utilisation d’une sortie structurée n’est pas forcément toujours nécessaire. Dans certains cas, le plus simple est encore de demander au LLM de fournir ses extractions sous la forme de requêtes (par exemple, de requêtes qui ajoutent directement les nœuds/relations détectées), qui peuvent être exécutées telles quelles, ou sous forme de triplets RDF.</p>
<p>Maintenant que nous avons vu la procédure générale, nous allons regarder plus en détail les différentes façons d’extraire et de représenter l’information contenue dans les chunks au sein d’un graphe, en commençant par l’approche la plus simple (extraction de thèmes) jusqu’à la plus complète (extraction d’entités et de relations).</p>



<h3 class="wp-block-heading">Extraction thématique</h3>



<p>Dans cette première approche, on va s’intéresser à la détection et l’extraction des thèmes abordés dans le document. On y construit donc une représentation thématique des différents documents du corpus de sorte à obtenir une structure de type&nbsp;:</p>



<figure class="wp-block-image aligncenter size-full"><a href="/wp-content/uploads/2025/09/Theme_extraction.png"><img loading="lazy" decoding="async" width="872" height="178" src="/wp-content/uploads/2025/09/Theme_extraction.png" alt="" class="wp-image-23756" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Theme_extraction.png 872w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Theme_extraction-300x61.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Theme_extraction-768x157.png 768w" sizes="auto, (max-width: 872px) 100vw, 872px" /></a><figcaption class="wp-element-caption">Figure 4&nbsp;: Schéma d’ontologie d’une extraction de thèmes</figcaption></figure>



<p>Le graphe a donc une structure légère et est utilisé à des fins de référencement, afin d&#8217;identifier facilement et rapidement les documents traitant d&#8217;un (ou plusieurs) sujet(s) d&#8217;intérêt donné(s). Ce type de graphe permet aussi d’établir des similarités entre documents (ou entre chunks) sur la base des sujets qu’ils ont en commun, ou simplement d’avoir une représentation schématique du corpus de documents et des thèmes qui y sont abordés.</p>
<p>Cela peut se faire soit de façon non-dirigée (laisser le LLM déterminer librement de la liste des thèmes abordés dans le chunk), soit dirigée (le LLM choisit un ou plusieurs thèmes parmi une liste prédéfinie de thèmes fournie dans les instructions du prompt).</p>



<h3 class="wp-block-heading">Extraction d’entités nommées</h3>



<p>L’extraction (ou reconnaissance) d’entités nommées (<em>named-entity recognition</em>, souvent abrégé en NER) est un domaine bien connu du traitement du langage naturel (<em>natural language processing</em> (NLP)) qui consiste à détecter et catégoriser les entités (personne, organisation, lieu, etc.) qui sont nommées dans un texte. L’objectif va donc être similaire à celui de l’extraction thématique&nbsp;: créer un graphe en liant les chunks de texte aux entités qui y sont mentionnées. Nous obtenons donc un graphe avec le schéma-type suivant&nbsp;:</p>



<figure class="wp-block-image aligncenter size-full"><a href="/wp-content/uploads/2025/09/Entity_extraction.png"><img loading="lazy" decoding="async" width="877" height="176" src="/wp-content/uploads/2025/09/Entity_extraction.png" alt="" class="wp-image-23752" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Entity_extraction.png 877w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Entity_extraction-300x60.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Entity_extraction-768x154.png 768w" sizes="auto, (max-width: 877px) 100vw, 877px" /></a><figcaption class="wp-element-caption">Figure 5&nbsp;: Schéma d’ontologie d’une extraction d’entités nommées</figcaption></figure>



<p>Ce type de graphe permet aussi d’établir des similarités entre documents (ou entre chunks) sur la base des entités qu’ils ont en commun. Il est intéressant de noter que cette extraction est similaire à une extraction complète (incluant entités et relations, voir section ci-dessous), si ce n’est qu’ici seules les entités sont extraites, et pas les relations qui les interconnectent. Il s’agit d’une solution plus légère et facile à mettre en place, lorsqu’une extraction complète n’est pas nécessaire.</p>
<p>Ce genre d’extraction peut se faire facilement par l’utilisation de LLM avec outputs structurés. Le package <code>pydantic</code> permet de créer des templates sur mesure pour la structure attendue en sortie. Par exemple&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" style="color:#000000;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>from pydantic import BaseModel, Field
from typing import List
class Entity(BaseModel):
    category: str = Field(description="The category of the entity.")
    name: str = Field(description="The name of the entity.")
class Extraction(BaseModel):
    entityList: List&#91;Entity&#93; = Field(description="The list of extracted entities.")
structured_llm = llm.with_structured_output(Extraction)
extracted=structured_llm.invoke(myPrompt)</textarea></pre><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: #AF00DB">from</span><span style="color: #000000"> pydantic </span><span style="color: #AF00DB">import</span><span style="color: #000000"> BaseModel, Field</span></span>
<span class="line"><span style="color: #AF00DB">from</span><span style="color: #000000"> typing </span><span style="color: #AF00DB">import</span><span style="color: #000000"> List</span></span>
<span class="line"><span style="color: #0000FF">class</span><span style="color: #000000"> </span><span style="color: #267F99">Entity</span><span style="color: #000000">(</span><span style="color: #267F99">BaseModel</span><span style="color: #000000">):</span></span>
<span class="line"><span style="color: #000000">    category: </span><span style="color: #267F99">str</span><span style="color: #000000"> = Field(</span><span style="color: #001080">description</span><span style="color: #000000">=</span><span style="color: #A31515">&quot;The category of the entity.&quot;</span><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #000000">    name: </span><span style="color: #267F99">str</span><span style="color: #000000"> = Field(</span><span style="color: #001080">description</span><span style="color: #000000">=</span><span style="color: #A31515">&quot;The name of the entity.&quot;</span><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #0000FF">class</span><span style="color: #000000"> </span><span style="color: #267F99">Extraction</span><span style="color: #000000">(</span><span style="color: #267F99">BaseModel</span><span style="color: #000000">):</span></span>
<span class="line"><span style="color: #000000">    entityList: List&#91;Entity&#93; = Field(</span><span style="color: #001080">description</span><span style="color: #000000">=</span><span style="color: #A31515">&quot;The list of extracted entities.&quot;</span><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #000000">structured_llm = llm.with_structured_output(Extraction)</span></span>
<span class="line"><span style="color: #000000">extracted=structured_llm.invoke(myPrompt)</span></span></code></pre></div>



<p><br />Dans cet exemple simple, on demande au LLM de retourner une sortie structurée de type « Extraction », avec comme attribut « entityList » qui est une liste d’objets « Entity » définis juste avant.</p>
<p>Il est intéressant de noter que ce type de template peut être enrichi si l’on souhaite extraire des informations supplémentaires ou contraindre le type d’entités détectées. Par exemple, si l’on souhaite uniquement détecter des entités de type « personne » et « entreprise », le template peut être modifié en créant des classes « Personne » et « Entreprise », dans lesquelles on listera les attributs que l’on souhaite extraire pour chaque instance de ces entités, et en remplaçant le champs « entityList » par deux champs « personList » et « enterpriseList » dans l’objet final à retourner.</p>
<p>L’avantage d’utiliser la méthode <code>with_structured_output</code> est que langchain vérifiera automatiquement que la sortie du LLM est bien conforme au template.</p>



<h3 class="wp-block-heading">Extraction d’entités et de relations</h3>



<p>L’objectif ici est la construction d’un graphe qui va représenter la connaissance contenue au sein du ou des documents sous la forme d’entités (nœuds) interconnectées (relations). Il s’agit de la tâche la plus complète (et la plus compliquée), sur laquelle nous allons nous pencher le plus en détail.</p>
<p>Prenons le chunk de texte suivant, afin d’illustrer le genre d’extraction que nous souhaitons réaliser ici :</p>
<p><em>“The San Fransisco-based 9th U.S. Circuit Court of Appeals rejected the legal challenge by the Federal Trade Commission to Microsoft’s $69</em><em> </em><em>billion acquisition of Activision Blizzard, the developer of </em><em>“</em><em>Call of Duty.</em><em>”</em><em> A three</em><em>‑</em><em>judge panel unanimously upheld a lower court</em><em>’</em><em>s decision denying a preliminary injunction, finding that the FTC had not demonstrated a likelihood of success in proving the merger would harm competition. The acquisition, completed in late</em><em> </em><em>2023 following UK regulatory approval, is the largest ever in the video gaming industry.”<br /></em>(Source: adapted from <a href="https://www.reuters.com/legal/microsoft-wins-ftc-appeal-challenging-69-bln-activision-blizzard-deal-2025-05-07/">Reuters, 2025</a>).</p>
<p>Une fois l’information extraite, voici un exemple de graphe qu’il est possible de construire depuis ce texte :</p>



<figure class="wp-block-image aligncenter size-large"><a href="/wp-content/uploads/2025/09/Full_Extracted_KG.png"><img loading="lazy" decoding="async" width="1024" height="537" src="/wp-content/uploads/2025/09/Full_Extracted_KG-1024x537.png" alt="" class="wp-image-23761" srcset="https://www.smalsresearch.be/wp-content/uploads/2025/09/Full_Extracted_KG-1024x537.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Full_Extracted_KG-300x157.png 300w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Full_Extracted_KG-768x402.png 768w, https://www.smalsresearch.be/wp-content/uploads/2025/09/Full_Extracted_KG.png 1330w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Figure 6&nbsp;: Exemple d’extraction depuis un texte</figcaption></figure>



<p>Ce type d’extraction peut se faire de nombreuses façons différentes. La prochaine section sera spécialement dédiée aux différentes approches qui peuvent être adoptées pour réaliser une extraction complète, leurs avantages et inconvénients.</p>



<h2 class="wp-block-heading">Quelles approches pour réaliser une extraction d’entités et de relations&nbsp;?</h2>



<h3 class="wp-block-heading">Extraction manuelle VS outils dédiés</h3>



<p>La construction d’un graphe de ce type peut se faire de manière manuelle en suivant la technique présentée dans la section précédente (envoyer un prompt incluant les instructions et le chunk au LLM, récupérer et décomposer l’output structuré renvoyé en sortie, puis mettre à jour le graphe via requêtes), ou alors langchain propose un outil permettant d’automatiser ces différentes tâches via le <a href="https://python.langchain.com/api_reference/experimental/graph_transformers/langchain_experimental.graph_transformers.llm.LLMGraphTransformer.html">LLM Graph Transformer</a>.</p>
<p>Cet outil permet de simplifier la procédure, en prenant en charge les instructions au LLM, la construction du template et le traitement de la sortie structurée. Il offre plusieurs possibilités de personnalisation, comme la possibilité de restreindre les types de nœud que l’on souhaite détecter (par ex. uniquement des nœuds de type « Person », « Company » et « Location »), de restreindre les types de relation, ou encore de personnaliser le prompt d’instructions.</p>
<p>De plus, une instance <code>LLMGraphTransformer</code> renvoie en sortie liste d’objets de type <code>GraphDocument</code>, contenant les nœuds et relations détectés, qui est exploitable directement par plusieurs drivers langchain vers des bases de données orientées graphe (telles que Memgraph, TigerGraph, Neo4j, etc.), afin de réaliser directement l’importation des entités et relations extraites vers le graphe.</p>
<p>Ci-dessous, un exemple illustratif de l’extraction des données depuis une liste de chunks via l’outil <code>LLMGraphTransformer</code>, suivie de l’importation des entités et relations vers Neo4j&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" style="color:#000000;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>doc_transformer=LLMGraphTransformer(llm=llm)
graph_docs=doc_transformer.convert_to_graph_documents(listOfChunks)

from langchain_neo4j import Neo4jGraph
graph=Neo4jGraph(
    url='XXXXX',
    username='YYYYY',
    password='ZZZZZ'
)
graph.add_graph_documents(graph_docs)</textarea></pre><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: #000000">doc_transformer=LLMGraphTransformer(</span><span style="color: #001080">llm</span><span style="color: #000000">=llm)</span></span>
<span class="line"><span style="color: #000000">graph_docs=doc_transformer.convert_to_graph_documents(listOfChunks)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #AF00DB">from</span><span style="color: #000000"> langchain_neo4j </span><span style="color: #AF00DB">import</span><span style="color: #000000"> Neo4jGraph</span></span>
<span class="line"><span style="color: #000000">graph=Neo4jGraph(</span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #001080">url</span><span style="color: #000000">=</span><span style="color: #A31515">&#39;XXXXX&#39;</span><span style="color: #000000">,</span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #001080">username</span><span style="color: #000000">=</span><span style="color: #A31515">&#39;YYYYY&#39;</span><span style="color: #000000">,</span></span>
<span class="line"><span style="color: #000000">    </span><span style="color: #001080">password</span><span style="color: #000000">=</span><span style="color: #A31515">&#39;ZZZZZ&#39;</span></span>
<span class="line"><span style="color: #000000">)</span></span>
<span class="line"><span style="color: #000000">graph.add_graph_documents(graph_docs)</span></span></code></pre></div>



<p><br />Il existe aussi une alternative gratuite pour Neo4j, qui ne requiert aucune programmation, le <a href="https://llm-graph-builder.neo4jlabs.com/">Neo4j LLM Knowledge Graph Builder</a>. Cet outil en ligne prend toutes les étapes en charge, en allant du prétraitement des documents (pdf, page web) jusqu’à la construction du graphe de connaissances résultant, et offre de multiples options de personnalisation (contraindre les types d’entité et/ou de relation à détecter, etc.). Voir <a href="https://neo4j.com/labs/genai-ecosystem/llm-graph-builder/">ici</a> pour plus de détails.</p>



<h3 class="wp-block-heading">Extraction libre VS extraction supervisée</h3>



<p>Il est à noter que si aucune contrainte (sur les types d’entité et de relation à extraire) n’est définie avec ces outils, ils vont librement extraire toutes les informations qu’ils peuvent trouver. Ce genre d’extraction « à l’aveugle » peut éventuellement être utilisée pour des petits documents, ou dans des cas où l’on ne sait pas à l’avance le genre de structure que l’on peut extraire, mais il est généralement préférable d’établir à l’avance l’ontologie que l’on souhaite adopter pour le graphe.</p>
<p>Une extraction libre est en effet souvent problématique pour plusieurs raisons :</p>
<p><strong>Explosion des types d’entité et de relation </strong></p>
<p>Lorsque la taille ou le nombre de documents augmente, l&#8217;on risque rapidement de se retrouver avec un très grand nombre de types différents d’entités et de relations au sein du graphe, ce qui peut le rendre difficile à exploiter (par ex. pour des applications de RAG).</p>
<p><strong>Incohérence de types</strong></p>
<p>En l’absence d’une ontologie fournissant une nomenclature claire, il y a des risques d’incohérence dans les types détectés (par exemple, une entreprise pourra être labelisée comme « Enterprise », une autre comme « Company », et une troisième comme « Organization »). En pratique, ce genre de soucis peut potentiellement être réglé a posteriori en listant tous les types de nœud et en rassemblant les types sémantiquement proches.</p>
<p><strong>Soucis de réification</strong></p>
<p>Par définition, une relation dans un graphe relie un nœud à un autre nœud. Un souci peut émerger lorsqu’une entité doit se connecter à une information qui a été modélisée sous la forme d’une relation. Pour illustrer le problème, reprenons en guise d&#8217;exemple l’acquisition d’Activision Blizzard par Microsoft. Supposons qu&#8217;un premier chunk de texte mentionne simplement cette acquisition sans plus de détails, elle sera fort potentiellement enregistrée sous la forme&nbsp;:</p>
<p><code>(Microsoft)-[ACQUIRES]-&gt;(Activision Blizzard)</code></p>
<p>Si maintenant le chunk suivant mentionne l’information « <em>The FTC challenged the acquisition&#8230;</em> », nous avons un problème car il n’est plus possible de modéliser</p>
<p><code>(FTC)-[CHALLENGES]-&gt;(Acquisition)</code></p>
<p>puisque l’acquisition a été précédemment modélisée sous la forme d’une relation, et non d’un nœud pouvant être référencé par une relation.</p>
<p>Dans ce cas, la relation peut par exemple être supprimée puis remplacée par un nœud, afin de la rendre référençable :</p>
<p><code>(Microsoft)-[INITIATES]-&gt;(Acquisition)-[TARGETS]-&gt;(Activision Blizzard)</code></p>
<p>Ce processus, appelé <strong>réification</strong>, n’est pas automatique et demande l’ajout d’une étape d’enrichissement pour détecter de potentielles références à des informations modélisées sous forme de relations, et les réifier si nécessaire.</p>



<h2 class="wp-block-heading">Quelques alternatives aux LLM</h2>



<p>Maintenant que nous avons vu une série d’approches basées spécifiquement sur les LLM, cette section propose quelques outils alternatifs basés sur des méthodes de NLP classique.</p>
<p>Si l&#8217;objectif est uniquement de faire l’extraction d’entités nommées, vous pouvez trouver <a href="/named-entity-recognition-une-application-du-nlp-utile/">ici un article de blog dédié à ce sujet</a>, ainsi qu’un <a href="/pii-filtering-fr/">exemple d’application de NER en PII filtering</a>. Il existe de nombreux modèles de NER préentrainés disponibles sur des plateformes telles que <a href="https://huggingface.co/">Hugging Face</a>.</p>
<p>Concernant l’extraction d’entités et de relations, elle peut se faire typiquement de 2 façons distinctes&nbsp;:</p>



<ul class="wp-block-list">
<li><strong>L’extraction en 2 étapes séparées&nbsp;:</strong> l&#8217;on commence par l’utilisation d’un NER pour la détection et la catégorisation des entités, suivie d&#8217;une extraction de relations sur la base du texte et des entités détectées, afin de déterminer les relations entre ces dernières. Quelques exemples d’outils pour l’extraction de relations incluent <a href="https://github.com/thunlp/OpenNRE">openNRE</a>, <a href="https://github.com/alimirzaei/spacy-relation-extraction">spacy-relation-extraction</a> ou encore <a href="https://github.com/jackboyla/GLiREL">GliREL</a>.</li>



<li><strong>L’extraction conjointe (end-to-end) &nbsp;:</strong> il s’agit d’outils qui réalisent l’extraction d’entités et de relations en une seule étape, tels que <a href="https://nlp.stanford.edu/software/openie.html">OpenIE</a>, <a href="https://github.com/SapienzaNLP/relik">Relik</a>,&nbsp;<a href="https://github.com/Babelscape/rebel">REBEL</a> ou <a href="https://www.diffbot.com/products/natural-language/">Diffbot</a> (solution commerciale).</li>
</ul>



<h2 class="wp-block-heading">Vérifier la conformité de ce qui a été détecté</h2>



<p>La grande force des LLM pour ce genre de tâche d’extraction est leur compréhension du langage naturel, ce qui permet de personnaliser l’extraction en adaptant le prompt d’instructions. Par exemple, en l’absence de template de sortie pour la réponse structurée (que le LLM peut peiner à respecter si le template devient trop compliqué), il est possible d’obtenir des nœuds et relations conformes à l’ontologie en décrivant l’ontologie directement dans le prompt d’instructions, mais il est important de rester vigilant aux extractions. En effet, il n’y a aucune garantie que le LLM ne fasse pas d’erreur, et ne renvoie pas en sortie une relation/entité non-conforme.</p>
<p>De manière générale, lorsqu’un LLM (ou tout autre outil) est utilisé pour extraire de l’information de façon automatique depuis un texte vers un graphe de connaissances, il est utile de vérifier que ce qui a été extrait est bien conforme à l’ontologie et fidèle à l’information qui se trouve dans la source.</p>
<ol>
<li>Vérifier que l’extraction respecte l’ontologie</li>
</ol>
<p>Comme nous l’avons déjà mentionné dans un <a href="/shacl-logische-en-vormcontroles-met-kg-technologieen/">précédent article de blog</a>, il est possible de valider la structure et le contenu d’un graphe de connaissances à l’aide du standard SHACL. Il s’agit d’un langage qui va contenir les différentes contraintes qui s’appliquent sur un graphe de connaissances. Il est possible soit d’effectuer une validation finale du graphe, pour vérifier que le contenu respecte effectivement les contraintes énoncées en SHACL (et de lister les données qui violent ces contraintes), soit d’effectuer ces validations de façon transactionnelle à chaque nouvelle information qui est ajoutée, afin de refuser tout nouvel ajout illégal. Bien qu’initialement prévu pour des graphes en RDF, certaines bases de données peuvent tout de même interpréter des contraintes en SHACL et valider le graphe, comme <a href="https://neo4j.com/labs/neosemantics/">neo4j avec le package <em>neosemantics</em> (n10s)</a>.</p>
<ol start="2">
<li>Vérifier que l’extraction est correcte</li>
</ol>
<p>Le risque d’une extraction automatique est qu’une information introduite dans le graphe soit factuellement incorrecte vis-à-vis du texte d’origine, ce qui peut être particulièrement problématique si ce graphe est utilisé comme potentielle source d’information (par exemple pour une application de graphRAG). Plusieurs approches peuvent être suivies. La plus simple est une vérification humaine des informations extraites, mais cela peut devenir difficile, voire infaisable, lorsque les documents deviennent trop longs/nombreux. L’autre approche consiste à utiliser un second LLM afin de vérifier ce qui a été extrait de chaque chunk. Comme nous l’avons mentionné dans <a href="/experiences-pratiques-avec-levaluation-automatique-de-la-rag/">l’article d’évaluation de LLM</a>, il est plus facile, pour les LLM, de détecter les erreurs a posteriori que de les éviter.</p>



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



<p>Ces technologies, bien que performantes, ne sont jamais parfaites. Sauf extraction libre (à l’aveugle), mais qui risque d’aboutir à la création d’un graphe difficilement exploitable, la construction d’un graphe de connaissances à partir de texte est une tâche qui demande du travail, tant en amont (prétraitement des textes, établissement d’une ontologie pour le graphe sur la base du contenu du texte) qu’en aval (validation de la structure du graphe vis-à-vis de l’ontologie et vérification de la véracité et la fiabilité de son contenu).</p>



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



<p><em>Ce post est une contribution individuelle de Pierre Leleux, data scientist et network data analyst 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>Data ingestion voor generatieve AI-toepassingen: kernbegrippen</title>
		<link>https://www.smalsresearch.be/databeheer-voor-generatieve-ai-toepassingen-kernbegrippen/</link>
		
		<dc:creator><![CDATA[Katy Fokou]]></dc:creator>
		<pubDate>Wed, 13 Nov 2024 12:40:56 +0000</pubDate>
				<category><![CDATA[[NL]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[Artificial intelligence]]></category>
		<category><![CDATA[data ingestion]]></category>
		<guid isPermaLink="false">/?p=21540</guid>

					<description><![CDATA[“Garbage in, garbage out” is een veelgebruikte uitspraak om de impact van data op de resultaten van kunstmatige intelligentiesystemen te beschrijven. Generatieve AI-toepassingen zoals vraag-en-antwoordsystemen vormen geen uitzondering op de regel. De knowledge bases waarop ze vertrouwen om antwoorden te genereren, moeten worden gevoed door een ingestion pipeline die speciaal is toegespitst op dit soort data, die in verschillende vormen beschikbaar zijn, zowel gestructureerd als ongestructureerd.]]></description>
										<content:encoded><![CDATA[
<p><a href="/21293-2/"><em>Version en français</em></a></p>



<p>Data ingestion is het proces waarbij data uit verschillende bronnen worden verzameld en geïmporteerd in een gecentraliseerd opslagsysteem (datawarehouse, data lake, vector store, etc.) met het oog op gebruik voor specifieke doeleinden. Data kunnen uit verschillende bronnen komen, zoals databases, PDF/Excel/xml-bestanden, logbestanden, API&#8217;s en evenementen of websites. Het ingestion-proces moet waarborgen dat de data correct en volledig zijn en in bijna realtime beschikbaar zijn om bedrijfsanalyses te ondersteunen.</p>



<p>Hoewel de traditionele ingestion-methodes bekend zijn, heeft het gebruik van data om grote taalmodellen (LLM&#8217;s) te voeden een aantal specifieke kenmerken. In dit artikel bespreken we de ingestion van voornamelijk ongestructureerde data om de knowledge bases op te bouwen waarop generatieve AI-toepassingen zoals chatbots zijn gebaseerd.</p>



<h1 class="wp-block-heading">Beschrijving van een data ingestion pipeline</h1>



<p>De hieronder weergegeven pipeline [Representatie van een ingestion pipeline in een systeem voor question answering] is van toepassing op een RAG-systeem (Retrieval-Augmented Generation) voor het genereren van antwoorden op vragen op basis van een knowledge base. De knowledge base wordt gevoed door verschillende databronnen die de pipeline doorlopen, van verzamelen tot indexeren in een vector database. De voornaamste stappen in deze pipeline zijn de volgende.</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/image-2.png"><img loading="lazy" decoding="async" width="1024" height="499" src="/wp-content/uploads/2024/11/image-2-1024x499.png" alt="" class="wp-image-21418" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/image-2-1024x499.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-2-300x146.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-2-768x375.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-2.png 1222w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Representatie van een ingestion pipeline in een systeem voor question answering</figcaption></figure>



<p><strong>Data laden</strong></p>



<p>De belangrijkste stap bij het bouwen van een ingestion pipeline voor een bepaald project is het identificeren van de databronnen die nodig zijn om dat project te voltooien. De input die gebruikt wordt in RAG-projecten bestaat voornamelijk uit ongestructureerde data uit verschillende bronnen, zoals websites, sociale netwerken, locale directories, databases, content management tools (bijv. SharePoint, Confluence), en opslagdiensten (bijv. S3). Voor elk van de gebruikte bronnen is het essentieel om over de juiste connectoren te beschikken en te controleren of je de benodigde toegangsrechten hebt.</p>



<p><strong>Extractie</strong></p>



<p>Zodra de bronnen zijn geïdentificeerd en de connectoren zijn geconfigureerd, kan de extractie van de inhoud beginnen. Het extractieproces hangt af van de databron en het dataformaat. Als de databron een webpagina is, moet een scrapingtool worden gebruikt om de HTML-inhoud te extraheren, waarna de inhoud moet worden geanalyseerd om de relevante informatie te extraheren. Als de databron een afbeelding is, moet je misschien een OCR-tool gebruiken, terwijl je voor databases de juiste SQL-query&#8217;s moet schrijven.</p>



<p>De inhoudsextractie kan gecombineerd worden met een inhoudsverrijkingsproces om metadata te genereren. Deze metadata worden uit de databron zelf gehaald (bijv. documentnaam, auteursnaam, URL, aanmaak- en wijzigingsdatum, tags) of uit de inhoud zelf (koptekst, titel, XML-tags). Een andere methode voor dataverrijking bestaat uit het gebruik van generatieve modellen om de beschrijvingen van afbeeldingen en tabellen in de data te genereren.</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/image-1.png"><img loading="lazy" decoding="async" width="1024" height="527" src="/wp-content/uploads/2024/11/image-1-1024x527.png" alt="" class="wp-image-21417" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/image-1-1024x527.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-1-300x154.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-1-768x395.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-1.png 1274w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Vergelijking van verschillende methoden om tekst uit een afbeelding te extraheren: rechts wordt een samenvatting van de afbeelding gegenereerd met behulp van een groot multimodaal model, en hieronder wordt de tekst geëxtraheerd met behulp van OCR.</figcaption></figure>



<p>Ongeacht het formaat van de originele data, moet het resultaat van het extractieproces gestandaardiseerd zijn. Over het algemeen bestaat het uit tekst en bijbehorende metadata in JSON-formaat.</p>



<p><strong>Opschonen en transformeren</strong></p>



<p>Data geëxtraheerd uit bronnen is zelden bruikbaar zoals het is, en moet opgeschoond worden. Het opschonen is de meest tijdrovende fase en varieert afhankelijk van de use case. De meest voorkomende operaties die worden toegepast op inhoud zijn de volgende:</p>



<ul class="wp-block-list">
<li>Opschonen van leestekens en speciale karakters.</li>



<li>Verwijderen van duplicaten.</li>



<li>Verwijderen van onnodige informatie, zoals reclamebanners en cookies in inhoud van websites die ruis introduceren in de data.</li>



<li>Controleren en corrigeren van tegenstrijdige, inconsistente of valse informatie, die het antwoord dat aan de andere kant van de RAG-procesketen wordt gegenereerd sterk beïnvloedt.</li>



<li>Verwerken van ontbrekende informatie. Enkele voorbeelden van ontbrekende informatie in ongestructureerde data zijn links naar andere webpagina&#8217;s met aanvullende informatie op de geëxtraheerde inhoud, e-mails die verwijzen naar andere e-mails, enz.</li>
</ul>



<p><strong>Chunking</strong></p>



<p>Chunking is het opsplitsen van tekst in kleinere eenheden. Hierdoor kan het model alleen die passages ophalen die informatie bevatten die relevant is voor het antwoord. Er bestaan verschillende chunkingmethoden, die kunnen worden gegroepeerd in twee categorieën: chunking op basis van vooraf gedefinieerde regels (vaste grootte, per alinea) en chunking op basis van semantiek (groepering van gelijksoortige segmenten). Efficiënt chunken bestaat uit het vinden van de juiste balans tussen wachttijd en kosten. Hoe kleiner de chunk, hoe meer opslag er nodig is en hoe hoger de latency; hoe groter de chunk, hoe groter de context van het model en dus hoe hoger de kosten. Welke methode ook gekozen wordt, het is belangrijk om rekening te houden met de structuur van de tekst en de maximale contextlengte van het taalmodel.</p>



<p><strong>Genereren van vector database weergave (<em>Embedding</em>)</strong></p>



<p>Dit is de fase waarin tekstdata wordt omgezet in vectoren waarop het semantisch zoeken specifiek voor RAG (retrieval) kan worden toegepast. Er bestaan verschillende embeddingstechnieken, maar de meest effectieve is de contextual embeddingstechniek gebaseerd op grote taalmodellen.</p>



<p><strong>Indexering</strong></p>



<p>Dit is de laatste fase in de ingestion pipeline. De data-output van de pipeline wordt geïndexeerd in een vector database zoals Weaviate, Pinecone, ElasticSearch, enz. Metadata wordt ook in de database geplaatst, zodat de resultaten kunnen worden verfijnd tijdens het zoeken (<em>retrieval</em>). De keuze van de <a href="/betere-zoekresultaten-met-vector-databases/">Vector databases</a> en het type indexering hangt af van het volume van de op te slaan data en de vereiste prestaties.</p>



<h1 class="wp-block-heading">Andere aspecten om te overwegen</h1>



<p><strong>Batch of streaming ingestion</strong></p>



<p>In batchmodus worden data massaal opgenomen met regelmatige tussenpozen of op aanvraag.</p>



<p>In streamingmodus worden nieuwe data direct in realtime of bijna realtime opgenomen. De streamingmodus wordt gekozen als de meest actuele informatie nodig is en als deze informatie snel verandert. Streaming ingestion vereist constante controle om de kleinste verandering in de datastructuur te detecteren.</p>



<p><strong>Updates beheren</strong></p>



<p>Om updates te beheren, is de traceerbaarheid van data belangrijk. Dit houdt in dat informatie zoals bron, versie, tijdstempel, laatste wijzigingsdatum, enz. wordt bijgehouden. Er zijn twee mogelijke strategieën voor het beheren van updates in bestemmingsdatabases: incrementeel updaten (alleen data die veranderd is wordt opgenomen) of volledig updaten. De veelheid aan databronnen en -formaten die worden gebruikt door LLM-gebaseerde toepassingen introduceert tal van problemen die ofwel te wijten zijn aan slecht beheer van de data bij de bron, of aan slechte tracering van wijzigingen door de dataverbruiker.</p>



<p><strong>Beheer van de veiligheid</strong></p>



<p>Zoals bij alle systemen die data verwerken, is er een minimum aan veiligheidsmaatregelen van toepassing op het ingestion proces:</p>



<ul class="wp-block-list">
<li>Toegang tot bronnen controleren.</li>



<li>De juiste toegangsrechten toekennen wanneer inhoud wordt ingevoegd in de doeldatabase.</li>



<li>Beveiligen van dataoverdracht tussen de bron en het ingestion systeem om knoeien met data (<em>data tampering</em>) te voorkomen.</li>



<li>Enz.</li>
</ul>



<p>Bij RAG-toepassingen worden persoonsgegevens regelmatig aangetroffen in niet-gestructureerde documenten. Deze gegevens vereisen bijzondere aandacht, omdat ze onderhevig zijn aan strikte regelgeving (<a href="https://www.cnil.fr/en">GDPR</a>). Gegevens moeten vaak worden geanonimiseerd voordat ze worden ingevoegd in de bestemmingsdatabase. Daarom is het noodzakelijk om een filterfase in te bouwen voor persoonlijk identificeerbare gegevens of <a href="/pii-filtering/"><em>PII filtering</em></a> in de pipeline. Doeltreffende tools bestaan, maar ze garanderen geen 100% correcte filtering.</p>



<p>Een ander aandachtspunt specifiek voor RAG is de keuze van betrouwbare bronnen. In veel geavanceerde RAG-toepassingen wordt informatie uit websites gehaald. Een good practice is om de toepassing te beperken tot een lijst van vooraf gedefinieerde websites die kunnen worden opgevraagd.</p>



<p><strong>Monitoring en foutenbeheer</strong></p>



<p>Bij elke stap van de pipeline moeten fouten worden geregistreerd in logboeken en moeten waarschuwingssystemen worden ingesteld.</p>



<p>De algemene evaluatie van het ingestion systeem gebeurt indirect door <a href="/evalueren-van-een-generatief-vraag-antwoordsysteem/">de prestaties van het RAG-systeem te monitoren</a>. Een slechte antwoord kan te wijten zijn aan een gebrek aan informatie in de database (de bronnen opnieuw evalueren), slechte chunking ( het gebruik van chunks en hun impact op de geleverde antwoord meten), enz&#8230;.</p>



<h1 class="wp-block-heading">Enkele bijzondere gevallen</h1>



<p><strong>RAG gecombineerd met web search</strong></p>



<p>Typisch zijn de informatiebronnen die het vraag-antwoordsysteem voeden de knowledge base die wordt gevoed door de ingestion pipeline en de resultaten van web queries die on the fly worden uitgevoerd tijdens het verwerken van de vraag.</p>



<p>Het extractieproces wordt aangestuurd door het generatieve model (LLM) dat, afhankelijk van de query, de meest geschikte bron of een combinatie van de twee aanroept.</p>



<p><strong>Multimodale RAG</strong></p>



<p>Multimodale RAG maakt het mogelijk om data in verschillende vormen op te vragen: tekst, beeld, video en audio.</p>



<p>Er bestaan diverse strategieën om deze verschillende soorten data in te voeren:</p>



<ul class="wp-block-list">
<li>Gebruik van een referentiemodaliteit. Een modaliteit dient als referentie voor de datarepresentatie en de andere modaliteiten worden verankerd in deze referentiemodaliteit met behulp van specifieke modellen. In het hierboven weergegeven pipeline-voorbeeld is de referentiemodaliteit tekst en wordt voor elk beeld in de data een tekstuele samenvatting gegenereerd die dat beeld weergeeft.</li>



<li>Gebruik van een multimodaal model. Een enkel multimodaal embeddingmodel wordt gebruikt om vectorrepresentaties van alle soorten data te genereren.</li>
</ul>



<h1 class="wp-block-heading">Tools</h1>



<p>De keuze van een ingestion-platform hangt af van de complexiteit van het proces, het volume van de verwerkte data, de vereiste verwerkingssnelheid en de beschikbare bron- en bestemmingsconnectoren.</p>



<ul class="wp-block-list">
<li><a href="https://airbyte.com/">Airbyte</a>. Engine voor gestructureerde en ongestructureerde data-integratie die wordt gebruikt om datawarehouses of data lakes te voeden.</li>



<li><a href="https://unstructured.io/">Unstructured</a>. Tool voor het bouwen van data pipelines voor LLM&#8217;s [<a href="https://www.smalsresearch.be/wp-content/uploads/2024/10/QR-Unstructured.pdf">Hier vindt u een link naar een quick review die wij over deze tool geschreven hebben</a>].</li>



<li><a href="https://python.langchain.com/docs/concepts/document_loaders/">Langchain</a>. Bijzonder veelzijdige tool voor het ontwikkelen van toepassingen op basis van generatieve AI, integreert met tal van databronnen en het Unstructured-platform, biedt tal van chunkingfuncties.</li>



<li><a href="https://www.llamaindex.ai/">LlamaIndex</a>. Tool voor het ontwikkelen van toepassingen op basis van generatieve AI voor het doorzoeken van knowledge bases.&nbsp;LlamaIndex biedt ook een service voor het beheer van <a href="https://www.llamaindex.ai/blog/introducing-llamacloud-and-llamaparse-af8cedf9006b">LLamaCloud</a>data pipelines.</li>



<li><a href="https://docs.ray.io/en/latest/index.html">Ray</a>. Python library voor het beheren van gedistribueerde computerprocessen.</li>



<li>Data ophalen van een webpagina: BeautifulSoup (Python library), <a href="https://github.com/microsoft/playwright">Playwright</a>, <a href="https://www.firecrawl.dev">FireCrawl</a>.</li>



<li><a href="https://microsoft.github.io/presidio/">Presidio</a>: Filteren van persoonsidentificerende gegevens.</li>
</ul>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/image.png"><img loading="lazy" decoding="async" width="1024" height="637" src="/wp-content/uploads/2024/11/image-1024x637.png" alt="" class="wp-image-21416" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/image-1024x637.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-300x187.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-768x478.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image.png 1300w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Voorbeeld van een pipeline gegenereerd met de Unstructured open-source library</figcaption></figure>



<h1 class="wp-block-heading">Conclusies</h1>



<p>Data ingestion is een kritieke stap bij de ontwikkeling van een toepassing gebaseerd op generatieve AI omdat, zoals het gezegde luidt, “garbage in, garbage out”. Het bovenstaande artikel presenteert enkele technieken en best practices voor data ingestion; elke toepassing heeft echter zijn eigen specifieke kenmerken en moeilijkheden, die grotendeels afhangen van het toepassingsdomein van de oplossing. Daarom moet de ontwikkeling van een data ingestion-strategie het resultaat zijn van een nauwe samenwerking tussen een technisch expert en een domeinspecialist.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Ingestion de données pour les applications d&#8217;IA générative: concepts-clés</title>
		<link>https://www.smalsresearch.be/ingestion-de-donnees-pour-les-applications-d-ia-generative/</link>
		
		<dc:creator><![CDATA[Katy Fokou]]></dc:creator>
		<pubDate>Wed, 13 Nov 2024 11:11:39 +0000</pubDate>
				<category><![CDATA[[FR]]]></category>
		<category><![CDATA[Blog post]]></category>
		<category><![CDATA[Artificial intelligence]]></category>
		<category><![CDATA[data ingestion]]></category>
		<guid isPermaLink="false">/?p=21293</guid>

					<description><![CDATA[« Garbage in, garbage out » c’est la formule consacrée pour décrire l’impact des données sur les résultats des systèmes d’intelligence artificielle. Les applications d’IA génératives telles que les systèmes de questions-réponses ne dérogent pas à la règle. Les bases de connaissances sur lesquelles elles s’appuient pour générer des réponses doivent être alimentées par un pipeline d’ingestion dédié à ce type de données qui se présentent sous différentes formes, structurées et non structurées.]]></description>
										<content:encoded><![CDATA[
<p><a href="/databeheer-voor-generatieve-ai-toepassingen-kernbegrippen/"><em>Nederlandstalige versie</em></a></p>



<p>L&#8217;ingestion de données est le processus de collecte et d&#8217;importation de données provenant de différentes sources vers un système de stockage centralisé (data warehouse, data lake, vector store, etc.) en vue de les exploiter pour des usages spécifiques. Les données peuvent provenir de sources diverses telles que les bases de données, les fichiers PDF/excel/xml, les logs, les APIs et événements ou les sites web. Le processus d&#8217;ingestion doit s&#8217;assurer que les données sont correctes, complètes et disponibles en temps quasi-réel pour soutenir les analyses d&#8217;entreprise.</p>



<p>Si les méthodes d’ingestion de données traditionnelles sont bien connues, l&#8217;utilisation de données pour alimenter de grands modèles de langage (LLM) présente quelques spécificités. Dans cet article, nous allons discuter de l&#8217;ingestion de données, principalement non structurées, pour constituer les bases de connaissance sur lesquelles s’appuient des applications d&#8217;IA générative telles que les chatbots.</p>



<h1 class="wp-block-heading">Description d’un pipeline d’ingestion de données</h1>



<p>Le pipeline présenté ci-dessous s’applique à un système de type RAG (Retrieval-Augmented Generation) pour la génération de réponses aux questions basée sur une base de connaissance. La base de connaissance est alimentée par plusieurs sources de données qui traverse le pipeline, de la collecte à l’indexation dans une base de données vectorielle. Les principales étapes de ce pipeline sont les suivantes.</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/image-2.png"><img loading="lazy" decoding="async" width="1024" height="499" src="/wp-content/uploads/2024/11/image-2-1024x499.png" alt="" class="wp-image-21418" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/image-2-1024x499.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-2-300x146.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-2-768x375.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-2.png 1222w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Représentation d’un pipeline d’ingestion dans un système de question answering.</figcaption></figure>



<p><strong>Chargement des données</strong></p>



<p>L&#8217;étape la plus importante dans la construction d&#8217;un pipeline d&#8217;ingestion pour un projet donné consiste à identifier les sources de données nécessaires pour la réalisation de ce projet. Les inputs utilisées dans le cadre de projets RAG sont principalement des données non structurées provenant de multiples sources telles que les sites internet, les réseaux sociaux, les répertoires locaux, bases de données, les outils de gestion de contenus (par exemple SharePoint), Confluence et les services de stockage (par exemple S3). Pour chacune des sources utilisées, il est essentiel de disposer des connecteurs appropriés et de vérifier que l&#8217;on possède les droits d&#8217;accès nécessaires.</p>



<p><strong>Extraction</strong></p>



<p>Une fois les sources identifiées et les connecteurs configurés, l&#8217;extraction du contenu peut commencer. Le processus d&#8217;extraction dépend de la source de données et du format de données. Si la source de données est une page web, il convient d&#8217;utiliser un outil de <em>scraping</em> pour extraire le contenu HTML, puis d&#8217;analyser ce contenu pour en extraire les informations pertinentes. Si la source de données est une image, il sera nécessaire d&#8217;utiliser un outil OCR, tandis que pour les bases de données, il faudra écrire des requêtes SQL appropriées.</p>



<p>L’opération d&#8217;extraction du contenu peut être associé à un processus d&#8217;enrichissement du contenu par génération de métadonnées. Ces métadonnées sont extraites de la source de données elle-même (par exemple le nom du document, le nom de l&#8217;auteur, l&#8217;URL, les dates de création et de modification, les tags) ou du contenu lui-même (l&#8217;en-tête, le titre, les tags XML). Une autre méthode d&#8217;enrichissement de données consiste à utiliser des modèles génératifs pour générer les descriptions images et de tableaux se trouvant dans les données.&nbsp;</p>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/image-3.png"><img loading="lazy" decoding="async" width="1024" height="528" src="/wp-content/uploads/2024/11/image-3-1024x528.png" alt="" class="wp-image-21424" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/image-3-1024x528.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-3-300x155.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-3-768x396.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-3.png 1273w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Comparaison de différentes méthodes d’extraction de texte à partir d’une image: à droite un résumé de l’image est généré à l’aide d’un modèle large multimodal (LMM) et en dessous le texte est extrait à l’aide d’un OCR.</figcaption></figure>



<p>Quelle que soit le format des données d&#8217;origine, le résultat du processus d’extraction doit être uniformisé. Il consiste généralement en un texte et les métadonnées associées sous format JSON.</p>



<p><strong>Nettoyage et transformation</strong></p>



<p>Les données extraites des sources sont rarement utilisables telles quelles et nécessitent d’être nettoyées. L’opération de nettoyage est l’étape la plus chronophage et varie selon le cas d’utilisation. Les opérations les plus communes appliquées au contenu sont les suivantes&nbsp;:</p>



<ul class="wp-block-list">
<li>Nettoyage de la ponctuation et de caractères spéciaux.</li>



<li>Suppression des doublons.</li>



<li>Suppression des informations inutiles comme par exemple les bannières publicitaires et cookies présentes dans les contenus provenant de sites internet qui introduisent du bruit dans les données.</li>



<li>Contrôle et correction des informations contradictoires, incohérentes ou fausses, celles-ci affectent fortement la réponse générée à l’autre bout de la chaine du processus RAG.</li>



<li>Traitement des informations manquantes. Quelques exemples d’informations manquantes dans les données non structurées sont par exemple des liens vers d’autres page web contenant des informations complémentaires au contenu extrait, des emails renvoyant vers d’autres emails, etc.</li>
</ul>



<p><strong>Chunking</strong></p>



<p>Le <em>chunking</em> est l’opération de découpage d’un texte en plus petites unités. Cela permet au modèle de récupérer uniquement les passages contenant l’information pertinente pour la réponse. Ils existent plusieurs méthodes de <em>chunking</em> qui peuvent être regroupées en deux catégories&nbsp;: le <em>chunking</em> basé sur des règles prédéfinies (taille fixe, par paragraphe) et le <em>chunking</em> basé sur la sémantique (groupement de segments similaires). Un <em>chunking</em> efficace nécessite de trouver le bon équilibre entre temps d’attente et coût. Plus petit est le <em>chunk</em>, plus on a besoin de stockage et plus le temps de latence est élevé, plus le <em>chunk</em> est grand, plus le contexte du modèle est grand et donc le coût élevé. Quelle que soit la méthode choisie, il est important de prendre en compte la structure du texte et la longueur maximale de contexte du modèle de langage.</p>



<p><strong>Génération des représentations vectorielles de données (<em>Embedding</em>)</strong></p>



<p>C’est l’étape de conversion des données textuelles en vecteurs sur lesquels pourra s’appliquer la recherche sémantique propre au RAG (<em>retrieval</em>). Ils existent plusieurs techniques <em>d’embedding </em>mais la plus performante est la technique d’<em>embedding</em> contextuelle basée sur les grands modèles de langage.</p>



<p><strong>L’indexation</strong></p>



<p>C’est l’étape ultime du pipeline d’ingestion. Les données en sortie du pipeline sont indexées dans une base de données vectorielle telle que Weaviate, Pinecone, ElasticSearch, etc. Les métadonnées sont également insérées dans la base de données, elles permettent d’affiner les résultats lors de l’opération de recherche (<em>retrieval</em>). Le choix de la <a href="/de-meilleurs-resultats-de-recherche-grace-aux-bases-de-donnees-vectorielles/">base de données vectorielle</a> ainsi que du type d’indexation se fait en fonction du volume de données à stocker et des performances recherchées.</p>



<h1 class="wp-block-heading">Autres aspects à prendre en compte</h1>



<p><strong>Ingestion en batch ou en streaming</strong></p>



<p>En mode batch, les données sont ingérées en masse à intervalles réguliers ou sur demande.</p>



<p>En mode streaming, les nouvelles données sont directement ingérées en temps réel ou presque. On choisit le mode streaming quand il est nécessaire d’avoir l’information la plus récente et que celle-ci évolue rapidement. L’ingestion en streaming requiert un monitoring constant afin de détecter le moindre changement dans la structure des données.</p>



<p><strong>Gestion des mises à jour</strong></p>



<p>Pour gérer les mises à jour, la traçabilité des données est importante. Ceci implique de traquer des informations tels que source, version, timestamp, date de dernière modification, … La mise à jour est alors déclenchée par les informations traquées. Deux stratégies sont possibles pour gérer les mises à jour dans les bases de données de destination&nbsp;: la mise à jour incrémentale (seules les données qui ont changé sont ingérées) ou la mise à jour intégrale. La multiplicité des sources et des formats des données utilisées par les applications basées sur les LLM introduit de nombreux problèmes&nbsp;qui sont&nbsp;soit dus à une mauvaise gouvernance des données à la source, soit dus à un mauvais traçage des changements par le consommateur de données.</p>



<p><strong>Gestion de la sécurité</strong></p>



<p>Comme pour tout système qui traite des données, un minimum de mesures de sécurité s’applique&nbsp;au processus d’ingestion:</p>



<ul class="wp-block-list">
<li>Le contrôle des accès aux sources.</li>



<li>L’attribution des droits d’accès appropriés au moment de l’insertion du contenu dans la base de données cible.</li>



<li>La sécurisation du transfert des données entre la source et le système d’ingestion pour éviter la modification de données (<em>data tampering</em>).</li>



<li>Etc.</li>
</ul>



<p>Dans le cas des applications RAG, on retrouve régulièrement des données à caractère personnel dans les documents non-structurés. Celles-ci requièrent une attention particulière car soumise à une régulation stricte (<a href="https://www.cnil.fr/fr/identifier-les-donnees-personnelles">RGPD</a>). Bien souvent une anonymisation des données est nécessaire avant insertion dans la base de données de destination. Il faut donc prévoir une étape de filtrage de données personnelles identifiables ou <a href="/pii-filtering-fr/"><em>PII filtering</em></a> dans le pipeline. Des outils efficaces existent mais ceux-ci ne garantissent pas un filtrage à 100% correct.</p>



<p>Un autre point d’attention propre au RAG est le choix de sources fiables. Dans beaucoup d’applications RAG avancées, les informations sont extraites à la volée de sites web. Une bonne pratique consiste à restreindre l’application à une liste de sites web prédéfinis qui peuvent être interrogés.</p>



<p><strong>Monitoring et gestion des erreurs</strong></p>



<p>A chaque étape du pipeline les erreurs doivent être enregistrés dans des journaux et des systèmes d’alertes doivent être mis en place.</p>



<p>L’évaluation globale du système d’ingestion se fait de façon indirecte en <a href="/evaluation-dun-systeme-generatif-de-questions-reponses/">monitorant les performances du système RAG</a>. Une mauvaise réponse peut être due au manque d’informations dans la base de données (réévaluer les sources), à un mauvais <em>chunking</em> (mesurer l’utilisation des <em>chunks</em>, leur impact dans la réponse fournie), etc…</p>



<h1 class="wp-block-heading">Quelques cas particuliers</h1>



<p><strong>Le RAG combiné à une recherche web</strong></p>



<p>Typiquement, les sources d’information qui alimentent le système de question-réponse sont&nbsp;la base de connaissance alimentée par le pipeline d’ingestion et le résultat de requêtes web exécutées à la volée au moment de traiter la question.</p>



<p>Le processus d’extraction est piloté par le modèle génératif (LLM) qui, en fonction de la question, fait appel à la source la plus appropriée ou à une combinaison des deux.</p>



<p><strong>Le RAG multimodal</strong></p>



<p>Le RAG multimodal permet d’interroger les données sous différentes formes&nbsp;: texte, image, vidéo, audio. Plusieurs stratégies sont alors possibles pour ingérer ces différents types de données&nbsp;:</p>



<ul class="wp-block-list">
<li>Utilisation d’une modalité de référence. Une modalité sert de référence pour la représentation des données et les autres modalités sont ancrées dans cette modalité de référence grâce à des modèles spécifiques. Dans l’exemple de pipeline illustré ci-dessus, la modalité de référence est le texte et pour chaque image présente dans les données on génère un résumé textuel qui représente cette image.</li>



<li>Utilisation d’un modèle multimodal. Un modèle d’<em>embedding</em> unique et multimodal est utilisé pour générer les représentations vectorielles des données quelque soit leur type.</li>
</ul>



<h1 class="wp-block-heading">Outils</h1>



<p>Le choix d’une plateforme d’ingestion dépend de la complexité du processus, du volume de données traité, de la rapidité de traitement nécessaire et des connecteurs source et destination disponibles.</p>



<ul class="wp-block-list">
<li><a href="https://airbyte.com/">Airbyte</a>. Moteur d’intégration des données structurées et non structurées utilisé pour alimenter les <em>data warehouse</em> ou <em>data lake</em>.</li>



<li><a href="https://unstructured.io/">Unstructured</a>. Outil de construction de pipelines de données pour les LLM <a href="https://www.smalsresearch.be/wp-content/uploads/2024/10/QR-Unstructured.pdf">[vous trouverez une quick review que nous avons écrit sur cet outil en suivant ce lien]</a>.</li>



<li><a href="https://python.langchain.com/docs/concepts/document_loaders/">Langchain</a>. Outil très versatile de développement d’applications basées sur l’IA générative, s’intègre avec de nombreuses sources de données ainsi que la plateforme Unstructured, propose de nombreuses fonctions de <em>chunking</em>.</li>



<li><a href="https://www.llamaindex.ai/">LlamaIndex</a>. Outil de développement d’applications basées sur l’IA générative pour la recherche dans les bases de connaissance.&nbsp;LlamaIndex dispose également d’un service de gestion des pipelines de données <a href="https://www.llamaindex.ai/blog/introducing-llamacloud-and-llamaparse-af8cedf9006b">LLamaCloud</a>.</li>



<li><a href="https://docs.ray.io/en/latest/index.html">Ray</a>. Bibliothèque Python pour la gestion des processus computationnels distribués.</li>



<li>Récupération des données d’une page web&nbsp;: BeautifulSoup (bibliothèque Python), <a href="https://github.com/microsoft/playwright">Playwright</a>, <a href="https://www.firecrawl.dev">FireCrawl</a>.</li>



<li><a href="https://microsoft.github.io/presidio/">Presidio</a>&nbsp;: Filtrage des données personnelles identifiables.</li>
</ul>



<figure class="wp-block-image size-large"><a href="/wp-content/uploads/2024/11/image.png"><img loading="lazy" decoding="async" width="1024" height="637" src="/wp-content/uploads/2024/11/image-1024x637.png" alt="" class="wp-image-21416" srcset="https://www.smalsresearch.be/wp-content/uploads/2024/11/image-1024x637.png 1024w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-300x187.png 300w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image-768x478.png 768w, https://www.smalsresearch.be/wp-content/uploads/2024/11/image.png 1300w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Exemple de pipeline simple généré en Python avec la bibliothèque open-source d’Unstructured</figcaption></figure>



<h1 class="wp-block-heading">Conclusions</h1>



<p>L’ingestion de données est une étape critique dans la construction d’une application basée sur l’IA générative car comme le dit l’adage, « garbage in, garbage out ». L’article ci-dessus présente quelques techniques et bonnes pratiques d’ingestion de données ; cependant, chaque cas d’application a ses spécificités et ses difficultés qui dépendent largement du domaine d’application de la solution. C’est pourquoi, l’élaboration d’une stratégie d’ingestion de données doit être le résultat d’une collaboration étroite entre un expert technique et un spécialiste du domaine.</p>


]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Unstructured &#8211; Outil d&#8217;ingestion de données</title>
		<link>https://www.smalsresearch.be/unstructured-outil-dingestion-de-donnees/</link>
		
		<dc:creator><![CDATA[Katy Fokou]]></dc:creator>
		<pubDate>Tue, 15 Oct 2024 09:50:09 +0000</pubDate>
				<category><![CDATA[[FR]]]></category>
		<category><![CDATA[Quick reviews]]></category>
		<category><![CDATA[Artificial intelligence]]></category>
		<category><![CDATA[data ingestion]]></category>
		<category><![CDATA[Large Language Model]]></category>
		<guid isPermaLink="false">https://www.smalsresearch.be/unstructured-outil-dingestion-de-donnees/</guid>

					<description><![CDATA[Unstructured est un outil d&#8217;ingestion de documents pour le développement d&#8217;applications basées sur les grands modèles de langue (LLM) telles que les applications de type RAG. L&#8217;outil est disponible comme plateforme payante no-code, sous forme d&#8217;API payant ou comme package Python open-source. Unstructured is een documentinvoertool voor de ontwikkeling van applicaties gebaseerd op grote taalmodellen [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Unstructured est un outil d&#8217;ingestion de documents pour le développement d&#8217;applications basées sur les grands modèles de langue (LLM) telles que les applications de type RAG. L&#8217;outil est disponible comme plateforme payante no-code, sous forme d&#8217;API payant ou comme package Python open-source.</p>




<p>Unstructured is een documentinvoertool voor de ontwikkeling van applicaties gebaseerd op grote taalmodellen (LLM) zoals RAG-toepassingen. De tool is beschikbaar als een betalend no-code platform, als betalende API of als open-source Python library.</p>







            <div data-wp-interactive="core/file" class="wp-block-file">
                <object data-wp-bind--hidden="!state.hasPdfPreview" hidden class="wp-block-file__embed" data="https://www.smalsresearch.be/wp-content/uploads/2024/10/QR-Unstructured.pdf" type="application/pdf" style="width:100%;height:600px" aria-label="Embed of QR-Unstructured."></object>
                <a id="wp-block-file--media-43b8f09f-c864-4077-98fa-689ba447f515" href="https://www.smalsresearch.be/wp-content/uploads/2024/10/QR-Unstructured.pdf">QR-Unstructured</a><a href="https://www.smalsresearch.be/wp-content/uploads/2024/10/QR-Unstructured.pdf" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-43b8f09f-c864-4077-98fa-689ba447f515">Download</a>
                </div>
            ]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
