如何为-AI-代理构建工具
如何为 AI 代理构建工具
本文的目标是强调在为 AI 代理构建工具时应关注什么。适当的工具对于高性能代理至关重要,因此我将更深入地探讨代理工具的使用。我将涵盖诸如良好的工具定义和描述以及将工具以最佳方式提供给代理的优化方式等主题。
工具为什么对 AI 代理很重要

这张信息图表突出了文章的内容。我将讨论为什么好的工具对你的代理至关重要。然后,我将强调如何使用清晰的命名和 docstrings 定义适当的工具,以及如何改进工具的功能。最后,我还会讨论如何让你的工具对代理可用。图片由 ChatGPT 提供。
拥有可用的工具是使代理有效的重要组成部分。没有访问工具,LLM 就不会有相同的选项,例如执行网络搜索或在数据库表中查找信息。因此,如何定义和利用你的代理工具对于你的代理性能至关重要。
在为你的代理定义工具时,需要考虑各种因素。从我自己的代理工作经历来看,我发现许多这些考虑也适用于使用工具的人类,例如:
-
工具应该有良好的定义,包括适当的命名和描述
-
工具应该有一个特定的目的
-
你应该为工具提供适当的类型定义,包括工具的输入和输出
通常,我认为你可以通过遵循以下引用的原则走得很远。你创建的所有工具都应该以人类易于理解的方式定义,了解工具及其工作原理。
工具应该被定义得易于人类使用
我发现这个原则在 ML 工作中适用性很强,例如,在分析你提供给 LLM 的提示时也是如此。你应该始终问自己,人类是否能够理解提示中提供的任务。如果不能,提示就需要澄清。
正确的工具定义
正确的工具定义是你可以对你的 AI 代理做出的简单改进。我所说的正确工具定义是指:
-
你的工具应该有一个清晰的名字,代表工具的功能
-
你的工具应该有一个描述性良好的文档字符串,包括工具的简短描述、所有输入参数及其类型,以及工具返回内容的定义
我将首先展示一个糟糕的工具示例,突出问题,然后提供一个良好的工具定义示例。
# bad tool definition
def search(query):
results = search_database()
return results
由于以下问题,这是一个糟糕的工具定义:
-
工具命名不具描述性。搜索模糊;例如,它也可能指执行语义搜索
-
它缺少一个定义输入和输出类型以及工具功能的文档字符串
-
工具缺少输入和输出参数的类型。使用此工具的 LLM 可能能够推断出
*query*是一个字符串。然而,一旦使用工具,模型将不得不花费时间理解输出格式。
因此,你应该这样定义工具:
@dataclass
class KeywordSearchResult:
id: str
filename: str
document_content: str
# good tool definition
def keyword_search(query: str) -> list[KeywordSearchResult]:
"""
Performs keyword search in the database.
Input parameters:
query: str - the keywords to search for
Output:
A list of all keyword search results, with each result containing:
- id (str) - the id of the document as defined in the database
- filename (str) - the filename of the document
- document_content (str) - the text contents of the document
"""
results = search_databse()
return results
在这个例子中,我创建了一个单独的数据类,代表工具的输出格式。这使得你的代理更容易理解工具的工作方式,并使处理输出变得更加容易。此外,我定义了一个适当的文档字符串,其中包含工具的简单描述、所有输入参数及其类型,以及工具返回的内容。我将工具名称命名为 keyword_search 而不是简单的 search。
对你的工具进行这些简单的改进将大大提高你的代理的性能。然而,还有其他技术你可以应用来定义你的工具,这将使你的代理更加有效。
工具功能
继续讨论你的工具,你也可以通过使工具更具体并为模型提供工具的干净输出来提高代理性能。我将继续使用关键字示例来具体说明我的意思。
制作特定工具
工具应尽可能具体。创建模糊的工具会使模型更难知道何时使用该工具。因此,你将更频繁地遇到模型错误地使用工具的情况。例如,可能包括:
-
在不正确的时间使用工具。例如,当应该使用
semantic_search时使用keyword_search -
使用模型时参数不正确
-
错误处理工具的输出
因此,你的工具应该始终具有明确、单一的目的。
提供干净的输出
另一种大大提高你的代理工具质量的方法是为代理提供一个干净的输出。这意味着在工具内部解析结果,使其以易于代理理解的方式结构化。我将在下面的例子中再次描述这一点。
我将创建一个名为 _*parse_keyword_search_output* 的工具,该工具接受关键字搜索输出并将它们解析成结构化字符串。在这个例子中,我还包括关键字搜索结果包含一些不必要的输出。当我们解析输出时,这些结果自然会排除。
@dataclass
class KeywordSearchResult:
id: str
filename: str
document_content: str
uneccesary_field_a: str
uneccesary_field_b: str
def _parse_keyword_search_output(keyword_search_results: list[KeywordSearchResult]) -> str:
"""Parse the output from the keyword search tool, into a structured string, only containing necessary information"""
output_string = ""
tot_num_documents = len(keyword_search_results)
for i, result in enumerate(keyword_search_results):
document_id, filename, document_content = result["id"], result["filename"], result["document_content"]
output_string += f"""\n\n
Document {i+1}/{tot_num_documents}:
ID: {document_id}
filename: {filename}
content: {document_content}
"""
return output_string
def keyword_search(query: str, url: str) -> list[KeywordSearchResult]:
"""<docstring>"""
results = search_databse()
return parse_results(results)
以这种方式解析输出使得代理处理关键字搜索工具的输出变得更加容易。请记住,确保keyword_search工具的文档字符串描述了解析关键字搜索工具将提供的输出格式。
避免返回所有结果
当使用如关键字搜索这样的工具时,工具有时会返回数百甚至数千个结果。这将立即膨胀代理的上下文。为了防止这种情况,你应该添加选项来排序工具的输出,并且只返回最大数量的项目,如下面的示例中所示:
def keyword_search(query: str, url: str, sort_ascending=True, max_return_items=10) -> list[KeywordSearchResult]:
"""<docstring>"""
results = search_databse()
if sort_ascending:
results = sort(results, ascending=True)
else:
results = sort(results, ascending=False)
results = parse_results(results)
if max_return_items < len(results):
return results[:max_return_items]
return results
通常,模型看到前 10 或 20 个结果就足够了,既可以获取最有用的信息(在关键字搜索中,通常最相关的结果是前几个),也可以理解输出格式。
信息性错误处理
信息性错误处理是当您的代理不可避免地遇到问题时必须设置的临界安全措施。这个问题可能由以下原因引起:
-
代理错误地使用了一个工具,在这种情况下,你应该通知代理为什么它错误地使用了该工具,并可能还提供如何修复它的方法
-
API 失败是因为第三方提供商的问题。在这种情况下,你可能需要通知模型等待或通知用户问题
-
缺少包,在这种情况下,你应该通知代理安装所需的包
def keyword_search(query: str, url: str) -> list[KeywordSearchResult]:
"""<docstring>"""
try:
results = search_database()
return parse_results(results)
except RatelimitError as e:
raise RuntimeError(
f"Rate limit error: {e}. "
f"Wait before retrying. If this error persists, contact support."
)
except APINotAvailableError as e:
raise RuntimeError(
f"API not available: {e}. "
f"Check that the provided URL is correct and the endpoint is operational."
)
except Exception as e:
raise RuntimeError(
f"Unexpected error: {e}. Please try again."
)
这种信息性的错误处理使得代理处理工具失败的场景变得更加容易。通常,你应该在错误处理中确保以下内容:
-
你返回一个描述性的错误消息,包括错误跟踪和描述错误的字符串
-
你应该理想地通知代理在接收到这个错误后应该如何行动。例如,如果模型遇到速率限制错误,如果是第一次遇到这个错误,它应该运行 time.sleep(),否则它应该通知用户。
将工具提供给您的代理
现在你已经拥有了功能性和正确定义的工具,是时候将它们提供给您的代理了。然而,在提供工具给代理时,还有一些考虑事项需要考虑。
-
上下文中可以容纳多少工具?
-
何时提供工具?
-
如何在上下文中提供工具?
关于第一个要点,我认为在你的环境中考虑应该修复多少工具是很重要的。给代理提供太多的工具会让代理难以知道何时使用哪个工具,因此,模型在有效利用工具方面会感到困难。因此,你应该审查你的工具并考虑它们是否都是代理表现良好的必要条件。
继续讨论这个话题,你可能还需要考虑何时提供工具。例如,当代理为用户执行简单的总结任务时,keyword_search工具可能不相关。你可以修改代理的上下文,使得一些工具仅在相关时才可用。
最后,你也应该考虑如何使工具可用。在你的提示中,你应该为你的工具创建一个单独的部分,无论是使用 Markdown 标题还是单独的 XML 标签。然后,你应该在这个部分中放置所有你的工具以及如何以及何时使用这些工具的描述。
结论
在这篇文章中,我介绍了如何与你的智能体工具一起工作。我讨论了工具是 AI 智能体最重要的方面,这使得它们能够如此有效。此外,我还讨论了如何创建适当的工具定义以及如何创建专业工具。我相信,当你致力于你的 AI 智能体时,与你的工具一起工作,改进它们的定义以及你的智能体如何使用它们,是你能投入时间做的最重要的事情。
👉 我的免费资源
🚀 用大型语言模型提升你的工程能力(免费 3 天电子邮件课程)
👉 在社交平台上找到我:
📩 订阅我的通讯
🧑💻 联系我
✍️ Medium

浙公网安备 33010602011771号