一、简介
1.介绍
官网介绍到LangChain的目标是简化LLM与Java应用程序的集成。
统一的API:每一个LLM提供商(如Open AI 或Google vetex AI)和向量存储(如Pinecone或Milvus)使用专有的API。LangChain4j提供了一个统一的API,以避免需要为每个API学习和实现特定的API。要尝试不同的LLM或嵌入存储,可以轻松地在它们之间切换,而无需重写代码,目前支持15个流行的LLM提供商和15个嵌入商店。
功能全面的工具箱:LLM的应用程序,确定了常见的抽象、模式和技术。LangChain4j将这些改进为一个可用的包。我们的工具箱包括从低级提示模板、聊天内存管理和输出解析到高级模式(如AI Services和RAG)的各种工具。对于每个抽象,我们提供了一个接口以及基于通用技术的多个现成的实现。无论您是构建聊天机器人还是开发具有从数据摄取到检索的完整管道的RAG。
支持的LLM和其他支持情况(Stream流式回答)
核心功能:
- Chat and Language Models:切换大模型
- Chat Memory:对系统内聊天指定聊天memoryId进行分区,可以根据memoryId来持续对话内容。
- Model Parameters:根据选择模型型号和提供程序,可以调整许多参数
- Response Streaming:响应式处理,LLM提供程序一种逐个令牌传输相应的方法,不用等待整个文本
- AI Services:高级的核心功能,通过代理的形式帮我们实现特定的
- Service层放服务,只需要关注业务,不需要关注底层实现
- Tools:除了生成本文以外,还可以触发操作。在tools层可以根据触发条件调用不同的函数
- RAG:根据特定的文档 + 向量化 数据,来扩展模型的知识库,提高搜索的有效性
- Embedding Stores:向量数据库存储功能,提供很多事例,可以使用ES、Redis
2.SpringAI区别
二、使用
1.主要模型接口
- ChatLanguageModel
- LanguageModel
- StreamingChatLanguageModel
- StreamingLanguageModel
- EmbeddingModel
- ModerationModel
以上都是langchain4j提供的大模型接口,都有不同的实现,比如ChatLanguage就有OpenAi提供的OpenAiChatModel和LocalAi提供的LocalAiChat Model实现等等。
例子:使用QianfanChatModel创建一个基础语言模型,进行LLM的基础调用
具体结构如下
1.1 导入依赖
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>0.31.0</version>
</dependency>
1.2 核心代码
//基础模型 ->ChatLanguageModel, 接收多个CharMessages作为输入并返回AiMessage,ChatLanguage属于LangChain4j的基础Api
QianfanChatModel model = QianfanChatModel.builder()
.apiKey("Your apiKey")
.secretKey("Your secretKey")
.modelName("modelName")
.build();
String answer = model.generate("你叫什么名字");
System.out.println(answer);
//2.定制化模型
QianfanChatModel model1 = QianfanChatModel.builder()
.apiKey("xrvMCg8jUn9XFjlweo5yCzZL")
.secretKey("2oDq7RMIakIVHdMfYmpHuoGa9HtD6YEH")
.temperature(50.00)
.maxRetries(2)
.topP(2.00)
.modelName("Yi-34B-Chat")
.endpoint("12")
.responseFormat("21")
.penaltyScore(2.00)
.logRequests(true)
.logResponses(true)
.build();
//1.单轮聊天ChatMessage
String answer = model.generate("你好,我的名字是小思");
String answer1 = model.generate("我的名字是什么呀");
System.out.println(answer);
System.out.println(answer1);
System.out.println("---------------------------------------------------");
//2.多轮聊天ChatMessage - 多轮对话的输入输出,通过手动管理比较复杂,所以提供了chatMemory来管理消息
//入参分为UserMessage和SystemMessage
UserMessage firstUserMessage = UserMessage.from("Hello, my name is Klaus");
AiMessage firstAiMessage = model.generate(firstUserMessage).content(); // Hi Klaus, how can I help you?
UserMessage secondUserMessage = UserMessage.from("What is my name?");
AiMessage secondAiMessage = model.generate(firstUserMessage, firstAiMessage, secondUserMessage).content(); // Klaus
System.out.println(secondAiMessage.text());
2.内存记忆
发送一次SystrmMessages,然后在User与LLM进行两次交流,第三次将前两次的包一起发送给LLM。 LangChain4j能够帮助我们管理内存,不用自己取维护。
2.1 导入依赖
<!--引入依赖 -->
<dependency>
<groupId>org.mapdb</groupId>
<artifactId>mapdb</artifactId>
<version>3.1.0</version>
</dependency>
2.2 核心代码
//1. 带有一个人的聊天记忆
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.maxMessages(10) //设置上下文条数
.build();
QianfanService build = AiServices.builder(QianfanService.class)
.chatLanguageModel(model)
.chatMemory(chatMemory)
.build();
String answer = build.chat("你好,自我介绍一下,我叫小思,我的爱好是打篮球");
System.out.println(answer);
String answer1 = build.chat("我的名字是啥,我的爱好是啥呀");
System.out.println(answer1);
//2.带有多人聊天记忆
String answer = assistant.chat(1,"Hello, my name is xiaoyu");
System.out.println(answer); // Hello xiaoyu!******
String answer1 = assistant.chat(2,"Hello, my name is xiaomi");
System.out.println(answer1); // Hello xiaomi!******
String answerWithName1 = assistant.chat(1,"What's my name?");
System.out.println(answerWithName1); // Your name is xiaoyu.
String answerWithName2 = assistant.chat(2,"What's my name?");
System.out.println(answerWithName2); // Your name is xiaomi.
//记忆持久化 -》 需要实现ChatMemoryStore,实现getMessages,updateMessages,deleteMessages方法
class PersistentChatMemoryStore implements ChatMemoryStore {
private final DB db = DBMaker.fileDB("chat-memory.db").transactionEnable().make();
private final Map<String, String> map = db.hashMap("messages", STRING, STRING).createOrOpen();
@Override
public List<ChatMessage> getMessages(Object memoryId) {
String json = map.get((String) memoryId);
return messagesFromJson(json);
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> messages) {
String json = messagesToJson(messages);
map.put((String) memoryId, json);
db.commit();
}
@Override
public void deleteMessages(Object memoryId) {
map.remove((String) memoryId);
db.commit();
}
}
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.maxMessages(10)
.chatMemoryStore(new PersistentChatMemoryStore()) //传入自定义持久化存储
.build();
2.3 流式回复
因此许多LLM提供者提供了一种逐个token地传输响应的方法,而不是等待生成整个文本。这极大地改善了用户体验,因为用户不需要等待未知的时间,几乎可以立即开始阅读响应。
核心代码
QianfanStreamingChatModel qianfanStreamingChatModel = QianfanStreamingChatModel.builder()
.apiKey("Your apiKey")
.secretKey("Your secretKey")
.modelName("modelName")
.build();
qianfanStreamingChatModel.generate("讲讲雷军的故事", new StreamingResponseHandler<AiMessage>() {
@Override
public void onNext(String token) {
System.out.print(token);
}
@Override
public void onComplete(Response<AiMessage> response) {
System.out.println("onComplete: " + response);
}
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
});
2.4AiService高级应用
官方解释: 将接口与低级组件一起提供 Class , AiServices 并 AiServices 创建实现此接口的代理对象。目前,它使用反射,但我们也在考虑替代方案。此代理对象处理输入和输出的所有转换。在本例中,输入是单个 String ,但我们使用ChatLanguageModel 作为 ChatMessage 输入。因此, AiService 会自动将其转换为 UserMessage 并调用 ChatLanguageModel .由于 chat 该方法的输出类型是 String ,在返回 AiMessage 后 ChatLanguageModel ,它会在从 chat 方法返回之前转换为 String。
应用场景
- 可以对用户模糊描述提取有用的信息,进行精确的业务处理
- 对文档提取特定的数据进行业务处理
核心代码
public class AI_Service_with_System_and_User_Messages_Example {
static ChatLanguageModel model = OpenAiChatModel.builder()
.baseUrl(ApiKeys.BASE_URL)
.apiKey(ApiKeys.OPENAI_API_KEY)
.logRequests(true)
.logResponses(true)
.timeout(ofSeconds(60))
.build();
interface TextUtils {
@SystemMessage("You are a professional translator into {{language}}")
@UserMessage("Translate the following text: {{text}}")
String translate(@V("text") String text, @V("language") String language);
@SystemMessage("Summarize every message from user in {{n}} bullet points. Provide only bullet points.")
List<String> summarize(@UserMessage String text, @V("n") int n);
@UserMessage("Extract information about a person from {{it}}")
Person extractPersonFrom(String text);
}
public static void main(String[] args) {
TextUtils utils = AiServices.create(TextUtils.class, model);
String translation = utils.translate("Hello, how are you?", "italian");
System.out.println(translation); // Ciao, come stai?
String text = "AI, or artificial intelligence, is a branch of computer science that aims to create "
+ "machines that mimic human intelligence. This can range from simple tasks such as recognizing "
+ "patterns or speech to more complex tasks like making decisions or predictions.";
List<String> bulletPoints = utils.summarize(text, 3);
bulletPoints.forEach(System.out::println);
// [
// "- AI is a branch of computer science",
// "- It aims to create machines that mimic human intelligence",
// "- It can perform simple or complex tasks"
// ]
}
}
5.rag
检索增强生成(Retrieval-augmented Generation),简称RAG,是当下热门的大模型前沿技术之一。检索增强模型结合了语言模型和信息检索技术。具体来说,当模型需要生成文本或者回答问题的时候,它会先从一个庞大的文档集合中检索出相关的信息,然后利用这些检索到的信息来指导文本的生成,从而提高预测的质量和准确性。
5.1 引入依赖
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-easy-rag</artifactId>
<version>0.31.0</version>
</dependency>
5.2 核心代码
QianfanChatModel chatLanguageModel = QianfanChatModel.builder()
.apiKey(API_KEY)
.secretKey(SECRET_KEY)
.modelName("Yi-34B-Chat")
.build();
// 1.所有的文件位置 -》FileSystemDocumentLoader将加载一个ApacheTikeDocumentParser
//由langchain4j-easy-rag依赖项通过SPI提供
List<Document> documents = FileSystemDocumentLoader.loadDocuments("/home/langchain4j/documentation");
// 2.初始化矢量数据库,简单的就放入内存中,此处不集成其他Redis和Es数据库
InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
EmbeddingStoreIngestor.ingest(documents, embeddingStore); //将文档进行切分,每个文档分成更小的部分TestSegments
//3.发送请求
IAiService assistant = AiServices.builder(IAiService.class)
.chatLanguageModel(chatLanguageModel)
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.contentRetriever(EmbeddingStoreContentRetriever.from(embeddingStore))
.build();
String answer = assistant.chat("The Question");
System.out.println(answer);
5.3 对接的数据库
构建矢量数据库
用户Query