הארכיון – זיכרון בעמק הסוכנים

1. מבוא

וספר, הארכיונאית, יושבת ליד השולחן בקומת הקרקע

בשבוע הראשון שאלת מי אומר מה רץ. בשבוע השני שאלנו מי מחליט מה יופעל בהמשך. בשבוע השלישי נשאלת השאלה מה נשאר אחרי ריצה. השבוע השיחה מסתיימת, והשאלה היא מה שורד ממנה – מסתבר שמה זה קובע לאן זה יגיע.

הארכיון הוא המקום שאליו מגיעים כשמשהו השתבש. מגדל שבו הכל מתועד, ווספר, הארכיונאי, יושב ליד השולחן בקומת הקרקע. הפנס נכבה בלילה. אתה הולך ושואל.

נעים להיות בחברתה. חודש לאחר מכן, היא שמחה לפגוש אותך.

רשומה היא לא זיכרון.

המשפט הזה הוא כל שיעור ה-Lab. הטיפוס במגדל מתבצע בארבעה שלבים, וכל שלב הוא קומה במגדל:

שלב

הרצפה

מה הוא זוכר

מה שומר עליו

1

השולחן והרצפה

הביקור הזה

session.state · SqliteSessionService

2

קומה שנייה, המגירה שלך

המבקר הזה

הקידומת user:

3

קומה שלישית, המגדל

מה נאמר

‫Vertex AI Memory Bank

4

קומה רביעית, העונה

the whole valley

BigQuery

כל עלייה בסולם נובעת מכך שמשהו נפל מהשלב שמתחת.

הארכיון, חתך פתוח – חמש קומות, וצוות קטן ששומר על כל אחת מהן

אתם כבר מכירים את חמש הדרכים של הארכיונאי לשכוח, כי כל אחת מהן קרתה לכם בשיחת תמיכה:

מה שהיא אומרת

מה השתבש

‫~~1~~

‫~~Could you give me that reference again?~~

‫~~forgot within one conversation~~ — week three fixed this

~~2~~

~~העברתי אותך. Please start from the beginning.~~

~~ההיסטוריה נעלמה עם התהליך~~ – בשבוע השלישי גם זה תוקן

3

ברוכים הבאים! איך אוכל לעזור לך?

למישהו עם פנייה פתוחה מהחודש שעבר

4

אפשר לתאר את הנזק?

בפעם האחרונה היא הסתכלה על הפנס

5

לא נתקלנו בזה בעבר.

‫31 אנשים שאלו העונה

הקו השלישי הוא של השבוע הנוכחי. הוא נכשל בשלוש דרכים שונות – ביקור חדש (פרק 2), משפט בלי שורה על הפתק (פרק 3) וארכיון שקיים רק בתוך התהליך (פרק 4) – וכל דרך היא פרק. השורה הרביעית היא בשבילך: look() בarchive/agent.py היא קוראת סימן מתמונה. בשורה חמש מופיע פרק 5, והיא אופציונלית.

לא צריך להשתמש בנתונים של שבועות 1 עד 3. סוכן הוא מודל עם הוראה וכמה כלים. כל השאר מוסבר מעצמו.

תכתוב שלוש שורות, וכל אחת מהן היא מושג זיכרון:

הקו

מה זה

tool_context.state[CASE] = case

המצב נכתב על ידי הקוד, אף פעם לא על ידי השיחה

CASE = "user:case"

תחילית היא משך חיים

found = await ctx.search_memory(query)

מדיניות הביטול – לא נשמרת

כבר יש שורה נוספת שאתם יכולים לקרוא – מדיניות הכתיבה, await ctx.add_events_to_memory(...) – ובפרק 3 תוכלו לקרוא מה היא עושה לפני שתכתבו את השורה שמשתמשת בה.

שתי הפעולות האחרות הן לא עריכות בכלל: בונים מגדל (מנוע סוכנים שמארח את Memory Bank) ואותו קוד מתחבר אליו באופן עצמאי, וטוענים מחסן נתונים (BigQuery), מציבים מעליו גרף ומעבירים לאותו סוכן שתי שאילתות מנוהלות – אחת לפי משמעות ואחת לפי חיבור.

בכל פרק מופעלת אותה לולאה, והיא הלולאה שתשתמשו בה בסוכנים שלכם: קריאת הקוד ← כתיבת השורה ← צפייה בה במגדל. שום דבר לא מופעל בצורה שבורה, שום דבר לא מופעל מחדש ושום דבר לא מופעל באמצעות Ctrl+C: כל עריכה נאספת בהודעה הבאה, וחיבור המגדל הוא שורה אחת בקובץ שהארכיון קורא מחדש בכל בקשה. המגדל הוא ציור שמשורטט מחדש: הוא קורא את אותם קבצים שאתם עורכים, ויש לו שלושה לחצנים – 🌙 מסמן את סוף היום, 🗓 מתחיל את הביקור הבא ו-🔥 שוכח אתכם. כל שאר הפעולות שאתם מבצעים בקוד ובטרמינל.

