乐于分享
好东西不私藏

Spring AI @Tool 机制原理与四大金融工具实现

Spring AI @Tool 机制原理与四大金融工具实现

导读

在 AI 智能体系统里,让大模型 “会动手” 比 “会说话” 更重要

只会聊天的 AI 只能做客服;能自动调用工具、执行计算、处理数据的 AI,才能干金融、医疗、法律、研发的硬核活。

而在 Spring AI 生态中,@Tool 就是打通 “大模型 → 代码执行” 的关键钥匙

这一篇我们彻底讲透:

@Tool 到底是什么、Spring AI 如何扫描、如何传参、如何回调、如何返回、如何和 Skill/Agent 联动,并且完整实现金融领域最常用的四大工具

全文 3000 字以上、带原理图解、执行流程图、完整可运行代码、企业级最佳实践。

一、为什么必须用 @Tool 机制?

1.1 没有 Tool,大模型就是 “瘸腿”

传统大模型调用有三个致命问题:

  1. 只会说不会干
    无法做精确计算、无法查数据库、无法调用接口
  2. 幻觉严重
    金融估值、风险指标随口编
  3. 不可控
    输出格式不固定,业务无法对接

根本原因:大模型本身不是执行引擎,它需要 “手脚”。

1.2 Tool 到底是什么?

Tool = 一段可被大模型自动调用的结构化函数。

它有明确的:

  • 功能描述
  • 输入参数
  • 输出格式
  • 执行逻辑

大模型通过理解用户问题 → 判断是否需要工具 → 生成调用参数 → 交给框架执行 → 拿回结果 → 组织语言回答

1.3 Spring AI @Tool 的核心价值

  1. 零代码接入
    一个注解搞定,不用写协议
  2. 自动扫描注册
    启动即生效
  3. 参数自动解析
    JSON / 对象自动映射
  4. 流式 / 非流式兼容
    无缝对接 SSE
  5. 与 Skill/Agent 天然联动
    企业级直接落地
  6. 金融级安全可控
    白名单、权限、审计

一句话:

@Tool 让大模型从 “语言模型” 变成 “行动模型”。

二、@Tool 执行全流程原理(图文)

2.1 工具调用完整流程

1. 启动应用   ↳ Spring 扫描所有 @Tool 方法   ↳ 生成工具描述:名称、入参、说明   ↳ 注册到 ToolCallbackProvider2. 用户发起提问   ↳ 例如:帮我算一下贵州茅台 DCF 估值3. Agent 构建 Prompt   ↳ 把系统描述 + 技能 + 工具列表一起发给 LLM4. LLM 做决策   ↳ 判断:需要调用 calculateDcf   ↳ 输出结构化调用指令(JSON)5. Spring AI 自动拦截解析   ↳ 识别工具调用   ↳ 参数反射映射   ↳ 执行对应 Java 方法6. 执行结果返回给 LLM   ↳ LLM 整理成自然语言7. 流式返回给用户

2.2 核心原理图解

用户 → Controller → Agent → ChatClient → LLM                                          ↑                                          ↓Spring AI Tool 调度器 ← 调用 → @Tool 方法(Java)

2.3 为什么要用 @Tool,而不是自己写调用?

  • 不用手动解析 LLM 返回
  • 不用处理复杂函数调用协议
  • 不用做参数类型转换
  • 不用维护工具列表
  • 天然支持多工具、并行调用
  • 完全和 Spring 生态融合

三、@Tool 核心注解与使用规则

3.1 @Tool 注解源码(简化)

