学习路线图

Function Calling 的学习路线结构说明:

Function Calling 是 LLM 与外部世界交互的基础能力,MCP 其实是 Function Calling 的一种标准化和扩展实现。因此,Function Calling 的学习路线应该更侧重于“LLM 如何理解并执行代码逻辑”。 我将按照以下模块构建内容:

定位:Function Calling 是 LLM 将自然语言转化为结构化参数以调用预定义函数的能力,它是 LLM 的“手和脚”,让模型从“只读”变“可执行”。

解决的核心问题:幻觉、数据滞后、无法操作业务系统。

解决方案:外挂工具,模型只负责“决策”和“参数提取”,不负责“执行

构成和设计原理:Prompt Engineering (Few-shot), Schema 定义 (JSON Schema), 解析与执行循环。

工作原理:用户提问 -> LLM 识别意图 -> 输出结构化 JSON -> 代码执行 -> 结果回传 -> LLM 生成回答。

1. 定位

Function Calling 是赋予大模型(LLM)“执行力”的关键技术。

  • 定义: 它是一种让 LLM 能够理解预定义的函数(工具),并根据用户指令输出结构化数据(通常是 JSON),以便外部程序执行具体操作的技术机制。
  • 类比: 如果 LLM 是大脑,Function Calling 就是神经系统。大脑(LLM)负责思考“做什么”,神经系统(Function Calling)负责将指令传递给手脚(外部 API/代码)去执行。
  • 与 MCP 的关系: MCP 是 Function Calling 的标准化协议版本。Function Calling 是通用概念,MCP 是为了解决 Function Calling 碎片化而制定的统一标准。

2. 解决的核心问题

背景

随着大模型普及,用户不再满足于“陪聊”,而是希望 AI 能干活(查天气、订机票、查数据库)。但原生 LLM 存在先天缺陷。

技术角度的核心难题

痛点

具体表现

传统/无 Function Calling 方案缺陷

1. 知识时效性滞后

模型训练数据截止于过去,无法回答“今天北京天气”或“最新股价”。

只能依靠模型幻觉瞎编,或需要人工微调(成本高且无法实时更新)。

2. 缺乏业务执行力

模型无法直接操作 ERP、CRM 系统,无法发送邮件或创建工单。

用户需复制模型建议,手动去系统操作,体验割裂。

3. 复杂计算能力弱

LLM 擅长语言推理,但不擅长精确数学计算或逻辑运算。

直接让 LLM 算数容易出错(如“9.11 和 9.9 谁大”)。

4. 私有数据隔离

模型无法访问企业内部的私有数据库或文档。

需将数据上传至公有云微调,存在严重数据泄露风险。

解决方案(设计思路)

  1. 外挂工具箱: 不改变模型权重,通过 Prompt 将可用工具列表告诉模型。
  2. 结构化输出: 强制模型输出符合特定 Schema(如 JSON Schema)的参数,而非自然语言。
  3. 执行与回填: 由外部代码执行函数,并将结果作为“新上下文”喂回给模型,让模型基于真实结果回答。

3. 构成和设计原理

核心设计思想

Function Calling 的核心在于“意图识别”“参数提取”的解耦。

  • 意图识别: 判断用户想干什么(调用哪个函数)。
  • 参数提取: 从自然语言中提取函数所需的变量。

核心支柱(三元模型)

支柱

实现载体

解决的核心问题

工具定义 (Schema)

JSON Schema / Pydantic

明确告诉 LLM“我能做什么”以及“需要什么参数”,消除歧义。

推理引擎 (LLM)

GPT-4 / Claude / Local LLM

理解用户自然语言,将其映射到工具定义中,生成结构化调用请求。

执行环境 (Runtime)

后端代码

安全地执行 LLM 生成的函数调用,处理异常,并将结果格式化。

架构分层

