Agentic AI/Google ADK

21. Session/Memory/Artifact [10]- VertexAiMemoryBankService(2/2)

아톨 2026. 10. 31. 17:55

6. 5단계: Agent 객체 생성

이제 에이전트를 만드는 코드입니다.

memory_agent = Agent(
    model=os.getenv("GOOGLE_MODEL", "gemini-3.5-flash"),
    name="memory_agent",
    instruction=(
        "당신은 질문에 성실히 답하는 도움되는 에이전트이며, "
        "질문과 대답은 모두 한글로만 해야 한다."
    ),
    tools=[load_memory],
    after_agent_callback=add_session_to_memory,
)

하나씩 살펴보겠습니다.

6-1. model

model=os.getenv("GOOGLE_MODEL", "gemini-3.5-flash")

에이전트가 사용할 LLM을 지정합니다.

여기서 os.getenv()는 환경변수를 가져오는 Python 함수입니다.

구조는 다음과 같습니다.

os.getenv("환경변수명", "기본값")

따라서 다음과 같은 의미입니다.

  • GOOGLE_MODEL이라는 환경변수가 존재하면 해당 값을 사용합니다.

  • 환경변수가 없으면 gemini-3.5-flash를 사용합니다.

다만 주의할 점이 있습니다.

gemini-3.5-flash라는 모델명이 현재 프로젝트에서 실제 지원되는 모델인지 별도로 확인해야 합니다. 모델명은 ADK 버전과 Vertex AI 모델 제공 상태에 따라 달라질 수 있습니다.

6-2. name

name="memory_agent"

에이전트의 이름입니다.

ADK가 해당 에이전트를 식별할 때 사용하는 이름입니다.

6-3. instruction

instruction=(
    "당신은 질문에 성실히 답하는 도움되는 에이전트이며, "
    "질문과 대답은 모두 한글로만 해야 한다."
)

에이전트의 행동 지침입니다.

여기서는 모든 질문과 답변을 한글로 처리하도록 지시하고 있습니다.

6-4. tools=[load_memory]

tools=[load_memory]

이 부분은 Memory Bank의 검색 기능과 연결됩니다.

앞서 설명한 add_session_to_memory()가 기억을 저장하는 역할이라면, load_memory는 저장된 기억을 검색하는 역할입니다.

두 기능을 비교해 보겠습니다.

기능 역할 사용 시점
add_session_to_memory 대화에서 기억 생성 요청 대화 종료 후
load_memory 기존 기억 검색 대화 중

예를 들어 다음과 같은 상황을 생각해 보겠습니다.

첫 번째 세션

사용자: 나는 Python과 AI Agent 공부를 계속할 생각이야.

대화가 끝나면 콜백이 실행되고 Memory Bank에 기억 생성 요청을 보냅니다.

두 번째 세션

사용자: 내가 요즘 공부하는 분야가 뭐였지?

이때 load_memory가 Memory Bank에 저장된 관련 기억을 검색할 수 있습니다.

검색된 결과를 바탕으로 에이전트가 답변합니다.

여기서 주의할 점이 있습니다.

load_memory를 도구로 등록했다고 해서 모든 대화마다 자동으로 검색되는 것은 아닙니다.

LLM이 해당 도구를 호출하도록 판단해야 합니다.

따라서 더욱 안정적으로 기억을 활용하고 싶다면 다음과 같이 instruction에 검색 지침을 추가할 수 있습니다.

instruction=(
    "당신은 질문에 성실히 답하는 도움되는 에이전트입니다. "
    "질문과 대답은 모두 한글로 해야 합니다. "
    "사용자의 과거 정보나 이전 대화에 관한 질문에는 "
    "load_memory 도구를 사용하여 관련 기억을 먼저 확인하세요."
)

참고로 최신 ADK에는 PreloadMemoryTool이라는 방식도 있습니다. 이것은 매번 모델이 도구 호출 여부를 판단하는 방식과 달리, 대화 시작 시점에 관련 기억을 검색해 에이전트의 문맥에 미리 제공하는 접근입니다.

6-5. after_agent_callback

after_agent_callback=add_session_to_memory

이번 실습의 핵심 연결 지점입니다.

ADK의 Callback 기능을 사용합니다.

