智慧體課程文件

構建使用程式碼的 Agent

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強的文件體驗

開始使用

Ask a Question Open In Colab

構建使用程式碼的 Agent

程式碼 Agent 是 smolagents 中的預設 Agent 型別。它們生成 Python 工具呼叫來執行動作,從而實現高效、富有表現力且準確的動作表示。

它們精簡的方法減少了所需動作的數量,簡化了複雜操作,並實現了對現有程式碼函式的重用。smolagents 為構建程式碼 Agent 提供了一個輕量級框架,程式碼量約 1000 行。

程式碼動作 vs JSON 動作 圖片來自論文 Executable Code Actions Elicit Better LLM Agents

如果你想了解更多關於程式碼 Agent 為何有效的資訊,請查閱 smolagents 文件中的這篇指南

為何選擇程式碼 Agent?

在多步 Agent 流程中,LLM 編寫並執行動作,通常涉及外部工具呼叫。傳統方法使用 JSON 格式指定工具名稱和引數(作為字串),系統必須解析這些資訊才能確定執行哪個工具

然而,研究表明,直接使用程式碼能讓工具呼叫型 LLM 更有效地工作。這是 smolagents 的核心原則,正如上圖所示(該圖來自論文 Executable Code Actions Elicit Better LLM Agents)。

用程式碼而非 JSON 編寫動作有以下幾個關鍵優勢:

  • 可組合性:輕鬆組合和重用動作
  • 物件管理:直接處理複雜結構,如影像
  • 通用性:能夠表達任何計算上可能的任務
  • 對 LLM 更自然:高質量的程式碼已經存在於 LLM 的訓練資料中

程式碼 Agent 如何工作?

From https://huggingface.co/docs/smolagents/conceptual_guides/react

上圖展示了 CodeAgent.run() 的工作方式,它遵循了我們在第一單元中提到的 ReAct 框架。smolagents 中 Agent 的主要抽象是 MultiStepAgent,它是核心構建塊。CodeAgent 是一種特殊的 MultiStepAgent,我們將在下面的例子中看到。

一個 CodeAgent 透過一系列步驟的迴圈來執行動作,現有的變數和知識被整合到 Agent 的上下文中,並儲存在執行日誌中。

  1. 系統提示儲存在 SystemPromptStep 中,使用者查詢則記錄在 TaskStep 中。

  2. 然後,執行以下 while 迴圈:

    2.1 方法 agent.write_memory_to_messages() 將 Agent 的日誌寫入一個 LLM 可讀的聊天訊息列表。

    2.2 這些訊息被髮送給一個 Model,該模型生成一個補全。

    2.3 解析補全以提取動作,在我們的例子中,由於我們使用的是 CodeAgent,這個動作應該是一個程式碼片段。

    2.4 執行該動作。

    2.5 結果被記錄到記憶體中的一個 ActionStep 裡。

在每一步結束時,如果 Agent 包含任何函式呼叫(在 agent.step_callback 中),它們將被執行。

看幾個例子

你可以跟隨這個筆記本中的程式碼,並使用 Google Colab 執行它。

阿福(Alfred)正在韋恩莊園策劃一場派對,他需要你的幫助來確保一切順利進行。為了協助他,我們將運用所學的關於多步 CodeAgent 如何運作的知識。

Alfred Party

如果你還沒有安裝 smolagents,可以執行以下命令進行安裝:

pip install smolagents -U

我們還要登入到 Hugging Face Hub,以便訪問無伺服器推理 API(Serverless Inference API)。

from huggingface_hub import login

login()

使用 smolagents 為派對選擇播放列表

音樂是一場成功派對的重要組成部分!阿福需要一些幫助來選擇播放列表。幸運的是,smolagents 能幫我們解決這個問題!我們可以構建一個能夠使用 DuckDuckGo 在網上搜索的 Agent。為了讓 Agent 能夠使用這個工具,我們在建立 Agent 時將其包含在工具列表中。

Alfred Playlist

