Next '26 개발자 기조연설: 메모리로 에이전트 개선

1. 소개

이 Codelab에서는 지속적이고 전문적인 지식을 추가하여 ADK 에이전트를 한 단계 업그레이드합니다. Agent Platform 세션으로 대화 상태를 관리하고, 메모리 뱅크로 장기 학습을 사용 설정하고, Spark 및 AlloyDB를 사용하여 RAG (검색 증강 생성)를 위한 복잡한 도시 규칙 데이터를 통합하는 방법을 알아봅니다.

실습할 내용

  • 대화 지속성을 위해 Agent Platform 세션 을 구성합니다.
  • 에이전트가 이전 상호작용에서 학습할 수 있도록 메모리 뱅크 를 구현합니다.
  • Spark Lightning Engine 을 사용하여 도시 규칙 문서를 수집하고 처리합니다.
  • AlloyDB 및 벡터 검색을 사용하여 RAG 시스템을 빌드합니다.
  • 향상된 에이전트를 Agent Platform에 배포합니다.

필요한 항목

예상 소요 시간: 60분

이 Codelab에서 만든 리소스의 비용은 $5 미만이어야 합니다.

2. 시작하기 전에

Google Cloud 프로젝트 만들기

  1. Google Cloud 콘솔의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.
  2. Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다. 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요.

Cloud Shell 시작

Cloud Shell 은 Google Cloud에서 실행되는 명령줄 환경으로, 필요한 도구가 사전 로드되어 있습니다.

  1. Google Cloud 콘솔 상단에서 Cloud Shell 활성화 를 클릭합니다.
  2. Cloud Shell에 연결되면 인증을 확인합니다.
    gcloud auth list
    
  3. 프로젝트가 구성되었는지 확인합니다.
    gcloud config get project
    
  4. 프로젝트가 예상대로 설정되지 않은 경우 설정합니다.
    export PROJECT_ID=<YOUR_PROJECT_ID>
    gcloud config set project $PROJECT_ID
    

인증 확인:

gcloud auth list

프로젝트 확인:

gcloud config get project

필요한 경우 설정:

export PROJECT_ID=<YOUR_PROJECT_ID>
gcloud config set project $PROJECT_ID

API 사용 설정

이 명령어를 실행하여 세션 관리, Spark 처리, AlloyDB에 필요한 모든 API를 사용 설정합니다.

gcloud services enable \
  aiplatform.googleapis.com \
  run.googleapis.com \
  alloydb.googleapis.com \
  dataproc.googleapis.com \
  documentai.googleapis.com \
  storage.googleapis.com \
  secretmanager.googleapis.com

3. 환경 설정

이 Codelab에서는 키노트 저장소의 사전 구성된 환경을 사용합니다.

  1. 저장소를 클론하고 프로젝트 폴더로 이동합니다.
git clone https://github.com/GoogleCloudPlatform/next-26-keynotes
cd next-26-keynotes/devkey/enhancing-agents-with-memory
  1. Python 가상 환경을 설정하고 필요한 ADK 패키지를 설치합니다.
uv venv
source .venv/bin/activate
uv sync

환경 변수 구성

에이전트가 Agent Platform 및 AlloyDB에 연결하려면 특정 구성이 필요합니다.

  1. 샘플 환경 파일을 복사합니다.
cp .env.example .env
  1. .env를 열고 다음 필드를 업데이트합니다.
    • GOOGLE_CLOUD_PROJECT: 프로젝트 ID입니다.
    • GOOGLE_CLOUD_LOCATION: us-central1입니다.
    • ALLOYDB_CLUSTER_ID: rules-db입니다.
GOOGLE_CLOUD_PROJECT=<YOUR_PROJECT_ID>
GOOGLE_CLOUD_LOCATION=global
GOOGLE_GENAI_USE_VERTEXAI=TRUE
GOOGLE_CLOUD_REGION=us-central1
ALLOYDB_CLUSTER_ID=rules-db
  1. 다음 도우미 스크립트를 실행하여 대화 세션 및 장기 메모리에 사용할 Agent Engine 인스턴스 를 만듭니다. 이렇게 하면 .env 파일의 AGENT_ENGINE_ID가 자동으로 채워집니다.
uv run utils/setup_agent_engine.py

성공하면 다음이 표시됩니다.

Creating Agent Engine instance...
Successfully created Agent Engine. ID: 1234567890
Updated .env with AGENT_ENGINE_ID=1234567890