after_agent_callback은 에이전트의 실행이 완료된 뒤 실행할 함수를 지정합니다.

즉 다음과 같은 순서가 됩니다.

사용자 질문
    ↓
Agent 실행
    ↓
Gemini가 답변 생성
    ↓
Agent 실행 완료
    ↓
after_agent_callback 실행
    ↓
add_session_to_memory 실행
    ↓
Memory Bank에 세션 전달

여기서 주의할 점이 있습니다.

after_agent_callback은 에이전트 실행이 끝난 뒤 실행되는 콜백이지, 개별 사용자 메시지가 들어올 때마다 무조건 별도의 저장 작업을 수행하는 기능은 아닙니다.

또한 메모리 생성 요청이 성공적으로 접수되었다는 것과 기억 추출이 완료되었다는 것은 구분해야 합니다.

6-6. root_agent

root_agent = memory_agent

ADK가 외부에서 실행할 최상위 에이전트를 지정합니다.

ADK는 에이전트 프로젝트에서 root_agent를 찾아 실행합니다.

따라서 memory_agent를 root_agent에 할당함으로써 이 에이전트가 프로젝트의 진입점이 됩니다.

7. 6단계: ADK 실행 명령어와 Memory Bank 연결

이제 앞에서 만든 에이전트를 실행하는 단계입니다.

실제로 사용한 명령은 다음과 같습니다.

(venv) PS C:\Dev\book_agentic_ai\adk\_>

adk web --port 8080 `
  --memory_service_uri="agentengine://projects/921865052026/locations/asia-northeast3/reasoningEngines/2528612861094133760"

PowerShell에서는 위처럼 줄바꿈할 때 백틱(`)을 사용할 수 있습니다. 한 줄로 입력해도 됩니다.

이 명령어를 구성 요소별로 나누어 보겠습니다.

7-1. adk web

adk web

ADK의 웹 개발 서버를 실행합니다.

브라우저에서 에이전트와 대화하고 테스트할 수 있는 개발 환경을 제공합니다.

7-2. --port 8080

--port 8080

웹 서버가 사용할 포트 번호입니다.

실행 후 일반적으로 다음 주소로 접속합니다.

http://localhost:8080

7-3. --memory_service_uri

--memory_service_uri="agentengine://..."

이것이 이번 실습에서 가장 중요한 옵션입니다.

이 옵션을 통해 ADK에 어떤 메모리 서비스를 사용할 것인지 지정합니다.

URI를 분해해 보겠습니다.

agentengine://
    projects/
        921865052026/
    locations/
        asia-northeast3/
    reasoningEngines/
        2528612861094133760

각각의 의미는 다음과 같습니다.

항목 역할
agentengine:// Agent Engine 기반 메모리 서비스 사용
projects/... GCP 프로젝트 식별
locations/... 리전 지정
reasoningEngines/... 대상 Agent Engine 식별

ADK는 이 URI를 확인하고 해당 Agent Engine의 Memory Bank를 사용할 수 있도록 메모리 서비스를 구성합니다.

내부적으로 연결되는 것이 바로 다음 객체입니다.

VertexAiMemoryBankService

즉 우리가 Python 코드에서 직접 다음과 같이 객체를 생성하지 않았더라도,

memory_service = VertexAiMemoryBankService(
    project="agent-project-512212",
    location="asia-northeast3",
    agent_engine_id="2528612861094133760",
)

adk web 실행 시 URI를 지정하면 ADK가 해당 서비스를 구성하고 실행 환경에 연결해 줍니다.

공식 ADK 문서에서도 agentengine:// URI를 통한 설정과 직접 VertexAiMemoryBankService를 생성하는 두 가지 방식을 안내하고 있습니다. <Cite refs={["turn602605search0","turn602605search1"]}/>

7-4. 여기서 꼭 구분해야 할 것: Memory Service와 Session Service

이 부분은 이번 실습에서 반드시 이해하고 넘어가야 합니다.

ADK에는 서로 다른 두 가지 서비스가 있습니다.

① Session Service

대화 세션 자체를 관리합니다.

예를 들어 다음 정보를 관리합니다.

  • 사용자 ID

  • 세션 ID

  • 대화 이벤트

  • 대화 진행 상태

