iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0

https://ithelp.ithome.com.tw/upload/images/20260806/20161290ftAA2ljpnE.png

演算法管邏輯,權重管偏好

今天要解決的問題

  • A* 搜尋最低總成本路徑
  • 靜態成本表達基本偏好
  • 動態成本表達環境狀態

觀念圖解

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

https://ithelp.ithome.com.tw/upload/images/20260806/20161290RLZwNdqG8q.png

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

https://ithelp.ithome.com.tw/upload/images/20260806/20161290ld9mH4dHpT.png

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

https://ithelp.ithome.com.tw/upload/images/20260806/20161290jtFd8HJauZ.png

動態 cost 則像即時路況。當資料量變大、模型額度快用完、或某個外部服務變慢,系統可以把該 action 的成本拉高,讓 planner 自動改走更合適的路。

Embabel 的 GOAP planner 背後可以用 A* 搜尋來理解:它會在可用 action 之間尋找能達成 goal 的低成本路徑。成本不只是錢,也可以是延遲、風險、模型品質、API 穩定性或人工審核負擔。

靜態權重用來表達基本偏好。例如本地 Java 計算便宜且準確,成本低;呼叫大型模型昂貴且慢,成本高。當兩條路都能達成目標,planner 自然會偏向較低成本的路。

進階做法是動態成本。當某個 provider 延遲升高、預算快用完、或某個資料來源暫時不可靠,就把該 action 的 cost 拉高,讓 agent 自動改走備援路徑。這比在流程中塞滿 if-else 更容易維運。

程式碼補充

A* 規劃最值得講的地方,就是成本不是裝飾。你可以讓主路徑便宜、備援路徑昂貴,planner 就會自然偏向正常路徑。

讓 planner 看到靜態成本與動態成本

  • 靜態 cost 表達基本偏好
  • 動態 cost 讀取目前 Blackboard 上的 domain object
  • @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");
    }
}

summarizeFastsummarizeAccurate 的輸入(TravellerActivity)與輸出(ActivitySummary)型別完全相同,因此對 planner 來說它們是兩條殊途同歸的路,cost 就是用來在它們之間排順序的依據:

  • 正常時fastSummarizeCost 算出 0.2 < summarizeAccurate 的 0.7 → planner 走快路。
  • 資料量 > 50fastSummarizeCost 動態拉高到 0.9 > 0.7 → planner 自動改走 summarizeAccurate 備援路。

這就是「正常走快路、異常走備援」的具體實作,也讓靜態 cost(基本偏好)與動態 cost(即時路況)真正影響到決策。

這裡還要特別注意:costMethod 不是隨便指定一個方法名而已。fastSummarizeCost 讀的是 TravellerActivity,因此它適合掛在同樣依賴 TravellerActivitysummarizeFast(...) action 上。若把它掛到 approve(OfferDraft draft, OfferPolicy policy),成本方法讀取的物件和 action 的語意就會錯開,讀者會誤以為 approve 的成本取決於另一個資料集。

今日實作 / 思考任務

為你的 action 表補上 cost 欄位,至少設計一個『正常時走快路、異常時走備援』的動態成本規則。


如果你也想進一步學習如何透過 AI 開發 Spring Framework 應用,讓 AI 協助理解框架、撰寫程式、除錯與驗>證,歡迎到 Hahow 看凱文大叔的最新課程【駕馭 AI 的全端實戰養成班:從零打造企業級智慧應用系統】。一起>學習如何駕馭 AI,提升 Spring 應用的開發效率與品質。
課程連結


上一篇
Day 05:把工作拆成幾個小步驟
系列文
讓 AI Agent 真的做事:用 Embabel 打造可控、可測試的智慧 Dashboard6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言