1. ã¯ããã«

1. 課é¡
çœå®³å¯Ÿå¿ã®ã·ããªãªã§ã¯ãè€æ°ã®å Žæã«ããããŸããŸãªã¹ãã«ããªãœãŒã¹ãããŒãºãæã€çåè ã調æŽããããã«ãã€ã³ããªãžã§ã³ããªããŒã¿ç®¡çãšæ€çŽ¢æ©èœãå¿ èŠã§ãããã®ã¯ãŒã¯ã·ã§ããã§ã¯ã次ã®ãã®ãçµã¿åãããæ¬çªç°å¢ AI ã·ã¹ãã ãæ§ç¯ããæ¹æ³ãåŠã³ãŸãã
- ðïž ã°ã©ã ããŒã¿ããŒã¹ïŒSpannerïŒ: çåè ãã¹ãã«ããªãœãŒã¹éã®è€éãªé¢ä¿ãä¿åãã
- ð AI ãæŽ»çšããæ€çŽ¢: ãšã³ããã£ã³ã°ã䜿çšããã»ãã³ãã£ãã¯æ€çŽ¢ãšããŒã¯ãŒãæ€çŽ¢ã®ãã€ããªããæ€çŽ¢
- ðž ãã«ãã¢ãŒãã«åŠç: ç»åãããã¹ããåç»ããæ§é åããŒã¿ãæœåºãã
- ð€ ãã«ããšãŒãžã§ã³ã ãªãŒã±ã¹ãã¬ãŒã·ã§ã³: è€éãªã¯ãŒã¯ãããŒçšã«å°éãšãŒãžã§ã³ãã調æŽãã
- ð§ é·æèšæ¶: Vertex AI Memory Bank ã䜿çšããããŒãœãã©ã€ãº

2. äœæããæ©èœ
æ¬¡ã®æ å ±ãå«ã Survivor Network Graph Database:
- ðºïž çåè ã®é¢ä¿ã® 3D ã€ã³ã¿ã©ã¯ãã£ã ã°ã©ãã®å¯èŠå
- ð ã€ã³ããªãžã§ã³ãæ€çŽ¢ïŒããŒã¯ãŒããã»ãã³ãã£ãã¯ããã€ããªããïŒ
- ðž ãã«ãã¢ãŒãã« ã¢ããããŒã ãã€ãã©ã€ã³ïŒç»å/åç»ãããšã³ãã£ãã£ãæœåºïŒ
- ð€ è€éãªã¿ã¹ã¯ã®ãªãŒã±ã¹ãã¬ãŒã·ã§ã³ã®ããã®ãã«ããšãŒãžã§ã³ã ã·ã¹ãã
- ð§ ããŒãœãã©ã€ãºãããã€ã³ã¿ã©ã¯ã·ã§ã³ã®ããã® Memory Bank ã®çµ±å
3. æ žãšãªããã¯ãããžãŒ
ã³ã³ããŒãã³ã | ãã¯ãããžãŒ | ç®ç |
ããŒã¿ããŒã¹ | Cloud Spanner Graph | ããŒãïŒçåè ãã¹ãã«ïŒãšãšããžïŒé¢ä¿ïŒãä¿åãã |
AI æ€çŽ¢ | Gemini + ãšã³ããã£ã³ã° | ã»ãã³ãã£ãã¯çè§£ + é¡äŒŒæ§æ€çŽ¢ |
ãšãŒãžã§ã³ã ãã¬ãŒã ã¯ãŒã¯ | ADKïŒAgent Development KitïŒ | AI ã¯ãŒã¯ãããŒããªãŒã±ã¹ãã¬ãŒããã |
ã¡ã¢ãª | Vertex AI Memory Bank | ãŠãŒã¶ãŒèšå®ã®é·æä¿å |
ããã³ããšã³ã | React + Three.js | ã€ã³ã¿ã©ã¯ãã£ã㪠3D ã°ã©ãã®å¯èŠå |
2. ç°å¢ã®æºåïŒã¯ãŒã¯ã·ã§ããã«åå ããŠããå Žåã¯ã¹ãããïŒ
ããŒã 1: è«æ±å ã¢ã«ãŠã³ããæå¹ã«ãã
- ãããã€ã«å¿ èŠãª 5 ãã«ã®ã¯ã¬ãžããã§è«æ±å ã¢ã«ãŠã³ããè«æ±ããŸããGmail ã¢ã«ãŠã³ãã§ããããšã確èªããŸãã
ããŒã 2: ãªãŒãã³ç°å¢
- ð ãã®ãªã³ã¯ãã¯ãªãã¯ãããšãCloud Shell ãšãã£ã¿ã«çŽæ¥ç§»åããŸãã
- ð æ¬æ¥ãã©ããã®æç¹ã§æ¿èªãæ±ããããå Žåã¯ã[æ¿èª] ãã¯ãªãã¯ããŠç¶è¡ããŸãã

- ð ç»é¢äžéšã«ã¿ãŒããã«ã衚瀺ãããªãå Žåã¯ãã¿ãŒããã«ãéããŸãã
- [衚瀺] ãã¯ãªãã¯ããŸãã
- [ã¿ãŒããã«] ãã¯ãªãã¯ããŸãã

- ðð» ã¿ãŒããã«ã§ã次ã®ã³ãã³ãã䜿çšããŠããã§ã«èªèšŒæžã¿ã§ããããšãšããããžã§ã¯ãããããžã§ã¯ã ID ã«èšå®ãããŠããããšã確èªããŸãã
gcloud auth list - ðð» GitHub ããããŒãã¹ãã©ãã ãããžã§ã¯ãã®ã¯ããŒã³ãäœæããŸãã
git clone https://github.com/google-americas/way-back-home.git
3. ç°å¢èšå®
1. åæå
Cloud Shell ãšãã£ã¿ã®ã¿ãŒããã«ã§ãã¿ãŒããã«ãç»é¢ã®äžéšã«è¡šç€ºãããªãå Žåã¯ã次ã®ããã«éããŸãã
- [衚瀺] ãã¯ãªãã¯ããŸãã
- [Terminal] ãã¯ãªãã¯ããŸãã

ðð» ã¿ãŒããã«ã§ãinit ã¹ã¯ãªãããå®è¡å¯èœã«ããŠå®è¡ããŸãã
cd ~/way-back-home/level_2
./init.sh
2. ãããžã§ã¯ãã®èšå®
ðð» ãããžã§ã¯ã ID ãèšå®ããŸãã
gcloud config set project $(cat ~/project_id.txt) --quiet
ðð» å¿ èŠãª API ãæå¹ã«ããŸãïŒ2 ïœ 3 åããããŸãïŒã
gcloud services enable compute.googleapis.com \
aiplatform.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
spanner.googleapis.com \
storage.googleapis.com
3. èšå®ã¹ã¯ãªãããå®è¡ãã
ðð» èšå®ã¹ã¯ãªãããå®è¡ããŸãã
cd ~/way-back-home/level_2
./setup.sh
ããã«ããã.env ãäœæãããŸããCloud Shell ã§ way_back_homeproject ãéããŸããlevel_2 ãã©ã«ãã« .env ãã¡ã€ã«ãäœæãããŠããŸããèŠã€ãããªãå Žåã¯ã[View] -> [Toggle Hidden File] ã®é ã«ã¯ãªãã¯ããŠè¡šç€ºããŸãã
4. ãµã³ãã«ããŒã¿ãèªã¿èŸŒã
ðð» ããã¯ãšã³ãã«ç§»åããŠäŸåé¢ä¿ãã€ã³ã¹ããŒã«ããŸãã
cd ~/way-back-home/level_2/backend
uv sync
ðð» åæçåè ããŒã¿ãèªã¿èŸŒã¿ãŸãã
uv run python ~/way-back-home/level_2/backend/setup_data.py
ããã«ãããæ¬¡ã®ãã®ãäœæãããŸãã
- Spanner ã€ã³ã¹ã¿ã³ã¹ïŒ
survivor-networkïŒ - ããŒã¿ããŒã¹ïŒ
graph-dbïŒ - ãã¹ãŠã®ããŒãããŒãã«ãšãšããžããŒãã«
- ã¯ãšãªã®ãããã㣠ã°ã©ãæåŸ ãããåºå:
============================================================
SUCCESS! Database setup complete.
============================================================
Instance: survivor-network
Database: graph-db
Graph: SurvivorGraph
Access your database at:
https://console.cloud.google.com/spanner/instances/survivor-network/databases/graph-db?project=waybackhome
åºåã® Access your database at ã®åŸã®ãªã³ã¯ãã¯ãªãã¯ãããšãGoogle Cloud ã³ã³ãœãŒã«ã® Spanner ãéãããšãã§ããŸãã

Google Cloud ã³ã³ãœãŒã«ã« Spanner ã衚瀺ãããŸãã

4. Spanner Studio ã§ã°ã©ãããŒã¿ãå¯èŠåãã
ãã®ã¬ã€ãã§ã¯ãSpanner Studio ã䜿çšããŠãGoogle Cloud ã³ã³ãœãŒã«ã§ Survivor Network ã°ã©ãããŒã¿ãçŽæ¥å¯èŠåããŠæäœããæ¹æ³ã«ã€ããŠèª¬æããŸããããã¯ãAI ãšãŒãžã§ã³ããæ§ç¯ããåã«ããŒã¿ãæ€èšŒããã°ã©ãæ§é ãçè§£ããã®ã«æé©ãªæ¹æ³ã§ãã
1. Spanner Studio ã«ã¢ã¯ã»ã¹ãã
- æåŸã®æé ã§ã¯ããªã³ã¯ãã¯ãªãã¯ã㊠Spanner Studio ãéããŸãã