שני מקומות, והם אף פעם לא משנים עבודה: כרטיסייה 1 היא המסוף, כרטיסייה 2 היא הארכיון. סביבת העבודה (adk web) מופיעה בדיוק פעם אחת, בפרק 1, כדי להציג את מצב הסשן הגולמי, ואז מסיימים את השימוש בה. בכל מקום שמופיע הסימן 👉 בהמשך, מצוין איזה סוג של תשלום הוא. ‫👉💻 היא כרטיסייה 1, ‏👉🖥 היא כרטיסייה 2, ‏👉🔬 היא סביבת העבודה. ‫👉📖 הוא פתיחת קובץ וקריאה – אין מה לשנות – ו-👉✏️ הוא סוג השלב היחיד שבו מתבצעת עריכה. בכל פעם שמופיע שלב שבו צריך להגיד משהו ל-Vesper, ההודעה המדויקת מופיעה בבלוק שמתחתיו – צריך להעתיק אותה כמו שהיא. ובקטע שהכותרת שלו מסתיימת ב-— read only, לא צריך להקליד, להדביק או ללחוץ על שום דבר: הקוד שבו כבר נמצא במאגר ופועל, והוא מודפס כדי שתוכלו לקרוא אותו.

המשפט מעל הדלת של וספר הוא המשפט שמופיע למעלה. המשפט שחותם את השבוע הזה הוא שורת הסיום של השבוע הרביעי בעונה כולה:

עובדות והעדפות שייכות למאגרי מידע שונים.

2. 🧰 הגדרה

  • מה – מצביעים על פרויקט או מדביקים מפתח, מתקינים ומוודאים ששרשרת הכלים ירוקה.
  • למה – לא מתבצעת כאן שום אתחול. כל שרת מתחיל לפעול רגע לפני השלב שבו הוא נדרש, כך שכאשר מסך נפתח, אתם יודעים איזו פקודה שייכת לו.
  • איך – סקריפט אחד שיוצר את הפרויקט, סקריפט אחד שמתקין ומפנה אתכם אל Vertex AI, וסקריפט אחד של בדיקה לפני טיסה שקורא את הקוד ומציין את המיקום שלכם.

כל מה שמופעל במעבדה הזו מופעל ב-Cloud Shell –‏ Python, ‏ uv ו-gcloud כבר מותקנים שם, והגישה אל Gemini מתבצעת דרך Vertex AI באמצעות פרטי הכניסה שלכם. אין מפתח API בשום מקום במעבדה הזו, ואין צורך להתקין שום דבר במחשב הנייד.

יש דבר אחד שלא תוכלו לקבל במעבדה הזו: פרויקט בענן של Google עם חיוב מופעל. בשלב 1 מקבלים חשבון שאפשר לשלם באמצעותו, ובשלב 4 הופכים את החשבון הזה לפרויקט – או בוחרים את פרויקט Agent Valley שכבר יצרתם בשבוע הראשון, השני או השלישי. צריך לבצע את הפעולות לפי הסדר הזה – כל שלב אחרי שלב 4 קורא את הפרויקט שנקבע בשלב 4.

‫1 · יצירת חשבון עם חיוב (~דקה)

🌐 חשוב לעשות את זה לפני כל דבר אחר. נכנסים לחשבון Google שמוגדר בו חיוב. כל חשבון כזה יעבוד. אם אין לכם חשבון כזה, תוכלו להתחיל תקופת ניסיון בחינם. תקבלו חשבון לחיוב, וזה כל מה שצריך בשלב 4.

‫2 · פתיחת Cloud Shell (כדקה)

‫🌐 לוחצים על Activate Cloud Shell בחלק העליון של מסוף Google Cloud – זהו הסמל בצורת טרמינל בכותרת.

הפעלת Cloud Shell מכותרת מסוף Google Cloud

🌐 לוחצים על פתיחת הכלי לעריכה (סמל של תיקייה פתוחה עם עיפרון). ייפתח Cloud Shell Editor עם סייר קבצים בצד ימין – שם עובדים בכל פעם שמופיע השלב 👉✏️.

פתיחה של Cloud Shell Editor

🌐 אם תתבקשו לאשר בשלב כלשהו היום, לחצו על אישור כדי להמשיך.

‫🌐 פותחים חלון של Terminal בתוך העורך – כלומר כרטיסייה 1, וכל שלב 👉💻 מופעל שם אלא אם מצוין אחרת. כרטיסייה 2 היא הארכיון, והיא נפתחת בפרק 1, ממש לפני השלב שבו צריך אותה. אם הטרמינל לא נמצא בחלק התחתון של המסך, פותחים אותו באמצעות View → Terminal:

פתיחת טרמינל חדש ב-Cloud Shell Editor

‫🌐 בודקים לאיזה חשבון אתם מחוברים – זה צריך להיות החשבון משלב 1:

gcloud auth list

‫3 · מקבלים את המעבדה (כדקה)

‫💻 משכפלים את מאגר התוכן – זהו מאגר הארכיון, לא מאגר התוכן של שבוע ראשון, שבוע שני או שבוע שלישי:

cd ~
git clone https://github.com/cuppibla/agent-valley-archive
cd agent-valley-archive

‫4 · יצירת הפרויקט – או שימוש חוזר בפרויקט משבוע קודם (כ-2 דקות)

‫💻 סקריפט אחד מוצא את החשבון לחיוב, יוצר בו פרויקט ומפנה את Cloud Shell לפרויקט הזה. אם השתמשתם בפרויקט 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 הוא מזהה הפרויקט – המזהה שלכם יהיה שונה. ארבעה דברים קורים שם:

billing

מערכת החיוב תשתמש בחשבון [YYYY-MM-DD] GDP Credit: החדש ביותר, אם יש כזה, או בכל חשבון אחר לחיוב שפתוח.

project

מחפש פרויקט Agent Valley שכבר בבעלותכם – מהשבוע הראשון, השני או השלישי – ומציע להשתמש בו מחדש. אם לא נמצא פרויקט כזה, המערכת יוצרת את agent-valley-XXXX ומקשרת אליו את החשבון לחיוב.

selects

