趋近智
使用Python实际构建LLM代理工具是代理开发的核心部分。构建自定义工具有两种主要方式:直接的Python函数或更有组织的Python类。你的选择将取决于工具需要执行的任务的复杂性,以及它是否需要在多次使用中记住信息。
Python的可读性和丰富的库使其成为开发LLM代理工具的极佳选择。无论你是执行简单的计算、查询数据库还是与网络服务交互,Python都能提供必要的构建块。
对于许多任务来说,一个简单的Python函数足以创建一个有效的工具。函数非常适合以下类型的工具:
可以将基于函数的工具视为一个专家,它非常擅长做一件事,并且不需要在不同任务之间保留记录。
一个结构良好的函数工具应包括:
我们来看一个例子。假设我们想要一个可以计算矩形面积的工具。
def calculate_rectangle_area(length: float, width: float) -> float:
"""
计算矩形的面积。
参数:
length (float): 矩形的长度。必须是正数。
width (float): 矩形的宽度。必须是正数。
返回:
float: 计算得到的矩形面积。
"""
if length <= 0 or width <= 0:
# 处理无效输入是一种好的做法,
# 尽管更详细的错误处理将在后面介绍。
raise ValueError("长度和宽度必须是正数。")
return length * width
# 示例用法(不属于工具本身,仅用于演示)
# area = calculate_rectangle_area(10.0, 5.0)
# print(f"面积为: {area}")
在这个calculate_rectangle_area工具中,文档字符串清楚地说明了其用途给LLM(以及任何人类开发者),包括预期的length和width参数(包括它们的类型和约束),以及它将返回的内容。类型提示(length: float、width: float、-> float)提供了额外的结构信息。
当你的工具需求超出这些局限时,是时候考虑使用Python类了。
当你需要构建有状态、组合相关功能或需要更复杂设置的工具时,Python类提供了一种有条理的方法。一个类可以封装数据(状态)和操作该数据的方法(行为)。
可以将基于类的工具视为一个更具多功能性的工作者,它能记住过去的交互、管理自己的资源,并提供一系列相关的服务。
FileManager工具可能包含read_file、write_file和list_directory_contents等方法。__init__)是进行此操作的自然之处。__enter__和__exit__等方法进行上下文管理,更有效地管理资源(如网络连接或文件句柄),确保资源得到正确获取和释放。class关键字开始。__init__方法(构造函数):当创建类的实例时,此方法会被调用。可用于:
self.my_data)存储。我们来看一个UserProfileTool,它可以存储和获取简单的用户偏好。
class UserProfileTool:
"""
管理简单的用户档案信息,如姓名和首选城市。
该工具允许设置和获取这些偏好。
"""
def __init__(self):
"""初始化一个空的用户档案。"""
self._name: str | None = None
self._preferred_city: str | None = None
print("UserProfileTool 已初始化。") # 用于演示
def set_preference(self, key: str, value: str) -> str:
"""
设置用户偏好。
当前支持“name”和“preferred_city”。
参数:
(str): 偏好(例如,“name”,“preferred_city”)。
value (str): 偏好的值。
返回:
str: 一条确认消息。
"""
if key == "name":
self._name = value
return f"用户名设置为“{value}”。"
elif key == "preferred_city":
self._preferred_city = value
return f"首选城市设置为“{value}”。"
else:
return f"未知偏好:“{key}”。支持的键是“name”、“preferred_city”。"
def get_preference(self, key: str) -> str | None:
"""
获取用户偏好。
参数:
preference (str): 要获取的偏好(例如,“name”、“preferred_city”)。
返回:
str | None: 偏好的值,如果未设置或偏好未知则为 None。
"""
if key == "name":
return self._name
elif key == "preferred_city":
return self._preferred_city
else:
# 对于未知键,代理框架可能更喜欢报错或返回特定消息。
# 这里我们返回 None,但你也可以抛出错误或返回消息。
print(f"尝试获取未知偏好:{key}")
return None
# 示例用法:
# profile_tool = UserProfileTool()
# print(profile_tool.set_preference("name", "Alex"))
# print(profile_tool.set_preference("preferred_city", "New York"))
# print(f"用户姓名: {profile_tool.get_preference('name')}")
# print(f"用户城市: {profile_tool.get_preference('preferred_city')}")
# print(f"用户最喜欢的颜色: {profile_tool.get_preference('favorite_color')}")
在这个UserProfileTool中,__init__方法初始化了_name和_preferred_city(内部状态,按照惯例以单下划线作为前缀,表示它们供内部使用,但仍然可以访问)。set_preference和get_preference方法操作此状态。每个方法都有自己的文档字符串,为LLM代理清楚地定义了其功能。LLM将被呈现UserProfileTool中set_preference和get_preference作为可用的操作。
将工具实现为Python函数还是类,其决定取决于工具的要求,特别是在状态和复杂性方面。
一个关于工具实现中Python函数和类选择的决策指南。如果工具需要状态或组合多个相关操作,通常更倾向于使用类。否则,一个更简单的函数可能就足够了。
以下是快速总结:
无论你选择函数还是类,有两个元素对于使你的Python代码可用作LLM工具始终非常重要:文档字符串和类型提示。
文档字符串:如前所述,LLM代理框架通常会解析这些内容以理解你的工具功能。LLM本身依赖这些描述来:
类型提示:Python的类型提示(例如,name: str、count: int、-> list[str])有多种用途:
# 类型提示和文档字符串的良好使用
def search_knowledge_base(query: str, filters: list[str] | None = None) -> list[dict]:
"""
在知识库中搜索与查询匹配的文章。
可以可选地应用过滤器。
参数:
query (str): 搜索词或问题。
filters (list[str] | None, optional): 一个过滤器字符串列表
要应用(例如,['category:technical', 'tag:python'])。
默认为 None(无过滤器)。
返回:
list[dict]: 一个搜索结果列表,其中每个结果都是一个字典
包含“title”、“summary”和“url”。如果没有找到结果,则返回一个空
列表。
"""
# ... 实现细节 ...
print(f"正在搜索: {query} 使用过滤器: {filters}") # 占位符
if query == "python tools":
return [
{"title": "Python Functions as Tools", "summary": "...", "url": "/ch2/functions"},
{"title": "Python Classes for Tools", "summary": "...", "url": "/ch2/classes"}
]
return []
在这个例子中,query: str及其文档字符串解释的结合为LLM提供了精确信息。同样,-> list[dict]连同其在文档字符串“返回”部分的描述,为LLM准备了输出的结构。
虽然我们专注于编写工具本身的Python代码,但记住这些函数和类如何成为LLM的“活跃”工具很有用。通常,你将使用LLM代理框架(例如LangChain、LlamaIndex,甚至是自定义构建的框架)。这些框架提供了以下机制来:
本节我们不会详细介绍任何特定框架,但理解这一一般工作流程有助于理解为什么清晰的函数/方法签名、全面的文档字符串和准确的类型提示如此重要。它们是你的Python代码与LLM决策过程之间的桥梁。
通过掌握将工具实现为Python函数和类,你将获得为LLM代理创建广泛功能的灵活性。随着我们继续,我们将在这些基本结构上构建,以添加更高级的功能,如状态管理、外部服务交互和强大的错误处理。
这部分内容有帮助吗?
© 2026 ApX Machine Learning用心打造