目录

02 - 给 Agent 装上工具:从”只会聊天”到”能干活”

一句话总结:工具(Tools)让 Agent 从一个只会动嘴的聊天机器人,变成一个能查数据、搜信息、调接口的全能干将。


没有工具的 Agent,就是个”嘴强王者”

上一篇我们创建了第一个 Agent,它能聊天、能回答问题,看起来很厉害对吧?但你仔细想想,它的所有回答都来自训练数据 – 它没法查实时股价,没法搜最新新闻,更没法帮你调用你自己的业务接口。

打个比方:大语言模型就像一个非常聪明的人,脑子里装了很多知识,但他被关在一个房间里,既没有手机也没有电脑。你问他”今天天气怎么样”,他只能猜。但如果你给他一部手机(搜索工具)、一台电脑(数据查询工具)、甚至一把螺丝刀(自定义工具),那他就能真正帮你干活了。

在 Agno 里,这些”手机、电脑、螺丝刀”统称为 Tools(工具)


第一个工具:用 YFinance 查股票

Agno 内置了不少现成的工具,开箱即用。我们先来试试 YFinanceTools,它能直接从 Yahoo Finance 拉取股票数据。

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.yfinance import YFinanceTools

agent = Agent(
    name="股票分析师",
    model=OpenAIChat(id="gpt-4o-mini"),
    tools=[YFinanceTools()],
    instructions="你是一个股票分析师,用中文回答,数据来源于Yahoo Finance",
    markdown=True,
)
agent.print_response("NVIDIA 现在的股价是多少?", stream=True)

运行后你会看到 Agent 不再”瞎猜”了 – 它会调用 get_current_stock_price 函数去 Yahoo Finance 查真实数据,然后把结果整理成自然语言返回给你。

注意 tools 参数接收的是一个列表。这意味着你可以同时给 Agent 装多个工具,后面会讲到。


搜索工具:用 DuckDuckGo 搜网络

查股票只是开胃菜,搜索才是最常用的能力。Agno 内置了 DuckDuckGoTools,让 Agent 能搜索网页和新闻。

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.duckduckgo import DuckDuckGoTools

agent = Agent(
    name="搜索助手",
    model=OpenAIChat(id="gpt-4o-mini"),
    tools=[DuckDuckGoTools()],
    instructions="你是一个搜索助手,帮用户搜索信息并用中文总结",
    markdown=True,
)
agent.print_response("2024年诺贝尔物理学奖得主是谁?", stream=True)

这次 Agent 会先用 DuckDuckGo 搜索相关信息,拿到结果后再总结成中文回答。你训练数据里没有的最新信息,搜一搜就有了。


多工具组合:一个 Agent,多种能力

前面说了 tools 是个列表,所以我们完全可以把多个工具塞给同一个 Agent,让它自己判断该用哪个。

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.yfinance import YFinanceTools
from agno.tools.duckduckgo import DuckDuckGoTools

agent = Agent(
    name="全能助手",
    model=OpenAIChat(id="gpt-4o-mini"),
    tools=[YFinanceTools(), DuckDuckGoTools()],
    instructions="你是一个全能助手,可以查股票数据也可以搜索网络信息",
    markdown=True,
)
agent.print_response("搜索一下NVIDIA最近有什么大新闻,然后查一下它的股价", stream=True)

这里发生了一件很酷的事情:Agent 自己决定先用 DuckDuckGo 搜新闻,再用 YFinance 查股价,最后把两部分信息整合成一个完整的回答。你不需要写任何调度逻辑,LLM 自己搞定。


自定义工具:用 @tool 装饰器

内置工具再多,也不可能覆盖你所有的业务场景。好消息是,在 Agno 里写自定义工具非常简单 – 写个函数,加个 @tool 装饰器就行。

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools import tool


@tool
def get_weather(city: str) -> str:
    """获取指定城市的天气信息"""
    # 这里用模拟数据,实际项目中可以调用天气API
    weather_data = {
        "北京": "晴,25度C",
        "上海": "多云,28度C",
        "深圳": "小雨,30度C",
    }
    return weather_data.get(city, f"暂无{city}的天气数据")


