侧边栏壁纸
博主头像
毕业帮 博主等级

提供丰富的资源和服务,涵盖从论文写作、毕业设计、职业规划、就业准备等多个方面

  • 累计撰写 81 篇文章
  • 累计创建 18 个标签
  • 累计收到 3 条评论

目 录CONTENT

文章目录

Spring AI 与 LangChain4J 调用 Skill 完整指南

流苏
2026-03-11 / 0 评论 / 0 点赞 / 13 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

Spring AI 与 LangChain4J 如何调用 Skill 全面指南

一、Skill的定义与标准

1.1 什么是Skill

Skill(技能)是可重用的功能单元,通常封装为:

  • 函数/方法:带输入输出的可执行代码
  • API接口:HTTP RESTful服务
  • 工具:特定能力(搜索、计算、数据库查询)
  • 插件:第三方服务集成

Skill的核心特征

  1. 单一职责:一个Skill完成一个明确任务
  2. 标准化接口:输入参数、输出格式、错误处理
  3. 可发现性:元数据描述(名称、描述、参数)
  4. 可组合性:多个Skill可串联成复杂工作流

1.2 Skill的标准格式

1.2.1 OpenAI Function Calling 格式(事实标准)

{
  "name": "get_weather",
  "description": "Get the current weather in a given location",
  "parameters": {
    "type": "object",
    "properties": {
      "location": {
        "type": "string",
        "description": "The city and state, e.g. San Francisco, CA"
      },
      "unit": {
        "type": "string",
        "enum": ["celsius", "fahrenheit"],
        "description": "Temperature unit"
      }
    },
    "required": ["location"]
  }
}

1.2.2 OpenAPI/Swagger 格式

paths:
  /weather:
    get:
      summary: Get weather
      parameters:
        - name: location
          in: query
          required: true
          schema:
            type: string

1.2.3 自定义Schema格式

{
  "id": "skill-001",
  "name": "Calculator",
  "version": "1.0",
  "description": "Perform mathematical calculations",
  "input_schema": {...},
  "output_schema": {...},
  "endpoint": "http://api.example.com/calc"
}

二、Spring AI 调用 Skill

2.1 @Tool 注解方式(推荐)

Spring AI 0.8.0+ 支持 @Tool 注解,将Java方法暴露为Tool:

import org.springframework.ai.function.parameter.JsonSchemaGenerator;
import org.springframework.ai.tool.function.FunctionToolCallback;
import org.springframework.ai.tool.ToolDefinition;

@Service
public class WeatherService {
    
    @Tool(description = "Get current weather for a city")
    public Weather getWeather(
        @ToolParam(description = "City name, e.g. San Francisco") String city,
        @ToolParam(description = "Temperature unit: celsius or fahrenheit", 
                   defaultValue = "celsius") String unit
    ) {
        // 调用实际天气API
        return weatherClient.getWeather(city, unit);
    }
}

// 注册到ChatClient
@Configuration
public class AiConfig {
    
    @Bean
    public ChatClient chatClient(OpenAiChatModel chatModel, WeatherService weatherService) {
        
        // 自动扫描@Tool方法,生成FunctionDefinition
        List<FunctionToolCallback> tools = ToolFunctionUtils.getToolCallbacks(weatherService);
        
        return ChatClient.builder(chatModel)
            .defaultTools(tools)  // 注册工具
            .build();
    }
}

// 使用
@Autowired
private ChatClient chatClient;

public String chat(String message) {
    return chatClient.call(message);
    // 用户问"北京天气怎么样?"
    // AI自动调用 getWeather(city="北京", unit="celsius")
}

自动生成的Schema

{
  "name": "getWeather",
  "description": "Get current weather for a city",
  "parameters": {
    "type": "object",
    "properties": {
      "city": {"type": "string", "description": "City name"},
      "unit": {"type": "string", "default": "celsius"}
    },
    "required": ["city"]
  }
}

2.2 手动注册ToolDefinition

import org.springframework.ai.chat.model.function.FunctionCallback;
import org.springframework.ai.chat.model.function.FunctionCallbackContext;

@Bean
public FunctionCallback weatherTool() {
    return FunctionCallback.builder()
        .withName("get_weather")
        .withDescription("Get weather for a city")
        .withInputType(WeatherRequest.class)  // POJO类定义参数
        .withInvoker(request -> {
            WeatherRequest req = (WeatherRequest) request;
            return weatherService.getWeather(req.getCity(), req.getUnit());
        })
        .build();
}

