AI News HubLIVE
站内改写3 分钟阅读

使用Gemma 4轻松实现智能体工具调用

本教程展示如何为Gemma 4模型添加本地文件系统浏览和安全Python解释器工具,实现真正的自主智能体行为,让模型自主决定何时探索环境、何时执行计算。

来源KDnuggets作者: Matthew Mayo

在之前关于机器学习大师的文章中,我们构建了一个工具调用智能体,该智能体能够从公共API获取天气、新闻、汇率和时间等信息。那篇文章很好地涵盖了模式的合成部分,但留下了更有趣的一半:一个能够推理自身环境、检查自己机器并将它不信任自己的逻辑卸载出去的智能体。可以说,这更接近真正的“智能体”。

本文接续前文,为Gemma 4模型赋予两个新工具——沙盒化的本地文件系统探索器和受限的Python解释器——并观察模型自主决定何时查看环境、何时进行计算。

从对话到智能体

当你只给语言模型提供只读的Web API工具时,本质上你仍然只有一个聊天机器人,尽管它可能拥有更好的信息访问权限。模型接收提示,决定调用哪个API,然后将JSON响应拼接成段落。没有真正的环境概念,没有可检查的状态,没有可推理的后果;这更像检索增强生成而非真正的智能体。

智能体(实践者使用的含义)出现在模型开始与其运行的系统交互时。这可能包括读取本地文件系统、执行代码、修改文件、调用其他进程等。一旦工具能够执行除从远程服务返回干净字符串以外的操作,模型就必须开始询问自身:存在哪些文件?这个数字实际等于多少?在我声称某个文件夹包含什么之前,它里面有什么?

Gemma 4系列,特别是我们一直在使用的gemma4:e2b边缘变体,足够小以在笔记本电脑上本地运行,同时在结构化输出方面足够强大以可靠地驱动这种循环。这种组合使本地智能体模式变得有趣。本教程的完整代码可在此处找到。

架构复用

前一个教程的编排循环没有改变。我们定义Python函数,通过JSON模式暴露它们,将注册表连同用户提示传递给Ollama,拦截响应中的任何tool_calls块,在本地执行请求的函数,将结果作为工具角色消息追加,然后重新查询模型以便它综合出最终答案。相同的call_ollama助手、相同的TOOL_FUNCTIONS字典、相同的available_tools模式数组都出现了。

变化的是工具本身的性质。前一批工具都是远程API的瘦客户端,而现在构建的工具都在机器上运行代码。这使设计问题从“如何解析这个响应”转变为“如何确保模型即使意外也无法做它不应该做的事情。”

工具1:沙盒化文件系统探索器

第一个工具list_directory_contents赋予模型查看给定文件夹中文件的能力。这听起来很简单,直到你想起os.listdir接受任何字符串,包括/、~和../../etc。一个天真实现可能会愉快地遍历模型的“好奇心”直接到达你的API密钥。

这里的设计选择是在脚本开始时固定一个安全基础目录,并拒绝任何解析到该目录之外的请求。我们从不信任模型产生的字符串。我们将其连接到基础目录,绝对解析(因此..被规范化),然后验证解析后的路径是否仍然以基础目录开头。无论是/etc/passwd还是../../somewhere都折叠为无法通过前缀检查的路径,并在调用os.listdir之前被拒绝。

函数的其余部分则是常规工作:确认路径存在且是目录,列出其内容,并将每个条目格式化为[DIR]或[FILE]并附带字节大小。返回的字符串是结构化的纯英语,模型可以在第二轮解析。

工具2:受限的Python解释器

第二个工具execute_python_code是两者中更危险且更具教学意义的。前提是语言模型,尤其是小型模型,在精确算术、精确字符串操作以及涉及多步分支逻辑的任何方面都不可靠。让模型编写并运行确定性代码片段的工具比要求它通过自然语言推理出答案要好得多。

实现使用带有故意精简的builtins命名空间的exec()。我们完全替换builtins而不是黑名单个别函数,这意味着open、eval、exec、compile、import、input以及任何不在白名单中的函数在代码片段内部根本不存在。我们预导入math和statistics到片段的全局变量中,因为模型会经常使用它们,我们不希望强迫它对抗import限制。我们使用contextlib.redirect_stdout捕获stdout,以便模型获得其代码片段打印的确切输出。

空输出分支比看起来更重要。小型模型通常会写像x = sum(range(101))这样的表达式,然后忘记print(x)。返回特定的错误告诉它们使用print()为编排循环提供了重试选项;否则,模型将基于空字符串综合出最终答案并自信地编造一个值。

关于安全性的最后说明:这是一个学习沙盒,不是加固的。一个坚定的攻击者可以通过许多方式突破Python exec沙盒,其中大多数涉及通过().class.mro进行对象内省。对于在你自己笔记本电脑上运行的单用户智能体,白名单足够了。对于其他任何情况,你需要真正的隔离层——带seccomp的子进程、容器或RestrictedPython。

编排循环

主循环在结构上与前一个教程保持不变。模型使用用户提示和工具注册表进行查询,如果它响应tool_calls,则每个调用都针对TOOL_FUNCTIONS进行分派。一旦每个工具结果作为“role”: “tool”条目追加到消息历史中,我们使用丰富后的载荷重新调用Ollama,模型生成其基于事实的最终答案。相同的两轮模式,相同的逻辑。

测试工具

现在我们对工具进行测试。通过实际交互,我们可以观察模型如何自主决定调用文件浏览或代码执行工具,从而展示真正的智能体行为。