在前兩天的內容中,探討了 AI Agent 的概念以及 Semantic Kernel 的 Function Calling 機制,並且討論了並非所有 LLM 應用都需要設計成 Agent。然而,我們也理解到 AI Agent 的強大功能和靈活性是取決於其工具(Tools)設計,特別是在處理複雜任務時的優勢。
前陣子,Anthropic 發表了一篇關於其 AI Agent Tools 的技術文章,分享了他們在設計 Tools 時的經驗和挑戰。本篇就來解讀一下 Anthropic 的Tools實務經驗,並搭配 Semantic Kernel 時應如何對齊這些關鍵。
Anthropic 在其文章中提到,設計 AI Agent 的 Tools 時,歸納出五個核心原則:
精挑細選,量身打造專屬工具
許多開發者誤以為「工具越多越好」,但事實恰恰相反。Anthropic 發現,許多團隊只是單純將現有的 API 功能包裝成工具,但卻沒有考慮這些工具是否真正適合 AI Agent 程式使用。AI Agent 程式與傳統軟體有著根本性的差異。最關鍵的限制就是在於「上下文容量」,AI Agent 程式一次能處理的資訊量是有限的。所以如果工具回傳過多不相關的資訊,就會佔用寶貴的上下文,導致效率低落。
舉例來說,不應該建立一個 list_contacts 工具讓 Agent 程式逐筆檢視所有聯絡人,而是應該設計成 search_contacts 或 message_contact 等更精準的工具。同樣地,與其分別建立 list_users、list_events、create_event 三個獨立工具,倒不如整合成一個 schedule_event 工具,一次處理查詢空檔和安排會議的完整流程。Anthropic 的經驗認為,成功的工具設計應該從少數幾個針對高影響力工作流程的精心設計工具開始,確保每個工具都有清楚明確的用途,避免功能重疊造成 Agent 程式選擇困難。
建立命名空間,避免工具混淆
當 AI Agent 需要處理來自數十個不同來源、數百種工具時,如何讓 Agent 快速找到正確的工具會是一個關鍵挑戰。此時可以利用「命名空間」來發揮重要的作用。透過為相關工具加上共同的前綴,可以有效劃分功能界線。例如,使用 asana_search、jira_search 來區分不同服務的搜尋功能,或者用 asana_projects_search、asana_users_search 來區分同一服務內不同資源的搜尋。
Anthropic 的研究顯示,採用前綴或後綴的命名方案會對工具的使用效果產生顯著的影響,但是不同的大型語言模型會有不同的偏好。因此建議開發者根據自己的評估結果選擇最適合的命名方案。
回傳有意義的上下文資訊
工具的價值不僅僅在於執行功能,更在於提供有用的資訊給模型。一個優秀的工具實作應該向 Agent 回傳「高品質訊號」的資訊。在設計工具回應時,應該優先考慮上下文相關性,而非單純的技術完整性。例如:避免回傳低階技術識別碼如 UUID、具體像素尺寸的圖片網址、MIME 類型等資訊。相對的,應該提供如 name、image_url、file_type 這類更直覺、更能影響 Agent 後續行動的欄位。研究顯示,AI Agent 在處理自然語言描述時的表現遠優於處理難以理解的隨機識別碼。將 UUID 轉換為更具語義意義的描述,能有效減少「幻覺」現象,大幅提升檢索任務的精確度。對於需要彈性輸出格式的情境,可以在工具中加入 response_format 參數,讓代理程式選擇「簡潔」或「詳細」的回應格式。例如,詳細回應包含所有技術 ID 資訊,而簡潔回應只提供核心內容,可節省約三分之一的字元數量。
優化回應內容,提升字元使用效率
除了資訊品質,控制資訊數量也同樣重要。對於可能產生大量內容的工具,Anthropic 建議實作多種策略組合:
精心設計工具描述與規格
對工具描述進行優化是改善工具表現最有效的方法之一。這些描述會直接載入 Agent 的上下文中,共同引導 Agent 做出有效的工具呼叫行為。在撰寫工具描述時,可以想像如何向團隊新成員解釋這個工具。將可能被視為理所當然的專業知識明確化,包括查詢格式、術語定義、資源關係等。透過清楚描述預期的輸入和輸出,並搭配嚴格的資料模型來避免歧義。
輸入參數的命名也要明確具體,例如使用 user_id 而非模糊的 user。值得注意的是,即使是工具描述上的微小改進,也能帶來顯著的效果提升。過去 Claude Sonnet 3.5 在 SWE-bench Verified 評估中達到業界領先表現,正是歸功於對工具描述的精準優化,大幅降低了錯誤率並提高了任務完成度。
根據 Anthropic 五個經驗原則,Semantic Kernel 在設計 AI Agent 的工具時,可以從以下幾個方面進行對齊:
關於第1、3、4 項的原則,我個人認為比較是設計上的思維轉變,從「把所有 API 都包成工具」轉變為「設計專門針對 Agent 使用的工具」。這部分主要是思考如何將多個相關 API 功能整合成一個更高階的工具,並且確保每個工具都有明確的用途。並且針對回傳內容進行優化,確保提供給 Agent 的資訊是有意義的。是對「人」說話,而不是對「機器」說話。所以在本質上的表達上,應該是更偏向「自然語言」而非「技術語言」,這樣才能讓 Agent 更容易理解並做出正確的決策。這也考驗開發者的思維轉變,工程習慣需要調整,不過這裡會有個變因是 Agent 所使用的 LLM 模型,因為不同模型對於內容的理解能力會有差異,所以這部分需要多做測試來驗證。這也符合過去我在開發 Agent 時的經驗,模型能力的差異會直接影響到 Agent 的能力,不管是在調用工具的遵從上還是在內容的解讀上都是。
關於第2 項的命名空間,Semantic Kernel 本身並沒有提供這樣的機制,不過開發者可以自行在工具命名(function name)上加以區分,或者在工具描述中加入相關說明來達到類似的效果。這部分主要是看開發者如何規劃自己的工具集以及如何讓 Agent 更容易找到正確的工具。例如:
// 查詢訂單狀態的方法
[KernelFunction]
[Description("Retrieves the order status by order ID.")]
public string Crm_Get_Order_Status(
[Description("The ID of the order to retrieve the status for.")]
string orderId)
{
if (string.IsNullOrWhiteSpace(orderId))
{
return "訂單編號不可為空";
}
if (_orders.TryGetValue(orderId, out var status))
{
return status;
}
else
{
return "查無此訂單";
}
}
Kernel kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(
apiKey: Config.OpenAI_ApiKey,
modelId: Config.ModelId)
.Build();
// ✅ 數據分析師 Agent 專注於數據工具
kernel.Plugins.AddFromType<DataAnalysisPlugin>();
kernel.Plugins.AddFromType<CommonToolsPlugin>();
Kernel kernel = Kernel.CreateBuilder()
.AddOpenAIChatCompletion(
apiKey: Config.OpenAI_ApiKey,
modelId: Config.ModelId)
.Build();
// ❌ 掛載所有 Plugins,造成選擇困難
kernel.Plugins.AddFromType<CustomerServicePlugin>();
kernel.Plugins.AddFromType<SalesPlugin>();
kernel.Plugins.AddFromType<ProjectManagementPlugin>();
kernel.Plugins.AddFromType<DataAnalysisPlugin>();
kernel.Plugins.AddFromType<CommonToolsPlugin>();
[KernelFunction]
[Description("Retrieves the order status by order ID.")]
public string Crm_Get_Order_Status(
[Description("The ID of the order to retrieve the status for.")]
string orderId)
{
if (string.IsNullOrWhiteSpace(orderId))
{
return "訂單編號不可為空";
}
if (_orders.TryGetValue(orderId, out var status))
{
return status;
}
else
{
return "查無此訂單";
}
}
透過上述分析,我們可以看到 Semantic Kernel 在設計 AI Agent 工具時,能夠很好的對齊 Anthropic 所提出的五個核心原則。這些原則不僅有助於提升工具的有效性和效率,也能幫助開發者打造更強大、更靈活的 AI Agent 解決方案。