4. 세션 관리로 에이전트 만들기

이 단계에서는 여러 차례에 걸쳐 대화 기록을 유지할 수 있는 마라톤 플래너 에이전트 를 초기화합니다. 이는 ADK App 클래스와 Agent Platform 세션 을 사용하여 이루어집니다.

에이전트 및 세션 서비스 초기화

planner_agent/agent.py를 엽니다. Agent Platform 세션 을 통합하기 위해 ADK 클래스를 추가하는 방법을 확인할 수 있습니다. 이를 통해 시간이 지남에 따라 에이전트를 상태 저장으로 만들고 필요에 따라 컨텍스트를 수정할 수 있습니다.

from google.adk.agents import LlmAgent
from google.adk.sessions import VertexAiSessionService
from vertexai.agent_engines import AdkApp

PROJECT_ID = os.environ.get("GOOGLE_CLOUD_PROJECT")
REGION = os.environ.get("GOOGLE_CLOUD_REGION", "us-central1")

# Initialize Vertex AI for regional services
if PROJECT_ID:
    vertexai.init(project=PROJECT_ID, location=REGION)

# Define the agent logic
root_agent = LlmAgent(
    name="planner_agent",
    model="gemini-3-flash-preview",
    instruction="You are a helpful marathon planning assistant...",
    tools=[] # We will add tools in the next steps
)

def session_service_builder():
    """Builder for Agent Platform Sessions."""
    return VertexAiSessionService(project=PROJECT_ID, location=REGION)

# Wrap the agent in an AdkApp to manage stateful context
app = AdkApp(
    agent=root_agent,
    session_service_builder=session_service_builder
)

5. 메모리 뱅크로 장기 학습 사용 설정

세션 관리는 개별 대화를 추적하지만 장기 메모리에서도 동일한 작업을 할 수 있습니다. 이 단계에서는 에이전트를 엔터프라이즈 지원 및 완전 관리형 메모리 서비스인 Agent Platform의 메모리 뱅크에 연결합니다.

메모리 뱅크 서비스 초기화

메모리 뱅크를 사용하면 에이전트가 여러 세션에서 컨텍스트를 다시 호출할 수 있습니다. 메모리 서비스를 포함하도록 planner_agent/agent.py를 업데이트합니다.

from google.adk.memory import VertexAiMemoryBankService

def memory_service_builder():
    """Builder for Agent Platform Memory Bank."""
    return VertexAiMemoryBankService(
        project=PROJECT_ID,
        location=REGION,
        agent_engine_id=AGENT_ENGINE_ID
    )

자동 메모리 수집 구현

에이전트가 모든 턴에서 학습하도록 하려면 after_agent_callback을 추가합니다. 이 함수는 에이전트가 응답을 완료한 후에 트리거되므로 세션을 '소화'하고 관련 메모리를 뱅크에 저장할 수 있습니다.

  1. 콜백 함수를 정의합니다.
async def auto_save_memories(callback_context):
    """Callback to ingest the session into the memory bank after the turn."""
    # In AdkApp, the memory service is available via the invocation context
    if hasattr(callback_context._invocation_context, 'memory_service') and callback_context._invocation_context.memory_service:
        await callback_context._invocation_context.memory_service.add_session_to_memory(
            callback_context._invocation_context.session
        )
  1. 콜백을 LlmAgent에 연결합니다.
root_agent = LlmAgent(
    # ... other params
    after_agent_callback=[auto_save_memories],
)

6. RAG용 AlloyDB 설정

도시 규칙 데이터를 수집하려면 먼저 이를 저장할 고성능 데이터베이스가 필요합니다. 이 단계에서는 AlloyDB 클러스터를 만들고 벡터 검색을 위한 데이터베이스 스키마를 초기화합니다.

1. AlloyDB 클러스터 및 기본 인스턴스 만들기

Cloud Shell에서 다음 명령어를 실행하여 클러스터와 기본 인스턴스를 만듭니다.

# Create the cluster
gcloud alloydb clusters create rules-db \
  --password=postgres \
  --region=us-central1

# Create the primary instance with IAM authentication enabled
gcloud alloydb instances create rules-db-primary \
  --instance-type=PRIMARY \
  --cpu-count=2 \
  --region=us-central1 \
  --cluster=rules-db \
  --database-flags=alloydb.iam_authentication=on

