Aggiungi Memoria al Tuo Agente Weaviate: Un Tutorial Pratico di 2500 Parole
Se vuoi che il tuo agente intelligente ricordi effettivamente il contesto tra le conversazioni, devi weaviate add memory to your agent nel modo giusto, utilizzando la ricerca vettoriale per memorizzare e richiamare interazioni precedenti. Non stiamo semplicemente inserendo frammenti in un database; stiamo costruendo un vero e proprio grafo della conoscenza arricchito con ricerca semantica che mantiene il tuo agente sempre pronto.
Cosa Stai Costruendo e Perché È Importante
Stiamo costruendo un agente che utilizza Weaviate per la memorizzazione della memoria in modo che possa avere conversazioni significative, non solo domande e risposte senza stato. Dimentica quelle dimostrazioni superficiali di chatbot che resettano ogni domanda: si tratta di persistenza contestuale che i tuoi utenti sentiranno davvero.
Prerequisiti
- Python 3.11+
- Weaviate Community Edition (ultima versione stabile, io ho usato 1.19.0)
- Pacchetti Pip:
weaviate-client>=4.16.0,requests,dotenv - Chiave API di OpenAI o qualsiasi altra chiave API di modello di embedding (GPT-4, Cohere, o Huggingface)
- Docker installato (opzionale ma raccomandato per eseguire Weaviate localmente)
- Comprensione di base dei database vettoriali e della generazione di embedding
Statistiche Veloci su Weaviate
| Metrica | Valore |
|---|---|
| Stelle GitHub | 15.839 |
| Forks | 1.227 |
| Issue Aperte | 582 (al 20 marzo 2026) |
| Licenza | BSD-3-Clause |
| Ultimo Aggiornamento | 20 marzo 2026 |
Questi numeri mostrano che Weaviate è maturo ma ancora attivo; non sarai bloccato ad aspettare qualche libreria abbandonata.
Passo-Passo: Aggiungi Memoria al Tuo Agente Weaviate
Passo 1: Imposta il Server Weaviate
# Esegui Weaviate con Docker per test rapidi in locale
docker run -d \
-p 8080:8080 \
-e AUTH_ANONYMOUS_ACCESS_ENABLED=true \
-e QUERY_DEFAULTS_LIMIT=20 \
-e PERSISTENCE_DATA_PATH=/var/lib/weaviate \
-v $(pwd)/weaviate_data:/var/lib/weaviate \
semitechnologies/weaviate:latest
Perché è importante: Weaviate supporta la persistenza e l’accesso anonimo abilitato di default qui, rendendo facile lo sviluppo locale. Impostare QUERY_DEFAULTS_LIMIT=20 evita di imbattersi nei fastidiosi limiti di 10 risultati per le query, che infastidiscono anche gli sviluppatori esperti. Ricorda, se non vuoi accesso anonimo, imposta le chiavi API. Ma per il testing, va bene così.
Errori comuni: Se il contenitore si arresta in modo anomalo, verifica che la porta 8080 sia libera. A volte Docker Desktop o contenitori precedenti la occupano. Inoltre, se invii embedding più velocemente di quanto la persistenza di Weaviate possa gestire (cosa rara in locale), aspettati un ritardo.
Passo 2: Definisci uno Schema per la Memoria del Tuo Agente
import weaviate
client = weaviate.Client("http://localhost:8080")
schema = {
"classes": [
{
"class": "MemoryEntry",
"description": "Memorizza un singolo segmento di memoria per l'agente",
"properties": [
{
"name": "text",
"dataType": ["text"],
"description": "Il contenuto testuale della memoria."
},
{
"name": "embedding",
"dataType": ["number[]"],
"description": "Rappresentazione vettoriale dell'embedding."
},
{
"name": "timestamp",
"dataType": ["date"],
"description": "Quando è stata memorizzata la memoria."
}
],
"vectorizer": "none" # Inietteremo gli embedding noi stessi
}
]
}
client.schema.delete_all() # Pulisci completamente
client.schema.create(schema)
Perché nessun vettorizzatore? Il principale errore che commettono i principianti è utilizzare ciecamente i vettorizzatori di testo predefiniti di Weaviate. Va bene per la ricerca testuale semplice, ma quando vuoi un controllo stretto sul tuo modello di embedding (ad esempio, OpenAI, Cohere), devi caricare i vettori tu stesso. Questo elimina la confusione di tutorial concorrenti che abusano dei vettorizzatori predefiniti di Weaviate per gli agenti.
Eliminare lo schema prima di creare costringe a un nuovo inizio, il che ti salva da strani errori di “schema già esistente”. Certo, cancella i dati, ma questo è sviluppo locale.
Passo 3: Genera e Carica gli Embedding della Memoria
import os
import requests
from datetime import datetime
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
def get_openai_embedding(text):
resp = requests.post(
"https://api.openai.com/v1/embeddings",
headers={"Authorization": f"Bearer {OPENAI_API_KEY}"},
json={"input": text, "model": "text-embedding-ada-002"}
)
resp.raise_for_status()
return resp.json()["data"][0]["embedding"]
def add_memory_entry(client, text):
embedding = get_openai_embedding(text)
memory_obj = {
"text": text,
"embedding": embedding,
"timestamp": datetime.utcnow().isoformat()
}
client.data_object.create(memory_obj, "MemoryEntry", vector=embedding)
# Esempio di utilizzo
add_memory_entry(client, "Ricordo che il cielo è blu.")
add_memory_entry(client, "Il significato della vita è 42.")
Perché generare gli embedding tu stesso? Perché è incredibilmente prezioso separare la generazione degli embedding e la memorizzazione dei vettori. Potresti avere bisogno di cambiare il tuo modello di embedding in seguito o di aggregare vettori da diverse fonti. Altri tutorial mescolano tutto e finisci per essere bloccato.
Errore comune qui: dimenticare di passare l’embedding come parametro vettore vector=embedding nella chiamata data_object.create. Se lo salti, Weaviate cercherà di vettorializzarlo automaticamente (e fallirà perché abbiamo impostato vectorizer: none).
Passo 4: Interroga la Memoria con Ricerca Semantica
def query_memory(client, question, top_k=3):
question_embedding = get_openai_embedding(question)
near_vector = {"vector": question_embedding}
response = client.query.get("MemoryEntry", ["text", "timestamp"])\
.with_near_vector(near_vector)\
.with_limit(top_k)\
.do()
results = response.get("data", {}).get("Get", {}).get("MemoryEntry", [])
return results
# Testalo
results = query_memory(client, "Di che colore è il cielo?")
for res in results:
print(f"Memoria: {res['text']} (memorizzato il {res['timestamp']})")
Perché la ricerca semantica? La ricerca per parole chiave nella memoria è inutile per gli agenti che devono gestire conversazioni multi-turno con query sfumate. La vera magia è la ricerca di embedding per “pensieri simili” senza sovrapposizione esatta di parole chiave.
La funzione chiave è come mescoli e abbini queste query dinamicamente durante il runtime per mantenere il tuo agente consapevole del contesto senza soffocare su memorie irrilevanti.
Passo 5: Collega il Tuo Agente per Usare la Memoria di Weaviate
class MemoryAgent:
def __init__(self, weaviate_client):
self.client = weaviate_client
def remember(self, text):
add_memory_entry(self.client, text)
def recall(self, question):
return query_memory(self.client, question, top_k=5)
def chat(self, question):
memories = self.recall(question)
# Semplice concatenazione per il prompt—sostituisci con il tuo modello di prompt
prompt_context = "\n".join([m["text"] for m in memories])
prompt = f"Contesto:\n{prompt_context}\n\nDomanda: {question}\nRisposta:"
# Invia il prompt al LLM (non coperto qui)
# Simulazione:
return f"Risposta simulata basata sulle memorie:\n{prompt}"
agent = MemoryAgent(client)
agent.remember("L'agente è stato creato il 20 marzo 2026.")
agent.remember("Python è il linguaggio di programmazione riconosciuto per l'IA.")
print(agent.chat("Quando è stato creato l'agente?"))
Perché questo design? Separare la gestione della memoria dalla logica di “chat” dell’agente è cruciale. Odio il codice strettamente accoppiato dove gestire il contesto rende la tua chiamata di generazione un pasticcio annidato. Con questo schema, puoi tracciare, memorizzare e richiamare in modo indipendente. Se desideri sostituire un LLM migliore o aggiungere caching, è un gioco da ragazzi.
Le Insidie di Cui Non Sentirai Parlare Negli Altri Tutorial
- Confusione dello schema. Molti tutorial trascurano il design dello schema, ma se il tuo schema è errato, i tuoi vettori e i metadati saranno spazzatura. Ti pentirai di non aver pianificato i timestamp o metadati come gli ID utente per filtrare la tua memoria.
- I costi degli embedding contano. Gli embedding di OpenAI non sono gratuiti. Se aggiungi migliaia di memorie, aspettati una fattura. Batch la tua generazione per tagliare i costi e memorizza gli embedding in modo aggressivo.
- Il gonfiore della memoria uccide le prestazioni. Interrogare un DB vettoriale con decine di migliaia di voci? Vedrai picchi di latenza e risultati di richiamo rumorosi. È necessaria una potatura regolare—una realtà dura ma inevitabile.
- Disallineamenti delle dimensioni del vettore. Se scambi accidentalmente modelli o versioni di embedding, i tuoi vettori memorizzati non corrisponderanno ai vettori di query. Otterrai zero risultati o corrispondenze fuorvianti. Fissa sempre la versione del tuo modello di embedding nel tuo pipeline.
- La coerenza dei dati è un dolore. Senza supporto per le transazioni, scritture o aggiornamenti parziali possono lasciare memorie sospese senza contesto. Questo sottile bug può perseguitarti in produzione, specialmente se stai aggiornando memorie.
Esempio Completo Funzionante
import os
import requests
from datetime import datetime
import weaviate
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
WEAVIATE_URL = "http://localhost:8080"
def get_openai_embedding(text):
r = requests.post(
"https://api.openai.com/v1/embeddings",
headers={"Authorization": f"Bearer {OPENAI_API_KEY}"},
json={"input": text, "model": "text-embedding-ada-002"},
)
r.raise_for_status()
return r.json()["data"][0]["embedding"]
client = weaviate.Client(WEAVIATE_URL)
client.schema.delete_all()
schema = {
"classes": [
{
"class": "MemoryEntry",
"description": "Memorizza la memoria dell'agente",
"properties": [
{"name": "text", "dataType": ["text"]},
{"name": "embedding", "dataType": ["number[]"]},
{"name": "timestamp", "dataType": ["date"]}
],
"vectorizer": "none"
}
]
}
client.schema.create(schema)
def add_memory(text):
embedding = get_openai_embedding(text)
data = {"text": text, "embedding": embedding, "timestamp": datetime.utcnow().isoformat()}
client.data_object.create(data, "MemoryEntry", vector=embedding)
def query_memories(question, top_k=5):
q_emb = get_openai_embedding(question)
near_vector = {"vector": q_emb}
res = client.query.get("MemoryEntry", ["text", "timestamp"])\
.with_near_vector(near_vector).with_limit(top_k).do()
return res.get("data", {}).get("Get", {}).get("MemoryEntry", [])
class Agent:
def __init__(self, client):
self.client = client
def remember(self, text):
add_memory(text)
def chat(self, question):
memories = query_memories(question)
context = "\n".join([m["text"] for m in memories])
prompt = f"Contesto:\n{context}\n\nDomanda: {question}\nRisposta:"
# Risposta fittizia
return prompt
agent = Agent(client)
agent.remember("Il cielo è blu.")
agent.remember("L'acqua bolle a 100 gradi Celsius.")
print(agent.chat("Di che colore è il cielo?"))
Cosa c’è dopo?
Dopo aver padroneggiato l’integrazione della memoria di Weaviate, il tuo prossimo passo concreto è costruire un sistema di potatura e aggiornamento della memoria. Ciò significa valutare periodicamente quali ricordi sono obsoleti o irrilevanti e eliminarli o aggiornarli. Se lasci che la memoria cresca senza controllo, le risposte del tuo agente rallenteranno e diventeranno incoerenti.
Considera di implementare un decadimento basato sul tempo o un ranking di importanza della memoria per mantenere il tuo database snello. Questo affinerà il focus dell’agente su ciò che conta realmente.
FAQ
Perché dovrei disabilitare il vettorizzatore integrato di Weaviate?
I vettorizzatori integrati sono adatti per semplici dimostrazioni ma ti vincolano al loro specifico modello di embeddings e rendono impossibile l’aggiornamento. Vuoi iniettare i tuoi embeddings generati da modelli come il text-embedding-ada-002 di OpenAI, in modo da controllare la qualità dei vettori e i costi dell’API.
Cosa faccio se le mie query restituiscono zero risultati?
Prima di tutto, conferma che le dimensioni dei tuoi embeddings corrispondano. Gli embeddings ada-002 di OpenAI sono vettori a 1536 dimensioni. Se i tuoi vettori memorizzati e i vettori di query differiscono nelle dimensioni, la ricerca di similarità non restituirà nulla. Controlla anche che il vettorizzatore del tuo schema sia ‘none’ e che tu invii esplicitamente i tuoi vettori quando crei oggetti.
Come gestisco i costi degli embeddings con migliaia di voci di memoria?
Esegui l’embedding dei tuoi dati in batch invece di chiamate singole e memorizza gli embeddings su disco o Redis. Preprocessare nuove informazioni offline può anche aiutare. Inoltre, sii strategico su ciò che memorizzi: memorizza riassunti, non conversazioni complete. Infine, esplora modelli open-source più economici, ma fai attenzione all’accuratezza.
Raccomandazioni per profili di sviluppatori
| Tipo di sviluppatore | Passi successivi raccomandati |
|---|---|
| Ricercatore AI | Integra Weaviate con embeddings di trasformatori personalizzati ed esplora ricerche ibride combinando testo e similarità vettoriale. |
| Ingegnere Backend | Implementa la gestione del ciclo di vita della memoria con potatura automatizzata, ricostruzione degli indici e monitoraggio della durabilità. |
| Sviluppatore Full-Stack | Crea un dashboard UI per visualizzare e gestire le voci di memoria e collega la memoria di Weaviate alla tua interfaccia chat frontend. |
Dati aggiornati al 21 marzo 2026. Fonti: https://github.com/weaviate/weaviate, https://weaviate.io/product/integrations/mem0
Articoli correlati
- Potenzia i LLM con Grafi di Conoscenza Affidabili: L’Innovazione di Qinggang Zhang
- Sblocca il Tuo Marchio: Creare il Logo Perfetto per una Rete Neurale Convoluzionale
- Perché Usare l’Architettura degli Agenti AI
🕒 Published: