ai-agents-for-beginners

如何設計優秀的 AI 代理

(點擊上方圖片觀看本課程影片)

工具使用設計模式

工具很有趣,因為它們讓 AI 代理擁有更廣泛的能力範圍。代理不再只有有限的行動集,而是通過添加工具,代理現在可以執行各種不同的行動。在本章節中,我們將探討工具使用設計模式,描述 AI 代理如何使用特定工具來達成其目標。

簡介

在本課程中,我們希望回答以下問題:

學習目標

完成本課程後,你將能夠:

什麼是工具使用設計模式?

工具使用設計模式專注於賦予大型語言模型(LLM)與外部工具進行互動的能力,以達成特定目標。工具是代理可以執行的程式碼,能完成各種動作。工具可以是簡單的函式,例如計算器,或呼叫第三方服務的 API,如股價查詢或天氣預報。在 AI 代理的情境中,工具設計為由代理根據模型產生的函式呼叫來執行。

它可以應用於哪些使用案例?

AI 代理可利用工具完成複雜任務、擷取資訊或做出決策。工具使用設計模式常用於需要動態與外部系統互動的場景,如資料庫、網路服務或程式碼解譯器。這項能力適用於多種不同使用案例,包括:

實作工具使用設計模式所需的元素/建構模組是什麼?

這些建構模組讓 AI 代理能執行各種任務。以下是實作工具使用設計模式所需的關鍵元素:

接下來,我們將更詳細探討函式/工具呼叫。

函式/工具呼叫

函式呼叫是讓大型語言模型(LLMs)與工具互動的主要方式。你會發現「函式」和「工具」常被交替使用,因為「函式」(可重複使用的程式碼區塊)就是代理用來完成任務的「工具」。要調用函式的程式碼,LLM 必須依照使用者請求,與函式描述進行匹配。為此,會傳送一個包含所有可用函式描述的結構描述(schema)給 LLM。LLM 隨後會選擇最合適的函式,並返回其名稱及參數。該函式被調用後,回應被送回 LLM,LLM 利用該資訊來回應使用者請求。

開發者實作代理的函式呼叫功能,需具備:

  1. 支援函式呼叫的 LLM 模型
  2. 包含函式描述的結構描述(schema)
  3. 每個函式對應的程式碼

讓我們以取得某城市目前時間為例說明:

  1. 初始化支援函式呼叫的 LLM:

    並非所有模型都支援函式呼叫,因此確定所使用的 LLM 有此功能很重要。Azure OpenAI 支援函式呼叫。我們可以先啟動 Azure OpenAI 用戶端。

     # 初始化 Azure OpenAI 用戶端
     client = AzureOpenAI(
         azure_endpoint = os.getenv("AZURE_AI_PROJECT_ENDPOINT"), 
         api_key=os.getenv("AZURE_OPENAI_API_KEY"),  
         api_version="2024-05-01-preview"
     )
    
  2. 建立函式結構描述(Schema):

    接著我們會定義一個 JSON 結構描述,包含函式名稱、函式功能描述,以及函式參數的名稱和描述。 然後將此結構描述與使用者想取得舊金山時間的請求一併傳給前面創建的用戶端。值得注意的是,返回的是工具呼叫不是問題的最終答案。如前所述,LLM 回傳它為任務選擇的函式名稱及會傳給該函式的參數。

     # 供模型閱讀的功能描述
     tools = [
         {
             "type": "function",
             "function": {
                 "name": "get_current_time",
                 "description": "Get the current time in a given location",
                 "parameters": {
                     "type": "object",
                     "properties": {
                         "location": {
                             "type": "string",
                             "description": "The city name, e.g. San Francisco",
                         },
                     },
                     "required": ["location"],
                 },
             }
         }
     ]
    
      
     # 初始用戶訊息
     messages = [{"role": "user", "content": "What's the current time in San Francisco"}] 
      
     # 第一次 API 調用:請模型使用該功能
       response = client.chat.completions.create(
           model=deployment_name,
           messages=messages,
           tools=tools,
           tool_choice="auto",
       )
      
       # 處理模型的回應
       response_message = response.choices[0].message
       messages.append(response_message)
      
       print("Model's response:")  
    
       print(response_message)
      
    
     Model's response:
     ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_pOsKdUlqvdyttYB67MOj434b', function=Function(arguments='{"location":"San Francisco"}', name='get_current_time'), type='function')])
    
  3. 執行工作所需的函式程式碼:

    LLM 選定需要執行的函式後,必須實作並執行該函式程式碼以完成任務。 我們可以用 Python 實作取得當前時間的程式碼。還需撰寫從 response_message 中擷取函式名稱及參數的程式碼,以取得最終結果。

       def get_current_time(location):
         """Get the current time for a given location"""
         print(f"get_current_time called with location: {location}")  
         location_lower = location.lower()
            
         for key, timezone in TIMEZONE_DATA.items():
             if key in location_lower:
                 print(f"Timezone found for {key}")  
                 current_time = datetime.now(ZoneInfo(timezone)).strftime("%I:%M %p")
                 return json.dumps({
                     "location": location,
                     "current_time": current_time
                 })
          
         print(f"No timezone data found for {location_lower}")  
         return json.dumps({"location": location, "current_time": "unknown"})
    
      # 處理函數調用
       if response_message.tool_calls:
           for tool_call in response_message.tool_calls:
               if tool_call.function.name == "get_current_time":
         
                   function_args = json.loads(tool_call.function.arguments)
         
                   time_response = get_current_time(
                       location=function_args.get("location")
                   )
         
                   messages.append({
                       "tool_call_id": tool_call.id,
                       "role": "tool",
                       "name": "get_current_time",
                       "content": time_response,
                   })
       else:
           print("No tool calls were made by the model.")  
      
       # 第二次 API 調用:從模型獲取最終回應
       final_response = client.chat.completions.create(
           model=deployment_name,
           messages=messages,
       )
      
       return final_response.choices[0].message.content
    
       get_current_time called with location: San Francisco
       Timezone found for san francisco
       The current time in San Francisco is 09:24 AM.
    