2. 필수 IAM 역할 부여

관리형 AlloyDB MCP 서버를 사용하려면 ID에 특정 권한이 필요합니다. 다음 명령어를 실행하여 필요한 역할을 부여합니다.

export USER_EMAIL=$(gcloud config get-value account)

# Role to use MCP tools
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="user:$USER_EMAIL" \
  --role="roles/mcp.toolUser"

# Role to execute SQL in AlloyDB
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="user:$USER_EMAIL" \
  --role="roles/alloydb.admin"

# Role for IAM database authentication
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="user:$USER_EMAIL" \
  --role="roles/alloydb.databaseUser"

# Create the IAM-based database user
gcloud alloydb users create "$USER_EMAIL" \
  --cluster=rules-db \
  --region=us-central1 \
  --type=IAM_BASED

3. AlloyDB Studio를 통해 데이터베이스 및 테이블 만들기

AlloyDB 데이터베이스와 테이블은 SQL을 통해 관리되므로 Google Cloud 콘솔에서 AlloyDB Studio 를 사용하여 스키마를 완료합니다.

  1. AlloyDB > 클러스터 로 이동하여 rules-db를 클릭합니다.
  2. 왼쪽 탐색 메뉴에서 AlloyDB Studio 를 클릭합니다.
  3. postgres 사용자 및 설정한 비밀번호 (postgres)를 사용하여 로그인합니다.
  4. 다음 SQL을 실행하여 데이터베이스를 만듭니다.
    CREATE DATABASE city_rules;
    
  5. AlloyDB Studio에서 데이터베이스 연결을 city_rules로 전환하고 다음 SQL을 실행하여 확장 프로그램을 설치하고 rules 테이블을 만듭니다.
    -- Install extensions for vector search and ML
    CREATE EXTENSION IF NOT EXISTS vector;
    CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
    
    -- Create the rules table
    CREATE TABLE IF NOT EXISTS rules (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        text TEXT NOT NULL,
        city TEXT NOT NULL,
        embedding vector(3072) DEFAULT NULL
    );
    
    -- Grant your IAM user access to the table (replace with your email)
    GRANT ALL PRIVILEGES ON TABLE rules TO "YOUR_EMAIL_ADDRESS";
    

7. Spark Lightning Engine으로 도시 규칙 데이터 수집

정말 정확한 계획을 제공하려면 에이전트에게 잘 만들어진 프롬프트뿐만 아니라 데이터 및 조직 컨텍스트에 대한 그라운딩 이 필요합니다. 이 단계에서는 Dataproc Serverless에서 Spark Lightning Engine 을 사용하여 대규모 도시 규칙 PDF를 처리하고 AlloyDB로 수집합니다.

Spark Lightning Engine을 사용해야 하는 이유

대규모로 에이전트를 그라운딩하려면 대량의 비정형 데이터를 처리해야 합니다. Spark Lightning Engine 은 Spark의 고성능 실행 엔진으로, 이러한 워크로드를 크게 가속화합니다. 여기서는 Google의 Document AI 를 사용하여 문서에 시맨틱 청킹 을 실행하는 데 사용합니다.

Spark 파이프라인 살펴보기

수집 로직은 spark-setup/spark_alloydb_processor.py에 정의되어 있습니다. 파이프라인은 다음 단계를 따릅니다.

  1. PDF 나열: Google Cloud Storage 버킷에서 문서 URI를 가져옵니다.
  2. 시맨틱 추출: UDF (사용자 정의 함수)를 사용하여 Document AI API를 호출합니다.
  3. AlloyDB에 쓰기: 추출된 텍스트 청크를 rules라는 AlloyDB 테이블에 저장합니다.
# Extract from spark_alloydb_processor.py
def process_document(gcs_uri: str):
    # ... calls Document AI to parse PDF ...
    return chunks

# Parallel processing with Spark Lightning Engine
process_udf = udf(process_document, chunk_schema)
chunked_df = uri_df.withColumn("chunks", process_udf(col("gcs_uri"))) \
                   .select(explode(col("chunks")).alias("chunk")) \
                   .select("chunk.*")

# Save to AlloyDB for Vector Search
chunked_df.write.format("jdbc") \
    .option("url", jdbc_url) \
    .option("dbtable", "rules") \
    .mode("append") \
    .save()

수집 작업 실행

제공된 스크립트를 사용하여 수집 프로세스를 트리거합니다.

