Java Function Calling案例

wen java案例 1

Java Function Calling 案例详解

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

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应用开发中的核心模式,它实现了:

  1. 功能扩展:让AI能够访问外部系统和数据
  2. 准确性提升:通过真实数据而非模型猜测
  3. 可维护性:功能模块化,易于更新和扩展
  4. 安全性:可以控制AI能访问哪些功能

在实际项目中,建议:

  • 明确定义函数接口和参数
  • 实现错误处理和超时机制
  • 合理使用缓存提高性能
  • 做好安全验证和权限控制

通过这些案例,你可以构建强大且可靠的Java Function Calling系统。

抱歉,评论功能暂时关闭!