Spring AI Function Calling 到底怎么工作:从工具声明到结果回传的调用链
本文定位Spring AI 原理 / Function Calling / Java 源码思路示例环境Java 21、Spring Boot 3.3、Spring AI 1.0.x。不同版本的类名和自动配置可能变化本文重点放在稳定的调用模型和工程边界。摘要很多 Java 开发者第一次使用 Spring AI 的工具调用能力时会觉得模型“自己执行了 Java 方法”。实际上模型从来没有直接运行代码它只是根据工具描述返回一个结构化的调用请求真正的工具查找、参数反序列化、权限校验、方法执行和结果回传都由应用程序完成。理解这条调用链很重要一旦把工具当作普通函数直接暴露就会出现参数不可信、权限缺失、重复执行和异常不可控等问题。本文从消息结构、工具注册、执行循环、结构化结果和安全校验五个层面拆解一个简化的 Java 实现。一、模型输出的不是“执行结果”而是调用意图一次典型对话包含三类消息用户消息、助手的工具调用消息、工具结果消息。模型决定调用getWeather时只会返回类似下面的结构{role:assistant,tool_calls:[{id:call-123,name:getWeather,arguments:{city:天津,date:2026-08-10}}]}应用收到这个结果后才会根据name找到工具、校验arguments、执行 Java 逻辑再把结果作为tool消息发回模型。模型随后可能继续调用其他工具也可能生成最终回答。Java ToolToolRouter模型ChatClient用户Java ToolToolRouter模型ChatClient用户问题问题 工具Schematool_call工具名 参数Schema/权限/限流校验执行方法结构化结果tool_result原问题 工具结果最终回答或下一次tool_call二、工具注册描述和执行器要分离一个可靠的工具注册表至少包含工具描述和执行函数两个部分。描述会发给模型执行函数只存在于后端。不能把 Java 方法名、数据库连接或内部异常直接暴露出去。publicrecordToolSpec(Stringname,Stringdescription,JsonNodeinputSchema,SetStringpermissions,RiskLevelriskLevel){}publicinterfaceToolExecutor{ToolSpecspec();ToolResultexecute(JsonNodearguments,AuthContextauth);}publicfinalclassToolRegistry{privatefinalMapString,ToolExecutorexecutors;publicToolExecutorrequire(Stringname){ToolExecutorexecutorexecutors.get(name);if(executornull){thrownewUnknownToolException(name);}returnexecutor;}}工具描述应当准确表达用途、输入格式和限制。例如“查询工单”要说明时间范围、最大数量和返回字段而不是使用“负责查询所有工单”这种过大的描述。描述越模糊模型越容易选择错误工具。三、参数解析不能只靠 JacksonJSON 能被反序列化成 Java 对象不代表参数就是合法业务输入。校验需要分三层结构校验字段类型、必填项、长度和枚举。安全校验路径、URL、表达式、SQL、脚本等危险输入。业务校验对象归属、状态、额度和调用者权限。publicFindTicketInputparseAndValidate(JsonNodenode,AuthContextauth){FindTicketInputinputmapper.convertValue(node,FindTicketInput.class);beanValidator.validate(input);if(input.limit()50){thrownewIllegalArgumentException(单次最多查询50条);}if(!ticketRepo.belongsToTenant(input.ticketId(),auth.tenantId())){thrownewAccessDeniedException(工单不属于当前租户);}returninput;}不要用模型返回的tenantId、operatorId或role覆盖认证上下文。工具的执行身份必须由服务端注入。四、执行循环与最大步数工具调用流程需要有最大轮次、总超时和结果大小上限否则模型可能在错误条件下反复调用。一个简化的执行器如下publicChatResultrun(StringuserText,AuthContextauth){ListMessagemessagesnewArrayList();messages.add(newUserMessage(userText));InstantdeadlineInstant.now().plus(Duration.ofSeconds(30));for(intround0;round6;round){if(Instant.now().isAfter(deadline)){returnChatResult.degraded(任务执行超时);}AssistantMessageassistantmodel.call(messages,registry.specs());messages.add(assistant);if(assistant.toolCalls().isEmpty()){returnChatResult.answer(assistant.text());}for(ToolCallcall:assistant.toolCalls()){ToolResultresultrouter.execute(call,auth);messages.add(newToolMessage(call.id(),result.truncatedView()));}}returnChatResult.degraded(工具调用次数超过限制);}这里的new ArrayList只属于一次请求的消息集合不应该把跨请求的对话对象共享在全局。每次调用都要把模型、Prompt 模板、工具版本和参数哈希写入 Trace方便后续复盘。五、工具结果要结构化和可控工具结果越自由模型越难稳定处理。建议统一成包含状态、数据、来源和是否截断的结构publicrecordToolResult(Stringstatus,Objectdata,Stringsource,booleantruncated,StringsafeErrorCode){publicToolResulttruncatedView(){Stringjsonserialize(data);if(json.length()12000)returnthis;returnnewToolResult(status,json.substring(0,12000),source,true,safeErrorCode);}}工具异常不要把数据库堆栈、内部地址和密钥信息传给模型。可以返回statusERROR、safeErrorCodeTIMEOUT和用户可理解的摘要详细错误保存在服务端日志。工具输出中的自然语言也可能包含 Prompt Injection需要和系统指令分层传递。六、并行工具调用与一致性模型可能在一次响应里返回多个工具调用。只有在工具之间没有依赖且都是只读操作时才适合并行执行。涉及写操作、库存、余额或顺序依赖时应强制串行。publicListToolResultexecuteBatch(ListToolCallcalls,AuthContextauth){if(calls.stream().anyMatch(call-registry.require(call.name()).spec().riskLevel().compareTo(RiskLevel.HIGH)0)){returncalls.stream().map(call-router.execute(call,auth)).toList();}returncalls.parallelStream().map(call-router.execute(call,auth)).toList();}并行不是默认优化。数据库连接池、第三方限流和日志顺序都可能受到影响。需要给单个请求设置并发数上限工具自身还要有超时和熔断。七、结构化输出和工具调用的区别结构化输出解决“最终回答要符合 JSON Schema”的问题Function Calling 解决“模型请求应用执行某个函数”的问题。两者可以一起使用工具调用获取数据最终回答用结构化 DTO 表达。publicrecordDiagnosticAnswer(Stringconclusion,ListStringevidence,ListStringnextActions,booleanneedsHumanReview){}不要把所有内容都做成工具调用。工具应该表达真实动作或外部数据访问纯粹的文本格式要求应该由结构化输出约束。职责清晰后测试和错误处理都会更简单。八、安全与审计每次 ToolCall 需要关联用户、租户、请求、模型、工具版本、输入哈希、权限结果、执行耗时、结果状态和重试次数。高风险工具要额外记录确认人和确认时间。工具调用审计不能记录完整敏感内容。建议保存哈希和脱敏摘要必要时把原始数据放到受控存储并设置访问审批。模型调用日志也不能绕过企业数据保留策略。九、测试清单模型选择不存在的工具时是否安全失败。工具参数缺失、类型错误、超长时是否被拦截。当前用户无权限时执行器是否完全不调用业务方法。工具超时后是否按错误类别重试且有最大次数。同一个幂等键重复执行是否返回同一个业务结果。工具返回超长文本或恶意指令时是否截断并隔离。达到最大轮次或总超时时是否给出可理解的降级结果。模型升级后工具 Schema 变化是否能被评测集发现。十、总结Function Calling 的本质是“模型提出结构化调用意图应用负责决定是否执行”。Spring AI 可以减少消息拼装和客户端适配工作但工具注册、权限、幂等、超时和审计仍然属于业务后端。理解调用链之后很多问题就会变得清晰Prompt 不是权限模型不是执行器Schema 不是业务校验重试不是可靠性能调用也不代表应该调用。把这些边界写进代码和测试才是 Java 接入 Agent 的真正价值。读者讨论你更关心工具调用的 API 使用还是工具在生产环境中的权限、幂等和审计建议先画出调用链再决定需要引入哪些框架能力。