對於模型,我們將依賴 InferenceClientModel,它提供了對 Hugging Face 的無伺服器推理 API 的訪問。預設模型是 "Qwen/Qwen2.5-Coder-32B-Instruct",它效能優越且可用於快速推理,但你也可以從 Hub 中選擇任何相容的模型。

執行一個 Agent 非常直接:

from smolagents import CodeAgent, DuckDuckGoSearchTool, InferenceClientModel

agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=InferenceClientModel())

agent.run("Search for the best music recommendations for a party at the Wayne's mansion.")

當你執行這個例子時,輸出將顯示正在執行的工作流步驟的跟蹤資訊。它還會打印出相應的 Python 程式碼以及訊息。

 ─ Executing parsed code: ──────────────────────────────────────────────────────────────────────────────────────── 
  results = web_search(query="best music for a Batman party")                                                      
  print(results)                                                                                                   
 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── 

幾步之後,你就會看到生成的播放列表,阿福可以用它來為派對助興!🎵

使用自定義工具準備選單

Alfred Menu

現在我們已經選好了播放列表,我們需要為客人準備選單。阿福同樣可以利用 smolagents 來完成這項工作。在這裡,我們使用 @tool 裝飾器來定義一個作為工具的自定義函式。我們稍後會更詳細地介紹工具的建立,所以現在,我們只需執行程式碼即可。

正如你在下面的例子中看到的,我們將使用 @tool 裝飾器建立一個工具,並將其包含在 tools 列表中。

from smolagents import CodeAgent, tool, InferenceClientModel

# Tool to suggest a menu based on the occasion
@tool
def suggest_menu(occasion: str) -> str:
    """
    Suggests a menu based on the occasion.
    Args:
        occasion (str): The type of occasion for the party. Allowed values are:
                        - "casual": Menu for casual party.
                        - "formal": Menu for formal party.
                        - "superhero": Menu for superhero party.
                        - "custom": Custom menu.
    """
    if occasion == "casual":
        return "Pizza, snacks, and drinks."
    elif occasion == "formal":
        return "3-course dinner with wine and dessert."
    elif occasion == "superhero":
        return "Buffet with high-energy and healthy food."
    else:
        return "Custom menu for the butler."

# Alfred, the butler, preparing the menu for the party
agent = CodeAgent(tools=[suggest_menu], model=InferenceClientModel())

# Preparing the menu for the party
agent.run("Prepare a formal menu for the party.")

Agent 將會執行幾步直到找到答案。在文件字串中明確允許的值有助於引導 Agent 使用存在的 `occasion` 引數值,並減少幻覺。

選單準備好了!🥗

在 Agent 內部使用 Python 匯入

我們已經準備好了播放列表和選單,但還需要檢查一個至關重要的細節:準備時間!

阿福需要計算一下,如果他現在開始準備,所有東西什麼時候能準備好,以防萬一需要其他超級英雄的幫助。

smolagents 專注於編寫和執行 Python 程式碼片段的 Agent,並提供沙盒執行以確保安全。

程式碼執行有嚴格的安全措施 —— 預設情況下,不在預定義安全列表中的匯入會被阻止。但是,你可以透過在 additional_authorized_imports 中以字串形式傳遞它們來授權額外的匯入。有關安全程式碼執行的更多詳細資訊,請參閱官方指南

在建立 Agent 時,我們將使用 additional_authorized_imports 來允許匯入 datetime 模組。

from smolagents import CodeAgent, InferenceClientModel
import numpy as np
import time
import datetime

agent = CodeAgent(tools=[], model=InferenceClientModel(), additional_authorized_imports=['datetime'])

agent.run(
    """
    Alfred needs to prepare for the party. Here are the tasks:
    1. Prepare the drinks - 30 minutes
    2. Decorate the mansion - 60 minutes
    3. Set up the menu - 45 minutes
    4. Prepare the music and playlist - 45 minutes

    If we start right now, at what time will the party be ready?
    """
)

這些例子只是你能用程式碼 Agent 做的開始,我們已經開始看到它們在準備派對方面的實用性。你可以在 smolagents 文件中瞭解更多關於如何構建程式碼 Agent 的資訊。

總而言之,smolagents 專注於編寫和執行 Python 程式碼片段的 Agent,並提供沙盒執行以確保安全。它同時支援本地和基於 API 的語言模型,使其能夠適應各種開發環境。

將我們的自定義派對準備 Agent 分享到 Hub

如果能把我們自己製作的阿福 Agent 分享給社群,那該多棒啊!這樣一來,任何人都可以輕鬆地從 Hub 下載並直接使用這個 Agent,將哥譚市的終極派對策劃師帶到他們的指尖!讓我們實現它吧!🎉

smolagents 庫使這成為可能,它允許你與社群分享一個完整的 Agent,並下載其他人制作的 Agent 以便立即使用。就像下面這樣簡單:

# Change to your username and repo name
agent.push_to_hub('sergiopaniego/AlfredAgent')

要再次下載這個 Agent,請使用以下程式碼:

# Change to your username and repo name
alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True)

alfred_agent.run("Give me the best playlist for a party at Wayne's mansion. The party idea is a 'villain masquerade' theme")  

更令人興奮的是,分享的 Agent 可以直接作為 Hugging Face Spaces 使用,讓你能夠即時與它們互動。你可以在這裡探索其他 Agent。

例如,AlfredAgent 可以在這裡找到。你可以直接在下方試用它:

你可能想知道——阿福是如何使用 smolagents 構建出這樣一個 Agent 的?透過整合多個工具,他可以像下面這樣生成一個 Agent。現在不用擔心工具的問題,因為本單元后面會有一個專門的部分詳細探討這個問題:

from smolagents import CodeAgent, DuckDuckGoSearchTool, FinalAnswerTool, InferenceClientModel, Tool, tool, VisitWebpageTool

@tool
def suggest_menu(occasion: str) -> str:
    """
    Suggests a menu based on the occasion.
    Args:
        occasion: The type of occasion for the party.
    """
    if occasion == "casual":
        return "Pizza, snacks, and drinks."
    elif occasion == "formal":
        return "3-course dinner with wine and dessert."
    elif occasion == "superhero":
        return "Buffet with high-energy and healthy food."
    else:
        return "Custom menu for the butler."

@tool
def catering_service_tool(query: str) -> str:
    """
    This tool returns the highest-rated catering service in Gotham City.
    
    Args:
        query: A search term for finding catering services.
    """
    # Example list of catering services and their ratings
    services = {
        "Gotham Catering Co.": 4.9,
        "Wayne Manor Catering": 4.8,
        "Gotham City Events": 4.7,
    }
    
    # Find the highest rated catering service (simulating search query filtering)
    best_service = max(services, key=services.get)
    
    return best_service

class SuperheroPartyThemeTool(Tool):
    name = "superhero_party_theme_generator"
    description = """
    This tool suggests creative superhero-themed party ideas based on a category.
    It returns a unique party theme idea."""
    
    inputs = {
        "category": {
            "type": "string",
            "description": "The type of superhero party (e.g., 'classic heroes', 'villain masquerade', 'futuristic Gotham').",
        }
    }
    
    output_type = "string"

    def forward(self, category: str):
        themes = {
            "classic heroes": "Justice League Gala: Guests come dressed as their favorite DC heroes with themed cocktails like 'The Kryptonite Punch'.",
            "villain masquerade": "Gotham Rogues' Ball: A mysterious masquerade where guests dress as classic Batman villains.",
            "futuristic Gotham": "Neo-Gotham Night: A cyberpunk-style party inspired by Batman Beyond, with neon decorations and futuristic gadgets."
        }
        
        return themes.get(category.lower(), "Themed party idea not found. Try 'classic heroes', 'villain masquerade', or 'futuristic Gotham'.")


# Alfred, the butler, preparing the menu for the party
agent = CodeAgent(
    tools=[
        DuckDuckGoSearchTool(), 
        VisitWebpageTool(),
        suggest_menu,
        catering_service_tool,
        SuperheroPartyThemeTool(),
	FinalAnswerTool()
    ], 
    model=InferenceClientModel(),
    max_steps=10,
    verbosity_level=2
)

