Usa immagini e messaggi multimodali
Gli agenti spesso devono ricordare immagini e testo. Screenshot, documenti, grafici e fotografie possono contenere dettagli che la memoria di solo testo non è in grado di preservare.
In questa guida imparerai come:
- aggiungere immagini standalone e allegare immagini ai messaggi thread;
- cercare entrambi i tipi di immagini;
- recuperare i byte dell'immagine originale;
- configurare l'estrazione automatica della memoria per utilizzare testo dei messaggi, descrizioni delle immagini o immagini originali.
Suggerimento: per l'impostazione dei package, vedere Introduzione alla memoria dell'agente. Se hai bisogno di un Oracle AI Database locale per questo esempio, segui Esegui Oracle AI Database localmente.
Crea un client OracleAgentMemory
Creare il client OracleAgentMemory utilizzato dagli esempi in questa guida. Si connette a Oracle AI Database, configura un incorporatore e un LLM con capacità di visione e imposta limiti per l'input di immagini. Vedere Formati di revisione, Limiti e Gestione dei dati vicino alla fine di questa guida per una spiegazione di questi limiti.
from pathlib import Path
import oracledb
from oracleagentmemory.apis.message import ImageContent, ImageMimeType, Message, TextContent
from oracleagentmemory.core import (
ImageInputLimitConfig,
MemoryExtractionConfig,
MemoryExtractionImageContext,
MemoryExtractionMode,
OracleAgentMemory,
SchemaPolicy,
)
from oracleagentmemory.core.embedders.embedder import Embedder
from oracleagentmemory.core.llms.llm import Llm
embedder = Embedder(model="YOUR_EMBEDDING_MODEL")
vision_llm = Llm(
model="YOUR_VISION_CAPABLE_MODEL",
supports_vision=True,
)
db_pool = oracledb.SessionPool(
user="YOUR DB USER",
password="YOUR DB PASSWORD",
dsn="localhost:1521/...",
)
memory_store_id = "T_IMAGE_GUIDE"
memory = OracleAgentMemory(
connection=db_pool,
embedder=embedder,
llm=vision_llm,
memory_extraction_config=MemoryExtractionConfig(
extract_memories=False,
extraction_mode=MemoryExtractionMode.BACKGROUND,
),
image_input_limit_config=ImageInputLimitConfig(
max_raw_image_bytes=10 * 1024 * 1024,
max_images_per_llm_request=20,
max_total_raw_image_bytes_per_llm_request=50 * 1024 * 1024,
),
schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
memory_store_id=memory_store_id,
)
image_bytes = Path("sample.png").read_bytes()
Il client imposta supports_vision=True durante la creazione di Llm. Impostare questa opzione solo quando il modello e l'endpoint del provider selezionati accettano l'input dell'immagine. Se si omette, Llm controlla i metadati del modello. Quando non sono disponibili metadati, Llm invia un'immagine di test di piccole dimensioni per determinare se l'endpoint accetta l'input di immagine. L'impostazione di supports_vision=True salta entrambi i controlli e non crea un modello di solo testo in grado di elaborare le immagini.
| Riferimento API: Llm | ImageInputLimitConfig | Configurazione estrazione memoria |
Memorizza un'immagine standalone
Utilizzare OracleAgentMemory.add_image() per aggiungere un'immagine standalone. Includere almeno una delle opzioni user_id, agent_id o thread_id. È necessario fornire un identificativo corrispondente quando si chiama in seguito list_images() o search().
Per la ricerca, l'SDK rappresenta un'immagine con una descrizione del testo. Con la ricerca vettoriale, incorpora quella descrizione con lo stesso incorporatore di testo utilizzato per la ricerca solo di testo; non incorpora i byte dell'immagine. Se si passa da description a add_image(), il kit SDK utilizza tale testo. Se lo ometti, l'LLM configurato che supporta la visione genera automaticamente la descrizione. Nell'esempio seguente viene fornita una descrizione, pertanto l'aggiunta dell'immagine non richiede un LLM.
image_id = memory.add_image(
image_bytes,
mime_type=ImageMimeType.PNG,
user_id="customer_123",
description="A red sample image used by the image support guide.",
metadata={"source": "profile-photo"},
)
images = memory.list_images(user_id="customer_123", limit=10)
stored_image = next(image for image in images if image.id == image_id)
print(stored_image.content)
list_images() restituisce immagini standalone corrispondenti ai valori user_id, agent_id o thread_id forniti. Ogni valore ImageRecord.content contiene la descrizione dell'immagine.
Per associare un'immagine standalone a un thread, chiamare OracleThread.add_image(). Questo metodo utilizza l'ID thread e qualsiasi ID utente o agente memorizzato nel thread, in modo da non passare di nuovo.
| Riferimento API: OracleAgentMemory | OracleThread | Record immagine |
Memorizza un'immagine come parte di un messaggio
Memorizza un'immagine come parte di un messaggio thread quando fornisce il contesto per un turno di conversazione e non deve essere gestita separatamente.
Un messaggio di solo testo può utilizzare una stringa per content. Per un messaggio contenente testo e immagini, passare un elenco ordinato di parti di contenuto. L'SDK conserva tale ordine quando memorizza e recupera il messaggio e quando crea un prompt di estrazione della memoria.
In formato dizionario, ogni parte di contenuto ha un valore type:
- Una parte di testo è
{"type": "text", "text": "..."}. - Una parte dell'immagine contiene
"type": "image", rawbytesemime_type. Può anche contenere undescription.
I valori mime_type supportati sono "image/png", "image/jpeg" e "image/webp".
thread = memory.create_thread(
thread_id="image-support-thread",
user_id="customer_123",
memory_extraction_config=MemoryExtractionConfig(
extract_memories=False,
extraction_mode=MemoryExtractionMode.BACKGROUND,
),
)
message_id = thread.add_messages(
[
{
"role": "user",
"content": [
{"type": "text", "text": "Please remember what is in this image."},
{
"type": "image",
"bytes": image_bytes,
"mime_type": "image/png",
},
],
}
]
)[0]
Il dizionario delle immagini in questo esempio omette description, quindi l'SDK ne genera uno con l'LLM configurato con capacità di visione.
Il client utilizza BACKGROUND, quindi l'SDK memorizza il messaggio, la generazione della descrizione delle code e restituisce prima del termine della generazione. Utilizzare INLINE quando la descrizione deve essere pronta prima che venga restituito add_messages().
Chiama wait_for_memory_extraction() prima di leggere o cercare la descrizione generata. Il metodo attende le attività di descrizione dell'immagine e di estrazione della memoria accodate da questo client.
Dopo la generazione, get_message() restituisce la descrizione nel campo ImageContent.description della parte immagine:
memory.wait_for_memory_extraction()
stored_message = thread.get_message(message_id)
attached_image = next(
part for part in stored_message.content if isinstance(part, ImageContent)
)
print(attached_image.description)
Se la generazione non riesce o la coda rifiuta il task, l'immagine rimane memorizzata senza una descrizione. Selezionare ImageContent.description prima di utilizzare il testo generato.
È inoltre possibile creare il messaggio con gli oggetti TextContent e ImageContent anziché con i dizionari. Entrambi i moduli memorizzano lo stesso messaggio.
typed_message_id = thread.add_messages(
[
Message(
role="user",
content=[
TextContent(text="This message uses the typed content API."),
ImageContent(
bytes=image_bytes,
mime_type=ImageMimeType.PNG,
description="A red square on a white background.",
),
],
)
]
)[0]
print(typed_message_id)
Poiché questo ImageContent include una descrizione, l'SDK non invia l'immagine a un LLM per la generazione della descrizione.
| Riferimento API: Llm | Configurazione estrazione memoria | Messaggi e contenuti dei messaggi | OracleThread |
Cerca immagini
Impostare record_types=["image"] per cercare le descrizioni delle immagini. Consente di cercare sia le immagini standalone che quelle allegate ai messaggi. Ogni risultato è un ImageRecord senza i byte originali dell'immagine.
È possibile fornire la descrizione personalmente o lasciare che l'LLM configurato che supporta la visione la generi. L'SDK memorizza e ricerca le descrizioni generate allo stesso modo delle descrizioni fornite.
Con la strategia VECTOR predefinita utilizzata in questa guida, l'SDK divide una descrizione dell'immagine in chunk quando necessario e incorpora tali chunk con il Embedder configurato. Incorpora la query con lo stesso embedder e confronta i vettori risultanti. Questo processo è lo stesso per le immagini standalone e le immagini allegate ai messaggi.
Altre strategie di ricerca elaborano le descrizioni in modo diverso. KEYWORD cerca il testo della descrizione memorizzata senza creare incorporamenti. HYBRID combina la corrispondenza di testo con i vettori prodotti dal OracleDBEmbedder configurato.
L'esempio seguente cerca entrambe le immagini. Ogni risultato include l'ID immagine. Un'immagine allegata include anche l'ID del relativo messaggio padre.
standalone_matches = memory.search(
"red sample image",
user_id="customer_123",
record_types=["image"],
max_results=5,
)
for match in standalone_matches:
print(match.record.id, match.content)
attached_matches = thread.search(
"red square on a white background",
record_types=["image"],
max_results=5,
)
for match in attached_matches:
print(match.record.message_id, match.record.id, match.content)
Le sezioni di recupero che seguono utilizzano questi ID per caricare i byte originali.
Con record_types=["message"], la ricerca esamina solo il testo del messaggio. Non cerca descrizioni di immagini allegate ai messaggi; utilizzare record_types=["image"] per tali descrizioni.
| Riferimento API: OracleAgentMemory | OracleThread | Risultati ricerca Oracle | Embedder |
Recupera byte immagine standalone
Per impostazione predefinita, list_images() restituisce i metadati e le descrizioni delle immagini, ma non i byte memorizzati. Per recuperare i byte, impostare include_bytes=True e fornire l'ID immagine dal risultato della ricerca insieme a user_id, agent_id o thread_id corrispondenti. Questi filtri limitano la richiesta a un'immagine.
#Raw bytes are omitted by default. To load them, use the image ID returned by
#the search result and pass the same user, agent, or thread ID used when
#adding it.
standalone_match = next(
match for match in standalone_matches if match.record.id == image_id
)
loaded_image = memory.list_images(
image_id=standalone_match.record.id,
user_id="customer_123",
include_bytes=True,
)[0]
| Riferimento API: OracleAgentMemory | Record immagine |
Recupera byte per un'immagine allegata a un messaggio
Per impostazione predefinita, le parti immagine restituite da get_message() e get_messages() non includono i relativi byte. Per recuperare un'immagine, passare il relativo ID dal risultato della ricerca a get_message(..., included_image_ids=[...]). Il valore message_id del risultato della ricerca identifica il messaggio da recuperare.
#get_message() omits image bytes unless included_image_ids selects them.
attached_match = next(
match
for match in attached_matches
if match.record.message_id == typed_message_id
)
message_with_bytes = thread.get_message(
attached_match.record.message_id,
included_image_ids=[attached_match.record.id],
)
hydrated_image = next(
part for part in message_with_bytes.content if isinstance(part, ImageContent)
)
| Riferimento API: messaggi e contenuto dei messaggi | OracleThread |
Gestisci immagini allegate ai messaggi
Un'immagine allegata appartiene al relativo messaggio padre. Per sostituire o rimuovere un'immagine allegata, chiamare update_message() con il nuovo contenuto del messaggio. L'eliminazione del messaggio elimina anche tutte le immagini ad esso collegate. delete_image() elimina solo le immagini standalone. Impossibile aggiornare direttamente il TTL di un'immagine allegata.
Quando si aggiunge un'immagine allegata, questa riceve l'ora di scadenza del messaggio padre. Se update_message() fa scadere il messaggio prima, l'SDK riduce anche il tempo di scadenza dell'immagine. L'estensione dell'ora di scadenza del messaggio, o la cancellazione con ttl_days=None, non estende o cancella l'ora di scadenza già memorizzata per l'immagine. Le letture e le ricerche escludono l'immagine dopo la scadenza dell'immagine o del relativo messaggio padre.
| Riferimento API: messaggi e contenuto dei messaggi | OracleThread |
Seleziona cosa vede l'estrazione automatica della memoria
Impostare MemoryExtractionConfig.memory_extraction_image_context per controllare quali parti di un messaggio contenenti immagini riceve l'LLM di estrazione della memoria. Questa impostazione modifica solo il prompt di estrazione. Non modifica il messaggio memorizzato né genera una descrizione dell'immagine mancante.
Contesto immagine per estrazione automatica memoria
| Valore | Cosa riceve l'estrazione LLM | Seleziona quando |
|---|---|---|
DISABLED |
Solo le parti di testo del messaggio. | L'estrazione deve ignorare le immagini. Si tratta dello stato predefinito. |
CAPTION |
Parti di testo e descrizioni di immagini, nel loro ordine originale. | Le descrizioni contengono le informazioni visive necessarie per l'estrazione oppure il provider LLM non deve ricevere byte di immagine. |
IMAGE |
Parti di testo e le immagini originali, nel loro ordine originale. | I ricordi dipendono dai dettagli visivi che le descrizioni non contengono. LLM e il relativo endpoint devono accettare l'input di immagine. |
Nell'esempio seguente viene utilizzato CAPTION. Con memory_extraction_frequency=1, l'estrazione viene eseguita dopo il primo messaggio. Con MemoryExtractionMode.INLINE, l'estrazione viene completata prima che venga restituito add_messages().
caption_thread = memory.create_thread(
thread_id="caption-extraction-thread",
user_id="customer_123",
memory_extraction_config=MemoryExtractionConfig(
extract_memories=True,
extraction_mode=MemoryExtractionMode.INLINE,
memory_extraction_frequency=1,
memory_extraction_image_context=MemoryExtractionImageContext.CAPTION,
),
)
caption_thread.add_messages(
[
Message(
role="user",
content=[
TextContent(text="Remember the color and shape in this image."),
ImageContent(
bytes=image_bytes,
mime_type=ImageMimeType.PNG,
description="A red square on a white background.",
),
],
)
]
)
Per inviare l'immagine originale, sostituire MemoryExtractionImageContext.CAPTION con MemoryExtractionImageContext.IMAGE. LLM configurato in OracleAgentMemory deve accettare l'input dell'immagine.
In modalità CAPTION, ogni immagine inviata per l'estrazione deve avere una descrizione non vuota. Fornire description quando si aggiunge ogni immagine o configurare un LLM con capacità di visione per generare le descrizioni. Con MemoryExtractionMode.BACKGROUND, l'SDK accoda la generazione della descrizione prima dell'estrazione della memoria per lo stesso thread. Se un'immagine non ha ancora una descrizione all'inizio dell'estrazione, l'SDK rifiuta la richiesta.
Non utilizzare MemoryExtractionImageContext.MEMORY. Questo valore è riservato per uso futuro e l'SDK lo rifiuta.
| Riferimento API: MemoryExtractionImageContext | Configurazione estrazione memoria |
Aggiorna o elimina un'immagine standalone
Dopo aver aggiunto un'immagine standalone, utilizzare update_image() per modificarne la descrizione, i metadati o i byte. La descrizione viene memorizzata in ImageRecord.content e indicizzata per la ricerca. Passare una stringa per sostituirla oppure passare None per generare una sostituzione con l'LLM di visione configurato. Se si omette description, la descrizione esistente rimane invariata.
memory.update_image(
image_id,
description="A red square used by the image support guide.",
metadata={"source": "reviewed-profile-photo"},
)
updated_image = memory.list_images(
image_id=image_id,
user_id="customer_123",
)[0]
print(updated_image.content)
print(updated_image.metadata)
deleted = memory.delete_image(image_id)
print(deleted)
L'esempio recupera l'immagine dopo update_image() per verificare la nuova descrizione e i nuovi metadati. Quindi passa image_id a delete_image() e controlla che un'immagine sia stata eliminata.
Per sostituire i byte, passare insieme image e mime_type. Nella stessa chiamata, è possibile mantenere la descrizione corrente, fornirne una nuova o richiedere una sostituzione generata con description=None. A differenza di un'immagine allegata a un messaggio, un'immagine standalone può avere i propri metadati, indicatori orari e TTL.
| Riferimento API: OracleAgentMemory | Risultati ricerca Oracle |
Revisione di formati, limiti e gestione dei dati
Prima di memorizzare un'immagine, l'SDK decodifica i suoi byte e verifica il formato. Se si passa a mime_type, il formato decodificato deve corrispondere. L'SDK accetta immagini PNG, JPEG e WebP, ma rifiuta PNG animati e WebP animati. Impossibile disabilitare questa convalida.
Per impostazione predefinita, un'immagine raw può essere fino a 10 MiB. Una singola richiesta LLM può contenere fino a 100 immagini e 100 MiB di dati di immagine. Utilizzare ImageInputLimitConfig per ridurre questi limiti per la distribuzione o aumentarli fino ai valori massimi documentati. Il client all'inizio di questa guida consente 10 MiB per immagine, 20 immagini per richiesta e 50 MiB di dati di immagine per richiesta.
Oracle AI Agent Memory memorizza i byte delle immagini in Oracle AI Database. La generazione di una descrizione invia tali byte al provider LLM configurato. L'estrazione della memoria invia anche i byte in modalità IMAGE. In modalità CAPTION, l'estrazione della memoria invia invece le descrizioni delle immagini. Una descrizione può rivelare informazioni dall'immagine originale. Rivedere le considerazioni sulla sicurezza prima di inviare immagini riservate a un LLM per la generazione di descrizioni o l'estrazione della memoria.
Conclusione
In questa guida abbiamo imparato come aggiungere immagini standalone, allegare immagini ai messaggi, recuperare i byte delle immagini, cercare le descrizioni delle immagini e configurare l'estrazione automatica della memoria per utilizzare il testo dei messaggi, le descrizioni delle immagini o le immagini originali.
→ Dopo aver appreso come utilizzare immagini e messaggi multimodali, ora è possibile passare a Usa Time-to-Live per messaggi e memorie.
Codice completo
L'esempio completo è incluso in questa guida per la copia e l'esecuzione.
#Copyright © 2026 Oracle and/or its affiliates.
#This software is under the Apache License 2.0
#(LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or Universal Permissive License
#(UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl), at your option.
#Oracle Agent Memory Code Example - Use Images and Multimodal Messages
#---------------------------------------------------------------------
##Configure a vision capable memory client
from pathlib import Path
import oracledb
from oracleagentmemory.apis.message import ImageContent, ImageMimeType, Message, TextContent
from oracleagentmemory.core import (
ImageInputLimitConfig,
MemoryExtractionConfig,
MemoryExtractionImageContext,
MemoryExtractionMode,
OracleAgentMemory,
SchemaPolicy,
)
from oracleagentmemory.core.embedders.embedder import Embedder
from oracleagentmemory.core.llms.llm import Llm
embedder = Embedder(model="YOUR_EMBEDDING_MODEL")
vision_llm = Llm(
model="YOUR_VISION_CAPABLE_MODEL",
supports_vision=True,
)
db_pool = oracledb.SessionPool(
user="YOUR DB USER",
password="YOUR DB PASSWORD",
dsn="localhost:1521/...",
)
memory_store_id = "T_IMAGE_GUIDE"
memory = OracleAgentMemory(
connection=db_pool,
embedder=embedder,
llm=vision_llm,
memory_extraction_config=MemoryExtractionConfig(
extract_memories=False,
extraction_mode=MemoryExtractionMode.BACKGROUND,
),
image_input_limit_config=ImageInputLimitConfig(
max_raw_image_bytes=10 * 1024 * 1024,
max_images_per_llm_request=20,
max_total_raw_image_bytes_per_llm_request=50 * 1024 * 1024,
),
schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
memory_store_id=memory_store_id,
)
image_bytes = Path("sample.png").read_bytes()
##Store a standalone image
image_id = memory.add_image(
image_bytes,
mime_type=ImageMimeType.PNG,
user_id="customer_123",
description="A red sample image used by the image support guide.",
metadata={"source": "profile-photo"},
)
images = memory.list_images(user_id="customer_123", limit=10)
stored_image = next(image for image in images if image.id == image_id)
print(stored_image.content)
##Add a message with an image dictionary
thread = memory.create_thread(
thread_id="image-support-thread",
user_id="customer_123",
memory_extraction_config=MemoryExtractionConfig(
extract_memories=False,
extraction_mode=MemoryExtractionMode.BACKGROUND,
),
)
message_id = thread.add_messages(
[
{
"role": "user",
"content": [
{"type": "text", "text": "Please remember what is in this image."},
{
"type": "image",
"bytes": image_bytes,
"mime_type": "image/png",
},
],
}
]
)[0]
##Generate an attached image description
memory.wait_for_memory_extraction()
stored_message = thread.get_message(message_id)
attached_image = next(
part for part in stored_message.content if isinstance(part, ImageContent)
)
print(attached_image.description)
##Add typed multimodal message content
typed_message_id = thread.add_messages(
[
Message(
role="user",
content=[
TextContent(text="This message uses the typed content API."),
ImageContent(
bytes=image_bytes,
mime_type=ImageMimeType.PNG,
description="A red square on a white background.",
),
],
)
]
)[0]
print(typed_message_id)
##Search for images
standalone_matches = memory.search(
"red sample image",
user_id="customer_123",
record_types=["image"],
max_results=5,
)
for match in standalone_matches:
print(match.record.id, match.content)
attached_matches = thread.search(
"red square on a white background",
record_types=["image"],
max_results=5,
)
for match in attached_matches:
print(match.record.message_id, match.record.id, match.content)
##Retrieve standalone image bytes
#Raw bytes are omitted by default. To load them, use the image ID returned by
#the search result and pass the same user, agent, or thread ID used when
#adding it.
standalone_match = next(
match for match in standalone_matches if match.record.id == image_id
)
loaded_image = memory.list_images(
image_id=standalone_match.record.id,
user_id="customer_123",
include_bytes=True,
)[0]
##Retrieve attached image bytes
#get_message() omits image bytes unless included_image_ids selects them.
attached_match = next(
match
for match in attached_matches
if match.record.message_id == typed_message_id
)
message_with_bytes = thread.get_message(
attached_match.record.message_id,
included_image_ids=[attached_match.record.id],
)
hydrated_image = next(
part for part in message_with_bytes.content if isinstance(part, ImageContent)
)
##Extract memories from an image description
caption_thread = memory.create_thread(
thread_id="caption-extraction-thread",
user_id="customer_123",
memory_extraction_config=MemoryExtractionConfig(
extract_memories=True,
extraction_mode=MemoryExtractionMode.INLINE,
memory_extraction_frequency=1,
memory_extraction_image_context=MemoryExtractionImageContext.CAPTION,
),
)
caption_thread.add_messages(
[
Message(
role="user",
content=[
TextContent(text="Remember the color and shape in this image."),
ImageContent(
bytes=image_bytes,
mime_type=ImageMimeType.PNG,
description="A red square on a white background.",
),
],
)
]
)
##Update and delete a standalone image
memory.update_image(
image_id,
description="A red square used by the image support guide.",
metadata={"source": "reviewed-profile-photo"},
)
updated_image = memory.list_images(
image_id=image_id,
user_id="customer_123",
)[0]
print(updated_image.content)
print(updated_image.metadata)
deleted = memory.delete_image(image_id)
print(deleted)