001/* 002 * Copyright (c) 2023-2026, Agents-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.agentsflex.core.agent.react; 017 018import com.agentsflex.core.model.chat.tool.Parameter; 019import com.agentsflex.core.model.chat.tool.Tool; 020 021import java.util.List; 022 023/** 024 * ReAct Agent 工具函数辅助类 025 */ 026public class Util { 027 028 /** 029 * 生成带缩进的空格字符串 030 */ 031 public static String indent(int depth) { 032 StringBuilder sb = new StringBuilder(); 033 for (int i = 0; i < depth; i++) { 034 sb.append(" "); // 2 spaces per level 035 } 036 return sb.toString(); 037 } 038 039 /** 040 * 基于工具列表生成结构化、LLM 友好的工具描述文本 041 */ 042 public static String buildToolsDescription(List<Tool> tools) { 043 StringBuilder sb = new StringBuilder(); 044 for (Tool tool : tools) { 045 sb.append("### 工具名称: ").append(tool.getName()).append("\n"); 046 sb.append("**描述**: ").append(tool.getDescription()).append("\n"); 047 sb.append("**调用参数格式 (JSON 对象)**:\n"); 048 sb.append("```json\n"); 049 050 sb.append("{\n"); 051 Parameter[] rootParams = tool.getParameters(); 052 for (int i = 0; i < rootParams.length; i++) { 053 appendParameter(sb, rootParams[i], 1); 054 if (i < rootParams.length - 1) { 055 sb.append(","); 056 } 057 sb.append("\n"); 058 } 059 sb.append("}\n"); 060 sb.append("```\n\n"); 061 } 062 return sb.toString(); 063 } 064 065 /** 066 * 递归追加参数描述(支持 object 和 array) 067 */ 068 private static void appendParameter(StringBuilder sb, Parameter param, int depth) { 069 String currentIndent = indent(depth); 070 String typeLabel = getTypeLabel(param); 071 072 // 构建注释信息 073 StringBuilder comment = new StringBuilder(); 074 if (param.isRequired()) { 075 comment.append(" (必填)"); 076 } else { 077 comment.append(" (可选)"); 078 } 079 080 if (param.getDescription() != null && !param.getDescription().trim().isEmpty()) { 081 comment.append(" - ").append(param.getDescription().trim()); 082 } 083 084 if (param.getEnums() != null && param.getEnums().length > 0) { 085 comment.append(" [可选值: ").append(String.join(", ", param.getEnums())).append("]"); 086 } 087 088 String paramName = param.getName() != null ? param.getName() : "item"; 089 090 // 判断是否为数组类型 091 boolean isArray = isArrayType(param.getType()); 092 093 if (isArray && param.getChildren() != null && !param.getChildren().isEmpty()) { 094 // 数组元素为对象:描述其结构 095 sb.append(currentIndent).append("\"").append(paramName).append("\": ["); 096 sb.append(comment).append("\n"); 097 098 String innerIndent = indent(depth + 1); 099 sb.append(innerIndent).append("{\n"); 100 101 List<Parameter> elementFields = param.getChildren(); 102 for (int i = 0; i < elementFields.size(); i++) { 103 appendParameter(sb, elementFields.get(i), depth + 2); 104 if (i < elementFields.size() - 1) { 105 sb.append(","); 106 } 107 sb.append("\n"); 108 } 109 sb.append(innerIndent).append("}\n"); 110 sb.append(currentIndent).append("]"); 111 112 } else if (isArray) { 113 // 简单类型数组 114 sb.append(currentIndent).append("\"").append(paramName).append("\": [ \"<") 115 .append(typeLabel).append(">") 116 .append(comment) 117 .append("\" ]"); 118 119 } else if (param.getChildren() != null && !param.getChildren().isEmpty()) { 120 // 嵌套对象 121 sb.append(currentIndent).append("\"").append(paramName).append("\": {"); 122 sb.append(comment).append("\n"); 123 124 List<Parameter> children = param.getChildren(); 125 for (int i = 0; i < children.size(); i++) { 126 appendParameter(sb, children.get(i), depth + 1); 127 if (i < children.size() - 1) { 128 sb.append(","); 129 } 130 sb.append("\n"); 131 } 132 sb.append(currentIndent).append("}"); 133 134 } else { 135 // 叶子字段(简单类型) 136 sb.append(currentIndent).append("\"").append(paramName).append("\": \"<") 137 .append(typeLabel).append(">") 138 .append(comment) 139 .append("\""); 140 } 141 } 142 143 /** 144 * 判断类型是否为数组 145 */ 146 private static boolean isArrayType(String type) { 147 if (type == null) return false; 148 String lower = type.toLowerCase(); 149 return "array".equals(lower) || "list".equals(lower); 150 } 151 152 /** 153 * 获取标准化的类型标签 154 */ 155 private static String getTypeLabel(Parameter param) { 156 String type = param.getType(); 157 if (type == null) return "string"; 158 159 // 若有子字段,则视为 object 160 if (param.getChildren() != null && !param.getChildren().isEmpty()) { 161 return "object"; 162 } 163 164 String lower = type.toLowerCase(); 165 if ("string".equals(lower) || "str".equals(lower)) { 166 return "string"; 167 } else if ("integer".equals(lower) || "int".equals(lower)) { 168 return "integer"; 169 } else if ("number".equals(lower) || "float".equals(lower) || "double".equals(lower)) { 170 return "number"; 171 } else if ("boolean".equals(lower) || "bool".equals(lower)) { 172 return "boolean"; 173 } else if ("array".equals(lower) || "list".equals(lower)) { 174 return "array"; 175 } else { 176 return type; // 保留自定义类型名,如 date, uri 等 177 } 178 } 179}