目录

一、AI Agent 的核心概念与架构

为什么选择 Java 而不是 Python?

二、开发环境搭建

2.1 最低环境要求

2.2 Maven 核心依赖配置

三、第一个 Agent:基础对话实现

3.1 最简版 Agent(无工具)

3.2 Spring AI 版本对比

四、赋予 Agent 工具(Tools)能力

4.1 定义工具类(使用 @Tool 注解)

4.2 将工具注入 Agent

4.3 多工具编排执行原理

五、Agent 记忆管理

5.1 基础记忆策略

5.2 生产环境持久化记忆(Redis + MySQL)

Redis 存储示例

5.3 长期记忆 vs 短期记忆

六、复杂任务规划(多步任务自动拆解)

6.1 计划-执行模式(手动实现)

6.2 LangChain4j 原生规划器

6.3 非 AI 智能体(Non-AI Agent)

七、流式响应(Streaming)提升用户体验

7.1 什么是流式响应?

7.2 配合 Spring Boot WebFlux 实现 SSE

八、多模态 Agent(图像理解)

九、高级特性预览(2026 年)

9.1 Agent Skills(技能包)

9.2 MCP(Model Context Protocol)标准化工具访问

9.3 SubAgent 子代理协作

十、避坑指南

10.1 API Key 安全管理

10.2 Token 消耗控制

10.3 工具调用的错误处理

10.4 版本兼容性(2026 年)

十一、完整项目结构建议

十二、学习路径


一、AI Agent 的核心概念与架构

在 Java 中开发 AI Agent,本质上就是利用大语言模型(LLM)来构建一个能够自主执行任务、调用外部工具、记住对话上下文并做出决策的应用程序。一个生产级的 Agent 通常包含以下核心组件:

组件 职责说明
大脑(LLM) 理解用户意图、生成自然语言回复、决定何时调用哪些工具
工具(Tools) 通过 @Tool 注解将 Java 方法暴露给 LLM,让 Agent 能查询天气、读写数据库、调用 API 等-
记忆(Memory) 保存对话历史,实现多轮上下文感知;生产环境需持久化到 Redis/MySQL-49
规划(Planner) 面对复杂任务时自动拆解成多步计划,按顺序调用工具执行
Skills LangChain4j 1.12.1+ 引入的能力,类似“技能包”,需要时才激活,避免 Prompt 过长

为什么选择 Java 而不是 Python?

相比 Python 的 LangChain 生态,Java 在以下方面具有独特优势:

  • 强类型系统:编译期就能发现类型错误,降低运行时异常风险

  • 生态无缝集成:Agent 可直接调用企业内部 Java 微服务,无需经过 HTTP/JSON 转换

  • 可观测性:OpenTelemetry 原生支持,可追踪 LLM 调用和工具执行全过程

  • 高性能启动:Quarkus + GraalVM 可实现亚秒级冷启动,内存占用仅 50-150 MB

当前 Java AI Agent 生态两大主流框架是:

  • LangChain4j:LangChain 的 Java 移植版,功能全面,对 Agent 支持更底层、更灵活

  • Spring AI:Spring 官方出品的 AI 抽象层,与 Spring Boot 生态无缝集成

本文以 LangChain4j 为主线,同时兼顾 Spring AI 的差异点。

二、开发环境搭建

2.1 最低环境要求

组件 版本要求 说明
JDK 21+(推荐 Corretto 21) LangChain4j 0.35+ 需要 Java 21
Maven 3.9+ 项目构建工具
Spring Boot(可选) 3.3.0+ 如需整合 Spring 生态
DeepSeek/OpenAI API - 注册获取 API Key

