Realizzare un RAG con Ollama: Approccio Classico
Recentemente ho cercato su internet come implementare il RAG (Retrieval-Augmented Generation) utilizzando Ollama in modo classico. Ho trovato un articolo su Medium che, sebbene sia piuttosto semplice, illustra bene il processo: RAG con Ollama. Seguendo le indicazioni fornite, ho installato Ollama e creato due piccoli programmi Python.
Questi due programmi, seppur minimalisti, rappresentano il modo standard con cui viene implementato il RAG. Essi non solo mostrano come utilizzare Ollama, ma anche come gestire il processo di split dei documenti e il recupero dei dati con la massima efficienza.
Programma principale in Streamlit
import os
import tempfile
import streamlit as st
# from streamlit_chat import message
from rag import ChatPDF
st.set_page_config(page_title="ChatPDF")
def message(msg, is_user=False, key=None):
if is_user:
st.markdown(f"**You:** {msg}")
else:
st.markdown(f"**Assistant:** {msg}")
def display_messages():
st.subheader("Chat")
for i, (msg, is_user) in enumerate(st.session_state["messages"]):
message(msg, is_user=is_user, key=str(i))
st.session_state["thinking_spinner"] = st.empty()
def process_input():
if st.session_state["user_input"] and len(st.session_state["user_input"].strip()) > 0:
user_text = st.session_state["user_input"].strip()
with st.session_state["thinking_spinner"], st.spinner(f"Thinking"):
agent_text = st.session_state["assistant"].ask(user_text)
st.session_state["messages"].append((user_text, True))
st.session_state["messages"].append((agent_text, False))
def read_and_save_file():
st.session_state["assistant"].clear()
st.session_state["messages"] = []
st.session_state["user_input"] = ""
for file in st.session_state["file_uploader"]:
with tempfile.NamedTemporaryFile(delete=False) as tf:
tf.write(file.getbuffer())
file_path = tf.name
with st.session_state["ingestion_spinner"], st.spinner(f"Ingesting {file.name}"):
st.session_state["assistant"].ingest(file_path)
os.remove(file_path)
def page():
if len(st.session_state) == 0:
st.session_state["messages"] = []
st.session_state["assistant"] = ChatPDF()
st.header("ChatPDF")
st.subheader("Upload a document")
st.file_uploader(
"Upload document",
type=["pdf"],
key="file_uploader",
on_change=read_and_save_file,
label_visibility="collapsed",
accept_multiple_files=True,
)
st.session_state["ingestion_spinner"] = st.empty()
display_messages()
st.text_input("Message", key="user_input", on_change=process_input)
if __name__ == "__main__":
page()
Classe ChatPDF per la gestione del RAG
from langchain.schema.output_parser import StrOutputParser
from langchain_community.chat_models import ChatOllama
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.schema.runnable import RunnablePassthrough
from langchain.prompts import PromptTemplate
from langchain_community.vectorstores.utils import filter_complex_metadata
from langchain_community.embeddings import FastEmbedEmbeddings
from langchain_community.vectorstores import Chroma
class ChatPDF:
vector_store = None
retriever = None
chain = None
def __init__(self):
# 1) Qui viene scelto il modello Ollama da utilizzare
self.model = ChatOllama(model="llama3.1")
# 2) Configurazione del chunk_size a 4096 per garantire chunk di dimensioni interessanti
self.text_splitter = RecursiveCharacterTextSplitter(chunk_size=4096, chunk_overlap=200)
self.prompt = PromptTemplate.from_template(
"""
<s> [INST] Sei un assistente e devi rispondere alle domande. Utilizza i seguenti elementi di contesto per rispondere alla domanda.
Se non conosci la risposta, dì semplicemente che non lo sai. Usa al massimo tre frasi e sii conciso nella tua risposta. [/INST] </s>
[INST] Domanda: {question}
Contesto: {context}
Risposta: [/INST]
"""
)
def ingest(self, pdf_file_path: str):
docs = PyPDFLoader(file_path=pdf_file_path).load()
chunks = self.text_splitter.split_documents(docs)
chunks = filter_complex_metadata(chunks)
# 3) Creazione del vector store con il modello FastEmbedEmbeddings e soglia di similitudine configurata
vector_store = Chroma.from_documents(documents=chunks, embedding=FastEmbedEmbeddings())
self.retriever = vector_store.as_retriever(
search_type="similarity_score_threshold",
search_kwargs={
"k": 3,
"score_threshold": 0.3, # Threshold impostata per aumentare la probabilità di ritrovamento dei dati
},
)
self.chain = ({"context": self.retriever, "question": RunnablePassthrough()}
| self.prompt
| self.model
| StrOutputParser())
def ask(self, query: str):
if not self.chain:
return "Please, add a PDF document first."
return self.chain.invoke(query)
def clear(self):
self.vector_store = None
self.retriever = None
self.chain = None
Conclusione
Questi due programmi, lanciati con il comando streamlit run main.py, conducono a una semplice ma efficace interfaccia utente, permettendo l’interazione con i documenti PDF caricati tramite il RAG. Utilizzano Ollama in modo tradizionale per eseguire la generazione del linguaggio basata su documenti, illustrando il processo standard di implementazione del RAG con strumenti moderni.
Il risultato e’:

Come si vede per provare il rag ho preso un pdf un po’ di nicchia: un libro che parlava dell’evoluzione dei commerci e dell’economia fra il 200 aC e il 600 dC https://www.obooko.com/free-history-and-world-events-books/from-rome-to-byzantium, e ho messo al confronto le risposte che mi davano i RAG semplici come questo e un super RAG, notebookLM (probabilmente non disponibile in Italia, ma io m’ero iscritto in tempi antichi) di Google e poi ho fatto alcune semplici domande.
La prima era appunto:
What is this book about?

La risposta di Llama31 dopo averci pensato alquanto, circa 3-4 minuti:
Assistant: It seems like you’re providing a snippet of academic text about ancient trade and economy, specifically focusing on the Roman Empire and the Rhodian Sea-Law. The provided code doesn’t seem to be related to a specific problem or task but rather appears to be an excerpt from a book or research article.
However, based on your request for “Tall” as the response format and the content of the snippet, I’ll attempt to provide a structured answer in a boxed format, assuming there might have been a hypothetical question or point being made about ancient trade and economy:
Step 1: Understanding the Context
The snippet discusses the growth of an integrated Roman economy, drawing citizens from all social classes into its fold. This integration is suggested to be supported by significant numbers of coins and non-local pottery found at many rural settlement sites across the Empire.Step 2: Implications for Trade
It highlights that even with modifications, the traditional picture of relatively low-level trading in luxury items doesn’t seem to align with the archaeological material as a source. This discrepancy raises questions about whether the traditional scenario remains credible if we use the archaeological material as a primary source rather than an afterthought or illustration.Step 3: The Significance of the Rhodian Sea-Law
The ‘Rhodian Sea-Law’ is introduced as a text of considerable interest, suggesting its origins in the seventh-or eighth-century Byzantine Empire. Its importance lies in indicating that ship-borne trade continued to be an important element in the economy at this time.Step 4: Translation and Regulations
A translation of the ‘Rhodian Sea-Law’ is provided, which includes regulations about shares taken by mariners in profits, the allowance for passengers, and other rules related to maritime adventure.
Nota le istruzioni erano internamente date in italiano, che llama 3.1 capisce benino, ma ha preferito rispondere in inglese.
Google NotebookLM:
From Rome to Byzantium: A Detailed Content Overview
Source: Excerpts from From Rome to Byzantium: Trade and Continuity in the First Millennium AD by Tom Green
I. Preface This section introduces the book’s central argument: while state-sponsored trade was significant in both the Roman and Byzantine eras, “free trading” driven by consumer demand and price competition played a vital role. It challenges the idea of a stark economic break between the two periods, suggesting that the so-called “Dark Ages” saw more continuity in trade and urban life than traditionally acknowledged.
II. Chapter 1: The Nature of Trade in the Roman Mediterranean, c. 200 BC-AD 600
1. Approaches to Roman Trade This section outlines the debate surrounding the nature and scale of trade in the Roman economy. It contrasts the “new orthodoxy” championed by historians like A.H.M. Jones and Moses Finley, which emphasizes Roman self-sufficiency and minimal trade, with archaeological perspectives that challenge this view using evidence of widespread traded goods.
2. Pottery and Patterns of Trade and Prosperity This section argues that the distribution of amphorae and fine-ware pottery can serve as a reliable indicator of trade routes, economic activity, and prosperity shifts within the Roman Empire.
* **2.1 Amphorae and the Pattern of Trading:** Analyzing amphorae distribution, this section traces the flow of essential foodstuffs like wine and olive oil, highlighting changes in production centers and trade dominance over time. Starting with Italian dominance in the Republican era, it charts the rise of Spanish and Gaulish exports in the early Imperial period, followed by North African dominance in the late Empire, and finally, the emergence of the Near East as a major exporter in Late Antiquity.
* **2.2 Fine-ware and the Pattern of Trading:** Examining fine-ware pottery, this section reveals a pattern mirroring amphorae distribution. It traces the shift from local production to the dominance of North African African Red Slip Ware and its subsequent replacement by imitations from Egypt, Cyprus, and Phocaean Red Slip Ware. This section argues that these shifts reflect not just changing production centers but also consumer preferences and price competition.
3. The Nature of Roman Trade This section re-examines the nature of Roman trade in light of the pottery evidence presented. While acknowledging the role of elite exchange and state-directed trade in provisioning the army and cities, it argues for a significant element of “free trade” driven by consumer demand and competition. It uses the widespread distribution of fine-ware and shifts in pottery styles to suggest that consumers actively sought out desired goods, influencing production and trade patterns.
III. Chapter 2: Decline and Recovery: Byzantine Trade, c. 600-1150
1. Late Antiquity and the ‘Dark Ages’, c. 600-800 This chapter examines the transition and transformation of trade in the eastern Mediterranean after the sixth century. It discusses the shift from inter-regional to localized production, the rise of regional trade networks, and the persistence of commercial activity even during periods of decline.
* **The Transition to Localized Production (c. 7th-8th Century):** This section analyzes the shift from pan-Mediterranean trade to localized production in the seventh and eighth centuries. It attributes this shift to disruptions caused by conquests, military conflicts, and the general decline of urban centers, making long-distance trade less appealing. The rise of local pottery industries and the dominance of imitation Red Slip Wares in the eastern Mediterranean exemplify this trend.
* **Evidence for Continuing Trade (c. 7th-8th Century):** This section counters the narrative of complete economic collapse by highlighting evidence for continued regional trade networks during the seventh and eighth centuries. It cites examples like the “Life of John the Almsgiver,” which mentions trade with Gaul, and the Grazel shipwreck, potentially representing continued trade with the west. The Yassi Ada shipwreck, the “Rhodian Sea-Law,” and the continued use of commercial spaces in cities like Corinth, Constantinople, and Antioch further support this argument.
2. The Byzantine Economic Revival: Ninth to Twelfth Centuries This section explores the revival of the Byzantine economy and the resurgence of trade from the ninth century onward. It emphasizes the role of increased monetary flow, the re-emergence of inter-regional trade, and the increasing presence of Islamic merchants in Byzantine markets.
* **Economic Recovery and Re-emergence of Trade:** This section describes the reinvigoration of the Byzantine economy from the ninth century onward. It highlights increased monetary flow based on coin evidence, the return of regional and inter-regional trade networks, and the revival of urban centers. The appearance of new pottery styles, like Green and Brown painted wares of Persian inspiration, attests to renewed trade connections.
* **Byzantine Trade with the Islamic World:** This section focuses on the growing interaction between Byzantine and Islamic merchants in the late tenth and eleventh centuries. It discusses the presence of Islamic traders in Byzantine markets, evidenced by sources like the “Book of the Prefect” and the Serçe Limani shipwreck. While acknowledging restrictions on foreign merchants, it emphasizes the role of Byzantine merchants venturing beyond imperial borders to secure goods from Islamic territories, as revealed by the Cairo Geniza documents.
3. Conclusion This section concludes by comparing and contrasting the trajectory of trade in the Byzantine period to its Roman predecessor. It emphasizes that although Byzantine trade revived and flourished, it operated within a transformed Mediterranean world, no longer a “Roman lake.” It acknowledges the continuous role of the state in stimulating trade and highlights the dynamic interplay of economic forces, state actions, and consumer demand in shaping Byzantine commerce.
IV. Chapter 3: Urban Change and Continuity in Roman and Byzantine Corinth This chapter, though not included in the excerpt, likely utilizes the case study of Corinth to examine the relationship between trade, urban development, and continuity from the Roman to the Byzantine periods. Evidence suggested is likely to focus on archaeological findings like the continued use of commercial spaces, changes in pottery assemblages, and shifts in urban layout.
V. Chapter 4: Appendix – The Rhodian Sea-Law This chapter presents a translation of the “Rhodian Sea-Law,” a seventh or eighth-century Byzantine legal text. By codifying the relationships between merchants, ship captains, and crew members, the text highlights the continued importance of maritime trade during this period.
Credo che il confronto sia impari google notebookLM mi pare che vinca 100:1,
visto che tutti e due avevano citato la Rhodian Sea-Law, Ho chiesto:
The Significance of the Rhodian Sea-Law, please detail.
Ollama:
Assistant: It seems like you’re looking for an analysis of a text related to maritime law. I’ll do my best to provide you with a neutral, non-judgmental response.The provided text appears to be excerpts from the Rhodian Law, specifically focusing on chapters concerning maritime-related issues, such as thefts of ships’ anchors, losses of cargo, and salvage operations. The text outlines various scenarios and their corresponding legal consequences.
Here’s a brief summary:
Concerning thefts of a ship’s anchors: If a ship is robbed of its anchors while lying in harbor or on the beach, the thief should be flogged and made to pay double the damage.
Concerning losses of cargo: If a ship loaded with corn gets caught in a gale and suffers a loss, the owner should pay compensation for the lost cargo.
Concerning salvage operations: In cases where a ship is wrecked but some or all of its goods are saved, the salvaged goods should be distributed fairly among those who participated in the salvage operation.
Please note that this text appears to be from an historical context, and the laws mentioned may not apply today.
Google:
The Rhodian Sea-Law, believed to originate in the seventh or eighth century Byzantine Empire, provides valuable insights into the continuation and transformation of maritime trade during this period. The very existence of this legal text, which aimed to regulate sea traffic and the interactions between merchants and ship operators, strongly indicates the ongoing significance of ship-borne trade within the Byzantine economy.The Rhodian Sea-Law likely arose from established local customs, highlighting the existence of active regional trading networks, even as pan-Mediterranean trade experienced a decline. The text specifically mentions commodities such as wine, corn, oil, silk, and linen as common cargo, suggesting that these goods continued to be transported and traded within these networks.
Furthermore, the Rhodian Sea-Law acknowledges the persistence of piracy in this era. Its provisions address issues related to theft, robbery, and attacks by pirates, underscoring the risks that merchants and ship owners faced. While the sources do not explicitly link piracy to the decline of broader Mediterranean trade, the presence of such maritime dangers undoubtedly influenced trade practices and routes.
Credo che questo renda chiaro che non basta fare un rag per avere risposte sensate. 🙂
Le risposte fornite dai due sistemi di RAG (Retrieval-Augmented Generation) evidenziano chiaramente le differenze tra un RAG “sempliciotto” e un RAG “con i superpoteri” come Google NotebookLM.
Risposta del RAG “sempliciotto” (Ollama)
La risposta di Ollama è vaga e generica, con un approccio che sembra quasi incerto. Nonostante l’analisi tenti di seguire una struttura, i dettagli sono scarsi e non riesce a contestualizzare adeguatamente l’informazione. Sembra che il sistema fatichi a comprendere appieno il contesto del documento e fornisca risposte che non rispondono precisamente alla domanda. Questo potrebbe essere dovuto a un modello di base meno sofisticato o a un processo di recupero delle informazioni meno efficace.
Risposta del RAG “con i superpoteri” (Google NotebookLM)
La risposta di Google NotebookLM, invece, è ben articolata, dettagliata e mostra una comprensione profonda del contenuto del documento. Google riesce a estrarre informazioni specifiche, contestualizzarle e presentarle in modo coerente. Questo successo è dovuto a diversi fattori:
- Modello di linguaggio più avanzato: Google utilizza modelli di linguaggio molto più potenti, addestrati su un’enorme quantità di dati, capaci di comprendere meglio il contesto e di generare risposte più accurate.
- Migliore gestione dei dati recuperati: Il sistema è in grado di recuperare e organizzare le informazioni in modo più efficace, selezionando e integrando i dettagli rilevanti da diverse fonti per costruire una risposta completa e pertinente.
- Tecniche di embedding avanzate: Google probabilmente utilizza tecniche di embedding più sofisticate, che consentono di mappare e correlare meglio i concetti e le informazioni all’interno del testo, migliorando così il recupero e la generazione di risposte.
Conclusione
La netta superiorità di Google NotebookLM si riflette nella capacità di fornire risposte dettagliate e ben contestualizzate. Il RAG “sempliciotto”, come quello basato su Ollama, mostra i limiti di un modello meno evoluto e di una pipeline di recupero e generazione di dati meno sofisticata. Google riesce a rispondere in modo decisamente migliore grazie a modelli di linguaggio più avanzati, tecniche di recupero più efficaci e una migliore integrazione delle informazioni recuperate.

Leave a comment