一、核心概念

Function Calling(也叫 Tools 工具调用)是 LangChain4j 中让大语言模型(LLM)调用外部工具 / 函数的能力,用于弥补 LLM 本身的短板(如数学运算、数据查询、业务系统对接等)。核心逻辑:LLM 分析用户问题 → 判断是否需要调用工具 → 自动组装参数调用工具 → 获取工具返回结果 → 整理成自然语言回复用户。

二、入门案例:数学计算工具

以 “大模型不擅长数学运算,调用自定义计算器工具” 为例,完整实现步骤如下:

2.1 1. 创建工具类(标注 @Tool 注解)

工具类中的方法通过 @Tool 注解标记为可被 LLM 调用的工具,支持静态 / 非静态方法、任意访问权限,可注入 Spring 容器(@Component)。

package com.atguigu.java.ai.langchain4j.tools;

import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.agent.tool.ToolMemoryId;
import org.springframework.stereotype.Component;

/**
 * 计算器工具类(演示Function Calling核心用法)
 */
@Component // 注入Spring容器,方便后续配置
public class CalculatorTools {

    // 基础版工具方法
    @Tool // 标记为工具方法,默认使用方法名作为工具名称
    double sum(double a, double b) {
        System.out.println("调用加法运算");
        return a + b;
    }

    @Tool
    double squareRoot(double x) {
        System.out.println("调用平方根运算");
        return Math.sqrt(x);
    }

    // 进阶版:带注解增强的工具方法(推荐)
    @Tool(
        name = "加法",          // 自定义工具名称(替代默认方法名)
        value = "返回两个参数相加之和" // 工具描述,帮助LLM理解用途
    )
    double sumEnhance(
        @ToolMemoryId int memoryId, // 绑定会话记忆ID,区分不同用户/会话
        @P(value="加数1", required = true) double a, // 参数描述+必填校验
        @P(value="加数2", required = true) double b
    ) {
        System.out.println("调用加法运算 " + memoryId);
        return a + b;
    }

    @Tool(
        name = "平方根",
        value = "返回给定参数的平方根"
    )
    double squareRootEnhance(
        @ToolMemoryId int memoryId, 
        @P(value="被开方数", required = true) double x
    ) {
        System.out.println("调用平方根运算 " + memoryId);
        return Math.sqrt(x);
    }
}

2.2 2. 配置 AI 服务(绑定工具类)

@AiService 注解中通过 tools 属性指定要绑定的工具类(Spring Bean 名称),使 LLM 能调用该工具类的方法。

java

运行

import dev.langchain4j.service.AiService;
import static dev.langchain4j.service.spring.AiServiceWiringMode.EXPLICIT;

/**
 * 绑定工具的AI服务接口
 */
@AiService(
    wiringMode = EXPLICIT,
    chatModel = "qwenChatModel",       // 指定使用的大模型(如通义千问)
    chatMemoryProvider = "chatMemoryProvider", // 会话记忆提供者
    tools = "calculatorTools"          // 绑定计算器工具类(Spring Bean名称)
)
public interface SeparateChatAssistant {
    // 核心聊天方法(带会话记忆)
    String chat(@MemoryId int memoryId, @UserMessage String userMessage);
}

2.3 3. 测试工具调用

通过测试类验证 LLM 能否自动识别并调用工具完成数学运算。

package com.atguigu.java.ai.langchain4j;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class ToolsTest {

    @Autowired
    private SeparateChatAssistant separateChatAssistant;

    @Test
    public void testCalculatorTools() {
        // 用户提问:包含加法和平方根运算
        String answer = separateChatAssistant.chat(1, "1+2等于几,475695037565的平方根是多少?");
        // 预期输出:3,689706.4865(LLM调用工具计算后整理的结果)
        System.out.println(answer);
    }

    @Test
    public void testCalculatorToolsEnhance() {
        // 调用带@ToolMemoryId和@P的工具方法
        String answer = separateChatAssistant.chat(2, "5+8等于几,100的平方根是多少?");
        // 控制台会打印:调用加法运算 2 → 调用平方根运算 2
        System.out.println(answer); // 预期输出:13,10
    }
}

2.4 4. 工具调用流程解析

