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는 사용자를 이해하는 연속성을 담당한다는 것입니다.
참고할 공식 문서:
'Agentic AI > Google ADK' 카테고리의 다른 글
| 20. Session/Memory/Artifact [9]- VertexAiMemoryBankService(1/2) (0) | 2026.10.31 |
|---|---|
| 19. Session/Memory/Artifact [8]- InMemoryMemoryService (0) | 2026.10.25 |
| 18. Session/Memory/Artifact [7]- VertexAiSessionService(3/3) (0) | 2026.10.25 |
| 17. Session/Memory/Artifact [6]- VertexAiSessionService(2/3) (0) | 2026.10.25 |
| 16. Session/Memory/Artifact [5]- VertexAiSessionService(1/3) (0) | 2026.10.25 |