כותב את המזהה ל-~/project_id.txt ומריץ את gcloud config set project, כך שלא תתבקשו להקליד אותו בשום שלב אחרי זה.

waits

סקרים עד שהפרויקט מורשה להצגה בפועל, למשך עד שתי דקות

‫🌐 אותו פרויקט מופיע עכשיו במסוף – המזהה שלו נמצא בכרטיס Project info במרכז הבקרה:

מזהה הפרויקט בלוח הבקרה של המסוף

‫5 · התקנה והפניה אל Vertex AI (~3 min)

‫💻 מתקינים את 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

‫$(gcloud config get project) מחזירה ערך כלשהו כי היא הוגדרה בשלב 4. זו הסיבה לכך ששלב 4 מופיע ראשון.

‫setup_codelab.sh היא אידמפוטנטית – אפשר להריץ אותה שוב כמה פעמים שרוצים. הוא מבצע חמש פעולות, לפי הסדר:

api

קורא את הפרויקט שנבחר בשלב 4 ומפעיל בו את aiplatform.googleapis.com (Vertex AI ואת Agent Engine שמארח את Memory Bank) ואת bigquery.googleapis.com (המחסן של פרק 5)

uv env

‫uv venv יוצר .venv, או משתמש מחדש בקיים, ואז uv sync מתקין בדיוק את מה ש-uv.lock מצמיד – google-adk, google-genai וכל מה שמתחתיהם

site

פועל npm ci ב-site/ – הארכיון עצמו הוא אפליקציית Next.js – לכן bash valley.sh בפרק 1 לא נשאר שום דבר להורדה; המערכת מדלגת על הפעולה הזו אם החבילות כבר קיימות

‎.env

כותב את המשתנים שהמעבדה קוראת – GOOGLE_GENAI_USE_VERTEXAI, ‏ GOOGLE_CLOUD_PROJECT, ‏ GOOGLE_CLOUD_LOCATION, ‏ MEMORY_BANK_LOCATION ו-BQ_DATASET, ואין מפתח API בשום מקום

בדיקת המודל

מבצע שיחה אמיתית אחת עם Gemini, כך שאם הפרויקט לא טוב, הוא ייכשל בשלב ההגדרה ולא בשלב מאוחר יותר בתוך הפרק

‫6 · הוכחה שהיא ירוקה (כדקה)

‫💻 מריצים את הבדיקה המקדימה – כל סימן הוא בדיקה אמיתית, לא ניחוש:

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. Session, State, 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}}

הפונקציה יוצרת את השובר במילון מקומי ואז מחזירה אותו – ומילון מקומי נמחק עם הקריאה. אם מריצים את הפקודה כמו שהיא, Vesper שומע אתכם בצורה מושלמת: ארבעה write_down קריאות מופעלות, כל אחת מהן עונה "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}}

שמירה.

הכרטיסייה מתמלאת

‫👈💻 מפעילים את סביבת העבודה. זו הפעם היחידה שבה פותחים את החלון הזה בשיעור ה-Lab – זה החלון היחיד שבו מוצג מצב הסשן כ-JSON גולמי:

cd ~/agent-valley-archive
uv run adk web . --allow_origins="*"

‫👈🔬 פותחים את סביבת העבודה באמצעות Web Preview → Preview on port 8000 (הלחצן Web Preview הוא סמל העין מעל חלון בפינה השמאלית העליונה של Cloud Shell). בוחרים באפשרות ארכיון, ולפני שמקלידים משהו, לוחצים על מצב בחלונית הימנית.

‫👀 Empty (ריק). אף אחד עוד לא אמר כלום.

‫👉🔬 עכשיו תגיד את זה, הכל בהודעה אחת:

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 מופעלים – לוחצים על אחד מהם וקוראים את ה-JSON: "written": {"no": "k7f2"}. לוחצים שוב על מצב.

ארבעה דברים, ארבעה שדות, הודעה אחת

case   {"no": "k7f2", "item": "lantern", "mark": "q7",
        "symptom": "keeps going out at night"}

👀 ריק, ואז מלא, בתוך הודעה אחת. זה מה שהיא זוכרת, והתמונה לא הופיעה לבד. אתם כתבתם את השורה שכותבת אותו. זה כל המנגנון: פונקציה פשוטה שכותבת לתוך tool_context.state, והוראה שאומרת לה להשתמש בה בכל פעם שהמבקר אומר משהו שמתאים לשורה בפתק.

‫👉🔬 שואלים אותה:

What's my case number?

‫👀 k7f2. היא קוראת את זה מהפתק. בלי הפקודה EDIT ONE, היא הייתה מבקשת ממך את זה – שורה אחת ברשימת התמיכה, בתוך שיחה אחת.

שני השומרים הם שהפתק הוא טופס נייר: ארבע שורות קצרות, כל אחת כתובה פעם אחת. הם חשובים יותר ממה שנראה. בלי ההנחיות האלה, המודל מבין שהוא יכול להעביר את כל השיחה אל symptom, והפרק השלישי – הפרק שכל המטרה שלו היא שאין שורה כזו בטופס – מפסיק להיות נכון. הקוד שכותב את הצורה של החנות אוכף אותה, או שלא אוכף אותה.

עכשיו צריך לעבור למגדל

‫👈💻 סיימתם את העבודה בסביבת העבודה – אפשר להשאיר אותה פתוחה או לסגור את הכרטיסייה שלה. שאר התוכן של ה-Lab נמצא בארכיון. פותחים כרטיסייה שנייה של Terminal (כרטיסייה 2 – הארכיון):

cd ~/agent-valley-archive
bash valley.sh

