Agentic AI/Google ADK

19. Session/Memory/Artifact [8]- InMemoryMemoryService

아톨 2026. 10. 25. 19:52

이번 코드는 앞서 성공한 VertexAiSessionService 실습에서 한 단계 더 나아가, 대화 세션을 기억으로 저장하고, 나중에 그 기억을 검색해 활용하는 구조를 테스트하려는 코드입니다.

먼저 가장 중요한 결론부터 말씀드리겠습니다.

1. 어떤 명령어로 실행해야 할까요?

이번 코드의 목적이 InMemoryMemoryService 테스트라면, 우선 다음 명령어로 실행하는 것이 맞습니다.

adk web --port 8080

다만, 이 명령어만으로 InMemoryMemoryService가 자동으로 설정되는 것은 아닙니다. ADK가 사용하는 기본 서비스 설정과 에이전트 실행 환경에 따라 실제로 어떤 Memory Service가 연결되는지 확인해야 합니다.

 

두 명령어의 차이는 다음과 같습니다.

실행 명령어 주요 목적 이번 실습에서의 판단
adk web --port 8080 ADK Web을 기본 설정으로 실행 InMemoryMemoryService를 테스트할 때 우선 사용
adk web --port 8080 --session_service_uri="agentengine://projects/921865***/locations/asia-northeast3/reasoningEngines/2528612***" 세션 서비스를 지정된 Agent Engine 리소스에 연결하도록 설정 앞서 실습한 Google Cloud 관리형 세션 서비스를 다시 테스트할 때 고려

중요: --session_service_uri는 세션 서비스 설정이지, 그 자체로 Memory Service를 InMemoryMemoryService에서 Google Cloud의 장기 기억 서비스로 바꾸는 설정은 아닙니다. 따라서 두 명령어의 차이는 단순히 로컬 저장과 클라우드 저장의 차이라고 이해하면 안 됩니다.

이번 코드가 실제로 어떤 Memory Service를 사용하는지 확인한 다음, 테스트 목적에 맞는 명령어를 선택하는 것이 정확합니다.

공식 ADK CLI 문서에서도 세션 서비스와 메모리 서비스를 각각 별도의 옵션으로 설정하도록 구분하고 있습니다.

 
 

따라서 이번 테스트에서는 다음처럼 두 서비스를 명시적으로 설정하는 방법이 가장 이해하기 쉽습니다.

① InMemoryMemoryService만 테스트

adk web --port 8080 --memory_service_uri="memory://"

② 기존 Agent Engine 세션 서비스와 InMemoryMemoryService를 함께 사용

adk web --port 8080 --session_service_uri="agentengine://projects/9218***/locations/asia-northeast3/reasoningEngines/252861***" --memory_service_uri="memory://"

두 번째 명령어는 앞서 검증한 클라우드 세션 저장과 이번 메모리 저장을 함께 사용하는 구성입니다. 다만 메모리는 여전히 로컬 프로세스의 메모리에 저장되므로, 웹 서버를 재시작하면 InMemoryMemoryService에 저장한 기억은 사라집니다.

이번에는 첫 번째 명령어로 시작해서 Memory Service의 작동 원리를 먼저 확인하는 것을 권합니다.

2. 코드 전체의 역할부터 이해하기

코드를 기능별로 나누면 다음과 같습니다.

이 코드의 핵심은 저장 기능과 검색 기능을 서로 다른 두 곳에서 구현했다는 것입니다.

  • add_session_to_memory: 대화 세션을 기억 저장소에 추가합니다.

  • load_memory: 기억 저장소에 있는 내용을 검색할 수 있게 해주는 도구입니다.

둘 다 있어야 기억을 저장하고 다시 활용하는 흐름을 만들 수 있습니다.

3. 코드 한 줄씩 상세 해설

3-1. 라이브러리 가져오기

import os
from typing import Optional
from google.adk import Agent
from google.adk.agents.callback_context import CallbackContext
from google.adk.tools import load_memory
import google.adk as adk
from google.genai import types

각각의 역할을 살펴보겠습니다.

