記憶體設定檔

您可以使用 Memory Bank 生成結構化設定檔,這類資料結構會使用 LLM 填入及更新靜態結構定義。定義固定結構定義後,代理程式就能立即存取不斷變化的資訊,且延遲時間很短,不必在工作階段期間執行耗費資源的搜尋作業。

如要完成本指南中示範的步驟,請先按照「設定 Memory Bank」中的步驟操作。

總覽

在代理程式中使用結構化設定檔,可確保快速、簡潔地以一致的格式提供擷取的資訊,例如使用者的技術堆疊或偏好設定。舉例來說,您可以擷取包含下列內容的設定檔:

MemoryProfile(
    profile={
        "technical_stacks": "ADK, Python",
        "preferred_language": "Python",
        "tone_preference": "Succinct"
    },
    schema_id="user-profile"
)

結構化設定檔經過最佳化調整,可縮短擷取延遲時間,因為資訊的策劃工作是在生成時完成。非常適合用來啟動代理程式與使用者之間的互動。

瞭解結構化記憶體設定檔

系統會使用與自然語言記憶相同的生成方法 (GenerateMemoriesIngestEvents) 生成結構化設定檔。定義結構定義後,Memory Bank 會使用提供的資料來源,自動產生符合結構定義的設定檔。

使用結構化設定檔時,Memory Bank 會在記憶生成期間執行下列作業:

  • 擷取:從資料來源擷取符合結構定義的資訊和脈絡。系統只會擷取符合結構定義的資訊。您可以使用記憶體修訂版本檢查擷取的資訊和脈絡。
  • 合併:視需要更新商家檔案中的現有欄位。LLM 會根據新擷取的資訊和脈絡,判斷如何更新現有內容。如果設定檔中沒有這個欄位,系統會略過合併程序,直接以擷取的資訊更新欄位。

系統會根據您將資料擷取至 Memory Bank 時提供的 scope (例如 {"user_id": "123"}) 隔離設定檔。針對每個結構定義和範圍,Memory Bank 會維護單一設定檔做為可靠資料來源。產生的設定檔包含一或多個 Memory 執行個體。每個 Memory 執行個體都代表設定檔中的單一欄位,可用於檢查欄位的中繼資料和修訂版本記錄,例如:

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={...}
)

結構定義

Memory Bank 生成的設定檔會與建立或更新 Agent Platform 執行個體時定義的結構定義保持一致。您可以使用 pydantic 模型定義要讓 Memory Bank 擷取及維護的欄位。例如:

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")

建立或更新 Agent Platform 執行個體時,請將結構定義上傳至 Memory Bank。您可以定義多個獨立的設定檔結構定義,每個結構定義都必須有專屬 ID:

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]
                    }
                ]
            }
        }
    }
)

根據預設,Memory Bank 一律會嘗試擷取自然語言記憶。如果您只希望 Memory Bank 生成設定檔,可以停用自然語言記憶生成功能:

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}
                ]
            }
        }
    }
)

產生設定檔

您可以使用 GenerateMemoriesIngestEvents 方法提供對話記錄 (事件),觸發產生結構化記憶。與自然語言記憶體一樣,Memory Bank 會使用 LLM 從資料來源擷取有意義的資訊,並與現有記憶體合併。

範例

以下範例逐步說明如何使用先前定義的結構定義產生記憶體設定檔。

在傳送至 Memory Bank 的第一組範圍 {"user_id": "123"} 事件中,使用者表示他們使用 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?"}]}}]
  }
)

Memory Bank 會為結構定義中的「ADK」technical_stack 欄位擷取「ADK」。由於擷取的事件不含其餘結構定義的相關資訊,因此系統不會填入其他欄位。由於這是這個範圍的首次互動,系統會略過整併作業,並以這個初始值初始化設定檔。

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'
    )
  }
)
"""

在下一組傳送至 Memory Bank 的事件中,使用者表示自己是學生,主要使用 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?"}]}}]
  }
)

Memory Bank 會從互動中擷取「Python」和「學生」狀態。系統會合併 technical_stack 片段,並在現有的「ADK」項目中附加「Python」。系統會以「student」列舉填入先前空白的 job_status 欄位,並略過合併步驟。

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'
    )
  }
)
"""

擷取設定檔

產生後,您可以使用 RetrieveProfiles 方法,擷取特定範圍的合併設定檔。這會傳回對應至結構定義的最新資料。

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', ...}

商家檔案檢查

在幕後,設定檔是由 STRUCTURED_PROFILE 類型的個別記憶體組成。結構定義中的每個欄位都會對應至每個範圍的單一記憶體,方便進行精細的觀測能力。

雖然 RetrieveProfiles 是擷取個人資料的主要方法,但您可以檢查個別記憶體,稽核個人資料的演變過程。這項功能可存取:

  • 欄位層級中繼資料:查看及更新設定檔中個別欄位的特定存留時間 (TTL) 和 Memory.metadata
  • 修訂記錄:追蹤欄位的歷程,查看歷史值和觸發每次變更的特定對話內容。

舉例來說,您可以使用 RetrieveMemories 擷取所有含有使用者個人資料片段的回憶。根據預設,RetrieveMemories 只會擷取自然語言記憶,因此您需要明確要求 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(...)
   )
 )]
"""

接著,您可以擷取這個結構化設定檔片段的修訂版本記錄,檢查設定檔欄位隨時間的變化,以及每次變更前後的脈絡:

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'
   }
 )]
"""