iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0
Build on Google AI

AI 策展人:用 Google ADK 打造會思考、會介紹的 3D 展示平台系列 第 22 篇

Day 22|`curator_agent`:挑熱點、寫雙語文案、寫 FAQ

  • 分享至 

  • xImage
  •  

接力隊第五棒、最後一棒 curator_agent(策展人)。它拿到的是 Day 13 由 Pack 用幾何算好的「熱點候選」,要做的是挑、排、寫,不是決定位置。

比喻→術語對照表

比喻 術語 白話
策展人 curator_agent(LlmAgent) 接力隊最後一棒
候選名單 build_scene 回的 hotspot_candidates(hs_01…hs_08) 場景包依體積挑出的熱點,已附鏡頭與錨點
挑、排、寫 write_hotspots 從候選裡選、排序、寫 title/body/英文版
現場問答 write_faq 寫 12–20 題 {q, a, lang}
候選名單從哪來 exhibit Pack 的 suggest_hotspots(公開純函式) 純資料運算,不需要 AI

守則重點

tools=[catalog.list_parts, catalog.build_scene, catalog.write_hotspots, catalog.write_faq]
  1. list_parts 看零件樹。
  2. build_scene:Pack 給一批熱點候選(相機與錨點由幾何決定,不由你決定)。
  3. write_hotspots:從候選裡挑 3–8 個,依參觀動線排序,每個寫 title/body(繁體中文,兩到三句,講功能與看點,不寫規格表)與 title_en/body_en;只能用候選給的 id。
  4. write_faq:寫 12–20 題(lang 用 zh-TW),只根據零件樹與 QA 數字回答得出來的問題;不知道的規格不要編。

兩半:Pack 算位置,AI 寫字

誰做 需要 AI?
挑哪些零件當熱點候選(依體積由大到小取前 8)、錨點、鏡頭角度、導覽 tour、互動設定 exhibit Pack 的 build_scene → suggest_hotspots(Day 13) 不需要
從候選裡選 3–8 個、排序、寫標題/介紹/英文、寫 FAQ curator_agent 需要

build_scene 工具寫 scenes/main.scene.json 並跑契約驗證,回 hotspot_candidates: [{id, title, part_id}]。exhibit.set_camera 這個 Pack 工具只在 manifest 宣告,尚未實作(X1 HANDOFF:待 W5)。

write_hotspots 做的事

  • 讀 scenes/main.scene.json;任何 id 不在候選裡 → 整批拒絕(unknown_hotspot,「只能用 build_scene 給的候選 id」)。
  • 逐筆覆寫 title/body,order 依你給的順序重編(1、2、3…)。
  • scene["hotspots"] 換成被選中的那幾個(沒被選的候選就此消失)。
  • scene["tour"] 重新產生:{"enabled": true, "steps": [選中的 id 依序], "dwell_s": 8, "loop": true}。
  • 另外寫一份雙語文案到資產目錄的 extras/exhibit/hotspots.json:{asset_id, count, hotspots: [{id, title, body, title_en, body_en, anchor}]}。

這份 extras/exhibit/hotspots.json 不是 Day 14 離線包裡那份 hotspots.json:離線包是 exhibit-kiosk build 時從 scene.json 抽出 title/body/media 另外生成的。英文欄位只存在前者。

write_faq 做的事

doc = {"asset_id": asset_id, "generated": bool(faq), "count": len(faq), "items": list(faq)}
if not faq:
    doc["reason"] = "no_model_credentials"

寫到 extras/exhibit/faq.json;空清單就明確標「沒有生成,原因是沒有模型憑證」,不是留空白檔。

離線劇本

def plan_curator(state):
    if not state.get("scene"):         return [("build_scene", ...)]
    if "hotspots" not in outputs:      return [("write_hotspots", {"hotspots": []})]   # 空 list = 沿用候選,不寫文案
    if "faq" not in outputs:           return [("write_faq", {"faq": []})]

空 list 的 write_hotspots:沿用 scene 目前的熱點,不加文案;tour 照樣重新產生。

實跑(離線,ast_day22,exhibit.kiosk)

scene.tour = {"enabled": true, "steps": ["hs_01".."hs_08"], "dwell_s": 8, "loop": true}
hotspots(依序)= Housing_Body、Base_Plate、Motor、Output_Gear、Housing_Cover、ROT_Output_Shaft、Motor_Flange、ROT_Input_Shaft
                 (title 即零件英文原名;每個都沒有 body)
extras/exhibit/hotspots.json = {count: 8, hotspots[0]: {id: hs_01, title: Housing_Body, body: null, anchor: {part: p_0004}}}
extras/exhibit/faq.json      = {generated: false, count: 0, items: [], reason: "no_model_credentials"}

這 8 個就是 Day 14 展場離線包的 8 個熱點與導覽路線。

直接呼叫工具:兩個沒擋住的地方

用我標註「(測試)」的假文字呼叫 write_hotspots(不是 AI 輸出):

輸入 結果
只挑 2 個(hs_03、hs_01) 收下;scene.hotspots 只剩這 2 個、order 為 1、2;tour.steps = [hs_03, hs_01];英文欄位寫進 extras
同一個 id(hs_01)寫兩次 收下;contract_errors: [];scene.hotspots 出現兩筆 hs_01、tour.steps = [hs_01, hs_01]
先縮成 2 個之後再呼叫空 list 維持 2 個(「沿用」的是 scene 現有的熱點,不是原本 8 個候選)

「3–8 個」只在 docstring 與 instruction 裡,程式沒有檢查數量,也沒有檢查重複 id;scene 契約沒有 id 唯一性約束,所以驗證不會擋。這兩點已記進交接稿。

還沒做、還沒驗證的事

  • 真模型挑熱點、排序、寫中英文文案、寫 FAQ:沒有額度可測,完全沒實測(金鑰是免費層,見 Day 20)。
  • title_en/body_en 目前沒有任何程式讀取(viewer、kiosk 都沒有語言切換)。
  • faq.json 目前沒有任何消費者:docent(W5)與 kiosk 的斷網降級 FAQ 都還沒做。
  • 評測第 4 題 curator_hotspots_and_faq 的期望軌跡是離線的那幾步(build_scene → write_hotspots → write_faq),中文回答比對要真金鑰(Day 25)。

上一篇
Day 21|`semantic_agent`:零件中文名與材質推論
下一篇
Day 23|十個「沒有報錯」的坑
系列文
AI 策展人:用 Google ADK 打造會思考、會介紹的 3D 展示平台 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言