简介:本文系统讲解 Spring AI 中 @Tool 注解的底层原理与完整执行链路,涵盖工具扫描注册、参数解析、调度回调、结果返回以及与 Agent 的联动机制。结合金融场景四大常用工具(估值计算、风险指标、财务数据查询、格式化输出),提供完整可运行的代码示例与企业级落地建议,帮助开发者深入理解如何将大模型从语言模型转化为可执行业务动作的行动模型。
@Tool 是 Spring AI 框架中用于将普通 Java 方法暴露为大模型可调用工具的注解机制。 从定义上看,@Tool 标注的方法会被框架自动扫描、注册并纳入大模型的工具调用候选列表。当模型在推理过程中判断需要执行特定计算或访问外部系统时,框架会拦截模型的工具调用指令,通过反射机制激活对应方法,并将执行结果以结构化消息返回给模型,供其生成最终的自然语言回答。
从使用视角来看,@Tool 让开发者无须关注模型工具调用的底层协议细节,只需专注于业务逻辑本身。从架构视角来看,@Tool 是连接大模型推理能力与外部执行能力的桥梁,它将模型的理解能力与代码的可计算性、可验证性结合起来,从而解决模型本身无法精确执行操作的天然局限。
传统大模型应用存在三类突出矛盾:
第一,模型只能生成文本,无法执行确定性操作。 当业务场景要求精确计算估值、查询数据库、调用第三方接口时,模型自身无法完成,会给出过于概括甚至错误的回答。以金融场景为例,如果用户询问某只股票的 DCF 估值,模型可能给出一个基于训练数据的模糊数字,而不是基于实时财务数据的计算结果。
第二,模型存在事实性幻觉风险。 在处理需要访问实时数据或领域公式的场景时,模型倾向于“编造”合理但错误的答案。金融场景中,估值倍数、风险指标、历史波动率等数据如果依赖于模型记忆,将带来不可接受的风险。
第三,模型的输出格式不可预期。 当业务系统需要将模型输出直接接入下游流程(如报送、审计、对账)时,非结构化的文本内容难以被系统可靠解析。
@Tool 机制的意义在于:将大模型从“会说话的大脑”升级为“能做事的行动体”。 它使得模型可以调用经过身份鉴权、参数校验、逻辑验证和权限控制的方法,从而获得确定的计算结果、真实的数据访问和可追溯的执行记录。
@Tool 注解支持定义工具的名称和描述。其中,名称用于在工具调用协议中唯一标识该工具;描述则作为模型决策的重要依据,模型通过阅读描述来判断当前请求是否需要调用该工具。一个优秀的描述应当完整说明工具的功能边界、使用条件、输入输出含义,从而提升模型调用的准确率。
@Tool(name = "calculateDcf", description = "计算指定股票代码的DCF估值,需要输入股票代码和可选增长率参数")public String calculateDcf(String stockCode, Double growthRate) {// 业务实现}
Spring AI 的工具调度器会解析方法签名中声明的参数类型,并在模型输出调用请求时,将模型生成的 JSON 参数体结构化解码为 Java 对象。框架支持基础类型、包装类型、字符串、复杂对象乃至嵌套对象的自动映射。参数定义越严格,模型生成合法参数的概率越高。
public record DcfRequest(String stockCode, Double growthRate, Integer forecastYears) {}@Tool(description = "DCF估值计算,输入股票代码、增长率与预测年限")public String calculateDcf(DcfRequest request) {// 从 request 中取参}
当应用启动时,Spring AI 的自动配置模块会扫描 Spring 容器中所有带有 @Tool 注解的方法,为其生成对应的工具描述信息(名称、说明、参数 Schema),并注册到 ToolCallbackProvider 中。该 Provider 作为工具注册中心的抽象接口,供推理链路按需查找和调用工具。
在 Spring AI 的 Agent 架构中,@Tool 通常与模型上下文组装器配合使用。Agent 在组装 Prompt 时会将当前应用注册的全部工具描述一并发送给模型;模型根据用户问题与工具描述之间的匹配度来决定是否调用工具。Skill 则可以理解为业务技能的封装层,而 @Tool 提供的是更底层的可执行单元。二者天然的协同关系让企业可以将复杂业务流程拆分为多个可组合的工具调用链。
工具调用过程可以分为以下七个阶段:
1. 应用启动 -> Spring 扫描 @Tool 方法 -> 生成工具描述元数据 -> 注册到工具回调提供者2. 用户发起请求 -> 例如“计算某公司 DCF 估值”3. Agent 组装请求 -> 将工具列表、系统指令、历史消息一并发送给模型4. 模型推理决策 -> 判断需要调用 calculateDcf -> 输出结构化调用指令5. 框架拦截解析 -> 识别工具调用标记 -> 完成参数解码 -> 反射执行方法6. 结果回传模型 -> 模型基于工具返回值生成自然语言回答7. 结果输出用户 -> 支持流式传输或一次性返回
模型并非通过硬编码逻辑来选择工具,而是依赖工具描述与用户问题的语义相关性。工具描述越准确,模型选择命中率越高。Spring AI 在向模型发送消息时,会将工具列表构建为符合模型工具调用规范的结构化对象,模型在其输出结果中显式标注需要调用的工具名称及参数字典。
框架在拿到模型生成的调用参数后,会遵循 JSON Schema 进行校验。类型不匹配、必填参数缺失、格式非法等情况会被捕获并返回给模型,提示其修正参数后再次尝试。这种“多轮补全”模式极大提高了任务完成的准确率。
DCF(现金流量折现)是金融分析中使用最广泛的估值方法。模型中不应直接计算复杂公式,也缺乏财务预测能力,因此需要专门的工具实现。
@Componentpublic class DcfValuationTool {@Tool(name = "dcf_valuation", description = "基于自由现金流预测计算公司DCF估值,参数包含股票代码、预测年限(默认5年)、永续增长率(默认2.5%)")public String calculateDcf(String stockCode, Integer years, Double perpetualGrowthRate) {double freeCashFlow = queryBaseCashFlow(stockCode); // 从数据服务获取基础现金流double discountRate = 0.10; // 简化的折现率模型double pv = 0d;for (int i = 1; i <= years; i++) {pv += freeCashFlow * Math.pow(1 + 0.05, i - 1) / Math.pow(1 + discountRate, i);}double terminalValue = freeCashFlow * (1 + perpetualGrowthRate) / (discountRate - perpetualGrowthRate);pv += terminalValue / Math.pow(1 + discountRate, years);return "按 " + years + " 年预测期计算,该标的 DCF 预估内在价值为 " + String.format("%.2f", pv) + " 万元";}private double queryBaseCashFlow(String stockCode) {// 接入财务数据服务,这里为示意return 1000d;}}
风险指标工具负责计算夏普比率、最大回撤、波动率等。这些指标依赖历史价格序列,模型无法自行计算,必须通过工具完成。
@Tool(name = "risk_metrics", description = "根据股票代码计算近一年波动率、夏普比率与最大回撤,用于量化风险分析")public String calculateRiskMetrics(String stockCode) {List<Double> returns = fetchHistoricalReturns(stockCode);double mean = returns.stream().mapToDouble(Double::doubleValue).average().orElse(0);double variance = returns.stream().mapToDouble(r -> Math.pow(r - mean, 2)).average().orElse(0);double volatility = Math.sqrt(variance);double sharpe = (mean - 0.02) / volatility;double maxDrawdown = computeMaxDrawdown(returns);return String.format("年化波动率:%.2f,夏普比率:%.2f,最大回撤:%.2f", volatility, sharpe, maxDrawdown);}
面向数据库或内部数据服务,使模型具备实时查询财务指标的能力。这是消除幻觉的核心手段之一。
@Tool(name = "query_financial_metric", description = "查询指定股票的最新财务指标,如营收、利润、市盈率等。输入指标名称与股票代码")public String queryMetric(String stockCode, String metricName) {// 转换为 SQL 或调用指标服务,返回精确值return metricName + " = " + metricService.query(stockCode, metricName);}
将模型结果或计算结果组装为固定格式的 JSON/HTML 报告,满足下游系统自动化接入需求。
@Tool(name = "build_valuation_report", description = "将估值结果与风险指标整合为结构化的JSON报告")public String buildReport(String stockCode, String dcfResult, String riskResult) {Map<String, Object> report = new HashMap<>();report.put("type", "valuation_report");report.put("stockCode", stockCode);report.put("dcf", dcfResult);report.put("risk", riskResult);return new ObjectMapper().writeValueAsString(report);}
@Tool 是 Spring AI 对模型 Function Calling 协议的抽象与封装。 模型原生的 Function Calling 是通用的工具调用协议,而 @Tool 将其转化为面向业务方法级的声明式编程体验,开发者无须了解协议细节即可接入。
Agent 是更高层次的决策框架,Agent 负责理解目标、制定计划、维护记忆、决定调用哪些工具以及如何编排工具的执行顺序。@Tool 则是 Agent 手中可用的“能力单元”。一次 Agent 运行可能涉及多次 @Tool 调用。
模型的工具选择高度依赖描述文本。描述应包含清晰的触发条件、参数含义、返回值约束、典型调用示例。建议为每个工具编写 30~50 字的精炼描述。
工具粒度过粗会导致模型难以选择;粒度过细会增加调用次数和上下文长度。建议按业务能力域聚合,例如“估值类工具”“风险类工具”“数据查询类工具”。
企业环境必须对工具调用进行鉴权与审计。建议实现统一的调用拦截器,记录调用参数、执行耗时、返回结果摘要。涉及资金交易或数据修改的工具,必须增加二次确认机制,严禁模型直接执行高风险操作。
工具执行可能由于服务不稳定而超时或失败。在实现时,应为耗时操作设置显式的超时时间,并将异常转化为清晰的结构化错误信息返回给模型,供其向用户说明失败原因,避免出现“用户不知道发生了什么的”交互。
@Tool 是 Spring AI 中最具落地价值的机制之一。它统一了模型推理与代码执行的边界,让大模型应用不局限于内容生成,而是深入业务执行与数据操作层面。通过合理的工具设计、参数规划与流程协同,可以将大模型从辅助对话助手升级为企业核心业务流程的智能执行单元。对于金融等对精确性、可追溯性要求极高的行业,@Tool 并非可选项,而是迈向可靠智能应用的关键基础设施。