iT邦幫忙

2026 iThome 鐵人賽

DAY 3
0
Vibe Coding

agent工作流系列 第 9

【Day 9】怎麼應用 Tool Calling Engineering:自訂工具註冊、平行調用與異常容錯實戰

  • 分享至 

  • xImage
  •  

在昨天的文章中,我們建立了Tool Calling的核心認知——LLM 本身不執行程式,而是透過Tool Schema充當「決策與參數生成大腦」,再由外部Python環境完成執行並將結果回傳閉環

今天我們進入實戰篇:在實際開發中,我們該如何使用LangChain / Python 定義自訂工具、處理多工具平行調用(Parallel Tool Calling),並建立強健的工具異常容錯機制?


一、實戰場景:電商智慧客服的工具箱設計

假設我們要為客服Agent配備兩個核心工具:

  1. query_inventory(查詢庫存):輸入商品名稱,查詢當前各倉庫庫存量
  2. calculate_shipping_fee(計算運費):輸入會員等級與配送區域,計算運費

當使用者詢問:「我是 VIP 會員,想寄台北,另外幫我查一下降噪耳機跟機械鍵盤有沒有現貨?」模型應該能一次平行發起多個工具調用,並整合回傳


二、核心實作 1:使用 @tool 裝飾器定義型別安全工具

在LangChain中,定義工具的最佳實踐是結合Python Type Hints與Docstring
框架會自動將其轉譯為標準的JSON Schema

from langchain_core.tools import tool
from typing import Literal

@tool
def query_inventory(item_name: str) -> str:
    """根據商品名稱查詢倉庫目前的即時庫存量。
    
    Args:
        item_name: 商品完整名稱或關鍵字,例如 '降噪耳機' 或 '機械鍵盤'
    """
    # 模擬資料庫庫存查詢邏輯
    inventory_db = {
        "降噪耳機": 12,
        "機械鍵盤": 0,
        "無線滑鼠": 45
    }
    stock = inventory_db.get(item_name)
    if stock is not None:
        return f"商品【{item_name}】目前庫存量為: {stock} 件。"
    return f"查無商品【{item_name}】的庫存記錄。"

@tool
def calculate_shipping_fee(
    destination: Literal["台北", "台中", "高雄", "離島"], 
    membership_tier: Literal["NORMAL", "VIP", "VVIP"]
) -> str:
    """計算特定目的地與會員等級的配送運費。
    
    Args:
        destination: 配送目的地城市
        membership_tier: 用戶會員等級
    """
    if membership_tier in ["VIP", "VVIP"]:
        return f"會員等級為 {membership_tier},享有全台免運優惠,運費為 0 元。"
    
    fee_map = {"台北": 60, "台中": 80, "高雄": 80, "離島": 150}
    fee = fee_map.get(destination, 100)
    return f"配送至【{destination}】,一般會員運費為 {fee} 元。"

# 註冊可用工具清單
tools = [query_inventory, calculate_shipping_fee]

三、核心實作 2:模型綁定與平行工具調用(Parallel Tool Calling)

現代主流模型(如 GPT-4o 系列)支援平行工具調用
當單次提問包含多個查詢需求時,模型會在單一回應中一次輸出多組 tool_calls

import json
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, ToolMessage

# 1. 初始化模型並綁定工具清單
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.0)
llm_with_tools = llm.bind_tools(tools)

# 2. 用戶提出複合型問題
messages = [
    HumanMessage(content="我是 VIP 會員,想寄台北,另外幫我查一下降噪耳機跟機械鍵盤有沒有現貨?")
]

# 3. LLM 進行推理並發出工具調用決策
ai_msg = llm_with_tools.invoke(messages)
messages.append(ai_msg)

# 印出模型生成的工具調用清單 (將看到 3 個平行呼叫)
print(f"模型生成的工具調用數量: {len(ai_msg.tool_calls)}")
for call in ai_msg.tool_calls:
    print(f"- 預計調用: {call['name']} | 參數: {call['args']}")

