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. 工具设计原则
- 工具函数应该具有明确的职责和清晰的输入输出
- 提供详细的参数描述,帮助模型正确使用工具
- 处理异常情况,返回有意义的错误信息