基于DeepSeek大模型实现Function Call功能

发布于:2025-07-19 ⋅ 阅读:(23) ⋅ 点赞:(0)

Function Call 架构链式思维分析

问题核心

核心问题:在线DeepSeek模型如何与本地函数结合,实现智能函数调用?

链式思维分析

第一步:理解Function Call的本质

1.1 Function Call是什么?

Function Call是一种AI模型与外部函数交互的机制:

  • AI模型:负责理解用户意图,决定调用哪个函数
  • 外部函数:负责执行具体的业务逻辑,返回结果
  • 桥梁:通过标准化的接口实现两者之间的通信
1.2 为什么需要Function Call?
  • AI模型的局限性:大模型无法直接访问实时数据、执行计算、调用外部API
  • 本地函数的优势:可以访问本地资源、执行复杂计算、调用真实API
  • 结合的价值:AI的智能理解 + 本地函数的执行能力 = 完整的智能系统

第二步:分析当前架构设计

2.1 整体架构图
用户输入 → 本地服务器 → DeepSeek API → 本地函数 → 结果整合 → 最终回复
2.2 详细流程分析

阶段1:用户输入处理

// 用户输入:"查询北京的天气"
FunctionCallRequestDTO request = new FunctionCallRequestDTO();
request.setUserInput("查询北京的天气");

阶段2:构建Function Call请求

// 关键:将本地函数定义发送给在线模型
Map<String, Object> functionCallRequest = buildFunctionCallRequest(request);
// 包含:
// - 系统消息:指导模型使用函数
// - 用户消息:原始输入
// - 函数定义:本地函数的描述和参数
// - 调用策略:auto

阶段3:在线模型决策

// DeepSeek API接收请求,分析用户意图
Map<String, Object> apiResponse = callDeepSeekAPI(functionCallRequest);
// 模型返回:
// - 是否需要调用函数
// - 调用哪个函数
// - 函数参数是什么

阶段4:本地函数执行

// 如果模型决定调用函数
if (result.getFunctionCalled()) {
    // 在本地执行实际的函数
    Map<String, Object> functionResult = executeFunction(
        result.getFunctionName(), 
        result.getFunctionArguments()
    );
}

阶段5:结果整合

// 将函数执行结果发送回模型,生成最终回复
String finalContent = callDeepSeekAPIWithFunctionResult(
    request.getUserInput(), 
    result.getFunctionName(), 
    functionResult
);

第三步:深入理解结合机制

3.1 函数定义的作用

在线模型需要知道什么?

// 函数定义告诉模型:
{
  "name": "get_weather",
  "description": "获取指定城市的天气信息,包括温度、天气状况、湿度、风力等",
  "parameters": {
    "type": "object",
    "properties": {
      "city": {
        "type": "string",
        "description": "城市名称,如:北京、上海、广州"
      }
    },
    "required": ["city"]
  }
}

关键理解

  • 模型不需要知道函数的具体实现
  • 模型只需要知道函数的用途、参数、返回值格式
  • 模型根据这些信息决定是否调用函数
3.2 本地函数执行机制

本地函数的特点

private Map<String, Object> executeGetWeather(Map<String, Object> arguments) {
    String city = (String) arguments.get("city");
    
    // 本地函数可以:
    // 1. 调用真实的天气API
    // 2. 访问本地数据库
    // 3. 执行复杂计算
    // 4. 访问本地文件系统
    // 5. 调用其他本地服务
    
    Map<String, Object> weatherData = new HashMap<>();
    weatherData.put("city", city);
    weatherData.put("temperature", "25°C");
    // ... 更多数据
    
    return weatherData;
}
3.3 数据流转机制

数据流转图

用户输入: "查询北京的天气"
    ↓
本地服务器构建请求
    ↓
发送给DeepSeek API: 
{
  "messages": [...],
  "functions": [函数定义],
  "function_call": "auto"
}
    ↓
DeepSeek返回: 
{
  "function_call": {
    "name": "get_weather",
    "arguments": "{\"city\":\"北京\"}"
  }
}
    ↓
本地解析并执行函数
    ↓
函数返回结果: {"city":"北京","temperature":"25°C",...}
    ↓
发送给DeepSeek生成最终回复
    ↓
返回给用户: "根据查询结果,北京今天天气晴朗,温度25°C..."

第四步:关键技术点分析

4.1 函数定义标准化

为什么需要标准化?

  • 在线模型需要理解函数的能力
  • 需要统一的格式来描述函数
  • 确保模型能正确解析参数

标准格式