2.2 Maven 核心依赖配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>java-ai-agent-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- LangChain4j 版本(2026年最新稳定版) -->
        <langchain4j.version>0.35.0</langchain4j.version>
    </properties>

    <dependencies>
        <!-- LangChain4j 核心模块 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>

        <!-- OpenAI 兼容客户端(支持 DeepSeek、OpenAI、智谱等) -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
            <version>${langchain4j.version}</version>
        </dependency>

        <!-- [可选] Skills 技能包支持(LangChain4j 1.12.1+) -->
        <!-- <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-skills</artifactId>
            <version>1.12.1</version>
        </dependency> -->

        <!-- [可选] Spring Boot 集成 -->
        <!-- <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>3.3.0</version>
        </dependency> -->

        <!-- 日志(推荐使用 SLF4J + Logback) -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>2.0.16</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                    <!-- 保留参数名,便于 LLM 理解工具参数 -->
                    <parameters>true</parameters>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

版本提示(2026年) :LangChain4j 当前稳定版本为 0.35.0(2026年6月)。如需要使用 Agent Skills 新特性,需引入 1.12.1 及以上版本,但该版本仍处于快速迭代阶段。两种方式的 API 差异较大,建议根据项目需求选择统一版本。

三、第一个 Agent:基础对话实现

3.1 最简版 Agent(无工具)

package com.example.agent.basic;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.service.AiServices;

/**
 * 最简单的 AI Agent 示例
 * 功能:具备对话记忆能力的 AI 助理
 */
public class SimpleChatAgent {

    /**
     * 定义 AI 服务接口
     * Agent 会自动实现此接口的方法
     */
    interface Assistant {
        /**
         * 对话方法,Agent 自动处理记忆与回复
         * @param userMessage 用户输入的消息
         * @return Agent 的回复文本
         */
        String chat(String userMessage);
    }

    public static void main(String[] args) {
        // 1. 初始化 LLM 模型(使用 OpenAI 兼容接口)
        //    注意:将 "your-api-key" 替换为真实的 API Key
        //    建议通过 System.getenv("OPENAI_API_KEY") 从环境变量读取
        ChatLanguageModel model = OpenAiChatModel.builder()
                .apiKey("your-api-key")              // API 密钥
                .modelName("gpt-4o-mini")            // 模型名称(也可用 "deepseek-chat")
                .temperature(0.7)                    // 温度参数(0~1,越高越随机)
                .maxTokens(2048)                     // 最大输出 Token 数
                .logRequests(true)                   // [调试] 打印请求日志
                .logResponses(true)                  // [调试] 打印响应日志
                .build();

        // 2. 配置对话记忆(保留最近 10 条消息)
        //    MessageWindowChatMemory 采用滑动窗口机制,自动淘汰最早的消息
        ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);

        // 3. 使用 AiServices 构建 Agent 实例
        //    AiServices 是 LangChain4j 的核心构建器,会自动实现接口并注入模型和记忆
        Assistant assistant = AiServices.builder(Assistant.class)
                .chatLanguageModel(model)            // 注入 LLM 模型
                .chatMemory(chatMemory)              // 注入对话记忆
                .build();

        // 4. 测试对话
        System.out.println("用户: 我叫张三");
        String firstResponse = assistant.chat("我叫张三");
        System.out.println("Agent: " + firstResponse);

        System.out.println("\n用户: 我叫什么名字?");
        String secondResponse = assistant.chat("我叫什么名字?");
        System.out.println("Agent: " + secondResponse);
        // 预期输出:Agent 能记住用户叫「张三」
    }
}

3.2 Spring AI 版本对比

如果使用 Spring Boot + Spring AI(1.1.x 版本),实现方式如下:

<!-- Spring AI 需使用 BOM 统一版本管理 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.1.8</version>   <!-- 2026年6月最新稳定版 -->
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>
</dependencies>
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.stereotype.Service;

@Service
public class SpringAIAgent {

    private final ChatClient chatClient;

    public SpringAIAgent(ChatClient.Builder builder) {
        // 配置带记忆的 ChatClient
        this.chatClient = builder
                .withDefaultChatMemory(MessageWindowChatMemory.withMaxMessages(10))
                .build();
    }