2. ã°ã©ãæ§é ã®çè§£ïŒå šäœåïŒ
Survivor Network ããŒã¿ã»ããã¯ãè«çããºã«ãã²ãŒã ã®ç¶æ ã®ãããªãã®ãšèããŠãã ããã
ãšã³ãã£ã㣠| ã·ã¹ãã ã§ã®åœ¹å² | 説æã®ããã®äŸã |
Survivors | ãšãŒãžã§ã³ã/ãã¬ãŒã€ãŒ | ãã¬ãŒã€ãŒ |
ãã€ãªãŒã | ãŠãŒã¶ãŒã®æåšå° | Map Zones |
ã¹ãã« | ã§ããããš | èœå |
ããŒãº | äžè¶³ããŠãããã®ïŒå±æ©ïŒ | ã¯ãšã¹ã/ããã·ã§ã³ |
ãªãœãŒã¹ | äžçã§èŠã€ãã£ãã¢ã€ãã | Loot |
ç®æš: AI ãšãŒãžã§ã³ãã®ä»äºã¯ããã€ãªãŒã ïŒå Žæã®å¶çŽïŒãèæ ®ããŠãã¹ãã«ïŒãœãªã¥ãŒã·ã§ã³ïŒãããŒãºïŒåé¡ïŒã«çµã³ä»ããããšã§ãã
ð ãšããžïŒé¢ä¿ïŒ:
SurvivorInBiome: äœçœ®æ å ±ã®è¿œè·¡SurvivorHasSkill: èœåã®ã€ã³ãã³ããªSurvivorHasNeed: æå¹ãªåé¡ã®ãªã¹ãSurvivorFoundResource: ã¢ã€ãã ã®åšåº«SurvivorCanHelp: æšè«ãããé¢ä¿ïŒAI ãèšç®ããŸãïŒã
3. ã°ã©ãã®ã¯ãšãª
ããã€ãã®ã¯ãšãªãå®è¡ããŠãããŒã¿å ã®ãã¹ããŒãªãŒãã確èªããŠã¿ãŸãããã
Spanner Graph 㯠GQLïŒGraph Query LanguageïŒã䜿çšããŸããã¯ãšãªãå®è¡ããã«ã¯ãGRAPH SurvivorNetwork ã®åŸã«äžèŽãã¿ãŒã³ãæå®ããŸãã
ð ã¯ãšãª 1: ã°ããŒãã«åç°¿ïŒèª°ãã©ãã«ãããïŒãããåºç€ãšãªããŸããæå©æŽ»åã§ã¯ãäœçœ®æ å ±ãææ¡ããããšãéèŠã§ãã
GRAPH SurvivorNetwork
MATCH result = (s:Survivors)-[:SurvivorInBiome]->(b:Biomes)
RETURN TO_JSON(result) AS json_result
次ã®ãããªçµæã衚瀺ãããŸãã
ð ã¯ãšãª 2: ã¹ãã« ãããªãã¯ã¹ïŒèœåïŒå šå¡ã®å± å Žæãããã£ãããäœãã§ãããã調ã¹ãŸãã
GRAPH SurvivorNetwork
MATCH result = (s:Survivors)-[h:SurvivorHasSkill]->(k:Skills)
RETURN TO_JSON(result) AS json_result
次ã®ãããªçµæã衚瀺ãããŸãã
ð ã¯ãšãª 3: 屿©ã«çããŠãããŠãŒã¶ãŒã¯èª°ãïŒïŒããã·ã§ã³ ããŒãïŒå©ããå¿ èŠãšããŠããçåè ãšããã®çåè ãäœãå¿ èŠãšããŠãããã確èªã§ããŸãã
GRAPH SurvivorNetwork
MATCH result = (s:Survivors)-[h:SurvivorHasNeed]->(n:Needs)
RETURN TO_JSON(result) AS json_result
次ã®ãããªçµæã衚瀺ãããŸãã
ð äžçŽ: ãããã³ã° - 誰ã誰ãå©ãããããïŒ
ããã§ã°ã©ãã匷åã«ãªããŸãããã®ã¯ãšãªã¯ãä»ã®çåè ã®ããŒãºã«å¯Ÿå¿ã§ããã¹ãã«ãæã€çåè ãæ€çŽ¢ããŸãã
GRAPH SurvivorNetwork
MATCH result = (helper:Survivors)-[:SurvivorHasSkill]->(skill:Skills)-[:SkillTreatsNeed]->(need:Needs)<-[:SurvivorHasNeed]-(helpee:Survivors)
RETURN TO_JSON(result) AS json_result
次ã®ãããªçµæã衚瀺ãããŸãã
aside positive ãã®ã¯ãšãªã®å®è¡å 容:
ãå¿æ¥åŠçœ®ã§ç«å·ãæ²»çããããšã ã衚瀺ããã®ã§ã¯ãªãïŒããã¯ã¹ããŒãããæããã§ãïŒããã®ã¯ãšãªã§ã¯æ¬¡ã®å å®¹ãæ€çŽ¢ãããŸãã
- Elena Frost å»åž«ïŒå»åŠã®èšç·ŽãåããŠããïŒâ æ²»çã§ãã â ç°äžè¹é·ïŒç«å·ãè² ã£ãŠããïŒ
- David ChenïŒå¿æ¥åŠçœ®ã®è³æ ŒããïŒâ æ²»çã§ãã â Lt. ParkïŒè¶³éŠãæ»æ«ïŒ
ãã®æ¹æ³ã广çãªçç±:
AI ãšãŒãžã§ã³ãã®æ©èœ:
ã客æ§ããç«å·ã®æ²»çã¯èª°ãã§ããŸããïŒããšå°ããå ŽåããšãŒãžã§ã³ãã¯æ¬¡ã®å¯Ÿå¿ãè¡ããŸãã
- åæ§ã®ã°ã©ãã¯ãšãªãå®è¡ãã
- æ»ãå€: ãDr. Frost ã¯å»åŠã®èšç·ŽãåããŠãããç°äžè¹é·ãå©ããããšãã§ããŸãã
- ãŠãŒã¶ãŒã¯äžéããŒãã«ããªã¬ãŒã·ã§ã³ã·ããã«ã€ããŠç¥ãå¿ èŠã¯ãããŸããã
5. Spanner ã® AI ãæŽ»çšãããšã³ããã£ã³ã°
1. ãšã³ããã£ã³ã°ãéèŠãªçç±ïŒæäœãªããèªã¿åãå°çšïŒ
çåã·ããªãªã§ã¯ãæéãéèŠã§ããçåè
ã I need someone who can treat burns ã Looking for a medic ãªã©ã®ç·æ¥äºæ
ãå ±åãããšãã«ãããŒã¿ããŒã¹å
ã®æ£ç¢ºãªã¹ãã«åãæšæž¬ããã®ã«æéãè²»ããããšã¯ã§ããŸããã
å®éã®ã·ããªãª: ãµãã€ããŒ: Captain Tanaka has burnsâwe need medical help NOW!
ãmedicãã®åŸæ¥ã®ããŒã¯ãŒãæ€çŽ¢ â 0 ä»¶ã®æ€çŽ¢çµæ â
ãšã³ããã£ã³ã°ã䜿çšããã»ãã³ãã£ãã¯æ€çŽ¢ â ãå»çãã¬ãŒãã³ã°ãããå¿æ¥åŠçœ®ããæ€åº â
ããã¯ããšãŒãžã§ã³ãããŸãã«å¿ èŠãšããŠãããã®ã§ããããŒã¯ãŒãã ãã§ãªãæå³ãçè§£ããã€ã³ããªãžã§ã³ãã§äººéã®ãããªæ€çŽ¢ã§ãã
2. ãšã³ããã£ã³ã° ã¢ãã«ãäœæãã

次ã«ãGoogle ã® text-embedding-004 ã䜿çšããŠããã¹ãããšã³ããã£ã³ã°ã«å€æããã¢ãã«ãäœæããŸãã
ð Spanner Studio ã§ã次㮠SQL ãå®è¡ããŸãïŒ$YOUR_PROJECT_ID ã¯å®éã®ãããžã§ã¯ã ID ã«çœ®ãæããŠãã ããïŒã
âŒ ïž Cloud Shell ãšãã£ã¿ã§ãFile -> Open Folder -> way-back-home/level_2 ãéããŠãããžã§ã¯ãå
šäœã衚瀺ããŸãã

ð æ¬¡ã®ã¯ãšãªãã³ããŒããŠè²Œãä»ãã[å®è¡] ãã¿ã³ãã¯ãªãã¯ããŠãSpanner Studio ã§ãã®ã¯ãšãªãå®è¡ããŸãã
CREATE MODEL TextEmbeddings
INPUT(content STRING(MAX))
OUTPUT(embeddings STRUCT<values ARRAY<FLOAT32>>)
REMOTE OPTIONS (
endpoint = '//aiplatform.googleapis.com/projects/$YOUR_PROJECT_ID/locations/us-central1/publishers/google/models/text-embedding-004'
);
æ©èœ:
- Spanner ã«ä»®æ³ã¢ãã«ãäœæããŸãïŒã¢ãã«ã®éã¿ã¯ããŒã«ã«ã«ä¿åãããŸããïŒã
- Vertex AI ã® Google ã®
text-embedding-004ãæããŸã - ã³ã³ãã©ã¯ããå®çŸ©ããŸããå ¥åã¯ããã¹ããåºå㯠768 次å ã®æµ®åå°æ°ç¹é åã§ãã
ããªã¢ãŒã ãªãã·ã§ã³ããšã¯ïŒ
- Spanner ã¯ã¢ãã«èªäœãå®è¡ããŸãã
ML.PREDICTã䜿çšãããšãAPI çµç±ã§ Vertex AI ãåŒã³åºãããŸãã- Zero-ETL: ããŒã¿ã Python ã«ãšã¯ã¹ããŒãããŠåŠçããåã€ã³ããŒãããå¿ èŠããªã
Run ãã¿ã³ãã¯ãªãã¯ããŸããæåãããšã次ã®ããã«çµæã衚瀺ãããŸãã

3. ãšã³ããã£ã³ã°åã远å ãã
ð ãšã³ããã£ã³ã°ãæ ŒçŽããåã远å ããŸãã
ALTER TABLE Skills ADD COLUMN skill_embedding ARRAY<FLOAT32>;
Run ãã¿ã³ãã¯ãªãã¯ããŸããæåãããšã次ã®ããã«çµæã衚瀺ãããŸãã

4. ãšã³ããã£ã³ã°ãçæãã
ð AI ã䜿çšããŠåã¹ãã«ã®ãã¯ãã« ãšã³ããã£ã³ã°ãäœæããŸãã
UPDATE Skills
SET skill_embedding = (
SELECT embeddings.values
FROM ML.PREDICT(
MODEL TextEmbeddings,
(SELECT name AS content)
)
)
WHERE skill_embedding IS NULL;
Run ãã¿ã³ãã¯ãªãã¯ããŸããæåãããšã次ã®ããã«çµæã衚瀺ãããŸãã

åäœ: åã¹ãã«åïŒäŸ: ãå¿æ¥åŠçœ®ãïŒã¯ããã®æå³ã衚ã 768 次å ã®ãã¯ãã«ã«å€æãããŸãã
5. ãšã³ããã£ã³ã°ãæ€èšŒãã
ð ãšã³ããã£ã³ã°ãäœæãããããšã確èªããŸãã
SELECT
skill_id,
name,
ARRAY_LENGTH(skill_embedding) AS embedding_dimensions
FROM Skills
LIMIT 5;
æ³å®ãããåºå:

6. ã»ãã³ãã£ãã¯æ€çŽ¢ã詊ã
ã·ããªãªã®ãŠãŒã¹ã±ãŒã¹ïŒãmedicããšããçšèªã䜿çšããŠå»çã¹ãã«ãèŠã€ããïŒããã¹ãããŸãã
ð ãmedicãã«é¡äŒŒããã¹ãã«ãæ€çŽ¢ããŸãã
WITH query_embedding AS (
SELECT embeddings.values AS val
FROM ML.PREDICT(MODEL TextEmbeddings, (SELECT "medic" AS content))
)
SELECT
s.name AS skill_name,
s.category,
COSINE_DISTANCE(s.skill_embedding, (SELECT val FROM query_embedding)) AS distance
FROM Skills AS s
WHERE s.skill_embedding IS NOT NULL
ORDER BY distance ASC
LIMIT 10;
- ãŠãŒã¶ãŒã®æ€çŽ¢èªå¥ãmedicãããšã³ããã£ã³ã°ã«å€æãã
query_embeddingäžæããŒãã«ã«ä¿åããŸãã
æåŸ ãããçµæïŒè·é¢ãå°ããã»ã©é¡äŒŒæ§ãé«ãïŒ:

7. åæçšã® Gemini ã¢ãã«ãäœæãã

ð çæ AI ã¢ãã«ã®åç
§ãäœæããŸãïŒ$YOUR_PROJECT_ID ã¯å®éã®ãããžã§ã¯ã ID ã«çœ®ãæããŸãïŒã
CREATE MODEL GeminiPro
INPUT(prompt STRING(MAX))
OUTPUT(content STRING(MAX))
REMOTE OPTIONS (
endpoint = '//aiplatform.googleapis.com/projects/$YOUR_PROJECT_ID/locations/us-central1/publishers/google/models/gemini-2.5-pro',
default_batch_size = 1
);
ãšã³ããã£ã³ã° ã¢ãã«ãšã®éã:
- ãšã³ããã£ã³ã°: ããã¹ã â ãã¯ãã«ïŒé¡äŒŒæ€çŽ¢çšïŒ
- Gemini: ããã¹ã â çæãããããã¹ãïŒæšè«/åæçšïŒ

8. äºææ§åæã« Gemini ã䜿çšãã
ð ããã·ã§ã³ã®äºææ§ã«ã€ããŠãµãã€ããŒã®ãã¢ãåæããŸãã
WITH PairData AS (
SELECT
s1.name AS Name_A,
s2.name AS Name_B,
CONCAT(
"Assess compatibility of these two survivors for a resource-gathering mission. ",
"Survivor 1: ", s1.name, ". ",
"Survivor 2: ", s2.name, ". ",
"Give a score from 1-10 and a 1-sentence reason."
) AS prompt
FROM Survivors s1
JOIN Survivors s2 ON s1.survivor_id < s2.survivor_id
LIMIT 1
)
SELECT
Name_A,
Name_B,
content AS ai_assessment
FROM ML.PREDICT(
MODEL GeminiPro,
(SELECT Name_A, Name_B, prompt FROM PairData)
);
æ³å®ãããåºå:
Name_A | Name_B | ai_assessment
----------------|-------------------|----------------
"David Chen" | "Dr. Elena Frost" | "**Score: 9/10** Their compatibility is extremely high as David's practical, hands-on scavenging skills are perfectly complemented by Dr. Frost's specialized knowledge to identify critical medical supplies and avoid biological hazards."
6. ãã€ããªããæ€çŽ¢ã䜿çšããŠã°ã©ã RAG ãšãŒãžã§ã³ããæ§ç¯ãã
1. ã·ã¹ãã ã¢ãŒããã¯ãã£ã®æŠèŠ
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãããŸããŸãªã¿ã€ãã®ã¯ãšãªãæè»ã«åŠçã§ãããã«ãã¡ãœããæ€çŽ¢ã·ã¹ãã ãæ§ç¯ããŸãããã®ã·ã¹ãã ã«ã¯ããšãŒãžã§ã³ã ã¬ã€ã€ãããŒã« ã¬ã€ã€ããµãŒãã¹ ã¬ã€ã€ã® 3 ã€ã®ã¬ã€ã€ããããŸãã

3 ã€ã®ã¬ã€ã€ã䜿çšããçç±
- é¢å¿ã®åé¢: ãšãŒãžã§ã³ãã¯ã€ã³ãã³ããããŒã«ã¯ã€ã³ã¿ãŒãã§ãŒã¹ããµãŒãã¹ã¯å®è£ ã«çŠç¹ãåœãŠãŸãã
- æè»æ§: ãšãŒãžã§ã³ãã¯ç¹å®ã®æ¹æ³ã匷å¶ããããAI ã«ããèªåã«ãŒãã£ã³ã°ãèš±å¯ã§ããŸã
- æé©å: ã¡ãœãããããã£ãŠããå Žåã¯ãã³ã¹ãã®ããã AI åæãã¹ãããã§ããŸã
ãã®ã»ã¯ã·ã§ã³ã§ã¯ãäž»ã«ã»ãã³ãã£ãã¯æ€çŽ¢ïŒRAGïŒãå®è£ ããŸããããã¯ãããŒã¯ãŒãã ãã§ãªãæå³ã«åºã¥ããŠçµæãèŠã€ãããã®ã§ããåŸã»ã©ããã€ããªããæ€çŽ¢ã§è€æ°ã®æ¹æ³ãçµ±åããæ¹æ³ã«ã€ããŠèª¬æããŸãã
2. RAG ãµãŒãã¹ã®å®è£
ðð» ã¿ãŒããã«ã§ã次ã®ã³ãã³ããå®è¡ã㊠Cloud Shell ãšãã£ã¿ã§ãã¡ã€ã«ãéããŸãã
cloudshell edit ~/way-back-home/level_2/backend/services/hybrid_search_service.py
ã³ã¡ã³ããèŠã€ãã # TODO: REPLACE_SQL
ãã®è¡å šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
# This is your working query from the successful run!
sql = """
WITH query_embedding AS (
SELECT embeddings.values AS val
FROM ML.PREDICT(
MODEL TextEmbeddings,
(SELECT @query AS content)
)
)
SELECT
s.survivor_id,
s.name AS survivor_name,
s.biome,
sk.skill_id,
sk.name AS skill_name,
sk.category,
COSINE_DISTANCE(
sk.skill_embedding,
(SELECT val FROM query_embedding)
) AS distance
FROM Survivors s
JOIN SurvivorHasSkill shs ON s.survivor_id = shs.survivor_id
JOIN Skills sk ON shs.skill_id = sk.skill_id
WHERE sk.skill_embedding IS NOT NULL
ORDER BY distance ASC
LIMIT @limit
"""
3. ã»ãã³ãã£ãã¯æ€çŽ¢ããŒã«ã®å®çŸ©
ðð» ã¿ãŒããã«ã§ã次ã®ã³ãã³ããå®è¡ã㊠Cloud Shell ãšãã£ã¿ã§ãã¡ã€ã«ãéããŸãã
cloudshell edit ~/way-back-home/level_2/backend/agent/tools/hybrid_search_tools.py
hybrid_search_tools.py ã§ãã³ã¡ã³ã # TODO: REPLACE_SEMANTIC_SEARCH_TOOL ãèŠã€ããŸãã
ðãã®è¡å šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
async def semantic_search(query: str, limit: int = 10) -> str:
"""
Force semantic (RAG) search using embeddings.
Use this when you specifically want to find things by MEANING,
not just matching keywords. Great for:
- Finding conceptually similar items
- Handling vague or abstract queries
- When exact terms are unknown
Example: "healing abilities" will find "first aid", "surgery",
"herbalism" even though no keywords match exactly.
Args:
query: What you're looking for (describe the concept)
limit: Maximum results
Returns:
Semantically similar results ranked by relevance
"""
try:
service = _get_service()
result = service.smart_search(
query,
force_method=SearchMethod.RAG,
limit=limit
)
return _format_results(
result["results"],
result["analysis"],
show_analysis=True
)
except Exception as e:
return f"Error in semantic search: {str(e)}"
ãšãŒãžã§ã³ãã䜿çšããå Žå:
- é¡äŒŒæ§ãæ±ããã¯ãšãªïŒãX ã«é¡äŒŒãããã®ãæ¢ããŠãïŒ
- æŠå¿µã¯ãšãªïŒãå埩èœåãïŒ
- æå³ã®çè§£ãéèŠãªå Žå
4. ãšãŒãžã§ã³ãã®å€æã¬ã€ãïŒæé ïŒ
ãšãŒãžã§ã³ãã®å®çŸ©ã§ãã»ãã³ãã£ãã¯æ€çŽ¢ã«é¢é£ããéšåãã³ããŒããŠæç€ºã«è²Œãä»ããŸãã
ðð» ã¿ãŒããã«ã§ã次ã®ã³ãã³ããå®è¡ã㊠Cloud Shell ãšãã£ã¿ã§ãã¡ã€ã«ãéããŸãã
cloudshell edit ~/way-back-home/level_2/backend/agent/agent.py
ãšãŒãžã§ã³ãã¯ããã®æç€ºã䜿çšããŠé©åãªããŒã«ãéžæããŸãã
ðagent.py ãã¡ã€ã«ã§ãã³ã¡ã³ã # TODO: REPLACE_SEARCH_LOGIC ãèŠã€ãããã®è¡å
šäœã眮ãæããŸããæ¬¡ã®ã³ãŒãã«çœ®ãæããŸãã
- `semantic_search`: Force RAG/embedding search
Use for: "Find similar to X", conceptual queries, unknown terminology
Example: "Find skills related to healing"
ð # TODO: ADD_SEARCH_TOOLãã®è¡å
šäœã眮ãæããŸã ã®ã³ã¡ã³ããæ¢ããæ¬¡ã®ã³ãŒãã«çœ®ãæããŸãã
semantic_search, # Force RAG
5. ãã€ããªããæ€çŽ¢ã®ä»çµã¿ã«ã€ããŠïŒèªã¿åãå°çšã察å¿äžèŠïŒ
ã¹ããã 2 ïœ 4 ã§ã¯ãã»ãã³ãã£ãã¯æ€çŽ¢ïŒRAGïŒãå®è£ ããŸãããããã¯ãæå³ã«åºã¥ããŠçµæãæ€çŽ¢ããã³ã¢æ€çŽ¢ã¡ãœããã§ãããã ãããã®ã·ã¹ãã ã¯ããã€ããªããæ€çŽ¢ããšåŒã°ããŠããŸããåãµãŒãã¹ã¯ããããæ¬¡ã®ããã«åé¡ãããŸãã
ãã€ããªãã ããŒãžã®ä»çµã¿:
way-back-home/level_2/backend/services/hybrid_search_service.py ãã¡ã€ã«ã§ hybrid_search() ãåŒã³åºããããšããµãŒãã¹ã¯äž¡æ¹ã®æ€çŽ¢ãå®è¡ããçµæãçµ±åããŸãã
# Location: backend/services/hybrid_search_service.py
rank_kw = keyword_ranks.get(surv_id, float('inf'))
rank_rag = rag_ranks.get(surv_id, float('inf'))
rrf_score = 0.0
if rank_kw != float('inf'):
rrf_score += 1.0 / (K + rank_kw)
if rank_rag != float('inf'):
rrf_score += 1.0 / (K + rank_rag)
combined_score = rrf_score
ãã® Codelab ã§ã¯ãåºç€ãšãªãã»ãã³ãã£ãã¯æ€çŽ¢ã³ã³ããŒãã³ãïŒRAGïŒãå®è£ ããŸãããããŒã¯ãŒããšãã€ããªãã ã¡ãœããã¯ãã§ã«ãµãŒãã¹ã«å®è£ ãããŠããŸãããšãŒãžã§ã³ã㯠3 ã€ãã¹ãŠã䜿çšã§ããŸãã
ããã§ãšãããããŸãïŒãã€ããªããæ€çŽ¢ã䜿çšãã Graph RAG ãšãŒãžã§ã³ãã宿ããŸããã
7. ADK Web ã§ãšãŒãžã§ã³ãããã¹ããã
ãšãŒãžã§ã³ãããã¹ãããæãç°¡åãªæ¹æ³ã¯ãadk web ã³ãã³ãã䜿çšããããšã§ãããã®ã³ãã³ãã¯ãçµã¿èŸŒã¿ã®ãã£ãã ã€ã³ã¿ãŒãã§ãŒã¹ã§ãšãŒãžã§ã³ããèµ·åããŸãã
1. ãšãŒãžã§ã³ãã®å®è¡
ðð» ããã¯ãšã³ã ãã£ã¬ã¯ããªïŒãšãŒãžã§ã³ããå®çŸ©ãããŠããå ŽæïŒã«ç§»åããŠããŠã§ã ã€ã³ã¿ãŒãã§ãŒã¹ãèµ·åããŸãã
cd ~/way-back-home/level_2/backend
uv run adk web
ãã®ã³ãã³ãã¯ã ã§å®çŸ©ããããšãŒãžã§ã³ããèµ·åããŸãã
agent/agent.py
ãã¹ãçšã®ãŠã§ã ã€ã³ã¿ãŒãã§ãŒã¹ãéããŸãã
ð URL ãéããŸãã
ãã®ã³ãã³ãã¯ãããŒã«ã« URLïŒé垞㯠http://127.0.0.1:8000 ãªã©ïŒãåºåããŸãããã©ãŠã¶ã§éããŸãã

