FileAgent 实战:Spring AI Alibaba vs Langchain4J 深度对比

摘要:本文通过实际开发 FileAgent(文件操作 AI Agent)项目,深入对比 Spring AI Alibaba 和 Langchain4J 两个 Java AI 开发框架的差异、优缺点及适用场景。包含完整代码对比、架构分析和实践经验总结。


一、项目背景

在 AI Agent 开发领域,Java 开发者面临两个主流选择:Spring AI AlibabaLangchain4J。为了客观对比两者,我使用这两个框架分别实现了相同的 FileAgent 项目——一个能够通过自然语言对话进行文件操作(查看磁盘、列出目录、读写文件等)的 AI Agent。

项目功能

  • 自然语言对话交互
  • 查看磁盘驱动器信息
  • 列出目录内容
  • 📏 获取文件/目录大小
  • 📄 读取文件内容
  • ✏️ 创建和编辑文件
  • 🗑️ 删除文件/目录
  • 💾 会话管理和历史记录

二、技术栈对比

2.1 核心依赖

Spring AI Alibaba 版本
<!-- Spring Alibaba AI -->
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-starter</artifactId>
    <version>1.0.0-M6.1</version>
</dependency>
  • 版本: 1.0.0-M6.1(里程碑版本)
  • 生态: Spring AI 官方扩展,深度集成 Spring Boot
  • 模型支持: 阿里云通义千问系列(qwen-plus, qwen-max, qwen-turbo)
Langchain4J 版本
<!-- Langchain4J Core -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j</artifactId>
    <version>0.36.2</version>
</dependency>

<!-- Langchain4J OpenAI -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-open-ai</artifactId>
    <version>0.36.2</version>
</dependency>

<!-- Langchain4J Spring Boot Starter -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-spring-boot-starter</artifactId>
    <version>0.36.2</version>
</dependency>
  • 版本: 0.36.2
  • 生态: 社区活跃,兼容 OpenAI API
  • 模型支持: 通过 OpenAI 兼容 API 可连接多种模型(通义千问、智谱、文心一言等)

2.2 依赖对比总结

维度 Spring AI Alibaba Langchain4J
成熟度 里程碑版本(M6.1) 稳定版本(0.36.2)
官方支持 阿里云官方 社区驱动
模型生态 专注阿里云模型 支持多模型(OpenAI、Anthropic、HuggingFace等)
Spring 集成 原生深度集成 通过 Starter 集成
文档完善度 相对较少 文档丰富

三、核心代码对比

3.1 工具定义方式

这是两个框架最显著的差异点。

Spring AI Alibaba 版本(85 行)
@Component
public class FileTools {

    private final SkillManager skillManager;

    public FileTools(SkillManager skillManager) {
        this.skillManager = skillManager;
    }

    /**
     * 查看磁盘信息
     */
    public String listDisk(String params) {
        return skillManager.executeSkill("list_disk");
    }

    /**
     * 列出目录内容
     * @param path 目录路径
     */
    public String listFiles(String path) {
        return skillManager.executeSkill("list_files", path);
    }

    /**
     * 读取文件内容
     * @param path 文件路径
     * @param maxLines 最大行数(可选)
     */
    public String readFile(String path, Integer maxLines) {
        if (maxLines != null) {
            return skillManager.executeSkill("read_file", path, String.valueOf(maxLines));
        }
        return skillManager.executeSkill("read_file", path);
    }

    // ... 其他方法类似
}

特点

  • ✅ 代码简洁,职责清晰
  • ✅ 通过 SkillManager 统一管理技能
  • ✅ 易于扩展和维护
  • ❌ 依赖外部 SkillManager 实现
  • ❌ 需要额外编写 Skill 脚本
Langchain4J 版本(236 行)
@Component
public class FileTools {

    private static final Logger log = LoggerFactory.getLogger(FileTools.class);

    @Tool("列出所有磁盘驱动器及容量信息")
    public String listDisk() {
        try {
            File[] roots = File.listRoots();
            StringBuilder sb = new StringBuilder("磁盘驱动器列表:\n");
            for (File root : roots) {
                long totalSpace = root.getTotalSpace();
                long freeSpace = root.getFreeSpace();
                long usedSpace = totalSpace - freeSpace;
                double totalGB = totalSpace / (1024.0 * 1024 * 1024);
                double freeGB = freeSpace / (1024.0 * 1024 * 1024);
                double usedGB = usedSpace / (1024.0 * 1024 * 1024);
                sb.append(String.format("  %s - 总容量: %.2f GB, 已用: %.2f GB, 可用: %.2f GB\n",
                        root.getPath(), totalGB, usedGB, freeGB));
            }
            return sb.toString();
        } catch (Exception e) {
            log.error("获取磁盘信息失败", e);
            return "获取磁盘信息失败: " + e.getMessage();
        }
    }

