面对上百个API工具时,如何让AI智能体准确选择并调用合适的工具,是一个在构建复杂智能应用时常遇到的挑战。传统的Function Calling方式是将所有工具的schema一次性全部塞进提示词,这在工具数量庞大时不仅会导致Token消耗剧增,还会让大模型陷入“选择困难”,影响决策速度和准确率。
本文将介绍一个基于Spring AI Alibaba Graph实现的解决方案,通过 “向量检索粗筛 + 精确调用” 的两阶段策略,优雅地解决大规模工具调度问题。我们将以Java Math类的100+个静态方法为例,构建一个智能数学助手,并深入解析其核心架构与实现细节。
一、传统方案的困境与破局思路
假设我们需要构建一个支持各种数学运算的智能助手。Java Math类提供了超过100个静态方法,涵盖三角函数、对数、幂运算等。
传统做法:
- 将所有方法的描述(schema)放入LLM的提示词中。
- 每次用户提问(如“计算8的平方根”),LLM都需要从这100多个选项中理解并选择
sqrt()方法。
这带来三个明显问题:
- 成本高昂:每次调用都需传输大量工具描述,Token消耗巨大。
- 速度缓慢:LLM需要处理和理解所有工具信息才能做出决策。
- 准确率下降:选项过多容易导致混淆,例如
sqrt、cbrt、pow都与“开方”相关,模型可能选错。
破局思路:模仿人类解决问题的过程。
- 理解问题:先提取“计算平方根”这个核心意图。
- 快速筛选:在知识库中快速匹配出与“平方根”相关的几个方法(如
sqrt, cbrt, pow)。
- 精确选择:从这几个高度相关的方法中,精准选择
sqrt并执行。
这正是下文所述两阶段策略的核心。
二、核心架构:两阶段策略详解
整个工作流设计为两个核心阶段,通过图编排进行串联,流程清晰高效。

