diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 40dfe58..cce040d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,47 +1,55 @@ --- -name: Bug Report -about: Report a bug to help us improve +name: 缺陷报告 (Bug) +about: 提交缺陷以帮助我们改进 title: '[BUG] ' labels: bug assignees: '' --- -## Bug Description +## 修复方式(必选) -A clear and concise description of what the bug is. +你希望这个问题如何被解决?(请勾选一项) -## Steps to Reproduce +- [ ] 需要维护者修复(我暂时无法提交 PR) +- [ ] 我可以自行修复并提交 PR +- [ ] 不确定 / 需要讨论 -1. Go to '...' -2. Configure '...' -3. Call method '...' -4. See error +## 缺陷描述 -## Expected Behavior +请用简洁清晰的语言描述问题现象。 -A clear and concise description of what you expected to happen. +## 复现步骤 -## Actual Behavior +1. 进入 '...' +2. 配置 '...' +3. 调用方法 '...' +4. 看到错误 -What actually happened. +## 期望行为 -## Environment +你期望发生什么? -- **OS**: [e.g., macOS 14.0, Ubuntu 22.04] -- **Java Version**: [e.g., OpenJDK 17.0.2] -- **Assistant Agent Version**: [e.g., 1.0.0] -- **Spring Boot Version**: [e.g., 3.4.0] +## 实际行为 -## Logs/Stack Trace +实际发生了什么? + +## 环境信息 + +- **操作系统**: [例如 macOS 14.0, Ubuntu 22.04] +- **Java 版本**: [例如 OpenJDK 17.0.2] +- **Assistant Agent 版本**: [例如 1.0.0] +- **Spring Boot 版本**: [例如 3.4.0] + +## 日志/堆栈 ``` -Paste relevant logs or stack trace here +请粘贴相关日志或堆栈信息(注意去除敏感信息) ``` -## Configuration +## 配置 ```yaml -# Relevant configuration (remove sensitive data) +# 相关配置(请去除敏感信息) spring: ai: alibaba: @@ -50,11 +58,10 @@ spring: # ... ``` -## Additional Context - -Add any other context about the problem here. +## 额外上下文 -## Possible Solution (optional) +补充任何其他有助于定位问题的信息(例如:相关链接、截图、录屏、最小复现仓库等)。 -If you have an idea of what might be causing this or how to fix it. +## 可能的解决方案(可选) +如果你已经有初步排查结果或修复思路,请写在这里;如果你愿意提交 PR,也可以说明预计修改点/模块。 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..ee76ad7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,6 @@ +blank_issues_enabled: false + +contact_links: + - name: 使用问题 / Q&A + url: https://github.com///discussions + about: 使用咨询、安装问题、如何配置等,请优先在 Discussions 提问。 diff --git a/assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/search/tools/UnifiedSearchCodeactTool.java b/assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/search/tools/UnifiedSearchCodeactTool.java index 24a18f2..55c6005 100644 --- a/assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/search/tools/UnifiedSearchCodeactTool.java +++ b/assistant-agent-extensions/src/main/java/com/alibaba/assistant/agent/extension/search/tools/UnifiedSearchCodeactTool.java @@ -148,19 +148,50 @@ private SearchResultSet executeUnifiedSearch(Map params, ToolCon String query = (String) params.get("query"); Integer limit = params.containsKey("limit") ? ((Number) params.get("limit")).intValue() : 10; - // 解析要搜索的源类型列表 - List sourceTypes = parseSourceTypes(params); + // 解析要搜索的源 keys (可以是类型名,也可以是 provider 名) + List sourceKeys = parseSourceKeys(params); - log.info("UnifiedSearchCodeactTool#executeUnifiedSearch - reason=开始统一搜索, query={}, sourceTypes={}, limit={}", - query, sourceTypes, limit); + log.info("UnifiedSearchCodeactTool#executeUnifiedSearch - reason=开始统一搜索, query={}, sources={}, limit={}", + query, sourceKeys, limit); // 并行搜索多个数据源 List allItems = new ArrayList<>(); int successCount = 0; int failureCount = 0; - for (SearchSourceType sourceType : sourceTypes) { + for (String key : sourceKeys) { try { + // 1. 尝试作为 Provider Name 匹配 + Optional namedProvider = searchProviders.stream() + .filter(p -> p.getName().equalsIgnoreCase(key)) + .findFirst(); + + if (namedProvider.isPresent()) { + // 按指定 Provider 名称搜索 + SearchProvider provider = namedProvider.get(); + // 当指定具体 Provider 时,尝试使用 CUSTOM 类型,或者该 Provider 支持的第一个类型 + // 这里为了简单,我们传递 CUSTOM 类型,如果 Provider 不处理 SourceType 也没关系 + SearchRequest request = buildSearchRequest(query, SearchSourceType.CUSTOM, limit); + + List items = provider.search(request); + if (items != null) { + allItems.addAll(items); + } + successCount++; + log.debug("UnifiedSearchCodeactTool#executeUnifiedSearch - reason=指定Provider搜索成功, provider={}, resultCount={}", + provider.getName(), items.size()); + continue; + } + + // 2. 尝试作为 SourceType 匹配 + SearchSourceType sourceType; + try { + sourceType = SearchSourceType.valueOf(key.toUpperCase()); + } catch (IllegalArgumentException e) { + log.warn("UnifiedSearchCodeactTool#executeUnifiedSearch - reason=无效的源类型或Provider名称, key={}", key); + continue; + } + // 查找支持该源类型的 provider List providers = searchProviders.stream() .filter(p -> p.supports(sourceType)) @@ -185,8 +216,8 @@ private SearchResultSet executeUnifiedSearch(Map params, ToolCon } catch (Exception e) { failureCount++; - log.error("UnifiedSearchCodeactTool#executeUnifiedSearch - reason=单源搜索失败, sourceType={}, error={}", - sourceType, e.getMessage(), e); + log.error("UnifiedSearchCodeactTool#executeUnifiedSearch - reason=搜索执行失败, sourceKey={}, error={}", + key, e.getMessage(), e); } } @@ -208,10 +239,10 @@ private SearchResultSet executeUnifiedSearch(Map params, ToolCon } /** - * 解析要搜索的源类型列表。 + * 解析要搜索的源列表(字符串)。 */ - private List parseSourceTypes(Map params) { - List sourceTypes = new ArrayList<>(); + private List parseSourceKeys(Map params) { + List keys = new ArrayList<>(); // 如果指定了 sources 参数 if (params.containsKey("sources")) { @@ -219,24 +250,38 @@ private List parseSourceTypes(Map params) { if (sourcesObj instanceof List) { List sourcesList = (List) sourcesObj; for (Object source : sourcesList) { - try { - SearchSourceType type = SearchSourceType.valueOf(source.toString().toUpperCase()); - sourceTypes.add(type); - } - catch (Exception e) { - log.warn("UnifiedSearchCodeactTool#parseSourceTypes - reason=无效的源类型, source={}", source); + if (source != null) { + keys.add(source.toString()); } } } } - // 如果没有指定或解析失败,使用默认的源类型 - if (sourceTypes.isEmpty()) { - sourceTypes.add(SearchSourceType.PROJECT); - sourceTypes.add(SearchSourceType.KNOWLEDGE); + // 如果没有指定,使用默认的源类型 + if (keys.isEmpty()) { + keys.add(SearchSourceType.PROJECT.name()); + keys.add(SearchSourceType.KNOWLEDGE.name()); } - return sourceTypes; + return keys; + } + + /** + * 获取所有可用的源名称(包括标准类型和Provider名称)。 + */ + private List getAvailableSourceNames() { + List names = new ArrayList<>(); + // 添加标准类型 + for (SearchSourceType type : SearchSourceType.values()) { + names.add(type.name().toLowerCase()); + } + // 添加 Provider 名称 + if (searchProviders != null) { + for (SearchProvider p : searchProviders) { + names.add(p.getName()); + } + } + return names; } /** @@ -265,9 +310,9 @@ private CodeactToolDefinition buildCodeactDefinition() { .addParameter(ParameterNode.builder() .name("sources") .type(ParameterType.ARRAY) - .description("要搜索的数据源列表,默认搜索 project 和 knowledge") + .description("要搜索的数据源列表,支持标准类型(project, knowledge, web等)或指定Provider名称") .required(false) - .enumValues(Arrays.asList("project", "knowledge", "web", "experience")) + .enumValues(getAvailableSourceNames()) .build()) .addParameter(ParameterNode.builder() .name("limit") @@ -335,9 +380,9 @@ private String buildInputSchema() { sourcesProp.put("type", "array"); Map itemsProp = new LinkedHashMap<>(); itemsProp.put("type", "string"); - itemsProp.put("enum", Arrays.asList("project", "knowledge", "web", "experience")); + itemsProp.put("enum", getAvailableSourceNames()); sourcesProp.put("items", itemsProp); - sourcesProp.put("description", "要搜索的数据源列表,默认搜索 project 和 knowledge"); + sourcesProp.put("description", "要搜索的数据源列表,支持标准类型或Provider名称"); properties.put("sources", sourcesProp); // limit 参数(可选) diff --git a/assistant-agent-autoconfigure/src/main/java/com/alibaba/assistant/agent/autoconfigure/CodeactAgentConfig.java b/assistant-agent-start/src/main/java/com/alibaba/assistant/agent/start/config/CodeactAgentConfig.java similarity index 96% rename from assistant-agent-autoconfigure/src/main/java/com/alibaba/assistant/agent/autoconfigure/CodeactAgentConfig.java rename to assistant-agent-start/src/main/java/com/alibaba/assistant/agent/start/config/CodeactAgentConfig.java index 18bb715..092d2be 100644 --- a/assistant-agent-autoconfigure/src/main/java/com/alibaba/assistant/agent/autoconfigure/CodeactAgentConfig.java +++ b/assistant-agent-start/src/main/java/com/alibaba/assistant/agent/start/config/CodeactAgentConfig.java @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.alibaba.assistant.agent.autoconfigure; +package com.alibaba.assistant.agent.start.config; +import com.alibaba.assistant.agent.autoconfigure.CodeactAgent; import com.alibaba.assistant.agent.common.tools.CodeactTool; import com.alibaba.assistant.agent.common.tools.ReplyCodeactTool; import com.alibaba.assistant.agent.common.tools.SearchCodeactTool; @@ -26,6 +27,7 @@ import com.alibaba.assistant.agent.extension.experience.fastintent.FastIntentService; import com.alibaba.assistant.agent.extension.experience.hook.FastIntentReactHook; import com.alibaba.assistant.agent.extension.experience.spi.ExperienceProvider; +import com.alibaba.assistant.agent.extension.search.tools.SearchCodeactToolFactory; import com.alibaba.assistant.agent.extension.search.tools.UnifiedSearchCodeactTool; import com.alibaba.assistant.agent.common.enums.Language; import com.alibaba.cloud.ai.graph.agent.hook.Hook; @@ -245,7 +247,7 @@ def subscribe_medicine_reminder(): * * @param chatModel Spring AI的ChatModel * @param replyCodeactTools Reply模块的工具列表(可选) - * @param searchCodeactTools Search模块的工具列表(可选) + * @param searchCodeactToolFactory Search模块的工具工厂(可选) * @param triggerCodeactTools Trigger模块的工具列表(可选) * @param unifiedSearchCodeactTool 统一搜索工具(可选) * @param mcpToolCallbackProvider MCP工具提供者(由MCP Client Boot Starter自动注入,可选) @@ -254,7 +256,7 @@ def subscribe_medicine_reminder(): public CodeactAgent grayscaleCodeactAgent( ChatModel chatModel, @Autowired(required = false) List replyCodeactTools, - @Autowired(required = false) List searchCodeactTools, + @Autowired(required = false) SearchCodeactToolFactory searchCodeactToolFactory, @Autowired(required = false) List triggerCodeactTools, @Autowired(required = false) UnifiedSearchCodeactTool unifiedSearchCodeactTool, @Autowired(required = false) ToolCallbackProvider mcpToolCallbackProvider, @@ -277,9 +279,12 @@ public CodeactAgent grayscaleCodeactAgent( } // 添加Search工具 - if (searchCodeactTools != null && !searchCodeactTools.isEmpty()) { - allCodeactTools.addAll(searchCodeactTools); - logger.info("CodeactAgentConfig#grayscaleCodeactAgent - reason=添加SearchCodeactTools, count={}", searchCodeactTools.size()); + if (searchCodeactToolFactory != null) { + List searchTools = searchCodeactToolFactory.createTools(); + if (!searchTools.isEmpty()) { + allCodeactTools.addAll(searchTools); + logger.info("CodeactAgentConfig#grayscaleCodeactAgent - reason=添加SearchCodeactTools, count={}", searchTools.size()); + } } // 添加Reply工具 @@ -364,7 +369,7 @@ public CodeactAgent grayscaleCodeactAgent( .allowIO(false) .allowNativeAccess(false) .executionTimeout(30000) - .tools(replyCodeactTools.toArray(new ToolCallback[0])) + .tools(replyCodeactTools != null ? replyCodeactTools.toArray(new ToolCallback[0]) : new ToolCallback[0]) .codeactTools(allCodeactTools) .hooks(reactHooks) .subAgentHooks(codeactHooks)