    public String chat(String userMessage) {
        return chatClient.prompt()
                .user(userMessage)
                .call()
                .content();   // 同步调用,返回完整回复
    }
}

四、赋予 Agent 工具(Tools)能力

工具(Tools)是 Agent 的核心能力,它让 LLM 能够调用外部 Java 方法来执行实际操作(查询天气、读写数据库、调用 API 等)。

4.1 定义工具类(使用 @Tool 注解)

package com.example.agent.tools;

import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.agent.tool.P;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;

/**
 * Agent 可调用的工具集
 * 通过 @Tool 注解将 Java 方法暴露给 LLM
 */
public class AgentTools {

    // 模拟天气数据库
    private static final Map<String, String> WEATHER_DATA = new HashMap<>();
    static {
        WEATHER_DATA.put("北京", "晴,25°C,湿度 45%");
        WEATHER_DATA.put("上海", "多云,28°C,湿度 65%");
        WEATHER_DATA.put("广州", "雷阵雨,32°C,湿度 85%");
    }

    /**
     * 计算两个整数的和(基础数学工具)
     * @Tool 注解的 description 非常重要,LLM 根据它判断何时调用此工具
     *
     * @param a 第一个加数
     * @param b 第二个加数
     * @return 两数之和
     */
    @Tool("计算两个整数的和")
    public int add(@P("第一个加数") int a, @P("第二个加数") int b) {
        System.out.println("[Tool] add(" + a + ", " + b + ") 被调用");
        return a + b;
    }

    /**
     * 获取指定城市的天气信息
     * @P 注解用于描述参数,帮助 LLM 正确地提取参数值
     *
     * @param city 城市名称(如:北京、上海)
     * @return 天气描述字符串
     */
    @Tool("获取指定城市的实时天气信息")
    public String getWeather(
            @P("城市名称,例如:北京、上海") String city) {

        System.out.println("[Tool] getWeather(" + city + ") 被调用");

        if (city == null || city.trim().isEmpty()) {
            return "错误:城市名称不能为空";
        }

        String weather = WEATHER_DATA.get(city);
        if (weather == null) {
            return "抱歉,未找到「" + city + "」的天气信息,目前支持:北京、上海、广州";
        }
        return city + "的天气:" + weather;
    }

    /**
     * 获取当前日期
     *
     * @return 当前日期字符串(yyyy-MM-dd 格式)
     */
    @Tool("返回今天的日期")
    public String getToday() {
        System.out.println("[Tool] getToday() 被调用");
        return LocalDate.now().toString();
    }

    /**
     * 发送电子邮件(示例:模拟发送,实际需配置 SMTP)
     *
     * @param to      收件人邮箱
     * @param subject 邮件主题
     * @param body    邮件正文
     * @return 发送结果
     */
    @Tool("向指定邮箱发送邮件")
    public String sendEmail(
            @P("收件人邮箱地址") String to,
            @P("邮件主题") String subject,
            @P("邮件正文内容") String body) {

        System.out.println("[Tool] sendEmail(" + to + ", " + subject + ") 被调用");
        // 实际项目中此处调用 SMTP 服务或邮件 API
        // 本示例仅模拟发送
        return "邮件已发送至 " + to;
    }
}

 @Tool 注解的核心要点

  1. description 必须填写:LLM 根据描述判断何时调用该工具

  2. @P 注解(可选但推荐):为参数提供描述,帮助 LLM 正确解析参数值

  3. 返回值类型

    • void → 返回字符串 "Success"

    • String → 原样返回

    • 其他类型 → 自动序列化为 JSON 字符串

  4. 工具执行可能抛异常:应捕获并返回友好的错误信息,便于 LLM 理解

4.2 将工具注入 Agent

package com.example.agent.tools;

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.service.AiServices;

/**
 * 带工具调用能力的 Agent 示例
 * Agent 会自动判断何时调用 @Tool 注解的方法
 */
public class ToolAgentDemo {