./spark-setup/run_dataproc.sh

8. AlloyDB를 사용한 RAG

이제 도시 규칙 데이터가 AlloyDB에 있으므로 에이전트가 이를 사용하여 검색 증강 생성 (RAG) 을 실행할 수 있습니다. 이렇게 하면 마라톤 계획이 특정 도시 코드를 준수합니다.

RAG용 AlloyDB의 강력한 기능

AlloyDB는 벡터 검색에 탁월하므로 구조화된 데이터와 벡터 임베딩을 모두 같은 위치에 저장할 수 있습니다. 에이전트는 AlloyDB의 기본 제공 embedding 함수를 사용하여 가장 관련성이 높은 규칙 정보를 찾을 수 있습니다.

에이전트가 이 데이터에 액세스할 수 있도록 벡터 유사성을 사용하여 AlloyDB를 쿼리하는 도구를 제공합니다. 쿼리와 저장된 규칙 간의 거리를 계산하는 방법을 보여주는 hybrid_recall.sql에서 이 로직을 확인할 수 있습니다.

SELECT
    text,
    (embedding <=> 
     embedding('gemini-embedding-001', 
               'Restrictions for running a race on the Las Vegas strip')::vector) 
    as distance
FROM
    rules
WHERE city = 'Las Vegas'
ORDER BY
    distance ASC
LIMIT 5;

RAG 도구로 현지 규칙에 에이전트 기반

에이전트가 도구를 사용할 수 있도록 하려면 planner_agent/tools.py에서 도구를 정의한 다음 planner_agent/agent.py에 등록해야 합니다. Google Cloud의 관리형 원격 AlloyDB MCP 서버 를 사용하여 데이터베이스에 연결합니다.

  1. '하이브리드 재호출' 패턴을 사용하여 planner_agent/tools.py에서 도구를 정의합니다. streamable_http 프로토콜을 사용하여 관리형 AlloyDB MCP 서버에 연결합니다.
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async def get_local_and_traffic_rules(query: str) -> str:
    """Uses vector search in AlloyDB via managed MCP server."""
    # Vector search query using built-in AlloyDB embedding functions
    sql = f"SELECT text FROM rules WHERE city = 'Las Vegas' ORDER BY embedding <=> google_ml.embedding('gemini-embedding-001', '{query}')::vector ASC LIMIT 5;"
    
    # Establish a streamable HTTP connection to the MCP server
    async with streamablehttp_client(url, headers=get_auth_headers()) as (read_stream, write_stream, _):
        async with ClientSession(read_stream, write_stream) as session:
            await session.initialize()
            result = await session.call_tool(
                "execute_sql",
                arguments={
                    "instance": full_instance_name,
                    "database": "city_rules",
                    "sqlStatement": sql
                }
            )
            return "\n".join([c.text for c in result.content if hasattr(c, 'text')])
  1. 도구를 등록하고 planner_agent/agent.py를 완료합니다.
# ... imports ...

# Assemble the Agent
root_agent = LlmAgent(
    name="planner_agent",
    model="gemini-3-flash-preview",
    instruction="You are a helpful marathon planning assistant...",
    tools=[
        get_local_and_traffic_rules,
    ],
    after_agent_callback=[auto_save_memories],
)

# 2. Wrap the agent in an AdkApp to manage the stateful lifecycle
app = AdkApp(
    agent=root_agent,
    session_service_builder=session_service_builder,
    memory_service_builder=memory_service_builder
)

9. 에이전트 기술을 사용한 전문가 가이던스

에이전트 기술 은 에이전트가 작업을 더 효과적으로 수행할 수 있도록 특정 안내, 가이던스, 리소스를 제공하는 자체 포함 모듈입니다. 모든 도구에 대한 복잡한 안내로 시스템 프롬프트를 어수선하게 만드는 대신 필요할 때만 로드되는 기능으로 전문 지식을 캡슐화할 수 있습니다.

Google은 에이전트가 데이터 쿼리 및 리소스 관리에 관한 업계 권장사항을 따르도록 Google 제품용 사전 빌드된 기술 (예: AlloyDB 및 BigQuery)을 제공합니다. Google Skills Depot에서 이러한 기술과 기타 전문 패턴을 살펴볼 수 있습니다. 여기에서 AlloyDB 기본 기술을 확인할 수 있습니다.

1. 기술 파일 살펴보기

