Pydantic AI Function Tools 與內建工具

如果只有單純的文字對話能力,AI 代理人的用途其實相當受限。要讓代理人成為真正解決問題的得力助手,你必須賦予它「行動」的能力——也就是讓 AI 能夠呼叫我們預先寫好的 Python 函數 (Functions)。

在 Pydantic AI 中,這個機制被稱為 Function Tools

什麼是 Function Tools?

Function Tools 允許你將任意的 Python 函數暴露給 AI 模型。運作原理如下:

  1. 你寫了一個 Python 函數,並加上了型別提示 (Type Hints) 與 Docstring (函數說明)。
  2. 透過 Pydantic AI 的裝飾器將這個函數註冊為代理人的工具。
  3. 框架會讀取該函數的名稱、說明以及參數型別,轉換成 JSON Schema 並傳遞給 AI。
  4. 當 AI 認為它需要這個函數的幫助來回答問題時,它會生成一組符合 Schema 的參數。
  5. 框架自動在本地端執行這個 Python 函數,並將回傳的結果再丟回給 AI。
  6. AI 根據函數的回傳結果,組合出最終的答案給你。

如何註冊工具

在 Pydantic AI 中,最簡單的註冊工具方式是使用 @agent.tool@agent.tool_plain 裝飾器。

使用 @agent.tool_plain (無依賴注入)

如果你的工具函數不需要存取任何外部依賴或執行環境的狀態,可以使用 @agent.tool_plain

from pydantic_ai import Agent

# 建立一個 Agent
agent = Agent('openai:gpt-4o-mini')

# 透過 @agent.tool_plain 裝飾器註冊一個純函數工具
# 強烈建議提供清晰的 Docstring,這會變成模型理解該工具用途的說明書
@agent.tool_plain
def calculate_bmi(height_cm: float, weight_kg: float) -> float:
    """
    計算使用者的 BMI (身體質量指數)。

    Args:
        height_cm: 身高 (單位:公分)
        weight_kg: 體重 (單位:公斤)
    """
    height_m = height_cm / 100
    bmi = weight_kg / (height_m ** 2)
    # 簡化到小數點後兩位
    return round(bmi, 2)

# 執行 Agent 時,如果它判斷需要計算 BMI,它就會自動呼叫這個函數
result = agent.run_sync("我身高 175 公分,體重 70 公斤,請問我的 BMI 是多少?健康嗎?")
print(result.data)

在上述過程中,你不需要手動處理字串解析或是呼叫函數,Pydantic AI 已經幫你處理好所有底層的繁瑣工作。模型會自動根據 height_cmweight_kg 生成對應的數值並觸發函數。

使用 @agent.tool (結合依賴注入)

工具函數經常需要存取外部資源(例如資料庫連線或是 API Token)。這時候,我們可以使用 @agent.tool 並結合 RunContext 來獲取依賴項,同時保持工具函數介面的乾淨。

import httpx
from pydantic_ai import Agent, RunContext

# 定義 Agent 需要一個 httpx.Client 作為依賴
agent = Agent('gemini-1.5-flash', deps_type=httpx.Client)

# 工具函數的第一個參數必須是 RunContext,這不會暴露給 AI 模型
@agent.tool
def get_external_data(ctx: RunContext[httpx.Client], query: str) -> str:
    """根據使用者的 query 查詢外部資料庫。"""

    # 透過 ctx.deps 拿到注入的 HTTP Client 並發送請求
    client = ctx.deps
    response = client.get(f"https://api.example.com/search?q={query}")
    return response.text

框架聰明地知道 RunContext 是給本地程式碼使用的,它不會將這個參數列入提供給 AI 的 Schema 中。對 AI 來說,這個工具就只有一個 query 參數。

工具的錯誤處理與重試 (ModelRetry)

如果工具執行過程中發現參數不合法或遇到預期內的錯誤,你可以拋出 ModelRetry 異常。Pydantic AI 會捕捉這個異常,並將錯誤訊息傳回給模型,要求模型修正參數後再試一次。

from pydantic_ai import Agent, RunContext
from pydantic_ai.exceptions import ModelRetry

agent = Agent('gemini-1.5-flash')

@agent.tool_plain
def fetch_user_profile(user_id: str) -> str:
    """根據 user_id 查詢使用者資料。"""
    if not user_id.startswith("USR-"):
        # 拋出 ModelRetry,模型會收到這個訊息並嘗試修正 user_id 格式
        raise ModelRetry("user_id 格式錯誤,必須以 'USR-' 開頭。請修正後重試。")

    return f"使用者 {user_id} 的資料..."

內建工具與 Capabilities

為了減少重複開發,Pydantic AI 內建了許多常用的工具。在最新的版本中,這些工具通常透過 Capabilities 的形式掛載到 Agent 上。

例如,如果你需要讓 Agent 具備執行 Python 程式碼或是網路搜尋的能力,你可以直接從框架中匯入這些預先封裝好的工具集:

from pydantic_ai import Agent
from pydantic_ai.capabilities import WebSearch
from pydantic_ai.builtin_tools import CodeExecutionTool

agent = Agent(
    'openai:gpt-4o',
    capabilities=[
        # 賦予網路搜尋能力
        WebSearch(),
    ]
)

# 直接掛載內建的程式碼執行工具
@agent.tool_plain
def execute_python(code: str) -> str:
    """執行 Python 程式碼並回傳結果"""
    # 實務上可使用 CodeExecutionTool 等內建工具來安全執行
    pass

給予 Agent 適當的工具,是突破語言模型只能「紙上談兵」限制的關鍵,讓它真正成為具備執行力的 AI 助手。對於更複雜的工具管理與權限控制,請參考下一章節的進階工具教學。