java编写 agent 入门案例

LangChain4j Agent 完整示例

基于 Java 17 + Spring Boot 2.6.13 + LangChain4j 0.36.2 的 AI Agent 实现,使用 DeepSeek API 进行流式对话和工具调用。

依赖配置

pom.xml

xml 复制代码
<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>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.13</version>
    <relativePath/>
  </parent>



  <properties>
    <java.version>17</java.version>
    <hutool.version>5.8.16</hutool.version>
    <ip2region.version>2.6.6</ip2region.version>
    <langchain4j.version>0.36.2</langchain4j.version>
  </properties>

  <dependencies>
    <!-- Spring Boot Web -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>


    <!-- LangChain4j Core -->
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j</artifactId>
      <version>${langchain4j.version}</version>
    </dependency>

    <!-- LangChain4j OpenAI (兼容DeepSeek) -->
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-open-ai</artifactId>
      <version>${langchain4j.version}</version>
    </dependency>

    <!-- LangChain4j Spring Boot Starter -->
    <dependency>
      <groupId>dev.langchain4j</groupId>
      <artifactId>langchain4j-spring-boot-starter</artifactId>
      <version>${langchain4j.version}</version>
    </dependency>

    <!-- OkHttp (解决版本冲突) -->
    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp</artifactId>
      <version>4.12.0</version>
    </dependency>

    <!-- OkHttp SSE (流式响应支持) -->
    <dependency>
      <groupId>com.squareup.okhttp3</groupId>
      <artifactId>okhttp-sse</artifactId>
      <version>4.12.0</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

核心代码

WeatherAgentDemo.java

java 复制代码
 

import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.TokenStream;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * LangChain4j Agent Demo
 * 使用 DeepSeek 模型,支持流式交互和工具调用
 */
public class WeatherAgentDemo {

    /**
     * 定义 AI Assistant 接口
     */
    interface WeatherAssistant {
        TokenStream chat(String userMessage);
    }

    /**
     * 天气工具类 - 包含多个工具方法
     */
    static class WeatherTools {

        @Tool("查询指定城市的天气情况")
        public String getWeather(String location) {
            // 规范命名
            return location + " 今天是晴天,温度25°C";
        }

        @Tool("查询指定城市的空气质量")
        public String tool2(@P("城市名称,例如:北京、上海") String a) {
            // 不规范的命名,通过 @P 注解说明参数含义
            return a + " 今天空气质量良好";
        }

        @Tool("查询指定城市未来三天的天气情况,不包括今天")
        public String tool3(@P("城市名称,例如:北京、上海") String a) {
            // 不规范的命名,通过 @P 注解说明参数含义
            return a + "明天阴天,后天是雨天,大后天可能会下雪";
        }
    }

    public static void main(String[] args) {

        // 1. 创建 StreamingChatLanguageModel (使用 DeepSeek API)
        StreamingChatLanguageModel model = OpenAiStreamingChatModel.builder()
                .baseUrl("https://api.deepseek.com")
                .apiKey("xxxxxxx")
                .modelName("deepseek-chat")  // 使用 deepseek-chat 模型(非推理模式)
                .temperature(0.7)
                .build();


        // 2. 创建工具实例
        WeatherTools weatherTools = new WeatherTools();

        // 3. 创建带记忆功能的 Assistant (使用内存 checkpointer)
        WeatherAssistant assistant = AiServices.builder(WeatherAssistant.class)
                .streamingChatLanguageModel(model)
                .tools(weatherTools)
                .chatMemory(MessageWindowChatMemory.withMaxMessages(10))  // 内存中保存最近10条消息
                .build();

        // 使用 CountDownLatch 等待异步响应完成
        CountDownLatch latch = new CountDownLatch(1);

        // 测试问题: 询问天气、空气质量和未来预报
        String question1 = "北京今天的天气质量如何?空气质量如何?未来三天的天气又怎么样";
        System.out.println("用户: " + question1);

        assistant.chat(question1)
                .onNext(token -> System.out.print(token))  // 流式输出每个 token
                .onComplete(response -> {
                    System.out.println("\n");  // 完成后换行
                    latch.countDown();  // 通知主线程继续
                })
                .onError(error -> {
                    error.printStackTrace();
                    latch.countDown();  // 即使出错也要释放锁
                })
                .start();

        // 等待流式响应完成(最多等待30秒)
        try {
            latch.await(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("等待被中断");
        }

        System.out.println("=== Demo 结束 ===");
    }
}

运行步骤

1. 环境要求

