通义千问( 四 ) Function Call 函数调用

时间:2025-03-10 16:40:20
import com.alibaba.dashscope.aigc.generation.Generation; import com.alibaba.dashscope.aigc.generation.GenerationParam; import com.alibaba.dashscope.aigc.generation.GenerationResult; import com.alibaba.dashscope.common.Message; import com.alibaba.dashscope.common.Role; import com.alibaba.dashscope.exception.ApiException; import com.alibaba.dashscope.exception.InputRequiredException; import com.alibaba.dashscope.exception.NoApiKeyException; import com.alibaba.dashscope.tools.FunctionDefinition; import com.alibaba.dashscope.tools.ToolCallBase; import com.alibaba.dashscope.tools.ToolCallFunction; import com.alibaba.dashscope.tools.ToolFunction; import com.alibaba.dashscope.utils.Constants; import com.alibaba.dashscope.utils.JsonUtils; import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.victools.jsonschema.generator.*; import com.yuan.tongyibase.tools.GetNamesTool; import com.yuan.tongyibase.tools.GetTimeTool; import com.yuan.tongyibase.tools.GetWhetherTool; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import com.alibaba.dashscope.aigc.generation.GenerationOutput.Choice; @RestController @RequestMapping("/tongyi") public class CallFuncController { @Value("${-key}") private String apiKey; @RequestMapping("/call/func") public String callFunc(@RequestParam(value = "message", required = false, defaultValue = "中国的首都是哪里?") String message) throws NoApiKeyException, InputRequiredException { String selectTool = selectTool(message); return selectTool; } public String selectTool(String message) throws NoApiKeyException, ApiException, InputRequiredException { // 设置API密钥 Constants.apiKey = apiKey; // 创建SchemaGeneratorConfigBuilder实例,指定使用JSON格式的模式版本 SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON); // 构建SchemaGeneratorConfig配置,包含额外的OpenAPI格式值,但不使用枚举的toString方法进行展平 SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES) .without(Option.FLATTENED_ENUMS_FROM_TOSTRING) .build(); // 根据配置创建SchemaGenerator实例,用于生成模式 SchemaGenerator generator = new SchemaGenerator(config); // 生成GetWhetherTool类的JSON Schema ObjectNode jsonSchema_whether = generator.generateSchema(GetWhetherTool.class); // 生成GetTimeTool类的JSON Schema ObjectNode jsonSchema_time = generator.generateSchema(GetTimeTool.class); // 生成GetNamesTool类的JSON Schema ObjectNode jsonSchema_names = generator.generateSchema(GetNamesTool.class); // 构建获取指定地区天气的函数定义 FunctionDefinition fd_whether = FunctionDefinition.builder() .name("get_current_whether") // 设置函数名称 .description("获取指定地区的天气") // 设置函数描述 .parameters(JsonUtils.parseString(jsonSchema_whether.toString()).getAsJsonObject()) // 设置函数参数 .build(); // 构建获取当前时刻时间的函数定义 FunctionDefinition fd_time = FunctionDefinition.builder() .name("get_current_time") // 设置函数名称 .description("获取当前时刻的时间") // 设置函数描述 .parameters(JsonUtils.parseString(jsonSchema_time.toString()).getAsJsonObject()) // 设置函数参数 .build(); // 构建获取当前names的函数定义 FunctionDefinition fd_names = FunctionDefinition.builder() .name("get_current_names") // 设置函数名称 .description("获取好友") // 设置函数描述 .parameters(JsonUtils.parseString(jsonSchema_names.toString()).getAsJsonObject()) // 设置函数参数 .build(); // 构建系统消息,用于提示助手使用工具回答问题 Message systemMsg = Message.builder() .role(Role.SYSTEM.getValue()) // 设置消息角色为系统 .content("你是一个乐于助人的AI助手。当被问到问题时,尽可能使用工具。") // 设置消息内容 .build(); Message userMsg = Message.builder().role(Role.USER.getValue()).content(message).build(); List<Message> messages = new ArrayList<>(); messages.addAll(Arrays.asList(systemMsg, userMsg)); // 构建生成参数对象,用于配置文本生成的相关参数 GenerationParam param = GenerationParam.builder() // 设置所使用的模型为“qwen-max” .model("qwen-turbo") //qwen-max // 设置对话历史,用于模型生成时参考 .messages(messages) // 设置生成结果的格式为消息格式 .resultFormat(GenerationParam.ResultFormat.MESSAGE) // 设置可用的工具函数列表,包括天气查询和时间查询功能 .tools(Arrays.asList( ToolFunction.builder().function(fd_whether).build(), ToolFunction.builder().function(fd_time).build(), ToolFunction.builder().function(fd_names).build())) .build(); // 大模型的第一轮调用 Generation gen = new Generation(); GenerationResult result = gen.call(param); System.out.println("\n大模型第一轮输出信息:" + JsonUtils.toJson(result)); for (Choice choice : result.getOutput().getChoices()) { messages.add(choice.getMessage()); // 如果需要调用工具 if (result.getOutput().getChoices().get(0).getMessage().getToolCalls() != null) { for (ToolCallBase toolCall : result.getOutput().getChoices().get(0).getMessage().getToolCalls()) { if (toolCall.getType().equals("function")) { // 获取工具函数名称和入参 String functionName = ((ToolCallFunction) toolCall).getFunction().getName(); String functionArgument = ((ToolCallFunction) toolCall).getFunction().getArguments(); // 大模型判断调用天气查询工具的情况 if (functionName.equals("get_current_whether")) { GetWhetherTool GetWhetherFunction = JsonUtils.fromJson(functionArgument, GetWhetherTool.class); String whether = GetWhetherFunction.call(); Message toolResultMessage = Message.builder() .role("tool") .content(String.valueOf(whether)) .toolCallId(toolCall.getId()) .build(); messages.add(toolResultMessage); System.out.println("\n工具输出信息:" + whether); } // 大模型判断调用时间查询工具的情况 else if (functionName.equals("get_current_time")) { GetTimeTool GetTimeFunction = JsonUtils.fromJson(functionArgument, GetTimeTool.class); String time = GetTimeFunction.call(); Message toolResultMessage = Message.builder() .role("tool") .content(String.valueOf(time)) .toolCallId(toolCall.getId()) .build(); messages.add(toolResultMessage); System.out.println("\n工具输出信息:" + time); } // 大模型判断调用[ names ]的情况 else if (functionName.equals("get_current_names")) { GetNamesTool GetNamesFunction = JsonUtils.fromJson(functionArgument, GetNamesTool.class); String names = GetNamesFunction.call(); Message toolResultMessage = Message.builder() .role("tool") .content(String.valueOf(names)) .toolCallId(toolCall.getId()) .build(); messages.add(toolResultMessage); System.out.println("\n工具输出信息:" + names); } } } } // 如果无需调用工具,直接输出大模型的回复 else { System.out.println("\n最终答案:" + result.getOutput().getChoices().get(0).getMessage().getContent()); return "\n最终答案:" + result.getOutput().getChoices().get(0).getMessage().getContent(); } } // 大模型的第二轮调用 包含工具输出信息 param.setMessages(messages); result = gen.call(param); System.out.println("\n大模型第二轮输出信息:" + JsonUtils.toJson(result)); System.out.println(("\n最终答案:" + result.getOutput().getChoices().get(0).getMessage().getContent())); return "\n最终答案:" + result.getOutput().getChoices().get(0).getMessage().getContent(); } }