メモリ プロファイル

Memory Bank を使用すると、LLM を使用して入力および更新される静的スキーマを持つデータ構造である構造化プロファイルを生成できます。固定スキーマを定義することで、セッション中に高コストの検索オペレーションを行うことなく、エージェントが進化する情報に即座に低レイテンシでアクセスできるようにします。

このガイドで説明する手順を完了するには、まず メモリバンクの設定の手順に沿って操作する必要があります。

概要

エージェントで構造化プロファイルを使用すると、ユーザーの技術スタックや好みなどの抽出された情報を、迅速かつ簡潔に、一貫した形式で利用できます。たとえば、次のようなコンテンツを含むプロファイルを取得できます。

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

構造化プロファイルは、情報のキュレーションという大変な作業が生成時に行われるため、低レイテンシでの取得に最適化されています。エージェントとユーザーの対話の初期化に最適です。

構造化メモリ プロファイルについて

構造化プロファイルは、自然言語メモリに使用するのと同じメソッド(GenerateMemoriesIngestEvents)を使用して生成されます。スキーマを定義すると、メモリバンクは、提供されたデータソースを使用して、スキーマに沿ったプロファイルの生成を自動的に試みます。

構造化プロファイルを使用する場合、メモリバンクはメモリーの生成中に次のオペレーションを実行します。

  • 抽出: スキーマに適合する情報とコンテキストをデータソースから抽出します。スキーマに沿った情報のみが抽出されます。抽出された情報とコンテキストは、メモリ リビジョンを使用して確認できます。
  • 統合: プロファイルの既存のフィールドを更新します(必要な場合)。LLM は、新しく抽出された情報とコンテキストに基づいて、既存のコンテンツを更新する方法を判断します。フィールドがプロファイルにまだ存在しない場合、統合はスキップされ、抽出された情報でフィールドが直接更新されます。

プロファイルは、メモリバンクにデータを取り込むときに指定した scope{"user_id": "123"} など)に基づいて分離されます。スキーマとスコープごとに、メモリバンクは信頼できる唯一の情報源として単一のプロファイルを保持します。生成されたプロファイルは、1 つ以上の 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={...}
)

スキーマ定義

メモリバンク が生成するプロファイルは、Agent Platform インスタンスの作成時または更新時に定義されたスキーマに沿っていますpydantic モデルを使用して、メモリバンクで抽出して維持するフィールドを定義できます。次に例を示します。

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 インスタンスを作成または更新するときに、スキーマをメモリバンクにアップロードします。複数の独立したプロファイル スキーマを定義できます。各スキーマは一意の ID で識別する必要があります。

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

デフォルトでは、メモリバンクは常に自然言語メモリの抽出を試みます。Memory Bank でプロファイルのみを生成する場合は、自然言語メモリの生成を無効にできます。

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

プロファイルの生成

構造化メモリの生成をトリガーするには、会話履歴(イベント)をGenerateMemoriesまたはIngestEventsメソッドに提供します。自然言語メモリと同様に、メモリバンクは LLM を使用してデータソースから意味のある情報を抽出し、既存のメモリと統合します。

次の例では、事前に定義したスキーマを使用してメモリ プロファイルを生成する手順について説明します。

スコープ {"user_id": "123"} のメモリバンクに送信される最初のイベント セットで、ユーザーは 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?"}]}}]
  }
)

メモリバンクは、スキーマの technical_stack フィールドに「ADK」を抽出します。取り込まれたイベントにスキーマの残りの部分に関連する情報が含まれていないため、他のフィールドは入力されません。これはこのスコープの最初の対話であるため、統合はスキップされ、プロファイルはこの初期値で初期化されます。

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

Memory Bank に送信される次のイベント セットで、ユーザーは学生であり、主に 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?"}]}}]
  }
)

メモリバンクは、対話から「Python」と「学生」の両方のステータスを抽出します。technical_stack フラグメントが統合され、既存の「ADK」エントリに「Python」が追加されます。システムは、以前は空だった job_status フィールドに「student」列挙型を入力し、統合ステップをスキップします。

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

プロファイルの取得

生成されたら、RetrieveProfiles メソッドを使用して、特定のスコープの統合プロファイルを取得できます。これにより、スキーマにマッピングされた最新のデータが返されます。

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

プロファイルの検査

プロファイルは、内部的には 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'
   }
 )]
"""