智能体课程文档
构建使用代码的 Agent
并获得增强的文档体验
开始使用
构建使用代码的 Agent
代码 Agent 是 smolagents
中的默认 Agent 类型。它们生成 Python 工具调用来执行动作,从而实现高效、富有表现力且准确的动作表示。
它们精简的方法减少了所需动作的数量,简化了复杂操作,并实现了对现有代码函数的重用。smolagents
为构建代码 Agent 提供了一个轻量级框架,代码量约 1000 行。
图片来自论文 Executable Code Actions Elicit Better LLM Agents
为何选择代码 Agent?
在多步 Agent 流程中,LLM 编写并执行动作,通常涉及外部工具调用。传统方法使用 JSON 格式指定工具名称和参数(作为字符串),系统必须解析这些信息才能确定执行哪个工具。
然而,研究表明,直接使用代码能让工具调用型 LLM 更有效地工作。这是 smolagents
的核心原则,正如上图所示(该图来自论文 Executable Code Actions Elicit Better LLM Agents)。
用代码而非 JSON 编写动作有以下几个关键优势:
- 可组合性:轻松组合和重用动作
- 对象管理:直接处理复杂结构,如图像
- 通用性:能够表达任何计算上可能的任务
- 对 LLM 更自然:高质量的代码已经存在于 LLM 的训练数据中
代码 Agent 如何工作?
上图展示了 CodeAgent.run()
的工作方式,它遵循了我们在第一单元中提到的 ReAct 框架。smolagents
中 Agent 的主要抽象是 MultiStepAgent
,它是核心构建块。CodeAgent
是一种特殊的 MultiStepAgent
,我们将在下面的例子中看到。
一个 CodeAgent
通过一系列步骤的循环来执行动作,现有的变量和知识被整合到 Agent 的上下文中,并保存在执行日志中。
系统提示存储在
SystemPromptStep
中,用户查询则记录在TaskStep
中。然后,执行以下 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
中),它们将被执行。
看几个例子
阿福(Alfred)正在韦恩庄园策划一场派对,他需要你的帮助来确保一切顺利进行。为了协助他,我们将运用所学的关于多步 CodeAgent
如何运作的知识。

如果你还没有安装 smolagents
,可以运行以下命令进行安装:
pip install smolagents -U
我们还要登录到 Hugging Face Hub,以便访问无服务器推理 API(Serverless Inference API)。
from huggingface_hub import login
login()
使用 smolagents 为派对选择播放列表
音乐是一场成功派对的重要组成部分!阿福需要一些帮助来选择播放列表。幸运的是,smolagents
能帮我们解决这个问题!我们可以构建一个能够使用 DuckDuckGo 在网上搜索的 Agent。为了让 Agent 能够使用这个工具,我们在创建 Agent 时将其包含在工具列表中。

对于模型,我们将依赖 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)
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
几步之后,你就会看到生成的播放列表,阿福可以用它来为派对助兴!🎵
使用自定义工具准备菜单

现在我们已经选好了播放列表,我们需要为客人准备菜单。阿福同样可以利用 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 并与社区分享吧!🕵️♂️💡
使用 OpenTelemetry 和 Langfuse 检查我们的派对准备 Agent 📡
在阿福微调派对准备 Agent 的过程中,他对调试运行过程感到越来越厌倦。Agent 天生具有不可预测性,难以检查。但既然他的目标是构建终极的派对准备 Agent 并将其部署到生产环境中,他需要强大的可追溯性以便未来进行监控和分析。
smolagents
再次挺身而出!它采用了 OpenTelemetry 标准来检测 Agent 的运行情况,实现了无缝的检查和日志记录。在 Langfuse 和 SmolagentsInstrumentor
的帮助下,阿福可以轻松地跟踪和分析他的 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。
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,让我们来学习如何创建工具调用 Agent,这是 smolagents
中可用的第二种 Agent 类型。
资源
- smolagents 博客 - smolagents 和代码交互简介
- smolagents: 构建优秀的 Agent - 构建可靠 Agent 的最佳实践
- 构建有效的 Agent - Anthropic - Agent 设计原则
- 使用 OpenTelemetry 分享运行记录 - 关于如何设置 OpenTelemetry 来跟踪你的 Agent 的详细信息。