import os 운영체제 환경변수 등을 읽습니다.
Optional 함수가 특정 타입의 값 또는 None을 반환할 수 있음을 표현합니다.
Agent ADK 에이전트를 생성합니다.
CallbackContext 에이전트의 콜백 함수에 실행 문맥을 전달합니다.
load_memory 저장된 기억을 검색하는 ADK 기본 도구입니다.
import google.adk as adk ADK 패키지를 adk라는 이름으로 가져옵니다. 이 코드에서는 실제로 사용하지 않습니다.
types Google Gen AI SDK의 콘텐츠 타입 등을 사용합니다.

여기서 CallbackContext가 중요합니다. 일반적인 함수라면 질문이나 문자열을 인자로 받겠지만, 콜백 함수는 에이전트 실행 과정에서 생성된 문맥을 전달받을 수 있습니다.

이 문맥을 통해 현재 실행 중인 세션과 Memory Service에 접근하려는 것입니다.

3-2. add_session_to_memory 함수

먼저 코드 전체를 다시 보겠습니다.

async def add_session_to_memory(
    callback_context: CallbackContext
) -> Optional[types.Content]:
    """Automatically save completed sessions to memory bank"""
    if hasattr(callback_context, "_invocation_context"):
        invocation_context = callback_context._invocation_context
        if invocation_context.memory_service:
            await invocation_context.memory_service.add_session_to_memory(
                invocation_context.session
            )

이 함수는 이번 코드에서 가장 중요한 부분입니다.

① async def

async def add_session_to_memory(...)

일반 함수가 아니라 비동기 함수입니다.

비동기 함수는 async def로 정의합니다. 이 함수는 Memory Service의 저장 작업을 기다려야 하므로 비동기 호출을 사용합니다.

② callback_context: CallbackContext

callback_context: CallbackContext

ADK가 콜백 함수를 실행할 때 전달하는 객체입니다.

이 객체에는 에이전트 실행과 관련된 문맥이 담겨 있습니다. 코드에서는 이 문맥을 이용해 현재 실행 정보에 접근합니다.

③ Optional[types.Content]

-> Optional[types.Content]

함수의 반환 타입을 나타냅니다.

  • types.Content: Google Gen AI SDK의 콘텐츠 객체

  • Optional[types.Content]: 콘텐츠 객체 또는 None

현재 코드에는 return 문이 없습니다. 따라서 정상적으로 끝나면 실제 반환값은 None입니다.

즉, 이 함수는 답변 문장을 만들어 반환하는 함수가 아니라 에이전트 실행 후 기억을 저장하는 부수 작업을 수행하는 함수입니다.

④ hasattr()로 속성 확인

if hasattr(callback_context, "_invocation_context"):

hasattr(객체, "속성이름")은 해당 객체에 특정 속성이 있는지 확인합니다.

예를 들어 다음과 같습니다.

hasattr(callback_context, "_invocation_context")

callback_context에 _invocation_context라는 속성이 있으면 True, 없으면 False를 반환합니다.

이렇게 확인하는 이유는 해당 속성이 없을 때 바로 접근하여 오류가 발생하는 것을 피하기 위해서입니다.

다만 _invocation_context처럼 이름 앞에 밑줄이 있는 속성은 일반적으로 내부 구현용 속성입니다. 따라서 ADK 버전이 바뀌면 동작 방식이 달라질 가능성이 있습니다. 학습용으로는 이해할 수 있지만, 실제 운영 코드에서는 현재 설치된 ADK 버전의 공개 API를 우선 사용하는 것이 좋습니다.

⑤ 실행 문맥 가져오기

invocation_context = callback_context._invocation_context

콜백 문맥 안에서 실제 에이전트 실행에 관한 정보를 가져옵니다.

이제 invocation_context를 통해 두 가지 핵심 정보에 접근합니다.

  • invocation_context.memory_service: 현재 실행에 연결된 메모리 서비스

  • invocation_context.session: 현재 대화 세션

쉽게 비유하면 다음과 같습니다.

  • callback_context: 에이전트 작업이 끝났다는 상황을 알려주는 안내 창구

  • invocation_context: 실제 작업에 관한 상세 정보

  • session: 현재 대화 기록

  • memory_service: 그 기록을 기억으로 저장할 서비스