planner_agent/skills/get-local-and-traffic-rules/SKILL.md에서 사전 구성된 기술 파일을 엽니다. 다음과 같이 표시됩니다.

---
name: get-local-and-traffic-rules
description: Retrieve local rules and traffic information for a specific jurisdiction.
---
# get_local_and_traffic_rules Skill

This skill provides guidelines on how to effectively use the `get_local_and_traffic_rules` tool.

## Overview
The `get_local_and_traffic_rules` tool interfaces with an AlloyDB database to perform vector similarity searches on a corpus of rules and traffic information using a provided natural language query.

## Usage Guidelines
1. **Query Specificity**: When calling the tool, provide specific details in the `query` argument. For example, instead of querying "food rules", use "rules regarding food vendors during public events".
2. **Contextual Use**: Use the tool when planning events or activities that require adherence to local municipal or state rules (e.g., street closures, noise ordinances, environmental rules).
3. **Handling Results**: The tool returns a string containing the text of the top 5 most relevant rules. If no error occurs, parse the returned string to inform your planning tasks.
4. **Error Handling**: If an error string is returned (e.g., "Error querying rules: ..."), you must report this failure or attempt an alternative approach if applicable.

## Underlying Mechanism
- The tool uses `google_ml.embedding` to convert the query into a vector representation.
- It calculates distance (`<=>`) against the `embedding` column in the `rules` table on an AlloyDB instance.
- Results are fetched in descending order of similarity, limited to 5 results.

2. 기술 등록 방법

planner_agent/agent.py에서 기술은 디렉터리에서 로드되어 에이전트의 도구에 추가됩니다. 코드는 다음과 같습니다.

import pathlib
from google.adk.skills import load_skill_from_dir
from google.adk.tools import skill_toolset

# Load the AlloyDB skill from its directory
alloydb_skill = load_skill_from_dir(pathlib.Path(__file__).parent / "skills" / "get-local-and-traffic-rules")

# Assemble the Agent with the Skill Toolset
root_agent = LlmAgent(
    name="planner_agent",
    model="gemini-3-flash-preview",
    instruction="You are a helpful marathon planning assistant...",
    tools=[
        get_local_and_traffic_rules,
        skill_toolset.SkillToolset(skills=[alloydb_skill])
    ],
    after_agent_callback=[auto_save_memories],
)

10. 에이전트 테스트

  1. 에이전트를 로컬에서 시작합니다.
uv run adk run planner_agent
  1. 도시 규칙에 관한 질문을 합니다. [user]: What are the rules for running a race on the Las Vegas strip?

에이전트는 get_local_and_traffic_rules 도구를 호출하고 AlloyDB에서 벡터 검색을 실행하며 Spark에서 처리한 공식 규칙 청크를 기반으로 답변을 반환합니다.

11. 에이전트 배포

Agent Platform에 배포

uv run adk deploy agent_engine \
  --env_file .env \
  planner_agent

12. 정리

지속적인 요금이 발생하지 않도록 하려면 이 Codelab 중에 만든 리소스를 삭제합니다.

AlloyDB 클러스터 삭제

# Delete the AlloyDB Cluster
gcloud alloydb clusters delete rules-db --region=us-central1 --force

에이전트 런타임 앱 삭제

콘솔을 통해 또는 gcloud 명령어 (리소스 이름이 있는 경우)를 사용하여 추론 엔진 인스턴스를 삭제할 수 있습니다. 간단히 콘솔을 사용합니다.

  1. 에이전트 런타임 페이지로 이동합니다.
  2. planner_agent를 선택하고 오른쪽의 점 3개 버튼을 클릭합니다.
  3. 삭제 를 클릭합니다.

13. 축하합니다

축하합니다. 고급 메모리 및 데이터 그라운딩 기능을 사용하여 ADK 에이전트를 성공적으로 개선했습니다.

학습한 내용

  • 상태 저장 에이전트: 대화 컨텍스트를 유지하기 위해 Agent Platform 세션을 통합합니다.
  • 장기 학습: 에이전트가 사용자 상호작용에서 학습할 수 있도록 Agent Platform 메모리 뱅크를 연결합니다.
  • 데이터 수집: Spark Lightning EngineDocument AI 를 사용하여 구조화되지 않은 문서를 처리합니다.
  • RAG: AlloyDB 에서 벡터 검색 시스템을 빌드하여 에이전트를 실제 규칙에 기반합니다.

다음 단계