当前位置: 首页 > news >正文

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

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 {@Autowiredprivate FunctionCallConfig functionCallConfig;@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate 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);// 调用APIMap<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_callJsonNode toolCalls = message.get("tool_calls");if (toolCalls != null && toolCalls.isArray() && toolCalls.size() > 0) {log.info("检测到工具调用: {}", toolCalls.toString());result.put("tool_calls", toolCalls);// 提取第一个工具调用的IDJsonNode 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_callObject toolCallsObj = apiResponse.get("tool_calls");if (toolCallsObj != null) {result.setFunctionCalled(true);if (toolCallsObj instanceof JsonNode) {// 真实API返回的JsonNodeJsonNode 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_idif (firstToolCall.has("id")) {result.setToolCallId(firstToolCall.get("id").asText());}}}} else if (toolCallsObj instanceof List) {// 模拟模式返回的ListList<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_idresult.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和contenttoolMessage.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 "抱歉,我无法生成最终回复。";}}
http://www.dtcms.com/a/286505.html

相关文章:

  • elementui-admin构建
  • 行为型设计模式:解释器模式
  • ES v.s Milvus v.s PG
  • 【unitrix】 6.8 加一运算(add_one.rs)
  • ubuntu源码安装ceres-solves
  • docker--Dockerfile
  • CherryStudio+playwright-mcp-server实现AI自动化
  • 20250718-1-Kubernetes 应用程序生命周期管理-应用部署、升级、弹性_笔记
  • C语言-一维数组,二维数组
  • 七彩喜康养平台:大数据时代,养老服务从智能走向智慧
  • 实习十三——传输层协议
  • iOS 数据持久化
  • iOS OC 图片压缩
  • 如何快速下载 MT4 交易平台
  • Linux学习之认识Linux的基本指令
  • LeetCodeHot100---螺旋矩阵---一题两解
  • Unity 常见数据结构分析与实战展示 C#
  • 基于单片机自行车自动防盗报警系统设计
  • VUE目录结构详解
  • NW983NW988美光固态闪存NW991NW992
  • 无符号乘法运算的硬件逻辑实现 ————取自《湖科大教书匠》
  • PAT 1012 The Best Rank
  • QML vscode语法高亮和颜色区分。
  • 【vLLM 学习】Encoder Decoder Multimodal
  • Kotlin集合过滤
  • 有效的括号数据结构oj题(力口20)
  • 无人机传感器模组运行与技术难点分析
  • Axure RP 10 预览显示“无标题文档”的空白问题探索【护航版】
  • 美团闪购最新版 mtgsig1.2
  • LP-MSPM0G3507学习--04GPIO控制