接力隊第四棒 semantic_agent(翻譯員)。任務:把 CAD 零件名變成展場觀眾看得懂的繁體中文名,並在有把握時標出材質。
| 比喻 | 術語 | 白話 |
|---|---|---|
| 翻譯員 | semantic_agent(LlmAgent) |
接力隊第四棒 |
| 零件清單 | list_parts 工具 |
列出零件樹(id、CAD 原名、階層、角色、體積、是否可點選) |
| 一次寫回所有名字 | set_part_semantics 工具 |
寫入 display_name 與 material_hint |
| 中文名 | display_name(asset.semantics.parts[]) |
給參觀者看的名字 |
| 材質線索 | material_hint |
自由文字,例如 steel、rubber |
| 這個零件只是分類標籤 | 非葉節點(selectable: false) |
demo 有 18 筆,其中 13 個葉零件、5 個分類節點 |
instruction 重點)instruction=_STATE_BRIEF + """
先 `list_parts`,再用一次 `set_part_semantics` 寫回結果(一次帶所有零件,不要一個一個呼叫)。
- display_name:**繁體中文**,展場觀眾看得懂的講法(`Input_Gear` → 小齒輪、`Housing_Cover` → 上蓋)。
- material_hint:只在名稱或角色明確暗示時才填(steel / aluminum / cast_iron / rubber / plastic…),
看不出來就不要填——寧可留白也不要猜錯材質。
- role 是 assembly 的節點也要給中文名。
""",
tools=[catalog.list_parts, catalog.set_part_semantics],
list_parts(asset_id):回傳每個零件的 id、name、display_name、node_path、role、material_hint、volume_mm3、selectable。
set_part_semantics(asset_id, parts):parts 每筆 {"id","display_name","material_hint"}。行為(程式 + 我直接呼叫實測):
id 不在零件樹 → 整批拒絕,回 envelope.fail("semantics.set_parts", "unknown_part", "零件樹裡沒有這些 id:[...]"),一筆都不寫。material_hint 給空字串會被忽略。{updated, named, total, contract_errors},named 是寫完之後有 display_name 的零件總數,並寫進 state["semantics"]。asset.json 時走契約驗證(contract_errors 空 = 通過)。| 去處 | 怎麼用 |
|---|---|
scene.parts[].display_name |
pack_sdk.scene_parts 複製 name、display_name、selectable、visible_default、explode_vector 五個欄位進 scene.json |
| 導覽熱點標題 | exhibit Pack 的熱點候選 title = display_name or name |
| viewer-core 的清單與標籤 | partLabel(id, entry, extrasName, nodeName):依序取 display_name、name、GLB 的 extras.name、節點名,都沒有才退回 id |
所以沒有中文名時,畫面不會空白,只是顯示英文原名。
我用 ast_day21(暫存目錄的離線管線產物)直接呼叫工具,用的是守則裡舉的兩個例子(不是 AI 翻的):
set_part_semantics([{"id":"p_9999","display_name":"不存在"}])
→ ok=False, error=unknown_part, "零件樹裡沒有這些 id:['p_9999']"
set_part_semantics([{"id":"p_0008","display_name":"小齒輪","material_hint":"steel"},
{"id":"p_0005","display_name":"上蓋","material_hint":""}])
→ ok=True, {updated: 2, named: 2, total: 18, contract_errors: []}
asset.json: p_0008 → ("小齒輪","steel");p_0005 → ("上蓋", None)
build_scene 之後 scene.parts:[("p_0005","上蓋"), ("p_0008","小齒輪")]
hotspots:hs_05(p_0005)title = "上蓋"
離線劇本(plan_semantic 直接回空):
def plan_semantic(state): return [] # 沒有模型就沒有中文命名——不捏造
def summary_semantic(state): return "(離線腳本)沒有 API key,略過零件中文化;display_name 維持空白,不填假資料。"
assets/ast_gearbox_demo/asset.json 讀回:18 筆 semantics.parts,display_name 非空 0 筆、material_hint 非空 0 筆。
agents/evals/expo_director.evalset.json 第 3 題 semantic_zh_display_names 的期望回答是「已呼叫 set_part_semantics 一次寫回所有零件的繁體中文 display_name,例如 Input_Gear 是小齒輪、Housing_Cover 是上蓋;材質只在名稱明確暗示時才填,看不出來的就留白」。但這題期望的工具軌跡裡沒有 list_parts 與 set_part_semantics(就是離線劇本的那 14 個呼叫),也就是文字期望與軌跡期望不一致;離線時兩者都跳過語意化,所以離線比對不受影響。真模型下會怎樣,要等有額度時校準才知道。
GOOGLE_API_KEY 額度可測,完全沒實測。material_hint → 3D 檔的金屬度/粗糙度(web-pack 的 MATERIAL_PBR 表,G4-m3):pack_web 呼叫 web-pack build 時沒有傳 --asset(agents/tools/catalog.py 的 argv 只有 --yup --validate [--draco]),所以寫了 material_hint 也不會影響輸出。這個接線屬 agents 子專案,G4-m3 筆記已記為待派工。role 欄位:cad-ingest 的 Python 原始碼裡沒有任何地方寫入 role,demo 資產 18 筆 role 全是 None。instruction 的「role 是 assembly 的節點也要給中文名」在真實資料上看不到這個欄位值,只能靠 selectable: false 辨認分類節點。下一篇:curator_agent,挑熱點、寫文案、寫 FAQ。