Audience: 对技术感兴趣的普通用户 + Python 开发者
承接上文: 第六章《大模型“动脑子”的全过程揭秘》
上一章我们讲完了 Inference(推理)。大模型坐在那里,像个哲学家一样,把“明天去哪玩”变成了“公园吧”。
但是,哲学家只能动嘴,不能动手。
如果你想问:“帮我算算这笔账” 或者 “帮我订张机票”,光靠“接龙”是算不出结果的,也是订不了票的。
这时候,AI 必须从 “思想家” 变成 “实干家”。
这就是 Tool Execution(工具执行) 的舞台。
01 为什么 AI 自己算不对 123 * 456?
技术名词:Tool Use(工具使用)、Function Calling(函数调用)
大模型的短板
大模型是“文科生”。它擅长预测文字,不擅长精确计算。
你问:
123 * 456 = ?模型推理:根据训练数据,这个数字通常在 50000 左右。
模型输出:
56088(很可能是错的,因为它没真的去乘)。
工具的强项
计算器是“理科生”。它只会算数,但算得绝对准。
模型输出:
Action: Calculator(123 * 456)计算器执行:返回
56088。
通俗解释:
AI 是那个出主意的老板,工具是那个干活的实习生。老板负责想“我们要赚 100 万”,实习生负责用 Excel 算“每天得卖多少杯咖啡”。
02 工具执行的完整链路
技术名词:JSON Schema(参数规范)、Sandbox(沙盒)
从 AI 决定用工具,到拿到结果,中间有 5 步:
┌──────────┐ 1. Generate ┌──────────┐│ LLM │ ──────────────→ │ Tool Call ││ (思想) │ │ (JSON) │└──────────┘ └────┬─────┘│ 2. Parse & Validate▼┌──────────┐ 4. Result ┌──────────┐│ LLM │ ←────────────── │ Executor ││ (再思考) │ │ (干活) │└──────────┘ 5. Inject └──────────┘
1️⃣ 生成 Tool Call(生成指令)
模型不再输出自然语言,而是输出一段 JSON。
{"name": "calculator","parameters": {"expression": "123 * 456"}}
2️⃣ 解析与校验(安全检查)
后端代码检查这段 JSON:
这个工具
calculator存在吗?参数
expression里有恶意代码吗?(比如os.system('rm -rf /'))
3️⃣ 执行(Execution)
在隔离环境中运行代码。
4️⃣ 返回结果(Observation)
拿到计算结果:56088。
5️⃣ 注入上下文(Feedback)
把结果塞回给 AI:“嘿,算出来了,是 56088,你可以回答用户了。”
03 开发者时间:Python 实现工具执行器
这是 Agent(第三章) 的升级版。我们加入了 安全沙盒 和 异常处理。
1. 定义危险操作黑名单(Security)
import astimport operator as op# 禁止的安全操作(防止 AI 删库跑路)SAFE_OPERATORS = {ast.Add: op.add,ast.Sub: op.sub,ast.Mult: op.mul,ast.Div: op.truediv,ast.Pow: op.pow,ast.USub: op.neg,}class SafeEval:"""安全计算器:只允许四则运算"""def __init__(self):self.operators = SAFE_OPERATORSdef eval_expr(self, expr: str) -> float:"""安全解析并计算表达式"""try:# 使用 AST(抽象语法树)解析,避免直接使用 evalnode = ast.parse(expr, mode='eval')return self._eval_node(node.body)except Exception as e:return f"计算错误: {e}"def _eval_node(self, node):if isinstance(node, ast.Num):return node.nelif isinstance(node, ast.BinOp):left = self._eval_node(node.left)right = self._eval_node(node.right)op_func = self.operators[type(node.op)]return op_func(left, right)elif isinstance(node, ast.UnaryOp):operand = self._eval_node(node.operand)op_func = self.operators[type(node.op)]return op_func(operand)else:raise TypeError(f"不支持的操作: {node}")
2. 实现执行器(Executor)
class ToolExecutor:def __init__(self):self.tools = {"calculator": SafeEval().eval_expr}def execute(self, tool_call_json: dict) -> str:"""执行工具调用"""tool_name = tool_call_json.get("name")params = tool_call_json.get("parameters", {})if tool_name not in self.tools:return f"Error: Tool '{tool_name}' not found."print(f"🔧 [Executor] 正在执行工具: {tool_name}, 参数: {params}")try:# 执行工具result = self.tools[tool_name](**params)return str(result)except Exception as e:# 捕获执行时的异常(如除零错误)return f"Execution Error: {e}"
3. 串联 Agent 进行测试
# 假设这是 Agent 生成的 JSONfake_tool_call = {"name": "calculator","parameters": {"expr": "100 * 1.05 + 50"}}executor = ToolExecutor()result = executor.execute(fake_tool_call)print(f"✅ 执行结果: {result}")
04 工程上的“避坑指南”
工具执行是 AI 应用最容易崩的地方,也是最危险的。
1️⃣ 代码执行沙盒(Code Interpreter)
如果让 AI 跑 Python 代码,绝对不能在服务器主环境跑。
方案: 使用 Docker 容器 或 Firecracker 微虚拟机。
原则: 限制 CPU、内存、网络访问(禁止访问内网数据库)。
2️⃣ API 调用的幂等性(Idempotency)
AI 可能会重复调用同一个工具。
场景: AI 让你“转账 100 元”。
灾难: 因为网络卡顿,AI 重试了 3 次,结果转了 300 元。
解法: 给每个请求加唯一 ID(Idempotency Key)。
3️⃣ 超时控制(Timeout)
AI 调用的 API 可能挂了。
解法: 设置硬超时(Hard Timeout),超过 5 秒直接掐断,告诉 AI “工具坏了”。
05 总结
工具执行 = AI 的双手 + 刹车片。
没有工具,AI 只是个嘴炮王者;
没有安全控制,AI 就是个定时炸弹。
至此,我们已经集齐了 Router(路由)、Agent(智能体)、MCP(接口)、RAG(知识)、Inference(大脑)、Tools(双手)。
整个系统看起来很完美了,对吧?
错。
因为 AI 有时候还是会胡说八道,或者输出违规内容。
这就是我们下一章要讲的:最后一道防线——Output Guardrail(输出护栏)。
夜雨聆风