② Memory Service

과거 대화에서 추출한 장기 기억을 관리합니다.

예를 들어 다음과 같은 정보를 관리합니다.

  • 사용자의 지속적인 관심사

  • 학습 계획

  • 선호하는 답변 방식

  • 반복적으로 등장하는 중요한 사실

두 서비스를 비교하면 다음과 같습니다.

구분 Session Service Memory Service
핵심 역할 대화 기록 관리 장기 기억 관리
데이터 질문과 답변 이벤트 추출된 기억
활용 현재 대화의 연속성 과거 대화의 정보 회상
이번 실습 기본 설정 사용 Vertex AI Memory Bank

그런데 우리가 실행한 명령어에는 다음 옵션이 없습니다.

--session_service_uri

따라서 Memory Service는 클라우드로 지정했지만, Session Service는 별도로 클라우드로 지정하지 않은 것입니다.

즉 클라우드 Memory Bank를 사용한다고 해서 대화 세션까지 자동으로 클라우드에 영구 저장되는 것은 아닙니다.

이것은 상당히 중요한 차이입니다.

나중에 다음과 같이 두 서비스를 모두 지정하면 클라우드 기반의 세션과 메모리를 함께 사용할 수 있습니다.

adk web --port 8080 `
  --session_service_uri="agentengine://projects/921865052026/locations/asia-northeast3/reasoningEngines/2528612861094133760" `
  --memory_service_uri="agentengine://projects/921865052026/locations/asia-northeast3/reasoningEngines/2528612861094133760"

다만 같은 Agent Engine을 양쪽에 사용하는 것이 항상 필수인 것은 아닙니다. Session과 Memory Bank는 각각 별도의 리소스 ID를 가질 수 있습니다.

이번 실습은 Memory Bank 자체의 작동을 이해하는 데 집중한 것으로 보면 됩니다.

8. 실제 대화에서 어떤 일이 발생하는가?

이제 앞에서 설명한 내용을 하나의 실제 시나리오로 연결하겠습니다.

가령 다음과 같이 두 번의 대화를 진행한다고 가정하겠습니다.

첫 번째 대화: 기억 생성

<box border radius="lg" padding={3} gap={3}>
<row align="center" gap={2}>
<badge color="info">Session 1</badge>
**첫 번째 대화**
</row>
<box background="rgba(59,130,246,0.08)" radius="lg" padding={3}>
**사용자**

나는 Python과 AI Agent를 공부하고 있어. 앞으로도 계속 공부할 생각이야.
</box>
<box background="surface-secondary" radius="lg" padding={3}>
memory_agent

좋은 계획이네요. Python과 AI Agent 학습을 꾸준히 이어가실 수 있도록 도와드리겠습니다.
</box>
<divider color="subtle"/>
<list connector="solid" marker="number" gap={2}>
<list-item>
Gemini 답변 생성

사용자 질문을 이해하고 답변합니다.
</list-item>
<list-item>
after_agent_callback 실행

add_session_to_memory()가 실행됩니다.
</list-item>
<list-item>
세션 이벤트 전달

현재 세션의 대화 이벤트가 Memory Bank에 전달됩니다.
</list-item>
<list-item>
Memory Bank 기억 생성

대화에서 장기적으로 활용할 정보를 추출합니다.
</list-item>
</list>
<box background="rgba(16,185,129,0.08)" radius="md" padding={3} gap={1}>
<badge color="success">추출 가능한 기억의 예</badge>
사용자는 Python과 AI Agent를 지속적으로 공부할 계획이다.
</box>
</box>

여기서 중요한 것은 Memory Bank가 대화 내용을 그대로 복사하는 것이 아니라는 점입니다.

대화의 의미를 분석하여 향후 활용할 기억을 생성하는 것이 핵심입니다.

두 번째 대화: 기억 검색

이제 첫 번째 대화와는 별개의 새로운 세션을 시작한다고 가정하겠습니다.

<box border radius="lg" padding={3} gap={3}>
<row align="center" gap={2}>
<badge color="info">Session 2</badge>
**새로운 대화**
</row>
<box background="rgba(59,130,246,0.08)" radius="lg" padding={3}>
**사용자**

