チャットメモリ
大規模言語モデル(LLM)は状態を持たないため、以前のインタラクションに関する情報を保持しません。これは、複数のインタラクションにわたってコンテキストや状態を維持したい場合に制約となる可能性があります。この問題に対処するため、Spring AI は、LLM との複数のインタラクションにわたって情報を保存および取得できるチャットメモリ機能を提供します。
ChatMemory
抽象化により、様々なユースケースに対応するために様々な型のメモリを実装できます。メッセージの基盤となるストレージは ChatMemoryRepository
によって処理され、メッセージの保存と取得のみを担います。どのメッセージを保持し、いつ削除するかは ChatMemory
実装によって決定されます。戦略の例としては、最後の N 個のメッセージを保持する、一定期間メッセージを保持する、一定のトークン制限までメッセージを保持するなどが挙げられます。
メモリの種類を選択する前に、チャットメモリとチャット履歴の違いを理解することが重要です。
チャットメモリ。大規模言語モデルが保持し、会話全体を通じてコンテキスト認識を維持するために使用する情報。
チャット履歴。ユーザーとモデル間で交換されたすべてのメッセージを含む、会話履歴全体。
ChatMemory
抽象化はチャットメモリの管理を目的として設計されています。これにより、現在の会話コンテキストに関連するメッセージを保存および取得できます。ただし、チャット履歴の保存には最適ではありません。交換されたすべてのメッセージの完全な記録を維持する必要がある場合は、完全なチャット履歴を効率的に保存および取得するために Spring Data を利用するなど、別のアプローチを検討する必要があります。
クイックスタート
Spring AI は、アプリケーションで直接使用できる ChatMemory
Bean を自動構成します。デフォルトでは、メッセージの保存にはメモリ内リポジトリ(InMemoryChatMemoryRepository
)を使用し、会話履歴の管理には MessageWindowChatMemory
実装を使用します。別のリポジトリ(Cassandra、JDBC、Neo4j など)がすでに構成されている場合、Spring AI は代わりにそれを使用します。
@Autowired
ChatMemory chatMemory;
次のセクションでは、Spring AI で使用できるさまざまなメモリ型とリポジトリについて詳しく説明します。
メモリの種類
ChatMemory
抽象化により、様々なユースケースに合わせて様々な型のメモリを実装できます。メモリ型の選択は、アプリケーションのパフォーマンスと動作に大きな影響を与える可能性があります。このセクションでは、Spring AI が提供する組み込みメモリ型とその特性について説明します。
メッセージウィンドウのチャットメモリ
MessageWindowChatMemory
は、指定された最大サイズまでメッセージウィンドウを維持します。メッセージ数が最大値を超えると、システムメッセージは保持され、古いメッセージは削除されます。デフォルトのウィンドウサイズは 20 メッセージです。
MessageWindowChatMemory memory = MessageWindowChatMemory.builder()
.maxMessages(10)
.build();
これは、Spring AI が ChatMemory
Bean を自動構成するために使用するデフォルトのメッセージ型です。
メモリストレージ
Spring AI は、チャットメモリを保存するための ChatMemoryRepository
抽象化を提供しています。このセクションでは、Spring AI が提供する組み込みリポジトリとその使用方法について説明しますが、必要に応じて独自のリポジトリを実装することもできます。
インメモリリポジトリ
InMemoryChatMemoryRepository
は、ConcurrentHashMap
を使用してメッセージをメモリに保存します。
デフォルトでは、他のリポジトリがまだ構成されていない場合、Spring AI は、アプリケーションで直接使用できる型 InMemoryChatMemoryRepository
の ChatMemoryRepository
Bean を自動構成します。
@Autowired
ChatMemoryRepository chatMemoryRepository;
InMemoryChatMemoryRepository
を手動で作成する場合は、次のようにします。
ChatMemoryRepository repository = new InMemoryChatMemoryRepository();
JdbcChatMemoryRepository
JdbcChatMemoryRepository
は、JDBC を使用してメッセージをリレーショナルデータベースに保存する組み込み実装です。複数のデータベースを標準でサポートしており、チャットメモリの永続的な保存を必要とするアプリケーションに適しています。
まず、プロジェクトに次の依存関係を追加します。
Spring AI は、アプリケーションで直接使用できる JdbcChatMemoryRepository
の自動構成を提供します。
@Autowired
JdbcChatMemoryRepository chatMemoryRepository;
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
JdbcChatMemoryRepository
を手動で作成したい場合は、JdbcTemplate
インスタンスと JdbcChatMemoryRepositoryDialect
を提供することで作成できます。
ChatMemoryRepository chatMemoryRepository = JdbcChatMemoryRepository.builder()
.jdbcTemplate(jdbcTemplate)
.dialect(new PostgresChatMemoryDialect())
.build();
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
サポートされているデータベースとダイアレクトの抽象化
Spring AI は、ダイアレクト抽象化により複数のリレーショナルデータベースをサポートします。以下のデータベースは標準でサポートされています。
PostgreSQL
MySQL/MariaDB
SQL Server
HSQLDB
JdbcChatMemoryRepositoryDialect.from(DataSource)
を使用すると、JDBC URL から適切なダイアレクトが自動検出されます。JdbcChatMemoryRepositoryDialect
インターフェースを実装することで、他のデータベースのサポートを継承できます。
プロパティの構成
プロパティ | 説明 | デフォルト値 |
| スキーマを初期化するタイミングを制御します。値: |
|
| 初期化に使用するスキーマスクリプトの場所。 |
|
| @@platform@@ プレースホルダーが使用されている場合に初期化スクリプトで使用するプラットフォーム。 | 自動検出 |
スキーマの初期化
自動構成により、起動時にデータベースのベンダー固有の SQL スクリプトを使用して SPRING_AI_CHAT_MEMORY
テーブルが自動的に作成されます。デフォルトでは、スキーマの初期化は組み込みデータベース(H2、HSQL、Derby など)に対してのみ実行されます。
spring.ai.chat.memory.repository.jdbc.initialize-schema
プロパティを使用してスキーマの初期化を制御できます。
spring.ai.chat.memory.repository.jdbc.initialize-schema=embedded # Only for embedded DBs (default)
spring.ai.chat.memory.repository.jdbc.initialize-schema=always # Always initialize
spring.ai.chat.memory.repository.jdbc.initialize-schema=never # Never initialize (useful with Flyway/Liquibase)
スキーマスクリプトの場所をオーバーライドするには、次を使用します。
spring.ai.chat.memory.repository.jdbc.schema=classpath:/custom/path/schema-mysql.sql
CassandraChatMemoryRepository
CassandraChatMemoryRepository
は Apache Cassandra を使用してメッセージを保存します。これは、特に可用性、耐久性、拡張性、Time-to-Live(TTL)機能を活用するために、チャットメモリの永続的な保存を必要とするアプリケーションに適しています。
CassandraChatMemoryRepository
は時系列スキーマを備えており、過去のすべてのチャットウィンドウの記録を保持します。これはガバノンスと監査に役立ちます。有効期限(TTL)を 3 年など、適切な値に設定することをお勧めします。
まず CassandraChatMemoryRepository
を使用するには、プロジェクトに依存関係を追加します。
Maven
Gradle
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-cassandra</artifactId>
</dependency>
dependencies {
implementation 'org.springframework.ai:spring-ai-starter-model-chat-memory-repository-cassandra'
}
Spring AI は、アプリケーションで直接使用できる CassandraChatMemoryRepository
の自動構成を提供します。
@Autowired
CassandraChatMemoryRepository chatMemoryRepository;
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
CassandraChatMemoryRepository
を手動で作成したい場合は、CassandraChatMemoryRepositoryConfig
インスタンスを提供することで作成できます。
ChatMemoryRepository chatMemoryRepository = CassandraChatMemoryRepository
.create(CassandraChatMemoryConfig.builder().withCqlSession(cqlSession));
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
プロパティの構成
プロパティ | 説明 | デフォルト値 |
| クラスタ検出を開始するホスト |
|
| 接続する Cassandra ネイティブプロトコルポート |
|
| Cassandra データセンターに接続する |
|
| Cassandra で書き込まれたメッセージの存続時間 (TTL) | |
| Cassandra キースペース |
|
| メッセージの Cassandra 列名 |
|
| Cassandra テーブル |
|
| 起動時にスキーマを初期化するかどうか。 |
|
ネオ 4j ChatMemoryRepository
Neo4jChatMemoryRepository
は、Neo4j を使用してチャットメッセージをプロパティグラフデータベースのノードとリレーションシップとして保存する組み込み実装です。チャットメモリの永続化に Neo4j のグラフ機能を活用したいアプリケーションに最適です。
まず、プロジェクトに次の依存関係を追加します。
Maven
Gradle
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-neo4j</artifactId>
</dependency>
dependencies {
implementation 'org.springframework.ai:spring-ai-starter-model-chat-memory-repository-neo4j'
}
Spring AI は、Neo4jChatMemoryRepository
の自動構成を提供し、アプリケーションで直接使用できます。
@Autowired
Neo4jChatMemoryRepository chatMemoryRepository;
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
Neo4jChatMemoryRepository
を手動で作成したい場合は、Neo4j Driver
インスタンスを提供することで作成できます。
ChatMemoryRepository chatMemoryRepository = Neo4jChatMemoryRepository.builder()
.driver(driver)
.build();
ChatMemory chatMemory = MessageWindowChatMemory.builder()
.chatMemoryRepository(chatMemoryRepository)
.maxMessages(10)
.build();
プロパティの構成
プロパティ | 説明 | デフォルト値 |
| 会話セッションを保存するノードのラベル |
|
| メッセージを保存するノードのラベル |
|
| ツール呼び出しを保存するノードのラベル (例: アシスタントメッセージ) |
|
| メッセージメタデータを保存するノードのラベル |
|
| ツールのレスポンスを保存するノードのラベル |
|
| メッセージに関連付けられたメディアを保存するノードのラベル |
|
チャットクライアントのメモリ
ChatClient API を使用する場合、複数のインタラクションにわたって会話のコンテキストを維持するために ChatMemory
実装を提供できます。
Spring AI には、ニーズに応じて ChatClient
のメモリ動作を構成するために使用できる組み込みアドバイザーがいくつか用意されています。
現在、ツール呼び出し時に大規模言語モデルと交換される中間メッセージはメモリに保存されません。これは現在の実装の制限であり、将来のリリースで修正される予定です。これらのメッセージを保存する必要がある場合は、ユーザー制御ツールの実行の説明書を参照してください。 |
MessageChatMemoryAdvisor
。このアドバイザーは、提供されているChatMemory
実装を使用して会話メモリを管理します。対話ごとに、メモリから会話履歴を取得し、それをメッセージのコレクションとしてプロンプトに含めます。PromptChatMemoryAdvisor
。このアドバイザーは、提供されているChatMemory
実装を使用して会話メモリを管理します。対話ごとに、メモリから会話履歴を取得し、それをプレーンテキストとしてシステムプロンプトに追加します。VectorStoreChatMemoryAdvisor
。このアドバイザーは、提供されているVectorStore
実装を使用して会話メモリを管理します。各インタラクションにおいて、ベクトルストアから会話履歴を取得し、それをプレーンテキストとしてシステムメッセージに追加します。
例: MessageWindowChatMemory
を MessageChatMemoryAdvisor
と一緒に使用したい場合は、次のように設定できます。
ChatMemory chatMemory = MessageWindowChatMemory.builder().build();
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
.build();
ChatClient
への呼び出しを実行すると、メモリは MessageChatMemoryAdvisor
によって自動的に管理されます。指定された会話 ID に基づいて、会話履歴がメモリから取得されます。
String conversationId = "007";
chatClient.prompt()
.user("Do I have license to code?")
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, conversationId))
.call()
.content();
PromptChatMemoryAdvisor
カスタムテンプレート
PromptChatMemoryAdvisor
はデフォルトのテンプレートを使用して、取得した会話メモリをシステムメッセージに追加します。この動作は、.promptTemplate()
ビルダーメソッドを介して独自の PromptTemplate
オブジェクトを提供することでカスタマイズできます。
ここで提供される PromptTemplate は、アドバイザーが取得したメモリとシステムメッセージをマージする方法をカスタマイズします。これは、アドバイザー実行前のユーザー / システムプロンプトの初期コンテンツのレンダリングに影響を与える ChatClient 自体に TemplateRenderer を設定すること(.templateRenderer() を使用)とは異なります。クライアントレベルのテンプレートレンダリングの詳細については、ChatClient プロンプトテンプレートを参照してください。 |
カスタム PromptTemplate
では、任意の TemplateRenderer
実装を使用できます(デフォルトでは、StringTemplate (英語) エンジンに基づく StPromptTemplate
を使用します)。重要な要件として、テンプレートには以下の 2 つのプレースホルダが含まれている必要があります。
元のシステムメッセージを受信するための
instructions
プレースホルダー。取得した会話メモリを受け取るための
memory
プレースホルダー。
VectorStoreChatMemoryAdvisor
カスタムテンプレート
VectorStoreChatMemoryAdvisor
はデフォルトのテンプレートを使用して、取得した会話メモリをシステムメッセージに追加します。この動作は、.promptTemplate()
ビルダーメソッドを介して独自の PromptTemplate
オブジェクトを提供することでカスタマイズできます。
ここで提供される PromptTemplate は、アドバイザーが取得したメモリとシステムメッセージをマージする方法をカスタマイズします。これは、アドバイザー実行前のユーザー / システムプロンプトの初期コンテンツのレンダリングに影響を与える ChatClient 自体に TemplateRenderer を設定すること(.templateRenderer() を使用)とは異なります。クライアントレベルのテンプレートレンダリングの詳細については、ChatClient プロンプトテンプレートを参照してください。 |
カスタム PromptTemplate
では、任意の TemplateRenderer
実装を使用できます(デフォルトでは、StringTemplate (英語) エンジンに基づく StPromptTemplate
を使用します)。重要な要件として、テンプレートには以下の 2 つのプレースホルダが含まれている必要があります。
元のシステムメッセージを受信するための
instructions
プレースホルダー。取得した会話メモリを受け取るための
long_term_memory
プレースホルダー。
チャットモデルのメモリ
ChatClient
ではなく ChatModel
を直接操作する場合は、メモリを明示的に管理できます。
// Create a memory instance
ChatMemory chatMemory = MessageWindowChatMemory.builder().build();
String conversationId = "007";
// First interaction
UserMessage userMessage1 = new UserMessage("My name is James Bond");
chatMemory.add(conversationId, userMessage1);
ChatResponse response1 = chatModel.call(new Prompt(chatMemory.get(conversationId)));
chatMemory.add(conversationId, response1.getResult().getOutput());
// Second interaction
UserMessage userMessage2 = new UserMessage("What is my name?");
chatMemory.add(conversationId, userMessage2);
ChatResponse response2 = chatModel.call(new Prompt(chatMemory.get(conversationId)));
chatMemory.add(conversationId, response2.getResult().getOutput());
// The response will contain "James Bond"