架构层级说明:

  1. 用户交互层 (Host): 负责接收用户指令,管理会话状态,发起 FC 请求。
  2. 模型服务层 (LLM): 负责语义理解,匹配工具,生成参数。
  3. 工具服务层 (Server): 负责实际业务逻辑执行(这是 MCP 重点解耦的部分)。
  4. 上下文闭环: 关键在于第 5 步,将执行结果再次发给 LLM,形成闭环。

4. 构成和工作原理

协议基石:JSON Schema

Function Calling 强依赖于 JSON Schema 来定义工具。这是 LLM 理解工具的“说明书”。

  • name: 函数名(如 get_weather
  • description: 函数描述(告诉 LLM 什么时候该用这个函数)
  • parameters: 参数定义(类型、必填项、枚举值)

核心组件

  1. Tool Registry (工具注册表): 存储所有可用函数的元数据。
  2. Parser (解析器): 将 LLM 输出的文本(有时包含 Markdown 标记)清洗为纯 JSON 对象。
  3. Dispatcher (调度器): 根据函数名路由到具体的代码逻辑。

工作原理(动态流程)

Function Calling 是一个“请求 - 响应 - 执行 - 再响应”的闭环过程。

第一步:工具声明 (Setup)

  • 开发者在代码中定义函数(如 search_database(query))。
  • 将函数的 Schema 描述放入 System Prompt 或 API 的 tools 参数中发送给 LLM。

第二步:意图识别与参数提取 (Inference)

  • 用户输入:“查一下北京明天的天气”。
  • LLM 分析:发现需要查天气,匹配到 get_weather 工具。
  • LLM 输出(停止生成自然语言,转为工具调用模式):
{
  "name": "get_weather",
  "arguments": {"location": "北京", "date": "tomorrow"}
}

第三步:外部执行 (Execution)

  • 应用程序拦截 LLM 的输出。
  • 解析 JSON,在本地或服务器端执行真实的 get_weather("北京", "tomorrow") 代码。
  • 获取真实结果:{"temp": 25, "condition": "Sunny"}

第四步:结果回填与最终回答 (Completion)

  • 将执行结果作为一条新的“系统消息”或“工具响应”发送回 LLM。
  • LLM 结合结果生成最终自然语言回复:“北京明天天气晴朗,气温 25 度。”

5. 实用场景与面试要求

典型应用场景

  1. RAG 增强检索: 将“搜索知识库”封装为 Function,让 LLM 自主决定何时检索。
  2. 数据分析助手: 将“SQL 查询”或“Python 绘图”封装为 Function,实现 Text-to-SQL 或自动图表生成。
  3. 自动化运维/办公: 调用 Jira、Slack、AWS API 完成工单创建、通知发送、资源扩缩容。

面试中的定位与要求

在 AI 应用开发面试中,Function Calling 是中级到高级的必考点。

  • 初级要求: 能调用 OpenAI/Claude 的官方 Function Calling API,会写 JSON Schema。
  • 中级要求: 理解 ReAct 模式(Reasoning + Acting),能处理多步工具调用(Chain of Thought),能处理工具调用失败的情况。
  • 高级要求:
    • 安全性: 如何防止 LLM 注入恶意代码?(沙箱执行、权限控制、安全校验)。
    • 准确性: 当模型参数提取错误时如何纠错?(Few-shot prompting, 自动重试机制)。
    • 架构设计: 如何设计一个支持动态加载插件的 Agent 系统?(参考 MCP 架构思想)。

Java + LangChain4j 实现 Function Calling 完整示例

下面是一个可运行的天气查询 Function Calling 示例,使用 LangChain4j(LangChain 的 Java 版本)。


一、项目依赖配置

Maven (pom.xml)
<dependencies>
    <!-- LangChain4j 核心 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j</artifactId>
        <version>0.31.0</version>
    </dependency>
    
    <!-- OpenAI 集成 -->
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai</artifactId>
        <version>0.31.0</version>
    </dependency>
    
    <!-- Lombok (简化代码) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.30</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
Gradle (build.gradle)
dependencies {
    implementation 'dev.langchain4j:langchain4j:0.31.0'
    implementation 'dev.langchain4j:langchain4j-open-ai:0.31.0'
    compileOnly 'org.projectlombok:lombok:1.18.30'
    annotationProcessor 'org.projectlombok:lombok:1.18.30'
}

二、完整代码实现

1. 工具类 - 天气服务
package com.example.ai.tools;

import dev.langchain4j.agent.tool.Tool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 天气查询工具 - 演示 Function Calling
 */
@Slf4j
@Component
public class WeatherService {

    /**
     * 查询天气 - 会被 LLM 自动识别和调用
     * @Tool 注解标记这是一个可被调用的函数
     */
    @Tool("查询指定城市的当前天气情况")
    public String getWeather(
            @P("城市名称,例如:北京、上海") String city,
            @P("日期,例如:今天、明天") String date
    ) {
        log.info("收到天气查询请求:city={}, date={}", city, date);
        
        // 模拟调用真实天气 API
        // 实际项目中这里会调用 和风天气/OpenWeatherMap 等 API
        return simulateWeatherAPI(city, date);
    }

    /**
     * 模拟天气 API 返回
     */
    private String simulateWeatherAPI(String city, String date) {
        // 实际项目中替换为真实 API 调用
        return String.format(
            "{\"city\":\"%s\",\"date\":\"%s\",\"temperature\":25,\"condition\":\"晴朗\",\"humidity\":60}",
            city, date
        );
    }
}
2. 助手类 - AI 助理
package com.example.ai.assistant;

import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;

/**
 * AI 助理接口 - 定义与 LLM 交互的契约
 */
public interface WeatherAssistant {

    @SystemMessage("你是一个智能天气助手,可以帮助用户查询天气信息。")
    @UserMessage("{{userMessage}}")
    String chat(String userMessage);
}
3. 主程序 - Function Calling 调用
package com.example.ai;

import com.example.ai.assistant.WeatherAssistant;
import com.example.ai.tools.WeatherService;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;

/**
 * Function Calling 主程序入口
 */
public class FunctionCallingDemo {

    public static void main(String[] args) {
        // 1. 配置 OpenAI 模型 (支持 Function Calling)
        OpenAiChatModel chatModel = OpenAiChatModel.builder()
                .apiKey("你的 OpenAI API Key")  // 从环境变量获取更安全
                .modelName("gpt-3.5-turbo-0613")  // 或 gpt-4-turbo
                .temperature(0.7)
                .build();

        // 2. 创建工具实例
        WeatherService weatherService = new WeatherService();

        // 3. 构建 AI 服务 - 自动注册工具函数
        WeatherAssistant assistant = AiServices.builder(WeatherAssistant.class)
                .chatLanguageModel(chatModel)
                .tools(weatherService)  // 关键:注册工具
                .build();

        // 4. 测试场景 1 - 触发 Function Calling
        System.out.println("=== 测试场景 1: 查询天气 ===");
        String response1 = assistant.chat("北京今天天气怎么样?");
        System.out.println("AI 回复:" + response1);

        // 5. 测试场景 2 - 多轮对话
        System.out.println("\n=== 测试场景 2: 多轮对话 ===");
        String response2 = assistant.chat("那上海明天呢?");
        System.out.println("AI 回复:" + response2);

        // 6. 测试场景 3 - 不需要调用工具
        System.out.println("\n=== 测试场景 3: 普通对话 ===");
        String response3 = assistant.chat("你好,介绍一下你自己");
        System.out.println("AI 回复:" + response3);
    }
}

三、执行流程时序图


四、进阶:多工具函数调用

1. 添加更多工具
package com.example.ai.tools;

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

@Component
public class CalendarService {

    @Tool("查询指定日期的日程安排")
    public String getSchedule(
            @P("日期,格式:YYYY-MM-DD") String date,
            @P("用户 ID") String userId
    ) {
        // 模拟查询日历
        return "{\"date\":\"" + date + "\",\"events\":[\"会议\",\"聚餐\"]}";
    }

    @Tool("创建新的日程提醒")
    public String createReminder(
            @P("提醒内容") String content,
            @P("提醒时间") String time
    ) {
        log.info("创建提醒:content={}, time={}", content, time);
        return "{\"status\":\"success\",\"reminderId\":\"REM001\"}";
    }
}
2. 注册多个工具
// 在主程序中注册多个工具
WeatherAssistant assistant = AiServices.builder(WeatherAssistant.class)
        .chatLanguageModel(chatModel)
        .tools(weatherService)      // 天气工具
        .tools(calendarService)     // 日历工具
        .tools(emailService)        // 邮件工具
        .build();

五、安全增强版(参考 MCP 安全设计)

1. 权限校验拦截器
package com.example.ai.security;

import dev.langchain4j.agent.tool.ToolExecutionRequest;
import dev.langchain4j.agent.tool.ToolExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 工具调用安全拦截器 - 实现 MCP 式的安全双闸
 */
@Slf4j
@Component
public class SecurityToolExecutor implements ToolExecutor {

    private final ToolExecutor delegate;
    private final PermissionChecker permissionChecker;

    public SecurityToolExecutor(ToolExecutor delegate, PermissionChecker checker) {
        this.delegate = delegate;
        this.permissionChecker = checker;
    }

    @Override
    public String execute(ToolExecutionRequest request, String memoryId) {
        // 第一道闸:用户授权检查
        if (!permissionChecker.checkUserPermission(memoryId, request.name())) {
            log.warn("用户无权调用工具:{}", request.name());
            return "错误:您没有权限执行此操作";
        }

        // 第二道闸:参数安全校验
        if (!permissionChecker.validateParameters(request)) {
            log.warn("参数校验失败:{}", request.name());
            return "错误:参数不符合安全规范";
        }

        // 记录审计日志
        log.info("工具调用审计:user={}, tool={}, params={}", 
                memoryId, request.name(), request.arguments());

        // 执行实际调用
        return delegate.execute(request, memoryId);
    }
}
2. 敏感操作二次确认
package com.example.ai.tools;

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

@Component
public class SensitiveOperationService {

    @Tool("删除用户数据 - 需要二次确认")
    public String deleteUserData(
            @P("用户 ID") String userId,
            @P("确认令牌 - 必须为 CONFIRM") String confirmToken
    ) {
        // 强制要求确认令牌,防止误操作
        if (!"CONFIRM".equals(confirmToken)) {
            throw new SecurityException("删除操作需要二次确认");
        }
        
        // 执行删除逻辑
        return "{\"status\":\"deleted\",\"userId\":\"" + userId + "\"}";
    }
}

六、常见问题与解决方案

问题

原因

解决方案

工具未被调用

函数描述不够清晰

优化 @Tool 的 description,明确使用场景

参数提取错误

参数名与 Schema 不匹配

确保 @P 注解的参数名与函数签名一致

中文乱码

编码问题

确保项目编码为 UTF-8

API Key 泄露

硬编码在代码中

使用环境变量 System.getenv("OPENAI_API_KEY")

调用超时

网络或 API 限制

增加超时配置 .timeout(Duration.ofSeconds(30))


七、运行结果示例

=== 测试场景 1: 查询天气 ===
[DEBUG] 收到天气查询请求:city=北京,date=今天
AI 回复:北京今天天气晴朗,气温 25 度,湿度 60%,适合外出活动。

=== 测试场景 2: 多轮对话 ===
[DEBUG] 收到天气查询请求:city=上海,date=明天
AI 回复:上海明天预计多云转晴,气温 23-28 度。

=== 测试场景 3: 普通对话 ===
AI 回复:你好!我是一个智能天气助手,可以帮您查询各地天气信息...

学习路线建议


Logo

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

更多推荐