‫👈🖥 פותחים את הארכיון באמצעות תצוגה מקדימה באינטרנט → שינוי יציאה, מקלידים 3440 ולוחצים על שינוי ותצוגה מקדימה. המספר 3440 לא מופיע ברשימה המהירה של Web Preview – ברירת המחדל היא 8080 – ולכן צריך להגדיר אותו באופן ידני בפעם הזו. לוחצים על ▶ התחלה ואז על הארכיון. מישהו מחוץ לדלת. בוחרים את מי שהגיע לבקש – שם ומין – ונכנסים.

המגדל, חתך

‫👀 בניין אחד. וספר יושב ליד השולחן בקומת הקרקע, ושם מתנהלת השיחה. מעליה: קומה ראשונה, קומה שנייה, קומה שלישית ועליית גג חשוכה. ארבעת השלבים הם ארבע הקומות. החיה הנאמנה שלך יושבת בקומת הקרקע, כי זה הגובה שאליו טיפסת. בעמודה שליד הציור מפורט מה יש בכל קומה כרגע – אותן ארבע חנויות כמו בטבלה שבמבוא, באותו הסדר. אף אחד מהפריטים בצד שמאל הוא לא לחצן.

‫👉🖥 מדביקים את אותם ארבעת הדברים בתיבה שמתחת לשיחה – בדיוק את ההודעה הזו – ומקישים על 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 כתב, והוא ימשיך לעשות את זה עד סוף המעבדה.

היא זוכרת את ההגדרות למשך הלילה – קריאה בלבד

מה שכתבתם ומה זה

הקו

מה זה

איפה הוא נמצא

tool_context.state[CASE] = case

מצב הסשן – נכתב על ידי הקוד, נקרא על ידי ההוראה

שולחן העבודה הווירטואלי · session.state

‫SqliteSessionService(DB) — אתם רק קוראים אותו

החנות של הסשן – ביקור בקובץ, לא בתהליך

קומה ראשונה · archive.db

השלב הזה נמשך ביקור אחד, והוא נמשך גם אחרי שעות הסגירה. הוא לא נשמר לביקור הבא.

4. מצב המשתמש

  • מה – חוזרים חודש אחרי כן, והטעות נעלמה. חמישה תווים, והוא עוקב אחריכם.
  • למה – סשן הוא ביקור אחד. הביקור הבא הוא סשן חדש, והוא לא קשור לסשן הקודם.
  • ‫How – חמישה תווים ב-state.py.

חודש לאחר מכן. נעים מאוד.

לוחצים כאן

‫👉🖥 לוחצים על 🗓 חודש לאחר מכן. זוהי סשן חדש של אותו מבקר – כמו התחלת שיחה חדשה בשבוע השלישי.

ברוכים הבאים לארכיון. איך אוכל לעזור לך?

‫👉🖥 מסתכלים על המגדל. בקומה הראשונה יש ספר נוסף – בביקור הזה. המגירה בקומה השנייה ריקה. הפתק על השולחן ריק.

ספר נוסף בקומה הראשונה; המגירה ריקה; הפתק ריק

👀 למה: ההחלקה נרשמת במצב הסשן, וסשן הוא הביקור הזה. שינוי ביקורים, שינוי סשנים. לא הועבר שום דבר כי לא הוגדר שיועבר משהו. הביקור האחרון עדיין נמצא בקובץ – כלומר, הספר הראשון בקומה הראשונה – אבל הפתק נכתב תחת מפתח שפעיל רק לביקור אחד.

עריכה שנייה

‫👉✏️ פותחים את 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"

שמירה. ללא הפעלה מחדש – הארכיון מייבא מחדש את הקוד בכל הודעה.

‫👉🖥 מדביקים שוב את אותם ארבעה דברים – בדיוק את ההודעה הזו:

Hi! My lantern keeps going out at night. My case number is k7f2, and there's a little q7 stamped on the base.

‫👉🖥 לוחצים שוב על 🗓 חודש לאחר מכן – אותו לחצן כמו קודם.

חלונית ההזזה, עם שם עליה

👀 המגירה בקומה השנייה נושאת את השם שלך, וארבעת השדות נמצאים בתוכה. הפתק על השולחן הוא אותן ארבע שורות – הוצאתי אותו מהמגירה כשנכנסת. החיה המוכרת שלך עלתה קומה. אותו מפתח, בכל ביקור, ערך אחד: הקידומת עושה את העבודה.

התחילית היא לכל החיים.

תחילית

כמה זמן הוא פעיל

באיזו קומה

(none)

הביקור הזה

השולחן

user:

בכל ביקור של המבקר

קומה שנייה, המגירה שלך

app:

לכולם, לנצח

חלק מקומה 4

temp:

בפנייה הזו בלבד – אף פעם לא עולה במדרגות

—

שולחן אחד, ארבע מגירות. בפרק הזה נתייחס לאחת מהן.

היא מכירה אותך עכשיו

‫👈🖥 זה ביקור חדש לגמרי, ועדיין לא אמרת כלום. אפשר לשאול אותה:

What did I bring in last time?

👀 לפי הרישומים שלי, הבאת פנס, מספר הפנייה k7f2. הוא מסומן ב-q7 ואמרת שהוא מפסיק לפעול בלילה. כל מילה שנאמרה יצאה מהמגירה, לא מהשיחה – הביקור הזה הוא הודעה אחת, וההודעה לא נקראת כלום. זהו מצב ברמת המשתמש שמבצע את העבודה שלו: מפתח user: קיים לפני שהמבקר אומר מילה, בכל ביקור שהוא מבצע.

המגירה מכילה את ארבע השורות שמופיעות בפס, ולא שום דבר אחר. מה שאתם אומרים שלא מופיע בשורה בתלוש – מה ניסיתם, למה זה חשוב לכם, אם אתם רוצים תלוש חדש – לא מגיע לשום מקום, ואחרי חודש הוא נעלם. חלונית ההזזה חוצה את החודש. משפט לא. פרק 3 עוסק בכך.

מה שכתבתם ומה זה

הקו

מה זה

איפה הוא נמצא

CASE = "user:case"

קידומת היא לכל החיים – אותו מפתח, בהיקף המבקר במקום הביקור

קומה שנייה · user:

השלב הזה מגיע למבקר אחד. חלונית ההזזה עוקבת אחריכם, אבל השיחה לא.

5. InMemoryMemoryService

  • מה – קוראים את השורה שמתארת את היום, כותבים את השורה ששואלת, ואז שעת סגירה אחת ושאלה אחת.
  • למה – השובר הוא טופס. הטופס כולל את השורות שנתת. אנשים לא מדברים בשורות – ותיעוד של מה שהם אמרו הוא רק חצי מהזיכרון.
  • איך – קוראים את file; שורה אחת ב-recall; ואז סמל אחד של ירח, סמל אחד של לוח שנה ושאלה אחת.

שעת סגירה. היא חוזרת על עקבותיה ועוברת ליד המדפים.

מה היא עושה בדרך הביתה – קריאה בלבד

השדה לא נשמר

הקו הזה מעביר את היום למדף. היא לא מסירה ממנו שום דבר. מדף מלא בכרטיסים לא עוזר יותר ממדף ריק אם אף אחד לא מסתכל עליו – וכשהקוד נשלח, אף אחד לא מסתכל עליו: recall, הצומת שפועל לפני Vesper בכל שאלה, לא שואל את המגדל שום דבר. אחסון שלא ניתן לשחזר ברגע הנכון הוא לא זיכרון, אלא יומן. החלק השני הוא שלכם, ואתם יכולים לכתוב אותו.

עריכה שלישית – הבקשה

‫👈📖 ב-archive/agent.py, מחפשים את recall – הפונקציה שנמצאת ממש מעל file. זהו צומת פונקציה פשוט שפועל לפני 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 – ולא מתייחסת למדיניות. זה הפיצול הנכון, ולכן ביקשתי ממך לכתוב את השאלה.

שעת הסגירה

‫👉🖥 תגיד שלושה דברים שאין להם שורה בפתק. הודעה אחת או שלוש:

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.

אפשר ללחוץ כאן

‫👉🖥 ואז לוחצים על 🌙 זה הכול להיום.

המילים עולות

‫👀 צופים בשולחן העבודה. שלושת הדברים שאמרת ממריאים מהנייר וצפים למעלה, ונוחתים בקומה השלישית. מתחת לכרטיסים שליד המגדל מופיעה רשימה – כרטיס אחד לכל הודעה ששלחתם, עם הסימון quote, המשפטים שלכם מילה במילה וההערה בתהליך הזה מעליהם. המנורה על השולחן נשארת דולקת עד שהם נוחתים.

חודש אחר כך, היא יודעת

‫👉🖥 לוחצים על 🗓 חודש לאחר מכן ושואלים:

What have I already tried?

👀 ניסית לתלות אותו גבוה יותר – זה לא עזר. היא יודעת. אין שורה כזו בפתק, ולא הייתה אף פעם, ולכן המגירה לא יכלה לענות על השאלה הזו. recall מצאה את הכרטיס, כתבה אותו ב-ctx.state["recalled"], וזו ההוראה שלה. ההבדל הוא בשורה אחת.

וזה הכול בראש שלה

מתחת לכרטיסים, לצד המגדל: בתהליך הזה. כרגע הזיכרון הוא InMemoryMemoryService – מילון בתוך bash valley.sh, והוא קיים בדיוק כל עוד התהליך הזה מתבצע. תסגור את המגדל הלילה ותפתח אותו מחר: הספרים נמצאים בקומה הראשונה, המגירה בקומה השנייה והקומה השלישית חשוכה. האותיות הקטנות נשמרו בקובץ. מה שאמרתם היה חלק מהתהליך, והתהליך הסתיים.

התמדה היא לא זיכרון.

יש שתי בעיות בקומה השלישית כמו שהיא מוצגת: היא בתהליך, והיא מנוסחת במילים שלכם – ציטוט, לא עובדה. בפרק הבא נתקן את שתי הבעיות האלה, בלי להשתמש בקוד בכלל.

מה קראתם, מה כתבתם ומה זה

הקו

מה זה

איפה הוא נמצא

‫await ctx.add_events_to_memory(events, custom_metadata=FILING) – אתם רק קוראים אותו

מדיניות הכתיבה – יום שלם, בשעת הסגירה

קומה שלישית · שירות הזיכרון

‫found = await ctx.search_memory(query) — עריכה שלוש

מדיניות ההחזרה – כל שאלה, לפני שהיא עונה

recall() ← ctx.state["recalled"]

בשלב הזה, המודל מגיע למה שנאמר – ושומר את זה במילון בתוך תהליך אחד, במילים שלכם. שני החלקים האלה שגויים, ובפרק הבא מתקנים את שניהם בלי קוד בכלל.