@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Tool {    // 工具名称,默认取方法名    String name() default "";    // 工具描述(给大模型看,必须写清楚)    String description();}

3.2 最关键:description 怎么写?

这是大模型能否正确调用的决定性因素

格式:

功能说明 + 适用场景 + 参数说明

示例:

@Tool(description = "DCF现金流折现估值,参数:cashFlows未来现金流数组、discountRate折现率、terminalGrowth永续增长率、sharesOutstanding总股本(亿股)")

3.3 方法定义规则

  1. 返回 String
    最稳定,大模型容易理解
  2. 参数简单
    int/double/ 数组 / 字符串,不要复杂对象
  3. 方法必须 public
  4. 类必须加 @Component
  5. 异常内部捕获
    不要抛到外层

四、Spring AI 扫描与注册机制(底层原理)

4.1 扫描流程

  1. Spring 启动
  2. 寻找所有 Bean 中带有 @Tool 注解的方法
  3. 生成 ToolDefinition(名称、描述、参数列表)
  4. 注册到 DefaultToolCallbackProvider
  5. 每次调用 ChatClient 时,自动把工具列表注入 Prompt

4.2 关键:工具如何传给大模型?

框架自动拼接:

你拥有以下工具:1. calculateDcf:DCF现金流折现估值...   参数:cashFlows: array, discountRatenumber ...

你完全不用写这段 Prompt。

4.3 大模型如何返回调用指令?

LLM 会返回类似格式:

{  "name": "calculateDcf",  "parameters": {    "cashFlows": [100,200,300],    "discountRate": 0.1,    "terminalGrowth": 0.03,    "sharesOutstanding": 12.56  }}

Spring AI 自动解析,直接调用你的 Java 方法。

五、企业级金融工具类完整实现(可直接上线)

我们构建一个 FinancialTools 类,统一管理所有金融计算工具。

5.1 类声明

@Slf4j@Component@RequiredArgsConstructorpublic classFinancialTools{    private final PythonScriptExecutor scriptExecutor;    // 下面放 4 个核心 Tool}

5.2 Tool 1:DCF 估值计算(最核心)

@Tool(description = "DCF现金流折现估值,用于计算股票内在价值。参数:cashFlows未来现金流数组、discountRate折现率(如0.1表示10%)、terminalGrowth永续增长率(如0.03表示3%)、sharesOutstanding总股本(单位:亿股)")public String calculateDcf(        double[] cashFlows,        double discountRate,        double terminalGrowth,        double sharesOutstanding) {    log.info("[Tool调用] DCF估值");    try {        PythonScriptExecutor.ScriptResult result = scriptExecutor.executeDcfCalculator(                cashFlows,                discountRate,                terminalGrowth,                sharesOutstanding        );        if (result.isSuccess()) {            return result.getOutput();        } else {            return "DCF计算失败:" + result.getError();        }    } catch (Exception e) {        log.error("DCF异常", e);        return "DCF计算异常:" + e.getMessage();    }}

5.3 Tool 2:技术指标计算(MA、RSI、MACD)

@Tool(description = "计算股票技术指标,包括MA移动平均线、RSI相对强弱、MACD。参数:prices 历史收盘价数组,建议至少30个数据点")public String calculateTechnicalIndicators(double[] prices) {    log.info("[Tool调用] 技术指标");    try {        var result = scriptExecutor.executeTechnicalIndicators(prices);        return result.isSuccess() ? result.getOutput() : "指标计算失败:" + result.getError();    } catch (Exception e) {        log.error("技术指标异常", e);        return "计算失败";    }}

5.4 Tool 3:VaR 风险价值计算

@Tool(description = "计算投资组合VaR风险价值,评估最大可能损失。参数:portfolioValue组合价值、meanReturn日均收益率、stdDev收益率标准差、confidenceLevel置信水平(如0.95)")public String calculateVar(        double portfolioValue,        double meanReturn,        double stdDev,        double confidenceLevel) {    log.info("[Tool调用] VaR风险计算");    try {        var result = scriptExecutor.executeVarCalculator(                portfolioValue,                meanReturn,                stdDev,                confidenceLevel        );        return result.isSuccess() ? result.getOutput() : "VaR计算失败:" + result.getError();    } catch (Exception e) {        log.error("VaR异常", e);        return "计算失败";    }}

5.5 Tool 4:投资组合优化(马科维茨)

@Tool(description = "投资组合优化,基于马科维茨理论最大化夏普比率。参数:assets资产代码数组、expectedReturns预期收益率数组、riskFreeRate无风险利率(如0.03)")public String optimizePortfolio(        String[] assets,        double[] expectedReturns,        double riskFreeRate) {    log.info("[Tool调用] 投资组合优化");    try {        var result = scriptExecutor.executePortfolioOptimizer(                assets,                expectedReturns,                riskFreeRate        );        return result.isSuccess() ? result.getOutput() : "组合优化失败:" + result.getError();    } catch (Exception e) {        log.error("组合优化异常", e);        return "计算失败";    }}

六、工具如何注入 Agent 并使用?

6.1 Controller 注入工具

@RestController@RequestMapping("/api/chat")@RequiredArgsConstructorpublic class ChatController {    private final AgentRegistry agentRegistry;    private final FinancialTools financialTools;    // ...}

6.2 构建上下文,传给 Agent

Map<StringObject> context = new HashMap<>();context.put("sessionId", sessionId);context.put("tools", financialTools); // 注入工具

6.3 Agent 内部自动使用

@Overridepublic Flux<StringprocessStream(String message, Map<StringObject> context) {    Object tools = context.get("tools");    var prompt = chatClientWithSkills.prompt().user(message);    if (tools != null) {        prompt.tools(tools); // 关键:注入工具    }    return prompt.stream().content();}

全程你不需要手动处理工具调用逻辑!

七、@Tool 高级特性与生产最佳实践

7.1 工具白名单(金融安全必备)

在 Skill 中声明可调用工具:

allowed-tools: calculateDcf,calculateVar

7.2 超时控制

// 在 PythonScriptExecutor 中process.waitFor(5TimeUnit.SECONDS);

7.3 熔断保护

if (failCount > 3) {    return "工具暂时不可用";}

7.4 日志全记录

log.info("Tool调用:{},参数:{}", methodName, params);

7.5 返回格式统一(JSON)

让 Python 脚本返回固定 JSON,大模型更容易理解。

八、常见问题与避坑

8.1 Tool 不生效?

  • 类没有加 @Component
  • 方法不是 public
  • description 写得太模糊
  • 参数太复杂(如自定义对象)
  • 没有注入到 Agent

8.2 LLM 不调用 Tool?

  • description 不清晰
  • 示例不足
  • 问题和工具不匹配
  • 技能中未允许该工具

8.3 参数传不进去?

  • 类型不匹配
  • 数组格式错误
  • 缺少必填字段

8.4 中文乱码?

  • 确保 Python 输出 utf-8
  • Java 读取流使用 StandardCharsets.UTF_8

九、总结:@Tool 是企业 AI 落地的基础设施

如果你只学会 Prompt、Agent、Skill,你的 AI 还只是 “半成品”。

只有加上 @Tool 自动调用能力,AI 才真正具备业务价值。

Spring AI 的 @Tool 机制:

  • 简单:一个注解
  • 强大:自动扫描、自动调用、自动解析
  • 稳定:完全融入 Spring 生态
  • 可扩展:支持接口、数据库、消息队列、Python 计算

在金融领域,它让 AI 真正做到:

✅ 估值精准不幻觉

✅ 风控合规可审计

✅ 资产配置科学

✅ 输出格式标准化

这就是可上线、可商用、可过审的企业级 AI。

十、下篇预告

第 9 篇我们将进入金融 AI 最关键的合规部分

《金融 AI 全链路审计:日志・质检・合规・复盘一体化》

带你实现:对话审计 + AI 自动评分 + 风险检测 + 合规留存。

扫码详细了解该项目