@Bean
public ChatClient chatClient(OpenAiChatModel model, FunctionCallback weatherTool) {
    return ChatClient.builder(model)
        .defaultFunctionCallbacks(List.of(weatherTool))
        .build();
}

2.3 使用 FunctionCallback 包装现有API

import org.springframework.ai.chat.model.function.FunctionCallback;
import org.springframework.ai.chat.model.function.FunctionCallbackContext;

public class ExternalApiTool {
    
    public FunctionCallback createTool(String name, String description, 
                                       String url, Class<?> requestType) {
        return FunctionCallback.builder()
            .withName(name)
            .withDescription(description)
            .withInputType(requestType)
            .withHttpService(HttpService.builder()
                .withUrl(url)
                .withMethod("GET")
                .build())
            .build();
    }
}

// 包装第三方天气API
@Bean
public FunctionCallback weatherTool() {
    return FunctionCallback.builder()
        .withName("get_weather")
        .withDescription("获取指定城市天气")
        .withInputType(WeatherRequest.class)
        .withInvoker(req -> {
            // 调用外部REST API
            String url = "http://api.weather.com?city=" + req.city();
            return restTemplate.getForObject(url, WeatherResponse.class);
        })
        .build();
}

2.4 调用外部Skill服务(OpenAI兼容)

很多Skill平台提供OpenAI兼容的Function Calling API:

import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.openai.OpenAiChatModel;

@Service
public class SkillService {
    
    @Autowired
    private OpenAiChatModel chatModel;
    
    // 方式1:直接调用Skill平台的OpenAI兼容接口
    public String callSkillThroughOpenAI(String skillName, String userQuery) {
        // 配置OpenAI客户端指向Skill平台
        OpenAiChatModel skillModel = new OpenAiChatModel(
            OpenAiChatModelOptions.builder()
                .baseUrl("http://skill-platform:8080/v1")  // Skill平台地址
                .apiKey("skill-api-key")
                .modelName(skillName)  // 指定Skill名称作为model
                .build()
        );
        
        String response = skillModel.call(userQuery);
        return response;
    }
    
    // 方式2:ChatClient调用多个Skill
    public String multiSkillChat(String message) {
        return ChatClient.create(skillModel)
            .call(message);
    }
}

2.5 动态加载Skill定义

import org.springframework.ai.chat.model.function.FunctionCallback;
import org.springframework.ai.chat.model.function.FunctionCallbackRegistry;

@Service
public class DynamicSkillLoader {
    
    @Autowired
    private FunctionCallbackRegistry registry;
    
    @Autowired
    private RestTemplate restTemplate;
    
    // 从Skill平台动态加载Skill定义
    @Scheduled(fixedDelay = 300000)  // 每5分钟刷新
    public void loadSkillsFromPlatform() {
        // 1. 获取Skill列表
        SkillDefinition[] skills = restTemplate.getForObject(
            "http://skill-platform/api/skills", 
            SkillDefinition[].class
        );
        
        // 2. 清空现有Skill
        registry.clear();
        
        // 3. 注册每个Skill
        for (SkillDefinition skill : skills) {
            FunctionCallback callback = createCallbackFromDefinition(skill);
            registry.register(callback);
        }
    }
    
    private FunctionCallback createCallbackFromDefinition(SkillDefinition skill) {
        return FunctionCallback.builder()
            .withName(skill.getName())
            .withDescription(skill.getDescription())
            .withInputType(skill.getInputType())  // 动态生成或预定义
            .withInvoker(request -> {
                // 动态调用Skill API
                return restTemplate.postForObject(
                    skill.getEndpoint(),
                    request,
                    skill.getOutputType()
                );
            })
            .build();
    }
}

2.6 使用 Spring AI 的 FunctionCallback

import org.springframework.ai.chat.model.function.FunctionCallback;
import org.springframework.ai.chat.model.function.FunctionCallbackContext;

@Component
public class CalculatorSkill {
    
    @FunctionSchema
    public static class AddRequest {
        private int a;
        private int b;
        // getters/setters
    }
    
    @FunctionSchema
    public static class AddResponse {
        private int result;
        // getters/setters
    }
    
    @Function
    public AddResponse add(@Parameter(description = "First number") int a,
                           @Parameter(description = "Second number") int b) {
        return new AddResponse(a + b);
    }
    
