
工具不是丟越多給 LLM 越好,而是要把正確工具放在正確位置。

像總消費金額、旅行次數、會員等級這類數字,應該由 Java domain object 或既有 service 計算,再透過工具提供給 LLM。LLM 可以負責把結果整理成人看得懂的摘要,但不應該自己心算或猜資料。
這樣切分後,錯誤責任也比較清楚:數字錯了查 Java 工具,文案不順查 prompt,流程不對查 action 條件。
好的 agentic system 不應該把所有資料塞進 prompt 後要求 LLM 自己計算。以 TravellerActivity 為例,總消費、旅遊次數、是否高消費,這些應由 Java domain object 或 service 計算,再透過工具方法暴露給 LLM。
這就是 domain tool 的價值。LLM 不需要知道資料庫細節,也不需要重算金額;它只需要在適當情境呼叫工具,取得準確數字後用自然語言整理結果。
但工具暴露要克制。不要把整個 service 全開給模型,也不要暴露能改資料的危險方法。每個 LLM action 只拿它需要的最小工具集,這是安全、測試與成本控制的共同基礎。
這裡也要先把來源講清楚:Tool calling 這件事本身不是 Embabel 發明的概念,它屬於 LLM / Spring AI 這一層常見能力;Embabel 的角色是把它放進 @Action 與 Ai 這套 agent 流程裡,讓你在某一個 action 內明確決定「這次 LLM 呼叫可以看到哪些工具」。
這一段直接聚焦工具邊界與顯式注入,不再分散到啟動樣板。
工具邊界需要先定清楚:像總消費、旅遊次數、會員資格這些資料,應該由 Java service 或 domain object 提供準確結果。LLM 可以整理語意與產生草稿,但不應該自己猜數字。
record TravellerActivity(String name, Instant from, Instant to, List<Trip> trips) {
@Tool(description = "Total travel spend in the selected period")
public float totalSpend() { ... }
}
@Action
ActivitySummary summarize(TravellerActivity activity, Ai ai) {
return ai.withDefaultLlm()
.withToolObject(activity)
.createObject("Summarize: " + activity, ActivitySummary.class);
}
這裡要一起看兩件事:
第一,@Tool 只是把 totalSpend() 標成「可被暴露的工具方法」,不是標完就自動給 LLM 用。
第二,真正把工具交給這次 LLM 呼叫的是 ai.withDefaultLlm().withToolObject(activity)。
這個主題的核心是:定義 domain tool + 在 Embabel 的 Ai 物件上顯式引用它。金額計算是 domain object 內的確定性能力,不是交給 LLM 自由推論。
為 TravellerActivity 設計 3 個可暴露給 LLM 的 @Tool 方法,並列出 3 個不該暴露的方法。
如果你也想進一步學習如何透過 AI 開發 Spring Framework 應用,讓 AI 協助理解框架、撰寫程式、除錯與驗>證,歡迎到 Hahow 看凱文大叔的最新課程【駕馭 AI 的全端實戰養成班:從零打造企業級智慧應用系統】。一起>學習如何駕馭 AI,提升 Spring 應用的開發效率與品質。
課程連結