跳到主要内容

Tool Calling

Tool Calling 是 Spring AI 中的一项重要功能,允许 AI 模型调用外部工具和函数来增强其能力。

什么是 Tool Calling?

Tool Calling 允许大语言模型在需要时主动调用预定义的函数或工具,从而扩展其能力范围。例如,模型可以调用天气查询API、数据库查询函数或计算器等。

在 Spring AI 中实现 Tool Calling

1. 定义工具函数

@Component
public class WeatherService {

@Tool(name = "get_current_weather", description = "获取指定城市的当前天气")
public String getCurrentWeather(
@Param(description = "城市名称") String city,
@Param(description = "温度单位,可选值:celsius 或 fahrenheit") String unit) {

// 模拟天气查询
String temperature = unit.equals("celsius") ? "25°C" : "77°F";
return String.format("当前%s的天气:%s,晴朗", city, temperature);
}
}

2. 配置 ChatClient 支持 Tool Calling

@Configuration
public class AiConfiguration {

@Bean
public ChatClient chatClient(ChatModel chatModel, List<Tool> tools) {
return new DefaultChatClient(chatModel, List.of(), List.of(), tools);
}
}

3. 使用 Tool Calling

@Service
public class AssistantService {

private final ChatClient chatClient;

public AssistantService(ChatClient chatClient) {
this.chatClient = chatClient;
}

public String handleQuery(String userQuery) {
Prompt prompt = new Prompt(
new UserMessage(userQuery),
OpenAiChatOptions.builder()
.withTools(List.of("get_current_weather")) // 指定可用工具
.build()
);

ChatResponse response = chatClient.call(prompt);

// 处理工具调用
if (response.getResult().getOutput().getToolCalls() != null &&
!response.getResult().getOutput().getToolCalls().isEmpty()) {

// 执行工具调用并获取结果
List<ToolCall> toolCalls = response.getResult().getOutput().getToolCalls();
List<ToolCallResult> toolCallResults = executeToolCalls(toolCalls);

// 将工具调用结果返回给模型进行最终回答
Prompt followUpPrompt = new Prompt(
List.of(
new UserMessage(userQuery),
response.getResult().getOutput(), // AI 的工具调用请求
new ToolCallResultMessage(toolCallResults) // 工具调用结果
)
);

ChatResponse finalResponse = chatClient.call(followUpPrompt);
return finalResponse.getResult().getOutput().getContent();
}

return response.getResult().getOutput().getContent();
}

private List<ToolCallResult> executeToolCalls(List<ToolCall> toolCalls) {
return toolCalls.stream().map(toolCall -> {
try {
// 执行工具调用
Object result = toolCall.execute();
return new ToolCallResult(toolCall, result.toString(), false, null);
} catch (Exception e) {
return new ToolCallResult(toolCall, null, true, e.getMessage());
}
}).collect(Collectors.toList());
}
}

复杂工具示例

数据库查询工具

@Component
public class DatabaseQueryService {

@Tool(name = "query_user_info", description = "根据用户ID查询用户信息")
public UserInfo queryUserInfo(@Param(description = "用户ID") Long userId) {
// 模拟数据库查询
return new UserInfo(userId, "张三", "zhangsan@example.com", 25);
}

@Tool(name = "query_order_history", description = "查询用户的订单历史")
public List<Order> queryOrderHistory(
@Param(description = "用户ID") Long userId,
@Param(description = "查询数量限制") Integer limit) {
// 模拟订单查询
List<Order> orders = new ArrayList<>();
orders.add(new Order(1001L, "商品A", new BigDecimal("99.99"), LocalDateTime.now()));
orders.add(new Order(1002L, "商品B", new BigDecimal("199.99"), LocalDateTime.now().minusDays(1)));
return orders;
}
}

计算工具

@Component
public class CalculationService {

@Tool(name = "calculate", description = "执行数学计算")
public String calculate(
@Param(description = "数学表达式,如 '2+3*4'") String expression) {
// 使用脚本引擎计算表达式
ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript");
try {
Object result = engine.eval(expression);
return String.format("%s = %s", expression, result.toString());
} catch (ScriptException e) {
return "计算错误:" + e.getMessage();
}
}
}

最佳实践

1. 工具设计原则

  • 工具函数应该具有明确的职责和清晰的输入输出
  • 提供详细的参数描述,帮助模型正确使用工具
  • 处理异常情况,返回有意义的错误信息

2. 工具调用流程

  1. 模型识别需要调用工具的情况
  2. 模型生成工具调用请求
  3. 系统执行工具调用
  4. 将结果返回给模型
  5. 模型基于工具结果生成最终回答

3. 安全考虑

  • 验证工具调用参数的有效性
  • 限制工具的执行权限
  • 记录工具调用日志用于审计

通过合理使用 Tool Calling 功能,可以让 AI 应用具备更强的实际问题解决能力。