
AI Agent 是由一系列大语言模型(LLM)调用构成的程序。它们接收用户任务,并通过调用“工具”来高效解决问题。工具本质上是 Agent 可以调用的函数。然而,构建一个高效的 Agent 远不止于简单地将一组函数塞入其上下文。关键在于如何精心定义工具,以及如何向 Agent 清晰地传达这些工具的信息。
本文旨在阐述为 AI Agent 构建工具时应关注的核心要点。恰当的工具对于实现高性能的 Agent 至关重要。我们将深入探讨“Agentic”(即由 Agent 驱动)的工具使用范式,涵盖如何定义与描述工具,以及如何以最优方式让 Agent 获取和使用工具。
为什么工具对 AI Agent 至关重要

工具的可用性直接决定了 Agent 的能力边界。没有工具,LLM 将无法执行诸如联网搜索或在数据库中查询信息等操作。因此,工具的定义与使用方式对 Agent 的性能有决定性影响。
定义工具时,需要从多个维度进行考量。根据实践经验,许多适用于人类使用工具的原则,同样适用于 Agent:
- 清晰的命名与描述:工具的名称和说明应能准确表达其功能。
- 单一职责:一个工具应专注于完成一个明确的任务。
- 规范的类型定义:应为工具的输入参数和返回值提供明确的类型声明。
遵循一个核心原则可以事半功倍:你创建的所有工具,其定义方式都应让人类能够轻松理解该工具的作用和工作机制。
工具应以便于人类理解和使用的方式来定义。
这一原则在机器学习工作中也普遍适用,例如在分析提示词(Prompt)时。你应该始终自问:人类能否理解这个提示词所描述的任务?如果不能,就需要进一步澄清。
规范的工具定义
规范化的工具定义是为 AI Agent 提升性能最简单有效的方法之一。所谓“规范”,主要包括:
- 清晰的名称:能准确表达工具的功能。
- 完整的文档字符串(Docstring):应包含工具功能的简要说明、所有输入参数的描述及类型、以及返回值的定义。
下面通过一个反面示例和一个规范示例进行对比。
# 不佳的工具定义示例
def search(query):
results = search_database()
return results
这个定义存在以下问题:
1. 命名模糊:search 过于宽泛,无法区分是关键词搜索还是语义搜索。
2. 缺少文档:没有说明工具的作用、输入和输出。
3. 缺乏类型提示:LLM 可能推断 query 是字符串,但难以确定返回的数据结构,增加了模型理解输出的负担。
一个规范的工具定义应如下所示:
from dataclasses import dataclass
@dataclass
class KeywordSearchResult:
id: str
filename: str
document_content: str
# 规范的工具定义示例
def keyword_search(query: str) -> list[KeywordSearchResult]:
"""
在数据库中执行关键词搜索。
参数:
query (str): 要搜索的关键词。
返回:
list[KeywordSearchResult]: 包含所有搜索结果的列表。每个结果包含:
- id (str): 文档在数据库中的唯一标识符。
- filename (str): 文档的文件名。
- document_content (str): 文档的文本内容。
"""
results = search_database(query)
return results
在这个改进的示例中:
* 使用 keyword_search 这个具体名称替代了模糊的 search。
* 定义了 KeywordSearchResult 数据类来明确输出格式,便于 Agent 理解和处理。
* 提供了详细的文档字符串,清晰说明了功能、参数和返回值。
这些简单的改进能显著提升 Agent 调用工具的准确性和效率。
提升工具的功能性
除了规范定义,还可以通过增强工具本身的“功能性”来进一步提升 Agent 的性能,主要体现在以下两个方面。
1. 让工具足够具体
工具的功能应尽可能具体、单一。模糊的工具会导致 Agent 在以下方面犯错:
* 误判使用时机:例如,在该使用 semantic_search 时错误调用了 keyword_search。
* 参数传递错误:由于不理解工具的确切用途,可能传入无效参数。
* 错误解析输出:无法正确理解工具返回的数据结构。
因此,确保每个工具都有一个清晰且唯一的目的。
2. 提供简洁的输出
另一种有效方法是,在工具内部将原始结果处理成对 Agent 友好的、结构化的字符串。这可以减少 Agent 解析复杂数据结构的负担。
以下示例展示了一个解析函数,它从原始的搜索结果中提取必要信息,并格式化为清晰的文本。
@dataclass
class KeywordSearchResult:
id: str
filename: str
document_content: str
unnecessary_field_a: str # 无关字段
unnecessary_field_b: str
def _parse_keyword_search_output(keyword_search_results: list[KeywordSearchResult]) -> str:
"""将关键词搜索工具的输出解析为仅包含必要信息的结构化字符串。"""
output_lines = []
total_docs = len(keyword_search_results)
for i, result in enumerate(keyword_search_results):
# 只提取必要字段,过滤无关信息
doc_info = f"""
Document {i+1}/{total_docs}:
ID: {result.id}
Filename: {result.filename}
Content: {result.document_content[:200]}... # 示例:截取部分内容
"""
output_lines.append(doc_info)
return "n".join(output_lines)
def keyword_search(query: str) -> str:
"""
在数据库中执行关键词搜索,并返回格式化的结果字符串。
(注意:实际函数签名和逻辑需根据 `_parse_keyword_search_output` 调整)
"""
raw_results: list[KeywordSearchResult] = search_database(query)
formatted_output = _parse_keyword_search_output(raw_results)
return formatted_output
通过这种方式,Agent 接收到的就是易于阅读和处理的文本,而非原始的、可能包含冗余字段的数据对象。记得在工具的文档字符串中说明最终提供的输出格式。
3. 限制返回结果数量
像搜索这类工具,可能返回成百上千条结果,这很容易撑满 Agent 的上下文窗口。为了避免这种情况,应为工具添加分页或限制返回数量的参数。
def keyword_search(query: str, max_results: int = 10, sort_by: str = "relevance") -> list[KeywordSearchResult]:
"""
在数据库中执行关键词搜索,并限制返回结果数量。
参数:
query (str): 搜索关键词。
max_results (int): 最多返回的结果数量,默认为10。
sort_by (str): 结果排序方式,例如 'relevance'(相关性)或 'date'(日期)。
返回:
list[KeywordSearchResult]: 经过排序和数量限制后的搜索结果列表。
"""
all_results = search_database(query, sort_by=sort_by)
return all_results[:max_results]
通常,让 Agent 查看前10到20条最相关的结果就足够了,这既能提供关键信息,又能帮助模型理解输出格式,同时有效控制上下文长度。
4. 信息丰富的错误处理
当工具执行出错时,提供清晰、有用的错误信息至关重要。这能帮助 Agent 理解问题所在并采取正确的后续行动。常见的错误类型包括:
* 工具调用错误:如参数类型不匹配或缺少必要参数。错误信息应指出具体问题并给出修正建议。
* 外部API失败:如第三方服务不可用。应提示 Agent 稍后重试或通知用户服务暂时中断。
* 依赖缺失:如运行工具所需的Python包未安装。应提示 Agent 尝试安装缺失的依赖。
良好的错误处理是构建健壮 Agent 系统的关键安全网。
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."
)
这种信息丰富的错误处理机制,使 Agent 在工具执行失败时能够更有效地应对。通常,应确保错误信息具备以下特征:
- 描述性:既包含错误栈(trace)信息,也包含对错误原因的文字说明。
- 可操作性:最好能指导 Agent 在收到错误后应如何操作。例如,遇到速率限制(rate limit)错误时,可建议首次重试前先等待(如
time.sleep()),若持续报错则转告用户。
向 Agent 提供工具
在拥有了实用且定义规范的工具后,下一步是让 Agent 能够使用它们。在向 Agent 提供工具时,需要考虑几个关键问题:
- 上下文容量:Agent 的上下文(context)中能容纳多少工具?
- 工具可用性:何时让特定工具对 Agent 可用?
- 工具呈现方式:在上下文中应以何种方式组织和描述工具?
对于上下文容量,关键在于平衡。向 Agent 提供过多工具可能导致其难以判断在特定场景下应使用哪个工具,从而降低工具使用的准确性和效率。因此,应仔细审视工具集,评估每个工具是否为 Agent 完成核心任务所必需。
关于工具可用性,可以考虑动态调整。例如,当 Agent 仅执行简单的文本总结(summarisation)任务时,keyword_search 工具可能并不相关。可以根据当前任务情境动态修改 Agent 的上下文,使某些工具仅在相关时才被“激活”和提供。
最后,需要考虑工具的呈现方式。在提示词(prompt)中,建议为工具创建一个独立、结构清晰的章节。可以使用 Markdown 标题(如 ## Available Tools)或独立的 XML 标签(如 <tools>)来划分。在该章节中,列出所有可用工具,并附上关于其功能、适用场景及调用方式的清晰说明。
结语
本文探讨了为 AI Agent 构建高效工具的核心策略。我们阐述了工具对于扩展 Agent 能力边界的重要性,并深入介绍了如何创建规范的工具定义以及打造专用工具。在开发 AI Agent 时,将精力投入到工具的设计、优化以及提升 Agent 的工具使用策略上,往往是获得显著性能提升的最有效途径。
关注“鲸栖”小程序,掌握最新AI资讯
本文由鲸栖原创发布,未经许可,请勿转载。转载请注明出处:http://www.itsolotime.com/archives/13353
