技術共有

3. LangChain4jのチャットメモリ

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

チャットメモリーの紹介

チャットメモリこれはチャット メモリと呼ばれるもので、ユーザーと大規模モデルの間の会話履歴が保存され、大規模モデルはこれらの会話履歴を使用してユーザーが最近言ったこととその意味を理解できます。

ただし、会話履歴をチャット メモリに保存し続けると、必要なストレージ容量がどんどん大きくなっていきます。そのため、ChatMemory はウィンドウ制限、削除メカニズム、永続化メカニズムなどの拡張機能もサポートしています。


ChatMemory は、デフォルトで 2 つの実装クラスを提供するインターフェイスです。

  • メッセージウィンドウチャットメモリ

コレクションのサイズに応じて、古いメッセージは削除されます。スライディングウィンドウとして、 N 最新のニュースを収集し、適合しなくなった古いニュースを排除します。ただし、各メッセージには異なる数のトークンを含めることができるため、MessageWindowChatMemory ラピッドプロトタイピングに非常に便利です。

  • トークンウィンドウチャットメモリ

トークンのサイズに応じて、古いメッセージが削除されます。スライディングウィンドウとしても動作しますが、保持することに重点を置いています。 N 最新のトークンを取得し、必要に応じて古いメッセージを削除します。情報は分割不可能です。メッセージが適切でない場合は、完全に削除されます。 TokenWindowChatMemory にはTokenizer それぞれを計算するChatMessage のトークン。


TokenWindowChatMemory と MessageWindowChatMemory の違い

TokenWindowChatMemory は MessageWindowChatMemory と似ていますが、MessageWindowChatMemory は List を直接取得する方法が異なります。<ChatMessage>サイズ、TokenWindowChatMemory は指定された Tokenizer を使用して、<ChatMessage>対応するトークンの数が推定され、設定された maxTokens と比較され、その数が maxTokens を超えた場合は削除され、最も古い ChatMessage も削除されます。

Tokenizer はデフォルトで提供されるインターフェイスであり、多くの大規模なモデルの ChatMessage API が使用するトークンの数に基づいて課金されるようにするために使用されます。 TokenWindowChatMemory は、セッションで使用されるトークンの総数を制御するために使用されます。

どちらの実装クラスも内部に ChatMemoryStore 属性を持ちます。ChatMemoryStore もデフォルトで InMemoryChatMemoryStore 実装クラスがあります。時間の経過とともに、SQL データベースやドキュメント ストアなどの一般的なストアにすぐに使える実装が追加される予定です。その間、このインターフェイスを実装して、選択したストレージに接続できます。


事例演習

ケース 1: ChatMemory に基づいて人気のあるネーミング マスターを作成する
  1. public class NameDemo {
  2. interface NamingMaster {
  3. String talk(String desc);
  4. }
  5. public static void main(String[] args) {
  6. ChatLanguageModel chatModel = ZhipuAiChatModel.builder()
  7. .apiKey("智普apikey")
  8. .build();
  9. ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
  10. NamingMaster namingMaster = AiServices.builder(NamingMaster.class)
  11. .chatLanguageModel(chatModel)
  12. .chatMemory(chatMemory)
  13. .build();
  14. System.out.println(namingMaster.talk("我姓李,帮我取一个好听的女孩名字,就一个你觉得最好的"));
  15. System.out.println("---");
  16. System.out.println(namingMaster.talk("换一个"));
  17. }
  18. }
ケース 2: ChatMemoryStore をカスタマイズして ChatMessage をディスクに保存する

Maven の依存関係を導入する

  1. <dependency>
  2. <groupId>org.mapdb</groupId>
  3. <artifactId>mapdb</artifactId>
  4. <version>3.0.9</version>
  5. <exclusions>
  6. <exclusion>
  7. <groupId>org.jetbrains.kotlin</groupId>
  8. <artifactId>kotlin-stdlib</artifactId>
  9. </exclusion>
  10. </exclusions>
  11. </dependency>

 ChatMemoryStore をカスタマイズして永続的なストレージを実現する

  1. public class PersistentChatMemoryStore implements ChatMemoryStore {
  2. private final DB db = DBMaker.fileDB("chat-memory.db").transactionEnable().make();
  3. private final Map<String, String> map = db.hashMap("messages", Serializer.STRING, Serializer.STRING).createOrOpen();
  4. @Override
  5. public List<ChatMessage> getMessages(Object memoryId) {
  6. String json = map.get((String) memoryId);
  7. return ChatMessageDeserializer.messagesFromJson(json);
  8. }
  9. @Override
  10. public void updateMessages(Object memoryId, List<ChatMessage> messages) {
  11. String json = ChatMessageSerializer.messagesToJson(messages);
  12. map.put((String) memoryId, json);
  13. db.commit();
  14. }
  15. @Override
  16. public void deleteMessages(Object memoryId) {
  17. map.remove((String) memoryId);
  18. db.commit();
  19. }
  20. }

  コードのテスト

  1. public class PersistentDemo {
  2. interface NamingMaster {
  3. String talk(String desc);
  4. }
  5. public static void main(String[] args) {
  6. ChatLanguageModel chatModel = ZhipuAiChatModel.builder()
  7. .apiKey("智普apikey")
  8. .build();
  9. ChatMemory chatMemory = MessageWindowChatMemory.builder()
  10. .chatMemoryStore(new PersistentChatMemoryStore())
  11. .maxMessages(10)
  12. .build();
  13. NamingMaster namingMaster = AiServices.builder(NamingMaster.class)
  14. .chatLanguageModel(chatModel)
  15. .chatMemory(chatMemory)
  16. .build();
  17. System.out.println(namingMaster.talk("我姓李,帮我取一个好听的女孩名字,就一个你觉得最好的"));
  18. System.out.println("---");
  19. System.out.println(namingMaster.talk("换一个"));
  20. }
  21. }
ケース 3: チャット記録をユーザーごとに個別に保存する
  1. public class NameDemo {
  2. interface NamingMaster {
  3. String talk(@MemoryId Integer userId, @UserMessage String desc);
  4. }
  5. public static void main(String[] args) {
  6. ChatLanguageModel chatModel = ZhipuAiChatModel.builder()
  7. .apiKey("智普apikey")
  8. .build();
  9. NamingMaster namingMaster = AiServices.builder(NamingMaster.class)
  10. .chatLanguageModel(chatModel)
  11. .chatMemoryProvider(userId -> MessageWindowChatMemory.withMaxMessages(10))
  12. .build();
  13. System.out.println(namingMaster.talk(1, "我姓李,帮我取一个好听的女孩名字,就一个你觉得最好的"));
  14. System.out.println("---");
  15. System.out.println(namingMaster.talk(2, "我姓赵,帮我取一个好听的男孩名字,就一个你觉得最好的"));
  16. System.out.println("---");
  17. System.out.println(namingMaster.talk(1, "换一个"));
  18. }
  19. }