此节点负责从海量工具中快速筛选出最相关的少数几个。其核心代码如下:
public class ToolAgent implements NodeAction {
private ChatClient chatClient;
private VectorStoreService vectorStoreService;
private String inputTextKey;
private static final String CLASSIFIER_PROMPT_TEMPLATE = “””
### Job Description
You are a text keyword extraction engine that can analyze the questions
passed in by users and extract the main keywords of this sentence.
### Task
You need to extract one or more keywords from this sentence,
without missing the main body of the user description
### Constraint
Multiple keywords returned, separated by spaces
“””;
@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
// 1. 获取用户输入
String inputText = (String) state.value(inputTextKey).orElseThrow();
// 2. 调用LLM提取问题关键词
ChatResponse response = chatClient.prompt()
.system(CLASSIFIER_PROMPT_TEMPLATE)
.user(inputText) // 例如:“计算 8 的平方根”
.call()
.chatResponse();
String keywords = response.getResult().getOutput().getText(); // 提取结果:“8 平方根 计算”
// 3. 基于关键词进行向量相似度检索,只返回最相关的Top-K个工具(例如K=3)
List<Document> hitTools = vectorStoreService.search(keywords, 3);
// 4. 更新状态,传递给下一节点
Map<String, Object> updatedState = new HashMap<>();
updatedState.put(Constant.HIT_TOOL, hitTools);
updatedState.put(inputTextKey, keywords);
return updatedState;
}
}
关键点:
- 意图理解:利用大模型提取用户问题的核心关键词。
- 向量检索:基于关键词的嵌入向量,在工具库中进行语义相似度搜索。
- Top-K筛选:仅保留相似度最高的K个(如3个)工具,极大减少后续LLM的决策负担。
向量库的初始化是性能的基础。系统启动时,会将所有工具的高质量描述转换为向量:
private void initializeVectorStore() {
List<Tool> allTools = new ArrayList<>();
// 遍历 Math 类的所有静态方法
for (Method method : Math.class.getMethods()) {
if (Modifier.isStatic(method.getModifiers())) {
// 从官方文档抓取方法的Javadoc作为高质量描述
Tool tool = MethodUtils.convertMethodToTool(method);
allTools.add(tool);
}
}
// 为每个工具创建Document对象并存入向量库(自动完成Embedding)
allTools.forEach(tool -> {
Document doc = new Document(
UUID.randomUUID().toString(),
tool.getDescription(), // 例如:“sqrt: Returns the square root of a double value...”
Map.of(
“method_name”, tool.getName(),
“parameter_types”, tool.getParameterTypes()
)
);
documents.add(doc);
});
// 批量添加到向量数据库
vectorStoreService.addDocuments(documents);
}
当用户查询“计算平方根”时,向量检索内部工作大致如下:
查询向量:embedding(“平方根 计算”) = [0.15, 0.87, 0.44, ...]
相似度计算:
sqrt 描述: “Returns the square root...” → 相似度 0.92
cbrt 描述: “Returns the cube root...” → 相似度 0.75
pow 描述: “Returns the value of...” → 相似度 0.68
sin 描述: “Returns the sine...” → 相似度 0.23
返回 Top-3: [sqrt, cbrt, pow]
阶段二:CalculateAgent (精确调用)
该节点接收筛选出的少数工具,交由LLM进行精确的Function Calling。
public class CalculateAgent implements NodeAction {
private ChatClient chatClient;
private String inputTextKey;
@Override
public Map<String, Object> apply(OverAllState state) throws Exception {
// 1. 获取上一节点筛选出的工具列表
List<Document> hitTools = (List<Document>) state.value(Constant.HIT_TOOL).orElseThrow();
// 2. 动态构建ToolCallback列表
List<ToolCallback> toolCallbacks = new ArrayList<>();
for (Document doc : hitTools) {
// 通过反射根据元数据找到对应的Method
Method toolMethod = ReflectionUtils.findMethod(
Math.class,
doc.getMetadata().get(“method_name”).toString(),
(Class<?>[]) doc.getMetadata().get(“parameter_types”)
);
// 构建工具定义
DefaultToolDefinition toolDef = DefaultToolDefinition.builder()
.name(ToolUtils.getToolName(toolMethod))
.description(ToolUtils.getToolDescription(toolMethod))
.inputSchema(JsonSchemaGenerator.generateForMethodInput(toolMethod))
.build();
// 创建可执行的回调
MethodToolCallback callback = MethodToolCallback.builder()
.toolDefinition(toolDef)
.toolMethod(toolMethod)
.build();
toolCallbacks.add(callback);
}
// 3. 调用LLM,仅传入筛选后的工具(如3个)
String inputText = (String) state.value(inputTextKey).orElse(“”);
ChatResponse response = chatClient.prompt()
.system(“Please use the tools to complete the task”)
.user(inputText) // “计算 8 的平方根”
.toolCallbacks(toolCallbacks) // 关键:只注册3个工具!
.call()
.chatResponse();
// 4. 返回最终结果
Map<String, Object> updatedState = new HashMap<>();
updatedState.put(Constant.SOLUTION, response.getResult().getOutput().getText());
return updatedState;
}
}
优势:
- 按需注册:LLM只需处理少量高度相关的工具,决策速度快,准确率高。
- 动态反射:通过元数据动态定位和调用方法,无需硬编码,扩展性强。
三、图编排与集成
使用Spring AI Alibaba Graph将上述两个节点优雅地串联起来,形成一个完整的工作流。
@RestController
@RequestMapping(“bigtool”)
public class BigToolController {
private final VectorStoreService vectorStoreService;
private CompiledGraph compiledGraph;
public BigToolController(VectorStoreService vectorStoreService, ChatModel chatModel)
throws GraphStateException {
this.vectorStoreService = vectorStoreService;
// 初始化向量数据库
this.initializeVectorStore();
// 创建ChatClient
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(new SimpleLoggerAdvisor())
.build();
// 定义状态管理策略
KeyStrategyFactory keyStrategyFactory = new KeyStrategyFactoryBuilder()
.addPatternStrategy(Constant.INPUT_KEY, new ReplaceStrategy())
.addPatternStrategy(Constant.HIT_TOOL, new ReplaceStrategy())
.addPatternStrategy(Constant.SOLUTION, new ReplaceStrategy())
.addPatternStrategy(Constant.TOOL_LIST, new ReplaceStrategy())
.build();
// 创建两个节点
ToolAgent toolAgent = new ToolAgent(chatClient, Constant.INPUT_KEY, vectorStoreService);
CalculateAgent calculateAgent = new CalculateAgent(chatClient, Constant.INPUT_KEY);
// 构建并编译执行图
StateGraph stateGraph = new StateGraph(“Big Tool Workflow”, keyStrategyFactory)
.addNode(“tools”, AsyncNodeAction.node_async(toolAgent))
.addNode(“calculate_agent”, AsyncNodeAction.node_async(calculateAgent))
.addEdge(START, “tools”)
.addEdge(“tools”, “calculate_agent”)
.addEdge(“calculate_agent”, END);
this.compiledGraph = stateGraph.compile();
}
@GetMapping(“/search”)
public String search(@RequestParam String query) {
Map<String, Object> initialState = Map.of(
Constant.INPUT_KEY, query,
Constant.TOOL_LIST, documents
);
Optional<OverAllState> result = compiledGraph.call(initialState);
return result.get().value(“solution”).get().toString();
}
}
四、实战效果演示
启动应用后,可以通过API进行测试:
-
基础数学运算
curl “http://localhost:18080/bigtool/search?query=计算8的平方根”
执行流程:
用户输入 -> ToolAgent提取关键词“平方根 计算” -> 向量检索匹配[sqrt, cbrt, pow] -> CalculateAgent调用sqrt(8) -> 返回结果 2.8284271247461903
-
三角函数计算
curl “http://localhost:18080/bigtool/search?query=sin(30度)的值是多少”
注意:向量检索的Top-K值设置至关重要。若K值太小(如K=3),可能无法召回sin函数(因为sin描述与“30度”的语义匹配度可能不够高)。此时需调整K值(例如设为5)或优化工具描述。这是一个典型的召回率问题,后续可通过混合检索策略优化。
-
比较运算
curl “http://localhost:18080/bigtool/search?query=5和8哪个更大”
执行流程:
关键词“比较 大小” -> 匹配[max, min, abs] -> 调用max(5, 8) -> 返回结果 8
五、性能与优势分析
通过基准测试对比传统方式与两阶段策略:

