工具是什么?

AI Agent 的一个关键方面是它们执行行动(Action)的能力。这是通过使用工具(Tool)实现的。

本节将学习工具是什么,如何高效地设计工具,以及如何通过系统消息将其集成进 Agent。

通过为 Agent 提供合适的工具,并且清楚地描述这些工具如何使用,可以显著地增加 AI 可以完成的任务。


1. AI 工具是什么?

工具(Tool)是提供给 LLM 的函数。该函数实现明确的目标

下面是 AI Agent 中经常使用的工具:

ToolDescription
Web Search允许 Agent 从互联网获取最新信息
Image Generation基于文本描述创建图片
Retrieval从外部源检索信息
API Interface与外部 API 进行交互

这些只是示例,因为实际上可以为任何用例创建工具!

好的工具应该是对 LLM 功能的补充

比如如果想要执行算术运算,那么为 LLM 提供计算器工具将比依赖模型的原生功能获得更好的结果。

此外,LLM 基于其训练数据预测提示词的补全内容,这意味着其内部知识仅包括训练前发生的事情。因此,如果 Agent 需要获取最新数据,那么必须通过工具提供。

比如如果直接向 LLM 询问今天的天气(未使用搜索工具),那么 LLM 很可能产生幻觉,随机编造天气信息。

工具应该包含:


2. 工具如何工作

LLM 只能接收文本输入,并且生成文本输出。LLM 本身无法调用工具。当我们谈论为 Agent 提供工具时,意思是告诉 LLM 工具的存在,并且要求模型在需要时生成调用工具的文本。比如如果提供从互联网查看天气的工具,然后询问巴黎的天气,LLM 将该问题识别为使用“天气”工具的时机。LLM 将生成代码形式的文本调用该工具。Agent 负责解析 LLM 的输出,识别需要工具调用,并且代表 LLM 调用该工具。工具的输出将被发送回 LLM, LLM 将为用户组装最终响应。

工具调用的输出是会话中另一种类型的消息。工具调用步骤通常不向用户显示:Agent 检索会话、调用工具、获取输出、将它们添加为新会话消息,然后将更新后的会话再次发送给 LLM。从用户的角度看,就像 LLM 使用该工具,但实际上是应用程序代码(Agent)使用的。


3. 如何将工具提供给 LLM?

完整的答案可能看起来很复杂,但我们基本上是使用系统提示词(system prompt)向模型提供可用工具的文本描述:

为使该机制生效,我们必须非常精确和准确地说明:

这就是为什么工具描述通常使用表达性强但精确的结构(比如计算机语言或 JSON)提供的原因。其实不必一定这样做,任何精确且连贯的格式都可以。

下面通过具体示例进行说明。

我们将实现简单的计算机器工具,它将两个整数相乘。Python 实现如下:

def calculator(a: int, b: int) -> int:
    """Multiply two integers."""
    return a * b

该工具名为 calculator,它将两个整数相乘,需要下面的输入:

该工具的输出是另一个整数:

所有细节都很重要。将它们放到描述工具的文本字符串中,以便 LLM 能理解。

Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int

当将前面的字符串作为输入的一部分传给 LLM 时,模型将其识别为工具,并且知道该工具需要传递什么作为输入,以及从输出中期望什么。

如果希望提供其它工具,那么必须保持一致,并且始终使用相同的格式。该过程很脆弱,很可能意外地忽视某些细节。

有更好的方式么?

3.1. 自动格式化工具部分

我们使用 Python 编写工具,该实现已经提供所需的全部:

使用编程语言的原因之一:表达性强、简单、准确。

我们可以将 Python 源代码作为工具的说明提供给 LLM,但工具的实现方式不重要。重要的是名字、做什么、期望的输入和提供的输出。

我们将借助 Python 的自省特性,利用源代码,自动地构建工具描述。所需的是工具实现使用类型提示、文档字符串、有意义的函数名称。我们将编写代码从源代码中提取相关部分。

完成后,只需使用 Python 装饰器说明 calculator 函数是一个工具:

@tool
def calculator(a: int, b: int) -> int:
    """Multiply two integers."""
    return a * b

print(calculator.to_string())

注意函数定义前面的 @tool 装饰器。

使用该实现,能够通过装饰器提供的 to_string() 函数从源代码自动地生成如下字符串:

Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int

3.2. 通用的工具实现

我们创建通用的 Tool 类,当需要使用工具时,可以重用它。

class Tool:
    """
    A class representing a reusable piece of code (Tool).

    Attributes:
        name (str): Name of the tool.
        description (str): A textual description of what the tool does.
        func (callable): The function this tool wraps.
        arguments (list): A list of argument.
        outputs (str or list): The return type(s) of the wrapped function.
    """
    def __init__(self,
                 name: str,
                 description: str,
                 func: callable,
                 arguments: list,
                 outputs: str):
        self.name = name
        self.description = description
        self.func = func
        self.arguments = arguments
        self.outputs = outputs

    def to_string(self) -> str:
        """
        Return a string representation of the tool,
        including its name, description, arguments, and outputs.
        """
        args_str = ", ".join([
            f"{arg_name}: {arg_type}" for arg_name, arg_type in self.arguments
        ])

        return (
            f"Tool Name: {self.name},"
            f" Description: {self.description},"
            f" Arguments: {args_str},"
            f" Outputs: {self.outputs}"
        )

    def __call__(self, *args, **kwargs):
        """
        Invoke the underlying function (callable) with provided arguments.
        """
        return self.func(*args, **kwargs)

Tool 类包含:

可以使用如下代码创建工具:

calculator_tool = Tool(
    "calculator",                   # name
    "Multiply two integers.",       # description
    calculator,                     # function to call
    [("a", "int"), ("b", "int")],   # inputs (names and types)
    "int",                          # output
)

也可以使用 Python 的 inspect 模块获取全部信息!@tool 装饰器就是这样做的。

使用该装饰器,像下面这样实现工具:

@tool
def calculator(a: int, b: int) -> int:
    """Multiply two integers."""
    return a * b

print(calculator.to_string())

可以使用工具的 to_string 方法自动地生成适合作为 LLM 工具描述的文本:

Tool Name: calculator, Description: Multiply two integers., Arguments: a: int, b: int, Outputs: int

在系统提示词中注入该描述。以本节开始的示例为例,下面是替换 tools_description 后的样子:

3.3. Model Context Protocol(MCP):统一的工具接口

MCP 是标准化应用程序如何向 LLM 提供工具开放协议。MCP 提供:

这意味着任何实现 MCP 的框架都可以利用该协议中定义的工具,从而消除为每个框架重新实现相同工具接口的需求。


4. 总结

Tool 在增强 AI Agent 的能力方面扮演至关重要的角色。

总结:

  1. 工具是什么 - 给 LLM 提供额外能力的函数,比如执行计算,或访问外部数据
  1. 如何定义工具 - 通过提供清晰的文本描述、输入、输出和可调用函数的方式
  1. 为什么工具至关重要 - 它们使 Agent 能够克服静态模型训练的限制,处理实时任务,执行专用操作