    /**
     * AI 服务接口
     * Agent 会自动实现接口,并根据用户问题决定调用哪个工具
     */
    interface SmartAssistant {
        /**
         * 智能对话方法
         * @param userMessage 用户输入(例如:"35 加 47 等于多少?")
         * @return Agent 回复(可能包含工具调用结果)
         */
        String chat(String userMessage);
    }

    public static void main(String[] args) {
        // 1. 初始化 LLM 模型(需要支持 Function Calling 的模型)
        //    GPT-4、GPT-4o-mini、DeepSeek-Chat、Claude 3 等均支持
        ChatLanguageModel model = OpenAiChatModel.builder()
                .apiKey("your-api-key")
                .modelName("gpt-4o-mini")        // 支持 Function Calling
                .temperature(0.3)                 // 工具调用场景建议较低温度
                .maxTokens(4096)
                .logRequests(true)
                .logResponses(true)
                .build();

        // 2. 配置记忆(保留最近 20 条消息,因为工具调用会增加消息数)
        ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(20);

        // 3. 构建带有工具的 Agent
        AgentTools tools = new AgentTools();       // 创建工具类实例
        SmartAssistant assistant = AiServices.builder(SmartAssistant.class)
                .chatLanguageModel(model)
                .chatMemory(chatMemory)
                .tools(tools)                      // 👈 关键:注册工具
                .build();

        // 4. 测试各类场景

        // 场景1:数学计算(触发 add 工具)
        System.out.println("用户: 35 加 47 等于多少?");
        String result1 = assistant.chat("35 加 47 等于多少?");
        System.out.println("Agent: " + result1);
        // 预期输出:35 + 47 = 82

        System.out.println("\n--- 分割线 ---\n");

        // 场景2:天气查询(触发 getWeather 工具)
        System.out.println("用户: 北京今天的天气怎么样?");
        String result2 = assistant.chat("北京今天的天气怎么样?");
        System.out.println("Agent: " + result2);
        // 预期输出:北京的天气:晴,25°C,湿度 45%

        System.out.println("\n--- 分割线 ---\n");

        // 场景3:不支持的场景(自然语言回复)
        System.out.println("用户: 你好,请介绍一下你自己");
        String result3 = assistant.chat("你好,请介绍一下你自己");
        System.out.println("Agent: " + result3);
    }
}

4.3 多工具编排执行原理

当用户问“北京今天多少度?请同时计算 12 乘 5”时,Agent 的执行流程如下:

这个过程中,LangChain4j 自动处理工具调用的编排、参数解析和结果返回,开发者只需专注实现 @Tool 方法。

五、Agent 记忆管理

5.1 基础记忆策略

LangChain4j 内置了多种记忆策略:

记忆策略 适用场景 特点
MessageWindowChatMemory 短期对话(客服、闲聊) 滑动窗口,自动淘汰旧消息
TokenWindowChatMemory Token 限制严格的场景 按 Token 数量滑动窗口
PersistentChatMemory 需要跨会话保存记忆的场景 持久化到数据库/Redis
自定义 Memory + ChatMemoryStore 特殊需求(加密、多租户、自定义淘汰策略) 完全自主控制
package com.example.agent.memory;

import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.memory.chat.TokenWindowChatMemory;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;

/**
 * Agent 记忆配置示例
 */
public class MemoryConfigExample {

    /**
     * 方式一:滑动窗口记忆(按消息条数)
     * 适用于:对话轮次可控的场景
     */
    public static ChatMemory windowByMessageCount() {
        // 保留最近 10 条消息,超出则淘汰最早的
        return MessageWindowChatMemory.withMaxMessages(10);
    }

    /**
     * 方式二:滑动窗口记忆(按 Token 数量)
     * 适用于:严格控制成本、模型 Token 上限较小的场景
     */
    public static ChatMemory windowByToken() {
        // 保留最近 4000 个 Token 的消息
        return TokenWindowChatMemory.withMaxTokens(4000);
    }