    @Tool("读取文件内容。参数: filePath - 文件路径(可选参数: maxLength - 最大读取长度)")
    public String readFile(String args) {
        try {
            // 智能解析参数:支持单个参数或多个参数(用|分隔)
            String filePath;
            Integer maxLength = null;
            
            if (args.contains("|")) {
                // 多参数格式: filePath|maxLength
                String[] parts = args.split("\\|", 2);
                filePath = parts[0].trim();
                if (parts.length > 1 && !parts[1].trim().isEmpty()) {
                    maxLength = Integer.parseInt(parts[1].trim());
                }
            } else {
                // 单参数格式: 仅文件路径
                filePath = args.trim();
            }

            log.info("读取文件请求 - 路径: {}, 最大长度: {}", filePath, maxLength);

            Path path = Paths.get(filePath);
            if (!Files.exists(path)) {
                return "文件不存在: " + filePath;
            }
            if (!Files.isRegularFile(path)) {
                return "路径不是文件: " + filePath;
            }

            String content = Files.readString(path);
            log.info("成功读取文件: {}, 内容长度: {} 字符", filePath, content.length());
            
            if (maxLength != null && content.length() > maxLength) {
                content = content.substring(0, maxLength) + "\n... (内容被截断,总长度: " + content.length() + " 字符)";
            }

            return "文件内容 (" + filePath + "):\n" + content;
        } catch (NumberFormatException e) {
            log.error("参数格式错误: {}", args, e);
            return "参数格式错误,请使用: 文件路径 或 文件路径|最大长度";
        } catch (Exception e) {
            log.error("读取文件失败: {}", args, e);
            return "读取文件失败: " + e.getMessage();
        }
    }

    // ... 其他方法类似
}

特点

  • ✅ 使用 @Tool 注解,语义清晰
  • ✅ 工具实现完整,自包含
  • ✅ 智能参数解析,支持灵活调用
  • ✅ 完善的日志和错误处理
  • ❌ 代码较长,每个工具需单独实现
  • 参数解析需要手动处理

3.2 AI Agent 构建方式

Spring AI Alibaba 版本
@Service
public class ChatService {

    private final ChatClient chatClient;
    private final FileTools fileTools;

    public ChatService(ChatClient.Builder chatClientBuilder, FileTools fileTools) {
        this.fileTools = fileTools;
        this.chatClient = chatClientBuilder.build();
    }

    public String chat(String message, String sessionId) {
        // 使用 ChatMemory 管理会话
        ChatMemory chatMemory = getOrCreateSession(sessionId);
        
        // 构建消息并添加 Function Callback
        Prompt prompt = new Prompt(
            message,
            ChatMemory.builder()
                .messages(chatMemory.getMessages())
                .build(),
            FunctionCallingOptions.builder()
                .functionCallbacks(List.of(
                    FunctionCallback.builder()
                        .function("listDisk", fileTools::listDisk)
                        .description("列出所有磁盘驱动器及容量信息")
                        .build(),
                    FunctionCallback.builder()
                        .function("readFile", fileTools::readFile)
                        .description("读取文件内容")
                        .build()
                    // ... 其他函数
                ))
                .build()
        );
        
        ChatResponse response = chatClient.call(prompt);
        return response.getResult().getOutput().getText();
    }
}
Langchain4J 版本
@Service
public class ChatService {

    private final FileTools fileTools;
    private final Map<String, ChatMemory> sessions = new ConcurrentHashMap<>();

    public ChatService(FileTools fileTools) {
        this.fileTools = fileTools;
    }

    private ChatLanguageModel createChatModel() {
        return OpenAiChatModel.builder()
                .apiKey(apiKey)
                .modelName(model)
                .baseUrl(baseUrl)
                .temperature(0.7)
                .build();
    }

    public String chat(String message, String sessionId) {
        ChatMemory memory = getOrCreateSession(sessionId);
        memory.add(UserMessage.from(message));
        
        // 使用 AiServices 构建 Agent,自动识别 @Tool 注解
        FileAgent agent = AiServices.builder(FileAgent.class)
                .chatLanguageModel(createChatModel())
                .chatMemory(memory)
                .tools(fileTools)
                .build();
        
        String response = agent.chat(message);
        memory.add(AssistantMessage.from(response));
        saveSession(sessionId);
        return response;
    }

    // 定义 Agent 接口
    public interface FileAgent {
        String chat(String message);
    }
}

对比分析

维度 Spring AI Alibaba Langchain4J
Agent 构建 手动注册 FunctionCallback 自动识别 @Tool 注解
代码复杂度 较高(需手动配置) 较低(声明式)
扩展性 灵活但繁琐 简洁但需遵循约定
类型安全 弱类型(字符串) 强类型(接口定义)

3.3 会话管理