내가 요즘 공부하는 분야가 뭐였지?
</box>
<box background="surface-secondary" radius="lg" padding={3}>
memory_agent

잠시 이전에 나눈 대화의 기억을 확인하겠습니다.
</box>
<box border radius="md" padding={3} gap={1}>
<row align="center">
<icon name="search" color="success"/>
load_memory 실행
</row>
<text color="secondary" size="xs">Memory Bank에서 관련 기억 검색</text>
<divider color="subtle"/>
검색 결과:

사용자는 Python과 AI Agent를 지속적으로 공부할 계획이다.
</box>
<box background="rgba(16,185,129,0.08)" radius="md" padding={3}>
memory_agent

이전 대화를 확인해 보니 Python과 AI Agent를 공부하고 계셨습니다. 앞으로도 계속 공부할 계획이라고 말씀하셨습니다.
</box>
</box>

이렇게 새로운 세션에서도 과거 대화에서 추출한 정보를 활용할 수 있습니다.

이것이 바로 Cross-session Memory(세션 간 기억 공유)의 핵심입니다.

8-1. 기억 생성과 검색은 별개의 작업이다

한 가지 더 주의해야 합니다.

첫 번째 대화가 끝나고 add_session_to_memory()가 호출되더라도, Memory Bank의 기억 생성 작업은 비동기 장기 실행 작업(LRO)으로 처리될 수 있습니다.

따라서 다음 두 가지는 구분해야 합니다.

  • 메모리 생성 요청이 접수됨

  • 메모리 생성 및 처리가 완료됨

ADK의 VertexAiMemoryBankService.add_session_to_memory()는 메모리 생성 작업을 요청하고 즉시 반환할 수 있습니다. 따라서 첫 번째 세션이 끝나자마자 두 번째 세션에서 검색하면 아직 기억이 준비되지 않았을 가능성도 있습니다.

테스트할 때는 첫 번째 대화 후 몇 초 정도 기다린 다음 두 번째 대화를 진행하는 것이 좋습니다. <Cite refs={["turn602605search4","turn602605search10"]}/>

9. 실습할 때 반드시 확인해야 할 5가지

여기까지 이해했다면 실제 테스트에서 발생할 수 있는 문제도 미리 알고 있는 것이 좋습니다.

① 첫 번째 대화가 Memory Bank에 제대로 전달되었는가?

after_agent_callback이 실행되었다고 해서 반드시 메모리 생성이 완료된 것은 아닙니다.

Google Cloud 공식 문서에서는 세션에 이벤트가 존재하는지 확인하도록 안내합니다.

특히 세션의 events가 비어 있다면 메모리 생성 요청에 전달할 내용이 없을 수 있습니다. <Cite refs={["turn602605search4"]}/>

② 동일한 사용자로 검색하고 있는가?

Memory Bank의 기억은 일반적으로 다음 범위로 구분됩니다.

app_name
    +
user_id

따라서 첫 번째 세션과 두 번째 세션에서 동일한 app_name, user_id를 사용하는 것이 중요합니다.

다른 사용자 ID로 접속하면 이전 사용자의 기억이 검색되지 않을 수 있습니다.

③ Memory Bank 생성이 완료되었는가?

첫 번째 대화 후 두 번째 대화에서 바로 검색하지 말고 잠시 기다려 보세요.

필요하다면 Google Cloud의 Agent Engine 관련 작업 상태와 로그도 확인해야 합니다.

④ load_memory가 실제 호출되었는가?

도구를 등록했더라도 LLM이 호출하지 않을 수 있습니다.

따라서 처음 테스트할 때는 다음과 같이 명확하게 질문하는 것이 좋습니다.

이전에 내가 공부한다고 말한 분야가 무엇인지
load_memory 도구를 사용해서 확인해 줘.

⑤ 세션 서비스와 메모리 서비스가 혼동되지 않았는가?

이번 실습에서는 다음 두 가지를 구분해야 합니다.

  • Session Service: 대화 이벤트를 관리

  • Memory Service: 대화에서 추출된 장기 기억을 관리

Memory Bank가 정상적으로 작동하는지 확인하려면 이 두 가지를 별도로 점검해야 합니다.