⑥ Memory Service가 있는지 확인

if invocation_context.memory_service:

현재 실행 문맥에 Memory Service가 연결되어 있는지 확인합니다.

연결되어 있다면 다음 저장 작업을 수행하고, 연결되어 있지 않다면 저장 작업을 건너뜁니다.

주의할 점은 이 조건문이 서비스가 정상적으로 저장할 수 있는지까지 검증하지는 않는다는 것입니다. 단지 서비스 객체가 존재하는지 확인합니다.

⑦ 세션을 기억으로 저장

await invocation_context.memory_service.add_session_to_memory(    invocation_context.session)

이 부분이 실제 저장 작업입니다.

invocation_context.session은 현재 대화 세션이고, add_session_to_memory()는 해당 세션을 메모리 서비스에 추가하는 메서드입니다.

await는 비동기 작업이 완료될 때까지 기다린다는 의미입니다.

전체 흐름은 다음과 같습니다. 

한 가지 알아둘 점이 있습니다. 이 함수의 주석은 memory bank라고 표현하지만, 실제로 연결된 서비스가 InMemoryMemoryService라면 Google Cloud의 영구적인 Memory Bank를 사용하는 것은 아닙니다. 어떤 서비스를 사용하는지는 코드의 이름이 아니라 실제 연결된 memory_service 객체가 결정합니다.

3-3. 에이전트 정의

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

이제 에이전트를 구성하는 부분입니다.

① 모델 설정

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

os.getenv()는 환경변수에서 값을 읽습니다.

  • GOOGLE_MODEL 환경변수가 있으면 그 값을 사용합니다.

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

다만 기본 모델명이 현재 계정과 API에서 사용 가능한지는 별도로 확인해야 합니다. 모델 호출 오류가 난다면 해당 모델의 지원 여부와 접근 권한부터 점검하세요.

② 에이전트 이름

name="memory_agent"

ADK에서 이 에이전트를 식별하는 이름입니다.

프로젝트 폴더와 ADK Web에서 에이전트를 찾을 때도 이 이름과 에이전트 파일 구조가 관련됩니다.

③ 에이전트 지침

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

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

이 문장은 답변을 한글로 작성하도록 유도하지만, 지침만으로 모든 상황에서 언어가 완벽하게 통제된다고 보장할 수는 없습니다.

④ tools=[load_memory]

tools=[load_memory]

에이전트가 사용할 수 있는 도구 목록입니다.

load_memory는 저장된 기억을 검색하는 도구입니다. 에이전트는 사용자의 질문에 답할 때 이전에 저장한 정보가 도움이 된다고 판단하면 이 도구를 활용할 수 있습니다.

여기서 중요한 점은 load_memory를 등록했다고 해서 에이전트가 반드시 모든 질문에서 기억을 검색하는 것은 아니라는 것입니다. 도구를 언제 호출할지는 모델의 판단과 지침에 영향을 받습니다.

또한 load_memory가 검색할 대상은 현재 실행에 연결된 Memory Service입니다. 기억이 저장되어 있지 않거나 다른 서비스에 저장되어 있다면 원하는 결과가 나오지 않을 수 있습니다.

⑤ after_agent_callback

after_agent_callback=add_session_to_memory

이 설정이 저장 기능을 자동으로 연결합니다.

after_agent_callback은 에이전트 실행이 끝난 뒤 실행할 콜백을 지정합니다.

따라서 매번 직접 다음과 같은 저장 코드를 호출할 필요 없이, 에이전트의 작업이 끝날 때 add_session_to_memory가 실행되도록 구성한 것입니다.

다만 콜백의 정확한 실행 시점과 반복 실행 방식은 ADK의 실행 흐름에 따릅니다. 도구 호출 한 번마다 무조건 저장되는 것이 아니라, 이 코드에서는 에이전트의 실행이 끝난 뒤 저장을 시도하도록 연결한 것입니다.

3-4. root_agent=memory_agent

root_agent = memory_agent

ADK가 에이전트 프로젝트의 시작점으로 찾을 수 있도록 루트 에이전트를 지정합니다.