Spring AI Alibaba 版本
private ChatMemory getOrCreateSession(String sessionId) {
    return sessions.computeIfAbsent(sessionId, id -> 
        MessageWindowChatMemory.withMaxMessages(20)
    );
}
Langchain4J 版本
private ChatMemory getOrCreateSession(String sessionId) {
    return sessions.computeIfAbsent(sessionId, id -> {
        Path sessionFile = getHistoryFilePath(id);
        if (Files.exists(sessionFile)) {
            try {
                String json = Files.readString(sessionFile);
                return ChatMemorySerializer.fromJson(json);
            } catch (Exception e) {
                log.warn("加载会话历史失败: {}", id, e);
            }
        }
        return MessageWindowChatMemory.withMaxMessages(20);
    });
}

对比

  • Langchain4J 版本支持持久化,会话历史可保存到文件
  • Spring AI Alibaba 版本默认在内存中,需自行实现持久化

四、功能特性对比

4.1 流式响应支持

两者都支持 SSE(Server-Sent Events)流式输出:

Spring AI Alibaba
@PostMapping(value = "/stream", produces = "text/event-stream;charset=UTF-8")
public Flux<String> streamChat(@RequestBody ChatRequest request) {
    return chatService.streamChat(request.getMessage(), request.getSessionId());
}

public Flux<String> streamChat(String message, String sessionId) {
    return Flux.create(sink -> {
        chatClient.stream(new Prompt(message))
            .doOnNext(response -> {
                String text = response.getResult().getOutput().getText();
                if (text != null) {
                    sink.next("data: " + text + "\n\n");
                }
            })
            .doOnComplete(() -> sink.complete())
            .doOnError(sink::error)
            .subscribe();
    });
}
Langchain4J
@PostMapping(value = "/stream", produces = "text/event-stream;charset=UTF-8")
public Flux<String> streamChat(@RequestBody ChatRequest request) {
    return chatService.streamChat(request.getMessage(), request.getSessionId());
}

public Flux<String> streamChat(String message, String sessionId) {
    return Flux.create(sink -> {
        StreamingChatLanguageModel streamingModel = OpenAiStreamingChatModel.builder()
                .apiKey(apiKey)
                .modelName(model)
                .baseUrl(baseUrl)
                .build();
        
        streamingModel.generate(
            getOrCreateSession(sessionId).messages(),
            new StreamingResponseHandler() {
                @Override
                public void onPartialResponse(String partialResponse) {
                    sink.next("data: " + partialResponse + "\n\n");
                }
                
                @Override
                public void onCompleteResponse(ChatResponse completeResponse) {
                    sink.complete();
                }
                
                @Override
                public void onError(Throwable error) {
                    sink.error(error);
                }
            }
        );
    });
}

4.2 REST API 接口

两个版本的 API 接口完全对齐:

POST   /api/chat          - 非流式对话
POST   /api/chat/stream   - 流式对话(SSE)
GET    /api/chat/sessions - 获取会话列表
GET    /api/chat/session/{id} - 获取会话历史
DELETE /api/chat/session/{id} - 删除会话
DELETE /api/chat/sessions - 清空所有会话

4.3 前端界面

两个版本复用相同的前端页面设计:

  • ✅ 现代化聊天界面
  • ✅ 实时流式响应显示
  • ✅ 会话管理(新建/切换/删除)
  • ✅ 快速操作按钮
  • ✅ Markdown 渲染(可选)

五、优缺点总结

5.1 Spring AI Alibaba

✅ 优点
  1. 官方支持:阿里云官方出品,持续迭代
  2. 深度集成:与 Spring Boot 3.x 完美融合
  3. 模型优化:针对通义千问系列模型深度优化
  4. 企业级特性:支持流式输出、Function Calling 等企业级功能
  5. 生态系统:可与其他阿里云服务无缝集成
缺点
  1. 版本不成熟:仍为里程碑版本(M6.1),API 可能变动
  2. 文档不足:官方文档相对较少,社区资源有限
  3. 模型限制:主要支持阿里云模型,灵活性较低
  4. 学习曲线:Function Callback 机制较复杂
  5. 技能管理:依赖外部 SkillManager,需额外配置

5.2 Langchain4J

✅ 优点
  1. 功能丰富:支持多种 AI 模型和提供商
  2. API 简洁:@Tool 注解声明式编程,代码清晰
  3. 类型安全:通过接口定义 Agent,编译期检查
  4. 生态活跃:社区活跃,文档完善
  5. 灵活性强:可通过 OpenAI 兼容 API 连接多种模型
  6. 内置功能:自带会话持久化、向量存储等
❌ 缺点
  1. 非官方:社区驱动,缺乏大厂背书
  2. 代码冗余:每个工具需完整实现,代码量较大
  3. 参数解析:需手动处理参数格式(如 | 分隔)
  4. Spring 集成:通过 Starter 间接集成,深度不如 Spring AI
  5. 模型适配:连接阿里云模型需通过兼容模式,可能有功能差异

