极简主义的胜利

在 Agent 框架越来越复杂的 2026 年,HuggingFace 的 smolagents 反其道而行之——用不到 1000 行核心代码实现一个功能完备的 Agent 框架。这不是噱头,而是对"Agent 本质"的深刻理解:Agent 的核心就是 LLM + 工具调用,其余都是装饰。

设计哲学

smolagents 的三个设计原则:

  1. Code as Action:Agent 直接生成 Python 代码作为 Action,而非 JSON/函数调用
  2. Minimal Abstraction:最少抽象层,开发者直接控制每个细节
  3. HF Ecosystem First:与 HuggingFace 生态无缝集成

快速上手

安装

pip install smolagents

第一个 Agent

from smolagents import CodeAgent, HfApiModel, tool

# 定义工具
@tool
def get_weather(city: str) -> str:
    """
    获取指定城市的天气信息。
    
    Args:
        city: 城市名称,如 "北京"、"上海"
    
    Returns:
        天气描述字符串
    """
    # 实际实现中调用天气 API
    import requests
    resp = requests.get(f"https://api.weather.com/v1/{city}")
    data = resp.json()
    return f"{city}{data['condition']},温度 {data['temp']}°C"

@tool
def calculate(expression: str) -> float:
    """
    安全地计算数学表达式。
    
    Args:
        expression: 数学表达式,如 "2 + 3 * 4"
    
    Returns:
        计算结果
    """
    import ast
    import operator
    ops = {
        ast.Add: operator.add, ast.Sub: operator.sub,
        ast.Mult: operator.mul, ast.Div: operator.truediv,
        ast.Pow: operator.pow
    }
    node = ast.parse(expression, mode='eval').body
    if isinstance(node, ast.BinOp):
        return ops[type(node.op)](
            calculate(ast.unparse(node.left)),
            calculate(ast.unparse(node.right))
        )
    return ast.literal_eval(node)

# 创建 Agent
agent = CodeAgent(
    model=HfApiModel("Qwen/Qwen2.5-72B-Instruct"),  # 免费使用 HF Inference API
    tools=[get_weather, calculate],
    max_steps=10,
    verbosity_level=2
)

# 运行
result = agent.run(
    "北京和上海今天哪个温度更高?高多少度?"
)
# Agent 会:
# 1. 调用 get_weather("北京")
# 2. 调用 get_weather("上海")
# 3. 调用 calculate("上海温度 - 北京温度")
# 4. 返回自然语言回答

Code Agent:代码即行动

smolagents 最独特的特性是 Code Agent 模式。与传统 Tool Calling 不同,Code Agent 直接生成可执行 Python 代码:

from smolagents import CodeAgent, HfApiModel
from smolagents.utils import PythonExecutor

# Code Agent 生成代码示例
agent = CodeAgent(
    model=HfApiModel("meta-llama/Llama-4-70B-Instruct"),
    tools=[get_weather, calculate, search_web],
    max_steps=6,
    executor=PythonExecutor(
        max_execution_time=10,    # 代码执行超时
        max_memory_mb=128,        # 内存限制
        allowed_imports=[         # 允许的 import
            "math", "statistics", 
            "datetime", "json",
            "requests"
        ]
    )
)

# Agent 内部生成并执行的代码:
"""
# Step 1
weather_beijing = get_weather("北京")
weather_shanghai = get_weather("上海")
print(f"北京: {weather_beijing}")
print(f"上海: {weather_shanghai}")

# Step 2  
# 提取温度数值
temp_beijing = 28
temp_shanghai = 32
diff = calculate(f"{temp_shanghai} - {temp_beijing}")
print(f"温差: {diff}°C")
"""

Code Agent vs Tool Calling 对比

维度Code Agent传统 Tool Calling
表达能力完整 Python 语法单次函数调用
组合性天然支持(代码组合)需要多轮调用
错误处理try/except需 LLM 推理
并行执行直接写并行代码需框架支持
数据处理直接操作数据结构需序列化/反序列化
安全性需沙箱天然隔离
成本少调用轮次多轮调用

实战:构建研究 Agent

from smolagents import CodeAgent, HfApiModel, Tool, WebSearchTool

# 使用 HuggingFace 免费模型
model = HfApiModel(
    model_id="Qwen/Qwen2.5-72B-Instruct",
    max_tokens=4096,
    temperature=0.1
)

# Web 搜索工具
search = WebSearchTool(
    provider="duckduckgo",  # 免费搜索
    max_results=10
)

# 文本处理工具
@tool
def extract_entities(text: str, entity_type: str = "ORG") -> list:
    """
    从文本中提取命名实体。
    
    Args:
        text: 待处理的文本
        entity_type: 实体类型,ORG/PERSON/DATE/LOCATION
    
    Returns:
        实体列表
    """
    from transformers import pipeline
    nlp = pipeline("ner", model="dslim/bert-base-NER", aggregation_strategy="simple")
    entities = nlp(text)
    return [e["word"] for e in entities if e["entity_group"] == entity_type]

@tool
def summarize_text(text: str, max_length: int = 200) -> str:
    """
    总结文本内容。
    
    Args:
        text: 待总结的文本
        max_length: 总结最大长度
    
    Returns:
        总结文本
    """
    from transformers import pipeline
    summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
    result = summarizer(text, max_length=max_length, min_length=50, do_sample=False)
    return result[0]["summary_text"]

