你有没有想过:让 AI 直接写一段 Python 代码来调用你的工具,而不是让它吐一堆 JSON 再去解析?Hugging Face 的 smolagents 就是这么干的——它是 HF 官方开源的轻量 Agent 库,核心理念是"代码即工具"(Code Agent):LLM 生成可执行的 Python 片段,在受控解释器里跑,比传统 JSON 工具调用更稳、更省 token。本教程从最小 CodeAgent 到"自定义工具 + 自带工具箱 + 换模型 + 沙箱安全",零基础也能几行代码跑通。
一、smolagents 是什么,为什么"代码即工具"
大多数 Agent 框架让模型输出 {"tool": "x", "args": {...}} 这样的 JSON,再自己解析执行;smolagents 的 CodeAgent 让模型直接写 result = my_tool(...) 这样的 Python,由内置受限解释器执行。它提供两种 Agent:
| Agent 类型 | 怎么行动 | 何时用 |
|---|---|---|
| CodeAgent(默认) | 每步写并执行 Python 片段 | 大多数场景,灵活、省 token |
| ToolCallingAgent | 输出 JSON 工具调用 | 需要和传统 JSON 工具链对齐时 |
本地执行意味着要讲安全。CodeAgent 默认在你的本地 Python 环境跑 LLM 生成的代码。框架内置了一个受限解释器(禁任意导入、限执行时间),但它不是金刚不坏——跑不可信任务时务必用沙箱(见 Step 6)。
Step 1:安装与最小 CodeAgent
用 HF 自带的 InferenceClientModel,不配 Key 也能跑(有频率限制),配了 HF_TOKEN 更快更稳:
pip install smolagents
from smolagents import CodeAgent, InferenceClientModel
# 不传 token 也能试,只是有频率限制
agent = CodeAgent(tools=[], model=InferenceClientModel())
answer = agent.run("2 的 10 次方是多少?只给出整数结果。")
print(answer)
HF_TOKEN,用环境变量 HF_TOKEN=hf_xxx 注入,或直接 InferenceClientModel(token="hf_xxx")。默认在本地执行代码。看到的输出里会有 LLM 生成的 Python 被实际运行。本步骤只有算数很安全;一旦接上能联网 / 读文件的工具,就要开始考虑隔离(Step 6)。
Step 2:加一个自定义工具(@tool)
用 @tool 装饰器,类型注解和 docstring 缺一不可——框架靠它们告诉模型怎么用这个工具:
from smolagents import CodeAgent, InferenceClientModel, tool
@tool
def fetch_stock_price(ticker: str) -> float:
"""获取股票当前价格。Args: ticker: 股票代码,如 'AAPL'。"""
prices = {"AAPL": 175.5, "TSLA": 210.2, "MSFT": 405.0}
return prices.get(ticker.upper(), 0.0)
agent = CodeAgent(tools=[fetch_stock_price], model=InferenceClientModel())
print(agent.run("买 5 股 AAPL 和 2 股 TSLA 一共多少钱?"))
docstring 里必须写清楚参数含义。模型靠 docstring 决定"传什么、何时调"。类型注解(str / float)则用于生成调用。两者不一致,工具就调不准。
Step 3:用自带工具箱(add_base_tools / WebSearchTool)
smolagents 自带一批工具。装 smolagents[toolkit] 后可用 add_base_tools=True 一键挂载,也可以单独挑:
from smolagents import CodeAgent, InferenceClientModel, WebSearchTool
agent = CodeAgent(
tools=[WebSearchTool()],
model=InferenceClientModel(),
# 或 add_base_tools=True 挂载整套自带工具
)
print(agent.run("2026 年最受欢迎的轻量级 Agent 框架有哪些?"))
WebSearchTool 联网搜索、VisitWebpageTool 抓网页正文、PythonInterpreterTool 等都开箱可用。新手先用自带工具箱,等明确需求再写自定义 @tool。Step 4:授权额外导入(additional_authorized_imports)
受限解释器默认禁止 import。若工具代码需要 requests、bs4,要显式白名单:
from smolagents import CodeAgent, InferenceClientModel
agent = CodeAgent(
tools=[],
model=InferenceClientModel(),
additional_authorized_imports=["requests", "bs4"],
)
print(agent.run("抓取 https://huggingface.co/blog 的标题。"))
只加你信得过的库。白名单里的库会被真实 import 并执行,等于把相应能力放进执行环境。宁可少加、用沙箱,也不要贪图方便把 os、subprocess 之类放进去跑不可信任务。
Step 5:换成你自己的模型(LiteLLM / OpenAI / 本地)
smolagents 模型无关,通过 LiteLLM 接 100+ 模型,也能直连 OpenAI 或本地 Ollama:
# 方案 A:用 LiteLLM 接 OpenAI / Anthropic / 本地
from smolagents import CodeAgent, LiteLLMModel
model = LiteLLMModel(model_id="openai/gpt-4o", temperature=0.2)
agent = CodeAgent(tools=[], model=model)
# 方案 B:本地 Ollama(完全离线、免费、隐私)
local = LiteLLMModel(model_id="ollama/llama3", api_base="http://localhost:11434")
agent_local = CodeAgent(tools=[], model=local)
print(agent.run("用一句话解释什么是代码智能体。"))
api_base 指过去即可,全程数据不出本机,适合处理公司内部文档。Step 6:安全与部署注意(沙箱 / E2B / Docker)
跑不可信或联网任务时,把代码执行挪到沙箱里:
import os
from smolagents import CodeAgent, InferenceClientModel
# 方案 A:E2B 远程沙箱(需 E2B_API_KEY)
os.environ["E2B_API_KEY"] = "e2b_xxx"
agent = CodeAgent(tools=[], model=InferenceClientModel(), use_e2b_executor=True)
# 方案 B:整体用 Docker 跑 Agent 进程,再加一层系统级隔离
print(agent.run("读取并总结 /data/report.txt 的要点。"))
本地直跑只适合可信场景。一旦 Agent 能联网、读文件、import 任意库,就必须上 E2B 之类的远程沙箱,或至少用 Docker 把整个进程圈起来。把"能写代码"的 Agent 直接放在生产主机上裸跑,是高危操作。
常见问题速查
| 现象 | 大概率原因 & 解决 |
|---|---|
| 频繁被限流 | 没设 HF_TOKEN,去 hf.co 拿一个设上 |
| 工具没被调用 | docstring / 类型注解不清,或模型太弱写不对调用 |
| import 报错 | 忘了在 additional_authorized_imports 白名单里加该库 |
| 想换模型报错 | LiteLLM 模型字符串格式应为 provider/model |