  • JDK: 17 或更高版本
  • Maven: 3.6+
  • IDE: IntelliJ IDEA / Eclipse(推荐)

4. 预期输出

复制代码
用户: 北京今天的天气质量如何?空气质量如何?未来三天的天气又怎么样
北京今天的天气是晴天,温度25°C。空气质量良好。未来三天:明天阴天,后天是雨天,大后天可能会下雪。

=== Demo 结束 ===

核心概念解析

1. 工具定义

使用 @Tool 注解标记方法为 AI 可调用的工具:

java 复制代码
@Tool("查询指定城市的天气情况")
public String getWeather(String location) {
    return location + " 今天是晴天,温度25°C";
}

关键点

  • @Tool 中的字符串是工具的功能描述,AI 会根据这个描述决定是否调用
  • 方法名、参数名、返回类型都会被 langchain4j 自动提取并发送给 AI
  • 一个类可以有多个 @Tool 方法,都会被注册

2. 参数说明

当参数命名不规范时,使用 @P 注解显式说明:

java 复制代码
@Tool("查询指定城市的空气质量")
public String tool2(@P("城市名称,例如:北京、上海") String a) {
    return a + " 今天空气质量良好";
}

作用

  • 告诉 AI 参数的具体含义和用法
  • 即使参数名是 ax 等无意义名称,AI 也能理解

3. 流式响应

使用 TokenStream 实现逐字输出的流式效果:

java 复制代码
assistant.chat(question)
    .onNext(token -> System.out.print(token))  // 逐字输出
    .onComplete(response -> latch.countDown())  // 完成后通知
    .onError(error -> { error.printStackTrace(); latch.countDown(); })
    .start();

4. 异步等待

由于流式响应是异步的,需要使用 CountDownLatch 等待完成:

java 复制代码
CountDownLatch latch = new CountDownLatch(1);

// ... 发起请求 ...

latch.await(30, TimeUnit.SECONDS);  // 最多等待30秒

5. 对话记忆

使用 MessageWindowChatMemory 保存对话历史:

java 复制代码
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
  • 内存中保存最近 10 条消息
  • AI 可以基于上下文进行多轮对话

工作流程

Yes
User Query
AI Analyzes Intent
Need Tool?
Check Available Tools
Match Most Suitable Tool
Extract Parameter Values
Invoke Tool Execution
Obtain Result
AI Organizes Response
Return to User

工具元数据

langchain4j 会将工具信息转换为 JSON Schema 发送给 AI:

json 复制代码
{
  "name": "getWeather",
  "description": "查询指定城市的天气情况",
  "parameters": {
    "type": "object",
    "properties": {
      "location": {
        "type": "string",
        "description": "城市名称"
      }
    },
    "required": ["location"]
  }
}

AI 根据这些信息决定:

  1. 是否需要调用工具
  2. 调用哪个工具
  3. 传入什么参数

常见问题

Q1: 为什么选择 deepseek-chat 而不是 deepseek-v4-pro?

A : deepseek-v4-pro 是推理模型,启用了 thinking mode,要求客户端回传 reasoning_content 字段,但 langchain4j 0.36.2 还不支持这个特性。使用 deepseek-chat 可以避免这个问题。

Q2: 一个工具类只能有一个 @Tool 方法吗?

A : 不是!一个类可以有多个 @Tool 方法,.tools() 会自动扫描并注册所有带注解的方法。AI 会根据用户问题智能选择最合适的工具。

Q3: 如何注册多个工具类?

A:

java 复制代码
WeatherTools weatherTools = new WeatherTools();
SearchTools searchTools = new SearchTools();

WeatherAssistant assistant = AiServices.builder(WeatherAssistant.class)
    .streamingChatLanguageModel(model)
    .tools(weatherTools, searchTools)  // 传入多个工具实例
    .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
    .build();

Q4: 为什么需要 CountDownLatch?

A : 流式响应是异步的,.start() 会立即返回,如果不等待,main 方法会直接退出导致线程终止。CountDownLatch 让主线程等待异步响应完成。

Q5: 如何隐藏工具执行的日志?

A : 在 application.properties 中添加:

properties 复制代码
logging.level.dev.langchain4j.service.tool=OFF
logging.level.dev.ai4j.openai4j=OFF

技术栈总结

组件 版本 说明
Java 17 运行环境
Spring Boot 2.6.13 Web 框架
LangChain4j 0.36.2 AI Agent 框架
DeepSeek API - AI 模型服务
OkHttp 4.12.0 HTTP 客户端
Maven 3.6+ 构建工具

最后, 贴出完整的代码

java 复制代码
package com.yuhou.utils;

import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.TokenStream;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * LangChain4j Agent Demo
 * 使用 DeepSeek v4-flash 模型,支持流式交互和工具调用
 */
public class WeatherAgentDemo {

