🛠️ 第十二章:Custom Tools 打造專屬武器 (讓 AI 長出手腳)

在上一章的實戰中,我們用 CrewAI 打造了一個包含「研究員」和「撰稿人」的虛擬團隊。 我們給了研究員一把公版的武器:SerperDevTool (Google 搜尋工具),讓它可以自己去網路上查資料。

但是,在真實的商業場景中,最有價值的資料從來不在 Google 上,而是在你公司的內部資料庫裡! 如果老闆叫 AI 寫一份「上個月被客訴最多的露營地排行榜分析」,AI 用 Google 搜尋是搜不到的。 你必須給 AI 一把「鑰匙」,教它如何打開公司的 Supabase 資料庫,把客訴紀錄撈出來看。

這堂大師級實戰課,我們將帶你進入 Agentic AI 最核心的領域:自訂工具 (Custom Tools)。 我們將教你如何把普通的 Python 函數,包裝成 AI 看得懂、而且「會自己決定什麼時候拿出來用」的超級武器!


🔧 實戰 1:破除迷思,什麼是 AI 的 Tool?

很多工程師以為,所謂的 Tool 就是寫一個 API 讓前端呼叫。完全不是這樣。 在 CrewAI (與 LangChain) 的生態系中,一個 Tool 必須具備兩個靈魂:

  1. 執行邏輯 (Python Code):當 AI 決定使用這個工具時,實際執行的程式碼。
  2. 使用說明書 (Docstring 與 Type Hint):這最重要!這是寫給 AI 大腦看的文字,告訴它「這個工具是幹嘛的」、「傳進來的參數必須是什麼格式」。

💡 Vibe Prompt 實戰 1:最基礎的計算機工具

大語言模型數學很爛(因為它們是靠機率猜字的)。如果你問它 345 乘以 678,它可能會亂猜一個數字。 我們來為 AI 裝備一台絕對不會算錯的計算機。

[!IMPORTANT] 請複製以下 Prompt 傳送給 AI:

我正在開發 CrewAI 系統,需要一個自訂工具 (Custom Tool) 讓 Agent 可以精準計算數學。 請幫我用 @tool 裝飾器寫一個 Python 函數 calculate_math(expression: str)。 需求: 1. 匯入 from langchain.tools import tool。 2. 使用 Python 的 eval() 來計算傳入的數學表達式 (expression)。 3. 請務必加上極度詳盡的 docstring,告訴 AI 什麼時候該用這個工具。 4. 加入 try-except 防止算式格式錯誤導致崩潰。

🤖 AI 的神級運算外掛:

from langchain.tools import tool

# @tool 裝飾器是魔法的關鍵,它會把這個普通的函數轉換成 AI 工具物件
@tool("數學計算大師工具")
def calculate_math(expression: str) -> str:
    """
    這是一個強大的數學計算機。
    大語言模型 (也就是你) 有時在進行複雜數學運算時會出錯。
    當任務中包含任何需要精確計算的數學問題 (例如:加減乘除、百分比計算、總和計算) 時,
    請「務必」使用這個工具來獲得正確答案,不要自己猜測。
    
    參數 'expression' 必須是合法的 Python 數學字串。
    範例輸入:"2500 * 0.15" 或 "(1200 + 800) / 4"
    """
    try:
        # 使用 eval 安全地計算數學字串
        # (在實戰中,為了絕對安全,我們會用更嚴謹的數學解析庫,但這裡先求簡單展示)
        result = eval(expression)
        return f"算式 '{expression}' 的計算結果為:{result}"
    except Exception as e:
        return f"計算發生錯誤,請檢查算式格式。錯誤細節:{str(e)}"

🔍 深度解析: 注意到了嗎?這段程式碼最長的部分是那段 """...""" (Docstring)。 如果你不寫這段,AI 拿到這個工具會滿頭問號,它不知道什麼時候該用。 但加上了那段警告(「請務必使用這個工具,不要自己猜測」),AI 在撰寫商業報告遇到折扣計算時,就會非常乖巧地停下來,呼叫 calculate_math("3999 * 0.8"),拿到 3199.2 之後,再繼續寫文章。這就是防呆的最高境界!


🗄️ 實戰 2:讓 AI 自己去翻 Supabase 資料庫

現在我們進入商業實戰。我們要寫一個工具,讓 AI 可以撈出特定營地的「即時庫存剩餘數量」。

💡 Vibe Prompt 實戰 2:打造資料庫查詢工具

[!IMPORTANT] 請複製以下 Prompt 傳送給 AI:

請幫我寫一個 CrewAI 的自訂工具:check_camp_vacancy(camp_id: str)。 需求: 1. 使用 supabase-py 連線到 Supabase (假設客戶端變數為 supabase_client)。 2. 去 "camps" 資料表中查詢 id 等於 camp_id 的欄位 "vacancy_count"。 3. 如果找不到,回傳 "查無此營地"。 4. 請寫上完整的 docstring,告訴 AI 傳入的 camp_id 必須是 UUID 格式。