10. 이번 실습을 한눈에 정리하면

지금까지 배운 내용을 기존의 ADK 메모리 실습과 비교해 보겠습니다.

구분 InMemoryMemoryService VertexAiMemoryBankService
저장 위치 로컬 메모리 Google Cloud
데이터 지속성 실행 환경에 종속 클라우드에 영속 저장
별도 GCP 리소스 불필요 Agent Engine 필요
인증 별도 GCP 인증 불필요 GCP 인증 필요
메모리 생성 세션 이벤트 전달 세션 이벤트 전달 및 기억 추출
검색 저장된 기억 검색 클라우드 Memory Bank 검색
활용 목적 학습 및 개발 실제 클라우드 기반 서비스

그리고 지금까지 학습한 ADK의 여러 서비스를 전체적으로 연결하면 다음과 같습니다.

<box border radius="lg" padding={3} gap={3}>
**ADK의 데이터 관리 서비스 구조**
<box background="rgba(59,130,246,0.08)" radius="md" padding={3} gap={1}>
**1. Session Service**
<text color="secondary" size="sm">현재 대화의 진행 상황과 이벤트 관리</text>
<text color="secondary" size="xs">InMemorySessionService → DatabaseSessionService → VertexAiSessionService</text>
</box>
<box background="rgba(16,185,129,0.08)" radius="md" padding={3} gap={1}>
**2. Memory Service**
<text color="secondary" size="sm">과거 대화에서 중요한 기억을 관리하고 검색</text>
<text color="secondary" size="xs">InMemoryMemoryService → VertexAiMemoryBankService</text>
</box>
<box background="rgba(168,85,247,0.08)" radius="md" padding={3} gap={1}>
**3. Artifact Service**
<text color="secondary" size="sm">파일이나 이미지 등 대화 과정에서 발생하는 산출물 관리</text>
<text color="secondary" size="xs">InMemoryArtifactService → GCSArtifactService</text>
</box>
</box>

세 가지는 서로 대체하는 서비스가 아닙니다.

각자 다른 종류의 데이터를 관리하며, 실제 서비스를 만들 때 함께 사용할 수 있습니다.

11. 권장하는 다음 실습

이번 실습을 마무리하기 전에 한 가지 더 해보면 좋겠습니다.

단순히 Memory Bank에 기억이 저장되는 것을 확인하는 수준에서 끝내지 말고, 로컬 ADK 에이전트를 종료했다가 다시 실행해도 과거의 기억을 활용하는지 검증하는 것입니다.

다음 순서로 테스트해 보세요.

순서실행 및 테스트확인할 사항
1 첫 번째 세션 시작 새로운 대화
2 사용자 정보 입력 기억할 만한 정보 제공
3 대화 종료 after_agent_callback 실행
4 잠시 대기 Memory Bank 기억 생성
5 ADK Web 종료 로컬 에이전트 서버 종료
6 ADK Web 재실행 동일한 Memory Bank URI 사용
7 새로운 세션 시작 이전 대화와 다른 세션
8 과거 정보 질문 load_memory 검색 결과 확인

여기서 이전 기억을 성공적으로 찾아낸다면, 클라우드 기반 장기 기억이 제대로 작동한다는 것을 확인할 수 있습니다.

한 가지 추가 실습 제안: 다음 단계에서는 VertexAiSessionService와 VertexAiMemoryBankService를 동시에 연결해 보기를 권합니다.

그러면 다음과 같은 완전한 클라우드 기반 에이전트 구조를 이해할 수 있습니다.

                사용자
                  │
                  ▼
              ADK Agent
                  │
          ┌───────┴────────┐
          ▼                ▼
     Session Service   Memory Service
          │                │
          ▼                ▼
    Vertex AI          Vertex AI
    Sessions           Memory Bank
          │                │
          ▼                ▼
      대화 이력          장기 기억

이 구조까지 이해하면 단순한 챗봇을 넘어, 사용자별 대화 이력과 장기 기억을 지속적으로 활용하는 AI Agent를 설계할 수 있게 됩니다.

핵심은 Session은 대화의 연속성을 담당하고, Memory는 사용자를 이해하는 연속성을 담당한다는 것입니다.

참고할 공식 문서:

반응형