1. 소개

1주차에서는 누가 어떤 프로그램을 실행하는지를 물었습니다. 2주차에서는 다음에 실행할 항목을 누가 결정하는지를 질문했습니다. 3주차에서는 러닝이 남기는 것을 물었습니다. 이번 주에 대화가 끝나고 무엇이 살아남을지 묻는 질문이 나오는데, 어떤 종류의 것인지에 따라 어디로 가는지 결정됩니다.
문제가 발생하면 아카이브로 이동합니다. 모든 것을 기록하는 타워와 1층 책상에 있는 기록 보관소 베스퍼가 있습니다. 밤에는 랜턴이 꺼집니다. 가서 물어봐.
그녀는 좋은 친구입니다. 한 달 후에도 만나 뵙게 되어 기쁩니다.
기록은 메모리가 아닙니다.
이 문장이 전체 실습입니다. 4개의 링을 오르게 되며 각 링은 타워의 층입니다.
rung | 바닥 | 기억하는 내용 | 무엇이 |
1 | 책상과 바닥에 있는 것 | 이번 방문 |
|
2 | 2층 서랍 | 이 방문자 |
|
3 | 3층, 타워 | 말한 내용 | Vertex AI Memory Bank |
4 | 4층, 시즌 | 전체 계곡 | BigQuery |
아래쪽에서 무언가가 떨어져 나갔기 때문에 위쪽으로 올라간 것입니다.

지원 통화에서 모두 경험한 적이 있으므로 아카이브 관리자의 5가지 망각 방법을 이미 알고 있습니다.
그녀가 말하는 내용 | 무엇이 잘못되었는지 | |
~~1~~ | ~~참조를 다시 알려 주시겠어요?~~ | ~~한 대화 내에서 잊어버림~~ - 3주차에 이 문제가 수정됨 |
~~2~~ | ~~연결해 드렸습니다. 처음부터 다시 시작해 주세요.~~ | ~~기록이 프로세스와 함께 종료됨~~ - 3주차에서 이 문제도 수정됨 |
3 | 환영합니다. 무엇을 도와드릴까요? | 지난달에 진행 중인 케이스가 있는 사용자 |
4 | 손상된 부분을 설명해 주시겠어요? | 지난번에는 랜턴을 봤어. |
5 | 이런 경우는 처음입니다. | 이번 시즌에 31명이 질문했습니다. |
세 번째 줄은 이번 주입니다. 새 방문 (2장), 슬립에 줄이 없는 문장 (3장), 프로세스 내부에만 있는 보관 파일 (4장) 등 세 가지 다른 방식으로 실패하며 각 방식이 하나의 장입니다. 네 번째 줄은 여러분이 채워야 합니다. archive/agent.py에서 look()은(는) 사진의 표시를 읽는 곳입니다. 다섯 번째 줄은 5장이며 선택사항입니다.
1~3주차는 필요하지 않습니다. 에이전트는 명령어와 몇 가지 도구가 있는 모델입니다. 그 외 모든 것은 이번 주에 설명됩니다.
세 줄을 작성하며 각 줄은 메모리 개념입니다.
선 | 기능 |
| 상태는 코드에 의해 작성되며 대화에 의해 작성되지 않습니다. |
| 접두사는 수명입니다. |
| 리콜 정책 - 제출이 기억되지 않음 |
읽을 수 있는 한 줄이 이미 있습니다. 쓰기 정책인 await ctx.add_events_to_memory(...)입니다. 3장에서는 이 정책을 사용하는 줄을 작성하기 전에 이 정책이 하는 일을 읽습니다.
나머지 두 단계는 수정이 아닙니다. 타워를 빌드(메모리 뱅크를 호스팅하는 에이전트 엔진)하면 동일한 코드가 자동으로 연결되고, 창고를 로드(BigQuery)하고, 그래프를 배치하고, 동일한 에이전트에 두 개의 관리 쿼리(의미별 하나, 연결별 하나)를 전달합니다.
모든 챕터는 동일한 루프를 실행하며, 이 루프는 자체 에이전트에서 사용할 루프입니다. 코드를 읽고 → 줄을 작성하고 → 타워에서 확인합니다. 처음부터 깨진 상태로 실행되는 것도 없고, 다시 시작되는 것도 없고, Ctrl+C로 중단되는 것도 없습니다. 모든 수정사항은 다음 메시지에서 선택되며, 타워 연결은 보관 파일이 모든 요청에서 다시 읽는 파일의 한 줄입니다. 타워는 다시 그리는 그림입니다. 내가 수정한 파일을 읽고 세 개의 버튼이 있습니다. 🌙은 하루를 끝내고, 🗓은 다음 방문을 시작하고, 🔥은 나를 잊습니다. 나머지는 코드와 터미널에서 실행합니다.
두 곳이며 작업이 변경되지 않습니다. 탭 1은 터미널이고 탭 2는 보관처리입니다. 작업대 (adk web)는 원시 세션 상태를 한 번 살펴보기 위해 1장에 정확히 한 번 표시되며, 그 후에는 완료됩니다. 아래의 모든 👉에 어떤 유형인지 표시되어 있습니다. 👉💻은 탭 1, 👉🖥은 탭 2, 👉🔬은 워크벤치입니다. 👉📖은 파일을 열고 읽기로, 변경할 사항이 없으며 👉✏️은 수정하는 단계입니다. 단계에서 Vesper에게 무언가를 말하라고 할 때마다 바로 아래 블록에 정확한 메시지가 있습니다. 그대로 복사하세요. 제목이 — 읽기 전용으로 끝나는 섹션에는 입력하거나, 붙여넣거나, 클릭할 항목이 없습니다. 해당 섹션의 코드는 이미 저장소에 있고 이미 실행 중이며, 읽을 수 있도록 출력되어 있습니다.
베스퍼의 문 위에 있는 문장이 맨 위에 있습니다. 이번 주에 끝나는 문장은 전체 시즌 4주차의 마지막 문장입니다.
사실과 환경설정은 서로 다른 스토어에 속합니다.
2. 🧰 설정
- 무엇 - 프로젝트를 가리키거나 키를 붙여넣고 설치한 후 도구 체인이 녹색임을 증명합니다.
- 이유: 여기서는 아무것도 부팅되지 않습니다. 모든 서버는 필요한 단계 바로 전에 시작되므로 화면이 열리면 어떤 명령어가 소유하는지 알 수 있습니다.
- 방법 - 프로젝트를 만드는 스크립트, Vertex AI를 설치하고 가리키는 스크립트, 코드를 읽고 위치를 알려주는 사전 비행 스크립트
이 실습의 모든 항목은 Cloud Shell에서 실행됩니다. Python, uv, gcloud는 이미 설치되어 있으며, Gemini는 사용자 인증 정보를 사용하여 Vertex AI를 통해 액세스합니다. 이 실습에는 API 키가 없으며 노트북에 설치할 항목도 없습니다.
이 실습에서 제공할 수 없는 것이 하나 있습니다. 바로 결제가 사용 설정된 Google Cloud 프로젝트입니다. 1단계에서는 비용을 지불할 수 있는 계정을 만들고, 4단계에서는 해당 계정을 프로젝트로 전환하거나 1주차, 2주차, 3주차에 이미 만든 Agent Valley 프로젝트를 선택합니다. 이 순서대로 실행하세요. 4단계 이후의 모든 단계에서는 4단계에서 결정된 프로젝트를 읽습니다.
1 · 결제가 가능한 계정 만들기(~1분)
🌐 다른 작업을 하기 전에 이 작업을 수행하세요. 결제가 사용 설정된 Google 계정으로 로그인합니다. 이러한 계정은 모두 사용할 수 있습니다. 계정이 없는 경우 무료 체험을 시작하세요. 4단계에 필요한 결제 계정이 제공됩니다.
2 · Cloud Shell 열기 (약 1분)
🌐 Google Cloud 콘솔 상단에서 Cloud Shell 활성화를 클릭합니다. 헤더에 있는 터미널 모양의 아이콘입니다.