    @Bean
    public FunctionCallback addFunction() {
        return FunctionCallback.builder()
            .withName("add")
            .withDescription("Add two numbers")
            .withInputType(AddRequest.class)
            .withInvoker(req -> {
                AddRequest request = (AddRequest) req;
                return add(request.getA(), request.getB());
            })
            .build();
    }
}

三、LangChain4J 调用 Skill

3.1 自定义 Tool 实现

import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.agent.tool.ToolParameter;
import com.fasterxml.jackson.annotation.JsonProperty;

public class WeatherTool implements Tool {
    
    private final WeatherService weatherService;
    
    public WeatherTool(WeatherService weatherService) {
        this.weatherService = weatherService;
    }
    
    @Override
    public String name() {
        return "get_weather";
    }
    
    @Override
    public String description() {
        return "Get current weather for a given city";
    }
    
    @Override
    public String execute(@JsonProperty("city") String city,
                          @JsonProperty("unit") String unit) {
        try {
            Weather weather = weatherService.getWeather(city, unit);
            return String.format("Temperature: %d°%s, Condition: %s",
                weather.getTemp(), unit, weather.getCondition());
        } catch (Exception e) {
            return "Error: " + e.getMessage();
        }
    }
    
    @Override
    public ToolParameter[] parameters() {
        return new ToolParameter[] {
            ToolParameter.builder()
                .name("city")
                .description("City name, e.g. San Francisco")
                .type(ToolParameterType.STRING)
                .required(true)
                .build(),
            ToolParameter.builder()
                .name("unit")
                .description("Temperature unit: celsius or fahrenheit")
                .type(ToolParameterType.STRING)
                .required(false)
                .defaultValue("celsius")
                .build()
        };
    }
}

// 使用
List<Tool> tools = List.of(new WeatherTool(weatherService));
ChatLanguageModel model = new OpenAiChatModel(
    OpenAiChatModelOptions.builder()
        .functionRegistry(new SimpleFunctionRegistry(tools))
        .build()
);

String response = model.chat("What's the weather in Paris?");
// 模型调用工具,执行get_weather("Paris")

3.2 使用 @Tool 注解(LangChain4J 0.30.0+)

import dev.langchain4j.agent.tool.Tool;

public class CalculatorTool {
    
    @Tool
    public int add(@ToolParam(description = "First number") int a,
                   @ToolParam(description = "Second number") int b) {
        return a + b;
    }
    
    @Tool
    public int multiply(@ToolParam(description = "First number") int a,
                        @ToolParam(description = "Second number") int b) {
        return a * b;
    }
}

// 自动扫描注册
ToolRegistry registry = ToolRegistry.builder()
    .add(new CalculatorTool())
    .build();

3.3 调用外部Skill API

import dev.langchain4j.agent.tool.HttpRequestTool;

public class ExternalSkillClient {
    
    public Tool createHttpTool(String skillName, String url, String method) {
        return HttpRequestTool.builder()
            .name(skillName)
            .description("Call external skill: " + skillName)
            .url(url)
            .httpMethod(method)
            .headers(Map.of("Authorization", "Bearer token"))
            .build();
    }
}

// 使用
List<Tool> tools = List.of(
    HttpRequestTool.builder()
        .name("get_stock_price")
        .description("Get stock price by symbol")
        .url("https://api.stock.com/price")
        .httpMethod("GET")
        .queryParam("symbol", "${symbol}")  // 参数占位符
        .build()
);

3.4 工具参数绑定与转换

public class ParameterBindingTool implements Tool {
    
    @Override
    public String execute(Map<String, Object> parameters) {
        // 参数自动映射
        String city = (String) parameters.get("city");
        String unit = (String) parameters.getOrDefault("unit", "celsius");
        
        // 类型转换
        Integer limit = (Integer) parameters.get("limit");
        
        return doSomething(city, unit, limit);
    }
    
    @Override
    public ToolSchema schema() {
        return ToolSchema.builder()
            .name("my_tool")
            .description("My tool description")
            .parameters(
                ToolParameter.builder()
                    .name("city")
                    .type(ToolParameterType.STRING)
                    .description("City name")
                    .required(true)
                    .build(),
                ToolParameter.builder()
                    .name("limit")
                    .type(ToolParameterType.INTEGER)
                    .description("Max results")
                    .required(false)
                    .defaultValue(10)
                    .build()
            )
            .build();
    }
}