{
  "name": "函数名称",
  "description": "详细描述,包含触发条件",
  "parameters": {
    "type": "object",
    "properties": {
      "参数名": {
        "type": "参数类型",
        "description": "参数说明"
      }
    },
    "required": ["必需参数列表"]
  }
}
4.2 参数传递机制

参数提取

// 从模型返回的JSON字符串中提取参数
JsonNode arguments = functionCall.get("arguments");
Map<String, Object> args = objectMapper.readValue(
    arguments.asText(), Map.class
);

参数验证

// 验证必需参数是否存在
String city = (String) arguments.get("city");
if (city == null) {
    // 处理参数缺失情况
}
4.3 结果整合机制

函数结果格式

// 函数返回结构化数据
Map<String, Object> functionResult = new HashMap<>();
functionResult.put("city", "北京");
functionResult.put("temperature", "25°C");
functionResult.put("weather", "晴天");

发送给模型

// 将函数结果作为function消息发送给模型
messages.add(Map.of(
    "role", "function", 
    "content", JSONUtil.toJsonStr(functionResult)
));

第五步:优势与挑战分析

5.1 架构优势

1. 职责分离

  • 在线模型:专注于理解用户意图和生成自然语言回复
  • 本地函数:专注于执行具体的业务逻辑和数据获取

2. 灵活性

  • 可以轻松添加新的本地函数
  • 可以集成各种外部API和服务
  • 可以访问本地资源和数据库

3. 安全性

  • 敏感操作在本地执行
  • 可以控制数据访问权限
  • 避免将敏感信息发送到外部

4. 实时性

  • 本地函数可以获取实时数据
  • 减少网络延迟
  • 提高响应速度
5.2 技术挑战

1. 函数定义管理

  • 需要维护函数定义的准确性
  • 需要确保描述与实现一致
  • 需要处理函数版本更新

2. 错误处理

  • 模型可能返回错误的函数调用
  • 本地函数可能执行失败
  • 需要完善的错误恢复机制

3. 性能优化

  • 两次API调用增加了延迟
  • 需要优化函数执行效率
  • 需要考虑缓存策略

4. 扩展性

  • 函数数量增加时的管理
  • 复杂参数的处理
  • 多函数调用的协调

第六步:实际应用场景

6.1 天气查询场景
用户: "查询北京的天气"
模型: 识别需要调用get_weather函数
本地: 调用天气API获取真实数据
模型: 基于真实数据生成自然语言回复
用户: 获得准确的天气信息
6.2 数学计算场景
用户: "计算 2+3*4 的结果"
模型: 识别需要调用calculate函数
本地: 执行数学计算
模型: 基于计算结果生成回复
用户: 获得计算结果和解释
6.3 时间查询场景
用户: "现在几点了?"
模型: 识别需要调用get_time函数
本地: 获取系统当前时间
模型: 基于时间数据生成回复
用户: 获得当前时间信息

第七步:优化建议

7.1 函数定义优化
  • 提供更详细的函数描述
  • 包含具体的触发条件
  • 添加参数示例和说明
7.2 错误处理增强
  • 实现函数调用的重试机制
  • 提供降级处理方案
  • 完善错误日志记录
7.3 性能优化
  • 实现函数结果缓存
  • 优化API调用频率
  • 考虑批量函数调用
7.4 扩展性设计
  • 实现动态函数注册
  • 支持函数组合调用
  • 提供函数调用链

总结

Function Call架构的核心思想是:

  1. 在线模型负责理解:理解用户意图,决定调用策略
  2. 本地函数负责执行:执行具体业务逻辑,获取真实数据
  3. 标准化接口连接:通过统一的函数定义和调用格式实现连接
  4. 结果整合生成回复:将函数结果发送回模型,生成最终回复

这种架构实现了AI智能理解与本地执行能力的完美结合,为用户提供了既智能又实用的交互体验。

#具体java代码如下

package com.mybase.system.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mybase.common.annotation.Log;
import com.mybase.common.model.R;
import com.mybase.common.utils.MyDateUtil;
import com.mybase.common.constant.PermissionConstants;
import com.mybase.system.config.FunctionCallConfig;
import com.mybase.system.dto.FunctionCallRequestDTO;
import com.mybase.system.dto.FunctionDefinitionDTO;
import com.mybase.system.vo.FunctionCallResultVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import java.util.*;

/**
 * Function Call 控制器
 * 基于DeepSeek大模型实现Function Call功能
 * 
 * @author wangmingjie
 * @since 2025-07-18
 */
@Slf4j
@RestController
@RequestMapping("/system/function-call")
@Tag(name = "Function Call", description = "基于DeepSeek大模型的Function Call功能")
public class FunctionCallController {

