做模具做什么网站,手机创建网站免费注册,app建站平台,百度广告联盟一个月能赚多少大模型能理解自然语言#xff0c;从而能解决问题#xff0c;但是就像人类大脑一样#xff0c;大脑只能发送指令#xff0c;实际行动得靠四肢#xff0c;所以LangChain4j提供的Tools机制就是大模型的四肢。
大模型的不足
大模型在解决问题时#xff0c;是基于互联网上很…大模型能理解自然语言从而能解决问题但是就像人类大脑一样大脑只能发送指令实际行动得靠四肢所以LangChain4j提供的Tools机制就是大模型的四肢。
大模型的不足
大模型在解决问题时是基于互联网上很多历史资料进行预测的而且答案具有一定的随机性那如果我问今天是几月几号大模型是大概率答错的因为大模型肯定还没有来得及学习今天所产生的最新资料。
比如
package com.timi;import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;public class _04_Toos {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(今天是几月几号));}
}
代码执行结果为
今天是十二月十九号。多执行几次每次执行结果很有可能不一样所以如果要求大模型处理时间相关的问题它就无能为力了。
因此我们扩展一下出现这种情况的原因是ChatGPT是基于历史数据来进行预测的它没办法拿到当前最新的数据比如说时间从而限制了它的进一步使用那么LangChain4j的Tools机制就能够帮助大模型来获取当前最新的数据从而解决上述时间相关的问题。
由于LangChain4j提供的demo不支持Tools机制需要大家自行获取OpenAI的ApiKey或者找一些OpenAI的代理来间接的调用OpenAI的API。
ToolSpecification
首先需要定义一个工具其实就是一个方法用来返回当前日期并且通过Tool注解来描述该工具从而使得大模型在需要获取当前时间时能够调用该工具方法得到当前时间
Tool(获取当前日期)
public static String dateUtil(){return LocalDateTime.now().toString();
}然后将工具方法转成ToolSpecification对象并传递给大模型
package com.timi;import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.agent.tool.ToolSpecification;
import dev.langchain4j.agent.tool.ToolSpecifications;
import dev.langchain4j.data.message.AiMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.output.Response;import java.time.LocalDateTime;
import java.util.Collections;public class _04_Tools {Tool(获取当前日期)public static String dateUtil(){return LocalDateTime.now().toString();}public static void main(String[] args) throws NoSuchMethodException {ChatLanguageModel model OpenAiChatModel.builder().baseUrl(http://localhost:3000/v1).apiKey(sk-peszVtFXoLnWK45bB15370Df6f344cAa9a088eF50f9c7302).build();ToolSpecification toolSpecification ToolSpecifications.toolSpecificationFrom(_04_Tools.class.getMethod(dateUtil));UserMessage userMessage UserMessage.from(今天是几月几号);ResponseAiMessage response model.generate(Collections.singletonList(userMessage), toolSpecification);System.out.println(response.content());}
}
所以一个ToolSpecification对象就代表一个工具当用户把要问题UserMessage和工具ToolSpecification一起传递给大模型大模型就知道要结合工具描述来解决用户的问题此时大模型响应的AiMessage不再是一串文本而是
AiMessage { text null toolExecutionRequests [ToolExecutionRequest { id call_IPiiRjIM5PmVdDWjpXcUN5c7, name dateUtil, arguments {} }] }一个ToolExecutionRequest表示一个工具执行请求表示大模型在解决问题时需要调用工具来解决用户的问题由于我们可能传了多个工具给大模型所以toolExecutionRequests是一个List表示为了解决用户的问题需要调用哪些工具。
所以我们在得到了ToolExecutionRequest后就需要取执行对应的工具方法了其中ToolExecutionRequest的name属性就是方法名arguments就表示要传递给方法的参数值
ResponseAiMessage 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这就是大模型想要的当前时间相当于是ToolExecutionRequest的响应结果那我们该如何把这个响应结果告诉给大模型从而让大模型告诉我“今天是几月几号”呢
前面在介绍ChatMessage类型时除开有UserMessage、AiMessage、SystemMessage之外还有一种类型就是ToolExecutionResultMessage因此ToolExecutionResultMessage就表示工具执行结果所以我们把工具的执行结果封装为ToolExecutionResultMessage即可
ToolExecutionResultMessage toolExecutionResultMessage ToolExecutionResultMessage.from(toolExecutionRequest.id(), toolExecutionRequest.name(), result);然后使用历史对话的思想把以上用户和大模型之间涉及到的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 username;private Integer age;public User(String username, Integer age) {this.username username;this.age age;}
}然后定义两个Tools
static class MyTools {Tool(获取当前日期)public static String dateUtil(String onUse) {return LocalDateTime.now().toString();}Tool(获取指定日期注册的用户信息)public static ListUser getUserInfo(String date) {System.out.println(接收到的date参数的值 date);User user1 new User(司马懿, 18);User user2 new User(曹操, 18);return Lists.newArrayList(user1, user2);}
}一个用来获取当前时间一个接收当前时间并返回用户信息。
再定义一个UserService接口
interface UserService {SystemMessage(先获取具体日期然后再解决用户问题)String getUserInfo(String desc);
}然后利用AiServices创建UserService接口的代理对象
public static void main(String[] args) {ChatLanguageModel model ZhipuAiChatModel.builder().apiKey(0f4d2b0e8d95f48e6e1f138b881d0a53.UkIov25cJBSvjFDo).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信息了。比如以上代码的执行结果为
接收到的date参数的值2024-04-21
2024年4月20日注册的用户有司马懿和曹操他们的年龄都是18岁。源码分析
在代理对象的invoke()方法中以下代码会去调用大模型的底层API
ResponseAiMessage response context.toolSpecifications null? context.chatModel.generate(messages): context.chatModel.generate(messages, context.toolSpecifications);当指定了Tools时就会调用context.chatModel.generate(messages, context.toolSpecifications)我们debug来看下返回结果 第一次响应是一个ToolExecutionRequest工具执行请求name为now表示要执行now()方法也就是获取当前时间然后会执行如下代码
for (ToolExecutionRequest toolExecutionRequest : aiMessage.toolExecutionRequests()) {// 执行工具ToolExecutor toolExecutor context.toolExecutors.get(toolExecutionRequest.name());// 工具执行结果String toolExecutionResult toolExecutor.execute(toolExecutionRequest, memoryId);// 把工具执行请求和结果封装为ToolExecutionResultMessageToolExecutionResultMessage toolExecutionResultMessage ToolExecutionResultMessage.from(toolExecutionRequest,toolExecutionResult);// 添加到ChatMemory中chatMemory.add(toolExecutionResultMessage);
}然后执行以下代码再次请求大模型此时ChatMemory中包含了第一次工具请求的结果
response context.chatModel.generate(chatMemory.messages(), context.toolSpecifications);这一次得到的响应是 仍然是一个工具执行请求只不过方法时getUserInfo()方法并且入参为上一步工具调用的结果然后和上面类似处理该工具执行请求也就是执行getUserInfo()方法得到工具执行结果同样再次把第二次的工具执行请求和结果封装为ToolExecutionResultMessage并添加到ChatMemory中此时ChatMemory中的内容为 依次为用户的问题、第一次工具执行请求和结果、第二次工具执行请求和结果。
把最终的ChatMemory发送给大模型之后大模型就知道了今天注册的新用户信息有哪些了就会把结果返回给你 基于此我们其实打通了大模型和我们系统内部数据之间的桥梁使得大模型能够调用我们提供的工具来获取系统内部的最新数据而我们可以更进一步让大模型基于这些数据来做更智能的事情比如
需求改为“获取今天注册的新用户信息然后基于这些用户发送一份邮件”我们只需要再定义一个发送邮件Tool就可以了
Tool(给指定用户发送邮件)
public void email(String user) {System.out.println(发送邮件 user);
}然后
ListUser users userService.getUserInfo(获取今天注册的新用户信息然后基于这些用户发送一份邮件);代码执行结果为
接收到的date参数的值2024-04-21
发送邮件司马懿,曹操
今天注册的用户有司马懿和曹操已经给他们发送了一份邮件。通过这个Demo我们发现我们可以利用自然语言来整合各项系统功能这将是一种新的编程模式自然语言编程。
本节总结
本节我们学习了LangChain4j中的Tools机制通过Tools机制可以通过自然语言整合大模型和系统内部功能使得大模型这个智能大脑拥有了灵活的四肢从而可以处理更复杂的场景同时也感受到了自然语言编程离我们越来越近了下一节我们将学习文本向量化以及向量模型、向量数据库这是检索增强生成RAG的基础。