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 的输出变得可控、可解析。