使用 LangChain4j ChatMemory 的生成式 AI 对话

在本文中,我们将探讨以下内容:

  • 如何使用LangChain4j ChatMemoryConversationalChain实现对话式交互?

  • 如何使用 PromptTemplate 提问?

示例代码存储库

可以在 GitHub 存储库中找到本文的示例代码

LangChain4j 教程系列

您可以查看本系列中的其他文章:

我假设您已经创建了一个 Java 项目,其对pom.xml具有以下依赖性:

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j</artifactId>
    <version>0.27.1</version>
</dependency>
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-open-ai</artifactId>
    <version>0.27.1</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.5.0</version>
</dependency>

ChatMemory需要什么?

一般来说,当我们人类进行对话时,我们会记住对话的背景,并用它来继续对话。

请看以下示例:

Person1: What are all the movies directed by Quentin Tarantino?
Person2: Pulp Fiction, Kill Bill, etc.
Person1: How old is he?
Person2: He is 60 years old.

在上面的对话中,Person2 会记住对话的上下文 并理解“他多大了?”问题中的“他”指的是昆汀·塔伦蒂诺。

让我们尝试使用 LangChain4j OpenAI LLM 实现上述对话。

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;

public class OpenAIChatMemoryDemo {
    
    public static void main(String[] args) {
      String openAiKey = "demo";
      //String openAiKey = System.getenv("OPENAI_API_KEY");
      ChatLanguageModel model = OpenAiChatModel.withApiKey(openAiKey);

      String answer = model.generate("What are all the movies directed by Quentin Tarantino?");
      System.out.println(answer); // Pulp Fiction, Kill Bill, etc.

      answer = model.generate("How old is he?");
      System.out.println(answer);
    }
}

运行上述代码时,将获得类似于以下内容的输出:

Answer 1: I'm sorry, I cannot answer that question without more context or information about the person you are referring to.

Answer 2: I'm sorry, without more context I am unable to determine who "he" is or his age. Can you please provide more information?
...

如您所见,ChatLanguageModel 不记得对话的上下文。

LangChain4j 提供了一种记住对话上下文的方法 使用 ConversationalChainChatMemory

如何将ConversationalChain与ChatMemory一起使用?

来自 ConversationalChain 的 JavaDocs:

用于与指定的 ChatLanguageModel 进行对话的链,同时保持 对话。包括一个默认的 ChatMemory(最多包含 10 条消息的消息窗口), 可以覆盖。建议改用 AiServices,因为它功能更强大。

让我们看看如何将ConversationalChainChatMemory一起使用。

import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;

public class OpenAIChatMemoryDemo {
    
    public static void main(String[] args) {
      String openAiKey = "demo";
      //String openAiKey = System.getenv("OPENAI_API_KEY");
      ChatLanguageModel model = OpenAiChatModel.withApiKey(openAiKey);

      ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(20);
      //ChatMemory chatMemory = TokenWindowChatMemory.withMaxTokens(300, new OpenAiTokenizer(GPT_3_5_TURBO));

      ConversationalChain chain = ConversationalChain.builder()
                                    .chatLanguageModel(model)
                                    .chatMemory(chatMemory)
                                    .build();
      String answer = chain.execute("What are all the movies directed by Quentin Tarantino?");
      System.out.println(answer); // Pulp Fiction, Kill Bill, etc.

      answer = chain.execute("How old is he?");
      System.out.println(answer); // Quentin Tarantino was born on March 27, 1963, so he is currently 58 years old.
    }
}

我们使用 MessageWindowChatMemory 创建了一个 ChatMemory 实例,最多包含 20 条消息。 除了使用 MessageWindowChatMemory,还可以使用具有指定最大令牌限制的 TokenWindowChatMemory

然后,我们使用聊天模型和聊天记忆创建了 ConversationalChain 的实例。 现在,当您运行上述代码时,您将获得类似于以下内容的输出:

Reservoir Dogs (1992), Pulp Fiction (1994), Jackie Brown (1997), ...

Quentin Tarantino was born on March 27, 1963, so he is currently 58 years old.

因此,ConversationalChain 会记住对话的上下文并提供正确的答案。

如果你是一个敏锐的观察者,你可能已经注意到第二个问题“他多大了?”并没有提供昆汀·塔伦蒂诺的确切年龄。 它根据模型训练的出生日期和日期计算年龄,而不是基于当前日期。

您可以通过提供更多上下文来优化问题以获取确切的年龄。

answer = chain.execute("How old is he as of "+ LocalDate.now() + "?");
System.out.println(answer); //As of February 21, 2024, Quentin Tarantino would be 60 years old.

现在您将获得昆汀·塔伦蒂诺的正确年龄。 虽然您可以执行字符串连接来提供上下文,但 LangChain4j 提供了一种使用 PromptTemplate 提问的更好方法。

如何使用 PromptTemplate 提问?

PromptTemplate 是一种使用预定义模板(可选)使用占位符提问的方法。

ConversationalChain chain = ConversationalChain.builder()
        .chatLanguageModel(model)
        .chatMemory(chatMemory)
        .build();
String answer = chain.execute("What are all the movies directed by Quentin Tarantino?");
System.out.println(answer); // Pulp Fiction, Kill Bill, etc.

Prompt prompt = PromptTemplate.from("How old is he as of {{current_date}}?").apply(Map.of());
answer = chain.execute(prompt.text());
System.out.println(answer); //As of February 21, 2024, Quentin Tarantino would be 60 years old.

我们使用 PromptTemplate 创建了一个带有占位符 {{current_date}}Prompt 实例。 但是,我们没有传递 current_date 的值,因为特殊变量 {{current_date}}{{current_time}}{{current_date_time}} 分别自动填充 LocalDate.now()、LocalTime.now()LocalDateTime.now()。

如果有其他占位符,则可以使用 Map 传递值。

Prompt prompt = PromptTemplate
                    .from("How old is {{name}} as of {{current_date}}?")
                    .apply(Map.of("name","Quentin Tarantino"));

PromptTemplates 提供了许多其他功能,我们将在以后的文章中探讨它们。

手动将消息添加到 ChatMemory

您也可以在不使用 ConversationalChain 的情况下手动将消息添加到 ChatMemory

ChatLanguageModel model = OpenAiChatModel.withApiKey(openAiKey);
ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(20);

chatMemory.add(UserMessage.userMessage("What are all the movies directed by Quentin Tarantino?"));
AiMessage answer = model.generate(chatMemory.messages()).content();
System.out.println(answer.text()); // Pulp Fiction, Kill Bill, etc.
chatMemory.add(answer);

chatMemory.add(UserMessage.userMessage("How old is he?"));
AiMessage answer2 = model.generate(chatMemory.messages()).content();
System.out.println(answer2.text()); // Quentin Tarantino was born on March 27, 1963, so he is currently 58 years old.
chatMemory.add(answer2);

我想不出您需要手动将消息添加到 ChatMemory 而不是 使用 ConversationalChain,但有这样的选项。

结论

在本文中,我们了解了如何使用 ConversationalChainChatMemory 来记住 对话的上下文。

ConversationalChain 的 JavaDocs 来看,建议改用 AiServices,因为它更强大。 在下一篇文章中,我们将探讨 AiServices 及其功能。


使用 LangChain4j ChatMemory 的生成式 AI 对话
http://47.123.5.226:8090//archives/shi-yong-langchain4j-chatmemory-de-sheng-cheng-shi-ai-dui-hua
作者
pony
发布于
2024年06月25日
许可协议