六、选择建议

6.1 选择 Spring AI Alibaba 的场景

  • 企业项目:已使用阿里云生态,需要深度集成
  • 通义千问专用:主要使用通义千问系列模型
  • 团队要求:团队熟悉 Spring 生态,偏好官方方案
  • 长期维护:需要大厂持续支持和版本保障

6.2 选择 Langchain4J 的场景

  • 多模型需求:需要灵活切换不同 AI 模型
  • 快速开发:希望用最少代码实现功能
  • 社区活跃:依赖社区文档和示例
  • 灵活性优先:不受限于单一模型提供商
  • 学术研究:需要尝试各种 AI 技术和框架

6.3 综合对比

维度 Spring AI Alibaba Langchain4J 推荐
易用性 ⭐⭐ ⭐⭐⭐⭐⭐ Langchain4J
灵活性 ⭐⭐⭐ ⭐⭐⭐⭐⭐ Langchain4J
企业支持 ⭐⭐⭐⭐ ⭐⭐⭐ Spring AI Alibaba
文档完善 ⭐⭐⭐ ⭐⭐⭐⭐⭐ Langchain4J
模型生态 ⭐⭐ ⭐⭐⭐⭐⭐ Langchain4J
Spring 集成 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ Spring AI Alibaba
类型安全 ⭐⭐⭐ ⭐⭐⭐⭐⭐ Langchain4J
成熟度 ⭐⭐⭐ ⭐⭐⭐⭐ Langchain4J

七、项目源码

两个版本的 FileAgent 项目均已开源,欢迎 Star 和 Fork:

Spring AI Alibaba 版本

  • Gitee 地址: https://gitee.com/mobuhan/fileagent
  • 📦 技术栈: Spring Boot 3.2.5 + Spring AI Alibaba 1.0.0-M6.1
  • 模型: 阿里云通义千问 qwen-turbo
  • 📝 代码行数: 约 500 行(核心功能)

Langchain4J 版本

  • 🌐 Gitee 地址: https://gitee.com/mobuhan/langchain4j-fileagent
  • 📦 技术栈: Spring Boot 3.2.5 + Langchain4J 0.36.2
  • 模型: 阿里云通义千问 qwen-turbo(通过 OpenAI 兼容 API)
  • 📝 代码行数: 约 800 行(核心功能)

八、快速开始

8.1 环境要求

8.2 启动步骤

# 1. 克隆项目
git clone https://gitee.com/mobuhan/langchain4j-fileagent.git
# 或
git clone https://gitee.com/mobuhan/fileagent.git

# 2. 配置 API Key
cd langchain4j-fileagent
cp src/main/resources/application-example.yml src/main/resources/application.yml
# 编辑 application.yml,填入 API Key

# 3. 启动项目
mvn spring-boot:run

# 4. 访问应用
# 打开浏览器访问: http://localhost:8081

8.3 示例对话

用户: 帮我查看一下 D 盘有哪些文件
AI: 正在查看 D 盘目录内容...
    目录内容 (D:\):
      [DIR]  Program Files
      [DIR]  Program Files (x86)
      [DIR]  Users
      [FILE] aa.txt                            1234 bytes
      [FILE] test.txt                          5678 bytes

用户: 帮我读取 D:\aa.txt 这个文件里的内容
AI: 正在读取文件内容...
    文件内容 (D:\aa.txt):
    这是一个测试文件,用于验证 FileAgent 的文件读取功能。
    第二行内容...

九、总结

通过实际开发对比,两个框架各有优劣:

  • Spring AI Alibaba 更适合企业级项目,特别是已深度使用阿里云生态的团队。它的优势在于官方支持和深度集成,但目前在灵活性和文档完善度上有所欠缺。

  • Langchain4J 更适合快速开发和原型验证,其声明式编程风格和丰富的功能让开发者能够更快地上手。如果你需要灵活切换不同 AI 模型,或者希望有更完善的社区支持,Langchain4J 是更好的选择。

我的建议

  • 如果是生产环境且主要使用阿里云服务,选择 Spring AI Alibaba
  • 如果是快速开发或需要多模型支持,选择 Langchain4J
  • 如果不确定,可以先使用 Langchain4J 验证功能,后期再根据需求迁移

两个项目我都已开源,欢迎大家尝试、对比,并在评论区分享你的使用体验!


十、参考资料

  1. Spring AI Alibaba 官方文档
  2. Langchain4J 官方文档
  3. 阿里云通义千问 API 文档
  4. Spring Boot 3.x 官方文档

标签: AI Agent Spring AI Langchain4J 通义千问 Function Calling Java 人工智能

版权声明: 本文为原创文章,转载请注明出处。项目源码已开源,欢迎 Star 和 Fork!

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