四、调用常见Skill平台的实践

4.1 Dify Skill调用

Dify 提供OpenAI兼容API,可直接用OpenAI SDK调用:

// Spring AI
import org.springframework.ai.openai.OpenAiChatModel;

@Configuration
public class DifyConfig {
    
    @Bean
    public OpenAiChatModel difyModel() {
        return new OpenAiChatModel(
            OpenAiChatModelOptions.builder()
                .baseUrl("http://dify-server:/v1")  // Dify地址
                .apiKey("dify-app-api-key")
                .modelName("dify-app-id")  // Dify应用ID
                .build()
        );
    }
    
    @Bean
    public ChatClient difyChatClient(OpenAiChatModel difyModel) {
        return ChatClient.create(difyModel);
    }
}

// 调用
String response = difyChatClient.call("Analyze this data");
// Dify内部的Workflow/Skill自动执行

4.2 Coze Skill调用

Coze 同样提供OpenAI兼容接口:

OpenAiChatModel cozeModel = new OpenAiChatModel(
    OpenAiChatModelOptions.builder()
        .baseUrl("https://api.coze.com/open_api/v2/chat")
        .apiKey("coze-api-token")
        .modelName("your-bot-id")
        .build()
);

4.3 文心一言/千帆 Skill调用

import org.springframework.ai.baidu.AiService;  // 需自定义或社区实现

// 千帆平台也支持Function Calling
public class QianwanSkillService {
    
    @Bean
    public ChatModel qianwanModel() {
        return new BaiduErnieChatModel(
            BaiduErnieChatModelOptions.builder()
                .apiKey("...")
                .secretKey("...")
                .modelName("ernie-bot-4.0")
                .functions(skillFunctionDefinitions)  // 注册Skill定义
                .build()
        );
    }
}

4.4 自定义Skill平台集成

假设Skill平台提供REST API:

import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.chat.model.function.FunctionCallback;
import org.springframework.ai.chat.model.function.FunctionCallbackRegistry;

@Service
public class SkillPlatformIntegration {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @Autowired
    private FunctionCallbackRegistry registry;
    
    // 1. 定期从Skill平台拉取Skill定义
    @Scheduled(fixedDelay = 60000)
    public void syncSkills() {
        SkillDefinition[] skills = restTemplate.getForObject(
            "http://skill-platform/api/v1/skills",
            SkillDefinition[].class
        );
        
        for (SkillDefinition skill : skills) {
            registerSkill(skill);
        }
    }
    
    private void registerSkill(SkillDefinition skill) {
        FunctionCallback callback = FunctionCallback.builder()
            .withName(skill.getName())
            .withDescription(skill.getDescription())
            .withInputType(skill.getInputSchema())  // 动态创建Class
            .withHttpService(HttpService.builder()
                .withUrl(skill.getEndpoint())
                .withMethod(skill.getMethod())
                .withHeaders(skill.getHeaders())
                .build())
            .build();
        
        registry.register(callback);
    }
    
    // 2. ChatClient自动使用已注册的Skill
    @Bean
    public ChatClient chatClient(OpenAiChatModel model) {
        return ChatClient.builder(model)
            .defaultFunctionCallbacks(registry.getCallbacks())
            .build();
    }
}

五、Skill调用流程详解

5.1 Spring AI 调用流程

用户请求 → ChatClient → ChatModel(OpenAI) → 返回FunctionCall请求
    ↓
Spring AI解析FunctionCall → 查找对应FunctionCallback
    ↓
执行FunctionCallback(可能是Java方法或HTTP调用)
    ↓
获得结果 → 回传给ChatModel
    ↓
ChatModel生成最终回答 → 返回用户

代码示例

// 1. 定义Skill
@Bean
public FunctionCallback searchTool(SearchService searchService) {
    return FunctionCallback.builder()
        .withName("search")
        .withDescription("Search for information")
        .withInputType(SearchRequest.class)
        .withInvoker(req -> searchService.search(((SearchRequest) req).getQuery()))
        .build();
}

// 2. 创建ChatClient并注册Skill
ChatClient chatClient = ChatClient.builder(chatModel)
    .defaultFunctionCallbacks(List.of(searchTool))
    .build();

// 3. 用户对话
String response = chatClient.call("Search for Java tutorials");