agent.run("Give me the best playlist for a party at the Wayne's mansion. The party idea is a 'villain masquerade' theme")

如你所見,我們建立了一個帶有多項工具的 CodeAgent,這些工具增強了 Agent 的功能,使其成為終極派對策劃師,並準備好與社群分享!🎉

現在輪到你了:利用我們剛剛學到的知識,構建你自己的 Agent 並與社群分享吧!🕵️‍♂️💡

如果你想分享你的 Agent 專案,可以建立一個 Space 並在 Hugging Face Hub 上標記 agents-course。我們很期待看到你的創作!

使用 OpenTelemetry 和 Langfuse 檢查我們的派對準備 Agent 📡

在阿福微調派對準備 Agent 的過程中,他對除錯執行過程感到越來越厭倦。Agent 天生具有不可預測性,難以檢查。但既然他的目標是構建終極的派對準備 Agent 並將其部署到生產環境中,他需要強大的可追溯性以便未來進行監控和分析。

smolagents 再次挺身而出!它採用了 OpenTelemetry 標準來檢測 Agent 的執行情況,實現了無縫的檢查和日誌記錄。在 LangfuseSmolagentsInstrumentor 的幫助下,阿福可以輕鬆地跟蹤和分析他的 Agent 的行為。

設定過程非常簡單!

首先,我們需要安裝必要的依賴項:

pip install opentelemetry-sdk opentelemetry-exporter-otlp openinference-instrumentation-smolagents langfuse

接下來,阿福已經在 Langfuse 上建立了一個賬戶並準備好了他的 API 金鑰。如果你還沒有這樣做,可以在這裡註冊 Langfuse Cloud,或探索其他替代方案

一旦你有了你的 API 金鑰,需要像下面這樣正確配置它們:

import os

# Get keys for your project from the project settings page: https://cloud.langfuse.com
os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." 
os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." 
os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 EU region
# os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 US region

設定好環境變數後,我們現在可以初始化 Langfuse 客戶端了。get_client() 使用環境變數中提供的憑據來初始化 Langfuse 客戶端。

from langfuse import get_client
 
langfuse = get_client()
 
# Verify connection
if langfuse.auth_check():
    print("Langfuse client is authenticated and ready!")
else:
    print("Authentication failed. Please check your credentials and host.")

最後,阿福準備好初始化 SmolagentsInstrumentor 並開始跟蹤他的 Agent 的效能了。

from openinference.instrumentation.smolagents import SmolagentsInstrumentor

SmolagentsInstrumentor().instrument()

阿福現在連線上了 🔌!來自 smolagents 的執行記錄正在 Langfuse 中被記錄下來,這讓他可以全面瞭解 Agent 的行為。有了這個設定,他就可以回顧之前的執行情況,並進一步完善他的派對準備 Agent。

要了解更多關於追蹤你的 Agent 以及如何使用收集到的資料來評估其效能的資訊,請檢視附加單元 2
from smolagents import CodeAgent, InferenceClientModel

agent = CodeAgent(tools=[], model=InferenceClientModel())
alfred_agent = agent.from_hub('sergiopaniego/AlfredAgent', trust_remote_code=True)
alfred_agent.run("Give me the best playlist for a party at Wayne's mansion. The party idea is a 'villain masquerade' theme")  

阿福現在可以在這裡訪問這些日誌,以進行審查和分析。

實際上,在執行過程中發生了一個小錯誤。你能在日誌中發現它嗎?試著追蹤 Agent 是如何處理它並仍然返回一個有效答案的。這裡是錯誤的直接連結,如果你想驗證你的答案的話。當然,這個錯誤在此期間已經被修復了,更多細節可以在這個 issue 中找到。

與此同時,建議的播放列表為派對準備營造了完美的氛圍。很酷,對吧?🎶


現在我們已經建立了我們的第一個程式碼 Agent,讓我們來學習如何建立工具呼叫 Agent,這是 smolagents 中可用的第二種 Agent 型別。

資源

< > 在 GitHub 上更新

© . This site is unofficial and not affiliated with Hugging Face, Inc.