Você pode usar o Memory Bank para gerar perfis estruturados, que são estruturas de dados com esquemas estáticos preenchidos e atualizados usando LLMs. Ao definir um esquema fixo, você garante que seus agentes tenham acesso imediato e de baixa latência a informações em constante evolução, sem a necessidade de operações de pesquisa caras durante uma sessão.
Para concluir as etapas demonstradas neste guia, primeiro siga as etapas em Configurar o Memory Bank.
Visão geral
Usar perfis estruturados com seu agente garante que as informações extraídas, como as preferências ou as tecnologias usadas por um usuário, estejam disponíveis de forma rápida, concisa e com um formato consistente. Por exemplo, você pode recuperar perfis que incluem conteúdo como:
MemoryProfile(
profile={
"technical_stacks": "ADK, Python",
"preferred_language": "Python",
"tone_preference": "Succinct"
},
schema_id="user-profile"
)
Os perfis estruturados são otimizados para recuperação de baixa latência, porque o trabalho árduo de organizar as informações é feito no momento da geração. Eles são ótimos para iniciar uma interação entre um agente e um usuário.
Entender os perfis de memória estruturada
Os perfis estruturados são gerados pelos mesmos métodos (GenerateMemories e IngestEvents) usados para as memórias em linguagem natural. Depois de definir um esquema, o Memory Bank vai tentar gerar automaticamente perfis que se alinham a ele usando as fontes de dados fornecidas.
Ao usar perfis estruturados, o Memory Bank realiza as seguintes operações durante a geração de dados de memória:
- Extração: extrai informações e contexto que se encaixam no esquema da fonte de dados. Somente as informações que se alinham ao esquema serão extraídas. É possível inspecionar quais informações e contexto foram extraídos usando revisões de memória.
- Consolidação: atualiza (se necessário) os campos existentes no perfil. Um LLM vai julgar como atualizar o conteúdo atual com base nas informações e no contexto recém-extraídos. Se o campo ainda não existir no perfil, a consolidação será ignorada, e o campo será atualizado diretamente com as informações extraídas.
Os perfis são isolados com base no scope (como {"user_id": "123"}) que você forneceu ao ingerir dados no Memory Bank. Para cada esquema e escopo, a Central de Memória mantém um único perfil como fonte de verdade. Um perfil gerado é composto por uma ou mais instâncias de Memory. Cada instância Memory representa um único campo no perfil que pode ser usado para inspecionar os metadados e o histórico de revisões do campo, como:
Memory(
create_time=datetime.datetime(...),
memory_type=<MemoryType.STRUCTURED_PROFILE: 'STRUCTURED_PROFILE'>,
name='projects/.../locations/.../reasoningEngines/.../memories/...',
scope={
'user_id': '123'
},
structured_content=MemoryStructuredContent(
data={
'language_preference': 'Java'
},
schema_id='user-profile'
),
update_time=datetime.datetime(...),
expire_time=datetime.datetime(...),
metadata={...}
)
Definição do esquema
Os perfis gerados pelo Memory Bank se alinham ao esquema definido quando a instância da Agent Platform foi criada ou atualizada. É possível usar um modelo pydantic para definir os campos que você quer que o Memory Bank extraia e mantenha. Exemplo:
from pydantic import BaseModel, Field
from typing import Literal
class UserProfile(BaseModel):
name: str = Field(
description="Name of the user.")
technical_stack: str = Field(
description="Comma-separated list tools or languages used by the user.")
primary_goal: str = Field(
description="The main objective the user is pursuing.")
expertise_level: str = Field(
description="Current skill level (e.g., Junior, Senior).")
job_status: Literal['unemployed', 'part_time', 'full_time', 'student'] = Field(
description="The job status of the individual")
Faça upload do esquema para o Memory Bank ao criar ou atualizar sua instância do Agent Platform. É possível definir vários esquemas de perfil independentes. Cada um precisa ser identificado por um ID exclusivo:
schema_config = {
"id": "user-profile",
"memory_schema": UserProfile.model_json_schema()
}
memory_bank = client.agent_engines.create(
config={
"context_spec": {
"memory_bank_config": {
"structured_memory_configs": [
{
"schema_configs": [schema_config]
}
]
}
}
}
)
Por padrão, o Memory Bank sempre tenta extrair memórias em linguagem natural. É possível desativar a geração de dados de memória em linguagem natural se você quiser que o Memory Bank gere apenas perfis:
memory_bank = client.agent_engines.create(
config={
"context_spec": {
"memory_bank_config": {
"structured_memory_configs": [
{
"schema_configs": [schema_config]
}
],
# Optional: Disable natural language memories.
"customization_configs": [
{"disable_natural_language_memories": True}
]
}
}
}
)
Geração de perfil
Você aciona a geração de memórias estruturadas fornecendo um histórico de conversas (eventos) aos métodos GenerateMemories ou IngestEvents. Assim como as memórias de linguagem natural, o Memory Bank usa LLMs para extrair informações significativas das fontes de dados e consolidá-las com as memórias atuais.
Exemplo
O exemplo a seguir mostra a geração de perfis de memória usando o esquema definido anteriormente.
No primeiro conjunto de eventos enviados ao Memory Bank para o escopo {"user_id": "123"}, o usuário indica que trabalha com agentes do ADK:
client.agent_engines.memories.generate(
name=memory_bank.api_resource.name,
scope={"user_id": "123"},
direct_contents_source={
"events": [
{"content": {
"parts": [{
"text": "Can you help me build an ADK agent that organizes my daily tasks?"}]}}]
}
)
O Memory Bank extrai "ADK" para o campo technical_stack no esquema. Nenhum outro campo é preenchido porque o evento ingerido não contém informações relevantes para o restante do esquema. Como essa é a primeira interação para esse escopo, a consolidação é ignorada, e o perfil é inicializado com esse valor inicial.
result = client.agent_engines.memories.retrieve_profiles(
name=memory_bank.api_resource.name,
scope={"user_id": "123"},
)
"""
Returns:
RetrieveProfilesResponse(
profiles={
'user-profile': MemoryProfile(
profile={
'technical_stack': 'ADK'
},
schema_id='user-profile'
)
}
)
"""
No próximo conjunto de eventos enviados ao Memory Bank, o usuário indica que é estudante e programa principalmente em Python:
client.agent_engines.memories.generate(
name=memory_bank.api_resource.name,
scope={"user_id": "123"},
direct_contents_source={
"events": [
{"content": {
"parts": [
{"text": "Do you have any career recommendations for students that specialize in Python?"}]}}]
}
)
O Memory Bank extrai "Python" e o status "estudante" da interação. O fragmento technical_stack é consolidado, anexando "Python" à entrada "ADK" existente. O sistema preenche o campo job_status, que estava vazio, com a enumeração "student" e pula a etapa de consolidação.
result = client.agent_engines.memories.retrieve_profiles(
name=memory_bank.api_resource.name,
scope=scope
)
"""
Returns:
RetrieveProfilesResponse(
profiles={
'user-profile': MemoryProfile(
profile={
'technical_stack': 'ADK, Python',
'job_status': 'student'
},
schema_id='user-profile'
)
}
)
"""
Recuperação de perfil
Depois de gerado, é possível recuperar o perfil consolidado para um escopo específico usando o método RetrieveProfiles. Isso retorna os dados mais atualizados mapeados para seu esquema.
result = client.agent_engines.memories.retrieve_profiles(
name=memory_bank.api_resource.name,
scope={"user_id": "123"},
)
# Accessing the data
for profile in result.profiles.values():
print(profile)
# Output: {'technical_stack': 'ADK, Python', 'job_status': 'student', ...}
Inspeção de perfil
Internamente, um perfil é composto de recordações individuais do tipo STRUCTURED_PROFILE. Cada campo no seu esquema é mapeado para uma única memória por escopo, permitindo uma observabilidade granular.
Embora RetrieveProfiles seja o método principal para recuperação de perfis em produção, é possível inspecionar memórias individuais para auditar a evolução do perfil. Isso dá acesso a:
- Metadados no nível do campo: veja e atualize o time to live (TTL) e
Memory.metadataespecíficos para campos individuais no perfil. - Histórico de revisões: rastreie a linhagem de um campo para conferir valores históricos e o contexto específico da conversa que acionou cada mudança.
Por exemplo, você pode usar RetrieveMemories para recuperar todas as recordações que contêm fragmentos do perfil de um usuário. Por padrão, o RetrieveMemories só recupera memórias em linguagem natural. Portanto, você precisa solicitar explicitamente as memórias de STRUCTURED_PROFILE:
client.agent_engines.memories.retrieve(
name="...",
scope={"user_id": "123"},
config={
"memory_types": ["STRUCTURED_PROFILE"]
}
)
"""
Returns:
[RetrieveMemoriesResponseRetrievedMemory(
memory=Memory(
create_time=datetime.datetime(...),
memory_type=<MemoryType.STRUCTURED_PROFILE: 'STRUCTURED_PROFILE'>,
name='projects/.../locations/.../reasoningEngines/.../memories/...',
scope={
'user_id': '1'
},
structured_content=MemoryStructuredContent(
data={
'technical_stack': 'ADK, Python'
},
schema_id='user'
),
update_time=datetime.datetime(...)
)
)]
"""
Em seguida, recupere o histórico de revisões desse fragmento de perfil estruturado para inspecionar como o campo do perfil mudou ao longo do tempo e o contexto de cada uma dessas mudanças:
for retrieved_memory in list(results):
list(client.agent_engines.memories.revisions.list(
name=retrieved_memory.memory.name
))
"""
Returns:
[MemoryRevision(
create_time=datetime.datetime(...),
expire_time=datetime.datetime(...),
extracted_memories=[
IntermediateExtractedMemory(
context='The user indicated that they have expertise in Python when asking about career options.',
structured_data={
'technical_stack': 'Python'
}
),
],
name='projects/.../locations/.../reasoningEngines/.../memories/.../revisions/...',
structured_data={
'technical_stack': 'ADK, Python'
}
),
MemoryRevision(
create_time=datetime.datetime(...),
expire_time=datetime.datetime(...),
extracted_memories=[
IntermediateExtractedMemory(
context='The user indicated that they need help building an ADK agent',
structured_data={
'technical_stack': 'ADK'
}
),
],
name='projects/.../locations/.../reasoningEngines/.../memories/.../revisions/...',
structured_data={
'technical_stack': 'ADK'
}
)]
"""