URL ãã¯ãªãã¯ãããšãADK ãŠã§ã UI ã衚瀺ãããŸããå·Šäžã® [ãšãŒãžã§ã³ã] ãéžæããŠãã ããã

2. æ€çŽ¢æ©èœã®ãã¹ã
ãšãŒãžã§ã³ãã¯ãã¯ãšãªãã€ã³ããªãžã§ã³ãã«ã«ãŒãã£ã³ã°ããããã«èšèšãããŠããŸãããã£ãã ãŠã£ã³ããŠã§æ¬¡ã®å ¥åã詊ããŠãããŸããŸãªæ€çŽ¢æ¹æ³ã®åäœã確èªããŠãã ããã
𧬠A. ã°ã©ã RAGïŒã»ãã³ãã£ãã¯æ€çŽ¢ïŒ
ããŒã¯ãŒããäžèŽããªããŠããæå³ãã³ã³ã»ããã«åºã¥ããŠã¢ã€ãã ãèŠã€ããŸãã
ãã¹ãã¯ãšãª:ïŒä»¥äžããéžæïŒ
Who can help with injuries?
What abilities are related to survival?
確èªãã¹ãç¹:
- çç±ã«ã¯ãã»ãã³ãã£ãã¯æ€çŽ¢ãŸã㯠RAG æ€çŽ¢ã«ã€ããŠèšåããå¿ èŠããããŸãã
- æŠå¿µçã«é¢é£ããçµæïŒãæè¡ããªã©ïŒã
- çµæã«ã¯ 𧬠ã¢ã€ã³ã³ã衚瀺ãããŸãã
ð B. ãã€ããªããæ€çŽ¢
ããŒã¯ãŒã ãã£ã«ã¿ãšã»ãã³ãã£ãã¯çè§£ãçµã¿åãããŠãè€éãªã¯ãšãªã«å¯Ÿå¿ããŸãã
ãã¹ãã¯ãšãª:ïŒä»¥äžããéžæïŒ
Find someone who can ply a plane in the volcanic area
Who has healing abilities in the FOSSILIZED?
Who has healing abilities in the mountains?
確èªãã¹ãç¹:
- çç±ã«ã¯ãã€ããªããæ€çŽ¢ã«ã€ããŠèšåããå¿ èŠããããŸãã
- çµæã¯äž¡æ¹ã®æ¡ä»¶ïŒã³ã³ã»ãã + å Žæ/ã«ããŽãªïŒã«äžèŽããå¿ èŠããããŸãã
- äž¡æ¹ã®æ¹æ³ã§èŠã€ãã£ãçµæã«ã¯ ð ã¢ã€ã³ã³ã衚瀺ãããæäžäœã«ã©ã³ã¯ä»ããããŸãã
ðð» ãã¹ããå®äºããããã³ãã³ãã©ã€ã³ã§ Ctrl+C ãæŒããŠããã»ã¹ãçµäºããŸãã
8. å®å šãªã¢ããªã±ãŒã·ã§ã³ãå®è¡ãã
ãã«ã¹ã¿ã㯠ã¢ãŒããã¯ãã£ã®æŠèŠ

SessionService ãš Runner ã远å
ðð» ã¿ãŒããã«ã§ã次ã®ã³ãã³ããå®è¡ã㊠Cloud Shell ãšãã£ã¿ã§ãã¡ã€ã« chat.py ãéããŸãïŒç¶è¡ããåã«ãåã®ããã»ã¹ãçµäºããããã«ãctrl+Cããå®è¡ããããšã確èªããŠãã ããïŒã
cloudshell edit ~/way-back-home/level_2/backend/api/routes/chat.py
ðchat.py ãã¡ã€ã«ã§ãã³ã¡ã³ã # TODO: REPLACE_INMEMORY_SERVICES ãèŠã€ãããã®è¡å
šäœã眮ãæããŸããæ¬¡ã®ã³ãŒãã«çœ®ãæããŸãã
session_service = InMemorySessionService()
memory_service = InMemoryMemoryService()
ðchat.py ãã¡ã€ã«ã§ãã³ã¡ã³ã # TODO: REPLACE_RUNNER ãèŠã€ãããã®è¡å
šäœã眮ãæããŸããæ¬¡ã®ã³ãŒãã«çœ®ãæããŸãã
runner = Runner(
agent=root_agent,
session_service=session_service,
memory_service=memory_service,
app_name="survivor-network"
)
1. ç³è«ãéå§
åã®ã¿ãŒããã«ããŸã å®è¡äžã®å Žåã¯ãCtrl+C ãæŒããŠçµäºããŸãã
ðð» ã¢ããªã®èµ·å:
cd ~/way-back-home/level_2/
./start_app.sh
ããã¯ãšã³ããæ£åžžã«èµ·åãããšã次ã®ããã« Local: http://localhost:5173/" ã衚瀺ãããŸãã
ð ã¿ãŒããã«ã§ [Local: http://localhost:5173/] ãã¯ãªãã¯ããŸãã

2. ã»ãã³ãã£ãã¯æ€çŽ¢ã詊ã
ã¯ãšãª:
Find skills similar to healing

çºçããäºè±¡:
- ãšãŒãžã§ã³ããé¡äŒŒæ§ãªã¯ãšã¹ããèªèãã
- ãhealingãã®ãšã³ããã£ã³ã°ãçæãã
- ã³ãµã€ã³è·é¢ã䜿çšããŠæå³çã«é¡äŒŒããã¹ãã«ãæ€çŽ¢ãã
- æ»ãå€: first aidïŒååã¯ãhealingããšäžèŽããŸããããæ»ãå€ã¯ first aid ã§ãïŒ
3. ãã€ããªããæ€çŽ¢ããã¹ããã
ã¯ãšãª:
Find medical skills in the mountains
çºçããäºè±¡:
- ããŒã¯ãŒã ã³ã³ããŒãã³ã:
category='medical'ã®ãã£ã«ã¿ - ã»ãã³ãã£ã㯠ã³ã³ããŒãã³ã: ãå»çããåã蟌ã¿ãé¡äŒŒåºŠã§ã©ã³ã¯ä»ããã
- çµ±å: äž¡æ¹ã®æ¹æ³ã§èŠã€ãã£ãçµæãåªå ããŠãçµæãçµ±åããŸããð
ã¯ãšãªïŒçç¥å¯ïŒ:
Who is good at survival and in the forest?
çºçããäºè±¡:
- ããŒã¯ãŒãæ€çŽ¢:
biome='forest' - ã»ãã³ãã£ãã¯æ€çŽ¢: ããµãã€ãã«ãã«é¡äŒŒããã¹ãã«
- ãã€ããªããã¯äž¡æ¹ãçµã¿åãããŠæé©ãªçµæãåŸã
ðð» ãã¹ããå®äºããããã¿ãŒããã«ã§ Ctrl+C ãæŒããŠçµäºããŸãã
9. ãã«ãã¢ãŒãã« ãã€ãã©ã€ã³ - ããŒã«ã¬ã€ã€
ãã«ãã¢ãŒãã« ãã€ãã©ã€ã³ãå¿ èŠãªçç±
ãµãã€ãã« ãããã¯ãŒã¯ã¯ããã¹ãã ãã§ã¯ãããŸãããçŸå Žã®çåè ã¯ããã£ãããéããŠéæ§é åããŒã¿ãçŽæ¥éä¿¡ããŸãã
- ðž ç»å: ãªãœãŒã¹ãå±éºãæ©åšã®åç
- ð¥ åç»: ç¶æ³ã¬ããŒãã SOS ãããŒããã£ã¹ã
- ð ããã¹ã: ãã£ãŒã«ãã«é¢ããæ³šæäºé ãŸãã¯ãã°
åŠçãããã¡ã€ã«
æ¢åã®ããŒã¿ãæ€çŽ¢ããåã®ã¹ããããšã¯ç°ãªããããã§ã¯ãŠãŒã¶ãŒãã¢ããããŒããããã¡ã€ã«ãåŠçããŸããchat.py ã€ã³ã¿ãŒãã§ãŒã¹ã¯æ·»ä»ãã¡ã€ã«ãåçã«åŠçããŸãã
ãœãŒã¹ | ã³ã³ãã³ã | ç®æš |
User Attachment | ç»å/åç»/ããã¹ã | ã°ã©ãã«è¿œå ããæ å ± |
ãã£ããã®ã³ã³ããã¹ã | ãããã¯ååã®åçã§ãã | ã€ã³ãã³ããšè¿œå ã®è©³çް |
èšç»ãããã¢ãããŒã: é æ¬¡ãšãŒãžã§ã³ã ãã€ãã©ã€ã³
å°éãšãŒãžã§ã³ããé£çµãã Sequential AgentïŒmultimedia_agent.pyïŒã䜿çšããŸãã

ãã㯠backend/agent/multimedia_agent.py ã§ SequentialAgent ãšããŠå®çŸ©ãããŸãã
ããŒã«ã¬ã€ã€ã¯ããšãŒãžã§ã³ããåŒã³åºãããšãã§ããæ©èœãæäŸããŸããããŒã«ã¯ããã¡ã€ã«ã®ã¢ããããŒãããšã³ãã£ãã£ã®æœåºãããŒã¿ããŒã¹ãžã®ä¿åãšãã£ããæ¹æ³ããåŠçããŸãã
1. ããŒã«ãã¡ã€ã«ãéã
ðð» æ°ããã¿ãŒããã«ãéããŸããã¿ãŒããã«ã§ãCloud Shell ãšãã£ã¿ã§ãã¡ã€ã«ãéããŸãã
cloudshell edit ~/way-back-home/level_2/backend/agent/tools/extraction_tools.py
2. upload_media ããŒã«ãå®è£
ãã
ãã®ããŒã«ã¯ãããŒã«ã« ãã¡ã€ã«ã Google Cloud Storage ã«ã¢ããããŒãããŸãã
ð extraction_tools.py ã§ãã³ã¡ã³ã pass # TODO: REPLACE_UPLOAD_MEDIA_FUNCTION ãèŠã€ããŸãã
ãã®è¡å šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
"""
Upload media file to GCS and detect its type.
Args:
file_path: Path to the local file
survivor_id: Optional survivor ID to associate with upload
Returns:
Dict with gcs_uri, media_type, and status
"""
try:
if not file_path:
return {"status": "error", "error": "No file path provided"}
# Strip quotes if present
file_path = file_path.strip().strip("'").strip('"')
if not os.path.exists(file_path):
return {"status": "error", "error": f"File not found: {file_path}"}
gcs_uri, media_type, signed_url = gcs_service.upload_file(file_path, survivor_id)
return {
"status": "success",
"gcs_uri": gcs_uri,
"signed_url": signed_url,
"media_type": media_type.value,
"file_name": os.path.basename(file_path),
"survivor_id": survivor_id
}
except Exception as e:
logger.error(f"Upload failed: {e}")
return {"status": "error", "error": str(e)}
3. extract_from_media ããŒã«ãå®è£
ãã
ãã®ããŒã«ã¯ã«ãŒã¿ãŒã§ããmedia_type ããã§ãã¯ããé©åãªæœåºããŒã«ïŒããã¹ããç»åãåç»ïŒã«ãã£ã¹ãããããŸãã
ðextraction_tools.py ã§ãã³ã¡ã³ã pass # TODO: REPLACE_EXTRACT_FROM_MEDIA ãèŠã€ããŸãã
ãã®è¡å šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
"""
Extract entities and relationships from uploaded media.
Args:
gcs_uri: GCS URI of the uploaded file
media_type: Type of media (text/image/video)
signed_url: Optional signed URL for public/temporary access
Returns:
Dict with extraction results
"""
try:
if not gcs_uri:
return {"status": "error", "error": "No GCS URI provided"}
# Select appropriate extractor
if media_type == MediaType.TEXT.value or media_type == "text":
result = await text_extractor.extract(gcs_uri)
elif media_type == MediaType.IMAGE.value or media_type == "image":
result = await image_extractor.extract(gcs_uri)
elif media_type == MediaType.VIDEO.value or media_type == "video":
result = await video_extractor.extract(gcs_uri)
else:
return {"status": "error", "error": f"Unsupported media type: {media_type}"}
# Inject signed URL into broadcast info if present
if signed_url:
if not result.broadcast_info:
result.broadcast_info = {}
result.broadcast_info['thumbnail_url'] = signed_url
return {
"status": "success",
"extraction_result": result.to_dict(), # Return valid JSON dict instead of object
"summary": result.summary,
"entities_count": len(result.entities),
"relationships_count": len(result.relationships),
"entities": [e.to_dict() for e in result.entities],
"relationships": [r.to_dict() for r in result.relationships]
}
except Exception as e:
logger.error(f"Extraction failed: {e}")
return {"status": "error", "error": str(e)}
äž»ãªå®è£ ã®è©³çް:
- ãã«ãã¢ãŒãã«å
¥å: ããã¹ã ããã³ããïŒ
_get_extraction_prompt()ïŒãšç»åãªããžã§ã¯ãã®äž¡æ¹ãgenerate_contentã«æž¡ããŸãã - æ§é ååºå:
response_mime_type="application/json"ã¯ãLLM ãæå¹ãª JSON ãè¿ãããã«ããŸããããã¯ãã€ãã©ã€ã³ã«ãšã£ãŠéèŠã§ãã - Visual Entity Linking: ããã³ããã«æ¢ç¥ã®ãšã³ãã£ãã£ãå«ãŸããŠãããããGemini ã¯ç¹å®ã®æåãèªèã§ããŸãã
4. save_to_spanner ããŒã«ãå®è£
ãã
ãã®ããŒã«ã¯ãæœåºããããšã³ãã£ãã£ãšãªã¬ãŒã·ã§ã³ã Spanner Graph DB ã«ä¿æããŸãã
ðextraction_tools.py ã§ãã³ã¡ã³ã pass # TODO: REPLACE_SPANNER_AGENT ãèŠã€ããŸãã
ãã®è¡å šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
"""
Save extracted entities and relationships to Spanner Graph DB.
Args:
extraction_result: ExtractionResult object (or dict from previous step if passed as dict)
survivor_id: Optional survivor ID to associate with the broadcast
Returns:
Dict with save statistics
"""
try:
# Handle if extraction_result is passed as the wrapper dict from extract_from_media
result_obj = extraction_result
if isinstance(extraction_result, dict) and 'extraction_result' in extraction_result:
result_obj = extraction_result['extraction_result']
# If result_obj is a dict (from to_dict()), reconstruct it
if isinstance(result_obj, dict):
from extractors.base_extractor import ExtractionResult
result_obj = ExtractionResult.from_dict(result_obj)
if not result_obj:
return {"status": "error", "error": "No extraction result provided"}
stats = spanner_service.save_extraction_result(result_obj, survivor_id)
return {
"status": "success",
"entities_created": stats['entities_created'],
"entities_existing": stats['entities_found_existing'],
"relationships_created": stats['relationships_created'],
"broadcast_id": stats['broadcast_id'],
"errors": stats['errors'] if stats['errors'] else None
}
except Exception as e:
logger.error(f"Spanner save failed: {e}")
return {"status": "error", "error": str(e)}
ãšãŒãžã§ã³ãã«é«åºŠãªããŒã«ãæäŸããããšã§ããšãŒãžã§ã³ãã®æšè«æ©èœã掻çšããªãããããŒã¿ã®å®å šæ§ã確ä¿ããŸãã
5. GCS ãµãŒãã¹ãæŽæ°ãã
GCSService ã¯ãGoogle Cloud Storage ãžã®å®éã®ãã¡ã€ã« ã¢ããããŒããåŠçããŸãã
ðð» ã¿ãŒããã«ã§ãCloud Shell ãšãã£ã¿ã§ãã¡ã€ã«ãéããŸãã
cloudshell edit ~/way-back-home/level_2/backend/services/gcs_service.py
ð gcs_service.py ãã¡ã€ã«ã§ãupload_file 颿°å
ã® # TODO: REPLACE_SAVE_TO_GCS ã³ã¡ã³ããèŠã€ããŸãã
ãã®è¡å šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
blob = self.bucket.blob(blob_name)
blob.upload_from_filename(file_path)
ããããµãŒãã¹ã«æœè±¡åããããšã§ããšãŒãžã§ã³ã㯠GCS ãã±ãããBLOB åã眲åä»ã URL ã®çæã«ã€ããŠç¥ãå¿ èŠããªããªããŸãããã¢ããããŒãããæ±ããã ãã§ãã
6. ïŒèªã¿åãå°çšïŒãšãŒãžã§ã³ã ã¯ãŒã¯ãã㌠> åŸæ¥ã®ã¢ãããŒãã®çç±
ãšãŒãžã§ã³ãæ©èœã®ã¡ãªãã:
æ©èœ | ããã ãã€ãã©ã€ã³ | ã€ãã³ã ããªãã³ | ãšãŒãžã§ã³ã ã¯ãŒã¯ãã㌠|
è€éã | äœïŒ1 ã¹ã¯ãªããïŒ | é«ïŒ5 ã€ä»¥äžã®ãµãŒãã¹ïŒ | äœïŒPython ãã¡ã€ã« 1 å: |
ç¶æ 管ç | ã°ããŒãã«å€æ° | ããŒãïŒåé¢ïŒ | UnifiedïŒãšãŒãžã§ã³ãã®ç¶æ ïŒ |
ãšã©ãŒåŠç | ã¯ã©ãã·ã¥ | ãµã€ã¬ã³ã ãã° | ã€ã³ã¿ã©ã¯ãã£ãïŒããã®ãã¡ã€ã«ãèªã¿åããŸããã§ãããïŒ |
ãŠãŒã¶ãŒã®ãã£ãŒããã㯠| ã³ã³ãœãŒã« ããªã³ã | ããŒãªã³ã°ãå¿ èŠ | ImmediateïŒãã£ããã®äžéšïŒ |
é©å¿æ§ | åºå®ããžã㯠| å³å¯ãªé¢æ° | ã€ã³ããªãžã§ã³ãïŒLLM ãæ¬¡ã®ã¹ããããæ±ºå®ïŒ |
ã³ã³ããã¹ãèªè | ãªã | ãªã | FullïŒãŠãŒã¶ãŒã®æå³ãææ¡ããŠããïŒ |
éèŠãªçç±: multimedia_agent.pyïŒ4 ã€ã®ãµããšãŒãžã§ã³ãïŒã¢ããããŒã â æœåº â ä¿å â èŠçŽïŒãå«ã SequentialAgentïŒã䜿çšããããšã§ãè€éãªã€ã³ãã©ã¹ãã©ã¯ãã£ãšè匱ãªã¹ã¯ãªãããã€ã³ããªãžã§ã³ããªäŒè©±åã¢ããªã±ãŒã·ã§ã³ ããžãã¯ã«çœ®ãæããŸãã
10. ãã«ãã¢ãŒãã« ãã€ãã©ã€ã³ - ãšãŒãžã§ã³ã ã¬ã€ã€
ãšãŒãžã§ã³ã ã¬ã€ã€ã¯ãã¿ã¹ã¯ãå®äºããããã«ããŒã«ã䜿çšãããšãŒãžã§ã³ãã§ããã€ã³ããªãžã§ã³ã¹ãå®çŸ©ããŸããåãšãŒãžã§ã³ãã«ã¯ç¹å®ã®åœ¹å²ããããæ¬¡ã®ãšãŒãžã§ã³ãã«ã³ã³ããã¹ããæž¡ããŸãã以äžã¯ããã«ããšãŒãžã§ã³ã ã·ã¹ãã ã®ã¢ãŒããã¯ãã£å³ã§ãã

1. ãšãŒãžã§ã³ã ãã¡ã€ã«ãéã
ðð» ã¿ãŒããã«ã§ãCloud Shell ãšãã£ã¿ã§ãã¡ã€ã«ãéããŸãã
cloudshell edit ~/way-back-home/level_2/backend/agent/multimedia_agent.py
2. ã¢ããããŒã ãšãŒãžã§ã³ããå®çŸ©ãã
ãã®ãšãŒãžã§ã³ãã¯ããŠãŒã¶ãŒã®ã¡ãã»ãŒãžãããã¡ã€ã«ãã¹ãæœåºããGCS ã«ã¢ããããŒãããŸãã
ðmultimedia_agent.py ãã¡ã€ã«ã§ã# TODO: REPLACE_UPLOAD_AGENT ã®ã³ã¡ã³ããæ¢ããŸãã
ãã®è¡å šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
upload_agent = LlmAgent(
name="UploadAgent",
model="gemini-2.5-flash",
instruction="""Extract the file path from the user's message and upload it.
Use `upload_media(file_path, survivor_id)` to upload the file.
The survivor_id is optional - include it if the user mentions a specific survivor (e.g., "survivor Sarah" -> "Sarah").
If the user provides a path like "/path/to/file", use that.
Return the upload result with gcs_uri and media_type.""",
tools=[upload_media],
output_key="upload_result"
)
3. æœåºãšãŒãžã§ã³ããå®çŸ©ãã
ãã®ãšãŒãžã§ã³ãã¯ãã¢ããããŒããããã¡ãã£ã¢ããèªèãããGemini Vision ã䜿çšããŠæ§é åããŒã¿ãæœåºããŸãã
ðmultimedia_agent.py ãã¡ã€ã«ã§ã# TODO: REPLACE_EXTRACT_AGENT ã®ã³ã¡ã³ããæ¢ããŸãã
ãã®è¡å šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
extraction_agent = LlmAgent(
name="ExtractionAgent",
model="gemini-2.5-flash",
instruction="""Extract information from the uploaded media.
Previous step result: {upload_result}
Use `extract_from_media(gcs_uri, media_type, signed_url)` with the values from the upload result.
The gcs_uri is in upload_result['gcs_uri'], media_type in upload_result['media_type'], and signed_url in upload_result['signed_url'].
Return the extraction results including entities and relationships found.""",
tools=[extract_from_media],
output_key="extraction_result"
)
instruction ã {upload_result} ãåç
§ããŠããããšã«æ³šç®ããŠãã ãããããããADK ã§ãšãŒãžã§ã³ãéã§ç¶æ
ãæž¡ãæ¹æ³ã§ãã
4. Spanner ãšãŒãžã§ã³ããå®çŸ©ãã
ãã®ãšãŒãžã§ã³ãã¯ãæœåºããããšã³ãã£ãã£ãšé¢ä¿ãã°ã©ã ããŒã¿ããŒã¹ã«ä¿åããŸãã
ðmultimedia_agent.py ãã¡ã€ã«ã§ã# TODO: REPLACE_SPANNER_AGENT ã®ã³ã¡ã³ããæ¢ããŸãã
ãã®è¡å šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
spanner_agent = LlmAgent(
name="SpannerAgent",
model="gemini-2.5-flash",
instruction="""Save the extracted information to the database.
Upload result: {upload_result}
Extraction result: {extraction_result}
Use `save_to_spanner(extraction_result, survivor_id)` to save to Spanner.
Pass the WHOLE `extraction_result` object/dict from the previous step.
Include survivor_id if it was provided in the upload step.
Return the save statistics.""",
tools=[save_to_spanner],
output_key="spanner_result"
)
ãã®ãšãŒãžã§ã³ãã¯ãåã®ã¹ãããïŒupload_result ãš extraction_resultïŒã®äž¡æ¹ããã³ã³ããã¹ããåãåããŸãã
5. èŠçŽãšãŒãžã§ã³ããå®çŸ©ãã
ãã®ãšãŒãžã§ã³ãã¯ãåã®ãã¹ãŠã®ã¹ãããã®çµæãçµ±åããŠããŠãŒã¶ãŒã«ããããããã¬ã¹ãã³ã¹ãçæããŸãã
ðmultimedia_agent.py ãã¡ã€ã«ã§ãsummary_instruction="" # TODO: REPLACE_SUMMARY_AGENT_PROMPT ã®ã³ã¡ã³ããæ¢ããŸãã
ãã®è¡å šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
USE_MEMORY_BANK = os.getenv("USE_MEMORY_BANK", "false").lower() == "true"
save_msg = "6. Mention that the data is also being synced to the memory bank." if USE_MEMORY_BANK else ""
summary_instruction = f"""Provide a user-friendly summary of the media processing.
Upload: {{upload_result}}
Extraction: {{extraction_result}}
Database: {{spanner_result}}
Summarize:
1. What file was processed (name and type)
2. Key information extracted (survivors, skills, needs, resources found) - list names and counts
3. Relationships identified
4. What was saved to the database (broadcast ID, number of entities)
5. Any issues encountered
{save_msg}
Be concise but informative."""
ãã®ãšãŒãžã§ã³ãã¯ããŒã«ãå¿ èŠãšããŸãããå ±æãããã³ã³ããã¹ããèªã¿åãããŠãŒã¶ãŒåãã«ããããããèŠçŽãçæããã ãã§ãã
ð§ ã¢ãŒããã¯ãã£ã®æŠèŠ
ã¬ã€ã€ | ãã¡ã€ã« | 責任ç¯å² |
Tooling |
| æ¹æ³ - ã¢ããããŒããæœåºãä¿å |
ãšãŒãžã§ã³ã |
| å 容 - ãã€ãã©ã€ã³ããªãŒã±ã¹ãã¬ãŒããã |
11. ãã«ãã¢ãŒãã« ããŒã¿ ãã€ãã©ã€ã³ - ãªãŒã±ã¹ãã¬ãŒã·ã§ã³
æ°ããã·ã¹ãã ã®ã³ã¢ã¯ãbackend/agent/multimedia_agent.py ã§å®çŸ©ããã MultimediaExtractionPipeline ã§ããADKïŒAgent Development KitïŒã®ã·ãŒã±ã³ã·ã£ã« ãšãŒãžã§ã³ã ãã¿ãŒã³ã䜿çšããŸãã
1. Sequential ã䜿çšããçç±
ã¢ããããŒãã®åŠçã¯ç·åœ¢ã®äŸåé¢ä¿ãã§ãŒã³ã§ãã
- ãã¡ã€ã«ïŒã¢ããããŒãïŒããªããšãããŒã¿ãæœåºã§ããŸããã
- ããŒã¿ãæœåºïŒæœåºïŒãããŸã§ãããŒã¿ãä¿åããããšã¯ã§ããŸããã
- çµæïŒä¿åïŒãåŸããããŸã§ãèŠçŽããããšã¯ã§ããŸããã
ãã®å Žå㯠SequentialAgent ãæé©ã§ãã1 ã€ã®ãšãŒãžã§ã³ãã®åºåãæ¬¡ã®ãšãŒãžã§ã³ãã®ã³ã³ããã¹ã/å
¥åãšããŠæž¡ããŸãã
2. ãšãŒãžã§ã³ãã®å®çŸ©
multimedia_agent.py ã®äžéšã§ãã€ãã©ã€ã³ãã©ã®ããã«çµã¿ç«ãŠãããŠããããèŠãŠã¿ãŸããããðð» ã¿ãŒããã«ã§ã次ã®ã³ãã³ããå®è¡ã㊠Cloud Shell ãšãã£ã¿ã§ãã¡ã€ã«ãéããŸãã
cloudshell edit ~/way-back-home/level_2/backend/agent/multimedia_agent.py
åã®äž¡æ¹ã®ã¹ãããããå
¥åãåãåããŸããã³ã¡ã³ã # TODO: REPLACE_ORCHESTRATION ãèŠã€ããŸãããã®è¡å
šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
sub_agents=[upload_agent, extraction_agent, spanner_agent, summary_agent]
3. Root Agent ãšæ¥ç¶ãã
ðð» ã¿ãŒããã«ã§ã次ã®ã³ãã³ããå®è¡ã㊠Cloud Shell ãšãã£ã¿ã§ãã¡ã€ã«ãéããŸãã
cloudshell edit ~/way-back-home/level_2/backend/agent/agent.py
ã³ã¡ã³ã # TODO: REPLACE_ADD_SUBAGENT ãèŠã€ããŸãããã®è¡å
šäœã次ã®ã³ãŒãã«çœ®ãæããŸãã
sub_agents=[multimedia_agent],
ãã®åäžã®ãªããžã§ã¯ãã¯ã4 ã€ã®ããšãã¹ããŒããã 1 ã€ã®åŒã³åºãå¯èœãªãšã³ãã£ãã£ã«å¹æçã«ãã³ãã«ããŸãã
4. ãšãŒãžã§ã³ãéã®ããŒã¿ãããŒ
åãšãŒãžã§ã³ãã¯ãåŸç¶ã®ãšãŒãžã§ã³ããã¢ã¯ã»ã¹ã§ããå ±æã³ã³ããã¹ãã«åºåãä¿åããŸãã

5. ã¢ããªã±ãŒã·ã§ã³ãéãïŒã¢ããªããŸã å®è¡äžã®å Žåã¯ã¹ãããïŒ
ðð» ã¢ããªã®èµ·å:
cd ~/way-back-home/level_2/
./start_app.sh
ð ã¿ãŒããã«ã§ [Local: http://localhost:5173/] ãã¯ãªãã¯ããŸãã
6. ãã¹ãç»åã®ã¢ããããŒã
ð ãã£ãã ã€ã³ã¿ãŒãã§ãŒã¹ã§ã次ã®ããããã®åçãéžæã㊠UI ã«ã¢ããããŒãããŸãã
ãã£ãã ã€ã³ã¿ãŒãã§ãŒã¹ã§ããšãŒãžã§ã³ãã«ç¹å®ã®ã³ã³ããã¹ããäŒããŸãã
Here is the survivor note
ããã«ç»åãæ·»ä»ããŸãã


ðð» ã¿ãŒããã«ã§ããã¹ããå®äºããããCtrl+CããæŒããŠããã»ã¹ãçµäºããŸãã
6. GCS ãã±ããã§ã®ãã«ãã¢ãŒãã« ã¢ããããŒãã確èªãã
- Google Cloud ã³ã³ãœãŒã«ã§ Storage ãéããŸãã
- Cloud Storage ã§ [ãã±ãã] ãéžæãã

- ãã±ãããéžæããŠ
mediaãã¯ãªãã¯ããŸãã

- ã¢ããããŒãããç»åã¯ãã¡ãã§ç¢ºèªã§ããŸãã

7. Spanner ã§ãã«ãã¢ãŒãã« ã¢ããããŒãã確èªããïŒçç¥å¯ïŒ
以äžã¯ãtest_photo1 ã® UI ã®åºåäŸã§ãã
- Google Cloud ã³ã³ãœãŒã«ã® Spanner ãéããŸãã
- ã€ã³ã¹ã¿ã³ã¹ãéžæããŸã:
Survivor Network - ããŒã¿ããŒã¹ãéžæããŸãã
graph-db - å·ŠåŽã®ãµã€ãããŒã§ã[Spanner Studio] ãã¯ãªãã¯ããŸãã
ð Spanner Studio ã§ãæ°ããããŒã¿ãã¯ãšãªããŸãã
SELECT
s.name AS Survivor,
s.role AS Role,
b.name AS Biome,
r.name AS FoundResource,
s.created_at
FROM Survivors s
LEFT JOIN SurvivorInBiome sib ON s.survivor_id = sib.survivor_id
LEFT JOIN Biomes b ON sib.biome_id = b.biome_id
LEFT JOIN SurvivorFoundResource sfr ON s.survivor_id = sfr.survivor_id
LEFT JOIN Resources r ON sfr.resource_id = r.resource_id
ORDER BY s.created_at DESC;
以äžã®çµæã§ç¢ºèªã§ããŸãã

12. Agent Engine ã䜿çšãã Memory Bank
1. ã¡ã¢ãªã®ä»çµã¿
ãã®ã·ã¹ãã ã§ã¯ã峿ã³ã³ããã¹ããšé·æåŠç¿ã®äž¡æ¹ãåŠçããããã«ããã¥ã¢ã«ã¡ã¢ãª ã¢ãããŒãã䜿çšããŠããŸãã

2. ã¡ã¢ãªãŒ ãããã¯ãšã¯
èšæ¶ã®ãããã¯ã¯ããšãŒãžã§ã³ããäŒè©±å šäœã§èšæ¶ãã¹ãæ å ±ã®ã«ããŽãªãå®çŸ©ããŸããããŸããŸãªçš®é¡ã®ãŠãŒã¶ãŒèšå®ãä¿ç®¡ãããã¡ã€ã« ãã£ããããã®ãããªãã®ã ãšèããŠãã ããã
2 ã€ã®ãããã¯:
search_preferences: ãŠãŒã¶ãŒãæ€çŽ¢ãå¥œãæ¹æ³- ããŒã¯ãŒãæ€çŽ¢ãšã»ãã³ãã£ãã¯æ€çŽ¢ã®ã©ã¡ãã奜ã¿ãŸããïŒ
- ã©ã®ãããªã¹ãã«ããã€ãªãŒã ãããæ€çŽ¢ããŠãããã
- äŸ: ããŠãŒã¶ãŒã¯å»çã¹ãã«ã«ã»ãã³ãã£ãã¯æ€çŽ¢ã奜ãã
urgent_needs_context: 远跡ããŠãã屿©- ã¢ãã¿ãªã³ã°å¯Ÿè±¡ã®ãªãœãŒã¹ã¯äœã§ããïŒ
- ã©ã®çåè ãå¿é ããŠãããã
- äŸ: ããŠãŒã¶ãŒã¯åãã£ã³ãã®è¬äžè¶³ã远跡ããŠããŸãã
3. èšæ¶ã®ãããã¯ã®èšå®
ã«ã¹ã¿ã ã¡ã¢ãªãããã¯ã¯ããšãŒãžã§ã³ããäœãèšæ¶ãã¹ãããå®çŸ©ããŸãããããã¯ãAgent Engine ã®ãããã€æã«æ§æãããŸãã
ðð» ã¿ãŒããã«ã§ã次ã®ã³ãã³ããå®è¡ã㊠Cloud Shell ãšãã£ã¿ã§ãã¡ã€ã«ãéããŸãã
cloudshell edit ~/way-back-home/level_2/backend/deploy_agent.py
ããã«ããããšãã£ã¿ã§ ~/way-back-home/level_2/backend/deploy_agent.py ãéããŸãã
æ§é äœ MemoryTopic ãªããžã§ã¯ããå®çŸ©ããŠãæœåºããŠä¿åããæ
å ±ã LLM ã«æç€ºããŸãã
ðdeploy_agent.py ãã¡ã€ã«ã§ã# TODO: SET_UP_TOPIC ãæ¬¡ã®ããã«çœ®ãæããŸãã
# backend/deploy_agent.py
custom_topics = [
# Topic 1: Survivor Search Preferences
MemoryTopic(
custom_memory_topic=CustomMemoryTopic(
label="search_preferences",
description="""Extract the user's preferences for how they search for survivors. Include:
- Preferred search methods (keyword, semantic, direct lookup)
- Common filters used (biome, role, status)
- Specific skills they value or frequently look for
- Geographic areas of interest (e.g., "forest biome", "mountain outpost")
Example: "User prefers semantic search for finding similar skills."
Example: "User frequently checks for survivors in the Swamp Biome."
""",
)
),
# Topic 2: Urgent Needs Context
MemoryTopic(
custom_memory_topic=CustomMemoryTopic(
label="urgent_needs_context",
description="""Track the user's focus on urgent needs and resource shortages. Include:
- Specific resources they are monitoring (food, medicine, ammo)
- Critical situations they are tracking
- Survivors they are particularly concerned about
Example: "User is monitoring the medicine shortage in the Northern Camp."
Example: "User is looking for a doctor for the injured survivors."
""",
)
)
]
4. ãšãŒãžã§ã³ãã®çµ±å
ãšãŒãžã§ã³ã ã³ãŒãã¯ãæ å ±ãä¿åããŠååŸããããã« Memory Bank ãèªèããŠããå¿ èŠããããŸãã
ðð» ã¿ãŒããã«ã§ã次ã®ã³ãã³ããå®è¡ã㊠Cloud Shell ãšãã£ã¿ã§ãã¡ã€ã«ãéããŸãã
cloudshell edit ~/way-back-home/level_2/backend/agent/agent.py
ããã«ããããšãã£ã¿ã§ ~/way-back-home/level_2/backend/agent/agent.py ãéããŸãã
ãšãŒãžã§ã³ãã®äœæ
ãšãŒãžã§ã³ããäœæãããšãã«ãafter_agent_callback ãæž¡ããŠãã€ã³ã¿ã©ã¯ã·ã§ã³åŸã«ã»ãã·ã§ã³ãã¡ã¢ãªã«ä¿åãããããã«ããŸããadd_session_to_memory 颿°ã¯ããã£ããã®å¿çãé
ããªãã®ãé²ãããã«éåæã§å®è¡ãããŸãã
ð agent.py ãã¡ã€ã«ã§ãã³ã¡ã³ã # TODO: REPLACE_ADD_SESSION_MEMORY ãèŠã€ãããã®è¡å
šäœã 次ã®ã³ãŒãã«çœ®ãæããŸãã
async def add_session_to_memory(
callback_context: CallbackContext
) -> Optional[types.Content]:
"""Automatically save completed sessions to memory bank in the background"""
if hasattr(callback_context, "_invocation_context"):
invocation_context = callback_context._invocation_context
if invocation_context.memory_service:
# Use create_task to run this in the background without blocking the response
asyncio.create_task(
invocation_context.memory_service.add_session_to_memory(
invocation_context.session
)
)
logger.info("Scheduled session save to memory bank in background")
ããã¯ã°ã©ãŠã³ãä¿å
ð agent.py ãã¡ã€ã«ã§ãã³ã¡ã³ã # TODO: REPLACE_ADD_MEMORY_BANK_TOOL ãèŠã€ãããã®è¡å
šäœã 次ã®ã³ãŒãã«çœ®ãæããŸãã
if USE_MEMORY_BANK:
agent_tools.append(PreloadMemoryTool())
ð agent.py ãã¡ã€ã«ã§ãã³ã¡ã³ã # TODO: REPLACE_ADD_CALLBACK ãèŠã€ãããã®è¡å
šäœã 次ã®ã³ãŒãã«çœ®ãæããŸãã
after_agent_callback=add_session_to_memory if USE_MEMORY_BANK else None
Vertex AI ã»ãã·ã§ã³ ãµãŒãã¹ãèšå®ãã
ðð» ã¿ãŒããã«ã§ã次ã®ã³ãã³ããå®è¡ã㊠Cloud Shell ãšãã£ã¿ã§ãã¡ã€ã« chat.py ãéããŸãã
cloudshell edit ~/way-back-home/level_2/backend/api/routes/chat.py
ðchat.py ãã¡ã€ã«ã§ãã³ã¡ã³ã # TODO: REPLACE_VERTEXAI_SERVICES ãèŠã€ãããã®è¡å
šäœã眮ãæããŸããæ¬¡ã®ã³ãŒãã«çœ®ãæããŸãã
session_service = VertexAiSessionService(
project=project_id,
location=location,
agent_engine_id=agent_engine_id
)
memory_service = VertexAiMemoryBankService(
project=project_id,
location=location,
agent_engine_id=agent_engine_id
)
4. ã»ããã¢ãããšå°å ¥
ã¡ã¢ãªæ©èœããã¹ãããåã«ãæ°ããã¡ã¢ãª ãããã¯ã䜿çšããŠãšãŒãžã§ã³ãããããã€ããç°å¢ãæ£ããæ§æãããŠããããšã確èªããå¿ èŠããããŸãã
ãã®ããã»ã¹ãåŠçããããã®ã³ã³ãããšã³ã¹ ã¹ã¯ãªãããçšæãããŠããŸãã
ããã〠ã¹ã¯ãªããã®å®è¡
ðð» ã¿ãŒããã«ã§ãããã〠ã¹ã¯ãªãããå®è¡ããŸãã
cd ~/way-back-home/level_2
./deploy_and_update_env.sh
ãã®ã¹ã¯ãªããã¯ã次ã®ã¢ã¯ã·ã§ã³ãå®è¡ããŸãã
backend/deploy_agent.pyãå®è¡ããŠããšãŒãžã§ã³ããšã¡ã¢ãªã®ãããã¯ã Vertex AI ã«ç»é²ããŸãã- æ°ãã Agent Engine ID ãååŸããŸãã
AGENT_ENGINE_IDã䜿çšããŠ.envãã¡ã€ã«ãèªåçã«æŽæ°ããŸãã.envãã¡ã€ã«ã§USE_MEMORY_BANK=TRUEãèšå®ãããŠããããšã確èªããŸãã
[!IMPORTANT] deploy_agent.py ã® custom_topics ã倿Žããå Žåã¯ããã®ã¹ã¯ãªãããåå®è¡ã㊠Agent Engine ãæŽæ°ããå¿
èŠããããŸãã
13. ãã«ãã¢ãŒãã« ããŒã¿ã§ã¡ã¢ãªãã³ã¯ãæ€èšŒãã
ã¡ã¢ãªãã³ã¯ãæ©èœããŠãããã©ããã¯ããšãŒãžã§ã³ãã«èšå®ãæããã»ãã·ã§ã³éã§ãã®èšå®ãä¿æããããã©ããã確èªããããšã§æ€èšŒã§ããŸãã
1. ã¢ããªã±ãŒã·ã§ã³ãéããŸãïŒã¢ããªã±ãŒã·ã§ã³ããã§ã«å®è¡ãããŠããå Žåã¯ããã®æé ãã¹ãããããŸãïŒã
æ¬¡ã®æé ã«æ²¿ã£ãŠãã¢ããªã±ãŒã·ã§ã³ãå床éããŸããåã®ã¿ãŒããã«ããŸã å®è¡äžã®å Žåã¯ãCtrls+C ãæŒããŠçµäºããŸãã
ðð» ã¢ããªã®èµ·å:
cd ~/way-back-home/level_2/
./start_app.sh
ð ã¿ãŒããã«ã§ [Local: http://localhost:5173/] ãã¯ãªãã¯ããŸãã
2. ããã¹ãã䜿çšãã Memory Bank ã®ãã¹ã
ãã£ãã ã€ã³ã¿ãŒãã§ãŒã¹ã§ããšãŒãžã§ã³ãã«ç¹å®ã®ã³ã³ããã¹ããäŒããŸãã
"I'm planning a medical rescue mission in the mountains. I need survivors with first aid and climbing skills."
ð ã¡ã¢ãªãããã¯ã°ã©ãŠã³ãã§åŠçããããŸã§ 30 ç§ã»ã©åŸ ã¡ãŸãã
2. æ°ããã»ãã·ã§ã³ãéå§ãã
ããŒãžãæŽæ°ãããšãçŸåšã®äŒè©±å±¥æŽïŒçæèšæ¶ïŒãã¯ãªã¢ãããŸãã
以åã«æäŸããã³ã³ããã¹ãã«åºã¥ã質åãããŸãã
"What kind of missions am I interested in?"
æ³å®ãããåç:
ããããŸã§ã®äŒè©±ã«åºã¥ããŠãã客æ§ã¯æ¬¡ã®ããšã«èå³ããæã¡ã®ããã§ãã
- å»çæå©ããã·ã§ã³
- 山岳/é«å°ã§ã®éçš
- å¿ èŠãªã¹ãã«: å¿æ¥åŠçœ®ãç»å±±
ãããã®æ¡ä»¶ã«äžèŽããçåè ããæ¢ãããŸããããïŒã
3. ç»åã¢ããããŒãã§ãã¹ããã
ç»åãã¢ããããŒãããŠã次ã®ããã«è³ªåããŸãã
remember this
ããã«è¡šç€ºãããŠããåçãŸãã¯ãèªèº«ã®åçãéžæããŠãUI ã«ã¢ããããŒãã§ããŸãã
4. Vertex AI Agent Engine ã§ç¢ºèªãã
Google Cloud ã³ã³ãœãŒã« Agent Engine ã«ç§»åããŸãã
- å·Šäžã®ãããžã§ã¯ãéžæããŒã«ã§ãããžã§ã¯ããéžæããŸãã

- åã®ã³ãã³ã
use_memory_bank.shã§ãããã€ãããšãŒãžã§ã³ã ãšã³ãžã³ã確èªããŸãã
äœæãããšãŒãžã§ã³ã ãšã³ãžã³ãã¯ãªãã¯ããŸãã - ãã®ãããã€ããããšãŒãžã§ã³ãã® [
Memories] ã¿ããã¯ãªãã¯ãããšããã¹ãŠã®ã¡ã¢ãªã衚瀺ã§ããŸãã
ðð» ãã¹ããå®äºããããã¿ãŒããã«ã§ãCtrl+Cããã¯ãªãã¯ããŠããã»ã¹ãçµäºããŸãã
ãç²ãããŸã§ããããã§ãMemory Bank ããšãŒãžã§ã³ãã«ã¢ã¿ãããããŸããã
14. Cloud Run ã«ãããã€ãã
1. ããã〠ã¹ã¯ãªãããå®è¡ãã
ðð» ããã〠ã¹ã¯ãªãããå®è¡ããŸãã
cd ~/way-back-home/level_2
./deploy_cloud_run.sh
ãããã€ãæ£åžžã«å®äºãããšãURL ã衚瀺ãããŸããããããããã€ããã URL ã§ãã
ðð» URL ãååŸããåã«ã次ã®ã³ãã³ããå®è¡ããŠæš©éãä»äžããŸãã
source .env && gcloud run services add-iam-policy-binding survivor-frontend --region $REGION --member=allUsers --role=roles/run.invoker && gcloud run services add-iam-policy-binding survivor-backend --region $REGION --member=allUsers --role=roles/run.invoker
ãããã€ããã URL ã«ç§»åãããšãã¢ããªã±ãŒã·ã§ã³ãã©ã€ãã§è¡šç€ºãããŸãã
2. ãã«ã ãã€ãã©ã€ã³ã«ã€ããŠ
cloudbuild.yaml ãã¡ã€ã«ã«ã¯ã次ã®é 次ã¹ããããå®çŸ©ãããŠããŸãã
- Backend Build:
backend/Dockerfileãã Docker ã€ã¡ãŒãžããã«ãããŸãã - Backend Deploy: ããã¯ãšã³ã ã³ã³ããã Cloud Run ã«ãããã€ããŸãã
- Capture URL: æ°ããããã¯ãšã³ã URL ãååŸããŸãã
- ããã³ããšã³ã ãã«ã:
- äŸåé¢ä¿ãã€ã³ã¹ããŒã«ããŸãã
VITE_API_URL=ãæ¿å ¥ã㊠React ã¢ããªããã«ãããŸãã
- ããã³ããšã³ã ã€ã¡ãŒãž:
frontend/Dockerfileãã Docker ã€ã¡ãŒãžããã«ãããŸãïŒéçã¢ã»ãããããã±ãŒãžåããŸãïŒã - Frontend Deploy: ããã³ããšã³ã ã³ã³ããããããã€ããŸãã
3. Deployment ã確èªãã
ãã«ããå®äºãããïŒã¹ã¯ãªããã§æäŸããããã°ãªã³ã¯ã確èªïŒã次ã®ããšã確èªã§ããŸãã
- Cloud Run ã³ã³ãœãŒã«ã«ç§»åããŸãã
survivor-frontendãµãŒãã¹ãèŠã€ããŸãã- URL ãã¯ãªãã¯ããŠã¢ããªã±ãŒã·ã§ã³ãéããŸãã
- æ€çŽ¢ã¯ãšãªãå®è¡ããŠãããã³ããšã³ããããã¯ãšã³ããšéä¿¡ã§ããããšã確èªããŸãã
4. ïŒã¯ãŒã¯ã·ã§ããåå è ã®ã¿ïŒäœçœ®æ å ±ãæŽæ°ãã
ðð» è£å®ã¹ã¯ãªãããå®è¡ããŸãã
cd ~/way-back-home/level_2
./set_level_2.sh
waybackhome.dev ãéããšãçŸåšå°ãæŽæ°ãããŠããããšãããããŸããããã§ã¬ãã« 2 ã¯å®äºã§ãã

ïŒçç¥å¯ïŒ5. æåãããã€
ã³ãã³ããæåã§å®è¡ããå Žåããããã»ã¹ãããæ·±ãçè§£ãããå Žåã¯ãcloudbuild.yaml ãçŽæ¥äœ¿çšããæ¹æ³ãã芧ãã ããã
æžã蟌㿠cloudbuild.yaml
cloudbuild.yaml ãã¡ã€ã«ã¯ãå®è¡ããã¹ãããã Google Cloud Build ã«æç€ºããŸãã
- steps: é æ¬¡å®è¡ãããã¢ã¯ã·ã§ã³ã®ãªã¹ããåã¹ãããã¯ã³ã³ããïŒ
dockerãgcloudãnodeãbashïŒã - substitutions: ãã«ãæã«æž¡ãããšãã§ãã倿°ïŒäŸ:
$_REGIONïŒã - workspace: ã¹ãããããã¡ã€ã«ãå
±æã§ããå
±æãã£ã¬ã¯ããªïŒ
backend_url.txtãå ±æããæ¹æ³ãšåæ§ïŒã
Deployment ãå®è¡ãã
ã¹ã¯ãªããã䜿çšããã«æåã§ãããã€ããã«ã¯ãgcloud builds submit ã³ãã³ãã䜿çšããŸããå¿
èŠãªä»£å
¥å€æ°ãæž¡ããªããã°ãªããŸããã
# Load your env vars first or replace these values manually
export PROJECT_ID=your-project-id
export REGION=us-central1
gcloud builds submit --config cloudbuild.yaml \
--project "$PROJECT_ID" \
--substitutions _REGION="us-central1",_GOOGLE_API_KEY="",_AGENT_ENGINE_ID="your-agent-id",_USE_MEMORY_BANK="TRUE",_GOOGLE_GENAI_USE_VERTEXAI="TRUE"
15. ãŸãšã
1. äœæããå 容
â
ã°ã©ã ããŒã¿ããŒã¹: ããŒãïŒãµãã€ããŒãã¹ãã«ïŒãšãšããžïŒé¢ä¿ïŒãå«ã Spanner
â
AI Search: ãšã³ããã£ã³ã°ã䜿çšããããŒã¯ãŒãæ€çŽ¢ãã»ãã³ãã£ãã¯æ€çŽ¢ããã€ããªããæ€çŽ¢
â
ãã«ãã¢ãŒãã« ãã€ãã©ã€ã³: Gemini ã䜿çšããŠç»å/åç»ãããšã³ãã£ãã£ãæœåºãã
â
ãã«ããšãŒãžã§ã³ã ã·ã¹ãã : ADK ã䜿çšãã調æŽãããã¯ãŒã¯ãããŒ
â
ã¡ã¢ãªãã³ã¯: Vertex AI ã䜿çšããé·æçãªããŒãœãã©ã€ãº
â
æ¬çªç°å¢ãžã®ãããã€: Cloud Run + Agent Engine
2. ã¢ãŒããã¯ãã£ã®æŠèŠ

3. åŸãããç¥èŠ
- ã°ã©ã RAG: ã°ã©ã ããŒã¿ããŒã¹æ§é ãšã»ãã³ãã£ã㯠ãšã³ããã£ã³ã°ãçµã¿åãããŠã€ã³ããªãžã§ã³ãæ€çŽ¢ãå®çŸ
- ãã«ããšãŒãžã§ã³ã ãã¿ãŒã³: è€éãªè€æ°ã¹ãããã®ã¯ãŒã¯ãããŒçšã®é 次ãã€ãã©ã€ã³
- ãã«ãã¢ãŒãã« AI: éæ§é åã¡ãã£ã¢ïŒç»å/åç»ïŒããæ§é åããŒã¿ãæœåºãã
- ã¹ããŒããã« ãšãŒãžã§ã³ã: Memory Bank ã䜿çšããŠã»ãã·ã§ã³éã§ããŒãœãã©ã€ãºãæå¹ã«ãã
4. ã¯ãŒã¯ã·ã§ããã®å 容
- Level0: Identify YourselfïŒèªå·±ç޹ä»ïŒ
- Level1: æ£ç¢ºãªäœçœ®æ å ±
- ã¬ãã« 2ïŒãã® CodelabïŒ: ã°ã©ã RAGãADKãMemory Bank ã䜿çšããŠãã«ãã¢ãŒãã« AI ãšãŒãžã§ã³ããæ§ç¯ãã
- Level3: ADK åæ¹åã¹ããªãŒãã³ã° ãšãŒãžã§ã³ãã®æ§ç¯
- Level4: åæ¹åãã«ããšãŒãžã§ã³ã ã·ã¹ãã ã®ã©ã€ãé ä¿¡
- Level5: Google ADKãA2AãKafka ã䜿çšããã€ãã³ã ããªãã³ ã¢ãŒããã¯ãã£