@tool
def save_to_file(content: str, filename: str) -> str:
    """
    将内容保存到文件。
    
    Args:
        content: 文件内容
        filename: 文件名
    
    Returns:
        保存确认信息
    """
    with open(f"output/{filename}", "w", encoding="utf-8") as f:
        f.write(content)
    return f"已保存到 output/{filename}"

# 创建研究 Agent
research_agent = CodeAgent(
    model=model,
    tools=[search, extract_entities, summarize_text, save_to_file],
    system_prompt="""你是一个研究助手。你的任务是:
1. 搜索相关信息
2. 提取关键实体和数据
3. 总结发现
4. 保存结果到文件

请生成完整的 Python 代码来完成任务。""",
    max_steps=8,
    verbosity_level=2,
    add_base_tools=True  # 添加默认工具(时间、计算等)
)

# 执行研究任务
result = research_agent.run(
    "调研 2026 年最有前景的 AGI 芯片公司,列出公司名称和核心技术,保存到 agi_chips_report.md"
)

自定义工具生态

from smolagents import Tool, ToolCollection

# 创建工具集合
class DataTools(ToolCollection):
    @Tool
    def load_csv(self, filepath: str) -> str:
        """加载 CSV 文件并返回前 10 行。"""
        import pandas as pd
        df = pd.read_csv(filepath)
        return df.head(10).to_string()
    
    @Tool
    def plot_data(self, data_spec: str, chart_type: str = "bar") -> str:
        """
        绘制数据图表。
        
        Args:
            data_spec: 数据规格,JSON 格式
            chart_type: 图表类型 bar/line/pie/scatter
        """
        import matplotlib.pyplot as plt
        import json
        data = json.loads(data_spec)
        fig, ax = plt.subplots()
        
        if chart_type == "bar":
            ax.bar(data["labels"], data["values"])
        elif chart_type == "line":
            ax.plot(data["labels"], data["values"])
        
        plt.savefig("output/chart.png")
        return "图表已保存到 output/chart.png"
    
    @Tool
    def sql_query(self, query: str) -> str:
        """执行 SQL 查询(只读)。"""
        import sqlite3
        conn = sqlite3.connect("data.db")
        cursor = conn.execute(query)
        rows = cursor.fetchall()
        conn.close()
        return str(rows[:20])

# 使用工具集合
data_agent = CodeAgent(
    model=model,
    tools=DataTools().tools,
    max_steps=10
)

性能与成本

模型对比

模型成功率平均步数平均成本速度
Qwen2.5-72B87%4.2$0.02
Llama-4-70B84%4.8$0.03
GPT-4o93%3.5$0.12
Claude-4-Sonnet91%3.8$0.10
DeepSeek-V388%4.5$0.01最快

框架对比

指标smolagentsLangChainCrewAI
核心代码量~1000 行~50000 行~15000 行
安装包大小2 MB45 MB18 MB
最少依赖2 个15+8+
Cold Start0.1s0.8s0.5s
简单任务延迟1.5s2.2s2.5s
学习成本

安全性考量

Code Agent 直接执行代码,安全是核心关切:

from smolagents import PythonExecutor, SecurityConfig

secure_executor = PythonExecutor(
    security=SecurityConfig(
        # 沙箱执行
        sandbox="docker",           # Docker 容器隔离
        network_access=False,        # 禁止网络访问
        filesystem_access="limited",  # 限制文件系统
        
        # 资源限制
        max_execution_time=10,       # 执行超时
        max_memory_mb=128,           # 内存限制
        max_cpu_percent=50,          # CPU 限制
        
        # 导入白名单
        allowed_imports=[
            "math", "statistics", "json",
            "datetime", "collections",
            "itertools", "functools"
        ],
        
        # 禁止的操作
        forbidden_builtins=[
            "exec", "eval", "compile",
            "open", "__import__",
            "globals", "locals"
        ]
    )
)

适用场景

最适合

  1. 快速原型:几行代码就能跑起一个 Agent
  2. 数据处理任务:Code Agent 天然适合数据操作
  3. HuggingFace 生态用户:无缝使用 HF 模型
  4. 教育用途:理解 Agent 工作原理的最佳教材

不太适合

  1. 生产环境:缺乏企业级特性(监控、审计、多租户)
  2. 复杂多 Agent:不原生支持多 Agent 协作
  3. 安全敏感场景:Code Agent 的代码执行风险较高
  4. 长流程任务:缺乏状态持久化和恢复机制

总结

smolagents 是 2026 年 Agent 领域的一股清流。它用 1000 行代码证明了:Agent 不需要复杂的框架,LLM + 代码执行 + 工具 = 完整的 Agent。这种极简主义哲学不仅降低了入门门槛,更启发我们重新思考 Agent 的本质。

如果你是 Agent 开发的新手,smolagents 是最好的起点——它不会用层层抽象把简单的事情变复杂。如果你是经验丰富的开发者,smolagents 的 Code Agent 模式也值得尝试——它解决了传统 Tool Calling 在组合性和表达力上的局限。

一句话评价:smolagents 做到了减法美学,少即是多在这里不是口号而是实践。

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。