相关新闻

IDEA 2026.2 被曝一个终端大bug:引起了开发者众怒

IDEA 2026.2 被曝一个终端大bug:引起了开发者众怒

一个令人抓狂的场景 想象一下,你正在 IDE 中专注地调试代码,想把终端窗口从底部拖到编辑器侧边栏,以便更高效地利用屏幕空间。拖拽、释放,然后——终端崩了。进程重启,历史记录丢失,你的工作流被硬生生打断…

2026/10/14 7:31:32 阅读更多 →
怎样轻松实现完整网页截图:Chrome全屏截图插件完整指南

怎样轻松实现完整网页截图:Chrome全屏截图插件完整指南

怎样轻松实现完整网页截图:Chrome全屏截图插件完整指南 【免费下载链接】full-page-screen-capture-chrome-extension One-click full page screen captures in Google Chrome 项目地址: https://gitcode.com/gh_mirrors/fu/full-page-screen-capture-chrome-exte…

2026/10/13 14:42:01 阅读更多 →
Codeforces新手参赛全指南:从环境搭建到实战避坑

Codeforces新手参赛全指南:从环境搭建到实战避坑

1. 从旁观到入局:我的Codeforces初体验第一次在Codeforces(简称CF)上按下“Register”按钮,感觉和当年第一次走进线下考场没什么两样,手心有点冒汗,心跳也快了几拍。作为一个在算法竞赛圈外徘徊了许久的程序…