// 内部自动流程:
// a. chatModel判断需要调用search工具
// b. 调用searchTool.execute(...)
// c. 将搜索结果作为Observation回传给model
// d. model生成最终回答

5.2 LangChain4J 调用流程

// 1. 定义Tool
public class SearchTool implements Tool {
    @Override
    public String name() { return "search"; }
    
    @Override
    public String execute(String query) {
        return searchService.search(query);
    }
    
    @Override
    public ToolParameter[] parameters() {
        return new ToolParameter[]{
            ToolParameter.builder()
                .name("query")
                .type(ToolParameterType.STRING)
                .description("Search query")
                .required(true)
                .build()
        };
    }
}

// 2. 注册到ToolRegistry
ToolRegistry registry = new SimpleToolRegistry();
registry.register(new SearchTool());

// 3. 创建Agent或LLM
ChatLanguageModel model = new OpenAiChatModel(...);
Agent agent = Agent.builder()
    .chatLanguageModel(model)
    .tools(registry)
    .build();

// 4. 执行
AgentExecutionResult result = agent.execute("Search Java tutorials");
// 自动:判断→调用→观察→生成最终答案

六、Skill调用的高级特性

6.1 工具调用模式

Spring AI支持三种模式:

ChatResponse response = chatClient.call(
    PromptTemplate.from("{{query}}")
        .apply(Map.of("query", userMessage))
        .create(),
    new FunctionEncounteredCallback() {
        @Override
        public void onFunctionEncountered(FunctionCallback function, 
                                          Map<String, Object> arguments) {
            log.info("调用工具: {}, 参数: {}", function.name(), arguments);
        }
    }
);

LangChain4J

AgentCallback callback = new AgentCallback() {
    @Override
    public void onTool(String toolName, String input, String output) {
        log.info("Tool {} called with {}, result: {}", toolName, input, output);
    }
    
    @Override
    public void onThought(String thought) {
        log.debug("Thought: {}", thought);
    }
};

AgentExecutionResult result = agent.execute(
    AgentExecutorRequest.builder()
        .input("question")
        .callback(callback)
        .build()
);

6.2 工具调用错误处理

public RobustTool implements Tool {
    
    @Override
    public String execute(Map<String, Object> parameters) {
        try {
            // 1. 参数验证
            validate(parameters);
            
            // 2. 调用实际服务
            String result = callExternalService(parameters);
            
            // 3. 结果格式化
            return formatResult(result);
            
        } catch (ValidationException e) {
            return "参数错误: " + e.getMessage();
        } catch (TimeoutException e) {
            return "服务超时,请重试";
        } catch (Exception e) {
            log.error("Tool execution failed", e);
            return "执行失败: " + e.getMessage();
        }
    }
}

6.3 工具权限控制

@Component
public class SkillAuthorizationService {
    
    public boolean canExecute(String userId, String skillName) {
        // 查数据库或调用IAM系统
        return permissionService.hasPermission(userId, "SKILL:" + skillName);
    }
    
    public List<String> getAllowedSkills(String userId) {
        return permissionService.getPermissions(userId)
            .stream()
            .filter(p -> p.startsWith("SKILL:"))
            .map(p -> p.substring(6))
            .collect(Collectors.toList());
    }
}

// 在Tool执行前检查
public Tool withAuthorization(FunctionCallback inner, 
                              SkillAuthorizationService auth) {
    return new AuthorizedTool(inner, auth);
}

6.4 工具调用监控与审计

@Aspect
@Component
public class SkillAuditAspect {
    
    @Autowired
    private AuditLogService auditLog;
    
    @Around("@annotation(org.springframework.ai.tool.RequiresSkill)")
    public Object auditSkillExecution(ProceedingJoinPoint pjp) throws Throwable {
        String skillName = pjp.getSignature().getName();
        String userId = SecurityContext.getCurrentUser();
        Map<String, Object> args = ... // 提取参数
        
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();
        long duration = System.currentTimeMillis() - start;
        
        auditLog.log(SkillAudit.builder()
            .userId(userId)
            .skillName(skillName)
            .parameters(args)
            .result(result)
            .duration(duration)
            .timestamp(Instant.now())
            .build());
        
        return result;
    }
}

七、Skill调用最佳实践

7.1 Skill设计原则

  1. 单一职责:一个Skill做一件事
  2. 幂等性:相同输入多次调用结果一致
  3. 快速失败:参数错误立即返回,不执行
  4. 详细文档:description清晰,parameter标注完整
  5. 版本化:Skill有版本号,兼容性管理

7.2 参数设计

// Good: 参数清晰、有默认值、复杂对象
@Tool
public Report generateReport(
    @ToolParam(description = "Report type: sales/marketing/finance") ReportType type,
    @ToolParam(description = "Start date (YYYY-MM-DD)") String startDate,
    @ToolParam(description = "End date (YYYY-MM-DD)", 
               defaultValue = "today") String endDate,
    @ToolParam(description = "Format: pdf/html", defaultValue = "html") String format
) { ... }

// Bad: 模糊参数、无默认值、多个可选参数混在一起
@Tool
public String process(String data) { ... }  // data是什么格式?包含什么?

7.3 错误处理策略

public class SafeTool implements Tool {
    
    @Override
    public String execute(Map<String, Object> params) {
        try {
            // 业务逻辑
            return doWork(params);
        } catch (BusinessException e) {
            // 返回人类可读的错误
            return String.format("业务错误: %s。建议: %s", 
                e.getMessage(), e.getSuggestion());
        } catch (TechnicalException e) {
            log.error("Tool technical error", e);
            return "系统错误,请联系管理员";
        }
    }
    
    @Override
    public ToolSchema schema() {
        return ToolSchema.builder()
            .name("safe_tool")
            .description("Safe tool with detailed error messages")
            .parameters(...)
            .errorHandling(ErrorHandling.RETURN_MESSAGE)  // 出错返回消息而非抛异常
            .build();
    }
}

7.4 性能优化

// 1. 批量支持
@Tool
public List<Result> batchSearch(@ToolParam(description = "List of queries") List<String> queries) {
    // 并行调用搜索API
    return queries.parallelStream()
        .map(this::searchSingle)
        .collect(Collectors.toList());
}

// 2. 缓存
@Cacheable(value = "skill-results", key = "#skillName + ':' + #params")
public Object executeSkill(String skillName, Object params) {
    return skillRegistry.execute(skillName, params);
}

// 3. 超时控制
@Tool(timeout = 5000)  // 5秒超时
public String longRunningSkill() { ... }

7.5 安全考虑

// 1. 参数校验
@Validated
public class SkillRequest {
    @NotBlank
    private String city;
    
    @Min(0)
    @Max(100)
    private Integer limit;
}

// 2. 敏感信息过滤
@Component
public class SensitiveDataFilter implements ToolPostProcessor {
    
    @Override
    public Object processResult(Object result) {
        return maskSensitiveInfo(result);
    }
    
    @Override
    public Object processError(Throwable error) {
        // 不泄露内部错误细节
        return "Operation failed";
    }
}

// 3. 调用频率限制
@RateLimit(name = "skill-calls", limitForPeriod = 100, periodInSeconds = 60)
public String rateLimitedSkill() { ... }

八、常见Skill平台对比

平台 协议 认证 优点 缺点
Dify OpenAI兼容API API Key 可视化编排、多模型支持 需自部署,资源消耗大
Coze OpenAI兼容 + 扩展 Bot Token 插件市场丰富、支持多平台 国内访问不稳定
文心千帆 百度自定义 AK/SK 中文优化、与百度生态整合 英文能力较弱
通义千问 阿里自定义 AK/SK 多模态、电商场景优化 文档较少
自定义Skill平台 REST API JWT/OAuth 完全控制、可定制 需自开发平台

九、调试与运维

9.1 调试工具

// 1. 日志记录(Spring AI)
logging.level.org.springframework.ai=DEBUG

// 2. 查看 FunctionCall 历史
@Bean
public FunctionCallbackInspector inspector() {
    return new FunctionCallbackInspector() {
        @Override
        public void afterCall(FunctionCallback callback, 
                              Map<String, Object> args, 
                              Object result) {
            log.info("Skill {} called with {}, result: {}", 
                callback.name(), args, result);
        }
    };
}

// 3. LangChain4J Callback
CallbackManager callbackManager = new CallbackManager.Builder()
    .addListener(new StdOutCallbackListener())
    .build();

9.2 监控指标

@TimerMetric(name = "skill.execution.duration")
public Object executeSkill(String skillName, Object params) { ... }

@CounterMetric(name = "skill.execution.count", 
               tags = {"skill", skillName})
public void incrementSkillCount() { ... }

@GaugeMetric(name = "skill.queue.size")
public int getSkillQueueSize() { ... }

9.3 热加载Skill

@RefreshScope  // Spring Cloud Config支持
public class DynamicSkillService {
    
    @Value("${skills.enabled:}")
    private List<String> enabledSkills;
    
    @PostConstruct
    public void init() {
        // 根据配置动态加载Skill
        for (String skill : enabledSkills) {
            registerSkill(skill);
        }
    }
}

十、最佳实践总结

10.1 Skill设计

  1. 粒度适中:一个Skill = 一个业务原子操作
  2. 幂等设计:相同输入总是相同输出
  3. 快速失败:参数验证前置,避免无效执行
  4. 详细文档:description、参数、返回值、错误码
  5. 版本管理:Skill API版本化,向后兼容

10.2 Spring AI使用

  • 优先 @Tool 注解方式,最简单
  • 复杂参数使用POJO类,支持嵌套对象
  • 集成Spring Security做权限控制
  • 使用 FunctionCallbackRegistry 统一管理
  • 配合 @RefreshScope 实现热加载

10.3 LangChain4J使用

  • 实现 Tool 接口,提供schema
  • 使用 ToolRegistry 集中注册
  • 参数类型:String、Integer、Boolean、Array、Object
  • 结合 Agent 实现自动工具选择
  • 利用 Callback 监控工具调用链

10.4 调用外部Skill

  1. 优先OpenAI格式:大多数平台兼容
  2. 统一网关模式:所有Skill通过网关路由
  3. 协议转换:将OpenAI Function Call转为平台特定协议
  4. 熔断降级:Skill失败不影响主流程
  5. 审计日志:记录所有Skill调用(谁、何时、参数、结果)

10.5 性能与成本

  • 缓存:相同query+skill参数缓存结果
  • 批量:支持批量调用减少网络开销
  • 超时:每个Skill设置超时(如5秒)
  • 并发限制:防止单个Skill拖垮系统
  • 成本监控:追踪每次调用成本(API费用、计算资源)

十一、技术选型建议

根据场景选择

场景 推荐方案
已有Spring Boot项目 Spring AI(生态整合好)
复杂Agent工作流 LangChain4J(Agent能力更强)
简单RAG+少量工具 Spring AI(学习成本低)
多工具动态选择 LangChain4J Agent
对接Skill平台 用OpenAI兼容API统一对接
自建Skill生态 定义标准(OpenAI Function),自动生成Spring/LangChain封装

Java生态现状

  • Spring AI:发展快,Spring团队维护,未来可期
  • LangChain4J:功能完善,文档丰富,成熟度更高
  • 两者都支持OpenAI Function Calling标准,可互操作

十二、未来趋势

12.1 Skill标准化

  • OpenAI Function Calling 已成为事实标准
  • OpenAPI 3.0 扩展支持LLM描述
  • Schema.org 等语义网标准可能融合

12.2 Skill发现与推荐

  • Skill Marketplace(类似App Store)
  • AI驱动的Skill推荐(根据用户query推荐可用Skill)
  • Skill评价与质量认证

12.3 Skill组合与编排

  • 可视化编排工具(类似Dify Workflow)
  • 自动Skill链生成(给定目标,自动组合Skill)
  • Skill依赖管理

12.4 Skill安全与治理

  • Skill沙箱执行(防止恶意代码)
  • Skill权限细粒度控制(数据级别)
  • Skill调用审计与合规

总结

Spring AI 和 LangChain4J 都通过Function Calling标准调用Skill:

Spring AI

  • 使用 @Tool 注解或 FunctionCallback 手动注册
  • 与Spring生态深度集成,适合企业级应用
  • 自动生成JSON Schema,开箱即用

LangChain4J

  • 实现 Tool 接口,提供schema
  • Agent自动选择工具,更灵活
  • 生态更成熟,文档丰富

调用外部Skill平台

  • 优先使用OpenAI兼容API
  • 封装HTTP调用为FunctionCallback/Tool
  • 支持动态加载、权限控制、审计日志

最佳实践

  1. Skill设计遵循单一职责、幂等性、快速失败
  2. 参数使用POJO或详细schema,提高准确性
  3. 添加监控、缓存、熔断等生产级特性
  4. 统一权限控制和审计日志

文档版本:v1.0
最后更新:2025年3月

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区