輸出範例:

模型生成的工具調用數量: 3
- 預計調用: calculate_shipping_fee | 參數: {'destination': '台北', 'membership_tier': 'VIP'}
- 預計調用: query_inventory | 參數: {'item_name': '降噪耳機'}
- 預計調用: query_inventory | 參數: {'item_name': '機械鍵盤'}

四、核心實作 3:執行工具與異常容錯管線(Error Handling Loop)

在執行工具時,API逾時、參數型別異常或資料庫斷線是常態
千萬不要讓Python直接拋出Exception中斷程式,應將錯誤轉化為 ToolMessage 餵回模型,讓模型具備自我修正或委婉告知使用者的機會

# 建立工具名稱對應字典
tools_by_name = {tool.name: tool for tool in tools}

# 4. 本地環境依序/並行執行工具,並進行異常攔截
for tool_call in ai_msg.tool_calls:
    tool_name = tool_call["name"]
    tool_args = tool_call["args"]
    tool_id = tool_call["id"]
    
    try:
        # 動態查找並執行工具
        selected_tool = tools_by_name.get(tool_name)
        if not selected_tool:
            raise ValueError(f"未知的工具名稱: {tool_name}")
            
        tool_output = selected_tool.invoke(tool_args)
    except Exception as e:
        # 異常攔截:將錯誤格式化為工具回傳訊息,防止系統崩潰
        tool_output = f"工具執行失敗 (錯誤原因: {str(e)}),請嘗試調整參數或提示用戶。"
    
    # 5. 包裝成 ToolMessage 寫回上下文
    messages.append(
        ToolMessage(
            content=str(tool_output),
            tool_call_id=tool_id
        )
    )

# 6. 將工具執行結果餵回 LLM,產生最終自然語言回覆
final_response = llm_with_tools.invoke(messages)
print("\n最終回答:")
print(final_response.content)

最終模型整合回傳範例:

您好!為您查詢到相關資訊如下:

  1. 運費資訊:您身為 VIP 會員,寄送至台北享有免運優惠(運費 0 元)
  2. 商品庫存
    • 降噪耳機:目前現貨剩餘 12 件
    • 機械鍵盤:目前已無現貨(庫存為 0 件)

五、生產級 Tool Calling 工程檢驗清單

在將Tool Calling上線至生產環境前,請務必完成以下檢查:

檢驗維度 潛在風險 最佳工程實踐
Docstring 描述 模型不知道何時觸發工具 明確撰寫「在何種條件下應調用」,並給出典型參數範例
參數嚴格驗證 模型傳入非法型別或自創字串 使用 Pydantic 或 Literal 限制枚舉值,啟用型別驗證
超時與重試 外部 API 延遲拖垮整條對話鏈 為每個 Tool 呼叫設定 Strict Timeout(如 3 秒),並限制重試次數
敏感權限確認 Agent 未經確認直接執行危險操作(如扣款、刪除) 引入 Human-in-the-Loop(人機協同審查) 機制攔截關鍵操作

小結與下集預告

透過自訂Tool Schema、平行調用處理與異常防禦管線,我們成功讓LLM擁有了與外部世界精準互動的能力

然而,當系統需求變得更加複雜——例如需要先查詢資料、經由人工審批、再依據結果分流到不同子任務時,單純的線性Tool Calling迴圈將難以應付。我們需要更具表達力的工作流狀態機(State Machine)

明天 【Day 10】甚麼是 LangGraph,我們將正式邁向進階Agent框架,探討現代AI工作流如何利用「圖(Graph)結構」來精確控制多步驟與分支決策!


上一篇
【Day 8】甚麼是 Tool Calling Engineering:賦予LLM連結真實世界的手與腳
下一篇
【Day 10】甚麼是 LangGraph:從線性鏈路邁向循環狀態圖的 Agent 架構
系列文
agent工作流15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言