2026/10/13 14:42:06 阅读更多 →

最新新闻

CMS技术演进:从静态生成到云原生架构

CMS技术演进:从静态生成到云原生架构

1. 内容管理系统的前世今生1993年,伊利诺伊大学的学生们为了管理NCSA官网的新闻更新,编写了一个简单的网页发布脚本。这个看似不起眼的工具,后来被公认为世界上第一个内容管理系统(CMS)的雏形。当时没人能预料到&#…

2026/10/14 10:45:54 阅读更多 →
agent-skills 实战:从零构建可靠的 AI Agent 能力体系

agent-skills 实战:从零构建可靠的 AI Agent 能力体系

1. 从零理解 agent-skills:它到底是什么,为什么值得关注 第一次看到 “agent-skills” 这个词,很多人会下意识把它当成某个具体框架或者某个开源库的名字。但如果你最近在关注 AI 应用开发这个圈子,会发现它其实更像是一个正在快速…

2026/10/14 10:45:54 阅读更多 →
收藏 | 超详细解析LLM与Agent,小白也能轻松入门AI开发

收藏 | 超详细解析LLM与Agent,小白也能轻松入门AI开发

本文系统介绍了LLM(大型语言模型)和AI Agent的核心概念、特点及区别。LLM是经过海量文本训练的神经网络,擅长预测文本序列,但知识静态、被动响应。AI Agent则以LLM为核心,能自主规划、调用工具、自我优化,完…

2026/10/14 10:45:54 阅读更多 →
从AI设计到CAD绘制与Bug检测:开源工具实操指南

从AI设计到CAD绘制与Bug检测:开源工具实操指南

过去两年我一直在留意一个趋势:AI 已经不是只会在聊天框里写东西了,而是真的开始进入那些需要“职业手活”的岗位。最有代表性的三个方向,就是标题里说的这三个——AI 当设计师、AI 画 CAD、AI 测 Bug。对应到开源社区里,我也确实…

2026/10/14 10:45:54 阅读更多 →
神经网络前向传播详解:从手算到Python代码实现

神经网络前向传播详解:从手算到Python代码实现

开头这200来字我得说明白一件事:很多人学神经网络,一上来就被反向传播劝退,看了一堆偏导数、链式法则就开始怀疑人生。其实大可不必。我见过太多初学者最后能啃下深度学习,靠的不是一开始就把梯度背下来,而是老老实实把…

2026/10/14 10:45:54 阅读更多 →
Shell脚本多行注释技巧与工程实践

Shell脚本多行注释技巧与工程实践

1. Shell脚本多行注释的必要性与挑战 在Bash和KornShell(KSH)脚本开发中,我们经常遇到需要临时禁用大段代码或添加详细说明文档的情况。与大多数编程语言不同,Shell脚本原生并不支持类似C语言的/* */或Python的 这样的多行注释语法…

2026/10/14 10:44:53 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →