AI大模型实用(五)Java快速实现智能体整理(LangChain4j构建Java AI智能体)

目录

一、大模型与智能体对比

二、智能体示例

1、定义工具tools

[工具1: 用户CURD](#工具1: 用户CURD)

[工具2: 翻译](#工具2: 翻译)

[工具3: 数值计算](#工具3: 数值计算)

[工具4: 日期格式化](#工具4: 日期格式化)

[工具5: 调用第三方API](#工具5: 调用第三方API)

2、使用AiServices来组装智能体,将工具和模型结合起来

[3. 新建controller控制器进行调用返回](#3. 新建controller控制器进行调用返回)

三、AiService也可以作为其他AiService的@Tool

四、访问执行过的Tools

五、处理Tool异常

1、处理tool参数异常

方法一:抛出异常

方法二:给LLM返回一个text消息

2、处理tool运行时异常


一、大模型与智能体对比

大模型: 优势在知识问答和文本生成;劣势在处理实时信息、精确计算或访问个性化工具时存在局限。

智能体可以让大模型调用个性化工具(智能体 ~= 工具 + 大模型)。

比如,大模型可以英文翻译; 而智能体可以英文翻译---》调用个性化工具/专业工具进行润色---》保存到数据库等一些列自主规划、个性化规划的应用

二、智能体示例

官网:https://docs.langchain4j.dev/intro/

https://docs.langchain4j.dev/tutorials/spring-boot-integration/

LangChain4j实现智能体中:

  • 一个agent可以包含若干@AiService;
  • 一个@AiServicek可以包含若干@Tool;
  • 一个@Tool可以若干工具类操作,比如CURD、调用第三方API、调用http接口,与缓存redis/HDFS等等交互;

示意图如下:

注意: AiService也可以作为其他AiService的@Tool

步骤:

  1. 定义工具(Tools)。工具可以是任何东西:网页搜索、外部API调用、或执行一段特定代码等
  2. 使用AiServices来组装智能体,将工具和模型结合起来。

注,AiServices原理:

http://www.cppcns.com/ruanjian/java/718092.html

  1. 新建controller控制器进行调用返回

1、定义工具tools

工具1: 用户CURD

java 复制代码
package com.ai.LangChain4j.agent;

import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.agent.tool.P;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

@Component
public class AiUserTool {
    @Autowired
    private UserService userService;

    //通过@P注解为参数添加描述信息
    @Tool("新增用户服务")
    public void addUser(@P("用户名称") String name, @P("用户年龄") String age, @P("用户性别") String sex) {
        User user = new User(null, name, age, sex);
        userService.addUser(user);
    }

    @Tool("根据用户名查询用户完整信息")
    public User findUser(@P("用户名称") String name) {
        return userService.findUser(name);
    }
    @Async
    @Tool("异步查询")
    public CompletableFuture<User> getUserAsync(String userId) {
        return CompletableFuture.supplyAsync(() ->
                userService.findById(userId)
        );
    }
}

工具2: 翻译

java 复制代码
package com.ai.LangChain4j;

import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.spring.AiService;

@AiService
public interface TranslatorService {
    @SystemMessage("你是一位翻译助手")
    @UserMessage("请将以下句子翻译成英文:{{message}}") // 模板化提示
    String chat(String message);
}

工具3: 数值计算

java 复制代码
@Component
public class MyCalculatorTool {
    //@Tool注解定义可被LLM调用的工具方法,自动将工具方法注册到LangChain4J服务中
    @Tool("用于计算两个数字的加法、减法、乘法和除法")
    public double calculate(double a, double b, String operator) {
        switch (operator) {
            case "+": return a + b;
            case "-": return a - b;
            case "*": return a * b;
            case "/":
                if (b == 0) throw new IllegalArgumentException("除数不能为零");
                return a / b;
            default: throw new IllegalArgumentException("不支持的操作符: " + operator);
        }
    }
}

工具4: 日期格式化

java 复制代码
package com.ai.LangChain4j.agent;

import dev.langchain4j.agent.tool.Tool;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class DateTimeTool {

    @Tool("获取当前时间,返回格式为 yyyy-MM-dd HH:mm:ss")
    public String getCurrentDateTime() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String time = LocalDateTime.now().format(formatter);
//        log.info("调用获取时间工具,返回: {}", time);
        return time;
    }
}

工具5: 调用第三方API

java 复制代码
package com.ai.LangChain4j.agent;

import org.springframework.stereotype.Component;
import dev.langchain4j.agent.tool.Tool;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
@Component
public class MyWebSearchTool {
    private final RestTemplate restTemplate = new RestTemplate();

    @Tool("在互联网上搜索实时信息,可以调用公开平台的api查询信息,例如当前新闻、天气等")
    public String searchWeb(String query) {
        // 为了演示,我们返回一个固定的字符串,实际中应该调用真实的搜索API
        return "根据搜索查询'" + query + "',这里是模拟的搜索结果:xxxxxxxxx";
    }
}

2、使用AiServices来组装智能体,将工具和模型结合起来

定义一个AiService:

java 复制代码
package com.ai.LangChain4j.agent;

import dev.langchain4j.service.spring.AiService;

@AiService
public interface MyAssistantService {
    String chat(String userMessage);
}
复制代码
.tools(calculatorTool, webSearchTool, aiUserTool,bookingTools) //给 AI Service 绑定工具:
使用AiServices的话,就设置tools就行了,之后它的实现类自动管理tool的调用
注: 这里可以绑定若干需要的工具
java 复制代码
package com.ai.LangChain4j.agent;

import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.service.AiServices;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import dev.langchain4j.memory.chat.TokenWindowChatMemory;
import java.time.Duration;

@Configuration
public class MyAgentConfiguration {

    //配置带工具的AI服务

    @Bean
    public MyAssistantService assistant(MyCalculatorTool calculatorTool, MyWebSearchTool webSearchTool, AiUserTool aiUserTool,BookingTools bookingTools) {
        ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(20);

        return AiServices.builder(MyAssistantService.class)
                .chatModel(OpenAiChatModel.builder()
                        .baseUrl(baseUrl)
                        .apiKey(apiKey)
                        .modelName(modelName)        //使用的模型名称
//                .maxTokens(1000)           // 单次回答的最大token数
                        .logRequests(logRequests)   // 记录请求日志
                        .logResponses(logResponses) // 记录响应日志
                        .returnThinking(false)       // 是否返回AI的思考过程
//                .customHeaders(map)
                        // 超时配置优化
                        .timeout(Duration.ofMinutes(5))  // 长文本处理设置较长超时
                        .temperature(0.1) // 降低随机性,使工具调用更稳定(0-1,越高越随机)
                        .build())
                .tools(calculatorTool, webSearchTool, aiUserTool,bookingTools) //给 AI Service 绑定工具:
                .chatMemory(chatMemory)//记忆功能概述 记忆对话功能允许AI记住之前的对话内容,实现上下文连贯的对话体验。LangChain4j提供了多种记忆存储方式,包括内存存储、Redis存储等。
                .build();
    }

    @Value("${langchain4j.open-ai.chat-model.api-key}")
    private String apiKey;

    @Value("${langchain4j.open-ai.chat-model.base-url}")
    private String baseUrl;

    @Value("${langchain4j.open-ai.chat-model.model-name}")
    private String modelName;

    @Value("${langchain4j.open-ai.chat-model.log-requests}")
    private Boolean logRequests;

    @Value("${langchain4j.open-ai.chat-model.log-responses}")
    private Boolean logResponses;

}

3. 新建controller控制器进行调用返回

java 复制代码
package com.ai.LangChain4j.agent;

import com.ai.LangChain4j.CalculatorTool;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.service.AiServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
// 参考 https://developer.aliyun.com/article/1683612
@RestController
@RequestMapping("/agent")
public class MyAgentController {
    @Autowired
    private MyAssistantService myAssistantService;
    @Autowired
    private ChatModel chatModel;

    /**
     * 定义工具、组装智能体、集成Spring Boot,并添加记忆功能
     * @param message
     * @return
     */
    @GetMapping("/chat")
    public String assistantchat(String message) {

        return myAssistantService.chat(message);
    }
}

三、AiService也可以作为其他AiService的@Tool

java 复制代码
interface RouterAgent {

        @dev.langchain4j.service.UserMessage("""
            Analyze the following user request and categorize it as 'legal', 'medical' or 'technical',
            then forward the request as it is to the corresponding expert provided as a tool.
            Finally return the answer that you received from the expert without any modification.

            The user request is: '{{it}}'.
            """)
        String askToExpert(String request);
    }

    interface MedicalExpert {

        @dev.langchain4j.service.UserMessage("""
            You are a medical expert.
            Analyze the following user request under a medical point of view and provide the best possible answer.
            The user request is {{it}}.
            """)
        @Tool("A medical expert")
        String medicalRequest(String request);
    }

    interface LegalExpert {

        @dev.langchain4j.service.UserMessage("""
            You are a legal expert.
            Analyze the following user request under a legal point of view and provide the best possible answer.
            The user request is {{it}}.
            """)
        @Tool("A legal expert")
        String legalRequest(String request);
    }

    interface TechnicalExpert {

        @dev.langchain4j.service.UserMessage("""
            You are a technical expert.
            Analyze the following user request under a technical point of view and provide the best possible answer.
            The user request is {{it}}.
            """)
        @Tool("A technical expert")
        String technicalRequest(String request);
    }
java 复制代码
MedicalExpert medicalExpert = AiServices.builder(MedicalExpert.class)
        .chatModel(model)
        .build();
LegalExpert legalExpert = AiServices.builder(LegalExpert.class)
        .chatModel(model)
        .build();
TechnicalExpert technicalExpert = AiServices.builder(TechnicalExpert.class)
        .chatModel(model)
        .build();

RouterAgent routerAgent = AiServices.builder(RouterAgent.class)
        .chatModel(model)
        .tools(medicalExpert, legalExpert, technicalExpert)
        .build();

routerAgent.askToExpert("I broke my leg what should I do");

注意: RouterAgent可以使用3个AiService作为tool

注:agent不能使用 chat memory

四、访问执行过的Tools

需要使用Result:

java 复制代码
interface Assistant {

    Result<String> chat(String userMessage);
}

Result<String> result = assistant.chat("Cancel my booking 123-456");

String answer = result.content();
List<ToolExecution> toolExecutions = result.toolExecutions();

ToolExecution toolExecution = toolExecutions.get(0);
ToolExecutionRequest request = toolExecution.request();
String result = toolExecution.result(); // tool execution result as text
Object resultObject = toolExecution.resultObject(); // actual value returned by the tool



流式输出场景下:
interface Assistant {

    TokenStream chat(String message);
}

TokenStream tokenStream = assistant.chat("Cancel my booking");

tokenStream
    .onToolExecuted((ToolExecution toolExecution) -> System.out.println(toolExecution))
    .onPartialResponse(...)
    .onCompleteResponse(...)
    .onError(...)
    .start();

五、处理Tool异常

1、处理tool参数异常

方法一:抛出异常

java 复制代码
Assistant assistant = AiServices.builder(Assistant.class)
        .chatModel(chatModel)
        .tools(tools)
        .toolArgumentsErrorHandler((error, errorContext) -> { throw MyCustomException(error); })
        .build();

try {
    assistant.chat(...);
} catch (MyCustomException e) {
    // handle e
}

方法二:给LLM返回一个text消息

java 复制代码
Assistant assistant = AiServices.builder(Assistant.class)
        .chatModel(chatModel)
        .tools(tools)
        .toolArgumentsErrorHandler((error, errorContext) -> ToolErrorHandlerResult.text("Something is wrong with tool arguments: " + error.getMessage()))
        .build();

2、处理tool运行时异常

注: 同上,也可以抛出异常或给LLM返回一个text消息

java 复制代码
Assistant assistant = AiServices.builder(Assistant.class)
        .chatModel(chatModel)
        .tools(tools)
        .toolExecutionErrorHandler((error, errorContext) -> ToolErrorHandlerResult.text("Something is wrong with tool execution: " + error.getMessage()))
        .build();
相关推荐
PPPHUANG24 分钟前
一次 CompletableFuture 误用,如何耗尽 IO 线程池并拖垮整个系统
java·后端·代码规范
恩创软件开发32 分钟前
创业日常2026-1-8
java·经验分享·微信小程序·小程序
想用offer打牌1 小时前
一站式了解Spring AI Alibaba的流式输出
java·人工智能·后端
Lonely丶墨轩1 小时前
从登录入口窥见架构:一个企业级双Token认证系统的深度拆解
java·数据库·sql
掘根2 小时前
【仿Muduo库项目】EventLoop模块
java·开发语言
信码由缰2 小时前
Java 中的 AI 与机器学习:TensorFlow、DJL 与企业级 AI
java
沙子迷了蜗牛眼3 小时前
当展示列表使用 URL.createObjectURL 的创建临时图片、视频无法加载问题
java·前端·javascript·vue.js
ganshenml3 小时前
【Android】 开发四角版本全解析:AS、AGP、Gradle 与 JDK 的配套关系
android·java·开发语言
我命由我123453 小时前
Kotlin 运算符 - == 运算符与 === 运算符
android·java·开发语言·java-ee·kotlin·android studio·android-studio