函式呼叫是大多數(若非全部)代理工具使用設計的核心,但自行從頭實作有時具有挑戰性。 正如我們在課程 2所學,代理框架提供了預建的建構模組,方便實作工具使用。

使用代理框架的工具使用範例

以下示範如何使用不同代理框架來實作工具使用設計模式:

Microsoft Agent Framework

Microsoft Agent Framework 是一個開源 AI 框架,用於創建 AI 代理。它簡化了函式呼叫的流程,允許你使用 @tool 裝飾器將工具定義為 Python 函式。框架負責模型與程式碼之間的雙向通信,並提供對預建工具(如檔案搜尋和程式碼解釋器)的存取,藉由 AzureAIProjectAgentProvider

下圖說明了 Microsoft Agent Framework 中函式呼叫的流程:

function calling

在 Microsoft Agent Framework 中,工具以被裝飾的函式定義。我們可以用 @tool 裝飾器將先前的 get_current_time 函式轉成工具。框架會自動序列化函式及其參數,產生送給 LLM 的結構描述。

from agent_framework import tool
from agent_framework.azure import AzureAIProjectAgentProvider
from azure.identity import AzureCliCredential

@tool
def get_current_time(location: str) -> str:
    """Get the current time for a given location"""
    ...

# 建立客戶端
provider = AzureAIProjectAgentProvider(credential=AzureCliCredential())

# 建立一個代理並使用工具運行
agent = await provider.create_agent(name="TimeAgent", instructions="Use available tools to answer questions.", tools=get_current_time)
response = await agent.run("What time is it?")

Azure AI Agent Service

Azure AI Agent Service 是較新的代理框架,旨在使開發者能安全地建立、部署並擴充高品質且可擴展的 AI 代理,而無需管理底層的計算和存儲資源。它特別適合企業應用,因為該服務是全方位管理且具企業級安全性的服務。

相較於直接使用 LLM API 進行開發,Azure AI Agent Service 提供以下優勢:

Azure AI Agent Service 提供的工具可分為兩大類:

  1. 知識工具:
  2. 行動工具:

Agent Service 允許我們將這些工具作為一個 toolset 一起使用,同時利用 threads 追蹤特定對話的訊息歷史。

假設你是名為 Contoso 公司的銷售代理,你想開發一個會話代理,回答銷售資料相關問題。

以下圖片示範如何利用 Azure AI Agent Service 分析銷售資料:

Agentic Service In Action

若要使用這些服務中的工具,可以建立用戶端並定義工具或工具集。以下 Python 程式碼示範了實作方式。LLM 將能夠根據使用者請求,選擇使用使用者自創函式 fetch_sales_data_using_sqlite_query 或內建的程式碼解譯器。

import os
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential
from fetch_sales_data_functions import fetch_sales_data_using_sqlite_query # fetch_sales_data_using_sqlite_query 函數,可以在 fetch_sales_data_functions.py 文件中找到。
from azure.ai.projects.models import ToolSet, FunctionTool, CodeInterpreterTool

project_client = AIProjectClient.from_connection_string(
    credential=DefaultAzureCredential(),
    conn_str=os.environ["PROJECT_CONNECTION_STRING"],
)

# 初始化工具集合
toolset = ToolSet()

# 使用 fetch_sales_data_using_sqlite_query 函數初始化函數調用代理,並將其添加到工具集合中
fetch_data_function = FunctionTool(fetch_sales_data_using_sqlite_query)
toolset.add(fetch_data_function)

# 初始化代碼解譯器工具並將其添加到工具集合中。
code_interpreter = CodeInterpreterTool()toolset.add(code_interpreter)

agent = project_client.agents.create_agent(
    model="gpt-4o-mini", name="my-agent", instructions="You are helpful agent", 
    toolset=toolset
)

使用工具使用設計模式建立可信賴 AI 代理的特別考量是什麼?

一般來說,LLM 動態生成 SQL 最常見的疑慮是安全性,尤其是 SQL 注入風險或惡意操作(如刪除或竄改資料庫)。這些疑慮雖然合理,但可以透過適當設定資料庫存取權限有效減輕。對大多數資料庫來說,就是將資料庫設定為唯讀。對 PostgreSQL 或 Azure SQL 等資料庫服務,應給應用程式唯讀(SELECT)角色。

在安全環境中執行應用程式會進一步提升保護。在企業情境,資料通常會從作業系統擷取並轉換成具有易用結構的唯讀資料庫或資料倉儲。此做法確保資料安全,優化效能與可存取性,並且限制應用程式只能唯讀存取。

範例程式碼

想了解更多關於工具使用設計模式的問題?

加入 Microsoft Foundry Discord,與其他學習者交流,參加辦公時間並解決你的 AI 代理問題。

其他資源

上一課

理解代理設計模式

下一課

Agentic RAG


免責聲明: 本文件由 AI 翻譯服務 Co-op Translator 翻譯而成。雖然我們致力於確保準確性,但請注意,機器自動翻譯可能包含錯誤或不準確之處。原始文件的母語版本應被視為權威來源。對於重要資訊,建議進行專業人工翻譯。我們不對因使用本翻譯而產生的任何誤解或誤釋承擔責任。