Puoi utilizzare Memory Bank per generare profili strutturati, ovvero strutture di dati con schemi statici compilati e aggiornati utilizzando gli LLM. Definendo uno schema fisso, ti assicuri che i tuoi agenti abbiano accesso immediato e a bassa latenza alle informazioni in evoluzione senza la necessità di costose operazioni di ricerca durante una sessione.
Per completare i passaggi illustrati in questa guida, devi prima seguire i passaggi descritti in Configurare Memory Bank.
Panoramica
L'utilizzo di profili strutturati con il tuo agente garantisce che le informazioni estratte, come gli stack tecnici o le preferenze di un utente, siano disponibili in modo rapido, conciso e con un formato coerente. Ad esempio, puoi recuperare profili che includono contenuti come:
MemoryProfile(
profile={
"technical_stacks": "ADK, Python",
"preferred_language": "Python",
"tone_preference": "Succinct"
},
schema_id="user-profile"
)
I profili strutturati sono ottimizzati per il recupero a bassa latenza, perché il lavoro di cura delle informazioni viene eseguito al momento della generazione. Sono ideali per inizializzare un'interazione tra un agente e un utente.
Informazioni sui profili di memoria strutturati
I profili strutturati vengono generati tramite gli stessi metodi (GenerateMemories e IngestEvents) utilizzati per i ricordi in linguaggio naturale. Dopo aver definito uno schema, Memory Bank tenterà automaticamente di generare profili in linea con lo schema utilizzando le origini dati fornite.
Quando utilizzi i profili strutturati, Memory Bank esegue le seguenti operazioni durante il salvataggio di informazioni:
- Estrazione: estrae le informazioni e il contesto che corrispondono allo schema dall'origine dati. Vengono estratte solo le informazioni in linea con lo schema. Puoi controllare le informazioni e il contesto estratti utilizzando le revisioni dei ricordi.
- Consolidamento: aggiorna (se necessario) i campi esistenti nel profilo. Un LLM valuterà come aggiornare i contenuti esistenti in base alle informazioni e al contesto appena estratti. Se il campo non esiste già nel profilo, il consolidamento viene ignorato e il campo viene aggiornato direttamente con le informazioni estratte.
I profili sono isolati in base al scope (come {"user_id": "123"}) fornito durante l'importazione dei dati in Memory Bank. Per ogni schema e ambito, Memory Bank mantiene un singolo profilo come fonte attendibile. Un profilo generato è composto da una o più istanze Memory. Ogni istanza Memory rappresenta un singolo campo all'interno del profilo che puoi utilizzare per controllare i metadati e la cronologia delle revisioni del campo, ad esempio:
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={...}
)
Definizione schema
I profili generati da Memory Bank sono in linea con lo schema definito quando l'istanza di Agent Platform è stata creata o aggiornata. Puoi utilizzare un modello pydantic per definire i campi che vuoi che Memory Bank estragga e mantenga. Ad esempio:
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")
Carica lo schema in Memory Bank quando crei o aggiorni l'istanza di Agent Platform. Puoi definire più schemi di profilo indipendenti; ogni schema deve essere identificato da un ID univoco:
schema_config = {
"id": "user-profile",
"memory_schema": UserProfile.model_json_schema()
}
agent_engine = client.agent_engines.create(
config={
"context_spec": {
"memory_bank_config": {
"structured_memory_configs": [
{
"schema_configs": [schema_config]
}
]
}
}
}
)
Per impostazione predefinita, Memory Bank tenta sempre di estrarre i ricordi in linguaggio naturale. Puoi disattivare il salvataggio di informazioni in linguaggio naturale se vuoi che Memory Bank generi solo profili:
agent_engine = 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}
]
}
}
}
)
Generazione del profilo
Attivi la generazione di ricordi strutturati fornendo una cronologia delle conversazioni (eventi) ai metodi GenerateMemories o IngestEvents. Come per i ricordi in linguaggio naturale, Memory Bank utilizza gli LLM per estrarre informazioni significative dalle origini dati e consolidarle con i ricordi esistenti.
Esempio
L'esempio seguente illustra la generazione di un profilo di memoria utilizzando lo schema definito in precedenza.
Nel primo set di eventi inviati a Memory Bank per l'ambito {"user_id": "123"}, l'utente indica di lavorare con gli agenti ADK:
client.agent_engines.memories.generate(
name=agent_engine.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?"}]}}]
}
)
Memory Bank estrae "ADK" per il campo technical_stack nello schema. Nessun altro campo viene compilato perché l'evento importato non contiene informazioni pertinenti per il resto dello schema. Poiché si tratta della prima interazione per questo ambito, il consolidamento viene ignorato e il profilo viene inizializzato con questo valore iniziale.
result = client.agent_engines.memories.retrieve_profiles(
name=agent_engine.api_resource.name,
scope={"user_id": "123"},
)
"""
Returns:
RetrieveProfilesResponse(
profiles={
'user-profile': MemoryProfile(
profile={
'technical_stack': 'ADK'
},
schema_id='user-profile'
)
}
)
"""
Nel set di eventi successivo inviato a Memory Bank, l'utente indica di essere uno studente e di programmare principalmente in Python:
client.agent_engines.memories.generate(
name=agent_engine.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?"}]}}]
}
)
Memory Bank estrae sia "Python" sia lo stato "student" dall'interazione. Il frammento technical_stack viene consolidato, aggiungendo "Python" alla voce "ADK" esistente. Il sistema compila il campo job_status precedentemente vuoto con l'enumerazione "student" e salta il passaggio di consolidamento.
result = client.agent_engines.memories.retrieve_profiles(
name=agent_engine_name,
scope=scope
)
"""
Returns:
RetrieveProfilesResponse(
profiles={
'user-profile': MemoryProfile(
profile={
'technical_stack': 'ADK, Python',
'job_status': 'student'
},
schema_id='user-profile'
)
}
)
"""
Recupero del profilo
Una volta generato, puoi recuperare il profilo consolidato per un ambito specifico utilizzando il metodo RetrieveProfiles. Vengono restituiti i dati più aggiornati mappati allo schema.
result = client.agent_engines.memories.retrieve_profiles(
name=agent_engine.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', ...}
Controllo del profilo
Dietro le quinte, un profilo è composto da singoli ricordi di tipo STRUCTURED_PROFILE. Ogni campo dello schema viene mappato a una singola memoria per ambito, consentendo un'osservabilità granulare.
Sebbene RetrieveProfiles sia il metodo principale per il recupero dei profili in produzione, puoi controllare i singoli ricordi per verificare l'evoluzione del profilo. In questo modo puoi accedere a:
- Metadati a livello di campo: visualizza e aggiorna durata (TTL) specifico e
Memory.metadataper i singoli campi del profilo. - Cronologia delle revisioni: Trace la derivazione di un campo per visualizzare i valori storici e il contesto di conversazione specifico che ha attivato ogni modifica.
Ad esempio, puoi utilizzare RetrieveMemories per recuperare tutti i ricordi contenenti frammenti del profilo di un utente. Per impostazione predefinita, RetrieveMemories recupera solo i ricordi in linguaggio naturale, quindi devi richiedere esplicitamente i ricordi 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(...)
)
)]
"""
Poi, puoi recuperare la cronologia delle revisioni di questo frammento di profilo strutturato per controllare come il campo del profilo è cambiato nel tempo e il contesto di ognuna di queste modifiche:
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'
}
)]
"""