爱码网专注于资源免费下载

LongChat4J-Tools自然语言的魅力

爱码网2024-07-11 13:51:02498技术文章LongChat4JTools自然语言魅力

大模型能理解自然语言,从而能解决问题,但是就像汽车的发动机一样,发动机只能输出动力,实际行动得靠四个轮子,所以LangChain4j提供的Tools机制就是大模型的四轮。通过Tools机制可以通过自然语言整合大模型和系统内部功能,使得大模型这个智能大脑拥有了灵活的四肢,从而可以处理更复杂的场景

一.大模型的不足

大模型本质上是通过已经学习的历史资料对问题的答案进行预测,具有一定的随机性,比如如果问“今天是几月几号?”,大模型给的答案大概率是错误的,因为大模型肯定还没有学习最新产生的资料。

比如:

public static void main(String[] args) {
        ChatLanguageModel model = OpenAiChatModel.builder()
                .baseUrl("http://langchain4j.dev/demo/openai/v1")
                .apiKey("demo")
                .build();


        System.out.println(model.generate("今天是几月几号?"));
    }

// 执行结果为:今天是10月17号。

多执行几次,每次执行结果很有可能不一样,所以大模型对于时间时间相关的问题很是无能为力。

LongChain4j的Tools机制能够帮助大模型补充、拓展一些额外的操作或提过给大模型额外的额数据等。

二.ToolSpecification

通过@Tool注解来描述该工具,大模型在需要获取当前时间时能够调用该工具方法得到当前时间:

@Tool("获取当前日期")
public static String dateUtil(){
	return LocalDateTime.now().toString();
}

然后将工具方法转成ToolSpecification对象,并传递给大模型:

public static void main(String[] args) throws NoSuchMethodException {
        ChatLanguageModel model = ZhipuAiChatModel
                .builder()
                .apiKey("2fab5ffe686592a682852a2d5b1e0b9f.b3xu1RXX5w9eqk22")
                .build();
        
        // 创建Tool
        ToolSpecification toolSpecification = ToolSpecifications.toolSpecificationFrom(Main02.class.getMethod("dataUtil"));

        UserMessage userMessage = UserMessage.from("今天是几月几号");

        Response<AiMessage> generate = model.generate(Collections.singletonList(userMessage), toolSpecification);

        System.out.println(generate.content());
    }

    @Tool("获取当前日期")
    public static String dataUtil() {
        return LocalDateTime.now().toString();
    }

一个ToolSpecification对象就代表一个工具,当把UserMessage和工具ToolSpecification一起传递给大模型,大模型就知道要结合工具描述来解决用户的问题,此时大模型响应的AiMessage不再是一串文本,而是:

AiMessage { text = null toolExecutionRequests = [ToolExecutionRequest { id = "call_IPiiRdafd348dHDHcUN5c7", name = "dateUtil", arguments = "{}" }] }

到了ToolExecutionRequest后,就需要取执行对应的工具方法了,其中ToolExecutionRequest的name属性就是方法名,arguments就表示要传递给方法的参数值:

 Response<AiMessage> response = model.generate(Collections.singletonList(userMessage), toolSpecification);

AiMessage aiMessage = response.content();
if (aiMessage.hasToolExecutionRequests()) {
	for (ToolExecutionRequest toolExecutionRequest : aiMessage.toolExecutionRequests()) {
		String methodName = toolExecutionRequest.name();
		Method method = _04_Tools.class.getMethod(methodName);

		// result就是当前时间
		String result = (String) method.invoke(null);
		System.out.println(result);
	}
}

此时的输出结果为:2024-03-24T11:37:02.618942

ChatMessage类型,除有UserMessage、AiMessage、SystemMessage之外,还有一种类型就是ToolExecutionResultMessage,因此ToolExecutionResultMessage就表示工具执行结果,把工具的执行结果封装为ToolExecutionResultMessage,使用历史对话的思想,把以上用户和大模型之间涉及到的ChatMessage按顺序添加到List中发送给大模型即可:

ToolExecutionResultMessage toolExecutionResultMessage = ToolExecutionResultMessage.from(toolExecutionRequest.id(), toolExecutionRequest.name(), result);

AiMessage message = model.generate(Lists.newArrayList(userMessage, aiMessage, toolExecutionResultMessage)).content();
System.out.println(message.text());

这样大模型就能正确的告诉当前时间:

今天是2024年3月24日。

三.AiServices整合Tools

以上使用Tools的方式有点复杂,而AiServices能简化这个过程。

假如有这么一个需求:获取今天注册的所有新用户信息。

定义User对象:

static class User {
        private String name;
        private Integer age;

        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
}

两个Tools:

    static class MyTools {

        @Tool("用来获取当前具体日期")
        public String dateUtil(String onUse) {
            return LocalDateTime.now().toString();
        }

        @Tool("获取指定日期的用户信息")
        public List<User> getUserInfo(String date) {
            System.out.println("日期:" + date);

            User user1 = new User("周瑜", 88);
            User user2 = new User("曹操", 99);
            return Lists.newArrayList(user1, user2);
        }

    }

一个用来获取当前时间,一个接收当前时间并返回用户信息。

再定义一个UserService接口:

    interface UserService {
        @SystemMessage("先获取当前具体的日期,然后再解决用户问题")
        String getUserInfo(String desc);
    }

利用AiServices创建UserService接口的代理对象:

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ChatLanguageModel model = ZhipuAiChatModel
                .builder()
                .apiKey("2fab5ffe686592a68dsafasd5b1e0b9f.b3xu1RXX5w9eqk22")
                .build();

        UserService userService = AiServices.builder(UserService.class).chatLanguageModel(model)
                .tools(new MyTools())
                .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
                .build();

        String userInfo = userService.getUserInfo("获取今天注册的用户信息");
        System.out.println(userInfo);
    }

并执行getUserInfo()方法,传入描述信息就可以获取到User信息。比如以上代码的执行结果为:

2024-07-11 00:25:27 [main] dev.langchain4j.agent.tool.DefaultToolExecutor.execute()
DEBUG: About to execute ToolExecutionRequest { id = "call_8827327983046036773", name = "dateUtil", arguments = "{"arg0":"today"}" } for memoryId default
2024-07-11 00:25:27 [main] dev.langchain4j.agent.tool.DefaultToolExecutor.execute()
DEBUG: Tool execution result: 2024-07-11T00:25:27.111
2024-07-11 00:25:28 [main] dev.langchain4j.agent.tool.DefaultToolExecutor.execute()
DEBUG: About to execute ToolExecutionRequest { id = "call_8827327673808387532", name = "getUserInfo", arguments = "{"arg0":"2024-07-11"}" } for memoryId default
日期:2024-07-11
2024-07-11 00:25:28 [main] dev.langchain4j.agent.tool.DefaultToolExecutor.execute()
DEBUG: Tool execution result: [
  {
    "name": "周瑜",
    "age": 88
  },
  {
    "name": "曹操",
    "age": 99
  }
]
根据您的要求,我已经获取到了今天注册的用户信息。经过查询,今天(2024年7月11日)注册的用户有周瑜和曹操,他们的年龄分别是88岁和99岁。

转载:https://zxse.cn/archives/1720626691595

本文链接:https://www.icode1024.com/article/632.html

网友评论