- Token消耗:大幅降低95%以上,因仅需传输少量工具描述。
- 响应速度:显著提升,LLM决策路径变短。
- 准确率:不降反升,因为LLM面对的选项高度相关,干扰信息少。
六、关键技术实现细节
1. 高质量工具描述生成
项目启动时自动从Oracle官方Java文档抓取方法的Javadoc,确保描述准确、丰富,这对向量检索的效果至关重要。
// 示例:抓取Math类方法文档
ConcurrentHashMap<String, String> methodDocs = fetchFromOfficialJavadoc(“https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html”);
2. 向量检索服务
基于Spring AI提供的抽象,可以轻松切换底层向量数据库。
@Service
public class VectorStoreService {
private final VectorStore vectorStore; // 可注入SimpleVectorStore、Milvus等实现
public List<Document> search(String query, int topK) {
return vectorStore.similaritySearch(
SearchRequest.builder()
.query(query)
.topK(topK)
.build()
);
}
}
- 中小规模:使用Spring AI内置的
SimpleVectorStore(工具数<1万)。
- 大规模:可替换为
Milvus、Elasticsearch或Weaviate等专业向量数据库。
3. 清晰的状态键设计
通过定义清晰的状态键,实现节点间解耦的数据传递。
public class Constant {
public static final String INPUT_KEY = “input”; // 用户输入
public static final String HIT_TOOL = “hit_tool”; // 命中的工具
public static final String SOLUTION = “solution”; // 最终结果
}
七、架构扩展与应用场景
此架构具有高度通用性,不仅限于数学工具:
- 企业级API网关:管理成百上千个内部微服务API。员工用自然语言描述需求,系统自动匹配并调用对应API。
- 智能客服知识库:将常见问题解答(FAQ)和标准话术封装为工具,根据客户问题精准匹配回复策略。
- 代码生成助手:对接大型代码库或模板库,根据开发者意图生成对应的代码片段。
八、实践总结与最佳实践
在开发过程中,我们总结了以下关键点:
- 工具描述质量是核心:丰富、准确、包含多语言关键词的描述能极大提升向量检索召回率。
- Top-K值需权衡:K值过小(如1)易导致召回失败,过大(如10)则引入噪声。K=3或5通常是较好的平衡点。
- 考虑混合检索:对于关键场景,可结合向量检索(语义)和关键词匹配(字面)的结果,再进行重排序,以提高稳定性。
- 完善可观测性:记录关键词提取、检索结果、LLM选择等各环节日志,便于问题排查和效果优化。
九、结语
从“如何让AI从100个工具中智能选择”的疑问出发,到实现一个完整的、基于向量检索的两阶段调度系统,这一实践深刻揭示了处理复杂AI应用问题的有效路径:分层处理、语义优先、平衡性能与精度。利用Spring AI Alibaba Graph这样的框架,可以让我们更专注于业务逻辑而非底层编排,大幅提升开发效率。希望本文的实战方案能为你在构建大规模AI智能体应用时提供有价值的参考。