工具是 Agent 的手和眼
前三篇我们讲了 Agent 的思维框架——ReAct 如何边想边做,Plan-and-Solve 如何先规划再执行。但思维框架再好,Agent 如果只能和 LLM 自己对话,能做的事情极其有限。
工具(Tool)是 Agent 突破语言模型边界的关键。有了工具,Agent 可以:
- 查询实时数据(股价、天气、新闻)
- 操作文件系统
- 调用外部 API
- 执行代码计算
但工具设计得好不好,直接决定了 Agent 的可靠性。一个设计糟糕的工具,会让 Agent 在错误中打转,甚至产生安全漏洞。
这篇文章,我们从零拆解工具调用的全貌:设计、验证、安全、并行调用、错误处理——五个维度,配合实际运行结果。
好工具 vs 坏工具:同一任务,截然不同的 Agent 行为
先做一个对比实验,把这个结论建立在真实数据上。
同样是"查股价"的功能,我们写两个版本:
坏工具(三个典型缺陷):
@tooldefbad_stock_tool(x:str)->str:"""Get stock info."""# ← 文档简陋:参数含义、返回格式、示例全无_MOCK_STOCKS={"AAPL":189.5,"GOOGL":175.2,"MSFT":420.3}price=_MOCK_STOCKS[x]# ← KeyError 直接崩溃,不捕获returnf"{price}"# ← 只返回数字,没有单位、货币、上下文好工具(三个对应改进):
@tooldefget_stock_price(symbol:str)->str:"""查询股票的当前价格和涨跌幅。 参数: symbol:股票代码,大写字母,例如 "AAPL"、"GOOGL"、"MSFT"、"TSLA"、"BABA" 返回: 包含股票名称、当前价格(美元)、今日涨跌幅的字符串。 如果代码不存在,返回错误说明。 示例: get_stock_price("AAPL") → "Apple Inc. (AAPL): $189.50 USD, 今日 +1.23%" get_stock_price("UNKNOWN") → "未找到股票代码 UNKNOWN,支持的代码:..." """symbol=symbol.strip().upper()ifnotre.match(r"^[A-Z]{1,5}$",symbol):returnf"无效的股票代码格式:{symbol!r}。代码应为 1-5 个大写字母。"info=_MOCK_STOCKS.get(symbol)ifinfoisNone:supported="、".join(_MOCK_STOCKS.keys())returnf"未找到股票代码{symbol}。当前支持:{supported}"sign="+"ifinfo["change_pct"]>=0else""return(f"{info['name']}({symbol}): "f"${info['price']:.2f}