calculator_tool 计算器工具完整逐行详解

整体作用

这是一个 LangChain 标准结构化工具(Structured Tool),专门给大模型调用,用来安全计算数学表达式。 通过严格限制 eval 执行权限,杜绝代码注入风险,只允许基础四则运算与简单数值函数。

1. 装饰器 @tool

python

运行

@tool
def calculator_tool(expression: str) -> str:
  • 来源:from langchain.tools import tool
  • 功能:自动把普通 Python 函数转换成 LLM 可识别工具
    1. 自动读取函数文档字符串(docstring)生成工具描述
    2. 自动解析参数类型 expression: str 生成 JSON Schema
    3. LLM 在需要计算时,会自动生成 tool_call 调用这个函数
  • 约束:大模型会严格按照 expression 传一段纯数学表达式,如 "35 * (10 - 2)"

2. 文档字符串 docstring

python

运行

"""
Evaluates basic mathematical expressions.

Args:
    expression: A mathematical expression like "25 + 17" or "100 / 4"

Returns:
    The calculated result as a string
"""

这段内容会完整传给 LLM,让模型明白:

  • 工具用途:计算数学式子
  • 需要传入什么格式参数
  • 返回什么类型结果

3. 函数入参与返回值标注

  • expression: str:必须传入字符串格式数学表达式,不能直接传数字
  • -> str:计算完成后统一转为字符串返回,方便大模型拼接回答

4. try-except 异常捕获块

python

运行

try:
    # 计算逻辑
except Exception as e:
    return f"Error calculating: {str(e)}"

捕获所有计算异常,常见报错场景:

  • 语法错误:"5 ++ 3""(10+2" 括号不匹配
  • 除零错误:"10 / 0"
  • 包含未授权函数 / 变量 不会直接抛出程序崩溃,而是返回可读错误文本给 LLM,模型可以修正表达式重新计算。

5. 安全白名单 allowed_names

python

运行

allowed_names = {
    'abs': abs, 'round': round, 'min': min, 'max': max,
    'sum': sum, 'len': len, 'int': int, 'float': float
}

eval 默认能执行任意 Python 代码,极度危险,这里手动只放行安全数值函数

  • abs:绝对值
  • round:四舍五入
  • min/max:取最小最大值
  • sum:求和
  • int/float:类型转换 不在这个字典里的函数(如 open__import__osexec)一律无法调用。

6. 核心安全执行语句 eval

python

运行

result = eval(expression, {"__builtins__": {}}, allowed_names)

eval(待执行字符串, 全局作用域, 局部作用域) 三层安全隔离:

  1. 第二个参数 {"__builtins__": {}} 清空 Python 所有默认内置函数,彻底屏蔽系统操作、文件读写、导入模块等高危能力。 没有这一行,攻击者写 __import__("os").system("rm -rf /") 会直接破坏服务器。

  2. 第三个参数 allowed_names 局部作用域仅提供我们手动允许的数学工具,表达式里只能使用字典里定义的函数。

示例对比

允许:

python

运行

eval("abs(-10)", {}, allowed_names)  # 返回 10
eval("round(3.1415, 2)", {}, allowed_names) # 返回3.14
eval("20 * 5 - 8 / 2", {}, allowed_names)

禁止(直接报错):

python

运行

eval("open('secret.txt')", {}, allowed_names)
eval("__import__('os')", {}, allowed_names)

7. 结果处理

python

运行

return str(result)

计算结果可能是 int /float,统一转字符串输出,LLM 更容易解析、拼接进回答。

完整运行测试示例

python

运行

from langchain.tools import tool

@tool
def calculator_tool(expression: str) -> str:
    """
    Evaluates basic mathematical expressions.

    Args:
        expression: A mathematical expression like "25 + 17" or "100 / 4"

    Returns:
        The calculated result as a string
    """
    try:
        # For safety, only allow basic math operations
        allowed_names = {
            'abs': abs, 'round': round, 'min': min, 'max': max,
            'sum': sum, 'len': len, 'int': int, 'float': float
        }
        # Evaluate the expression safely
        result = eval(expression, {"__builtins__": {}}, allowed_names)
        return str(result)
    except Exception as e:
        return f"Error calculating: {str(e)}"

# 测试正常计算
print(calculator_tool.run("100 / (5 + 15)"))  # 5.0
print(calculator_tool.run("abs(-99)"))          # 99

# 测试错误表达式
print(calculator_tool.run("10 / 0"))
# Error calculating: division by zero

现有工具优缺点

优点

  1. eval 双层隔离,极大降低代码注入风险,可在线上环境安全使用
  2. 自带异常兜底,不会中断 Agent 流程
  3. LangChain 标准工具,可直接 llm.bind_tools() 给大模型调用
  4. 支持括号、四则运算、基础数值函数

局限

  1. 不支持幂运算 **、开方、三角函数(可手动补充进 allowed_names)
  2. 不支持中文数字、中文运算符,只能接收英文符号表达式
  3. 仅拦截函数调用,无法屏蔽复杂无限循环表达式(极少场景风险)
  4. len 被放进白名单,表达式中写 len([1,2,3]) 会生效,不需要可以删除
Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