🤖 AI 的資料庫直連通道:

import os
from langchain.tools import tool
from supabase import create_client

# 初始化連線
supabase_client = create_client(os.getenv("SUPABASE_URL"), os.getenv("SUPABASE_KEY"))

@tool("營地空位查詢系統")
def check_camp_vacancy(camp_id: str) -> str:
    """
    這是一個用來查詢露營地即時剩餘空位數量的內部資料庫工具。
    當客戶或任務需要確認某個營地「是否還有位子」、「剩幾個空位」時,請呼叫此工具。
    
    參數 'camp_id' 必須是營地的唯一識別碼 (通常是一長串英文數字組合,例如 'a1b2-c3d4...')。
    請不要傳入營地的中文名稱!如果你只知道中文名稱,請先使用其他搜尋工具找出它的 ID。
    """
    print(f"🕵️‍♂️ [系統日誌] AI 正在查詢資料庫,目標營地 ID: {camp_id}")
    try:
        response = supabase_client.table("camps").select("name, vacancy_count").eq("id", camp_id).execute()
        
        # 判斷是否有抓到資料
        if len(response.data) > 0:
            camp_info = response.data[0]
            return f"營地『{camp_info['name']}』目前剩餘空位:{camp_info['vacancy_count']} 帳。"
        else:
            return f"錯誤:資料庫中找不到 ID 為 {camp_id} 的營地。"
            
    except Exception as e:
        return f"資料庫連線發生異常:{str(e)}"

📧 實戰 3:讓 AI 擁有發送 Email 的權力 (Action Tools)

上面的工具都是「讀取 (Read)」,相對安全。 但如果你的 AI 員工是「自動行銷大師」,我們希望他在寫完促銷文章後,直接「自己寄信」給客戶呢? 這叫做 Action (動作執行) 工具。這種工具非常強大,但也極度危險!

💡 Vibe Prompt 實戰 3:打造 Email 發送按鈕

[!IMPORTANT] 請複製以下 Prompt 傳送給 AI:

我需要一個自訂工具 send_marketing_email(recipient_email: str, subject: str, content: str)。 這個工具用來讓 AI 可以自己寄送行銷信件。 為了展示概念,我們不需要真實的 SMTP 寄信程式碼,請用 print() 模擬寄信過程即可。 重點在於:請在 docstring 中嚴格警告 AI,在寄信之前,必須確保內容沒有攻擊性,且主旨必須吸引人。 請給我完整的程式碼。

🤖 AI 的全自動發信機:

from langchain.tools import tool

@tool("自動化 Email 寄發系統")
def send_marketing_email(recipient_email: str, subject: str, content: str) -> str:
    """
    這是一個用來對外發送真實 Email 的危險工具!一旦呼叫,信件將立刻發出且無法收回。
    
    當你完成了行銷文案的撰寫,並且被指示要「發送給客戶」時,請使用此工具。
    參數說明:
    - recipient_email: 目標客戶的 Email 信箱 (必須是正確的信箱格式)。
    - subject: 信件主旨。請確保主旨極度吸引人,且不能有錯字。
    - content: 信件內文 (支援純文字或 HTML 格式)。
    
    【警告】:發送前請確保你已經仔細檢查過 content,不可包含任何捏造的促銷代碼或不實的價格承諾!
    """
    
    # 這裡可以用 smtplib 或第三方服務如 SendGrid 來實作真實寄信
    print("\n" + "="*50)
    print("🚨 [行動警告] AI 觸發了真實世界的操作!")
    print(f"📧 正在寄信給: {recipient_email}")
    print(f"📌 主旨: {subject}")
    print(f"📝 內文預覽: {content[:50]}...")
    print("="*50 + "\n")
    
    return f"系統回報:信件 '{subject}' 已成功送達至 {recipient_email}。"

🎭 實戰 4:多工具組合技,讓 AI 成為超人

我們現在有了三個工具:計算機、資料庫查詢、寄信機。 現在我們要把它們全部武裝到一個 Agent 身上,看看會發生什麼驚人的化學反應。

💡 Vibe Prompt 實戰 4:武裝全能傭兵並發布複雜任務

[!IMPORTANT] 請複製以下 Prompt 傳送給 AI:

請幫我整合剛才的三個工具 (calculate_math, check_camp_vacancy, send_marketing_email)。 1. 建立一個超級 Agent (Sales & Marketing Exec),把這三個工具都掛到 tools=[] 裡面。 2. 建立一個極度複雜的 Task,情境如下: "老闆要求你推銷 ID 為 'camp-123' 的營地給 VIP 客戶 vip@example.com。" "你必須先去查這個營地剩幾個位子。" "如果還有位子,請算出包場(假設每帳 1200 元)打 8 折的總價格。" "最後,把這些資訊寫成一封極度熱情的 Email,並用工具發送給他。" 請給我整合這一切的 CrewAI 執行腳本。