    @Autowired
    private FunctionCallConfig functionCallConfig;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;



    /**
     * 预定义的函数定义列表
     */
    private static final List<FunctionDefinitionDTO> PREDEFINED_FUNCTIONS = Arrays.asList(
        // 天气查询函数
        FunctionDefinitionDTO.builder()
            .name("get_weather")
            .description("获取指定城市的天气信息,包括温度、天气状况、湿度、风力等")
            .parameters(Map.of(
                "type", "object",
                "properties", Map.of(
                    "city", Map.of(
                        "type", "string",
                        "description", "城市名称,如:北京、上海、广州"
                    ),
                    "date", Map.of(
                        "type", "string",
                        "description", "查询日期,格式:YYYY-MM-DD,默认为今天"
                    )
                ),
                "required", Arrays.asList("city")
            ))
            .build(),
        
        // 计算器函数
        FunctionDefinitionDTO.builder()
            .name("calculate")
            .description("执行数学计算,支持加减乘除和基本数学运算")
            .parameters(Map.of(
                "type", "object",
                "properties", Map.of(
                    "expression", Map.of(
                        "type", "string",
                        "description", "数学表达式,如:2+3*4、(10+5)/3"
                    )
                ),
                "required", Arrays.asList("expression")
            ))
            .build(),
        
        // 时间查询函数
        FunctionDefinitionDTO.builder()
            .name("get_time")
            .description("获取当前时间信息,当用户询问时间、几点、现在时间等问题时调用此函数")
            .parameters(Map.of(
                "type", "object",
                "properties", Map.of(
                    "timezone", Map.of(
                        "type", "string",
                        "description", "时区,如:Asia/Shanghai、UTC、America/New_York,默认为Asia/Shanghai"
                    ),
                    "format", Map.of(
                        "type", "string",
                        "description", "时间格式,如:yyyy-MM-dd HH:mm:ss、yyyy年MM月dd日,默认为yyyy-MM-dd HH:mm:ss"
                    )
                ),
                "required", new ArrayList<>()
            ))
            .build(),
        
        // 翻译函数
        FunctionDefinitionDTO.builder()
            .name("translate")
            .description("文本翻译功能,支持多种语言之间的翻译")
            .parameters(Map.of(
                "type", "object",
                "properties", Map.of(
                    "text", Map.of(
                        "type", "string",
                        "description", "要翻译的文本"
                    ),
                    "source_lang", Map.of(
                        "type", "string",
                        "description", "源语言,如:zh、en、ja、ko"
                    ),
                    "target_lang", Map.of(
                        "type", "string",
                        "description", "目标语言,如:zh、en、ja、ko"
                    )
                ),
                "required", Arrays.asList("text", "target_lang")
            ))
            .build()
    );
//https://api-docs.deepseek.com/zh-cn/guides/json_mode  
    //deepseek DeepSeek 提供了 JSON Output 功能,来确保模型输出合法的 JSON 字符串。
    /**
     * 执行Function Call。参考https://api-docs.deepseek.com/zh-cn/guides/function_calling
     * 
     */
    @Log(module = "Function Call", operationType = "执行", description = "执行Function Call")
    @Operation(summary = "执行Function Call", description = "基于DeepSeek大模型执行Function Call")
    @PostMapping("/execute")
    @SaCheckPermission(PermissionConstants.SYSTEM_FUNCTION_CALL_EXECUTE)
    public R<FunctionCallResultVO> executeFunctionCall(@RequestBody FunctionCallRequestDTO request) {
        try {
            log.info("开始执行Function Call,用户输入:{}", request.getUserInput());
            
            // 参数验证
            if (StrUtil.isBlank(request.getUserInput())) {
                return R.fail("用户输入不能为空");
            }

            // 记录开始时间
            long startTime = System.currentTimeMillis();

            // 构建Function Call请求
            Map<String, Object> functionCallRequest = buildFunctionCallRequest(request);
            
            // 第一次调用DeepSeek API - 判断是否需要调用函数
            Map<String, Object> apiResponse = callDeepSeekAPIReal(functionCallRequest);
            
            // 解析响应
            FunctionCallResultVO result = parseFunctionCallResponse(apiResponse);
            
            // 如果调用了函数,执行函数并获取结果
            if (result.getFunctionCalled()) {
                Map<String, Object> functionResult = executeFunction(result.getFunctionName(), result.getFunctionArguments());
                result.setFunctionResult(functionResult);
                
                // 第二次调用DeepSeek API - 将函数结果发送给模型生成最终回复
                String finalContent = callDeepSeekAPIWithFunctionResult(
                    request,  // 传递第一次调用的完整请求
                    apiResponse,          // 传递第一次调用的完整响应
                    result,
                    functionResult
                );
                result.setContent(finalContent);
            }
            
            long endTime = System.currentTimeMillis();
            result.setResponseTime((int) (endTime - startTime));
            result.setModel(functionCallConfig.getDeepseek().getModelName());
            
            log.info("Function Call执行完成,耗时:{}ms,函数调用:{}", 
                    result.getResponseTime(), result.getFunctionCalled());
            
            return R.ok(result);
            
        } catch (Exception e) {
            log.error("Function Call执行失败", e);
            FunctionCallResultVO errorResult = new FunctionCallResultVO();
            errorResult.setSuccess(false);
            errorResult.setErrorMessage("Function Call执行失败: " + e.getMessage());
            return R.ok(errorResult);
        }
    }