flowchart TD
    A[用户提问] --> B[构造UserMessage发送给LLM]
    B --> C[LLM分析问题:需要调用工具]
    C --> D[生成ToolExecutionRequests:组装参数调用对应工具方法]
    D --> E[工具方法执行(如sum/平方根),返回结果]
    E --> F[构造ToolExecutionResultMessage发送给LLM]
    F --> G[LLM整理工具结果,生成自然语言回复]
    G --> H[返回AiMessage给用户]

关键消息类型

  • SystemMessage:系统提示词(定义 AI 角色);
  • UserMessage:用户提问;
  • AiMessage(工具调用请求):包含 toolExecutionRequests,告知要调用的工具和参数;
  • ToolExecutionResultMessage:工具执行结果;
  • AiMessage(最终回复):LLM 基于工具结果整理的自然语言答案。

三、核心注解详解

3.1 1. @Tool 注解(标记工具方法)

用于标记可被 LLM 调用的方法,可选字段:

表格

字段 作用 默认值
name 工具名称,帮助 LLM 识别工具用途 方法名
value 工具描述,详细说明工具功能,推荐必写(提升 LLM 调用准确性) 空字符串

3.2 2. @P 注解(标记工具方法参数)

用于描述工具方法的参数,帮助 LLM 理解参数含义并正确传参,必填字段为 value

表格

字段 作用 默认值
value 参数描述(如 “加数 1”“被开方数”),必填 -
required 标记参数是否为必需项,LLM 会校验必填参数是否缺失 true

3.3 3. @ToolMemoryId 注解(绑定会话记忆 ID)

  • 作用:将 AI 服务方法中 @MemoryId 注解的参数值,自动传递给工具方法的 @ToolMemoryId 参数;
  • 适用场景:多用户 / 多会话场景,在工具方法中区分不同用户的会话,例如记录日志、隔离数据等;
  • 使用条件:AI 服务方法必须有 @MemoryId 参数,工具方法才能使用 @ToolMemoryId

四、硅谷小智集成工具调用(扩展)

结合之前的 “硅谷小智” 医疗客服场景,可通过 Function Calling 对接真实业务系统:

// 挂号工具类
@Component
public class RegistrationTools {

    @Tool(
        name = "查询号源",
        value = "根据科室和日期查询协和医院的挂号号源情况"
    )
    String queryRegistrationSource(
        @ToolMemoryId Long memoryId,
        @P(value="科室名称", required = true) String department,
        @P(value="预约日期", required = true) String date
    ) {
        // 对接医院挂号系统,查询号源
        return "消化内科2025-04-14上午剩余号源:5个,下午剩余号源:8个😜";
    }

    @Tool(
        name = "预约挂号",
        value = "为用户预约协和医院指定科室、日期、时间的号源"
    )
    String register(
        @ToolMemoryId Long memoryId,
        @P(value="姓名", required = true) String name,
        @P(value="身份证号", required = true) String idCard,
        @P(value="科室名称", required = true) String department,
        @P(value="预约日期", required = true) String date,
        @P(value="预约时间", required = true) String time,
        @P(value="医生姓名", required = false) String doctor
    ) {
        // 对接医院挂号系统,执行预约逻辑
        return "已为" + name + "预约" + date + time + department + doctor + "的号源✅,请携带身份证就诊!";
    }
}

// 小智AI服务绑定挂号工具
@AiService(
    wiringMode = EXPLICIT,
    chatModel = "qwenChatModel",
    chatMemoryProvider = "chatMemoryProviderXiaozhi",
    tools = {"registrationTools"} // 绑定挂号工具类
)
public interface XiaozhiAgent {
    String chat(@MemoryId Long memoryId, @UserMessage String userMessage);
}

// 测试
@Test
public void testRegistrationTool() {
    String answer = xiaozhiAgent.chat(1L, "帮我查一下消化内科2025-04-14的号源");
    System.out.println(answer); // 输出工具返回的号源信息
}

五、核心总结

  1. Function Calling 用于弥补 LLM 短板,核心是通过 @Tool 标记工具方法,在 @AiService 中绑定工具类;
  2. @Toolname/value@P 注解能提升 LLM 调用工具的准确性,@ToolMemoryId 支持多会话隔离;
  3. 工具调用流程:用户提问 → LLM 判定调用工具 → 执行工具方法 → LLM 整理结果回复,关键是 LLM 自动完成 “是否调用”“如何传参” 的决策。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