
可以用導航軟體來理解:不是每條路都一樣好,所以 planner 需要排序。

A* 會在可行路徑中找出成本較低的選擇。成本可以代表金錢、時間、風險、模型價格、API 穩定性,或人工審核負擔。

靜態 cost 是基本偏好:本地 Java 計算通常便宜又準確,大模型通常比較貴也比較慢。

動態 cost 則像即時路況。當資料量變大、模型額度快用完、或某個外部服務變慢,系統可以把該 action 的成本拉高,讓 planner 自動改走更合適的路。
Embabel 的 GOAP planner 背後可以用 A* 搜尋來理解:它會在可用 action 之間尋找能達成 goal 的低成本路徑。成本不只是錢,也可以是延遲、風險、模型品質、API 穩定性或人工審核負擔。
靜態權重用來表達基本偏好。例如本地 Java 計算便宜且準確,成本低;呼叫大型模型昂貴且慢,成本高。當兩條路都能達成目標,planner 自然會偏向較低成本的路。
進階做法是動態成本。當某個 provider 延遲升高、預算快用完、或某個資料來源暫時不可靠,就把該 action 的 cost 拉高,讓 agent 自動改走備援路徑。這比在流程中塞滿 if-else 更容易維運。
A* 規劃最值得講的地方,就是成本不是裝飾。你可以讓主路徑便宜、備援路徑昂貴,planner 就會自然偏向正常路徑。
@Cost 方法參數要可為 null,因為規劃時該物件可能還不存在關鍵前提:cost 只有在「多個 action 能產生同一個 output type」時才會被 planner 拿來比較。如果某個輸出型別只有唯一一個 action 能產生,planner 別無選擇,cost 設多少都不影響結果。所以下面刻意安排兩個都產生 ActivitySummary 的 action,讓 planner 真的需要「排順序」。
@Agent(description = "Offer draft review")
public class OfferFlowAgent {
// 路徑 A:便宜小模型 —— 成本低,但資料量大時品質不足
@Cost(name = "fastSummarizeCost")
public double fastSummarizeCost(@Nullable TravellerActivity activity) {
if (activity != null && activity.trips().size() > 50) {
return 0.9; // 資料量大,小模型摘要不可靠 → 拉高成本,讓 planner 改走備援
}
return 0.2; // 正常情況:便宜又夠用
}
@Action(costMethod = "fastSummarizeCost")
public ActivitySummary summarizeFast(TravellerActivity activity, Ai ai) {
return ai.withLlm("gpt-4o-mini")
.createObject("Summarize concisely: " + activity, ActivitySummary.class);
}
// 路徑 B:大模型 —— 成本固定偏高,但穩定可靠(備援路徑)
@Action(cost = 0.7)
public ActivitySummary summarizeAccurate(TravellerActivity activity, Ai ai) {
return ai.withLlm("gpt-4o")
.createObject("Summarize carefully: " + activity, ActivitySummary.class);
}
@Action(cost = 0.2)
public ReviewedOffer approve(OfferDraft draft, OfferPolicy policy) {
policy.assertAllowed(draft);
return new ReviewedOffer(draft.offer(), "approved");
}
}
summarizeFast 與 summarizeAccurate 的輸入(TravellerActivity)與輸出(ActivitySummary)型別完全相同,因此對 planner 來說它們是兩條殊途同歸的路,cost 就是用來在它們之間排順序的依據:
fastSummarizeCost 算出 0.2 < summarizeAccurate 的 0.7 → planner 走快路。fastSummarizeCost 動態拉高到 0.9 > 0.7 → planner 自動改走 summarizeAccurate 備援路。這就是「正常走快路、異常走備援」的具體實作,也讓靜態 cost(基本偏好)與動態 cost(即時路況)真正影響到決策。
這裡還要特別注意:costMethod 不是隨便指定一個方法名而已。fastSummarizeCost 讀的是 TravellerActivity,因此它適合掛在同樣依賴 TravellerActivity 的 summarizeFast(...) action 上。若把它掛到 approve(OfferDraft draft, OfferPolicy policy),成本方法讀取的物件和 action 的語意就會錯開,讀者會誤以為 approve 的成本取決於另一個資料集。
為你的 action 表補上 cost 欄位,至少設計一個『正常時走快路、異常時走備援』的動態成本規則。
如果你也想進一步學習如何透過 AI 開發 Spring Framework 應用,讓 AI 協助理解框架、撰寫程式、除錯與驗>證,歡迎到 Hahow 看凱文大叔的最新課程【駕馭 AI 的全端實戰養成班:從零打造企業級智慧應用系統】。一起>學習如何駕馭 AI,提升 Spring 應用的開發效率與品質。
課程連結