🌐 편집기 열기 (연필이 있는 폴더 열기 아이콘)를 클릭합니다. 이렇게 하면 왼쪽에 파일 탐색기가 있는 Cloud Shell 편집기가 표시됩니다. 단계가 👉✏️로 표시될 때마다 여기에서 작업합니다.

🌐 오늘 언제든지 승인하라는 메시지가 표시되면 승인을 클릭하여 계속합니다.
🌐 편집기(탭 1) 내에서 터미널을 열고 달리 명시되지 않는 한 모든 👉💻 단계가 여기서 실행됩니다. 탭 2는 보관 파일이며, 보관 파일이 필요한 단계 바로 전인 1장에서 엽니다. 터미널이 아직 화면 하단에 없으면 보기 → 터미널을 사용하여 엽니다.

🌐 로그인한 계정을 확인합니다. 1단계에서 사용한 계정이어야 합니다.
gcloud auth list
3. 실습 가져오기(~1분)
💻 저장소 클론 - 1주차, 2주차, 3주차 저장소가 아닌 보관 저장소입니다.
cd ~
git clone https://github.com/cuppibla/agent-valley-archive
cd agent-valley-archive
4 · 프로젝트 만들기 또는 이전 주의 프로젝트 재사용(~2분)
💻 스크립트 하나로 결제 계정을 찾고, 결제 계정에 프로젝트를 만들고, Cloud Shell이 해당 프로젝트를 가리키도록 합니다. 1주차, 2주차 또는 3주차를 진행한 경우 Agent Valley 프로젝트를 먼저 찾아 재사용을 제안합니다. '예'를 선택하면 두 번째 청구 가능한 프로젝트를 고려할 필요가 없습니다.
cd ~/agent-valley-archive
./setup_project.sh
👀 선택한 결제 계정의 ✓, 생성하거나 재사용하는 프로젝트의 ✓, 다음과 같은 종료 문구를 예상합니다.
cd ~/agent-valley-archive
Project ready: agent-valley-4271
Next: ./setup_codelab.sh
agent-valley-4271는 프로젝트 ID입니다. 사용자의 프로젝트 ID는 숫자가 다릅니다. 여기서 네 가지 일이 일어납니다.
결제 | 가장 최근의 | |
project | 이미 소유한 Agent Valley 프로젝트(1주차, 2주차 또는 3주차)를 찾아 재사용하도록 제안합니다. 그렇지 않으면 | |
선택 | ID를 | |
대기 | 프로젝트가 실제로 게재되도록 허용될 때까지 최대 2분 동안 폴링합니다. | |
🌐 이제 콘솔에 동일한 프로젝트가 표시됩니다. ID는 대시보드의 프로젝트 정보 카드에 있습니다.