    /**
     * 方式三:持久化记忆(跨会话)
     * 适用于:需要保存用户偏好的长期记忆场景
     */
    public static ChatMemory persistentMemory() {
        // 使用内存存储(实际生产可替换为 RedisChatMemoryStore 或 JdbcChatMemoryStore)
        ChatMemoryStore store = new InMemoryChatMemoryStore();

        return MessageWindowChatMemory.builder()
                .maxMessages(50)
                .chatMemoryStore(store)    // 注入存储介质
                .id("user-session-id")     // 会话标识
                .build();
    }
}

5.2 生产环境持久化记忆(Redis + MySQL)

在实际生产环境中,对话记忆必须持久化存储,否则服务重启后所有对话将丢失。

Redis 存储示例
package com.example.agent.memory;

import dev.langchain4j.store.memory.chat.ChatMemoryStore;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Jedis;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;

/**
 * Redis 实现的 ChatMemoryStore
 * 支持分布式部署和跨会话记忆
 */
public class RedisChatMemoryStore implements ChatMemoryStore {

    private final JedisPool jedisPool;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public RedisChatMemoryStore(String host, int port) {
        this.jedisPool = new JedisPool(host, port);
    }

    @Override
    public List<dev.langchain4j.data.message.ChatMessage> getMessages(Object memoryId) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "chat_memory:" + memoryId.toString();
            String json = jedis.get(key);
            if (json == null) {
                return List.of();
            }
            // 反序列化 JSON 为消息列表
            return objectMapper.readValue(json,
                    objectMapper.getTypeFactory().constructCollectionType(List.class,
                            dev.langchain4j.data.message.ChatMessage.class));
        } catch (Exception e) {
            throw new RuntimeException("Failed to load chat memory", e);
        }
    }

    @Override
    public void updateMessages(Object memoryId, List<dev.langchain4j.data.message.ChatMessage> messages) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "chat_memory:" + memoryId.toString();
            String json = objectMapper.writeValueAsString(messages);
            // 设置 TTL(例如 7 天过期)
            jedis.setex(key, 7 * 24 * 3600, json);
        } catch (Exception e) {
            throw new RuntimeException("Failed to save chat memory", e);
        }
    }

    @Override
    public void deleteMessages(Object memoryId) {
        try (Jedis jedis = jedisPool.getResource()) {
            String key = "chat_memory:" + memoryId.toString();
            jedis.del(key);
        }
    }
}

5.3 长期记忆 vs 短期记忆

对于需要跨会话记住用户偏好的场景,建议采用 双记忆架构:

实现思路:

  1. 每次对话同时查询长期记忆区,将核心偏好注入 System Prompt

  2. 对话结束后,LLM 自动提取关键偏好并存储到长期记忆区

  3. 为用户记忆配置 TTL(如 7 天),定期清理无效数据

六、复杂任务规划(多步任务自动拆解)

当 Agent 面对复合任务(如“帮我订一张从北京到上海的机票,并提醒我明天带伞”)时,需要自动拆解为多步计划并依次执行。

6.1 计划-执行模式(手动实现)

package com.example.agent.planning;

import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.chat.ChatLanguageModel;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
import java.util.ArrayList;

/**
 * Agent 规划器示例
 * 将复合任务自动拆解为可执行步骤
 */
public class AgentPlanner {

    /**
     * 规划步骤的数据结构
     */
    static class PlanStep {
        public String tool;   // 要调用的工具名
        public String input;  // 工具参数
        public String description; // 步骤描述
    }

