Java Function Calling 案例详解
Function Calling(函数调用)是AI模型与外部系统交互的重要机制,下面我将通过几个典型案例,展示如何在Java中实现和使用Function Calling。

基础函数调用案例
1 定义函数接口
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
import java.util.function.Function;
// 定义函数接口
@FunctionalInterface
public interface ToolFunction<R> {
R apply(String arguments);
}
// 天气查询函数
public class WeatherFunction implements Function<String, String> {
@Override
public String apply(String city) {
// 模拟天气查询
return String.format("城市:%s,当前温度:25°C,天气:晴", city);
}
}
// 计算器函数
public class CalculatorFunction implements Function<String, String> {
@Override
public String apply(String expression) {
try {
// 简单表达式计算
String[] parts = expression.split(" ");
double num1 = Double.parseDouble(parts[0]);
String operator = parts[1];
double num2 = Double.parseDouble(parts[2]);
double result = switch (operator) {
case "+" -> num1 + num2;
case "-" -> num1 - num2;
case "*" -> num1 * num2;
case "/" -> num2 != 0 ? num1 / num2 : Double.NaN;
default -> throw new IllegalArgumentException("不支持的运算符");
};
return String.format("计算结果:%.2f", result);
} catch (Exception e) {
return "计算错误:" + e.getMessage();
}
}
}
2 函数注册中心
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class FunctionRegistry {
private final Map<String, Function<String, String>> functions = new HashMap<>();
public void registerFunction(String name, Function<String, String> function) {
functions.put(name, function);
}
public String executeFunction(String name, String arguments) {
Function<String, String> function = functions.get(name);
if (function == null) {
return "函数未找到: " + name;
}
return function.apply(arguments);
}
public boolean hasFunction(String name) {
return functions.containsKey(name);
}
public Map<String, Function<String, String>> getAllFunctions() {
return new HashMap<>(functions);
}
}
集成OpenAI Function Calling
1 函数定义注解
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AITool {
String name();
String description();
}
2 工具类实现
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class AIToolExecutor {
private final Map<String, Method> tools = new HashMap<>();
private final ObjectMapper mapper = new ObjectMapper();
public AIToolExecutor(Object service) {
registerTools(service);
}
private void registerTools(Object service) {
for (Method method : service.getClass().getDeclaredMethods()) {
if (method.isAnnotationPresent(AITool.class)) {
AITool annotation = method.getAnnotation(AITool.class);
tools.put(annotation.name(), method);
}
}
}
public ObjectNode getToolsDefinition() {
ObjectNode toolsNode = mapper.createObjectNode();
ArrayNode toolsArray = toolsNode.putArray("tools");
for (Map.Entry<String, Method> entry : tools.entrySet()) {
ObjectNode toolNode = toolsArray.addObject();
toolNode.put("type", "function");
ObjectNode functionNode = toolNode.putObject("function");
AITool annotation = entry.getValue().getAnnotation(AITool.class);
functionNode.put("name", annotation.name());
functionNode.put("description", annotation.description());
// 生成参数schema
ObjectNode parametersNode = generateParameterSchema(entry.getValue());
functionNode.set("parameters", parametersNode);
}
return toolsNode;
}
public String executeTool(String toolName, String arguments) {
Method method = tools.get(toolName);
if (method == null) {
return "Tool not found: " + toolName;
}
try {
// 解析参数并执行
JsonNode argsNode = mapper.readTree(arguments);
Object[] args = parseArguments(method, argsNode);
Object result = method.invoke(serviceInstance, args);
return mapper.writeValueAsString(result);
} catch (Exception e) {
return "Error executing tool: " + e.getMessage();
}
}
}
完整的使用案例
1 配置OpenAI客户端
<!-- Maven依赖 -->
<dependency>
<groupId>com.theokanning.openai-gpt3-java</groupId>
<artifactId>service</artifactId>
<version>0.18.2</version>
</dependency>
import com.theokanning.openai.OpenAiService;
import com.theokanning.openai.completion.chat.*;
import com.theokanning.openai.function.FunctionDefinition;
public class OpenAIClient {
private final OpenAiService service;
private final FunctionRegistry functionRegistry;
public OpenAIClient(String apiKey, FunctionRegistry functionRegistry) {
this.service = new OpenAiService(apiKey);
this.functionRegistry = functionRegistry;
}
public String chatWithFunctions(String userMessage) {
// 构建函数定义
List<FunctionDefinition> functions = new ArrayList<>();
functions.add(createWeatherFunction());
functions.add(createCalculatorFunction());
// 构建请求
ChatCompletionRequest request = ChatCompletionRequest.builder()
.model("gpt-3.5-turbo")
.messages(Arrays.asList(
new ChatMessage(ChatMessageRole.SYSTEM.value(), "你是一个有用的助手,可以使用工具来回答问题。"),
new ChatMessage(ChatMessageRole.USER.value(), userMessage)
))
.functions(functions)
.functionCall("auto")
.build();
// 发送请求并处理响应
ChatCompletionResult result = service.createChatCompletion(request);
ChatMessage response = result.getChoices().get(0).getMessage();
// 处理函数调用
if (response.getFunctionCall() != null) {
return handleFunctionCall(response);
}
return response.getContent();
}
private String handleFunctionCall(ChatMessage message) {
ChatFunctionCall functionCall = message.getFunctionCall();
String functionName = functionCall.getName();
String arguments = functionCall.getArguments();
// 执行函数
String functionResult = functionRegistry.executeFunction(functionName, arguments);
// 将结果返回给AI
ChatMessage functionMessage = ChatMessage.builder()
.role(ChatMessageRole.FUNCTION.value())
.name(functionName)
.content(functionResult)
.build();
// 再次调用AI获取最终回答
ChatCompletionRequest request = ChatCompletionRequest.builder()
.model("gpt-3.5-turbo")
.messages(Arrays.asList(
new ChatMessage(ChatMessageRole.SYSTEM.value(), "你是一个有用的助手"),
message,
functionMessage
))
.build();
ChatCompletionResult result = service.createChatCompletion(request);
return result.getChoices().get(0).getMessage().getContent();
}
}
2 实际应用示例
public class CustomerServiceAgent {
private final AIToolExecutor toolExecutor;
private final OpenAIClient aiClient;
public CustomerServiceAgent(String apiKey) {
this.toolExecutor = new AIToolExecutor(new CustomerServiceTools());
this.aiClient = new OpenAIClient(apiKey,
createFunctionRegistry());
}
public String handleCustomerRequest(String request) {
return aiClient.chatWithFunctions(request);
}
private static class CustomerServiceTools {
@AITool(name = "get_order_status",
description = "获取订单状态")
public String getOrderStatus(@JsonProperty("order_id") String orderId) {
// 查询订单状态
return String.format("订单 %s 当前状态: 已发货", orderId);
}
@AITool(name = "check_inventory",
description = "检查商品库存")
public String checkInventory(@JsonProperty("product_id") String productId) {
// 检查库存
return String.format("商品 %s 库存: 100件", productId);
}
@AITool(name = "calculate_refund",
description = "计算退款金额")
public String calculateRefund(
@JsonProperty("order_amount") double orderAmount,
@JsonProperty("days_used") int daysUsed) {
double refundAmount = orderAmount * (1 - daysUsed * 0.1);
return String.format("退款金额: ¥%.2f", Math.max(refundAmount, 0));
}
}
}
高级用法
1 异步函数调用
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class AsyncFunctionExecutor {
private final ExecutorService executor = Executors.newFixedThreadPool(10);
public CompletableFuture<String> executeAsync(String functionName, String arguments) {
return CompletableFuture.supplyAsync(() -> {
return executeFunction(functionName, arguments);
}, executor);
}
public CompletableFuture<Map<String, String>> executeParallel(
Map<String, String> functionCalls) {
List<CompletableFuture<Map.Entry<String, String>>> futures =
new ArrayList<>();
for (Map.Entry<String, String> call : functionCalls.entrySet()) {
CompletableFuture<Map.Entry<String, String>> future =
executeAsync(call.getKey(), call.getValue())
.thenApply(result -> Map.entry(call.getKey(), result));
futures.add(future);
}
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApply(v -> futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
}
}
2 带缓存的函数调用
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
public class CachedFunctionExecutor {
private final Cache<String, String> cache;
private final FunctionRegistry functionRegistry;
public CachedFunctionExecutor(FunctionRegistry functionRegistry) {
this.functionRegistry = functionRegistry;
this.cache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000)
.build();
}
public String executeWithCache(String functionName, String arguments) {
String cacheKey = functionName + ":" + arguments;
String cachedResult = cache.getIfPresent(cacheKey);
if (cachedResult != null) {
return cachedResult;
}
String result = functionRegistry.executeFunction(functionName, arguments);
cache.put(cacheKey, result);
return result;
}
}
测试示例
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class FunctionCallingTest {
@Test
public void testWeatherFunction() {
FunctionRegistry registry = new FunctionRegistry();
registry.registerFunction("get_weather", new WeatherFunction());
String result = registry.executeFunction("get_weather", "北京");
assertTrue(result.contains("北京"));
assertTrue(result.contains("25°C"));
}
@Test
public void testCalculatorFunction() {
FunctionRegistry registry = new FunctionRegistry();
registry.registerFunction("calculate", new CalculatorFunction());
String result = registry.executeFunction("calculate", "10 + 20");
assertEquals("计算结果:30.00", result);
result = registry.executeFunction("calculate", "100 / 4");
assertEquals("计算结果:25.00", result);
}
@Test
public void testUnknownFunction() {
FunctionRegistry registry = new FunctionRegistry();
String result = registry.executeFunction("unknown_func", "test");
assertTrue(result.contains("函数未找到"));
}
}
Function Calling 是AI应用开发中的核心模式,它实现了:
- 功能扩展:让AI能够访问外部系统和数据
- 准确性提升:通过真实数据而非模型猜测
- 可维护性:功能模块化,易于更新和扩展
- 安全性:可以控制AI能访问哪些功能
在实际项目中,建议:
- 明确定义函数接口和参数
- 实现错误处理和超时机制
- 合理使用缓存提高性能
- 做好安全验证和权限控制
通过这些案例,你可以构建强大且可靠的Java Function Calling系统。