    /**
     * 测试Function Call连接
     */
    @Operation(summary = "测试连接", description = "测试DeepSeek API连接状态")
    @PostMapping("/test")
    @SaCheckPermission(PermissionConstants.SYSTEM_FUNCTION_CALL_EXECUTE)
    public R<Map<String, Object>> testConnection() {
        try {
            log.info("开始测试DeepSeek API连接");
            
            // 构建简单的测试请求
            Map<String, Object> testRequest = new HashMap<>();
            testRequest.put("model", functionCallConfig.getDeepseek().getModelName());
            testRequest.put("messages", Arrays.asList(
                Map.of("role", "user", "content", "你好,请简单回复一下")
            ));
            testRequest.put("max_tokens", 50);
            testRequest.put("temperature", 0.7);
            
            // 调用API
            Map<String, Object> response = callDeepSeekAPIReal(testRequest);
            
            Map<String, Object> result = new HashMap<>();
            result.put("success", true);
            result.put("message", "连接测试成功");
            result.put("model", functionCallConfig.getDeepseek().getModelName());
            result.put("response", response.get("content"));
            
            log.info("DeepSeek API连接测试成功");
            return R.ok(result);
            
        } catch (Exception e) {
            log.error("DeepSeek API连接测试失败", e);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "连接测试失败: " + e.getMessage());
            return R.ok(result);
        }
    }

    /**
     * 获取配置信息
     */
    @Operation(summary = "获取配置", description = "获取Function Call配置信息")
    @GetMapping("/config")
    @SaCheckPermission(PermissionConstants.SYSTEM_FUNCTION_CALL_CONFIG)
    public R<Map<String, Object>> getConfig() {
        Map<String, Object> config = new HashMap<>();
        config.put("apiUrl", functionCallConfig.getDeepseek().getApiUrl());
        config.put("modelName", functionCallConfig.getDeepseek().getModelName());
        config.put("timeoutMs", functionCallConfig.getDeepseek().getTimeoutMs());
        config.put("maxTokens", functionCallConfig.getDeepseek().getMaxTokens());
        config.put("temperature", functionCallConfig.getDeepseek().getTemperature());
        config.put("functionCount", PREDEFINED_FUNCTIONS.size());
        
        return R.ok(config);
    }

    /**
     * 获取预定义函数列表
     */
    @Operation(summary = "获取函数列表", description = "获取所有预定义的函数列表")
    @GetMapping("/functions")
    @SaCheckPermission(PermissionConstants.SYSTEM_FUNCTION_CALL_CONFIG)
    public R<List<FunctionDefinitionDTO>> getFunctions() {
        return R.ok(PREDEFINED_FUNCTIONS);
    }

    /**
     * 构建Function Call请求
     */
    private Map<String, Object> buildFunctionCallRequest(FunctionCallRequestDTO request) {
        Map<String, Object> requestBody = new HashMap<>();
        
        // 设置模型
        requestBody.put("model", functionCallConfig.getDeepseek().getModelName());
        
        // 构建消息 - 添加系统消息来指导模型使用函数
        List<Map<String, Object>> messages = new ArrayList<>();
        
        // 添加系统消息,指导模型使用函数
        messages.add(Map.of(
            "role", "system", 
            "content", "你是一个智能助手,支持Function Call功能。当用户询问时间、天气、计算、翻译等问题时,你必须使用Function Call格式调用相应的函数,而不是在回复中提及函数。\n\n重要规则:\n1. 当用户询问时间相关问题时,必须调用get_time函数\n2. 当用户询问天气相关问题时,必须调用get_weather函数\n3. 当用户询问计算相关问题时,必须调用calculate函数\n4. 当用户询问翻译相关问题时,必须调用translate函数\n\n不要在任何情况下在回复中提及函数名称或代码,直接使用Function Call格式调用函数。"
        ));
        
        // 添加用户消息
        messages.add(Map.of("role", "user", "content", request.getUserInput()));
        requestBody.put("messages", messages);
        
        // 设置工具定义 - 使用tools而不是functions,符合DeepSeek API格式
        List<Map<String, Object>> tools = new ArrayList<>();
        for (FunctionDefinitionDTO function : PREDEFINED_FUNCTIONS) {
            Map<String, Object> toolDef = new HashMap<>();
            toolDef.put("type", "function");
            
            Map<String, Object> functionDef = new HashMap<>();
            functionDef.put("name", function.getName());
            functionDef.put("description", function.getDescription());
            functionDef.put("parameters", function.getParameters());
            
            toolDef.put("function", functionDef);
            tools.add(toolDef);
        }
        requestBody.put("tools", tools);
        
        // 设置工具调用策略 - 让模型自动决定是否调用函数
        requestBody.put("tool_choice", "auto");
        
        // 设置其他参数
        requestBody.put("max_tokens", functionCallConfig.getDeepseek().getMaxTokens());
        requestBody.put("temperature", functionCallConfig.getDeepseek().getTemperature());
        requestBody.put("stream", false);
        
        log.debug("构建的Function Call请求: {}", requestBody);
        return requestBody;
    }


    
    /**
     * 调用真实的DeepSeek API
     */
    private Map<String, Object> callDeepSeekAPIReal(Map<String, Object> requestBody) throws Exception {
        log.debug("调用DeepSeek API,URL: {}, Model: {}", 
                functionCallConfig.getDeepseek().getApiUrl(), functionCallConfig.getDeepseek().getModelName());
        
        // 构建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        if (StrUtil.isNotBlank(functionCallConfig.getDeepseek().getApiKey())) {
            headers.setBearerAuth(functionCallConfig.getDeepseek().getApiKey());
        }
        
        // 发送请求
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<String> response = restTemplate.postForEntity(
                functionCallConfig.getDeepseek().getApiUrl(), entity, String.class);
        
        if (response.getStatusCode() == HttpStatus.OK) {
            String responseBody = response.getBody();
            log.debug("callDeepSeekAPIReal DeepSeek API响应:{}", responseBody);
            
            JsonNode jsonResponse = objectMapper.readTree(responseBody);
            
            Map<String, Object> result = new HashMap<>();
            
            // 提取回答内容
            JsonNode choices = jsonResponse.get("choices");
            if (choices != null && choices.isArray() && choices.size() > 0) {
                JsonNode firstChoice = choices.get(0);
                JsonNode message = firstChoice.get("message");
                if (message != null) {
                    result.put("content", message.get("content").asText(""));
                    
                    // 检查是否有工具调用 - 使用tool_calls而不是function_call
                    JsonNode toolCalls = message.get("tool_calls");
                    if (toolCalls != null && toolCalls.isArray() && toolCalls.size() > 0) {
                        log.info("检测到工具调用: {}", toolCalls.toString());
                        result.put("tool_calls", toolCalls);
                        
                        // 提取第一个工具调用的ID
                        JsonNode firstToolCall = toolCalls.get(0);
                        if (firstToolCall.has("id")) {
                            result.put("tool_call_id", firstToolCall.get("id").asText());
                        }
                    } else {
                        log.info("未检测到工具调用,模型直接回复");
                    }
                }
            }
            
            // 提取使用统计
            JsonNode usage = jsonResponse.get("usage");
            if (usage != null) {
                Map<String, Object> usageMap = new HashMap<>();
                usageMap.put("prompt_tokens", usage.get("prompt_tokens").asInt());
                usageMap.put("completion_tokens", usage.get("completion_tokens").asInt());
                usageMap.put("total_tokens", usage.get("total_tokens").asInt());
                result.put("usage", usageMap);
            }
            
            
            return result;
        } else {
            throw new RuntimeException("DeepSeek API调用失败,状态码:" + response.getStatusCode());
        }
    }

    
    /**
     * 从用户输入中提取城市名称
     */
    private String extractCityFromInput(String userInput) {
        // 简单的城市提取逻辑
        String[] cities = {"北京", "上海", "广州", "深圳", "杭州", "南京", "武汉", "成都", "西安", "重庆"};
        for (String city : cities) {
            if (userInput.contains(city)) {
                return city;
            }
        }
        return "北京"; // 默认返回北京
    }
    
    /**
     * 从用户输入中提取数学表达式
     */
    private String extractExpressionFromInput(String userInput) {
        // 简单的表达式提取逻辑
        if (userInput.contains("计算")) {
            int start = userInput.indexOf("计算") + 2;
            int end = userInput.indexOf("的结果");
            if (end > start) {
                return userInput.substring(start, end).trim();
            }
        }
        // 提取数字和运算符
        return userInput.replaceAll("[^0-9+\\-*/()]", "").trim();
    }
    
    /**
     * 从用户输入中提取要翻译的文本
     */
    private String extractTextFromInput(String userInput) {
        // 简单的文本提取逻辑
        if (userInput.contains("把") && userInput.contains("翻译")) {
            int start = userInput.indexOf("把") + 1;
            int end = userInput.indexOf("翻译");
            if (end > start) {
                return userInput.substring(start, end).replaceAll("['\"]", "").trim();
            }
        }
        return "你好世界"; // 默认文本
    }
    
    /**
     * 从用户输入中提取目标语言
     */
    private String extractTargetLangFromInput(String userInput) {
        if (userInput.contains("英文") || userInput.contains("英语")) {
            return "en";
        } else if (userInput.contains("中文") || userInput.contains("汉语")) {
            return "zh";
        }
        return "en"; // 默认英文
    }

    /**
     * 解析Function Call响应
     */
    private FunctionCallResultVO parseFunctionCallResponse(Map<String, Object> apiResponse) {
        FunctionCallResultVO result = new FunctionCallResultVO();
        result.setSuccess(true);
        result.setContent((String) apiResponse.get("content"));
        result.setUsage((Map<String, Object>) apiResponse.get("usage"));
        
        // 检查是否有工具调用 - 使用tool_calls而不是function_call
        Object toolCallsObj = apiResponse.get("tool_calls");
        if (toolCallsObj != null) {
            result.setFunctionCalled(true);
            
            if (toolCallsObj instanceof JsonNode) {
                // 真实API返回的JsonNode
                JsonNode toolCalls = (JsonNode) toolCallsObj;
                if (toolCalls.isArray() && toolCalls.size() > 0) {
                    JsonNode firstToolCall = toolCalls.get(0);
                    JsonNode function = firstToolCall.get("function");
                    if (function != null) {
                        result.setFunctionName(function.get("name").asText());
                        
                        // 解析函数参数
                        JsonNode arguments = function.get("arguments");
                        if (arguments != null) {
                            try {
                                Map<String, Object> args = objectMapper.readValue(
                                        arguments.asText(), Map.class);
                                result.setFunctionArguments(args);
                            } catch (Exception e) {
                                log.warn("解析函数参数失败", e);
                                result.setFunctionArguments(new HashMap<>());
                            }
                        }
                        
                        // 保存tool_call_id
                        if (firstToolCall.has("id")) {
                            result.setToolCallId(firstToolCall.get("id").asText());
                        }
                    }
                }
            } else if (toolCallsObj instanceof List) {
                // 模拟模式返回的List
                List<Map<String, Object>> toolCalls = (List<Map<String, Object>>) toolCallsObj;
                if (!toolCalls.isEmpty()) {
                    Map<String, Object> firstToolCall = toolCalls.get(0);
                    Map<String, Object> function = (Map<String, Object>) firstToolCall.get("function");
                    if (function != null) {
                        result.setFunctionName((String) function.get("name"));
                        
                        // 解析函数参数
                        String arguments = (String) function.get("arguments");
                        if (arguments != null) {
                            try {
                                Map<String, Object> args = objectMapper.readValue(arguments, Map.class);
                                result.setFunctionArguments(args);
                            } catch (Exception e) {
                                log.warn("解析函数参数失败", e);
                                result.setFunctionArguments(new HashMap<>());
                            }
                        }
                        
                        // 保存tool_call_id
                        result.setToolCallId((String) firstToolCall.get("id"));
                    }
                }
            }
            
            log.info("解析到函数调用: {},参数: {},tool_call_id: {}", 
                    result.getFunctionName(), result.getFunctionArguments(), result.getToolCallId());
        } else {
            result.setFunctionCalled(false);
            log.info("未解析到函数调用");
        }
        
        return result;
    }

    /**
     * 执行函数调用
     */
    private Map<String, Object> executeFunction(String functionName, Map<String, Object> arguments) {
        log.info("执行函数:{},参数:{}", functionName, arguments);
        
        try {
            switch (functionName) {
                case "get_weather":
                    return executeGetWeather(arguments);
                case "calculate":
                    return executeCalculate(arguments);
                case "get_time":
                    return executeGetTime(arguments);
                case "translate":
                    return executeTranslate(arguments);
                default:
                    log.warn("未知函数:{}", functionName);
                    return new HashMap<>(); // 返回空Map表示函数执行失败
            }
        } catch (Exception e) {
            log.error("执行函数失败:{}", functionName, e);
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("success", false);
            errorResult.put("message", "函数执行失败: " + e.getMessage());
            return errorResult;
        }
    }

    /**
     * 执行天气查询函数
     */
    private Map<String, Object> executeGetWeather(Map<String, Object> arguments) {
        String city = (String) arguments.get("city");
        String date = (String) arguments.get("date");
        
        log.info("查询天气:城市={},日期={}", city, date);
        
        // 这里可以集成真实的天气API
        // 目前返回模拟数据
        Map<String, Object> weatherData = new HashMap<>();
        weatherData.put("city", city);
        weatherData.put("date", date != null ? date : "今天");
        weatherData.put("temperature", "25°C");
        weatherData.put("weather", "晴天");
        weatherData.put("humidity", "60%");
        weatherData.put("wind", "东南风 3级");
        
        log.info("天气查询结果:{}", weatherData);
        return weatherData;
    }

    /**
     * 执行计算器函数
     */
    private Map<String, Object> executeCalculate(Map<String, Object> arguments) {
        String expression = (String) arguments.get("expression");
        
        log.info("执行计算:表达式={}", expression);
        
        try {
            // 这里可以集成更安全的表达式计算库
            // 目前使用简单的示例
            double result = evaluateExpression(expression);
            
            Map<String, Object> calcResult = new HashMap<>();
            calcResult.put("expression", expression);
            calcResult.put("result", result);
            
            log.info("计算结果:{}", calcResult);
            return calcResult;
        } catch (Exception e) {
            log.error("计算失败:{}", expression, e);
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("success", false);
            errorResult.put("message", "计算失败: " + e.getMessage());
            return errorResult;
        }
    }

    /**
     * 执行时间查询函数
     */
    private Map<String, Object> executeGetTime(Map<String, Object> arguments) {
        String timezone = (String) arguments.get("timezone");
        String format = (String) arguments.get("format");
        
        log.info("查询时间:时区={},格式={}", timezone, format);
        
        // 这里可以集成真实的时间API
        // 目前返回模拟数据
        Map<String, Object> timeData = new HashMap<>();
        timeData.put("timezone", timezone != null ? timezone : "Asia/Shanghai");
        timeData.put("format", format != null ? format : "yyyy-MM-dd HH:mm:ss");
        timeData.put("current_time", MyDateUtil.getDateParseTime());
        timeData.put("timestamp", System.currentTimeMillis());
        
        log.info("时间查询结果:{}", timeData);
        return timeData;
    }

    /**
     * 执行翻译函数
     */
    private Map<String, Object> executeTranslate(Map<String, Object> arguments) {
        String text = (String) arguments.get("text");
        String sourceLang = (String) arguments.get("source_lang");
        String targetLang = (String) arguments.get("target_lang");
        
        log.info("执行翻译:文本={},源语言={},目标语言={}", text, sourceLang, targetLang);
        
        // 这里可以集成真实的翻译API
        // 目前返回模拟数据
        Map<String, Object> translateResult = new HashMap<>();
        translateResult.put("original_text", text);
        translateResult.put("source_language", sourceLang != null ? sourceLang : "auto");
        translateResult.put("target_language", targetLang);
        translateResult.put("translated_text", "这是翻译后的文本");
        translateResult.put("confidence", 0.95);
        
        log.info("翻译结果:{}", translateResult);
        return translateResult;
    }

    /**
     * 简单的表达式计算(仅用于演示)
     */
    private double evaluateExpression(String expression) {
        // 这里应该使用更安全的表达式计算库
        // 目前只是简单的示例实现
        if (expression.contains("+")) {
            String[] parts = expression.split("\\+");
            return Double.parseDouble(parts[0].trim()) + Double.parseDouble(parts[1].trim());
        } else if (expression.contains("-")) {
            String[] parts = expression.split("-");
            return Double.parseDouble(parts[0].trim()) - Double.parseDouble(parts[1].trim());
        } else if (expression.contains("*")) {
            String[] parts = expression.split("\\*");
            return Double.parseDouble(parts[0].trim()) * Double.parseDouble(parts[1].trim());
        } else if (expression.contains("/")) {
            String[] parts = expression.split("/");
            return Double.parseDouble(parts[0].trim()) / Double.parseDouble(parts[1].trim());
        } else {
            return Double.parseDouble(expression.trim());
        }
    }

    /**
     * 第二次调用DeepSeek API,将函数结果发送给模型生成最终回复
     */
    private String callDeepSeekAPIWithFunctionResult(FunctionCallRequestDTO request, Map<String, Object> apiResponse, FunctionCallResultVO result, Map<String, Object> functionResult) {
        log.debug("第二次调用DeepSeek API,发送函数结果给模型生成最终回复");

        // 构建完整的消息列表,包含完整的对话历史
        List<Map<String, Object>> messages = new ArrayList<>();
        
        // 1. 添加第一次调用的所有消息(系统消息 + 用户消息)
//        List<Map<String, Object>> originalMessages = (List<Map<String, Object>>) functionCallRequest.get("messages");
//        messages.addAll(originalMessages);
        
        // 1、添加用户消息  (不需要系统消息)
        messages.add(Map.of("role", "user", "content", request.getUserInput()));
        
        // 2. 添加assistant的tool_calls消息
        Object toolCallsObj = apiResponse.get("tool_calls");
        if (toolCallsObj != null) {
            Map<String, Object> assistantMessage = new HashMap<>();
            assistantMessage.put("role", "assistant");
            assistantMessage.put("content", ""); // 确保content为空字符串
            assistantMessage.put("tool_calls", toolCallsObj);
            messages.add(assistantMessage);
        }
        

        
        // 3. 添加tool消息(函数结果)- 根据OpenAI示例,tool消息不应该包含name字段
        Map<String, Object> toolMessage = new HashMap<>();
        toolMessage.put("role", "tool");
        toolMessage.put("tool_call_id", result.getToolCallId());
        // 移除name字段,只保留tool_call_id和content
        toolMessage.put("content", JSONUtil.toJsonStr(functionResult));
        messages.add(toolMessage);

        // 构建请求体
        Map<String, Object> requestBody = new HashMap<>();
        
//        // 设置工具定义 - 使用tools而不是functions,符合DeepSeek API格式
//        List<Map<String, Object>> tools = new ArrayList<>();
//        for (FunctionDefinitionDTO function : PREDEFINED_FUNCTIONS) {
//            Map<String, Object> toolDef = new HashMap<>();
//            toolDef.put("type", "function");
//            
//            Map<String, Object> functionDef = new HashMap<>();
//            functionDef.put("name", function.getName());
//            functionDef.put("description", function.getDescription());
//            functionDef.put("parameters", function.getParameters());
//            
//            toolDef.put("function", functionDef);
//            tools.add(toolDef);
//        }
//        requestBody.put("tools", tools);
        
        requestBody.put("model", functionCallConfig.getDeepseek().getModelName());
        requestBody.put("messages", messages);
        requestBody.put("max_tokens", functionCallConfig.getDeepseek().getMaxTokens());
        requestBody.put("temperature", functionCallConfig.getDeepseek().getTemperature());
        requestBody.put("stream", false);

        log.debug("第二次调用请求体: {}", requestBody);

        try {
  
            return callDeepSeekAPIRealWithFunctionResult(requestBody);
        } catch (Exception e) {
            log.error("第二次DeepSeek API调用失败", e);
            return "抱歉,我无法生成最终回复。";
        }
    }

    /**
     * 调用真实的DeepSeek API,发送函数结果
     */
    private String callDeepSeekAPIRealWithFunctionResult(Map<String, Object> requestBody) throws Exception {
        log.debug("调用DeepSeek API,发送函数结果,URL: {}, Model: {}", 
                functionCallConfig.getDeepseek().getApiUrl(), functionCallConfig.getDeepseek().getModelName());
        
        // 构建请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        if (StrUtil.isNotBlank(functionCallConfig.getDeepseek().getApiKey())) {
            headers.setBearerAuth(functionCallConfig.getDeepseek().getApiKey());
        }
        
        // 发送请求
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
        ResponseEntity<String> response = restTemplate.postForEntity(
                functionCallConfig.getDeepseek().getApiUrl(), entity, String.class);
        
        if (response.getStatusCode() == HttpStatus.OK) {
            String responseBody = response.getBody();
            log.debug(" callDeepSeekAPIRealWithFunctionResult DeepSeek API响应:{}", responseBody);
            
            JsonNode jsonResponse = objectMapper.readTree(responseBody);
            
            JsonNode choices = jsonResponse.get("choices");
            if (choices != null && choices.isArray() && choices.size() > 0) {
                JsonNode firstChoice = choices.get(0);
                JsonNode message = firstChoice.get("message");
                if (message != null) {
                    return message.get("content").asText("");
                }
            }
        } else {
            throw new RuntimeException("DeepSeek API调用失败,状态码:" + response.getStatusCode());
        }
        return "抱歉,我无法生成最终回复。";
    }
    

}


网站公告

今日签到

点亮在社区的每一天
去签到