让大模型“能动手”到底是救命还是作妖:你敢把执行权交给它吗?

举报
bug菌 发表于 2026/01/13 15:44:19 2026/01/13
【摘要】 🏆本文收录于《滚雪球学SpringBoot 3》:https://blog.csdn.net/weixin_43970743/category_12795608.html,专门攻坚指数提升,本年度国内最系统+最专业+最详细(永久更新)。  本专栏致力打造最硬核 SpringBoot3 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。...

🏆本文收录于《滚雪球学SpringBoot 3》:https://blog.csdn.net/weixin_43970743/category_12795608.html,专门攻坚指数提升,本年度国内最系统+最专业+最详细(永久更新)。
  
本专栏致力打造最硬核 SpringBoot3 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。 如果想快速定位学习,可以看这篇【SpringBoot3教程导航帖】https://blog.csdn.net/weixin_43970743/article/details/151115907,你想学习的都被收集在内,快速投入学习!!两不误。
  
若还想学习更多,可直接前往《滚雪球学SpringBoot(全版本合集)》:https://blog.csdn.net/weixin_43970743/category_11599389.html,涵盖SpringBoot所有版本教学文章。

演示环境说明:

  • 开发工具:IDEA 2021.3
  • JDK版本: JDK 17(推荐使用 JDK 17 或更高版本,因为 Spring Boot 3.x 系列要求 Java 17,Spring Boot 3.5.4 基于 Spring Framework 6.x 和 Jakarta EE 9,它们都要求至少 JDK 17。)
  • Spring Boot版本:3.5.4(于25年7月24日发布)
  • Maven版本:3.8.2 (或更高)
  • Gradle:(如果使用 Gradle 构建工具的话):推荐使用 Gradle 7.5 或更高版本,确保与 JDK 17 兼容。
  • 操作系统:Windows 11

前言

我第一次把“函数调用”接进业务系统的时候,心情很复杂:一方面像给模型装上了手脚——它终于不只是“嘴强王者”;另一方面又有点发怵:**这玩意儿要是被提示注入忽悠了,岂不是能把我数据库当游乐场?**😅

所以这篇我按你的大纲来:讲清原理、给你 Spring Boot 3 的 Java 实现(天气 API / 数据库查询两套示例),最后认真聊安全边界,别让“执行力”变成“破坏力”。

先提醒一句:Spring AI 生态里“Function Calling”这套 API 在新版本里逐步向 Tool Calling(工具调用)迁移,底层概念一致:模型只会请求调用工具,真正执行发生在你应用侧。Spring AI 官方参考把这条链路讲得很清楚。
OpenAI 官方也强调:你给模型一组 tools(JSON schema 描述),模型会返回工具调用请求,你的应用执行并把结果回传。

1)让大模型具备“执行力”:到底发生了什么?

把它想象成一场“带脚本的对话”,分 6 步走(这 6 步非常关键,理解了你就不容易被玄学带跑偏):

  1. 你发起一次聊天请求,同时告诉模型:“你可以用这些工具(函数)。”(每个工具有名称、描述、入参 schema)
  2. 模型判断自己需要外部信息/动作(比如实时天气、查库),于是返回一个工具调用请求:工具名 + JSON 入参。
  3. 你的应用根据工具名找到对应的 Java 函数/方法
  4. 你的应用执行真实逻辑(调用天气服务、跑 SQL、访问内部系统)。
  5. 你的应用把执行结果回传给模型(作为额外上下文)。
  6. 模型基于工具结果生成最终自然语言回答

重点来了(别忽略!):

  • 模型不会真的“直接访问你的数据库/网络”。它只是“提出调用请求”,执行权永远在你服务端。
  • 所以你要把它当成一个“会写调用意图的实习生”:能干活,但必须上锁、加审批、留审计😄。

2)定义 Java Function 并注册为 Spring Bean(最常用、最稳的姿势)

Spring AI 的理念是:你把函数作为 Spring Bean 暴露出来,框架帮你做“工具描述 + 回调编排”的样板工作。旧的 FunctionCallback/Function Calling 文档也这么描述(虽然新版本更推荐 Tool Calling 命名)。

下面我用Tool Calling方式来写(更贴近新版本参考),但你会发现结构跟 Function Calling 几乎一模一样。

2.1 天气查询工具(外部 API / 你自己的 WeatherClient)

Step A:定义入参/出参 record(强烈建议这么做,清晰又可校验)

public record WeatherRequest(String location, String unit) {} // unit: "C" or "F"
public record WeatherResponse(double temp, String unit, String description) {}

Step B:实现工具(Function)并注册为 Bean

import java.util.function.Function;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ToolsConfig {

  @Bean(name = "get_weather")
  public Function<WeatherRequest, WeatherResponse> getWeatherTool(WeatherClient weatherClient) {
    return req -> {
      // 这里你可以调用真实天气 API,也可以先 mock
      var data = weatherClient.query(req.location(), req.unit());
      return new WeatherResponse(data.temp(), req.unit(), data.summary());
    };
  }
}

Spring AI 会把这个 Function 包装成可供模型调用的 ToolCallback(概念上就是“工具”),并在模型返回工具调用时自动回调执行。


3)模型自动回调:让 GPT 调用你的天气 API 或数据库查询方法

这里分两种常见形态:

  • A:Function 作为 Tool(上面那种)
  • B:直接把某个 Java 方法暴露为 Tool(更细粒度,也更“像写业务”)

3.1 用 ChatClient 发起请求,并“允许”使用哪些工具(关键:白名单!)

Spring AI 工具调用参考强调:你可以传 ToolCallback 对象,或者只传工具名,让框架运行时解析。