🤖 AI 的終極自動化演繹:

from crewai import Agent, Task, Crew, Process

# 1. 建立配備三把神兵利器的超級銷售員
super_sales = Agent(
    role='頂級銷售與行銷總監',
    goal='利用數據與精確的計算,向 VIP 客戶發送無法拒絕的推銷信件。',
    backstory='你是一個冷靜、邏輯嚴密,但文筆充滿煽動性的頂級銷售員。你絕不犯錯,做事一定先查證資料庫。',
    verbose=True,
    # 🔥 全副武裝!
    tools=[check_camp_vacancy, calculate_math, send_marketing_email]
)

# 2. 下達超級複雜、需要多步驟推理的任務
vip_sales_task = Task(
    description=(
        "這是一項緊急的高階銷售任務!\n"
        "1. 請先查詢營地 ID 為 'camp-123' 的剩餘空位。\n"
        "2. 假設我們一個營位收費 1200 元。請計算:如果客戶把剩下的位子『全部包場』,並且我們給他 8 折 (0.8) 優惠,總金額會是多少?\n"
        "3. 請把『剩餘數量』與『打折後的總價格』,寫成一封熱情、尊榮的 VIP 邀請信。\n"
        "4. 信件對象為 'vip@example.com'。\n"
        "5. 最後,請執行發送動作。"
    ),
    expected_output="寄送完成後,請回報你寄出的信件主旨與總價格。",
    agent=super_sales
)

# 3. 啟動總部!
sales_crew = Crew(
    agents=[super_sales],
    tasks=[vip_sales_task],
    process=Process.sequential,
    verbose=True
)

print("🚀 啟動超級銷售員,準備見證奇蹟...")
# 注意:為了讓這段程式碼順利跑,你需要去 mock(模擬) Supabase 工具的回傳,否則他查不到 camp-123 會報錯
sales_crew.kickoff()

🔍 深度解析 (終端機將會發生的事): 當你按下執行後,你會看到 AI 大腦 (super_sales) 的思考過程 (Thought Process),這段對話價值百萬:

  1. Thought: 我需要先知道 camp-123 剩幾個位子。 Action: 呼叫 check_camp_vacancy('camp-123') Observation: 營地『星空部落』目前剩餘空位:15 帳。
  2. Thought: 好的,有 15 個位子。一個位子 1200 元,包場打 8 折。我必須算出總價。 Action: 呼叫 calculate_math('15 * 1200 * 0.8') Observation: 計算結果為:14400.0
  3. Thought: 數據齊全了!我現在要寫一封信,並發送出去。 Action: 呼叫 send_marketing_email('vip@example.com', '【尊榮 VIP 限時專案】星空部落 15 帳極致包場優惠', '親愛的 VIP... 總包場特惠只要 14,400 元...') Observation: 系統回報:信件已成功送達。

這就是 Agentic Workflow 的極致! 它不再是死板的一問一答,它學會了「推理」、「規劃」、「呼叫工具修正數據」、「執行最終動作」。你等於在電腦裡養了一個完全自動化的行銷部門!


✅ 本章總結與終極架構心法

在這個高達 6000 字的自訂工具實戰中,我們打破了大語言模型最致命的「知識盲區」與「數學白痴」限制。

回顧我們打造超級大腦的關鍵:

  1. @tool 裝飾器:將普通的 Python API 轉化為 AI 的武器庫。
  2. Docstring (說明書):這是靈魂!不寫清楚參數規則與使用時機,AI 就會亂用工具導致系統崩潰。
  3. 資料庫連線 (Supabase):讓 AI 能夠看到公司最機密的即時數據庫,這使得 AI 的商業價值翻了 100 倍。
  4. Action 動作執行 (Email/Line推播):讓 AI 長出手腳,可以直接把價值傳遞給客戶。

⚠️ 【危險警告:Human-in-the-Loop】 當你的 AI 擁有了 send_marketing_email 或是 process_credit_card_refund (退款工具) 時,絕對不能讓它全自動運行! 如果 AI 突然發瘋(幻覺),決定把全公司的商品通通打 1 折發信賣給客戶,公司會瞬間倒閉。 在真實業界,我們會在危險工具前加上 「人類審批 (Human-in-the-Loop)」 機制:AI 寫好信後,必須先傳到老闆的 Line 上,老闆按下「同意」,API 才會真的把信寄出。

這就完美的自動化閉環! 下一章:第十三章:Automated Marketing:結合所有專案的終極行銷機器人,我們將把這堂課所有的精華結合起來,實作一個能自己找圖、自己寫文案、自己發佈的自動化印鈔機。我們下堂課見!

解鎖完整教學內容

本章為付費內容。加入專案即可解鎖超過 5000 字的深度解析,包含 10 個以上神級 Prompt 與真實 Source Code 範例!