6. MemoryBank

  • מה – סקריפט אחד בונה Memory Bank; שתי השורות שכבר יש לכם מתחילות לכתוב עובדות ב-Memory Bank ולקרוא אותן בחזרה.
  • למה – שירות זיכרון הוא שירות. המיקום של הארכיון הוא החלטה שקשורה לפריסה ולא לסוכן – אפשר לשנות אותו בלי לגעת בסוכן.
  • איך – מפעילים את make_tower.py, אומרים שלוש משפטים, לוחצים על 🌙, לוחצים על 🗓, שואלים שאלה אחת. אחר כך, תהיה לכם גישה לקריאה בלבד לנתוני הכתיבה והקריאה.

בניית המגדל

קומה 3 בפרק 3 הייתה מילון Python בתוך bash valley.sh. Memory Bank היא הגרסה המנוהלת של השכבה הזו: היא נמצאת במופע Agent Engine בפרויקט שלכם, היא שומרת עובדות שחולצו מהיום במקום משפטים, והיא מוצאת אותן לפי משמעות ולא לפי מילים משותפות. לא צריך לפרוס את Vesper ב-Agent Engine כדי להשתמש בו – מופע שלא נפרס בו כלום עדיין מארח Memory Bank, וזה מה שהסקריפט בונה: מגדל שאף אחד לא גר בו, והתפקיד היחיד שלו הוא לשמור את הכרטיסים.

‫👉💻 בכרטיסייה 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‏, agent_engines.create(), ושורה אחת שנכתבה ב-.env. הארכיון קורא מחדש את הקובץ הזה בכל בקשה, כך שאין צורך להפעיל מחדש שום דבר.

איך זה עובד

‫👈🖥 מסתכלים על קומה שלוש – המגדל מצייר את עצמו מחדש תוך כמה שניות. מתחת לכרטיסים מופיע עכשיו הכיתוב Memory Bank, והמדף ריק: שלושת הציטוטים מפרק 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.

משמאל: מה שהיא זוכרת. מימין: מה שנשמר במגדל.

‫👀 הכרטיסים הם לא משפטים שלכם. הם אומרים דברים כמו אני משתמש בפנס כדי לקרוא בלילה, ואז הוא כל הזמן נכבה וניסיתי כבר לתלות את הפנס במקום גבוה יותר, וכל אחת מההערות מסומנת ב-fact עם תאריך. זיקוק. מה שהזנתם היה שיחה. התוצאה היא עובדות.

‫👈🖥 לוחצים על 🗓 חודש לאחר מכן – זה ביקור חדש, ולכן שום דבר שאמרתם לא נמצא יותר בשיחה – ושואלים אותה את השאלה הבאה, שאין בה אף מילה משותפת עם הכרטיסים:

Should I just get a different lamp?

👀 מאחר שקיבלת את הפנס במתנה, ציינת שאתה לא רוצה להחליף אותו – וניסית כבר לתלות אותו גבוה יותר. כל מילה שאמרתי הגיעה מהכרטיס, ורק הכרטיס יכול היה לומר לה: הביקור הזה הוא הודעה אחת. חיפוש לפי דמיון. התמונה מתאימה למשמעות, לא למילים – בשאלה נכתב מנורה ולהחליף, ובכרטיס נכתב פנס ולהחליף. הוא כבר לא חלק מהתהליך: אם תכבו את המגדל הלילה, הכרטיסים יהיו שם מחר, כי הם נמצאים ב-Agent Engine ולא ב-bash valley.sh.

הכתיבה והקריאה – קריאה בלבד

הזכות להישכח

לוחצים כאן

‫👉🖥 לוחצים על 🔥 forget me (תשכח אותי) מתחת לתיבת ההודעה.

‫👀 שלוש קומות מחשיכות ואחת לא:

מה הוא מכיל

אחרי 🔥

floor three, the cards

מה היא זוכרת – העובדות שמאגר הזיכרון זיקק מהביקורים שלכם

הכרטיס נעלם – memories.delete, כרטיס אחד בכל פעם

קומה שנייה, המגירה

user:case, פתק שמועבר מהמבקר מביקור לביקור

נוקה

השולחן, הפתק

עותק הבקשה שנוצר במהלך הביקור

נוקה

קומה ראשונה, הספרים

הביקורים עצמם – סשן אחד ב-archive.db לכל ביקור, כל הודעה בו

ללא שינוי – המספר לא משתנה

הספרים הם התיעוד: שהיה ביקור, באיזה יום, ומה נאמר בו. הכרטיסים והמגירה הם הזיכרון: מה שהיא למדה מהביקורים האלה ומה שהיא לוקחת איתה לביקור הבא. בקשה להישכח מתייחסת לזיכרון – העובדות שנגזרות לגבי אדם מסוים והמצב שמתלווה אליו. ההחלטה אם גם התיעוד של הביקור יימחק היא החלטה נפרדת, שמתקבלת מסיבות נפרדות – שביל ביקורת, היסטוריית תמיכה – ובשיעור ה-Lab הזה הוא נשאר בכוונה, כדי שתוכלו לראות את ההבדל בין השניים: התיעוד והזיכרון הם לא אותו דבר, ושכחת אחד מהם לא משפיעה על השני. זה המשפט שמעל הדלת של וספר, כפי שנראה מהצד השני.

הזיכרון המופשט של ADK כולל add_events_to_memory ו-search_memory. אין אפשרות למחוק אותו. שכחה היא פעולת ניהול, לא פעולה של סוכן, ולכן היא מתבצעת באפליקציה – archive/tower.py, memories.delete בלקוח הגולמי – כך שהמודל לא יכול להגיע אליה בטעות. היכולת של סוכן לשכוח היא משהו שאתם מתכננים, בדיוק כמו היכולת שלו לזכור.

מה שפיתחתם וקראתם, ומה זה

הדבר

מה זה

איפה הוא נמצא