伪代码示例(表达意图为主,不纠结具体包名的小版本差异):

@RestController
public class AssistantController {

  private final ChatClient chatClient;

  public AssistantController(ChatClient.Builder builder) {
    this.chatClient = builder.build();
  }

  @GetMapping("/ask")
  public String ask(@RequestParam String q) {
    return chatClient.prompt()
        .user(q)
        // 重点:只允许本次对话使用 get_weather 这个工具
        .tools("get_weather")
        .call()
        .content();
  }
}

你看,这里真正的“权限开关”是你服务端控制的:你不把工具放进 tools 列表,它就算嘴上想调用,也没门

3.2 数据库查询工具:让模型“查数据”,但别让它“随便查”

先说我的底线:不要给模型一个“通用 SQL 执行器”(比如入参是 sql: "select * from ...")。这相当于把方向盘交给一个会背交通规则但没驾照的人🚗💥。

正确做法:定义“业务化”的查询工具(参数化、可控字段)

入参/出参:

public record UserLookupRequest(Long userId) {}
public record UserLookupResponse(Long userId, String name, String status) {}

工具实现:

@Bean(name = "get_user_by_id")
public Function<UserLookupRequest, UserLookupResponse> getUserByIdTool(UserRepository repo) {
  return req -> repo.findById(req.userId())
      .map(u -> new UserLookupResponse(u.getId(), u.getName(), u.getStatus()))
      .orElseThrow(() -> new IllegalArgumentException("User not found"));
}

调用:

return chatClient.prompt()
  .system("你是客服助手。需要用户信息时可以调用 get_user_by_id,但不得暴露敏感字段。")
  .user("帮我查一下用户 123 的状态,并用一句话解释。")
  .tools("get_user_by_id")
  .call()
  .content();

这样模型即使想“扩展查询范围”,也只能在你定义的输入 schema 里活动。工具调用的输入 schema/工具定义就是你的“围栏”。

4)安全性思考:限制 AI 的执行权限(这块不做,迟早要还债🙂)

下面这部分我写得稍微“啰嗦”点,因为它真的是上线分水岭。

4.1 工具白名单:每次请求只给“必要工具”

  • 不要默认把所有工具都挂上(特别是“写操作”工具)。
  • 同一个 ChatClient 可以按场景切不同 tools 列表。

经验话术

“能不用工具就不用;要用也只用这一把扳手,别把整个工具箱扔给模型。”

4.2 只暴露“业务能力”,不要暴露“底层能力”

✅ 推荐:get_user_by_id(userId)search_orders(status, from, to)
❌ 不推荐:execute_sql(sql)http_fetch(url)(除非你做了极强的域名/路径限制)

原因很简单:工具调用就是“执行入口”。OpenAI/Spring AI 的机制决定了——模型可以提出调用请求,你的应用会执行。你暴露得越底层,越容易被提示注入绕开业务限制。

4.3 对入参做严格校验:schema + 运行时校验双保险

  • schema(record 字段)只能限制形状
  • 运行时还要限制:长度、枚举、范围、正则、名单

例如 location 只允许城市名,不允许塞 URL;userId 必须是正整数;分页大小必须有上限。

4.4 工具执行要“最小权限”

  • 查库用只读账号(能读就别给写)
  • 写操作必须额外鉴权(比如用户确认、管理员角色、二次校验)
  • 对外 HTTP 调用限制目标域名(allowlist),防 SSRF

4.5 审计与可追溯:记录 tool_name + arguments + caller + result 摘要

你要能回答这三个问题:

  1. 谁触发的?2) 调了什么工具?3) 用了什么参数?
    出了事能定位,才叫“可控执行力”。

4.6 提示注入防线:把模型当“不可信输入”

  • 用户输入里如果出现“忽略系统指令、改用某工具、把数据库全导出”——你要靠工具白名单 + 参数校验挡住
  • 系统提示里明确:什么能做、什么不能做、敏感信息不返回
  • 重要动作要求人类确认(Human-in-the-loop)

🧧福利赠与你🧧

  无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。

最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G PDF编程电子书、简历模板、技术文章Markdown文档等海量资料。

ps:本文涉及所有源代码,均已上传至Gitee:https://gitee.com/bugjun01/SpringBoot-demo 开源,供同学们一对一参考 Gitee传送门https://gitee.com/bugjun01/SpringBoot-demo,同时,原创开源不易,欢迎给个star🌟,想体验下被🌟的感jio,非常感谢❗

🫵 Who am I?

我是 bug菌:

  • 热活跃于 CSDN:https://blog.csdn.net/weixin_43970743 | 掘金:https://juejin.cn/user/695333581765240 | InfoQ:https://www.infoq.cn/profile/4F581734D60B28/publish | 51CTO:https://blog.51cto.com/u_15700751 | 华为云:https://bbs.huaweicloud.cn/community/usersnew/id_1582617489455371 | 阿里云:https://developer.aliyun.com/profile/uolxikq5k3gke | 腾讯云:https://cloud.tencent.com/developer/user/10216480/articles 等技术社区;
  • CSDN 博客之星 Top30、华为云多年度十佳博主&卓越贡献奖、掘金多年度人气作者 Top40;
  • 掘金、InfoQ、51CTO 等平台签约及优质作者;
  • 全网粉丝累计 30w+

更多高质量技术内容及成长资料,可查看这个合集入口 👉 点击查看:https://bbs.csdn.net/topics/612438251 👈️
硬核技术公众号 「猿圈奇妙屋」https://bbs.csdn.net/topics/612438251 期待你的加入,一起进阶、一起打怪升级。

- End -

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。