    public static void main(String[] args) {
        ChatLanguageModel model = OpenAiChatModel.builder()
                .apiKey("your-api-key")
                .modelName("gpt-4o-mini")
                .build();

        // 用户目标
        String userGoal = "我想知道北京现在几点,并计算 123 乘以 456 的结果";

        // 构造规划 Prompt
        String planningPrompt = String.format("""
                你是一个任务规划者。用户的目标是:%s

                请将这个目标分解为一系列步骤,每个步骤包含:
                1. 步骤描述
                2. 需要调用的工具名称
                3. 调用参数

                可用工具列表:
                - getTime(city: String): 获取指定城市的当前时间
                - multiply(a: int, b: int): 计算两个整数的乘积

                请以 JSON 数组格式输出,例如:
                [
                  {"description": "获取纽约时间", "tool": "getTime", "input": "纽约"},
                  {"description": "计算乘积", "tool": "multiply", "input": "123,456"}
                ]

                只输出 JSON 数组,不要有其他文字。
                """, userGoal);

        // 生成计划
        String planJson = model.generate(planningPrompt);
        System.out.println("规划结果:\n" + planJson);

        // 实际项目中,此处需解析 JSON 并依次执行每个步骤
        // 可通过反射或工具注册表动态调用对应的 Java 方法
    }
}

6.2 LangChain4j 原生规划器

LangChain4j 提供了 AgentExecutor 和相关规划器接口,支持更复杂的链式处理。对于生产场景,建议采用框架原生的 Chain 模式(详见官方文档)。

6.3 非 AI 智能体(Non-AI Agent)

并非所有环节都需要 LLM 参与。对于计算平均分、状态转换等确定性操作,可以用非 AI 智能体(普通 Java 方法)来替代,以节省大模型调用成本。

/**
 * 非 AI 智能体示例
 * 纯 Java 代码实现,无需 LLM 参与
 */
public class NonAIAgent {

    /**
     * 聚合多个评审结果为综合评分
     * 演示了普通 Java 操作符如何作为一等智能体用于工作流
     *
     * @param hrReview    HR 评审结果
     * @param managerReview 经理评审结果
     * @param teamReview  团队评审结果
     * @return 综合评审结果
     */
    public CvReview aggregateScores(
            CvReview hrReview,
            CvReview managerReview,
            CvReview teamReview) {

        double avgScore = (hrReview.score + managerReview.score + teamReview.score) / 3.0;

        String combinedFeedback = String.join("\n\n",
                "HR评审: " + hrReview.feedback,
                "经理评审: " + managerReview.feedback,
                "团队评审: " + teamReview.feedback);

        return new CvReview(avgScore, combinedFeedback);
    }

    /**
     * 根据评分更新申请状态(确定性规则)
     */
    public String updateStatus(double score) {
        if (score >= 8.0) {
            return "已邀请面试";
        } else if (score >= 6.0) {
            return "待定,需进一步评估";
        } else {
            return "已拒绝";
        }
    }

    static class CvReview {
        double score;
        String feedback;

        CvReview(double score, String feedback) {
            this.score = score;
            this.feedback = feedback;
        }
    }
}

Non-AI Agent = 用普通 Java 代码(计算、if-else、循环、字符串处理)实现确定性的业务逻辑,不调用任何大模型。

它和普通 Java 方法的唯一区别是:在 Agent 架构里,它被当作一个独立的、可替换的“决策单元”来使用,而不是散落在各处的零散代码。

多智能体系统里,只要一个东西能接收输入、根据规则做决定、输出结果,就可以被称为“智能体”(Agent)。

  • aggregateScores:接收三个评审,输出综合结果 → 它是一个智能体

  • updateStatus:接收分数,输出状态字符串 → 它也是一个智能体

但它们不调用大模型,只靠 Java 的基本运算和 if 判断,所以叫做 Non-AI Agent(非 AI 智能体)。

你可以把它理解为:一个非常“死板”但绝对可靠的机器人,只会按你写的规则执行。

这样的设计将 AI 决策(理解简历、给出评语)与 确定性规则(计算平均分、状态转换)分离,既保证灵活性,又控制成本。

七、流式响应(Streaming)提升用户体验

7.1 什么是流式响应?

大模型生成文本是“一个一个词”蹦出来的,流式响应让前端能实时收到这些词,而不是等全部生成完再一次性返回,从而实现“打字机”效果。

package com.example.agent.streaming;