agent = Agent(
    name="天气助手",
    model=OpenAIChat(id="gpt-4o-mini"),
    tools=[get_weather],
    instructions="你是一个天气助手,帮用户查询天气",
)
agent.print_response("北京今天天气怎么样?")

几个关键点:

  • 函数签名很重要:参数名和类型提示会被传给 LLM,让它知道怎么调用
  • docstring 更重要:它是 LLM 理解”这个工具是干什么的”唯一依据。写清楚,LLM 才知道什么时候该用它
  • 返回值:工具的返回值会被送回给 LLM,由 LLM 组织成最终回答

工具类 Toolkit:管理一组相关工具

如果你有好几个相关的工具函数(比如一组数学运算),把它们散落在各处不太优雅。这时候可以用 Toolkit 类把它们组织起来。

from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools import Toolkit


class MathTools(Toolkit):
    def __init__(self):
        super().__init__(
            name="math_tools",
            tools=[self.add, self.multiply],
        )

    def add(self, a: float, b: float) -> str:
        """计算两个数的和

        Args:
            a: 第一个数
            b: 第二个数

        Returns:
            两个数的和
        """
        return str(a + b)

    def multiply(self, a: float, b: float) -> str:
        """计算两个数的积

        Args:
            a: 第一个数
            b: 第二个数

        Returns:
            两个数的积
        """
        return str(a * b)


agent = Agent(
    model=OpenAIChat(id="gpt-4o-mini"),
    tools=[MathTools()],
)
agent.print_response("计算 23.5 + 17.8,然后把结果乘以 3")

Toolkit@tool 装饰器的区别:

场景 推荐方式
一两个独立的工具函数 @tool 装饰器
一组相关的工具,或者工具需要共享状态 Toolkit

比如数据库查询工具需要共享连接池,天气工具需要共享 API key,这种情况用 Toolkit 就很合适 – 把共享的东西放在 self 上,各个工具方法都能访问。


工具调用是怎么工作的?

你可能好奇:Agent 是怎么知道该调用哪个工具的?这里简单说一下底层流程:

1. 你提问"北京今天天气怎么样?"
         |
         v
2. Agent 把你的问题 + 所有工具的定义名称描述参数一起发给 LLM
         |
         v
3. LLM 分析后决定我应该调用 get_weather 工具参数是 city="北京"
         |
         v
4. Agno 框架执行 get_weather("北京")拿到结果 "晴,25度C"
         |
         v
5. Agno 把工具执行结果发回给 LLM
         |
         v
6. LLM 基于工具结果生成最终回答"北京今天天气晴朗,气温25度。"

所以本质上,LLM 并不是自己去查天气的 – 它只是决定要查天气,然后告诉框架”帮我调这个函数,参数是这些”。框架执行完后把结果喂回来,LLM 再组织语言回答你。

这就是为什么 docstring 那么重要:它是 LLM 做决策的依据。如果你的工具描述写得含糊不清,LLM 可能根本不知道什么时候该用它。


本篇小结

  • tools 参数接收一个列表,可以混合使用内置工具和自定义工具
  • Agno 内置了不少好用的工具:YFinanceTools(股票)、DuckDuckGoTools(搜索)、ShellTools(命令行)、PythonTools(执行 Python)等等
  • @tool 装饰器可以把任意函数变成 Agent 工具,简单快捷
  • Toolkit 类可以组织一组相关的工具,适合需要共享状态的场景
  • 工具的 docstring 是灵魂 – 写清楚功能描述和参数说明,LLM 才能正确使用它

下一篇预告

03 - 让 Agent 说”结构化的话”:用 Pydantic 控制输出格式

到目前为止,Agent 的回答都是自由发挥的自然语言。但在实际项目中,你往往需要 Agent 返回结构化的数据 – 比如一个 JSON 对象、一个固定格式的分析报告。下一篇我们来看看怎么用 Pydantic 的 output_schema 让 Agent 的输出变得可控、可解析。