Poate fi folosit un model SLM precum Llama 3.2 pentru extragerea datelor din diferite documente, păstrând totodată un nivel ridicat al calității rezultatelor?
În acest articol vom demonstra că prin utilizarea unor tehnici RAG adecvate chiar și modelele LLM sunt suficiente pentru a prelucra documente voluminoase.
1. De la metode clasice la inteligența artificială RAG
În era digitală, accesul rapid și eficient la informații a devenit crucial. Deși căutarea clasică în documente a fost multă vreme standardul, apariția tehnologiilor bazate pe inteligență artificială, în special Retrieval-Augmented Generation (RAG), marchează o schimbare de paradigmă în modul în care interacționăm cu vastele cantități de date disponibile. Acest articol explorează diferențele fundamentale dintre aceste două abordări și evidențiază avantajele semnificative ale RAG.
Căutarea clasică în documente
Metodele tradiționale de căutare se bazează în principal pe potrivirea cuvintelor cheie și pe indexare. Aceste sisteme caută corespondențe exacte sau aproximative între termenii de căutare și conținutul documentelor. Deși eficiente pentru căutări simple, aceste metode prezintă mai multe limitări:
- Sensibilitate la formulare: rezultatele depind foarte mult de modul în care utilizatorul formulează interogarea.
- Lipsă de context: nu pot înțelege nuanțele sau contextul mai larg al întrebării.
- Rigiditate: dificultăți în interpretarea sinonimelor sau a conceptelor conexe.
- Volum mare de rezultate: pot returna un număr copleșitor de rezultate, lăsând utilizatorul să filtreze manual informațiile relevante.
- Incapacitate de sinteză: nu pot combina informații din surse multiple pentru a oferi un răspuns cuprinzător.
Căutarea bazată pe RAG
RAG (Retrieval-Augmented Generation) reprezintă o abordare revoluționară care combină puterea modelelor de limbaj mari (LLM) cu sisteme avansate de recuperare a informațiilor. Această tehnologie oferă numeroase avantaje față de metodele clasice:
- Înțelegere contextuală superioară: RAG poate interpreta întrebările utilizatorilor în context, înțelegând nu doar cuvintele cheie, ci și intenția din spatele întrebării. Aceasta permite formulări mai naturale și mai complexe ale interogărilor.
- Sinteză inteligentă a informațiilor: În loc să returneze simplu documente, RAG poate combina informații din multiple surse pentru a genera răspunsuri coerente și cuprinzătoare. Acest lucru economisește timp utilizatorului și oferă o perspectivă mai completă asupra subiectului.
- Adaptabilitate la diverse formate de date: RAG poate procesa și integra informații din diverse formate, inclusiv text, tabele și, în unele implementări, chiar și imagini sau video, oferind o perspectivă multi-modală asupra subiectului căutat.
- Gestionarea ambiguității și a nuanțelor: Sistemele RAG pot naviga prin ambiguități lingvistice și conceptuale, oferind răspunsuri nuanțate care iau în considerare multiple interpretări posibile ale întrebării.
- Actualizare continuă a cunoștințelor: Spre deosebire de sistemele clasice care necesită reindexare frecventă, RAG poate integra rapid noi informații în baza sa de cunoștințe, menținând rezultatele la zi.
- Personalizare și învățare: RAG poate învăța din interacțiunile anterioare pentru a oferi rezultate mai relevante și personalizate în timp, adaptându-se la nevoile și preferințele specifice ale utilizatorilor.
- Reducerea supraîncărcării informaționale: Prin furnizarea de răspunsuri concise și relevante, RAG reduce semnificativ timpul petrecut de utilizatori pentru a găsi și sintetiza informațiile necesare.
- Capacități de raționament și inferență: RAG nu se limitează doar la recuperarea informațiilor, ci poate face și inferențe logice, oferind insights și conexiuni care ar putea fi mai greu de observat pentru un utilizator uman.
- Multilingvism și traducere integrată: Sistemele RAG avansate pot opera eficient în multiple limbi, oferind traduceri și înțelegere cross-lingvistică, extinzând astfel accesul la informații globale.
- Îmbunătățirea experienței utilizatorului: Prin oferirea de răspunsuri directe și relevante, RAG transformă procesul de căutare într-o experiență mai naturală și mai satisfăcătoare pentru utilizator.
În ciuda avantajelor sale semnificative, implementarea RAG vine și cu provocări:
- Costuri computaționale: Procesarea RAG poate fi mai intensivă din punct de vedere al resurselor comparativ cu căutarea clasică.
- Confidențialitatea datelor: Utilizarea AI ridică întrebări legate de protecția datelor și securitatea informațiilor sensitive.
- Acuratețe și verificabilitate: Este crucial să se asigure că răspunsurile generate sunt precise și verificabile.
2. Utilizarea modelelor SLM locale pentru îmbunătățirea rezultatelor căutărilor
Prin folosirea unui model LLM de capacitate mare, vom putea avea rezultate bune, dar desigur vom avea și costuri pe măsură. Apare firesc întrebarea cum putem micșora aceste costuri și totodată păstra precizia, dar și confidențialitatea datelor.
Răspunsul este firesc: prin folosirea modelelor SLM, instalate local, care folosesc resurse puține, iar Llama 3.2. este una dintre cele mai bune soluții.
Llama 3.2 (furnizat de MetaAI) poate fi instalat pe un calculator cu o placă grafică nepretențioasă, poate rula chiar și doar prin CPU și este disponibil gratuit prin Ollama sau pe platforma HuggingFace.
Unul din avantajele folosirii Llama 3.2 este faptul că toată procesarea are loc pe calculatorul personal sau în rețeaua organizației, astfel încât confidențialitatea datelor este protejată.
Totuși Llama 3.2 este un model mic (3 miliarde de parametri – aproximativ 8 GB) și e posibil să nu se descurce la fel de bine ca un model LLM mare. Desigur Llama 3.2 nu este singura variantă posibilă. Putem utiliza și alte SLM-uri precum Phi 3.5 sau Qwen 2.5 cu același nivel ridicat al preciziei.
Din acest motiv putem folosi mici artificii care îmbunătățesc semnificativ calitatea rezultatelor.
2.1. Stabilirea strategiei necesare pentru extragerea datelor
Tradițional extragerea datelor decurge în felul următor:
- textul este citit și vectorizat;
- utilizatorul formulează o întrebare care este tokenizată;
- modelul LLM caută potrivirile cele mai bune în tokenii textului original și returnează cel mai probabil răspuns.
Pentru un model mic precum Llama 3.2 putem să identificăm imediat câteva probleme:
- pierderea contextului care face ca răspunsul să nu fie neapărat cel dorit;
- procesare intensă pentru că pentru un răspuns se face o căutare în tot documentul.
De aici, reiese o primă idee: oare cum ar fi dacă am segmenta documentul inițial în mai multe bucăți și am limita căutarea în interiorul segmentului care conține răspunsul?
Desigur ar trebui să știm prima dată ce conține fiecare bucată a documentului.
Prin urmare am putea să stabilim următoarea strategie:
- împărțim documentul în mai multe bucâți;
- folosim Llama 3.2 pentru a face un rezumat al fiecărei bucâți, a extrage cuvintele cheie esențiale;
- la întrebarea utilizatorului vom pune Llama 3.2 să identifice care este bucata de text cea mai probabilă care conține informația căutată;
- după identificarea acesteia vom pune Llama 3.2 să răspundă la întrebarea respectivă furnizând ca și context doar bucata de document respectivă.
Această strategie presupune o prelucrare inițială mai complexă, dar totodată pe conținut mai mic, ceea ce nu ar ridica probleme unui SLM mic.
2.2. Împlementarea codului RAG
Pentru a implementa strategia stabilită la punctul anterior vom folosi un model Llama 3.2 instruct instalat local pe care îl vom accesa prin serverul Ollama și un alt model tot local, Mxbai embed large care se va ocupa de tokenizarea informației.
Codul python va citi mai întai documentul (un document PDF în limba engleză de 34 de pagini) pe care îl va segmenta la nivel de pagină.
Apoi pentru fiecare pagină Llama 3.2 va face un rezumat, va stabili cuvintele cheie și va tokeniza rezultatul.
Informația prelucrată va fi salvată într-o bază de date locală.
În partea a doua, având deja aceaste date în baza de date, Llama 3.2 va prelucra întrebările utilizatorului, va identifica numărul paginii care conține răspunsul la întrebare și apoi va formula un răspuns doar din acea pagină.
Așadar pentru prima parte a prelucrării putem folosi codul următor:
import pandas as pd
import pymupdf
import lancedb
import json
import pyarrow as pa
import numpy as np
import re
from openai import OpenAI
def seteaza_prompt(question):
"""
Create a prompt as per LLAMA 3.2 format.
"""
system_message = "You are a helpful assistant for summarizing text and result in JSON format"
prompt_template = f'''
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
{system_message}<|eot_id|><|start_header_id|>user<|end_header_id|>
{question}<|eot_id|><|start_header_id|>AsistentLlama<|end_header_id|>
'''
return prompt_template
def proceseaza_prompt(prompt, client):
"""
Processes a prompt, generates a response, and extracts the assistant's reply.
"""
response = client.chat.completions.create(
model="llama3.2:3b-instruct-fp16",
messages=[
{"role": "user", "content": prompt}
],
temperature=0.1,
max_tokens=300,
)
return response.choices[0].message.content
def incarcare_document(file_path):
dict_pages = {}
# se citeste fisierul PDF
with pymupdf.open(file_path) as pdf_document:
for page_number in range(pdf_document.page_count):
page = pdf_document.load_page(page_number)
page_text = page.get_text()
dict_pages[page_number] = page_text
print(f"Processed PDF page {page_number + 1}")
return dict_pages
def prelucrare_pdf(table, filepath , client):
# incarcam documentul PDF
dict_pages = incarcare_document(filepath)
# pentru fiecare pagina din document utilizam Llama 3.2 pentru a face un rezumat si a scoate cuvintele cheie din text
for page_number, text in dict_pages.items():
question = f"""For the given passage, provide a long summary about it, incorporating all the main keywords in the passage.
Format should be in JSON format like below:
{{
"summary": <text summary> example "Some Summary text",
"keywords": <a comma separated list of main keywords and acronyms that appear in the passage> example ["keyword1","keyword2"],
}}
Make sure that JSON fields have double quotes, e.g., instead of 'summary' use "summary", and use the closing and ending delimiters.
Passage: {text}"""
# generam un prompt pentru Llama 3.2
prompt = seteaza_prompt(question)
# procesam pagina cu Llama 3.2 si instructiunile date
response = proceseaza_prompt(prompt,client)
try:
summary_json = json.loads(response)
except json.decoder.JSONDecodeError as e:
exception_msg = str(e)
# daca raspunsul nu e in formatul asteptat atunci incercam reformatarea lui
question = f"""Correct the following JSON {response} which has {exception_msg} to proper JSON format. Output only the corrected JSON.
Format should be in JSON format like below:
{{
"summary": <text summary> example "Some Summary text",
"keywords": <a comma separated list of keywords and acronyms that appear in the passage> example ["keyword1","keyword2"],
}}"""
# generam noul prompt
prompt = seteaza_prompt(question)
# reprocesam pagina cu Llama 3.2 si instructiunile date
response = proceseaza_prompt(prompt, client)
# Try parsing the corrected JSON
try:
summary_json = json.loads(response)
except json.decoder.JSONDecodeError as e:
continue
# se seteaza cuvintele cheie
keywords = ', '.join(summary_json['keywords'])
# folosim Ollama pentru a genera un embending pentru sumar si keywords
response = client.embeddings.create(model="mxbai-embed-large:latest", input=summary_json['summary'])
vectorS = response.data[0].embedding
response = client.embeddings.create(model="mxbai-embed-large:latest", input=keywords)
vecctorK = response.data[0].embedding
# se salveaza informatia in baza de date
table.add([{
"page_number": int(page_number),
"original_content": text,
"summary": summary_json['summary'],
"keywords": keywords
#"vectorS": vectorS,
#"vectorK": vecctorK
}])
def generare_tabela(db):
# se seteaza tabela db
table = db.create_table('summaries', schema=schema, mode='overwrite')
return table
# conectare la LanceDB
db = lancedb.connect('./my_db')
# se defineste schema bazei de date
schema = pa.schema([
pa.field("page_number", pa.int64()),
pa.field("original_content", pa.string()),
pa.field("summary", pa.string()),
pa.field("keywords", pa.string()),
pa.field("vectorS", pa.list_(pa.float32())),
pa.field("vectorK", pa.list_(pa.float32()))
])
# se seteaza clientul Ollama
client = OpenAI(
base_url = 'http://produseonline.go.ro:11434/v1',
api_key='ollama', # required, but unused
)
# setam documentul care urmeaza sa fie prelucrat
filepath = "./gdpr.pdf"
# pregatim baza de date
table = generare_tabela(db)
# se face pre procesarea textului
prelucrare_pdf(table, filepath, client)
Folosim câteva funcții importante:
- seteza_prompt stabilește felul cum arată promptul folosit când utilizăm model Llama 3.2;
- proceseaza_prompt lansează în execuție modelul Llama folosind promptul utilizatorului;
- incarcare_document prelucreaza documentul PDF si il returneaza in format text;
- generare_tabela seteaza baza de date care va fi utilizată pentru procesarea datelor;
- prelucrare_pdf face preprocesarea propriu-zisă: pentru fiecare pagină stabilește promptul, rulează procesarea și salvează datele în tabelă.
După acest prim pas avem în baza de date toate informațiile necesare pentru a putea să purtăm o conversație cu documentul prin intermediul modelului Llama 3.2.
Vom folosi următorul cod python:
import pandas as pd
import pymupdf
import lancedb
import json
import pyarrow as pa
import numpy as np
import re
from openai import OpenAI
def proceseaza_prompt(prompt, client):
"""
Processes a prompt, generates a response, and extracts the assistant's reply.
"""
response = client.chat.completions.create(
model="llama3.2:3b-instruct-fp16",
messages=[
{"role": "user", "content": prompt}
],
temperature=0.1,
max_tokens=700,
)
answer = response.choices[0].message.content
return response.choices[0].message.content
def incarcare_date(db, schema):
# Read the table from a Parquet file
table = db['summaries']
# Convert the table to a PyArrow table
arrow_table = table.to_arrow()
# Print the schema
#print("Schema:", arrow_table.schema)
# Convert the table to a dictionary for easier access
data = arrow_table.to_pydict()
# Print the data
##for key, values in data.items():
#print(f"{key}: {values}")
return data
# Connect to LanceDB
db = lancedb.connect('./my_db')
# Define the schema using PyArrow
schema = pa.schema([
pa.field("page_number", pa.int64()),
pa.field("original_content", pa.string()),
pa.field("summary", pa.string()),
pa.field("keywords", pa.string())
#pa.field("vectorS", pa.list_(pa.float32())), # Embedding size of 384
#pa.field("vectorK", pa.list_(pa.float32())),
])
client = OpenAI(
base_url = 'http://produseonline.go.ro:11434/v1',
api_key='ollama', # required, but unused
)
user_question = " what is the understanding of transfer for EDPB?"
# setam datele din baza de date
data = incarcare_date(db, schema)
# se seteaza sumarul informatiilor
summary_list = []
for idx, result in enumerate(data['summary']):
summary_list.append(f"{data['page_number'][idx]}# {result}")
question = f"""You receive a list of summaries in the format page number #summary. From the given list of summaries {summary_list}, rank which summary would possibly have \
the answer to the question '{user_question}'. Return only that number of the choosen summary from the list, without anything else."""
pagina_cea_mai_probabila = proceseaza_prompt(question,client)
#citim continutul pagini respective
context = data['summary'][int(pagina_cea_mai_probabila)]
question = f"""You are a helpful assistant that will go through the given query and context, think in steps, and then try to answer the query \
with the information in the context. Can you answer the query: '{user_question}' \
using the context below?
Context: '{context}'
"""
raspuns = proceseaza_prompt(question,client)
print(raspuns)
Codul parcurge următorii pași:
- încarcă datele preprocesate din baza de date într-o listă;
- folosește Llama 3.2 pentru a vedea care rezumat din listă este cel mai potrivit pentru a răspunde la întrebarea utilizatorului;
- stabilește numărul paginii care este cea mai potrivită;
- folosește Llama 3.2 pentru a găsi răspunsul la conținutul paginii identificate;
- în final returnează răspunsul la întrebare.
Pentru exemplul de față am folosit un ghid EDPB în format PDF care analizează diferite aspecte legale ale prelucrărilor de date cu caracter personal, iar termenii utilizați sunt de o complexitate ridicată.
Modelul dă următorul răspuns:
To answer the query "what is the understanding of transfer for EDPB" based on the given context, I'll break down the steps:
1. The context mentions the European Data Protection Board (EDPB) discussing Article 46(3)(a) GDPR and its implications on data processing contracts.
2. Specifically, it addresses laws of third countries requiring processors to process personal data without the controller's instructions, under certain conditions.
3. In such cases, the EDPB clarifies that processors must implement supplementary measures to ensure GDPR compliance.
From this information, we can infer that the understanding of "transfer" in this context refers to the transfer of personal data from the EU to a third country, where laws may require processing without the controller's instructions.
4. The EDPB emphasizes that this transfer is subject to specific conditions and requires supplementary measures to ensure GDPR compliance.
Therefore, based on the given context, the understanding of "transfer" for the EDPB seems to relate to the transfer of personal data outside the EU, where laws may require processing without the controller's instructions, and the need for supplementary measures to ensure GDPR compliance.
Este un răspuns corect și este remarcabil că procesarea a fost aproape instantă. Pre procesarea a 34 de pagini a durat doar câteva secunde.
Llama 3.2 nu a făcut o căutare după un termen exact, ci a înteles sensul întrebării și a identifcat cel mai posibil răspuns din document, iar apoi a dat și o interpretare și contextualizare a răspunsului.
3. Concluzii
Atunci când lucrăm cu multe documente este evident că avem nevoie de asistență și automatizări pentru a putea lua decizii precise și în cunoștință de cauză în cel mai scurt timp.
De exemplu, un ghid de accesare a fondurilor europene poate să fie întins pe sute de pagini și este destul de greu de înteles pentru cititorii obișnuiți. Avem cu siguranță suficiente întrebări dar o căutare după temeni exacți s-ar putea ori să aducă prea multe răspunsuri, ori să nu aducă nici un rezultat.
Astfel, folosirea unui asistent cu inteligență artificială care să poată face căutarea contextualizată e o adevărată binecuvântare.
Iar Llama 3.2 este și rapid și precis și sigur și mai ales… gratuit.