import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import dev.langchain4j.model.chat.response.ChatResponse;

/**
 * 流式响应 Agent 示例
 * 实时逐字输出,提升用户体验
 */
public class StreamingAgentDemo {

    public static void main(String[] args) {
        // 1. 使用 StreamingChatLanguageModel 替代普通的 ChatLanguageModel
        StreamingChatLanguageModel streamingModel = OpenAiStreamingChatModel.builder()
                .apiKey("your-api-key")
                .modelName("gpt-4o-mini")
                .temperature(0.7)
                .logRequests(true)
                .logResponses(true)
                .build();

        System.out.println("Agent 正在思考并实时输出:\n");

        // 2. 调用流式生成
        streamingModel.generate("请写一首关于春天的五言绝句",
                new StreamingChatResponseHandler() {

            /**
             * 每生成一个 Token 时回调
             * @param token 最新生成的文本片段
             */
            @Override
            public void onNext(String token) {
                // 实时输出,不加换行,实现逐字打印效果
                System.out.print(token);
            }

            /**
             * 全部生成完成时回调
             * @param response 完整的 ChatResponse 对象
             */
            @Override
            public void onComplete(ChatResponse response) {
                System.out.println("\n\n✅ 生成完成");
            }

            /**
             * 出错时回调
             * @param error 异常信息
             */
            @Override
            public void onError(Throwable error) {
                System.err.println("\n❌ 生成出错:" + error.getMessage());
                error.printStackTrace();
            }
        });

        // 注意:主线程需要等待生成完成,否则程序会提前退出
        // 实际项目中可用 CountDownLatch 或 CompletableFuture 来控制
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

7.2 配合 Spring Boot WebFlux 实现 SSE

// Spring Boot Controller 示例
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;

@RestController
public class StreamingController {

    private final StreamingChatLanguageModel streamingModel;

    public StreamingController() {
        this.streamingModel = OpenAiStreamingChatModel.builder()
                .apiKey(System.getenv("OPENAI_API_KEY"))
                .modelName("gpt-4o-mini")
                .build();
    }

    @GetMapping(value = "/chat/stream", produces = "text/event-stream")
    public Flux<String> streamChat(@RequestParam String message) {
        // 使用 Flux.create 将回调转换为响应式流
        return Flux.create(sink -> {
            streamingModel.generate(message, new StreamingChatResponseHandler() {
                @Override
                public void onNext(String token) {
                    sink.next(token);      // 每次收到 Token 就发送给客户端
                }

                @Override
                public void onComplete(ChatResponse response) {
                    sink.complete();       // 完成时关闭流
                }

                @Override
                public void onError(Throwable error) {
                    sink.error(error);
                }
            });
        });
    }
}

八、多模态 Agent(图像理解)

package com.example.agent.multimodal;

import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.TextContent;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;

/**
 * 多模态 Agent 示例
 * 支持图像识别和理解
 * 注意:需使用支持多模态的模型,如 GPT-4o、GPT-4o-mini、Claude 3 等
 */
public class MultimodalAgent {

    public static void main(String[] args) {
        // 必须使用支持多模态的模型
        ChatLanguageModel model = OpenAiChatModel.builder()
                .apiKey("your-api-key")
                .modelName("gpt-4o")      // gpt-4o 或 gpt-4o-mini 均支持多模态
                .build();

        // 构造包含图像的用户消息
        UserMessage message = UserMessage.from(
                TextContent.from("请描述这张图片中的内容,包括物体、颜色和可能的场景"),   // 文本指令
                ImageContent.from("https://example.com/image.jpg")                   // 图像 URL
                // 也可以使用本地图片: ImageContent.from(Path.of("/path/to/image.jpg"))
        );

        String response = model.generate(message);
        System.out.println("Agent 识别结果:" + response);
    }
}

九、高级特性预览(2026 年)

9.1 Agent Skills(技能包)

LangChain4j 1.12.1 版本正式引入 Agent Skills 特性,允许将 Skill 定义在独立的 Markdown 文件中,实现渐进式披露(需要时才加载详细指令),相比传统 System Prompt 模式更高效。

import dev.langchain4j.skill.FileSystemSkillLoader;
import dev.langchain4j.skill.Skills;

// 加载 Skills 目录下的所有技能包
List<FileSystemSkill> skillList = FileSystemSkillLoader.loadSkills(Path.of("skills/"));
Skills skills = Skills.from(skillList);

9.2 MCP(Model Context Protocol)标准化工具访问

MCP 是 Anthropic 推出的标准化协议,用于将工具、文件、数据库以统一的方式暴露给 AI Agent。

Spring AI 2.0-M6 已原生支持 MCP 注解 @McpTool@McpToolParam,开发者无需处理底层 JSON-RPC 协议。

9.3 SubAgent 子代理协作

多 Agent 协作模式支持:流水线(Chain)、扇出(Fan-out,并行执行)、循环优化(Loop until satisfied)和路由分发(Route to specialist)四种基础模式。

十、避坑指南

10.1 API Key 安全管理

❌ 错误做法:将 API Key 硬编码在代码中
✅ 正确做法

String apiKey = System.getenv("OPENAI_API_KEY");
// 或使用 Spring 的 @Value("${openai.api.key}")

10.2 Token 消耗控制

每次调用工具都会额外产生多次 LLM 请求(包含历史消息和工具返回结果),建议:

  • 控制 MessageWindowChatMemory 的窗口大小(通常 5-10 轮即可)

  • 工具返回值保持简洁,避免返回大量 JSON 数据

  • 使用 TokenWindowChatMemory 精确控制成本

10.3 工具调用的错误处理

@Tool("获取实时股票价格")
public String getStockPrice(@P("股票代码") String code) {
    try {
        // 调用外部 API
        return fetchFromExternalApi(code);
    } catch (Exception e) {
        // 返回友好错误信息,便于 LLM 理解并告知用户
        return "获取股票「" + code + "」价格失败:" + e.getMessage();
    }
}

10.4 版本兼容性(2026 年)

框架 当前稳定版 注意
LangChain4j 0.35.0 / 1.12.1 0.35 与 1.x 的 API 有较大差异,请统一版本
Spring AI 1.1.8 / 2.0-M6 1.x 与 2.0 API 不兼容,2.0 GA 预计 2026 年下半年发布
Spring Boot 3.5.15 Spring AI 2.0 需要 Spring Boot 4.0

十一、完整项目结构建议

my-java-agent/
├── pom.xml
├── src/main/java/com/example/agent/
│   ├── AgentApplication.java           # 主入口(可选 Spring Boot)
│   ├── basic/
│   │   └── SimpleChatAgent.java        # 基础对话 Agent
│   ├── tools/
│   │   ├── AgentTools.java             # 工具定义类
│   │   └── ToolAgentDemo.java          # 带工具的 Agent 演示
│   ├── memory/
│   │   ├── MemoryConfigExample.java    # 记忆配置
│   │   └── RedisChatMemoryStore.java   # Redis 记忆存储
│   ├── streaming/
│   │   └── StreamingAgentDemo.java     # 流式响应
│   ├── planning/
│   │   └── AgentPlanner.java           # 任务规划
│   └── multimodal/
│       └── MultimodalAgent.java        # 多模态示例
├── skills/                             # Agent Skills 目录(可选)
│   └── explain-code/
│       └── SKILL.md
└── README.md

十二、学习路径

  1. 入门:掌握基础对话记忆 → 为 Agent 添加 1-2 个简单工具(计算器、查时间)

  2. 进阶:实现多工具编排 → 学习持久化记忆(Redis)→ 流式响应

  3. 高级:多 Agent 协作(SubAgent、MCP)→ Agent Skills 技能包 → 全链路可观测性(OpenTelemetry)

最后,如有改进之处欢迎指正,觉得有帮助的话不妨点赞收藏支持一下,感谢!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