adk web으로 프로젝트를 실행할 때 ADK가 루트 에이전트를 발견할 수 있어야 합니다.

일반적으로 파일 이름이 agent.py라면 다음 구조처럼 사용할 수 있습니다.

hello_agent/
└── agent.py

프로젝트 폴더의 이름과 실행 위치는 실제 환경에 맞춰야 합니다. 기존에 hello_agent 패키지 구조를 사용하고 있다면 그 구조를 그대로 유지하면 됩니다.

4. 실제 테스트 절차

이번 실습에서는 세션 서비스와 메모리 서비스를 명시적으로 분리해서 테스트하겠습니다.

1단계: PowerShell에서 프로젝트 폴더로 이동

& "C:\Dev\book_agentic_ai\venv\Scripts\Activate.ps1"

cd "C:\Dev\book_agentic_ai\adk\_\hello_agent"

2단계: 메모리 서비스를 명시해 실행

adk web --port 8080 --memory_service_uri="memory://"

memory://는 ADK CLI에서 메모리 서비스를 메모리 기반 구현으로 사용하도록 지정하는 URI입니다.

ADK CLI 2.12.0 documentation
+1

브라우저에서 http://localhost:8080에 접속해 memory_agent를 선택합니다.

3단계: 기억할 정보를 대화에 입력

예를 들어 다음과 같이 입력합니다.

내 이름은 스티븐이고, 앞으로 Python과 AI Agent 공부를 계속할 생각이야.

에이전트가 정상적으로 답변하면 after_agent_callback이 실행되어 해당 세션을 메모리 서비스에 저장하도록 시도합니다.

4단계: 새로운 대화에서 기억 검색 테스트

새로운 세션을 시작한 뒤 다음과 같이 질문합니다.

내가 앞으로 어떤 공부를 계속한다고 했지?

에이전트가 load_memory 도구를 호출하고, 이전 세션에서 저장된 내용을 검색하여 답변한다면 저장과 검색의 연결이 성공한 것입니다.

이때 두 가지를 주의하세요.

  • 새 대화는 기존 대화와 다른 세션이어야 합니다.

  • 같은 InMemoryMemoryService 인스턴스가 유지되어야 합니다.

서버를 재시작하지 마세요. InMemoryMemoryService는 프로세스의 메모리를 사용하므로 서버를 종료하면 저장된 기억도 사라질 수 있습니다.

또한 모델이 도구를 호출하지 않거나 저장된 기억을 찾지 못하는 경우도 있습니다. 그런 경우에는 기억이 저장되었는지, memory_service가 실제로 연결되었는지, load_memory가 호출되었는지 차례로 확인해야 합니다.

5. 이번 실습에서 꼭 구분할 개념

SessionService 대화 세션을 생성하고 조회하며 관리한다.
MemoryService 이전 세션에서 얻은 내용을 기억으로 저장하고 검색한다.
add_session_to_memory 현재 세션을 기억 저장소에 추가한다.
load_memory 저장된 기억을 검색한다.
after_agent_callback 에이전트 실행이 끝난 뒤 저장 함수를 호출한다.

이번 실습의 핵심은 세션을 저장하는 것과 세션에서 얻은 정보를 기억으로 활용하는 것이 서로 다른 과정이라는 점입니다.

앞서 VertexAiSessionService를 사용해 서버 재시작 후에도 기존 대화 세션을 유지하는 데 성공하셨습니다. 이번 InMemoryMemoryService 실습에서는 그와 별도로, 한 세션에서 얻은 정보를 새로운 세션에서 검색하여 활용하는 흐름을 확인하는 것이 목표입니다.

따라서 지금은 다음 명령어로 시작하는 것이 가장 좋습니다.

adk web --port 8080 --memory_service_uri="memory://"

기존 Agent Engine 세션 서비스를 함께 테스트하고 싶을 때는 두 URI를 모두 지정하면 됩니다. 다만 그 경우에도 메모리 서비스는 memory://로 설정했으므로, 세션은 클라우드에 저장하더라도 기억은 로컬 프로세스의 메모리에 저장된다는 점을 기억하시면 됩니다.