5 · Vertex AI 설치 및 지정 (약 3분)
💻 uv를 설치하고, ADK를 Vertex AI로 전송하는 세 변수를 내보내고, 설정을 실행합니다.
cd ~/agent-valley-archive
curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.local/bin/env
export GOOGLE_GENAI_USE_VERTEXAI=TRUE
export GOOGLE_CLOUD_PROJECT=$(gcloud config get project)
export GOOGLE_CLOUD_LOCATION=global
./setup_codelab.sh
4단계에서 설정했으므로 $(gcloud config get project)에 반환할 항목이 있습니다. 이것이 4단계가 먼저 오는 이유입니다.
setup_codelab.sh는 멱등성을 가지므로 원하는 횟수만큼 다시 실행해도 안전합니다. 이 메서드는 순서대로 다음 다섯 가지 작업을 실행합니다.
api | 4단계에서 선택한 프로젝트를 읽고 | |
uv env |
| |
site |
| |
.env | 실험실에서 읽는 변수( | |
모델 확인 | Gemini에 실제 호출을 한 번 실행하므로 나중에 챕터 내에서가 아닌 설정 시간에 잘못된 프로젝트가 여기서 실패합니다. | |
6 · 녹색임을 증명 (~1분)
💻 프리플라이트를 실행합니다. 모든 체크표시는 추측이 아닌 실제 프로브입니다.
cd ~/agent-valley-archive
uv run python scripts/preflight.py
👀 사전 검사에서는 모델에 사용자 인증 정보가 작동하는지 증명하는 질문을 하나 하고, 보관 파일의 패키지가 제자리에 있는지 확인한 다음, 코드를 읽고 이번 주의 진행률 표시줄을 출력합니다.
cd ~/agent-valley-archive
desk ▢ the slip · write_down writes nothing chapter 1 · EDIT ONE
floor 1 ✓ the file · SqliteSessionService chapter 1, read only
floor 2 ▢ the drawer · CASE = "case" chapter 2 · EDIT TWO
floor 3 ✓ what was said · closing time files the day chapter 3, read only
floor 3 ▢ the asking · recall never looks chapter 3 · EDIT THREE
floor 3 ▢ the tower · InMemoryMemoryService chapter 4 · built, not edited
floor 3 ✓ the rules · USER_PREFERENCES, LANTERN_CONTEXT chapter 4, read only
3개는 이미 선택되어 있습니다. 읽기 전용인 항목입니다. 3개는 내가 작성한 줄이고 1개는 내가 만든 타워입니다. 실습 중 언제든지 사전 비행을 다시 실행하면 현재 위치가 표시됩니다. 체크리스트가 아닌 파일을 읽기 때문입니다.
3. 세션, 상태, SqliteSessionService
- 무엇 - 한 줄로 작성합니다. 워크벤치를 한 번 시작하고 슬립이 채워지는 것을 지켜봅니다. 그런 다음 타워에서도 동일한 작업을 수행합니다. 그런 다음 밤에 살아남는 이유를 읽습니다.
- 이유 - 메모리에 관해 가장 먼저 알아야 할 점은 메모리 자체로는 아무것도 기억하지 않는다는 것입니다. 누군가 작성합니다.
- 방법 -
agent.py에서 한 줄을 변경하고 다른 것은 변경하지 않습니다.
수정
👉📖 archive/agent.py을 열고 write_down을 찾습니다. 다음까지 읽기 👉:
case = dict(tool_context.state.get(CASE, {}))
if case.get(field):
return {"already_written": {field: case[field]}}
case[field] = value
# 👉 EDIT ONE — chapter 1. She heard you. Nothing was written. Delete the
# "# " in front of the next line, then save — the slip is session state,
# and state is written by code, never by the conversation:
# tool_context.state[CASE] = case
return {"written": {field: value}}
이 함수는 로컬 dict에서 전표를 빌드한 후 반환합니다. 로컬 dict는 호출과 함께 소멸됩니다. 이대로 실행하면 Vesper가 사용자의 말을 완벽하게 듣습니다. write_down 호출이 4번 실행되고 각 호출이 "written"에 응답하며 세션 상태는 비어 있습니다. 아무것도 세션 상태에 도달하지 않았기 때문입니다. 그녀는 당신의 말을 들었습니다. 아무것도 작성되지 않았습니다.
👉✏️ archive/agent.py에서 write_down 내부에 있는 한 줄 앞의 #를 삭제합니다(#와 그 뒤의 공백). 이전:
case[field] = value
# 👉 EDIT ONE — chapter 1. She heard you. Nothing was written. Delete the
# "# " in front of the next line, then save — the slip is session state,
# and state is written by code, never by the conversation:
# tool_context.state[CASE] = case
return {"written": {field: value}}
변경 후:
case[field] = value
# 👉 EDIT ONE — chapter 1. She heard you. Nothing was written. Delete the
# "# " in front of the next line, then save — the slip is session state,
# and state is written by code, never by the conversation:
tool_context.state[CASE] = case
return {"written": {field: value}}
저장합니다.
슬립이 채워집니다.
👉💻 워크벤치를 시작합니다. 실습에서 이 창을 여는 것은 이번이 처음이자 마지막입니다. 세션 상태를 원시 JSON으로 표시하는 유일한 창입니다.
cd ~/agent-valley-archive
uv run adk web . --allow_origins="*"
👉🔬 웹 미리보기 → 포트 8000에서 미리보기를 사용하여 워크벤치를 엽니다 (웹 미리보기 버튼은 Cloud Shell의 오른쪽 상단에 있는 창 위의 눈 아이콘임). 보관을 선택하고 아무것도 입력하기 전에 왼쪽 패널에서 상태를 클릭합니다.
👀 비어 있음 아직 아무도 말하지 않았습니다.
👉🔬 이제 다음을 한 번에 말하세요.
Hi! My lantern keeps going out at night. My case number is k7f2, and there's a little q7 stamped on the base.
👀 4개의 write_down 칩이 실행됩니다. 하나를 클릭하고 JSON을 읽습니다("written": {"no": "k7f2"}). 이제 State(상태)를 다시 클릭합니다.

case {"no": "k7f2", "item": "lantern", "mark": "q7",
"symptom": "keeps going out at night"}
👀 한 메시지 안에 비어 있다가 가득 차는 모습 그녀가 기억하는 것은 그것이며, 그것은 혼자 나타나지 않았습니다. 이 코드를 작성한 것은 바로 여러분입니다. 이것이 전체 메커니즘입니다. tool_context.state에 쓰는 일반 함수와 방문자가 메모의 한 줄에 맞는 말을 할 때마다 이 함수를 사용하라는 안내입니다.
👉🔬 다음과 같이 물어보세요.
What's my case number?
👀 k7f2. 그녀는 종이를 읽습니다. '수정' 권한이 없으면 지원 목록의 첫 번째 줄에 있는 한 대화 내에서 권한을 요청했을 것입니다.
두 개의 가드는 종이 양식인 슬립입니다. 짧은 선이 네 개이며 각 선은 한 번씩 작성됩니다. 겉으로 보이는 것보다 더 중요합니다. 이러한 제한이 없으면 모델은 전체 대화를 symptom에 입력할 수 있다는 것을 알게 되고, 슬립에 해당 항목이 없습니다가 전체 요점인 3장이 조용히 거짓이 됩니다. 스토어의 모양은 스토어를 작성하는 코드에 의해 적용되거나 적용되지 않습니다.
이제 타워로 이동하세요.
👉💻 워크벤치를 완료했습니다. 실행 상태로 두거나 탭을 닫으세요. 실습의 나머지 부분은 보관 파일에 있습니다. 두 번째 터미널 탭 (탭 2 - 보관 파일)을 엽니다.
cd ~/agent-valley-archive
bash valley.sh
👉🖥 웹 미리보기 → 포트 변경으로 보관 파일을 열고 3440을 입력한 다음 변경 및 미리보기를 클릭합니다. 3440은 웹 미리보기의 빠른 목록에 없으며 8080이 기본값이므로 이번에는 직접 설정해야 합니다. ▶ 시작을 누른 다음 보관 파일을 누릅니다. 문 앞에 있습니다. 이름과 종을 물어본 사람을 선택하고 들어갑니다.

👀 건물 하나 베스퍼는 1층에 있는 데스크에 있으며, 이곳에서 대화합니다. 위에는 1층, 2층, 3층, 어두운 다락방이 있습니다. 네 개의 가로대가 네 개의 층입니다. 내가 올라간 만큼만 내 마스코트가 올라가기 때문에 1층에 앉아 있습니다. 그림 옆의 열에는 현재 각 층에 있는 매장이 표시됩니다. 도입부의 표와 동일한 4개 매장이 동일한 순서로 표시됩니다. 오른쪽에는 버튼이 없습니다.
👉🖥 대화 아래 상자에 동일한 네 가지 항목(정확한 메시지)을 붙여넣고 Enter 키를 누릅니다.
Hi! My lantern keeps going out at night. My case number is k7f2, and there's a little q7 stamped on the base.

👀 데스크를 확인합니다. 슬립은 그림에 한 줄씩, 옆에 있는 슬립 아래에 전체가 작성됩니다. 동일한 도구, 동일한 상태: 타워는 write_down가 작성한 내용을 그릴 뿐이며 실습의 나머지 부분에서도 계속 그렇게 합니다.
밤새 기억함 - 읽기 전용
작성한 내용과 그 내용
선 | 기능 | 위치 |
| 세션 상태: 코드로 작성되고 요청 사항으로 읽음 | 데스크 · |
| 세션 저장소: 프로세스가 아닌 파일의 방문 | 1층 · |
이 단계는 한 번의 방문을 달성하며 영업시간이 종료된 후에도 유지됩니다. 다음 방문 시에는 유지되지 않습니다.
4. 사용자 상태
- 결과 - 한 달 후에 다시 돌아오면 슬립이 사라집니다. 5개의 캐릭터가 나를 따라다닙니다.
- 이유: 세션은 한 번의 방문입니다. 다음 방문은 새 세션이며 마지막 방문을 본 적이 없습니다.
- How -
state.py의 5자


👉🖥 🗓 한 달 후를 누릅니다. 이는 동일한 방문자의 새 세션입니다. 3주차의 새 대화 시작과 동일한 방식입니다.
보관 파일에 오신 것을 환영합니다. 무엇을 도와드릴까요?
👉🖥 타워를 보세요. 1층에는 다른 책이 있습니다(이번 방문). 2층 서랍이 비어 있습니다. 책상 위의 종이가 비어 있습니다.

👀 이유: 슬립은 세션 상태에 기록되며 세션은 이번 방문입니다. 방문 변경, 세션 변경 전달된 내용이 없으므로 아무것도 전달되지 않았습니다. 마지막 방문은 여전히 파일에 있습니다(1층의 첫 번째 책). 하지만 슬립은 한 번의 방문 동안 유지되는 키 아래에 작성되었습니다.
EDIT TWO
👉✏️ archive/state.py를 엽니다. 👉를 찾습니다. 이전:
# 👉 EDIT TWO — chapter 2. Five characters. A key with no prefix lives for one
# visit; `user:` follows the visitor into every visit after this.
CASE = "case"
변경 후:
CASE = "user:case"
저장합니다. 다시 시작 안 함: Archive는 메시지마다 코드를 다시 가져옵니다.
👉🖥 동일한 네 가지 항목을 다시 붙여넣습니다. 정확히 다음과 같은 메시지입니다.
Hi! My lantern keeps going out at night. My case number is k7f2, and there's a little q7 stamped on the base.
👉🖥 그런 다음 이전과 동일한 버튼인 🗓 한 달 후를 다시 누릅니다.

👀 2층 서랍에 네 이름이 적혀 있고, 그 안에 네 개의 필드가 들어 있어. 책상 위의 종이는 네 줄로 똑같습니다. 당신이 들어왔을 때 서랍에서 꺼낸 것입니다. 친숙한 캐릭터가 한 층 위로 이동했습니다. 방문할 때마다 동일한 키, 하나의 값: 이것이 바로 접두사의 역할입니다.
접두사는 수명입니다.
프리픽스 | TTL을 짧게 설정해야 한다는 것입니다 | 몇 층 |
(없음) | 이번 방문 | 책상 |
| 이 방문자가 방문할 때마다 | 2층 서랍 |
| 모두를 위해, 영원히 | 4층의 일부 |
| 이 턴만 해당 - 계단을 오르지 않음 | — |
테이블 1개, 서랍 4개 이 장에서는 그중 하나를 다룹니다.
이제 너를 알아
👉🖥 이번 방문은 완전히 새로운 방문이며 아직 아무 말도 하지 않았습니다. 다음과 같이 질문합니다.
What did I bring in last time?
👀 랜턴을 가져오셨다고 적혀 있습니다. 케이스 k7f2입니다. q7로 표시되어 있고 밤에 계속 꺼진다고 언급하셨습니다. 이 모든 단어는 대화가 아닌 드로어에서 나왔습니다. 이 방문은 메시지가 하나이며 메시지 이름은 없습니다. 이는 사용자 수준 상태가 작동하는 방식입니다. 방문자가 말을 하기 전, 방문할 때마다 user: 키가 있습니다.
서랍에는 전표에 있는 네 줄만 들어 있고 다른 것은 없습니다. 전표에 기재되지 않은 내용(시도한 내용, 관심을 갖는 이유, 새 제품을 원하는지 여부)은 전달되지 않으며 한 달 후에는 사라집니다. 창이 월을 교차합니다. 문장은 그렇지 않습니다. 3장에서 이에 대해 설명합니다.
작성한 내용과 그 내용
선 | 기능 | 위치 |
| 접두사는 수명입니다. 방문이 아닌 방문자로 범위가 지정된 동일한 키입니다. | 2층 · |
이 단계는 한 명의 방문자에게 도달합니다. 서랍은 따라오지만 대화는 여전히 따라오지 않습니다.
5. InMemoryMemoryService
- 무엇: 하루를 정리하는 줄을 읽고, 질문하는 줄을 쓰고, 종료 시간과 질문을 하나씩 씁니다.
- 이유: 전표는 양식입니다. 양식에 사용자가 지정한 선이 있습니다. 사람들은 줄 단위로 말하지 않으며, 말한 내용을 기록하는 것은 기억하는 것의 절반에 불과합니다.
- 방법 -
file읽기,recall의 한 줄, 🌙, 🗓, 질문 하나

집으로 가는 길에 하는 일 - 읽기 전용
필드가 기억되지 않음
이 줄은 날짜를 선반에 배치합니다. 이 경우 금액이 차감되지 않습니다. 아무도 보지 않으면 카드가 가득한 선반은 빈 선반과 똑같이 도움이 되지 않습니다. 코드가 제공될 때 아무도 보지 않습니다. 모든 질문에서 Vesper 전에 실행되는 노드인 recall는 타워에 아무것도 묻지 않습니다. 적절한 순간에 떠올릴 수 없는 저장소는 기억이 아니라 로그입니다. 나머지 절반은 여러분이 직접 작성해야 합니다.
3단계: 요청
👉📖 archive/agent.py에서 file 바로 위에 있는 함수인 recall를 찾습니다. 이는 모든 질문에서 Vesper 이전에 실행되는 일반 함수 노드입니다. 모델이 언제 검색할지 결정하는 것이 아니므로 아무것도 찾지 못하는 시간도 표시됩니다. 다음까지 읽기 👉:
if query.strip():
try:
# 👉 EDIT THREE — chapter 3. Filed is not remembered: the cards are on
# the shelf and nobody is looking at them. Delete the "# " in front
# of the next line, then save:
# found = await ctx.search_memory(query)
pass
except ValueError:
# no memory service wired on this runner — degrade, do not crash
pass
👉✏️ archive/agent.py에서 recall 내부에 있는 한 줄 앞의 #를 삭제합니다(#와 그 뒤의 공백). 이전:
try:
# 👉 EDIT THREE — chapter 3. Filed is not remembered: the cards are on
# the shelf and nobody is looking at them. Delete the "# " in front
# of the next line, then save:
# found = await ctx.search_memory(query)
pass
except ValueError:
변경 후:
try:
# 👉 EDIT THREE — chapter 3. Filed is not remembered: the cards are on
# the shelf and nobody is looking at them. Delete the "# " in front
# of the next line, then save:
found = await ctx.search_memory(query)
pass
except ValueError:
pass는 그대로 두세요. found이 이미 위의 None이므로 지금은 아무것도 하지 않습니다.
저장합니다. 다시 시작하지 않습니다.
두 줄, 두 정책이 있으며 그중 하나는 내가 작성했습니다. 쓰기 정책은 보관할 항목과 시점 (종료 시간, 하루 종일)을 결정합니다. 리콜 정책은 언제 무엇을 살펴볼지 (모든 질문, 질문 자체) 결정합니다. ADK는 동사(add_events_to_memory, search_memory)를 제공하며 정책에서 제외됩니다. 이것이 올바른 분할이며, 질문을 작성해야 하는 이유입니다.
영업 종료
👉🖥 전표에 항목이 없는 세 가지를 말해 줘. 메시지 1개 또는 3개:
I read by it at night, so night is exactly when I need it.
I've tried hanging it higher. No change.
I don't want a new one — it was a gift.

👉🖥 그런 다음 🌙 오늘은 여기까지를 누릅니다.

👀 데스크를 확인합니다. 세 가지를 말하면 미끄러져 떠올라 3층에 착륙합니다. 타워 옆에 나열된 카드 아래에는 보낸 메시지별로 카드 하나가 표시됩니다. 각 카드에는 quote 기호와 함께 문장이 단어별로 표시되고 그 위에 이 과정에서라는 문구가 표시됩니다. 착륙할 때까지 책상에 있는 램프가 켜져 있습니다.
한 달 후, 그녀는
👉🖥 🗓 한 달 후를 누르고 다음과 같이 질문합니다.
What have I already tried?
👀 더 높이 걸어 봤지만 도움이 되지 않았습니다. 그녀는 알고 있습니다. 슬립에는 이 항목이 포함되어 있지 않았으며, 포함된 적도 없으므로 서랍이 이 질문에 답할 수 없었습니다. recall가 카드를 찾아 ctx.state["recalled"]에 작성했으며, recall의 안내에는 이 내용이 포함되어 있습니다. 한 줄이 차이점입니다.
모두 그녀의 머릿속에 있는 것입니다.
타워 옆의 카드 아래를 확인하세요. 이 절차에 있습니다. 현재 메모리는 InMemoryMemoryService(bash valley.sh 내부의 사전)이며 이 프로세스가 실행되는 동안 정확히 유지됩니다. 오늘 밤에 타워를 닫고 내일 열어 줘. 책은 1층에 있고, 서랍은 2층에 있고, 3층은 어두워. 케이스가 파일에 남아 있습니다. 말한 내용은 프로세스에 저장되어 있었는데 프로세스가 사라졌습니다.
지속성은 메모리가 아닙니다.
3층에는 두 가지 문제가 있습니다. 진행 중인 상황이며, 내 자신의 말이 아닌 인용구입니다. 다음 장에서는 코드를 전혀 사용하지 않고 두 문제를 모두 수정합니다.
읽은 내용, 작성한 내용, 내용
선 | 기능 | 위치 |
| 쓰기 정책 - 마감 시간의 하루 전체 | 3층 · 메모리 서비스 |
| 회상 정책 - 대답하기 전에 모든 질문 |
|
이 단계에서는 말한 내용을 파악하고 한 프로세스 내의 사전에서 자신의 말로 유지합니다. 이 두 가지 모두 잘못되었으며 다음 장에서는 코드를 전혀 사용하지 않고 두 가지 모두 수정합니다.
6. MemoryBank
- 무엇 — 하나의 스크립트가 메모리 뱅크를 빌드합니다. 이미 있는 두 줄은 메모리 뱅크에 사실을 쓰고 다시 읽습니다.
- 이유: 메모리 서비스는 서비스입니다. 보관 파일이 있는 위치는 에이전트가 아닌 배포 결정입니다. 에이전트를 건드리지 않고 변경할 수 있습니다.
- 방법:
make_tower.py를 실행하고, 세 문장을 말하고, 🌙를 누르고, 🗓를 누르고, 질문 하나를 합니다. 그런 다음 쓰기와 읽기를 읽기 전용으로 확인합니다.
타워 빌드
3장의 3층은 bash valley.sh 내의 Python 사전이었습니다. 메모리 뱅크는 이러한 바닥의 관리 버전입니다. 프로젝트의 Agent Engine 인스턴스에 있으며, 문장 대신 하루 동안 추출된 사실을 보관하고 공유된 단어가 아닌 의미로 찾습니다. Vesper를 사용하기 위해 Agent Engine에 배포할 필요는 없습니다. 아무것도 배포되지 않은 인스턴스도 메모리 뱅크를 호스팅하며, 스크립트가 빌드하는 것은 카드를 보관하는 것만이 유일한 작업인 사람이 살지 않는 탑입니다.
👉💻 탭 1 (약 1분)에서 다음 단계를 따르세요.
cd ~/agent-valley-archive
uv run python scripts/make_tower.py
👀 예상:
building the tower in YOUR_PROJECT / us-central1 — about a minute...
built, with the two topics in archive/topics.py configured on it.
resource: projects/.../locations/us-central1/reasoningEngines/6792...
AGENT_ENGINE written to .env
Next — nothing to restart. The Archive reads .env on every message:
look at floor three — under the cards it now says Memory Bank.
(adk web, if you use it: --memory_service_uri "agentengine://projects/.../reasoningEngines/6792...")
SDK 호출 1개(agent_engines.create())와 .env에 작성된 한 줄 보관 파일은 요청이 있을 때마다 해당 파일을 다시 읽으므로 다시 시작할 필요가 없습니다.
애드워즈 동영상 광고,
👉🖥 3층을 살펴보세요. 몇 초 내에 타워가 자동으로 다시 그려집니다. 이제 카드 아래에 메모리 뱅크라고 표시되고 섹션이 비어 있습니다. 3장의 인용문은 진행 중이었지만 지금은 진행 중이 아닙니다. 다음 세 문장을 한 번에 또는 세 번에 걸쳐 말하세요.
I read by it at night, so night is exactly when I need it.
I've tried hanging it higher. No change.
I don't want a new one — it was a gift.
👉🖥 🌙 오늘 일정은 여기까지입니다를 누릅니다. 이제 닫는 데 약 8초가 걸립니다. 타워가 추출되고 있습니다. 그런 다음 3층을 살펴봅니다.

👀 카드는 문장이 아닙니다. 밤에 등불을 켜고 책을 읽는데 자꾸 꺼져요, 등불을 더 높이 걸어 봤는데도 그래요와 같은 말을 하며 각 발언은 날짜와 함께 fact로 표시됩니다. 증류 입력된 내용은 대화입니다. 결과적으로 사실이 밝혀졌습니다.
👉🖥 🗓 한 달 후를 누릅니다. 새로운 방문이므로 방금 말한 내용은 더 이상 대화에 없습니다. 카드와 단어 하나도 공유하지 않는 질문을 합니다.
Should I just get a different lamp?
👀 선물로 받은 제품이라 교체를 원하지 않으시며, 이미 더 높은 곳에 걸어 보셨다고 말씀해 주셨습니다. 이 모든 정보는 카드에서 가져온 것이며, 이 방문이 1개의 메시지 이전이라는 사실은 카드에서만 알 수 있습니다. 유사성 검색 타워는 단어가 아닌 의미와 일치합니다. 질문에서는 램프와 다른이라고 말했지만 카드에는 랜턴과 교체라고 표시되어 있습니다. 이제 이 프로세스가 종료됩니다. 오늘 밤 타워를 종료하면 내일 카드가 표시됩니다. bash valley.sh가 아닌 Agent Engine에 저장되기 때문입니다.
쓰기 및 읽기(읽기 전용)
잊혀질 권리

👉🖥 메시지 상자 아래에서 🔥 나를 잊어줘를 누릅니다.
👀 3개 층은 어두워지고 1개 층은 어두워지지 않습니다.
보유한 항목 | 🔥 이후 | |
3층, 카드 | 기억한 내용: 메모리 뱅크가 방문에서 추출한 사실 | 사라짐 - |
두 번째 서랍 |
| 삭제됨 |
데스크, 슬립 | 이 방문의 케이스 사본 | 삭제됨 |
1층, 책 | 방문 자체 - 방문당 | 변경되지 않음: 개수가 이동하지 않음 |
책은 방문이 언제 이루어졌는지, 방문에서 어떤 내용이 오갔는지에 관한 기록입니다. 카드와 서랍은 기억입니다. 즉, 그녀가 방문을 통해 얻은 것과 다음 방문으로 가져가는 것입니다. 잊혀지도록 요청하는 것은 기억, 즉 개인에 관해 파생된 사실과 개인을 따라다니는 상태에 관한 것입니다. 방문 기록이 함께 삭제되는지는 별도의 이유(감사 추적, 지원 기록)로 결정되며 이 실습에서는 의도적으로 유지하므로 기록과 기억은 동일하지 않으며 하나를 잊어도 다른 하나는 영향을 받지 않습니다. 베스퍼의 문 위에 있는 문구로, 반대쪽에서 본 모습입니다.
ADK 메모리 추상화에는 add_events_to_memory 및 search_memory이 있습니다. 삭제 기능이 없습니다. 잊기는 에이전트 작업이 아닌 거버넌스 작업이므로 모델이 실수로 도달할 수 없는 애플리케이션(원시 클라이언트의 archive/tower.py, memories.delete)에 있습니다. 에이전트가 잊을 수 있는지 여부는 기억할 수 있는지 여부와 마찬가지로 설계하는 것입니다.
빌드하고 읽은 항목과 그 항목의 내용
항목 | 기능 | 위치 |
| 메모리 서비스(서비스로서): 에이전트 외부의 배포 결정 | Agent Engine의 Vertex AI 메모리 뱅크 |
| 동일한 |
|
| 유지할 수 있는 항목(프롬프트가 아닌 쓰기 시간에 결정됨) |
|
🔥 → | 잊기는 애플리케이션 작업입니다. ADK의 메모리 API에는 삭제가 없습니다. |
|
이 단계는 언급된 내용에 도달합니다. 하루가 지나면 주제에서 허용하는 내용으로 요약된 사실이 나옵니다. 1층에 있는 책은 움직이지 않았습니다.
7. GraphRAG
선택사항.
- 무엇 - 하나의 스크립트가 계곡의 과거를 BigQuery에 로드하고, 데이터 웨어하우스 내부에서 임베딩을 생성하고, 행을 이동하지 않고 테이블 위에 그래프를 배치합니다. 그런 다음 Vesper에게 두 가지 질문을 합니다. Vesper는 이에 대해 두 가지 관리형 쿼리를 가지고 있습니다. 하나는 유사한 소리에 관한 것이고 다른 하나는 연결된 것에 관한 것입니다.
- 이유: 소리가 비슷하다고 연결된 것은 아닙니다. 벡터는 어디를 봐야 하는지 찾고, 그래프는 무엇이 연결되어 있는지 찾고, 답변은 걸어온 경로를 전달해야 합니다.
- 방법 -
bash scripts/season.sh, 한 번 이 장의 다른 모든 내용은 읽기 전용입니다.
Vesper의 타워는 구조상 사용자((app_name, user_id))로 범위가 지정됩니다. 다른 사람의 방문은 그녀의 기억이 아니며, 더 열심히 검색해도 바뀌지 않습니다. 그건 밸리 소유이고 밸리에서 창고에 보관하고 있어. 이번 시즌에 31명의 방문자가 밤에 q7 랜턴이 꺼지는 것에 대해 문의했으며, 그중 한 명이 원인을 찾았습니다. 이 챕터에서는 해당 창고를 로드하고 두 개의 고정된 쿼리를 전달합니다.
그래프 RAG
RAG는 검색 후 생성입니다. 올바른 레코드를 찾아 모델에 전달하고 모델이 레코드에서 답변하도록 합니다. 일반 RAG는 유사성을 기준으로 검색합니다. 질문을 삽입하고 가장 가까운 레코드를 가져옵니다. 질문과 비슷한 내용을 찾아주며, 4장의 타워가 멈춘 곳입니다. 그래프 RAG는 창고에 이미 있는 키인 가장자리를 따라 유사성에서 연결된 항목으로 이동하는 두 번째 검색 단계를 추가합니다. 두 단계는 서로 다른 질문에 답하며, 이 장에서는 두 질문을 모두 묻습니다.
단계별 방법 | 답변하는 질문 | 방법 | 이 장에서 |
유사성 | 어디를 살펴봐야 하나요? | 질문을 삽입합니다. |
|
순회 | 무엇이 연결되어 있나요? |
|
|
생성 | 방문자에게 뭐라고 말해야 하나요? | 모델, 경로를 인용으로 사용 | 그녀의 대답 |
실행하기
시즌은 지원 시스템에서 내보내는 방식대로 season/(방문자, 항목, 요청, 수정, 시즌)에 일반 CSV로 제공됩니다. 하나의 스크립트가 창고까지 모든 과정을 안내하며 이 챕터에서 실행하는 유일한 스크립트입니다.
👉💻 탭 1 (약 3분 소요, 각 단계를 진행하면서 출력하고 실패한 첫 번째 단계에서 중지됨):
cd ~/agent-valley-archive
bash scripts/season.sh
👀 종료되면 타워의 4층에 불이 들어오고 옆의 범례에 열림이라고 표시됩니다.
빌드된 항목 - 읽기 전용
읽기 방식 - 읽기 전용
물어봐
👉🖥 타워의 4층이 열려 있습니다. 방문자가 하는 것처럼 물어보세요.
Has anyone else had a q7 lantern go out at night?

👀 그녀는 대답합니다. 31명이 더 있습니다. 대부분은 불꽃이 낮게 앉아 있다가 한 시간 후에 꺼졌다고 말했습니다. 수달 말로는 심지가 너무 얕게 담겨 있다고 생각했습니다. 대답의 마지막 줄이 경로입니다. 다음은 그녀의 출력입니다. 읽기만 하고 그녀에게 다시 보내지는 마세요.
mark q7 → 31 visits this season → 10 different things said → the wicks in the q7 batch were dipped too shallow — they drown in the oil and starve in an hour
경로는 인용입니다. 여기서 각 홉은 그래프의 가장자리이고 가장자리는 키이므로 누구나 다시 걸어 동일한 31을 얻을 수 있습니다. 유사성 점수는 누구도 다시 확인할 수 없습니다. 경로 바로 전에 프로젝트에 그래프 예약이 없어서 행이 세 번의 조인을 통해 반환되었다고 말한다면 프로젝트의 버전에서 GRAPH_TABLE를 거부한 것입니다. 행과 경로는 동일합니다.
👉🖥 이제 마크를 제외하고 다음을 전송합니다.
Has anyone else had a lantern that keeps dying once the sun is down?
👀 동일한 31과 동일한 경로를 얻습니다. 달라진 점은 경로입니다. season_search가 먼저 실행되어 비슷한 5명의 방문자를 찾고(각각 q7 보유) 해당 표시를 가져온 후 걸었습니다. 유사한 항목은 연결되지 않습니다. 유사한 항목은 어디를 살펴봐야 하는지를 나타냅니다.
로드된 항목과 해당 항목
항목 | 기능 | 위치 |
명시적 스키마가 있는 | 창고: 이름과 유형이 있는 열 |
|
| 유사성 단계 - 살펴볼 위치 |
|
| 탐색 단계: 연결된 항목, 테이블이 노드와 화살표가 됨 |
|
| 그녀가 걸을 수 있는 유일한 길입니다. 경로는 인용입니다. |
|
방문자가 수십 명에 불과하다면 창고를 구매할 이유가 없습니다. 이 장에서는 규모가 아닌 쿼리의 모양을 가르칩니다. 이 그래프를 1,000배로 늘려도 MATCH는 한 글자도 바뀌지 않습니다.
8. 닫기
3개의 라인, 1개의 타워, 1개의 창고, 4개 층 다시 시작된 항목이 없습니다.
단계 | 한 일 | 구매한 항목 |
ONE |
| 슬립이 전혀 없는 경우: 상태가 코드로 작성됨 |
2 |
| 방문자를 따라가는 드로어 |
파일 |
| 말한 내용이 보관됨 |
3 |
| 보관된 항목, 요청된 항목, 제출된 항목이 기억되지 않음 |
타워 |
| 밤을 버티고 정제하는 탑 |
규칙 |
| 보관해야 하는 항목만 |
시즌 |
| 의미 및 연결별로 다른 모든 사용자의 방문 |
각 조각이 대체한 항목
ADK 2 | 대신 작성할 내용 | 비용 |
| 채팅 루프 옆에 있는 dict를 직접 디스크에 피클링 | 모델이 읽을 수 없으며, 이력서와 잠금을 |
| 사용자 테이블과 매 턴마다 조인 | 매번 키가 속한 위치를 결정해야 합니다. |
함수 노드에서 | 스크립트를 덤프하는 cron과 언제 스크립트를 확인할지 결정하는 모델 | 덤프만 되고 증류는 되지 않으며, 룩이 없었던 시간은 표시되지 않습니다. |
| 벡터 스토어, 추출 프롬프트, 통합 작업, 프롬프트의 '사소한 내용은 기억하지 마세요' | 세 가지 서비스를 제공하며, 모델이 다르게 느끼기 전까지는 규칙이 유지됩니다. |
| 내보내기, 다른 곳에 삽입, 그래프 데이터베이스, 동기화 작업, 모델 쓰기 SQL | 데이터가 웨어하우스를 떠나 이해되고 고객이 |
세 가지 질문, 첫 번째 '예'에서 중단
- 내일도 중요할까요? 아니요 → 아무것도 보관하지 않습니다. 대화에서 살아남거나 사라집니다.
- 함수로 확인할 수 있나요? 예 → 서랍 코드는 이를 작성하고, 모든 턴에서 이를 읽으며, 어떤 문장도 이를 변경할 수 없습니다.
- 그 외의 경우 → 타워 요청 시 검색되고, 다음에 말한 내용에 따라 수정됩니다.
한 문장
기록은 메모리가 아닙니다. 메모리는 기록과 두 가지 결정(보관할 내용과 확인할 시점)으로 구성되며, 어떤 종류의 내용인지에 따라 어느 층에 저장될지가 결정됩니다.
사실과 환경설정은 서로 다른 스토어에 속합니다.
👀 모든 층에 불이 켜져 있습니다. 상단에 familiar가 표시됩니다. 아카이브 스탬프는 여권에 있으며 5주 차에는 야시장이 열립니다. 여기에서 닉스는 무대를 실시간으로 크게 운영하며, 타워가 아는 모든 것이 함께 제공됩니다.