{"record":{"id":"9d8b96d759107eea","repo":"alibaba/spring-ai-alibaba","slug":"tool-selection-failed-using-all-tools","errorCode":null,"errorMessage":"Tool selection failed, using all tools: {}","messagePattern":"Tool selection failed, using all tools: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/interceptor/toolselection/ToolSelectionInterceptor.java","lineNumber":176,"sourceCode":"\t\t\tString responseText = response.getResult().getOutput().getText();\n\n\t\t\t// Parse JSON response\n\t\t\tSet<String> selected = parseToolSelection(responseText);\n\n\t\t\t// Add always-include tools\n\t\t\tselected.addAll(alwaysInclude);\n\n\t\t\t// Limit to maxTools if specified\n\t\t\tif (maxTools != null && selected.size() > maxTools) {\n\t\t\t\tList<String> selectedList = new ArrayList<>(selected);\n\t\t\t\tselected = new HashSet<>(selectedList.subList(0, maxTools));\n\t\t\t}\n\n\t\t\treturn selected;\n\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\tlog.warn(\"Tool selection failed, using all tools: {}\", e.getMessage());\n\t\t\treturn new HashSet<>(toolNames);\n\t\t}\n\t}\n\n\tprivate Set<String> parseToolSelection(String responseText) {\n\t\ttry {\n\t\t\t// Try to parse as JSON\n\t\t\tToolSelectionResponse response = objectMapper.readValue(responseText, ToolSelectionResponse.class);\n\t\t\treturn new HashSet<>(response.tools);\n\t\t}\n\t\tcatch (Exception e) {\n\t\t\t// Fallback: extract tool names from text\n\t\t\tlog.debug(\"Failed to parse JSON, using fallback extraction\");\n\t\t\treturn new HashSet<>();\n\t\t}\n\t}\n\n\t@Override","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/interceptor/toolselection/ToolSelectionInterceptor.java#L158-L194","documentation":"ToolSelectionInterceptor asks an LLM to pick a subset of available tools; selectTools wraps that selection in a broad catch, and on any failure it logs this warning and falls back to passing ALL tools to the model. The workflow continues, but the model sees the full tool set, which can degrade selection quality and increase token usage.","triggerScenarios":"selectTools throws inside the selection flow — typically when parseToolSelection cannot parse the model's responseText into a valid tool-name set (malformed JSON, hallucinated tool names, empty response), or the selection model call itself errors.","commonSituations":"1) The selection LLM returns prose or fenced markdown instead of the expected JSON/name list. 2) The selection model names tools that don't exist in toolNames. 3) A small/weak selection model (e.g. a cheap endpoint) that frequently produces unparseable output. 4) Selection prompt template misconfigured so instructions don't match the parser.","solutions":["Inspect the selection model's raw response (logged context) and strengthen the selection prompt with explicit output-format instructions and an example.","Make parseToolSelection more tolerant: strip markdown fences, trim whitespace, and ignore unknown tool names instead of failing.","Use a more capable model for tool selection.","If the fallback is acceptable, silence the noise by fixing the common parse failure case; if not, tighten validation of the selection response."],"exampleFix":"// before (brittle parser)\nSet<String> names = new HashSet<>(List.of(responseText.split(\",\")));\n// after\nString json = responseText.replaceAll(\"^```(json)?|```$\", \"\").trim();\nSet<String> names = parseNames(json, toolNames); // ignore unknown names","handlingStrategy":"fallback","validationCode":"static boolean isParsableSelection(String responseText) {\n    if (responseText == null) return false;\n    String s = responseText.replaceAll(\"```(json)?\", \"\").trim();\n    return s.startsWith(\"[\") || s.startsWith(\"{\") || !s.isEmpty();\n}","typeGuard":null,"tryCatchPattern":"try {\n    selected = selectionModel.call(selectionPrompt);\n} catch (Exception e) {\n    log.warn(\"Tool selection failed, using all tools: {}\", e.getMessage());\n    return new HashSet<>(toolNames);\n}","preventionTips":["Give the selection model a strict output format with an example","Strip markdown fences before parsing","Ignore unknown tool names instead of failing the parse","Use a reliable model for the selection step"],"tags":["fallback","tool-selection","llm-output-parsing","interceptor"],"backgroundTag":"unexpected-response-shape","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}