‫make_tower.py → AGENT_ENGINE ב-.env – נוצר, לא נערך, לא הופעל מחדש

שירות הזיכרון, כשירות: החלטת פריסה, מחוץ לסוכן

‫Vertex AI Memory Bank ב-Agent Engine

‫tower_service(engine) – אתם רק קוראים אותו

אותו משבצת Runner(memory_service=...), בית אחר

archive/service.py

‫"allowed_topics": TOPICS ב-FILING – קריאה בלבד

מה יישמר, ההחלטה מתקבלת בזמן הכתיבה, לא בהנחיה

‫archive/topics.py + ההגדרה של המגדל

‫🔥 → memories.delete — בוצעה הקשה, לא נכתב

שכחה היא פעולה של האפליקציה. ל-API של הזיכרון ב-ADK אין אפשרות מחיקה

archive/tower.py

השלב הזה מגיע למה שנאמר. יום אחד נכנס, עובדה אחת יוצאת – מזוקקת למה שהנושאים מאפשרים – והספר בקומה הראשונה אף פעם לא זז.

7. GraphRAG

אופציונלי.

  • מה – סקריפט אחד טוען את העבר של העמק ל-BigQuery, יוצר הטבעות בתוך מחסן הנתונים ומציג גרף על הטבלאות בלי להזיז שורה; לאחר מכן שתי שאלות ל-Vesper, שיש לו שתי שאילתות מנוהלות בשבילו: אחת לגבי מה שנשמע דומה, ואחת לגבי מה שמקושר.
  • למה – דומים לא אומר מחוברים. וקטור מוצא איפה לחפש, גרף מוצא מה מצורף, והתשובה צריכה לכלול את הנתיב שבו היא עברה.
  • איך – bash scripts/season.sh, פעם אחת. כל שאר התוכן בפרק הזה הוא לקריאה בלבד.

הגישה למגדל של וספר מוגבלת למשתמשים – (app_name, user_id) – בגלל עבודות בנייה. הזיכרון שלה לא כולל ביקורים של אנשים אחרים, וחיפוש מעמיק יותר לא ישנה את זה. הם שייכים לעמק, והעמק שומר אותם במחסן. במהלך העונה הזו, 31 מבקרים הגיעו בעקבות שאילתה לגבי פנס q7 שהתקלקל בלילה, ואחד מהם מצא את הסיבה. בפרק הזה נטען מחסן הנתונים הזה ומועברות אליו שתי שאילתות קבועות.

Graph RAG

מנוע ה-RAG פועל לפי העיקרון אחזור ואז יצירה: הוא מוצא את הרשומות המתאימות, מעביר אותן למודל ומאפשר לו להפיק מהן תשובה. ב-RAG רגיל, האחזור מתבצע לפי דמיון – המערכת מטמיעה את השאלה ושולפת את הרשומות הכי קרובות. החיפוש ימצא דברים שנשמעים כמו השאלה, וזה המקום שבו המגדל בפרק 4 נעצר. ‫Graph RAG מוסיף שלב שני של אחזור, שמתבצע אחרי קצוות – מפתחות שכבר קיימים במחסן – מכל דמיון שנמצא, לכל מה שמצורף אליו. שני השלבים האלה עונים על שאלות שונות, ובפרק הזה נסביר לכם איך לשאול את שתי השאלות:

שלב

השאלה שהתשובה מתייחסת אליה

איך

בפרק הזה

דמיון

איפה כדאי לחפש?

הטמעת השאלה, VECTOR_SEARCH

‫season_search – כשאין סימון של המבקר

מעבר

מה מחובר לזה?

‫MATCH נתיב בגרף נכסים

season_known_issue — one fixed MATCH

ליצירת תמונות,

מה אומרים למבקר?

המודל, עם הנתיב כציטוט

התשובה שלה

מפעילים פתרונות חכמים

העונה נשלחת כקובצי CSV פשוטים ב-season/ – מבקרים, פריטים, בקשות, תיקונים, עונות – כמו שמערכת תמיכה מייצאת אותם. סקריפט אחד מעביר אותם עד למחסן, והוא הדבר היחיד שמריצים בפרק הזה.

‫👈💻 בכרטיסייה 1 (כ-3 דקות; כל שלב מודפס תוך כדי, והתהליך נעצר בשלב הראשון שנכשל):

cd ~/agent-valley-archive
bash scripts/season.sh

‫👀 בסיום, הקומה הרביעית במגדל מוארת, ובמקרא שלידה מופיעה המילה פתוח.

מה הוא בנה – קריאה בלבד

איך היא קוראת את זה – קריאה בלבד

תשאלי אותה

‫👉🖥 Floor four is open on the tower. שואלים אותה כמו שמבקר רגיל היה שואל:

Has anyone else had a q7 lantern go out at night?

היא עונה, והשורה האחרונה היא הנתיב

👀 היא עונה – עוד שלושים ואחד... רובם אמרו שהלהבה הייתה נמוכה וכבתה אחרי שעה... לוטרה בשם מארלו גילתה שהפתילים נטבלו בצורה רדודה מדי – והשורה האחרונה בתשובה שלה היא הנתיב. זה הפלט שלה – קראו אותו, אל תשלחו אותו בחזרה אליה:

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

הנתיב הוא הציטוט. כל קפיצה היא קצה בגרף, וכל קצה הוא מפתח, כך שכל אחד יכול לחזור על התהליך ולקבל את אותו המספר. אף אחד לא יכול לבדוק שוב את מידת הדמיון בין החברות. אם היא אומרת, ממש לפני הנתיב, שהשורה חזרה דרך שלושה צירופים כי לפרויקט אין הזמנה של גרף, זה אומר שהמהדורה של הפרויקט דוחה את GRAPH_TABLE – השורות והנתיב זהים.

