智能体的每一步「行动」都要先过一道表示题:模型做出的决策,用什么格式交给执行器?主流答案有两种——让模型直接写一段可执行代码,或者让它吐出一个结构化的 JSON 对象。smolagents 把两种形态都做成了现成的类:CodeAgent 走代码路线,ToolCallingAgent 走 JSON 路线 [1]。
两种路线的差别,用一个具体任务看得最清楚:让智能体同时搜「哥谭市最好的餐饮服务」和「超级英雄派对主题创意」。CodeAgent 会生成并运行一段 Python 循环:
for query in [
"Best catering services in Gotham City",
"Party theme ideas for superheroes"
]:
print(web_search(f"Search for: {query}"))ToolCallingAgent 则输出一个 JSON 数组,每个元素只有工具名和参数两个字段:
[
{"name": "web_search", "arguments": "Best catering services in Gotham City"},
{"name": "web_search", "arguments": "Party theme ideas for superheroes"}
]框架拿到这串 JSON 后解析并分发给对应工具执行,整个过程不碰任何代码解析器 [1]。
为什么要主推代码动作
smolagents 官方立场很明确:框架主推 CodeAgent,因为整体表现更好——他们为此专门发过论文(arXiv 2402.01030)。原因值得展开说。代码可以声明变量、复用中间结果、表达循环和条件;JSON 是纯声明式结构,嵌套一层就多一堆转义和括号,中间结果也无法跨调用复用。同一个任务,代码版本往往更短、更省 token,还能做 JSON 表达不了的控制流。
但 JSON 也有自己的舒适区。它的结构严格、解析简单,更重要的是各家模型服务商的原生 API 都支持 function calling 协议——模型训练时就见过大量「按 schema 吐 JSON」的数据,输出稳定性反而高。不需要变量处理、不需要复杂工具调用的简单系统,正是 ToolCallingAgent 的用武之地 [1]。
用起来什么样
ToolCallingAgent 与 CodeAgent 走完全相同的多步工作流:先想、再做、再观察,直到给出最终答案;唯一的差别在动作的表示形式——不是可执行代码,而是指明工具名和参数的 JSON 对象,由系统解析后执行 [1]。搭一个能联网搜索的版本只要几行:
from smolagents import ToolCallingAgent, WebSearchTool, InferenceClientModel
agent = ToolCallingAgent(tools=[WebSearchTool()], model=InferenceClientModel())
agent.run("Search for the best music recommendations for a party at the Wayne's mansion.")运行时看 trace,CodeAgent 会显示「Executing parsed code:」,而这里显示的是一条调用公告:框架宣布正在调用 web_search 工具、参数是哪条查询。智能体生成结构化工具调用,系统处理后产出结果,全程没有代码执行环节 [1]。
工程上的几条经验
把 JSON 工具调用用稳,有几件事值得提前做。第一,很多服务商支持语法受限解码(schema 引导采样),能保证模型吐出合法 JSON,schema 违规一般在解析阶段就被拦下;把解析错误作为 Observation 喂回模型,比直接崩掉要好——下一轮它通常能自己改对。
第二,执行前校验参数。类型、取值范围、必填字段都过一遍,校验失败就返回一条人类可读的错误信息进对话,让智能体在下一个 Thought 步骤里自我修正 [1]。工具注册表也要保持干净:工具数量少、命名不歧义、描述具体,因为模型是靠 system 提示词里的描述选工具的,名字重叠或描述含糊会直接推高选错工具、传错参数的概率。
第三,选型凭经验法则:每一步都是单次、独立、参数固定的工具调用,用 ToolCallingAgent 足够;一旦出现循环、条件、算术或需要跨调用共享的中间状态,就该换 CodeAgent [1]。另外,WebSearchTool 封装的是 DuckDuckGo 搜索,结果天生不确定,依赖它的智能体轨迹在测试里应该用可重放的夹具评估,而不是每次都打真实请求。
顺带一提,Alfred 管家是这门课贯穿始终的示例角色:同一个派对筹备任务,先用 CodeAgent 写搜索循环解一遍,再用 ToolCallingAgent 吐两个 JSON 搜索调用解一遍,正好把「智能体类型」这个变量单独隔离出来对比。
本文改编自 Hugging Face agents-course 的 Writing actions as code snippets or JSON blobs 一节[1],原文以 Apache-2.0 许可发布。
来源
- 1Writing actions as code snippets or JSON blobs | Hugging Face Agents CourseHugging Face agents-course (Apache-2.0)
引用本页: smolagents 的工具调用智能体. TellWorld, https://www.tellworld.net/zh/practice/practice-smolagents-tool-calling. 更新于 2026-11-14