Usar Imagens e Mensagens Multimodais
Os agentes geralmente precisam lembrar imagens e texto. Capturas de tela, documentos, gráficos e fotografias podem conter detalhes que a memória somente texto não pode preservar.
Neste guia, você aprenderá a:
- adicionar imagens independentes e anexar imagens a mensagens de thread;
- pesquisar ambos os tipos de imagens;
- recuperar os bytes da imagem original;
- configurar a extração automática de memória para usar texto da mensagem, descrições de imagem ou imagens originais.
Dica: Para configurar o pacote, consulte Conceitos Básicos da Memória do Agente. Se você precisar de um Oracle AI Database local para este exemplo, siga Executar o Oracle AI Database localmente.
Criar um OracleAgentMemory Client
Crie o cliente OracleAgentMemory usado pelos exemplos neste guia. Ele se conecta ao Oracle AI Database, configura um incorporador e um LLM com capacidade de visão e define limites para entrada de imagem. Consulte Formatos de Revisão, Limites e Tratamento de Dados perto do final deste guia para obter uma explicação desses limites.
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()
O cliente define supports_vision=True quando cria Llm. Defina essa opção somente quando o modelo e o ponto final do provedor selecionados aceitarem entrada de imagem. Se você omiti-lo, o Llm verificará os metadados do modelo. Quando nenhum metadado está disponível, o Llm envia uma pequena imagem de teste para determinar se o ponto final aceita entrada de imagem. A definição de supports_vision=True ignora ambas as verificações; ela não torna um modelo somente texto capaz de processar imagens.
| Referência de API: Llm | ImageInputLimitConfig | MemoryExtractionConfig |
Armazenar uma imagem independente
Use OracleAgentMemory.add_image() para adicionar uma imagem standalone. Inclua pelo menos um dos user_id, agent_id ou thread_id. Você deve fornecer um identificador correspondente ao chamar mais tarde list_images() ou search().
Para pesquisa, o SDK representa uma imagem com uma descrição de texto. Com a pesquisa vetorial, ela incorpora essa descrição com o mesmo incorporador de texto usado para pesquisa somente texto; ela não incorpora os bytes de imagem. Se você informar description para add_image(), o SDK usará esse texto. Se você o omitir, o LLM configurado com capacidade de visão gerará a descrição automaticamente. O exemplo a seguir fornece uma descrição, portanto, a adição da imagem não faz uma solicitação de 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() retorna imagens stand-alone que correspondem ao user_id, agent_id ou thread_id fornecido. Cada valor ImageRecord.content contém a descrição da imagem.
Para associar uma imagem standalone a um thread, chame OracleThread.add_image(). Este método usa o ID do thread e quaisquer IDs de usuário ou agente armazenados no thread, para que você não os repasse novamente.
| Referência de API: OracleAgentMemory | OracleThread | Registro de imagem |
Armazenar uma Imagem como Parte de uma Mensagem
Armazene uma imagem como parte de uma mensagem de thread quando ela fornecer contexto para um turno de conversa e não precisar ser gerenciada separadamente.
Uma mensagem somente texto pode usar uma string para content. Para uma mensagem que contém texto e imagens, informe uma lista ordenada de partes de conteúdo. O SDK preserva essa ordem quando armazena e recupera a mensagem e quando cria um prompt de extração de memória.
No formato de dicionário, cada parte do conteúdo tem um type:
- Uma parte do texto é
{"type": "text", "text": "..."}. - Uma parte da imagem contém
"type": "image",bytesbruto emime_type. Também pode conter umdescription.
Os valores mime_type suportados são "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]
O dicionário de imagens neste exemplo omite description; portanto, o SDK gera um com o LLM configurado com capacidade de visão.
O cliente usa BACKGROUND, de modo que o SDK armazena a mensagem, gera a descrição das filas e retorna antes do término da geração. Use INLINE quando a descrição tiver que estar pronta para que add_messages() retorne.
Chame wait_for_memory_extraction() antes de ler ou procurar a descrição gerada. O método aguarda as tarefas image-description e memory-extraction enfileiradas por este cliente.
Após a geração ser bem-sucedida, get_message() retorna a descrição no campo ImageContent.description da parte da imagem:
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 a geração falhar ou a fila rejeitar a tarefa, a imagem permanecerá armazenada sem uma descrição. Verifique ImageContent.description antes de usar o texto gerado.
Você também pode construir a mensagem com objetos TextContent e ImageContent em vez de dicionários. Ambos os formulários armazenam a mesma mensagem.
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)
Como esse ImageContent inclui uma descrição, o SDK não envia a imagem a um LLM para geração de descrição.
| Referência de API: Llm | MemoryExtractionConfig | Mensagens e conteúdo da mensagem | OracleThread |
Pesquisar Imagens
Defina record_types=["image"] para pesquisar descrições de imagem. Isso pesquisa imagens autônomas e anexadas a mensagens. Cada resultado é um ImageRecord sem os bytes de imagem original.
Você mesmo pode fornecer a descrição ou permitir que o LLM configurado com capacidade de visão a gere. O SDK armazena e pesquisa descrições geradas da mesma forma que as descrições fornecidas.
Com a estratégia VECTOR padrão usada neste guia, o SDK divide uma descrição de imagem em chunks quando necessário e incorpora esses chunks ao Embedder configurado. Ele incorpora a consulta com o mesmo incorporador e compara os vetores resultantes. Esse processo é o mesmo para imagens autônomas e anexadas a mensagens.
Outras estratégias de pesquisa processam as descrições de maneira diferente. KEYWORD pesquisa o texto de descrição armazenado sem criar incorporações. O HYBRID combina correspondência de texto com vetores produzidos pelo OracleDBEmbedder configurado.
O exemplo a seguir procura ambas as imagens. Cada resultado inclui o ID da imagem. Uma imagem anexada também inclui o ID de sua mensagem pai.
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)
As seções de recuperação que se seguem utilizam esses IDs para carregar os bytes originais.
Com record_types=["message"], a pesquisa examina apenas o texto da mensagem. Ele não pesquisa descrições de imagens anexadas a mensagens; use record_types=["image"] para essas descrições.
| Referência de API: OracleAgentMemory | OracleThread | Resultado do OracleSearch | Incorporador |
Recuperar Bytes de Imagem Independentes
Por padrão, list_images() retorna metadados e descrições de imagem, mas não os bytes armazenados. Para recuperar os bytes, defina include_bytes=True e forneça o ID da imagem do resultado da pesquisa juntamente com um user_id, agent_id ou thread_id correspondente. Esses filtros limitam a solicitação a uma imagem.
#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]
| Referência de API: OracleAgentMemory | Registro de imagem |
Recuperar Bytes para uma Imagem Anexada a uma Mensagem
Por padrão, as partes da imagem retornadas por get_message() e get_messages() não incluem seus bytes. Para recuperar uma imagem, informe seu ID do resultado da pesquisa para get_message(..., included_image_ids=[...]). O resultado da pesquisa message_id identifica a mensagem a ser recuperada.
#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)
)
| Referência de API: Conteúdo de mensagens e mensagens | OracleThread |
Gerenciar Imagens Anexadas a Mensagens
Uma imagem anexada pertence à sua mensagem pai. Para substituir ou remover uma imagem anexada, chame update_message() pelo novo conteúdo da mensagem. A exclusão da mensagem também exclui todas as imagens anexadas a ela. O delete_image() exclui somente imagens standalone. Não é possível atualizar o TTL de uma imagem anexada diretamente.
Quando você adiciona uma imagem anexada, ela recebe o tempo de expiração da mensagem pai. Se o update_message() fizer com que a mensagem expire mais cedo, o SDK também reduzirá o tempo de expiração da imagem. A extensão do tempo de expiração da mensagem, ou a limpeza com ttl_days=None, não estende ou limpa o tempo de expiração já armazenado para a imagem. Leituras e pesquisas excluem a imagem após a expiração da imagem ou da mensagem pai.
| Referência de API: Conteúdo de mensagens e mensagens | OracleThread |
Selecione o que a extração automática de memória vê
Defina MemoryExtractionConfig.memory_extraction_image_context para controlar quais partes de uma mensagem que contêm imagens o LLM de extração de memória recebe. Esta configuração altera apenas o prompt de extração. Ele não altera a mensagem armazenada nem gera uma descrição de imagem ausente.
Contexto da imagem para extração automática de memória
| Valor | O que o LLM de extração recebe | Selecione-o quando |
|---|---|---|
DISABLED |
Apenas as partes de texto da mensagem. | A extração deve ignorar as imagens. Este é o padrão. |
CAPTION |
Peças de texto e descrições de imagens, em sua ordem original. | As descrições contêm as informações visuais necessárias para extração ou o provedor LLM não deve receber bytes de imagem. |
IMAGE |
Peças de texto e as imagens originais, em sua ordem original. | As memórias dependem de detalhes visuais que as descrições não contêm. O LLM e seu ponto final devem aceitar entrada de imagem. |
O exemplo a seguir usa CAPTION. Com memory_extraction_frequency=1, a extração é executada após a primeira mensagem. Com MemoryExtractionMode.INLINE, a extração é concluída antes do retorno de 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.",
),
],
)
]
)
Para enviar a imagem original, substitua MemoryExtractionImageContext.CAPTION por MemoryExtractionImageContext.IMAGE. O LLM configurado no OracleAgentMemory deve aceitar entrada de imagem.
No modo CAPTION, todas as imagens enviadas para extração devem ter uma descrição não vazia. Forneça description ao adicionar cada imagem ou configure um LLM capaz de gerar as descrições. Com MemoryExtractionMode.BACKGROUND, o SDK enfileira a geração de descrição antes da extração de memória para o mesmo thread. Se uma imagem ainda não tiver descrição quando a extração começar, o SDK rejeitará a solicitação.
Não utilize MemoryExtractionImageContext.MEMORY. Este valor é reservado para uso futuro e o SDK o rejeita.
| Referência de API: MemoryExtractionImageContext | MemoryExtractionConfig |
Atualizar ou Excluir uma Imagem Stand-alone
Depois de adicionar uma imagem stand-alone, use update_image() para alterar sua descrição, metadados ou bytes. A descrição é armazenada em ImageRecord.content e indexada para pesquisa. Informe uma string para substituí-la ou informe None para gerar uma substituição pelo LLM de visão configurado. Se você omitir description, a descrição existente permanece inalterada.
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)
O exemplo recupera a imagem após update_image() para verificar a nova descrição e os metadados. Em seguida, ele passa image_id para delete_image() e verifica se uma imagem foi excluída.
Para substituir os bytes, informe image e mime_type juntos. Na mesma chamada, você pode manter a descrição atual, fornecer uma nova ou solicitar uma substituição gerada por description=None. Ao contrário de uma imagem anexada a uma mensagem, uma imagem standalone pode ter seus próprios metadados, timestamps e TTL.
| Referência de API: OracleAgentMemory | Resultado do OracleSearch |
Revisar Formatos, Limites e Tratamento de Dados
Antes de armazenar uma imagem, o SDK decodifica seus bytes e verifica o formato. Se você informar mime_type, o formato decodificado deverá corresponder a ele. O SDK aceita imagens PNG, JPEG e WebP, mas rejeita imagens PNG animadas e WebP animadas. Não é possível desativar esta validação.
Por padrão, uma imagem bruta pode ter até 10 MiB. Uma única solicitação de LLM pode conter até 100 imagens e 100 MiB de dados de imagem. Use ImageInputLimitConfig para reduzir esses limites para sua implantação ou elevá-los até os valores máximos documentados. O cliente no início deste guia permite 10 MiB por imagem, 20 imagens por solicitação e 50 MiB de dados de imagem por solicitação.
O Oracle AI Agent Memory armazena bytes de imagens no Oracle AI Database. A geração de uma descrição envia esses bytes para o provedor LLM configurado. A extração de memória também envia os bytes no modo IMAGE. No modo CAPTION, a extração de memória envia descrições de imagem. Uma descrição pode revelar informações da imagem original. Revise as Considerações de Segurança antes de enviar imagens confidenciais a um LLM para geração de descrição ou extração de memória.
Conclusão
Neste guia, aprendemos a adicionar imagens autônomas, anexar imagens a mensagens, recuperar bytes de imagem, pesquisar descrições de imagem e configurar a extração automática de memória para usar texto de mensagem, descrições de imagem ou imagens originais.
→ Tendo aprendido a usar imagens e mensagens multimodais, agora você pode prosseguir para Usar o Tempo de Ativação para Mensagens e Memórias.
Código Inteiro
O exemplo completo está incluído neste guia para você copiar e executar.
#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)