‫👉🖥 עכשיו משמיטים את הסימן ושולחים את ההודעה הבאה:

Has anyone else had a lantern that keeps dying once the sun is down?

‫👀 היא מגיעה לאותו מספר, 31, ולאותה דרך. מה שמשתנה הוא הדרך: season_search רץ ראשון, מצא חמישה מבקרים שנשמעים דומים – כל אחד נושא q7 – לקח את הסימן, ורק אז הלך. הפונקציה Similar לא מחוברת, היא רק מציינת איפה לחפש.

מה נטען ומה זה

הדבר

מה זה

איפה הוא נמצא

‫bq load עם סכימות מפורשות – הרצה, לא כתיבה

מחסן נתונים: עמודות עם שמות וסוגים

archive.visitors / items / asks / fixes / seasons

ML.GENERATE_EMBEDDING + VECTOR_SEARCH

שלב הדמיון – איפה לחפש

‫archive.ask_embeddings, מודל embedder

‫CREATE PROPERTY GRAPH – לא הועברה שורה

שלב המעבר – מה מחובר; טבלאות הופכות לצמתים וחצים

archive.season_graph

‫GQL in archive/season/__init__.py – פרמטר אחד

הטיול היחיד שהיא יכולה לצאת אליו, והנתיב הוא הציטוט

season_known_issue(mark)

כמה עשרות מבקרים באתר לא מצדיקים קניית מחסן. בפרק הזה נלמד על הפורמט של השאילתה, ולא על קנה המידה. אם נגדיל את הגרף הזה פי אלף, MATCH לא ישתנה אפילו בתו אחד.

8. סגירה

שלושה קווים, מגדל אחד, מחסן אחד – ארבע קומות. לא הופעל מחדש שום דבר.

השלב

מה עשיתם

מה הוא קנה

ONE

‫tool_context.state[CASE] = case – עריכה

אם יש שגיאה כלשהי: המצב נכתב על ידי הקוד

שתיים

‫CASE = "user:case" – עריכה

חלונית הזזה שעוקבת אחר המבקר

הגשת המסמכים

await ctx.add_events_to_memory(..., custom_metadata=FILING) — כבר קראתי, לא כתיבה

מה שנאמר, נשמר

שלוש

found = await ctx.search_memory(query) — עריכה

מה נשמר, מה ביקשת – לא זוכרים מה הוגש

המגדל

‫make_tower.py, ואז AGENT_ENGINE ב-.env – נוצר וחובר על ידי קו אחד, לא הופעל מחדש שום דבר

מגדל שמזקק, ושורד את הלילה

הכללים

allowed_topics בFILING — קריאה, לא כתיבה

רק את מה שצריך לשמור

העונה

‫season.sh — loaded, embedded in place, a graph laid over it, walked with one MATCH

את הביקורים של כל השאר, לפי משמעות ולפי חיבור

מה כל חלק החליף

ADK 2

מה היית כותב במקום זאת

כמה זה עולה לכם

‫session.state + כלי אחד, נשמר על ידי SqliteSessionService

מילון לצד לולאת הצ'אט, ששמרתם בדיסק בעצמכם

המודל לא יכול לקרוא אותו, ואתם כותבים את קורות החיים ואת הנעילה

הקידומת user:

טבלת משתמשים וצירוף בכל תור

החלטה לאיזה מקש שייך כל תו, בכל פעם

‫add_events_to_memory + search_memory בצומת פונקציה

‫cron שמוחק תמלילים, והמודל מחליט מתי לבדוק

הוא משליך, לא מזקק – ואף פעם לא רואים את הפעמים שבהן הוא לא נראה

VertexAiMemoryBankService + allowed_topics

מאגר וקטורים, הנחיית חילוץ, משימת איחוד ו"אל תזכור טריוויה" בהנחיה

שלושה שירותים, והכלל תקף עד שהמודל יקבע אחרת

‫VECTOR_SEARCH + one fixed GQL MATCH

ייצוא, הטמעה במקום אחר, מסד נתונים של גרפים, משימת סנכרון וכתיבת SQL של המודל

הנתונים יוצאים ממחסן הנתונים כדי להבין אותם, ואתם מגלים אילו הצטרפויות הוא ניחש כשלקוח מבצע

שלוש שאלות, מפסיקים אחרי התשובה החיובית הראשונה

  1. האם זה יהיה חשוב מחר? לא → לא לשמור כלום. הוא מתחיל ונגמר בשיחה.
  2. האם פונקציה יכולה לבדוק את זה? כן ← מגירת האפליקציות. הקוד כותב אותו, כל תור קורא אותו, ואף משפט לא יכול לשנות אותו.
  3. אחרת → המגדל. התשובה מנוסחת מחדש על סמך מה שנאמר, נבדקת כשמבקשים אותה ומשתנה בהתאם למה שנאמר אחר כך.

המשפט

רשומה היא לא זיכרון. זיכרון הוא רשומה בתוספת שתי החלטות – מה לשמור ומתי להסתכל – ומה סוג הדבר שקובע באיזו קומה הוא יוצג.

עובדות והעדפות שייכות לחנויות שונות.

👀 כל קומה מוארת. החיה המוכרת מופיעה בחלק העליון. חותמת הארכיון נמצאת בדרכון, ובשבוע החמישי נפתח שוק הלילה – שם ניקס מנהלת את הבמה בקול רם, בזמן אמת, וכל מה שהמגדל יודע מגיע איתכם.