    /**
     * 定义 AI Assistant 接口
     */
    interface WeatherAssistant {
        TokenStream chat(String userMessage);
    }

    /**
     * 天气工具类
     */
    static class WeatherTools {

        @Tool("查询指定城市的天气情况")
        public String getWeather(String location) {
            //规范命名
            return location + " 今天是晴天,温度25°C";
        }

        @Tool("查询指定城市的空气质量")
        public String tool2(@P("城市名称,例如:北京、上海") String a) {
            //不规范的命名
            return a + " 今天空气质量良好";
        }

        @Tool("查询指定城市未来三天的天气情况,不包括今天")
        public String tool3(@P("城市名称,例如:北京、上海") String a) {
            //不规范的命名
            return a + "明天阴天,后天是雨天,大后天可能会下雪";
        }
    }

//发言检测类
    static class CheckUserSpeech {

        @Tool("我会告诉你用户在我的平台说了什么,你来帮助我检测用户的发言是否违规," +
                "例如涉及到:黄赌毒、流血暴力等。" +
                "如果你觉得用户的发言不应该被展示出来,调用此方法")
        public Boolean checkViolation(@P("用户发言的数据ID,例如:1546") Integer id) {
            System.out.println("deepseek 认为发言id:" + id + "不合规,系统将对此发言进行删除操作");
            这里你就可以调用你的自己xxxService.remove(id)来操作了
            return true;
        }
    }


    public static void main(String[] args) {

        // 1. 创建 StreamingChatLanguageModel (使用 DeepSeek API)
        StreamingChatLanguageModel model = OpenAiStreamingChatModel.builder()
                .baseUrl("https://api.deepseek.com")
                .apiKey("xxxxxxxxxxx")
                .modelName("deepseek-chat")  // 使用 deepseek-chat 模型(非推理模式)
                .temperature(0.7)
                .build();


        // 2. 创建工具实例
        WeatherTools weatherTools = new WeatherTools();
        CheckUserSpeech checkUserSpeech = new CheckUserSpeech();

        // 3. 创建带记忆功能的 Assistant (使用内存 checkpointer)
        WeatherAssistant assistant = AiServices.builder(WeatherAssistant.class)
                .streamingChatLanguageModel(model)
                .tools(weatherTools, checkUserSpeech)
                .chatMemory(MessageWindowChatMemory.withMaxMessages(10))  // 内存中保存最近10条消息
                .build();

        // 使用 CountDownLatch 等待异步响应完成
        CountDownLatch latch = new CountDownLatch(1);

        // 测试问题1: 询问天气
        String question1 = "用户的发言是:<" + "小明你真该死啊,CNMD" + ">该数据的id是 1233";
        System.out.println("用户: " + question1);

        assistant.chat(question1)
                .onNext(token -> System.out.print(token))  // 流式输出每个 token
                .onComplete(response -> {
                    System.out.println("\n");  // 完成后换行
                    latch.countDown();  // 通知主线程继续
                })
                .onError(error -> {
                    error.printStackTrace();
                    latch.countDown();  // 即使出错也要释放锁
                })
                .start();

        // 等待流式响应完成(最多等待30秒)
        try {
            latch.await(30, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("等待被中断");
        }

        System.out.println("=== Demo 结束 ===");
    }
}
相关推荐
环流_1 小时前
redis:持久化rdb
java·数据库·redis
代码中介商1 小时前
C++ STL 容器完全指南(三):deque、list 与 map 深度详解
开发语言·c++
xqqxqxxq2 小时前
Java 线程池(一)
java·开发语言
eggrall2 小时前
Linux进程信号——像收快递一样理解 Linux 信号
linux·开发语言·c++
Full Stack Developme2 小时前
spring-beans 解析
java·后端·spring
foundbug9992 小时前
MATLAB实现:基于图像对比度和波段相关性的高光谱波段选择算法
开发语言·算法·matlab
码农-阿杰2 小时前
生成偏向锁 + JIT
java
czt_java2 小时前
线程安全问题
java·开发语言·jvm
likerhood2 小时前
设计模式-装饰器模式(java)
java·设计模式·装饰器模式